diff -urN linux-2.4.26/CREDITS linux-2.4.27/CREDITS --- linux-2.4.26/CREDITS 2004-04-14 06:05:21.000000000 -0700 +++ linux-2.4.27/CREDITS 2004-08-07 16:26:04.249330136 -0700 @@ -1232,8 +1232,8 @@ D: National Language Support D: Linux Internationalization Project D: German Localization for Linux and GNU software -S: Helenenstrasse 18 -S: 65183 Wiesbaden +S: Kriemhildring 12a +S: 65795 Hattersheim am Main S: Germany N: Christoph Hellwig diff -urN linux-2.4.26/Documentation/CodingStyle linux-2.4.27/Documentation/CodingStyle --- linux-2.4.26/Documentation/CodingStyle 2001-09-09 16:40:43.000000000 -0700 +++ linux-2.4.27/Documentation/CodingStyle 2004-08-07 16:26:04.251330218 -0700 @@ -1,42 +1,75 @@ - Linux kernel coding style + Linux kernel coding style This is a short document describing the preferred coding style for the linux kernel. Coding style is very personal, and I won't _force_ my views on anybody, but this is what goes for anything that I have to be able to maintain, and I'd prefer it for most other things too. Please -at least consider the points made here. +at least consider the points made here. First off, I'd suggest printing out a copy of the GNU coding standards, -and NOT read it. Burn them, it's a great symbolic gesture. +and NOT reading it. Burn them, it's a great symbolic gesture. Anyway, here goes: Chapter 1: Indentation -Tabs are 8 characters, and thus indentations are also 8 characters. +Tabs are 8 characters, and thus indentations are also 8 characters. There are heretic movements that try to make indentations 4 (or even 2!) characters deep, and that is akin to trying to define the value of PI to -be 3. +be 3. Rationale: The whole idea behind indentation is to clearly define where a block of control starts and ends. Especially when you've been looking at your screen for 20 straight hours, you'll find it a lot easier to see -how the indentation works if you have large indentations. +how the indentation works if you have large indentations. Now, some people will claim that having 8-character indentations makes the code move too far to the right, and makes it hard to read on a 80-character terminal screen. The answer to that is that if you need more than 3 levels of indentation, you're screwed anyway, and should fix -your program. +your program. In short, 8-char indents make things easier to read, and have the added -benefit of warning you when you're nesting your functions too deep. -Heed that warning. +benefit of warning you when you're nesting your functions too deep. +Heed that warning. +Don't put multiple statements on a single line unless you have +something to hide: - Chapter 2: Placing Braces + if (condition) do_this; + do_something_everytime; + +Outside of comments, documentation and except in [cC]onfig.in, spaces are never +used for indentation, and the above example is deliberately broken. + +Get a decent editor and don't leave whitespace at the end of lines. + + + Chapter 2: Breaking long lines and strings + +Coding style is all about readability and maintainability using commonly +available tools. + +The limit on the length of lines is 80 columns and this is a hard limit. + +Statements longer than 80 columns will be broken into sensible chunks. +Descendants are always substantially shorter than the parent and are placed +substantially to the right. The same applies to function headers with a long +argument list. Long strings are as well broken into shorter strings. + +void fun(int a, int b, int c) +{ + if (condition) + printk(KERN_WARNING "Warning this is a long printk with " + "3 parameters a: %u b: %u " + "c: %u \n", a, b, c); + else + next_statement; +} + + Chapter 3: Placing Braces The other issue that always comes up in C styling is the placement of braces. Unlike the indent size, there are few technical reasons to @@ -59,7 +92,7 @@ Heretic people all over the world have claimed that this inconsistency is ... well ... inconsistent, but all right-thinking people know that (a) K&R are _right_ and (b) K&R are right. Besides, functions are -special anyway (you can't nest them in C). +special anyway (you can't nest them in C). Note that the closing brace is empty on a line of its own, _except_ in the cases where it is followed by a continuation of the same statement, @@ -79,60 +112,60 @@ } else { .... } - -Rationale: K&R. + +Rationale: K&R. Also, note that this brace-placement also minimizes the number of empty (or almost empty) lines, without any loss of readability. Thus, as the supply of new-lines on your screen is not a renewable resource (think 25-line terminal screens here), you have more empty lines to put -comments on. +comments on. - Chapter 3: Naming + Chapter 4: Naming C is a Spartan language, and so should your naming be. Unlike Modula-2 and Pascal programmers, C programmers do not use cute names like ThisVariableIsATemporaryCounter. A C programmer would call that variable "tmp", which is much easier to write, and not the least more -difficult to understand. +difficult to understand. HOWEVER, while mixed-case names are frowned upon, descriptive names for global variables are a must. To call a global function "foo" is a -shooting offense. +shooting offense. GLOBAL variables (to be used only if you _really_ need them) need to have descriptive names, as do global functions. If you have a function that counts the number of active users, you should call that -"count_active_users()" or similar, you should _not_ call it "cntusr()". +"count_active_users()" or similar, you should _not_ call it "cntusr()". Encoding the type of a function into the name (so-called Hungarian notation) is brain damaged - the compiler knows the types anyway and can check those, and it only confuses the programmer. No wonder MicroSoft -makes buggy programs. +makes buggy programs. LOCAL variable names should be short, and to the point. If you have -some random integer loop counter, it should probably be called "i". +some random integer loop counter, it should probably be called "i". Calling it "loop_counter" is non-productive, if there is no chance of it being mis-understood. Similarly, "tmp" can be just about any type of -variable that is used to hold a temporary value. +variable that is used to hold a temporary value. If you are afraid to mix up your local variable names, you have another -problem, which is called the function-growth-hormone-imbalance syndrome. -See next chapter. +problem, which is called the function-growth-hormone-imbalance syndrome. +See next chapter. - - Chapter 4: Functions + + Chapter 5: Functions Functions should be short and sweet, and do just one thing. They should fit on one or two screenfuls of text (the ISO/ANSI screen size is 80x24, -as we all know), and do one thing and do that well. +as we all know), and do one thing and do that well. The maximum length of a function is inversely proportional to the complexity and indentation level of that function. So, if you have a conceptually simple function that is just one long (but simple) case-statement, where you have to do lots of small things for a lot of -different cases, it's OK to have a longer function. +different cases, it's OK to have a longer function. However, if you have a complex function, and you suspect that a less-than-gifted first-year high-school student might not even @@ -140,41 +173,78 @@ maximum limits all the more closely. Use helper functions with descriptive names (you can ask the compiler to in-line them if you think it's performance-critical, and it will probably do a better job of it -that you would have done). +than you would have done). Another measure of the function is the number of local variables. They shouldn't exceed 5-10, or you're doing something wrong. Re-think the function, and split it into smaller pieces. A human brain can generally easily keep track of about 7 different things, anything more and it gets confused. You know you're brilliant, but maybe you'd like -to understand what you did 2 weeks from now. +to understand what you did 2 weeks from now. + + + Chapter 6: Centralized exiting of functions +Albeit deprecated by some people, the equivalent of the goto statement is +used frequently by compilers in form of the unconditional jump instruction. - Chapter 5: Commenting +The goto statement comes in handy when a function exits from multiple +locations and some common work such as cleanup has to be done. + +The rationale is: + +- unconditional statements are easier to understand and follow +- nesting is reduced +- errors by not updating individual exit points when making + modifications are prevented +- saves the compiler work to optimize redundant code away ;) + +int fun(int ) +{ + int result = 0; + char *buffer = kmalloc(SIZE); + + if (buffer == NULL) + return -ENOMEM; + + if (condition1) { + while (loop1) { + ... + } + result = 1; + goto out; + } + ... +out: + kfree(buffer); + return result; +} + + Chapter 7: Commenting Comments are good, but there is also a danger of over-commenting. NEVER try to explain HOW your code works in a comment: it's much better to write the code so that the _working_ is obvious, and it's a waste of -time to explain badly written code. +time to explain badly written code. -Generally, you want your comments to tell WHAT your code does, not HOW. +Generally, you want your comments to tell WHAT your code does, not HOW. Also, try to avoid putting comments inside a function body: if the function is so complex that you need to separately comment parts of it, -you should probably go back to chapter 4 for a while. You can make +you should probably go back to chapter 5 for a while. You can make small comments to note or warn about something particularly clever (or ugly), but try to avoid excess. Instead, put the comments at the head of the function, telling people what it does, and possibly WHY it does -it. +it. - Chapter 6: You've made a mess of it + Chapter 8: You've made a mess of it That's OK, we all do. You've probably been told by your long-time Unix user helper that "GNU emacs" automatically formats the C sources for you, and you've noticed that yes, it does do that, but the defaults it uses are less than desirable (in fact, they are worse than random -typing - a infinite number of monkeys typing into GNU emacs would never -make a good program). +typing - an infinite number of monkeys typing into GNU emacs would never +make a good program). So, you can either get rid of GNU emacs, or change it to use saner values. To do the latter, you can stick the following in your .emacs file: @@ -192,7 +262,7 @@ to add (setq auto-mode-alist (cons '("/usr/src/linux.*/.*\\.[ch]$" . linux-c-mode) - auto-mode-alist)) + auto-mode-alist)) to your .emacs file if you want to have linux-c-mode switched on automagically when you edit source files under /usr/src/linux. @@ -200,19 +270,20 @@ But even if you fail in getting emacs to do sane formatting, not everything is lost: use "indent". -Now, again, GNU indent has the same brain dead settings that GNU emacs -has, which is why you need to give it a few command line options. +Now, again, GNU indent has the same brain-dead settings that GNU emacs +has, which is why you need to give it a few command line options. However, that's not too bad, because even the makers of GNU indent recognize the authority of K&R (the GNU people aren't evil, they are just severely misguided in this matter), so you just give indent the -options "-kr -i8" (stands for "K&R, 8 character indents"). +options "-kr -i8" (stands for "K&R, 8 character indents"), or use +"scripts/Lindent", which indents in the latest style. "indent" has a lot of options, and especially when it comes to comment -re-formatting you may want to take a look at the manual page. But -remember: "indent" is not a fix for bad programming. +re-formatting you may want to take a look at the man page. But +remember: "indent" is not a fix for bad programming. - Chapter 7: Configuration-files + Chapter 9: Configuration-files For configuration options (arch/xxx/config.in, and all the Config.in files), somewhat different indentation is used. @@ -235,20 +306,20 @@ Experimental options should be denoted (EXPERIMENTAL). - Chapter 8: Data structures + Chapter 10: Data structures Data structures that have visibility outside the single-threaded environment they are created and destroyed in should always have reference counts. In the kernel, garbage collection doesn't exist (and outside the kernel garbage collection is slow and inefficient), which -means that you absolutely _have_ to reference count all your uses. +means that you absolutely _have_ to reference count all your uses. Reference counting means that you can avoid locking, and allows multiple users to have access to the data structure in parallel - and not having to worry about the structure suddenly going away from under them just -because they slept or did something else for a while. +because they slept or did something else for a while. -Note that locking is _not_ a replacement for reference counting. +Note that locking is _not_ a replacement for reference counting. Locking is used to keep data structures coherent, while reference counting is a memory management technique. Usually both are needed, and they are not to be confused with each other. @@ -258,9 +329,99 @@ the number of subclass users, and decrements the global count just once when the subclass count goes to zero. -Examples of this kind of "multi-reference-counting" can be found in +Examples of this kind of "multi-level-reference-counting" can be found in memory management ("struct mm_struct": mm_users and mm_count), and in filesystem code ("struct super_block": s_count and s_active). Remember: if another thread can find your data structure, and you don't have a reference count on it, you almost certainly have a bug. + + + Chapter 11: Macros, Enums, Inline functions and RTL + +Names of macros defining constants and labels in enums are capitalized. + +#define CONSTANT 0x12345 + +Enums are preferred when defining several related constants. + +CAPITALIZED macro names are appreciated but macros resembling functions +may be named in lower case. + +Generally, inline functions are preferable to macros resembling functions. + +Macros with multiple statements should be enclosed in a do - while block: + +#define macrofun(a,b,c) \ + do { \ + if (a == 5) \ + do_this(b,c); \ + } while (0) + +Things to avoid when using macros: + +1) macros that affect control flow: + +#define FOO(x) \ + do { \ + if (blah(x) < 0) \ + return -EBUGGERED; \ + } while(0) + +is a _very_ bad idea. It looks like a function call but exits the "calling" +function; don't break the internal parsers of those who will read the code. + +2) macros that depend on having a local variable with a magic name: + +#define FOO(val) bar(index, val) + +might look like a good thing, but it's confusing as hell when one reads the +code and it's prone to breakage from seemingly innocent changes. + +3) macros with arguments that are used as l-values: FOO(x) = y; will +bite you if somebody e.g. turns FOO into an inline function. + +4) forgetting about precedence: macros defining constants using expressions +must enclose the expression in parentheses. Beware of similar issues with +macros using parameters. + +#define CONSTANT 0x4000 +#define CONSTEXP (CONSTANT | 3) + +The cpp manual deals with macros exhaustively. The gcc internals manual also +covers RTL which is used frequently with assembly language in the kernel. + + + Chapter 12: Printing kernel messages + +Kernel developers like to be seen as literate. Do mind the spelling +of kernel messages to make a good impression. Do not use crippled +words like "dont" and use "do not" or "don't" instead. + +Kernel messages do not have to be terminated with a period. + +Printing numbers in parentheses (%d) adds no value and should be avoided. + + + Chapter 13: References + +The C Programming Language, Second Edition +by Brian W. Kernighan and Dennis M. Ritchie. +Prentice Hall, Inc., 1988. +ISBN 0-13-110362-8 (paperback), 0-13-110370-9 (hardback). +URL: http://cm.bell-labs.com/cm/cs/cbook/ + +The Practice of Programming +by Brian W. Kernighan and Rob Pike. +Addison-Wesley, Inc., 1999. +ISBN 0-201-61586-X. +URL: http://cm.bell-labs.com/cm/cs/tpop/ + +GNU manuals - where in compliance with K&R and this text - for cpp, gcc, +gcc internals and indent, all available from http://www.gnu.org + +WG14 is the international standardization working group for the programming +language C, URL: http://std.dkuug.dk/JTC1/SC22/WG14/ + +-- +Last updated on 16 March 2004 by a community effort on LKML. diff -urN linux-2.4.26/Documentation/Configure.help linux-2.4.27/Documentation/Configure.help --- linux-2.4.26/Documentation/Configure.help 2004-04-14 06:05:24.000000000 -0700 +++ linux-2.4.27/Documentation/Configure.help 2004-08-07 16:26:04.531341723 -0700 @@ -569,6 +569,19 @@ The umem driver has been allocated block major number 116. See Documentation/devices.txt for recommended device naming. +Promise SATA SX8 support +CONFIG_BLK_DEV_SX8 + Saying Y or M here will enable support for the + Promise SATA SX8 controllers. + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called sx8.o. + + The sx8 driver has been allocated block major numbers 160, 161. + See Documentation/devices.txt for recommended device naming. + Network block device support CONFIG_BLK_DEV_NBD Saying Y here will allow your computer to be a client for network @@ -1296,11 +1309,13 @@ If unsure, say N. -PROMISE PDC20246/PDC20262/PDC20265/PDC20267/PDC20268 support +Promise PDC202{46|62|65|67} support CONFIG_BLK_DEV_PDC202XX_OLD - Promise Ultra33 or PDC20246 - Promise Ultra66 or PDC20262 - Promise Ultra100 or PDC20265/PDC20267/PDC20268 + Promise Ultra 33 [PDC20246] + Promise Ultra 66 [PDC20262] + Promise FastTrak 66 [PDC20263] + Promise MB Ultra 100 [PDC20265] + Promise Ultra 100 [PDC20267] This driver adds up to 4 more EIDE devices sharing a single interrupt. This add-on card is a bootable PCI UDMA controller. Since @@ -1309,7 +1324,7 @@ not match, the driver attempts to do dynamic tuning of the chipset at boot-time for max-speed. Ultra33 BIOS 1.25 or newer is required for more than one card. This card may require that you say Y to - "Special UDMA Feature". + "Force (U)DMA burst transfers" (old name: "Special UDMA Feature"). If you say Y here, you need to say Y to "Use DMA by default when available" as well. @@ -1319,7 +1334,7 @@ If unsure, say N. -PROMISE PDC202{68|69|70|71|75|76|77} support +Promise PDC202{68|69|70|71|75|76|77} support CONFIG_BLK_DEV_PDC202XX_NEW Promise Ultra 100 TX2 [PDC20268] Promise Ultra 133 PTX2 [PDC20269] @@ -1334,17 +1349,16 @@ multiple cards can be installed and there are BIOS ROM problems that happen if the BIOS revisions of all installed cards (max of five) do not match, the driver attempts to do dynamic tuning of the chipset - at boot-time for max speed. Ultra33 BIOS 1.25 or newer is required - for more than one card. + at boot-time for max speed. If you say Y here, you need to say Y to "Use DMA by default when available" as well. If unsure, say N. -Special UDMA Feature +Force (U)DMA burst transfers CONFIG_PDC202XX_BURST - This option causes the pdc202xx driver to enable UDMA modes on the + This option causes the pdc202xx_old driver to enable UDMA modes on the PDC202xx even when the PDC202xx BIOS has not done so. It was originally designed for the PDC20246/Ultra33, whose BIOS will @@ -1357,9 +1371,17 @@ If unsure, say N. -Special FastTrak Feature +Ignore BIOS port disabled setting on FastTrak CONFIG_PDC202XX_FORCE - For FastTrak enable overriding BIOS. + Chipsets affected: + + PDC202{46|62|63|65|67} + (pdc202xx_old driver) + + PDC202{70|76} + (pdc202xx_new driver) + + Say Y unless you want to use Promise proprietary driver. SiS5513 chipset support CONFIG_BLK_DEV_SIS5513 @@ -4286,6 +4308,46 @@ inserted in and removed from the running kernel whenever you want). The module will be called acpiphp.o. If you want to compile it as a module, say M here and read . + +CONFIG_HOTPLUG_PCI_SHPC + Say Y here if you have a motherboard with a SHPC PCI Hotplug + controller. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called shpchp.o. If you want to compile it + as a module, say M here and read . + + When in doubt, say N. + +CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE + Say Y here if you want to use the polling mechanism for hot-plug + events for early platform testing. + + When in doubt, say N. + +CONFIG_HOTPLUG_PCI_SHPC_PHPRM_LEGACY + Say Y here for AMD SHPC. You have to select this option if you are + using this driver on platform with AMD SHPC. + + When in doubt, say N. + +CONFIG_HOTPLUG_PCI_PCIE + Say Y here if you have a motherboard that supports PCI Express Native + Hotplug + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called pciehp.o. If you want to compile it + as a module, say M here and read . + + When in doubt, say N. + +CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE + Say Y here if you want to use the polling mechanism for hot-plug + events for early platform testing. + + When in doubt, say N. MCA support CONFIG_MCA @@ -5543,14 +5605,15 @@ SIS 300 series support CONFIG_FB_SIS_300 This enables support for SiS 300 series chipsets (300/305, 540, 630, - 730). Documentation available at the maintainer's website at - . + 630S, 730S). Documentation available at the maintainer's website at + . SIS 315/330 series support CONFIG_FB_SIS_315 - This enables support for SiS 315/330 series chipsets (315, 550, 650, - M650, 651, 661FX, M661FX, 740, 741, 330). Documentation available at - the maintainer's site . + This enables support for SiS 315/330 series chipsets (315, 315PRO, + 55x, (M)650, 651, (M)661FX, 661MX, 740, (M)741(GX), (M)760, 330). + Documentation available at the maintainer's website at + . IMS Twin Turbo display support CONFIG_FB_IMSTT @@ -6109,8 +6172,7 @@ can be useful if you want to make your (or some other) machine appear on a different network than it physically is, or to use mobile-IP facilities (allowing laptops to seamlessly move between - networks without changing their IP addresses; check out - ). + networks without changing their IP addresses). Saying Y to this option will produce two modules ( = code which can be inserted in and removed from the running kernel whenever you @@ -7521,6 +7583,11 @@ not have to supply an alternative one. They just say Y to "Use default SBA-200E firmware", above. +CONFIG_ATM_FORE200E_USE_TASKLET + This defers work to be done by the interrupt handler to a + tasklet instead of handling everything at interrupt time. This + may improve the responsiveness of the host. + Maximum number of tx retries CONFIG_ATM_FORE200E_TX_RETRY Specifies the number of times the driver attempts to transmit @@ -9202,6 +9269,48 @@ say M here and read . The module will be called megaraid2.o. +CONFIG_SCSI_SATA + This driver family supports Serial ATA host controllers + and devices. + + If unsure, say N. + +CONFIG_SCSI_SATA_SVW + This option enables support for Broadcom/Serverworks/Apple K2 + SATA support. + + If unsure, say N. + +CONFIG_SCSI_SATA_PROMISE + This option enables support for Promise Serial ATA TX2/TX4. + + If unsure, say N. + +CONFIG_SCSI_SATA_SX4 + This option enables support for Promise Serial ATA SX4. + + If unsure, say N. + +CONFIG_SCSI_SATA_SIL + This option enables support for Silicon Image Serial ATA. + + If unsure, say N. + +CONFIG_SCSI_SATA_SIS + This option enables support for SiS Serial ATA 964/180. + + If unsure, say N. + +CONFIG_SCSI_SATA_VIA + This option enables support for VIA Serial ATA. + + If unsure, say N. + +CONFIG_SCSI_SATA_VITESSE + This option enables support for Vitesse VSC7174 Serial ATA. + + If unsure, say N. + Intel/ICP (former GDT SCSI Disk Array) RAID Controller support CONFIG_SCSI_GDTH Formerly called GDT SCSI Disk Array Controller Support. @@ -10840,13 +10949,15 @@ whenever you want). If you want to compile it as a module, say M here and read . -Network delay simualtor -CONFIG_NET_SCH_DELAY - Say Y if you want to delay packets by a fixed amount of - time. This is often useful to simulate network delay when +CONFIG_NET_SCH_NETEM + Say Y if you want to emulate network delay, loss, and packet + re-ordering. This is often useful to simulate networks when testing applications or protocols. - - This code is also available as a module called sch_delay.o + + To compile this driver as a module, choose M here: the module + will be called sch_netem. + + If unsure, say N. Ingress Qdisc CONFIG_NET_SCH_INGRESS @@ -12101,6 +12212,20 @@ module, say M here and read as well as . +CONFIG_E1000_NAPI + 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. + AMD LANCE and PCnet (AT1500 and NE2100) support CONFIG_LANCE If you have a network (Ethernet) card of this type, say Y and read @@ -13407,6 +13532,16 @@ under Linux, say Y here (you must also remember to enable the driver for your HIPPI card below). Most people will say N here. +IBM PowerPC Virtual Ethernet driver support +CONFIG_IBMVETH + This driver supports virtual ethernet adapters on newer IBM iSeries + and pSeries systems. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read . The module + will be called ibmveth.o. + Essential RoadRunner HIPPI PCI adapter support CONFIG_ROADRUNNER Say Y here if this is your PCI HIPPI network card. @@ -16093,6 +16228,27 @@ Say "y" to link the driver statically, or "m" to build a dynamically linked module called "g_ether". +CONFIG_USB_ETH_RNDIS + Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol, + and Microsoft provides redistributable binary RNDIS drivers for + older versions of Windows. + + If you say "y" here, the Ethernet gadget driver will try to provide + a second device configuration, supporting RNDIS to talk to such + Microsoft USB hosts. + +CONFIG_USB_FILE_STORAGE + The File-backed Storage Gadget acts as a USB Mass Storage + disk drive. As its storage repository it can use a regular + file or a block device (in much the same way as the "loop" + device driver), specified as a module parameter. + +CONFIG_USB_FILE_STORAGE_TEST + Say "y" to generate the larger testing version of the + File-backed Storage Gadget, useful for probing the + behavior of USB Mass Storage hosts. Not needed for + normal operation. + Always do synchronous disk IO for UBD CONFIG_BLK_DEV_UBD_SYNC The User-Mode Linux port includes a driver called UBD which will let @@ -17269,7 +17425,7 @@ automounter (amd), which is a pure user space daemon. To use the automounter you need the user-space tools from - ; you also + ; you also want to answer Y to "NFS file system support", below. If you want to compile this as a module ( = code which can be @@ -17427,13 +17583,10 @@ CONFIG_XFS_TRACE Say Y here to get an XFS build with activity tracing enabled. Enabling this option will attach historical information to XFS - inodes, pagebufs, certain locks, the log, the IO path, and a + inodes, buffers, certain locks, the log, the IO path, and a few other key areas within XFS. These traces can be examined using a kernel debugger. - Note that for the pagebuf traces, you will also have to enable - the sysctl in /proc/sys/vm/pagebuf/debug for this to work. - Say N unless you are an XFS developer. Debugging support (EXPERIMENTAL) @@ -23001,22 +23154,20 @@ Linux Bluetooth subsystem consist of several layers: BlueZ Core (HCI device and connection manager, scheduler) - HCI Device drivers (interface to the hardware) - L2CAP Module (L2CAP protocol) - SCO Module (SCO links) - RFCOMM Module (RFCOMM protocol) - BNEP Module (BNEP protocol) - CMTP Module (CMTP protocol) + HCI Device drivers (Interface to the hardware) + SCO Module (SCO audio links) + L2CAP Module (Logical Link Control and Adaptation Protocol) + RFCOMM Module (RFCOMM Protocol) + BNEP Module (Bluetooth Network Encapsulation Protocol) + CMTP Module (CAPI Message Transport Protocol) - Say Y here to enable Linux Bluetooth support and to build BlueZ Core - layer. + Say Y here to compile Bluetooth support into the kernel or say M to + compile it as module (bluez.o). To use Linux Bluetooth subsystem, you will need several user-space utilities like hciconfig and hcid. These utilities and updates to Bluetooth kernel modules are provided in the BlueZ package. - For more information, see . - - If you want to compile BlueZ Core as module (bluez.o) say M here. + For more information, see . L2CAP protocol support CONFIG_BLUEZ_L2CAP @@ -23029,7 +23180,7 @@ SCO links support CONFIG_BLUEZ_SCO - SCO link provides voice transport over Bluetooth. SCO support is + SCO link provides voice transport over Bluetooth. SCO support is required for voice applications like Headset and Audio. Say Y here to compile SCO support into the kernel or say M to @@ -23037,7 +23188,7 @@ RFCOMM protocol support CONFIG_BLUEZ_RFCOMM - RFCOMM provides connection oriented stream transport. RFCOMM + RFCOMM provides connection oriented stream transport. RFCOMM support is required for Dialup Networking, OBEX and other Bluetooth applications. @@ -23051,25 +23202,12 @@ BNEP protocol support CONFIG_BLUEZ_BNEP BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet - emulation layer on top of Bluetooth. BNEP is required for Bluetooth - PAN (Personal Area Network). - - To use BNEP, you will need user-space utilities provided in the - BlueZ-PAN package. - For more information, see . + emulation layer on top of Bluetooth. BNEP is required for + Bluetooth PAN (Personal Area Network). Say Y here to compile BNEP support into the kernel or say M to compile it as module (bnep.o). -CMTP protocol support -CONFIG_BLUEZ_CMTP - CMTP (CAPI Message Transport Protocol) is a transport layer - for CAPI messages. CMTP is required for the Bluetooth Common - ISDN Access Profile. - - Say Y here to compile CMTP support into the kernel or say M to - compile it as module (cmtp.o). - BNEP multicast filter support CONFIG_BLUEZ_BNEP_MC_FILTER This option enables the multicast filter support for BNEP. @@ -23078,6 +23216,15 @@ CONFIG_BLUEZ_BNEP_PROTO_FILTER This option enables the protocol filter support for BNEP. +CMTP protocol support +CONFIG_BLUEZ_CMTP + CMTP (CAPI Message Transport Protocol) is a transport layer + for CAPI messages. CMTP is required for the Bluetooth Common + ISDN Access Profile. + + Say Y here to compile CMTP support into the kernel or say M to + compile it as module (cmtp.o). + HCI UART driver CONFIG_BLUEZ_HCIUART Bluetooth HCI UART driver. @@ -23167,9 +23314,6 @@ 3Com Bluetooth Card (3CRWB6096) HP Bluetooth Card - The HCI BT3C driver uses external firmware loader program provided in - the BlueFW package. For more information, see . - Say Y here to compile support for HCI BT3C devices into the kernel or say M to compile it as module (bt3c_cs.o). @@ -28781,12 +28925,24 @@ The CAST6 encryption algorithm (synonymous with CAST-256) is described in RFC2612. +CONFIG_CRYPTO_TEA + TEA cipher algorithm. + + Tiny Encryption Algorithm is a simple cipher that uses + many rounds for security. It is very fast and uses + little memory. + + Xtendend Tiny Encryption Algorithm is a modifcation to + the TEA algorithm to address a potential key weakness + in the TEA algorithm. + CONFIG_CRYPTO_ARC4 ARC4 cipher algorithm. - This is a stream cipher using keys ranging from 8 bits to 2048 - bits in length. ARC4 is commonly used in protocols such as WEP - and SSL. + ARC4 is a stream cipher using keys ranging from 8 bits to 2048 + bits in length. This algorithm is required for driver-based + WEP, but it should not be for other purposes because of the + weakness of the algorithm. CONFIG_CRYPTO_DEFLATE This is the Deflate algorithm (RFC1951), specified for use in @@ -28794,6 +28950,12 @@ You will most probably want this if using IPSec. +CONFIG_CRYPTO_MICHAEL_MIC + Michael MIC is used for message integrity protection in TKIP + (IEEE 802.11i). This algorithm is required for TKIP, but it + should not be used for other purposes because of the weakness + of the algorithm. + CONFIG_CRYPTO_TEST Quick & dirty crypto test module. diff -urN linux-2.4.26/Documentation/DocBook/Makefile linux-2.4.27/Documentation/DocBook/Makefile --- linux-2.4.26/Documentation/DocBook/Makefile 2002-11-28 15:53:08.000000000 -0800 +++ linux-2.4.27/Documentation/DocBook/Makefile 2004-08-07 16:26:04.533341806 -0700 @@ -2,7 +2,7 @@ kernel-api.sgml parportbook.sgml kernel-hacking.sgml \ kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \ deviceiobook.sgml procfs-guide.sgml tulip-user.sgml \ - journal-api.sgml + journal-api.sgml libata.sgml PS := $(patsubst %.sgml, %.ps, $(BOOKS)) PDF := $(patsubst %.sgml, %.pdf, $(BOOKS)) @@ -79,6 +79,16 @@ $(TOPDIR)/scripts/docgen $(TOPDIR)/arch/i386/kernel/mca.c \ mcabook.sgml +libata.sgml: libata.tmpl $(TOPDIR)/drivers/scsi/libata-core.c \ + $(TOPDIR)/drivers/scsi/libata-scsi.c \ + $(TOPDIR)/drivers/scsi/sata_sil.c \ + $(TOPDIR)/drivers/scsi/sata_via.c + $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/scsi/libata-core.c \ + $(TOPDIR)/drivers/scsi/libata-scsi.c \ + $(TOPDIR)/drivers/scsi/sata_sil.c \ + $(TOPDIR)/drivers/scsi/sata_via.c \ + < libata.tmpl > libata.sgml + videobook.sgml: videobook.tmpl $(TOPDIR)/drivers/media/video/videodev.c $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/media/video/videodev.c \ videobook.sgml diff -urN linux-2.4.26/Documentation/DocBook/libata.tmpl linux-2.4.27/Documentation/DocBook/libata.tmpl --- linux-2.4.26/Documentation/DocBook/libata.tmpl 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.27/Documentation/DocBook/libata.tmpl 2004-08-07 16:26:04.533341806 -0700 @@ -0,0 +1,85 @@ + + + + + libATA Developer's Guide + + + + Jeff + Garzik + + + + + 2003 + Jeff Garzik + + + + + The contents of this file are subject to the Open + Software License version 1.1 that can be found at + http://www.opensource.org/licenses/osl-1.1.txt and is included herein + by reference. + + + + Alternatively, the contents of this file may be used under the terms + of the GNU General Public License version 2 (the "GPL") as distributed + in the kernel source COPYING file, in which case the provisions of + the GPL are applicable instead of the above. If you wish to allow + the use of your version of this file only under the terms of the + GPL and not to allow others to use your version of this file under + the OSL, indicate your decision by deleting the provisions above and + replace them with the notice and other provisions required by the GPL. + If you do not delete the provisions above, a recipient may use your + version of this file under either the OSL or the GPL. + + + + + + + + + Thanks + + The bulk of the ATA knowledge comes thanks to long conversations with + Andre Hedrick (www.linux-ide.org). + + + Thanks to Alan Cox for pointing out similarities + between SATA and SCSI, and in general for motivation to hack on + libata. + + + libata's device detection + method, ata_pio_devchk, and in general all the early probing was + based on extensive study of Hale Landis's probe/reset code in his + ATADRVR driver (www.ata-atapi.com). + + + + + libata Library +!Edrivers/scsi/libata-core.c + + + + libata Core Internals +!Idrivers/scsi/libata-core.c + + + + libata SCSI translation/emulation +!Edrivers/scsi/libata-scsi.c +!Idrivers/scsi/libata-scsi.c + + + + ata_sil Internals +!Idrivers/scsi/sata_sil.c + + + diff -urN linux-2.4.26/Documentation/cciss.txt linux-2.4.27/Documentation/cciss.txt --- linux-2.4.26/Documentation/cciss.txt 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.27/Documentation/cciss.txt 2004-08-07 16:26:04.534341847 -0700 @@ -14,6 +14,8 @@ * SA 6400 * SA 6400 U320 Expansion Module * SA 6i + * SA 6422 + * SA V100 If nodes are not already created in the /dev/cciss directory diff -urN linux-2.4.26/Documentation/crypto/api-intro.txt linux-2.4.27/Documentation/crypto/api-intro.txt --- linux-2.4.26/Documentation/crypto/api-intro.txt 2004-04-14 06:05:24.000000000 -0700 +++ linux-2.4.27/Documentation/crypto/api-intro.txt 2004-08-07 16:26:04.534341847 -0700 @@ -187,6 +187,7 @@ Brian Gladman (AES) Kartikey Mahendra Bhatt (CAST6) Jon Oberheide (ARC4) + Jouni Malinen (Michael MIC) SHA1 algorithm contributors: Jean-Francois Dive diff -urN linux-2.4.26/Documentation/filesystems/hpfs.txt linux-2.4.27/Documentation/filesystems/hpfs.txt --- linux-2.4.26/Documentation/filesystems/hpfs.txt 2001-06-11 19:15:27.000000000 -0700 +++ linux-2.4.27/Documentation/filesystems/hpfs.txt 2004-08-07 16:26:04.535341888 -0700 @@ -1,5 +1,5 @@ -Read/Write HPFS 2.05 -1998-2001, Mikulas Patocka +Read/Write HPFS 2.09 +1998-2004, Mikulas Patocka email: mikulas@artax.karlin.mff.cuni.cz homepage: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi @@ -283,6 +283,14 @@ 2.05 Fixed crash when got mount parameters without = Fixed crash when allocation of anode failed due to full disk Fixed some crashes when block io or inode allocation failed +2.06 Fixed some crash on corrupted disk structures + Better allocation strategy + Reschedule points added so that it doesn't lock CPU long time + It should work in read-only mode on Warp Server +2.07 More fixes for Warp Server. Now it really works +2.08 Creating new files is not so slow on large disks + An attempt to sync deleted file does not generate filesystem error +2.09 Fixed error on extremly fragmented files vim: set textwidth=80: diff -urN linux-2.4.26/Documentation/filesystems/xfs.txt linux-2.4.27/Documentation/filesystems/xfs.txt --- linux-2.4.26/Documentation/filesystems/xfs.txt 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.27/Documentation/filesystems/xfs.txt 2004-08-07 16:26:04.536341929 -0700 @@ -123,9 +123,15 @@ in /proc/fs/xfs/stat. It then immediately reset to "0". fs.xfs.sync_interval (Min: HZ Default: 30*HZ Max: 60*HZ) - The interval at which the xfssyncd thread for xfs filesystems - flushes metadata out to disk. This thread will flush log - activity out, and do some processing on unlinked inodes + The interval at which the xfssyncd thread flushes metadata + out to disk. This thread will flush log activity out, and + do some processing on unlinked inodes. + + fs.xfs.age_buffer (Min: 1*HZ Default: 15*HZ Max: 300*HZ) + The age at which xfsbufd flushes dirty metadata buffers to disk. + + fs.xfs.flush_interval (Min: HZ/2 Default: HZ Max: 30*HZ) + The interval at which xfsbufd scans the dirty metadata buffers list. fs.xfs.error_level (Min: 0 Default: 3 Max: 11) A volume knob for error reporting when internal errors occur. @@ -190,14 +196,3 @@ Setting this to "1" will cause the "noatime" flag set by the chattr(1) command on a directory to be inherited by files in that directory. - - vm.pagebuf.stats_clear (Min: 0 Default: 0 Max: 1) - Setting this to "1" clears accumulated pagebuf statistics - in /proc/fs/pagebuf/stat. It then immediately reset to "0". - - vm.pagebuf.flush_age (Min: 1*HZ Default: 15*HZ Max: 300*HZ) - The age at which dirty metadata buffers are flushed to disk - - vm.pagebuf.flush_int (Min: HZ/2 Default: HZ Max: 30*HZ) - The interval at which the list of dirty metadata buffers is - scanned. diff -urN linux-2.4.26/Documentation/ioctl-number.txt linux-2.4.27/Documentation/ioctl-number.txt --- linux-2.4.26/Documentation/ioctl-number.txt 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.27/Documentation/ioctl-number.txt 2004-08-07 16:26:04.536341929 -0700 @@ -183,5 +183,6 @@ 0xB1 00-1F PPPoX 0xCB 00-1F CBM serial IEC bus in development: - +0xF3 00-3F linux/sisfb.h SiS framebuffer device driver + 0xFE 00-9F Logical Volume Manager diff -urN linux-2.4.26/Documentation/kernel-parameters.txt linux-2.4.27/Documentation/kernel-parameters.txt --- linux-2.4.26/Documentation/kernel-parameters.txt 2004-04-14 06:05:24.000000000 -0700 +++ linux-2.4.27/Documentation/kernel-parameters.txt 2004-08-07 16:26:04.537341970 -0700 @@ -69,8 +69,9 @@ 53c7xx= [HW,SCSI] Amiga SCSI controllers. acpi= [HW,ACPI] Advanced Configuration and Power Interface - force Force ACPI on, even if blacklisted platform - off Disable ACPI + force Enable ACPI if default was off + off Disable ACPI if default was on + noirq Do not use ACPI for IRQ routing (see pci=noacpi) ht Limit ACPI to boot-time LAPIC enumeration for HT, disabling the run-time AML interpreter. strict Be less tolerant of platforms that are not diff -urN linux-2.4.26/Documentation/networking/bridge.txt linux-2.4.27/Documentation/networking/bridge.txt --- linux-2.4.26/Documentation/networking/bridge.txt 2000-11-09 15:57:53.000000000 -0800 +++ linux-2.4.27/Documentation/networking/bridge.txt 2004-08-07 16:26:04.537341970 -0700 @@ -1,11 +1,8 @@ -In order to use the ethernet bridging functionality you'll need the -userspace tools available at http://www.math.leidenuniv.nl/~buytenh/bridge. -The tarball available there contains extensive documentation, but if you -still have questions, don't hesitate to post to the mailing list (more info -at http://www.math.leidenuniv.nl/mailman/listinfo/bridge). You can also -mail me at buytenh@gnu.org. +In order to use the Ethernet bridging functionality, you'll need the +userspace tools. These programs and documentation are available +at http://bridge.sourceforge.net. The download page is +http://prdownloads.sourceforge.net/bridge. +If you still have questions, don't hesitate to post to the mailing list +(more info http://lists.osdl.org/mailman/listinfo/bridge). - -Lennert Buytenhek - diff -urN linux-2.4.26/Documentation/networking/ip-sysctl.txt linux-2.4.27/Documentation/networking/ip-sysctl.txt --- linux-2.4.26/Documentation/networking/ip-sysctl.txt 2004-04-14 06:05:25.000000000 -0700 +++ linux-2.4.27/Documentation/networking/ip-sysctl.txt 2004-08-07 16:26:04.538342011 -0700 @@ -289,6 +289,44 @@ changed would be a Beowulf compute cluster. Default: 0 +tcp_vegas_cong_avoid - BOOLEAN + Enable TCP Vegas congestion avoidance algorithm. + TCP Vegas is a sender-side only change to TCP that anticipates + the onset of congestion by estimating the bandwidth. TCP Vegas + adjusts the sending rate by modifying the congestion + window. TCP Vegas should provide less packet loss, but it is + not as aggressive as TCP Reno. + Default:0 + +tcp_bic - BOOLEAN + Enable BIC TCP congestion control algorithm. + BIC-TCP is a sender-side only change that ensures a linear RTT + fairness under large windows while offering both scalability and + bounded TCP-friendliness. The protocol combines two schemes + called additive increase and binary search increase. When the + congestion window is large, additive increase with a large + increment ensures linear RTT fairness as well as good + scalability. Under small congestion windows, binary search + increase provides TCP friendliness. + Default: 0 + +tcp_bic_low_window - INTEGER + Sets the threshold window (in packets) where BIC TCP starts to + adjust the congestion window. Below this threshold BIC TCP behaves + the same as the default TCP Reno. + Default: 14 + +tcp_bic_fast_convergence - BOOLEAN + Forces BIC TCP to more quickly respond to changes in congestion + window. Allows two flows sharing the same connection to converge + more rapidly. + Default: 1 + +tcp_default_win_scale - INTEGER + Sets the minimum window scale TCP will negotiate for on all + conections. + Default: 7 + ip_local_port_range - 2 INTEGERS Defines the local port range that is used by TCP and UDP to choose the local port. The first number is the first, the @@ -603,9 +641,11 @@ disabled if local forwarding is enabled. autoconf - BOOLEAN - Configure link-local addresses using L2 hardware addresses. + Autoconfigure addresses using Prefix Information in Router + Advertisements. - Default: TRUE + Functional default: enabled if accept_ra is enabled. + disabled if accept_ra is disabled. dad_transmits - INTEGER The amount of Duplicate Address Detection probes to send. diff -urN linux-2.4.26/Documentation/networking/packet_mmap.txt linux-2.4.27/Documentation/networking/packet_mmap.txt --- linux-2.4.26/Documentation/networking/packet_mmap.txt 2004-04-14 06:05:25.000000000 -0700 +++ linux-2.4.27/Documentation/networking/packet_mmap.txt 2004-08-07 16:26:04.540342093 -0700 @@ -1,11 +1,3 @@ - -DaveM: - -If you agree with it I will send two small patches to modify -kernel's configure help. - - Ulisses - -------------------------------------------------------------------------------- + ABSTRACT -------------------------------------------------------------------------------- @@ -405,8 +397,3 @@ Jesse Brandeburg, for fixing my grammathical/spelling errors ->>> EOF -- -To unsubscribe from this list: send the line "unsubscribe linux-net" in -the body of a message to majordomo@vger.kernel.org -More majordomo info at http://vger.kernel.org/majordomo-info.html \ No newline at end of file diff -urN linux-2.4.26/Documentation/usb/silverlink.txt linux-2.4.27/Documentation/usb/silverlink.txt --- linux-2.4.26/Documentation/usb/silverlink.txt 2002-11-28 15:53:08.000000000 -0800 +++ linux-2.4.27/Documentation/usb/silverlink.txt 2004-08-07 16:26:04.540342093 -0700 @@ -8,7 +8,7 @@ INTRODUCTION: This is a driver for the TI-GRAPH LINK USB (aka SilverLink) cable, a cable -designed by TI for connecting their TI8x/9x calculators to a computer +designed by TI for connecting their TI8x/9x graphing handhelds to a computer (PC or Mac usually). If you need more information, please visit the 'SilverLink drivers' homepage @@ -16,10 +16,8 @@ WHAT YOU NEED: -A TI calculator of course and a program capable to communicate with your -calculator. -TiLP will work for sure (since I am his developer !). yal92 may be able to use -it by changing tidev for tiglusb (may require some hacking...). +A TI calculator/handheld of course and a program capable to communicate with +your calculator. A good choice is TiLP (http://www.tilp.info). HOW TO USE IT: @@ -58,14 +56,19 @@ QUIRKS: The following problem seems to be specific to the link cable since it appears -on all platforms (Linux, Windows, Mac OS-X). +on all platforms (Linux, Windows, Mac OS-X). A guy told me it was a common but +weird behaviour with Cypress microcontrollers (it uses an CY7C64013). -In some very particular cases, the driver returns with success but +In some very particular cases, the driver returns with success (no error) but without any data. The application should retry a read operation at least once. +This problem and the need to issue IOCTL_TIUSB_RESET_PIPES before doing any +packet transfer (like TI's software do) make this driver difficult to use in +pure raw access. + HOW TO CONTACT US: -You can email me at roms@lpg.ticalc.org. Please prefix the subject line +You can email me at roms@tilp.info. Please prefix the subject line with "TIGLUSB: " so that I am certain to notice your message. You can also mail JB at jb@jblache.org: he has written the first release of this driver but he better knows the Mac OS-X driver. @@ -73,4 +76,4 @@ CREDITS: The code is based on dabusb.c, printer.c and scanner.c ! -The driver has been developed independantly of Texas Instruments. +The driver has been developed without any support from Texas Instruments Inc. diff -urN linux-2.4.26/MAINTAINERS linux-2.4.27/MAINTAINERS --- linux-2.4.26/MAINTAINERS 2004-04-14 06:05:25.000000000 -0700 +++ linux-2.4.27/MAINTAINERS 2004-08-07 16:26:04.542342175 -0700 @@ -113,6 +113,12 @@ W: http://sourceforge.net/projects/gkernel/ S: Maintained +8169 10/100/1000 GIGABIT ETHERNET DRIVER +P: Francois Romieu +M: romieu@fr.zoreil.com +L: netdev@oss.sgi.com +S: Maintained + 8250/16?50 (AND CLONE UARTS) SERIAL DRIVER P: Theodore Ts'o M: tytso@mit.edu @@ -328,6 +334,8 @@ M: maxk@qualcomm.com L: bluez-devel@lists.sf.net W: http://bluez.sf.net +W: http://www.bluez.org +W: http://www.holtmann.org/linux/bluetooth/ S: Maintained BLUETOOTH RFCOMM LAYER @@ -335,7 +343,6 @@ M: marcel@holtmann.org P: Maxim Krasnyansky M: maxk@qualcomm.com -W: http://bluez.sf.net S: Maintained BLUETOOTH BNEP LAYER @@ -343,65 +350,60 @@ M: marcel@holtmann.org P: Maxim Krasnyansky M: maxk@qualcomm.com -W: http://bluez.sf.net S: Maintained BLUETOOTH CMTP LAYER P: Marcel Holtmann M: marcel@holtmann.org -W: http://www.holtmann.org/linux/bluetooth/ S: Maintained -BLUETOOTH HCI USB DRIVER +BLUETOOTH HCI UART DRIVER P: Marcel Holtmann M: marcel@holtmann.org P: Maxim Krasnyansky M: maxk@qualcomm.com -W: http://bluez.sf.net S: Maintained -BLUETOOTH HCI UART DRIVER +BLUETOOTH HCI USB DRIVER P: Marcel Holtmann M: marcel@holtmann.org P: Maxim Krasnyansky M: maxk@qualcomm.com -W: http://bluez.sf.net +S: Maintained + +BLUETOOTH HCI BCM203X DRIVER +P: Marcel Holtmann +M: marcel@holtmann.org S: Maintained BLUETOOTH HCI BFUSB DRIVER P: Marcel Holtmann M: marcel@holtmann.org -W: http://www.holtmann.org/linux/bluetooth/ S: Maintained BLUETOOTH HCI DTL1 DRIVER P: Marcel Holtmann M: marcel@holtmann.org -W: http://www.holtmann.org/linux/bluetooth/ S: Maintained BLUETOOTH HCI BLUECARD DRIVER P: Marcel Holtmann M: marcel@holtmann.org -W: http://www.holtmann.org/linux/bluetooth/ S: Maintained BLUETOOTH HCI BT3C DRIVER P: Marcel Holtmann M: marcel@holtmann.org -W: http://www.holtmann.org/linux/bluetooth/ S: Maintained BLUETOOTH HCI BTUART DRIVER P: Marcel Holtmann M: marcel@holtmann.org -W: http://www.holtmann.org/linux/bluetooth/ S: Maintained BLUETOOTH HCI VHCI DRIVER P: Maxim Krasnyansky M: maxk@qualcomm.com -W: http://bluez.sf.net S: Maintained BONDING DRIVER @@ -954,11 +956,21 @@ M: tigran@veritas.com S: Maintained +INTEL PRO/100 ETHERNET SUPPORT +P: John Ronciak +M: john.ronciak@intel.com +P: Ganesh Venkatesan +M: Ganesh.Venkatesan@intel.com +W: http://sourceforge.net/projects/e1000/ +S: Supported + INTEL PRO/1000 GIGABIT ETHERNET SUPPORT P: Jeb Cramer M: cramerj@intel.com -P: Scott Feldman -M: scott.feldman@intel.com +P: John Ronciak +M: john.ronciak@intel.com +P: Ganesh Venkatesan +M: Ganesh.Venkatesan@intel.com W: http://sourceforge.net/projects/e1000/ S: Supported @@ -1141,11 +1153,14 @@ L: linux-scsi@vger.kernel.org S: Maintained -M68K -P: Jes Sorensen -M: jes@trained-monkey.org -W: http://www.clark.net/pub/lawrencc/linux/index.html +M68K ARCHITECTURE +P: Geert Uytterhoeven +M: geert@linux-m68k.org +P: Roman Zippel +M: zippel@linux-m68k.org L: linux-m68k@lists.linux-m68k.org +W: http://www.linux-m68k.org/ +W: http://linux-m68k-cvs.ubb.ca/ S: Maintained M68K ON APPLE MACINTOSH @@ -1306,6 +1321,8 @@ M: jmorris@intercode.com.au P: Hideaki YOSHIFUJI M: yoshfuji@linux-ipv6.org +P: Patrick McHardy +M: kaber@coreworks.de L: netdev@oss.sgi.com S: Maintained @@ -1638,6 +1655,12 @@ W: http://www.weinigel.se S: Supported +SERIAL ATA (SATA) SUBSYSTEM: +P: Jeff Garzik +M: jgarzik@pobox.com +L: linux-ide@vger.kernel.org +S: Supported + SGI VISUAL WORKSTATION 320 AND 540 P: Bent Hagemark M: bh@sgi.com @@ -2161,7 +2184,7 @@ XFS FILESYSTEM P: Silicon Graphics Inc -M: owner-xfs@oss.sgi.com +M: xfs-masters@oss.sgi.com M: nathans@sgi.com L: linux-xfs@oss.sgi.com W: http://oss.sgi.com/projects/xfs diff -urN linux-2.4.26/Makefile linux-2.4.27/Makefile --- linux-2.4.26/Makefile 2004-04-14 06:05:41.000000000 -0700 +++ linux-2.4.27/Makefile 2004-08-07 16:26:07.119448065 -0700 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 4 -SUBLEVEL = 26 +SUBLEVEL = 27 EXTRAVERSION = KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -175,6 +175,7 @@ DRIVERS-$(CONFIG_PPC32) += drivers/macintosh/macintosh.o DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.o DRIVERS-$(CONFIG_ISAPNP) += drivers/pnp/pnp.o +DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o DRIVERS-$(CONFIG_VT) += drivers/video/video.o DRIVERS-$(CONFIG_PARIDE) += drivers/block/paride/paride.a DRIVERS-$(CONFIG_HAMRADIO) += drivers/net/hamradio/hamradio.o @@ -186,7 +187,6 @@ DRIVERS-$(CONFIG_HIL) += drivers/hil/hil.o DRIVERS-$(CONFIG_I2O) += drivers/message/i2o/i2o.o DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda.o -DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o DRIVERS-$(CONFIG_GSC) += drivers/gsc/gscbus.o diff -urN linux-2.4.26/arch/alpha/kernel/sys_eiger.c linux-2.4.27/arch/alpha/kernel/sys_eiger.c --- linux-2.4.26/arch/alpha/kernel/sys_eiger.c 2001-10-12 15:35:53.000000000 -0700 +++ linux-2.4.27/arch/alpha/kernel/sys_eiger.c 2004-08-07 16:26:04.543342216 -0700 @@ -193,27 +193,20 @@ case 0x0f: bridge_count = 4; break; /* 4 */ }; - /* Check first for the built-in bridges on hose 0. */ - if (hose->index == 0 - && PCI_SLOT(dev->bus->self->devfn) > 20-bridge_count) { - slot = PCI_SLOT(dev->devfn); - } else { - /* Must be a card-based bridge. */ - do { - /* Check for built-in bridges on hose 0. */ - if (hose->index == 0 - && (PCI_SLOT(dev->bus->self->devfn) - > 20 - bridge_count)) { - slot = PCI_SLOT(dev->devfn); - break; - } - pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); - - /* Move up the chain of bridges. */ - dev = dev->bus->self; - /* Slot of the next bridge. */ + slot = PCI_SLOT(dev->devfn); + while (dev->bus->self) { + /* Check for built-in bridges on hose 0. */ + if (hose->index == 0 + && (PCI_SLOT(dev->bus->self->devfn) + > 20 - bridge_count)) { slot = PCI_SLOT(dev->devfn); - } while (dev->bus->self); + break; + } + /* Must be a card-based bridge. */ + pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); + + /* Move up the chain of bridges. */ + dev = dev->bus->self; } *pinp = pin; return slot; diff -urN linux-2.4.26/arch/alpha/kernel/sys_takara.c linux-2.4.27/arch/alpha/kernel/sys_takara.c --- linux-2.4.26/arch/alpha/kernel/sys_takara.c 2000-10-27 10:55:01.000000000 -0700 +++ linux-2.4.27/arch/alpha/kernel/sys_takara.c 2004-08-07 16:26:04.544342258 -0700 @@ -230,8 +230,12 @@ int slot = PCI_SLOT(dev->devfn); int pin = *pinp; unsigned int ctlreg = inl(0x500); - unsigned int busslot = PCI_SLOT(dev->bus->self->devfn); + unsigned int busslot; + if (!dev->bus->self) + return slot; + + busslot = PCI_SLOT(dev->bus->self->devfn); /* Check for built-in bridges. */ if (dev->bus->number != 0 && busslot > 16 diff -urN linux-2.4.26/arch/cris/drivers/eeprom.c linux-2.4.27/arch/cris/drivers/eeprom.c --- linux-2.4.26/arch/cris/drivers/eeprom.c 2003-08-25 04:44:39.000000000 -0700 +++ linux-2.4.27/arch/cris/drivers/eeprom.c 2004-08-07 16:26:04.545342299 -0700 @@ -506,7 +506,7 @@ static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t *off) { int read=0; - unsigned long p = file->f_pos; + unsigned long p = *off; unsigned char page; @@ -540,7 +540,7 @@ return -EFAULT; } - if( (p + count) > eeprom.size) + if(count > eeprom.size - p) { /* truncate count */ count = eeprom.size - p; @@ -560,7 +560,7 @@ if(read > 0) { - file->f_pos += read; + *off = p + read; } eeprom.busy--; @@ -605,7 +605,7 @@ { restart = 0; written = 0; - p = file->f_pos; + p = *off; while( (written < count) && (p < eeprom.size)) @@ -733,10 +733,10 @@ eeprom.busy--; wake_up_interruptible(&eeprom.wait_q); - if (written == 0 && file->f_pos >= eeprom.size){ + if (written == 0 && p >= eeprom.size){ return -ENOSPC; } - file->f_pos += written; + *off = p; return written; } diff -urN linux-2.4.26/arch/i386/defconfig linux-2.4.27/arch/i386/defconfig --- linux-2.4.26/arch/i386/defconfig 2004-04-14 06:05:25.000000000 -0700 +++ linux-2.4.27/arch/i386/defconfig 2004-08-07 16:26:04.546342340 -0700 @@ -105,6 +105,11 @@ # CONFIG_HOTPLUG_PCI_COMPAQ is not set # CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set # CONFIG_HOTPLUG_PCI_IBM is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set +# CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE is not set +# CONFIG_HOTPLUG_PCI_SHPC_PHPRM_LEGACY is not set +# CONFIG_HOTPLUG_PCI_PCIE is not set +# CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE is not set CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y @@ -151,6 +156,7 @@ # CONFIG_CISS_MONITOR_THREAD is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_SX8 is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_RAM is not set @@ -266,6 +272,7 @@ # CONFIG_WDC_ALI15X3 is not set # CONFIG_BLK_DEV_AMD74XX is not set # CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_ATIIXP is not set # CONFIG_BLK_DEV_CMD64X is not set # CONFIG_BLK_DEV_TRIFLEX is not set # CONFIG_BLK_DEV_CY82C693 is not set @@ -294,6 +301,7 @@ # CONFIG_BLK_DEV_ATARAID is not set # CONFIG_BLK_DEV_ATARAID_PDC is not set # CONFIG_BLK_DEV_ATARAID_HPT is not set +# CONFIG_BLK_DEV_ATARAID_MEDLEY is not set # CONFIG_BLK_DEV_ATARAID_SII is not set # @@ -337,6 +345,14 @@ # CONFIG_SCSI_AM53C974 is not set # CONFIG_SCSI_MEGARAID is not set # CONFIG_SCSI_MEGARAID2 is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_SATA_SVW 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 @@ -453,6 +469,7 @@ # CONFIG_FEALNX is not set # CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set +# CONFIG_FORCEDETH is not set # CONFIG_NE3210 is not set # CONFIG_ES3210 is not set # CONFIG_8139CP is not set diff -urN linux-2.4.26/arch/i386/kernel/acpi.c linux-2.4.27/arch/i386/kernel/acpi.c --- linux-2.4.26/arch/i386/kernel/acpi.c 2004-04-14 06:05:25.000000000 -0700 +++ linux-2.4.27/arch/i386/kernel/acpi.c 2004-08-07 16:26:04.547342381 -0700 @@ -59,7 +59,10 @@ Boot-time Configuration -------------------------------------------------------------------------- */ -int acpi_noirq __initdata = 0; /* skip ACPI IRQ initialization */ +#ifdef CONFIG_ACPI_PCI +int acpi_noirq __initdata; /* skip ACPI IRQ initialization */ +int acpi_pci_disabled __initdata; /* skip ACPI PCI scan and IRQ initialization */ +#endif int acpi_ht __initdata = 1; /* enable HT */ enum acpi_irq_model_id acpi_irq_model; @@ -105,6 +108,35 @@ return ((unsigned char *) base + offset); } +#ifdef CONFIG_ACPI_MMCONFIG + +u32 pci_mmcfg_base_addr; + +static int __init +acpi_parse_mcfg(unsigned long phys_addr, + unsigned long size) +{ + struct acpi_table_mcfg *mcfg = NULL; + + if (!phys_addr || !size) + return -EINVAL; + + mcfg = (struct acpi_table_mcfg *) __acpi_map_table(phys_addr, size); + if (!mcfg) { + printk(KERN_WARNING PREFIX "Unable to map MCFG\n"); + return -ENODEV; + } + + if (mcfg->base_reserved) { + printk(KERN_ERR PREFIX "MMCONFIG not in low 4GB of memory\n"); + return -ENODEV; + } + + pci_mmcfg_base_addr = mcfg->base_address; + + return 0; +} +#endif /* CONFIG_ACPI_MMCONFIG */ #ifdef CONFIG_X86_LOCAL_APIC @@ -406,6 +438,15 @@ return result; } +#ifdef CONFIG_ACPI_MMCONFIG + result = acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); + if (result < 0) { + printk(KERN_ERR PREFIX "Error %d parsing MCFG\n", result); + } else if (result > 1) { + printk(KERN_WARNING PREFIX "Multiple MCFG tables exist\n"); + } +#endif + #ifdef CONFIG_X86_LOCAL_APIC /* @@ -491,6 +532,11 @@ return 1; } + result = mp_irqs_alloc(); /* Dynamically allocate mp_irqs[] */ + if (result < 0) { + acpi_noirq = 1; + return result; + } result = acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic); if (!result) { @@ -502,9 +548,6 @@ return result; } - /* Build a default routing table for legacy (ISA) interrupts. */ - mp_config_acpi_legacy_irqs(); - /* Record sci_int for use when looking for MADT sci_int override */ acpi_table_parse(ACPI_FADT, acpi_parse_fadt); @@ -522,6 +565,9 @@ if (!acpi_sci_override_gsi) acpi_sci_ioapic_setup(acpi_fadt.sci_int, 0, 0); + /* Fill in identity legacy mapings where no override */ + mp_config_acpi_legacy_irqs(); + result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); diff -urN linux-2.4.26/arch/i386/kernel/edd.c linux-2.4.27/arch/i386/kernel/edd.c --- linux-2.4.26/arch/i386/kernel/edd.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.27/arch/i386/kernel/edd.c 2004-08-07 16:26:04.548342422 -0700 @@ -46,9 +46,8 @@ MODULE_DESCRIPTION("proc interface to BIOS EDD information"); MODULE_LICENSE("GPL"); -#define EDD_VERSION "0.10 2003-Dec-05" +#define EDD_VERSION "0.11 2004-Jun-21" #define EDD_DEVICE_NAME_SIZE 16 -#define REPORT_URL "http://domsch.com/linux/edd30/results.html" #define left (count - (p - page) - 1) @@ -312,10 +311,6 @@ } out: - p += snprintf(p, left, "\nPlease check %s\n", REPORT_URL); - p += snprintf(p, left, "to see if this device has been reported. If not,\n"); - p += snprintf(p, left, "please send the information requested there.\n"); - return proc_calc_metrics(page, start, off, count, eof, (p - page)); } @@ -405,7 +400,7 @@ return proc_calc_metrics(page, start, off, count, eof, 0); } - p += snprintf(p, left, "0x%x\n", info->params.num_default_cylinders); + p += snprintf(p, left, "%u\n", info->params.num_default_cylinders); return proc_calc_metrics(page, start, off, count, eof, (p - page)); } @@ -418,7 +413,7 @@ return proc_calc_metrics(page, start, off, count, eof, 0); } - p += snprintf(p, left, "0x%x\n", info->params.num_default_heads); + p += snprintf(p, left, "%u\n", info->params.num_default_heads); return proc_calc_metrics(page, start, off, count, eof, (p - page)); } @@ -431,7 +426,7 @@ return proc_calc_metrics(page, start, off, count, eof, 0); } - p += snprintf(p, left, "0x%x\n", info->params.sectors_per_track); + p += snprintf(p, left, "%u\n", info->params.sectors_per_track); return proc_calc_metrics(page, start, off, count, eof, (p - page)); } @@ -444,7 +439,7 @@ return proc_calc_metrics(page, start, off, count, eof, 0); } - p += snprintf(p, left, "0x%llx\n", info->params.number_of_sectors); + p += snprintf(p, left, "%llu\n", info->params.number_of_sectors); return proc_calc_metrics(page, start, off, count, eof, (p - page)); } diff -urN linux-2.4.26/arch/i386/kernel/i8259.c linux-2.4.27/arch/i386/kernel/i8259.c --- linux-2.4.26/arch/i386/kernel/i8259.c 2001-09-17 23:03:09.000000000 -0700 +++ linux-2.4.27/arch/i386/kernel/i8259.c 2004-08-07 16:26:04.548342422 -0700 @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -498,7 +499,8 @@ outb(LATCH >> 8 , 0x40); /* MSB */ #ifndef CONFIG_VISWS - setup_irq(2, &irq2); + if (!acpi_ioapic) + setup_irq(2, &irq2); #endif /* diff -urN linux-2.4.26/arch/i386/kernel/io_apic.c linux-2.4.27/arch/i386/kernel/io_apic.c --- linux-2.4.26/arch/i386/kernel/io_apic.c 2004-04-14 06:05:25.000000000 -0700 +++ linux-2.4.27/arch/i386/kernel/io_apic.c 2004-08-07 16:26:04.550342504 -0700 @@ -1691,18 +1691,10 @@ /* * - * IRQ's that are handled by the old PIC in all cases: + * IRQ's that are handled by the PIC in the MPS IOAPIC case. * - IRQ2 is the cascade IRQ, and cannot be a io-apic IRQ. * Linux doesn't really care, as it's not actually used * for any interrupt handling anyway. - * - There used to be IRQ13 here as well, but all - * MPS-compliant must not use it for FPU coupling and we - * want to use exception 16 anyway. And there are - * systems who connect it to an I/O APIC for other uses. - * Thus we don't mark it special any longer. - * - * Additionally, something is definitely wrong with irq9 - * on PIIX4 boards. */ #define PIC_IRQS (1<<2) @@ -1710,7 +1702,11 @@ { enable_IO_APIC(); - io_apic_irqs = ~PIC_IRQS; + if (acpi_ioapic) + io_apic_irqs = ~0; /* all IRQs go through IOAPIC */ + else + io_apic_irqs = ~PIC_IRQS; + printk("ENABLING IO-APIC IRQs\n"); /* @@ -1872,7 +1868,7 @@ entry.vector = assign_irq_vector(irq); - printk(KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> " + 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); diff -urN linux-2.4.26/arch/i386/kernel/mpparse.c linux-2.4.27/arch/i386/kernel/mpparse.c --- linux-2.4.26/arch/i386/kernel/mpparse.c 2004-04-14 06:05:25.000000000 -0700 +++ linux-2.4.27/arch/i386/kernel/mpparse.c 2004-08-07 16:26:04.551342545 -0700 @@ -1104,6 +1104,20 @@ } +/* allocate mp_irqs[] for ACPI parsing table parsing */ +int __init mp_irqs_alloc() +{ + int size = (MAX_IRQ_SOURCES * sizeof(int)) * 4; + + mp_irqs = (struct mpc_config_intsrc *)alloc_bootmem(size); + if (!mp_irqs) { + printk(KERN_ERR "mp_irqs_alloc(): alloc_bootmem(%d) failed!\n", size); + return -ENOMEM; + } + return 0; +} + + void __init mp_override_legacy_irq ( u8 bus_irq, u8 polarity, @@ -1111,8 +1125,6 @@ u32 global_irq) { struct mpc_config_intsrc intsrc; - int i = 0; - int found = 0; int ioapic = -1; int pin = -1; @@ -1145,23 +1157,9 @@ (intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus, intsrc.mpc_srcbusirq, intsrc.mpc_dstapic, intsrc.mpc_dstirq); - /* - * If an existing [IOAPIC.PIN -> IRQ] routing entry exists we override it. - * Otherwise create a new entry (e.g. global_irq == 2). - */ - for (i = 0; i < mp_irq_entries; i++) { - if ((mp_irqs[i].mpc_srcbus == intsrc.mpc_srcbus) - && (mp_irqs[i].mpc_srcbusirq == intsrc.mpc_srcbusirq)) { - mp_irqs[i] = intsrc; - found = 1; - break; - } - } - if (!found) { - mp_irqs[mp_irq_entries] = intsrc; - if (++mp_irq_entries == MAX_IRQ_SOURCES) - panic("Max # of irq sources exceeded!\n"); - } + mp_irqs[mp_irq_entries] = intsrc; + if (++mp_irq_entries == MAX_IRQ_SOURCES) + panic("Max # of irq sources exceeded!\n"); return; } @@ -1179,7 +1177,6 @@ int count; count = (MAX_MP_BUSSES * sizeof(int)) * 4; - count += (MAX_IRQ_SOURCES * sizeof(int)) * 4; bus_data = alloc_bootmem(count); if (!bus_data) { panic("Fatal: can't allocate bus memory for ACPI legacy IRQ!"); @@ -1188,7 +1185,7 @@ mp_bus_id_to_node = (int *)&bus_data[(MAX_MP_BUSSES * sizeof(int))]; mp_bus_id_to_local = (int *)&bus_data[(MAX_MP_BUSSES * sizeof(int)) * 2]; mp_bus_id_to_pci_bus = (int *)&bus_data[(MAX_MP_BUSSES * sizeof(int)) * 3]; - mp_irqs = (struct mpc_config_intsrc *)&bus_data[(MAX_MP_BUSSES * sizeof(int)) * 4]; + for (i = 0; i < MAX_MP_BUSSES; ++i) mp_bus_id_to_pci_bus[i] = -1; @@ -1206,13 +1203,20 @@ return; /* - * Use the default configuration for the IRQs 0-15. These may be + * Use the default configuration for the IRQs 0-15. Unless * overriden by (MADT) interrupt source override entries. */ for (i = 0; i < 16; i++) { + int idx; - if (i == 2) - continue; /* Don't connect IRQ2 */ + for (idx = 0; idx < mp_irq_entries; idx++) + if (mp_irqs[idx].mpc_srcbus == MP_ISA_BUS && + (mp_irqs[idx].mpc_dstapic == mp_ioapics[ioapic].mpc_apicid) && + (mp_irqs[idx].mpc_srcbusirq == i || + mp_irqs[idx].mpc_dstirq == i)) + break; + if (idx != mp_irq_entries) + continue; /* IRQ already used */ mp_irqs[mp_irq_entries].mpc_type = MP_INTSRC; mp_irqs[mp_irq_entries].mpc_irqflag = 0; /* Conforming */ @@ -1308,11 +1312,13 @@ if (!io_apic_set_pci_routing(ioapic, ioapic_pin, irq, edge_level, active_high_low)) entry->irq = irq; - printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d\n", - entry->id.segment, entry->id.bus, - entry->id.device, ('A' + entry->pin), - mp_ioapic_routing[ioapic].apic_id, ioapic_pin, - entry->irq); + printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d" + " -> IRQ %d %s %s\n", entry->id.segment, entry->id.bus, + entry->id.device, ('A' + entry->pin), + mp_ioapic_routing[ioapic].apic_id, ioapic_pin, + entry->irq, edge_level ? "level" : "edge", + active_high_low ? "low" : "high"); + } print_IO_APIC(); diff -urN linux-2.4.26/arch/i386/kernel/mtrr.c linux-2.4.27/arch/i386/kernel/mtrr.c --- linux-2.4.26/arch/i386/kernel/mtrr.c 2003-06-13 07:51:29.000000000 -0700 +++ linux-2.4.27/arch/i386/kernel/mtrr.c 2004-08-07 16:26:04.553342627 -0700 @@ -1648,11 +1648,17 @@ static ssize_t mtrr_read (struct file *file, char *buf, size_t len, loff_t *ppos) { - if (*ppos >= ascii_buf_bytes) return 0; - if (*ppos + len > ascii_buf_bytes) len = ascii_buf_bytes - *ppos; - if ( copy_to_user (buf, ascii_buffer + *ppos, len) ) return -EFAULT; - *ppos += len; - return len; + loff_t pos = *ppos; + if (pos < 0 || pos >= ascii_buf_bytes) + return 0; + if (len > ascii_buf_bytes - pos) + len = ascii_buf_bytes - pos; + if (copy_to_user(buf, ascii_buffer + pos, len)) + return -EFAULT; + pos += len; + *ppos = pos; + + return len; } /* End Function mtrr_read */ static ssize_t mtrr_write (struct file *file, const char *buf, size_t len, diff -urN linux-2.4.26/arch/i386/kernel/pci-irq.c linux-2.4.27/arch/i386/kernel/pci-irq.c --- linux-2.4.26/arch/i386/kernel/pci-irq.c 2004-04-14 06:05:25.000000000 -0700 +++ linux-2.4.27/arch/i386/kernel/pci-irq.c 2004-08-07 16:26:04.554342668 -0700 @@ -1067,6 +1067,7 @@ { u8 pin; extern int interrupt_line_quirk; + struct pci_dev *temp_dev; pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) { @@ -1076,9 +1077,44 @@ if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE && !(dev->class & 0x5)) return; - if (io_apic_assign_pci_irqs) - msg = " Probably buggy MP table."; - else if (pci_probe & PCI_BIOS_IRQ_SCAN) + if (io_apic_assign_pci_irqs) { + int irq; + + if (pin) { + pin--; /* interrupt pins are numbered starting from 1 */ + irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin); + /* + * Busses behind bridges are typically not listed in the MP-table. + * In this case we have to look up the IRQ based on the parent bus, + * parent slot, and pin number. The SMP code detects such bridged + * busses itself so we should get into this branch reliably. + */ + temp_dev = dev; + while (irq < 0 && dev->bus->parent) { /* go back to the bridge */ + struct pci_dev * bridge = dev->bus->self; + + pin = (pin + PCI_SLOT(dev->devfn)) % 4; + irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, + PCI_SLOT(bridge->devfn), pin); + if (irq >= 0) + printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get irq %d\n", + bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq); + dev = bridge; + } + dev = temp_dev; + if (irq >= 0) { +#ifdef CONFIG_PCI_USE_VECTOR + if (!platform_legacy_irq(irq)) + irq = IO_APIC_VECTOR(irq); +#endif + printk(KERN_INFO "PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n", + dev->bus->number, PCI_SLOT(dev->devfn), pin, irq); + dev->irq = irq; + return; + } else + msg = " Probably buggy MP table."; + } + } else if (pci_probe & PCI_BIOS_IRQ_SCAN) msg = ""; else msg = " Please try using pci=biosirq."; diff -urN linux-2.4.26/arch/i386/kernel/pci-pc.c linux-2.4.27/arch/i386/kernel/pci-pc.c --- linux-2.4.26/arch/i386/kernel/pci-pc.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.27/arch/i386/kernel/pci-pc.c 2004-08-07 16:26:04.555342710 -0700 @@ -1321,13 +1321,46 @@ * system to PCI bus no matter what are their window settings, so they are * "transparent" (or subtractive decoding) from programmers point of view. */ -static void __init pci_fixup_transparent_bridge(struct pci_dev *dev) +static void __devinit pci_fixup_transparent_bridge(struct pci_dev *dev) { if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && (dev->device & 0xff00) == 0x2400) dev->transparent = 1; } +/* + * Fixup for C1 Halt Disconnect problem on nForce2 systems. + * + * From information provided by "Allen Martin" : + * + * A hang is caused when the CPU generates a very fast CONNECT/HALT cycle + * sequence. Workaround is to set the SYSTEM_IDLE_TIMEOUT to 80 ns. + * This allows the state-machine and timer to return to a proper state within + * 80 ns of the CONNECT and probe appearing together. Since the CPU will not + * issue another HALT within 80 ns of the initial HALT, the failure condition + * is avoided. + */ +static void __devinit pci_fixup_nforce2(struct pci_dev *dev) +{ + u32 val, fixed_val; + u8 rev; + + pci_read_config_byte(dev, PCI_REVISION_ID, &rev); + + /* + * Chip Old value New value + * C17 0x1F0FFF01 0x1F01FF01 + * C18D 0x9F0FFF01 0x9F01FF01 + */ + fixed_val = rev < 0xC1 ? 0x1F01FF01 : 0x9F01FF01; + + pci_read_config_dword(dev, 0x6c, &val); + if (val != fixed_val) { + printk(KERN_WARNING "PCI: nForce2 C1 Halt Disconnect fixup\n"); + pci_write_config_dword(dev, 0x6c, fixed_val); + } +} + struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx }, @@ -1343,6 +1376,7 @@ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_via_northbridge_bug }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, pci_fixup_ncr53c810 }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_fixup_transparent_bridge }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2, pci_fixup_nforce2}, { 0 } }; @@ -1433,7 +1467,6 @@ if (!acpi_noirq && !acpi_pci_irq_init()) { pci_using_acpi_prt = 1; printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n"); - printk(KERN_INFO "PCI: if you experience problems, try using option 'pci=noacpi' or even 'acpi=off'\n"); } #endif if (!pci_using_acpi_prt) { diff -urN linux-2.4.26/arch/i386/kernel/setup.c linux-2.4.27/arch/i386/kernel/setup.c --- linux-2.4.26/arch/i386/kernel/setup.c 2004-04-14 06:05:25.000000000 -0700 +++ linux-2.4.27/arch/i386/kernel/setup.c 2004-08-07 16:26:04.557342792 -0700 @@ -2333,6 +2333,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 }, @@ -2443,6 +2444,8 @@ printk (KERN_INFO "CPU: L1 I cache: %dK", l1i); if ( l1d ) printk(", L1 D cache: %dK\n", l1d); + else + printk("\n"); if ( l2 ) printk(KERN_INFO "CPU: L2 cache: %dK\n", l2); diff -urN linux-2.4.26/arch/i386/mm/fault.c linux-2.4.27/arch/i386/mm/fault.c --- linux-2.4.26/arch/i386/mm/fault.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.27/arch/i386/mm/fault.c 2004-08-07 16:26:04.558342833 -0700 @@ -71,7 +71,7 @@ if (!vma || vma->vm_start != start) goto bad_area; if (!(vma->vm_flags & VM_WRITE)) - goto bad_area;; + goto bad_area; } return 1; diff -urN linux-2.4.26/arch/i386/mm/pageattr.c linux-2.4.27/arch/i386/mm/pageattr.c --- linux-2.4.26/arch/i386/mm/pageattr.c 2002-11-28 15:53:09.000000000 -0800 +++ linux-2.4.27/arch/i386/mm/pageattr.c 2004-08-07 16:26:04.558342833 -0700 @@ -52,11 +52,9 @@ static void flush_kernel_map(void * address) { - if (!test_bit(X86_FEATURE_SELFSNOOP, boot_cpu_data.x86_capability)) { - /* Could use CLFLUSH here if the CPU supports it (Hammer,P4) */ - if (boot_cpu_data.x86_model >= 4) - asm volatile("wbinvd":::"memory"); - } + /* Could use CLFLUSH here if the CPU supports it (Hammer,P4) */ + if (boot_cpu_data.x86_model >= 4) + asm volatile("wbinvd":::"memory"); /* Do global flush here to work around large page flushing errata in some early Athlons */ diff -urN linux-2.4.26/arch/ia64/configs/dig linux-2.4.27/arch/ia64/configs/dig --- linux-2.4.26/arch/ia64/configs/dig 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.27/arch/ia64/configs/dig 2004-08-07 16:26:04.559342874 -0700 @@ -28,9 +28,9 @@ # CONFIG_MCKINLEY is not set # CONFIG_IA64_GENERIC is not set CONFIG_IA64_DIG=y -# CONFIG_IA64_HP_SIM is not set # CONFIG_IA64_HP_ZX1 is not set # CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_HP_SIM 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 @@ -116,7 +116,6 @@ # # SCTP Configuration (EXPERIMENTAL) # -CONFIG_IPV6_SCTP__=y # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set # CONFIG_VLAN_8021Q is not set @@ -265,6 +264,7 @@ # CONFIG_WDC_ALI15X3 is not set # CONFIG_BLK_DEV_AMD74XX is not set # CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_ATIIXP is not set # CONFIG_BLK_DEV_CMD64X is not set # CONFIG_BLK_DEV_TRIFLEX is not set # CONFIG_BLK_DEV_CY82C693 is not set @@ -293,6 +293,7 @@ # CONFIG_BLK_DEV_ATARAID is not set # CONFIG_BLK_DEV_ATARAID_PDC is not set # CONFIG_BLK_DEV_ATARAID_HPT is not set +# CONFIG_BLK_DEV_ATARAID_MEDLEY is not set # CONFIG_BLK_DEV_ATARAID_SII is not set # @@ -430,6 +431,7 @@ # CONFIG_FEALNX is not set # CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set +# CONFIG_FORCEDETH is not set # CONFIG_NE3210 is not set # CONFIG_ES3210 is not set # CONFIG_8139CP is not set @@ -511,6 +513,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # CONFIG_INPUT_JOYDEV is not set CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_UINPUT is not set # # Character devices @@ -586,6 +589,7 @@ # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_SCx200 is not set # CONFIG_SCx200_GPIO is not set # CONFIG_INTEL_RNG is not set # CONFIG_HW_RANDOM is not set @@ -727,6 +731,11 @@ # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set # CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_TRACE is not set +# CONFIG_XFS_DEBUG is not set # # Network File Systems @@ -940,7 +949,6 @@ # CONFIG_USB_RTL8150 is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set -# CONFIG_USB_AX8817X is not set # CONFIG_USB_CDCETHER is not set # CONFIG_USB_USBNET is not set diff -urN linux-2.4.26/arch/ia64/configs/generic linux-2.4.27/arch/ia64/configs/generic --- linux-2.4.26/arch/ia64/configs/generic 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.27/arch/ia64/configs/generic 2004-08-07 16:26:04.560342915 -0700 @@ -28,9 +28,9 @@ # CONFIG_MCKINLEY is not set CONFIG_IA64_GENERIC=y # CONFIG_IA64_DIG is not set -# CONFIG_IA64_HP_SIM is not set # CONFIG_IA64_HP_ZX1 is not set # CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_HP_SIM 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 @@ -116,7 +116,6 @@ # # SCTP Configuration (EXPERIMENTAL) # -CONFIG_IPV6_SCTP__=y # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set # CONFIG_VLAN_8021Q is not set @@ -265,6 +264,7 @@ # CONFIG_WDC_ALI15X3 is not set # CONFIG_BLK_DEV_AMD74XX is not set # CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_ATIIXP is not set CONFIG_BLK_DEV_CMD64X=y # CONFIG_BLK_DEV_TRIFLEX is not set # CONFIG_BLK_DEV_CY82C693 is not set @@ -294,6 +294,7 @@ # CONFIG_BLK_DEV_ATARAID is not set # CONFIG_BLK_DEV_ATARAID_PDC is not set # CONFIG_BLK_DEV_ATARAID_HPT is not set +# CONFIG_BLK_DEV_ATARAID_MEDLEY is not set # CONFIG_BLK_DEV_ATARAID_SII is not set # @@ -436,6 +437,7 @@ # CONFIG_FEALNX is not set # CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set +# CONFIG_FORCEDETH is not set # CONFIG_NE3210 is not set # CONFIG_ES3210 is not set # CONFIG_8139CP is not set @@ -517,6 +519,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # CONFIG_INPUT_JOYDEV is not set CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_UINPUT is not set # # Character devices @@ -592,6 +595,7 @@ # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_SCx200 is not set # CONFIG_SCx200_GPIO is not set # CONFIG_FETCHOP is not set # CONFIG_INTEL_RNG is not set @@ -734,6 +738,11 @@ # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set # CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_TRACE is not set +# CONFIG_XFS_DEBUG is not set # # Network File Systems @@ -947,7 +956,6 @@ # CONFIG_USB_RTL8150 is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set -# CONFIG_USB_AX8817X is not set # CONFIG_USB_CDCETHER is not set # CONFIG_USB_USBNET is not set diff -urN linux-2.4.26/arch/ia64/configs/numa linux-2.4.27/arch/ia64/configs/numa --- linux-2.4.26/arch/ia64/configs/numa 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.27/arch/ia64/configs/numa 2004-08-07 16:26:04.561342956 -0700 @@ -28,9 +28,9 @@ # CONFIG_MCKINLEY is not set CONFIG_IA64_GENERIC=y # CONFIG_IA64_DIG is not set -# CONFIG_IA64_HP_SIM is not set # CONFIG_IA64_HP_ZX1 is not set # CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_HP_SIM 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 @@ -118,7 +118,6 @@ # # SCTP Configuration (EXPERIMENTAL) # -CONFIG_IPV6_SCTP__=y # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set # CONFIG_VLAN_8021Q is not set @@ -267,6 +266,7 @@ # CONFIG_WDC_ALI15X3 is not set # CONFIG_BLK_DEV_AMD74XX is not set # CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_ATIIXP is not set CONFIG_BLK_DEV_CMD64X=y # CONFIG_BLK_DEV_TRIFLEX is not set # CONFIG_BLK_DEV_CY82C693 is not set @@ -296,6 +296,7 @@ # CONFIG_BLK_DEV_ATARAID is not set # CONFIG_BLK_DEV_ATARAID_PDC is not set # CONFIG_BLK_DEV_ATARAID_HPT is not set +# CONFIG_BLK_DEV_ATARAID_MEDLEY is not set # CONFIG_BLK_DEV_ATARAID_SII is not set # @@ -438,6 +439,7 @@ # CONFIG_FEALNX is not set # CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set +# CONFIG_FORCEDETH is not set # CONFIG_NE3210 is not set # CONFIG_ES3210 is not set # CONFIG_8139CP is not set @@ -519,6 +521,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # CONFIG_INPUT_JOYDEV is not set CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_UINPUT is not set # # Character devices @@ -594,6 +597,7 @@ # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_SCx200 is not set # CONFIG_SCx200_GPIO is not set # CONFIG_FETCHOP is not set # CONFIG_INTEL_RNG is not set @@ -736,6 +740,11 @@ # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set # CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_TRACE is not set +# CONFIG_XFS_DEBUG is not set # # Network File Systems @@ -949,7 +958,6 @@ # CONFIG_USB_RTL8150 is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set -# CONFIG_USB_AX8817X is not set # CONFIG_USB_CDCETHER is not set # CONFIG_USB_USBNET is not set diff -urN linux-2.4.26/arch/ia64/configs/ski linux-2.4.27/arch/ia64/configs/ski --- linux-2.4.26/arch/ia64/configs/ski 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.27/arch/ia64/configs/ski 2004-08-07 16:26:04.562342997 -0700 @@ -28,9 +28,9 @@ # CONFIG_MCKINLEY is not set # CONFIG_IA64_GENERIC is not set # CONFIG_IA64_DIG is not set -CONFIG_IA64_HP_SIM=y # CONFIG_IA64_HP_ZX1 is not set # CONFIG_IA64_SGI_SN2 is not set +CONFIG_IA64_HP_SIM=y # CONFIG_IA64_PAGE_SIZE_4KB is not set # CONFIG_IA64_PAGE_SIZE_8KB is not set CONFIG_IA64_PAGE_SIZE_16KB=y @@ -83,7 +83,6 @@ # # SCTP Configuration (EXPERIMENTAL) # -CONFIG_IPV6_SCTP__=y # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set # CONFIG_VLAN_8021Q is not set @@ -202,6 +201,7 @@ # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_JOYDEV is not set # CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_UINPUT is not set # # Character devices @@ -256,6 +256,7 @@ # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_SCx200 is not set # CONFIG_SCx200_GPIO is not set # CONFIG_INTEL_RNG is not set # CONFIG_HW_RANDOM is not set @@ -374,6 +375,11 @@ # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set # CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_TRACE is not set +# CONFIG_XFS_DEBUG is not set # # Network File Systems diff -urN linux-2.4.26/arch/ia64/configs/zx1 linux-2.4.27/arch/ia64/configs/zx1 --- linux-2.4.26/arch/ia64/configs/zx1 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.27/arch/ia64/configs/zx1 2004-08-07 16:26:04.563343038 -0700 @@ -28,9 +28,9 @@ CONFIG_MCKINLEY=y # CONFIG_IA64_GENERIC is not set # CONFIG_IA64_DIG is not set -# CONFIG_IA64_HP_SIM is not set CONFIG_IA64_HP_ZX1=y # CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_HP_SIM 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 @@ -117,7 +117,6 @@ # # SCTP Configuration (EXPERIMENTAL) # -CONFIG_IPV6_SCTP__=y # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set # CONFIG_VLAN_8021Q is not set @@ -266,6 +265,7 @@ # CONFIG_WDC_ALI15X3 is not set # CONFIG_BLK_DEV_AMD74XX is not set # CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_ATIIXP is not set # CONFIG_BLK_DEV_CMD64X is not set # CONFIG_BLK_DEV_TRIFLEX is not set # CONFIG_BLK_DEV_CY82C693 is not set @@ -294,6 +294,7 @@ # CONFIG_BLK_DEV_ATARAID is not set # CONFIG_BLK_DEV_ATARAID_PDC is not set # CONFIG_BLK_DEV_ATARAID_HPT is not set +# CONFIG_BLK_DEV_ATARAID_MEDLEY is not set # CONFIG_BLK_DEV_ATARAID_SII is not set # @@ -431,6 +432,7 @@ # CONFIG_FEALNX is not set # CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set +# CONFIG_FORCEDETH is not set # CONFIG_NE3210 is not set # CONFIG_ES3210 is not set # CONFIG_8139CP is not set @@ -512,6 +514,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # CONFIG_INPUT_JOYDEV is not set CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_UINPUT is not set # # Character devices @@ -587,6 +590,7 @@ # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_SCx200 is not set # CONFIG_SCx200_GPIO is not set # CONFIG_INTEL_RNG is not set # CONFIG_HW_RANDOM is not set @@ -728,6 +732,11 @@ # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set # CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_TRACE is not set +# CONFIG_XFS_DEBUG is not set # # Network File Systems @@ -941,7 +950,6 @@ # CONFIG_USB_RTL8150 is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set -# CONFIG_USB_AX8817X is not set # CONFIG_USB_CDCETHER is not set # CONFIG_USB_USBNET is not set diff -urN linux-2.4.26/arch/ia64/defconfig linux-2.4.27/arch/ia64/defconfig --- linux-2.4.26/arch/ia64/defconfig 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.27/arch/ia64/defconfig 2004-08-07 16:26:04.564343079 -0700 @@ -28,9 +28,9 @@ # CONFIG_MCKINLEY is not set CONFIG_IA64_GENERIC=y # CONFIG_IA64_DIG is not set -# CONFIG_IA64_HP_SIM is not set # CONFIG_IA64_HP_ZX1 is not set # CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_HP_SIM 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 @@ -116,7 +116,6 @@ # # SCTP Configuration (EXPERIMENTAL) # -CONFIG_IPV6_SCTP__=y # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set # CONFIG_VLAN_8021Q is not set @@ -265,6 +264,7 @@ # CONFIG_WDC_ALI15X3 is not set # CONFIG_BLK_DEV_AMD74XX is not set # CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_ATIIXP is not set CONFIG_BLK_DEV_CMD64X=y # CONFIG_BLK_DEV_TRIFLEX is not set # CONFIG_BLK_DEV_CY82C693 is not set @@ -294,6 +294,7 @@ # CONFIG_BLK_DEV_ATARAID is not set # CONFIG_BLK_DEV_ATARAID_PDC is not set # CONFIG_BLK_DEV_ATARAID_HPT is not set +# CONFIG_BLK_DEV_ATARAID_MEDLEY is not set # CONFIG_BLK_DEV_ATARAID_SII is not set # @@ -436,6 +437,7 @@ # CONFIG_FEALNX is not set # CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set +# CONFIG_FORCEDETH is not set # CONFIG_NE3210 is not set # CONFIG_ES3210 is not set # CONFIG_8139CP is not set @@ -517,6 +519,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # CONFIG_INPUT_JOYDEV is not set CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_UINPUT is not set # # Character devices @@ -592,6 +595,7 @@ # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_SCx200 is not set # CONFIG_SCx200_GPIO is not set # CONFIG_FETCHOP is not set # CONFIG_INTEL_RNG is not set @@ -734,6 +738,11 @@ # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set # CONFIG_UFS_FS_WRITE is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_TRACE is not set +# CONFIG_XFS_DEBUG is not set # # Network File Systems @@ -947,7 +956,6 @@ # CONFIG_USB_RTL8150 is not set # CONFIG_USB_KAWETH is not set # CONFIG_USB_CATC is not set -# CONFIG_USB_AX8817X is not set # CONFIG_USB_CDCETHER is not set # CONFIG_USB_USBNET is not set diff -urN linux-2.4.26/arch/ia64/ia32/binfmt_elf32.c linux-2.4.27/arch/ia64/ia32/binfmt_elf32.c --- linux-2.4.26/arch/ia64/ia32/binfmt_elf32.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.27/arch/ia64/ia32/binfmt_elf32.c 2004-08-07 16:26:04.564343079 -0700 @@ -17,6 +17,8 @@ #include #include +#include "elfcore32.h" + #define CONFIG_BINFMT_ELF32 /* Override some function names */ diff -urN linux-2.4.26/arch/ia64/ia32/elfcore32.h linux-2.4.27/arch/ia64/ia32/elfcore32.h --- linux-2.4.26/arch/ia64/ia32/elfcore32.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.27/arch/ia64/ia32/elfcore32.h 2004-08-07 16:26:04.565343120 -0700 @@ -0,0 +1,133 @@ +/* + * IA-32 ELF core dump support. + * + * Copyright (C) 2003 Arun Sharma + * + * Derived from the x86_64 version + */ +#ifndef _ELFCORE32_H_ +#define _ELFCORE32_H_ + +#define USE_ELF_CORE_DUMP 1 + +/* Override elfcore.h */ +#define _LINUX_ELFCORE_H 1 +typedef unsigned int elf_greg_t; + +#define ELF_NGREG (sizeof (struct user_regs_struct32) / sizeof(elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef struct ia32_user_i387_struct elf_fpregset_t; +typedef struct ia32_user_fxsr_struct elf_fpxregset_t; + +struct elf_siginfo +{ + int si_signo; /* signal number */ + int si_code; /* extra code */ + int si_errno; /* errno */ +}; + +#define jiffies_to_timeval(a,b) do { (b)->tv_usec = 0; (b)->tv_sec = (a)/HZ; }while(0) + +struct compat_timeval +{ + int tv_sec, tv_usec; +}; + +struct elf_prstatus +{ + struct elf_siginfo pr_info; /* Info associated with signal */ + short pr_cursig; /* Current signal */ + unsigned int pr_sigpend; /* Set of pending signals */ + unsigned int pr_sighold; /* Set of held signals */ + pid_t pr_pid; + pid_t pr_ppid; + pid_t pr_pgrp; + pid_t pr_sid; + struct compat_timeval pr_utime; /* User time */ + struct compat_timeval pr_stime; /* System time */ + struct compat_timeval pr_cutime; /* Cumulative user time */ + struct compat_timeval pr_cstime; /* Cumulative system time */ + elf_gregset_t pr_reg; /* GP registers */ + int pr_fpvalid; /* True if math co-processor being used. */ +}; + +#define ELF_PRARGSZ (80) /* Number of chars for args */ + +struct elf_prpsinfo +{ + char pr_state; /* numeric process state */ + char pr_sname; /* char for pr_state */ + char pr_zomb; /* zombie */ + char pr_nice; /* nice val */ + unsigned int pr_flag; /* flags */ + __u16 pr_uid; + __u16 pr_gid; + pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid; + /* Lots missing */ + char pr_fname[16]; /* filename of executable */ + char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */ +}; + +#define ELF_CORE_COPY_REGS(pr_reg, regs) \ + pr_reg[0] = regs->r11; \ + pr_reg[1] = regs->r9; \ + pr_reg[2] = regs->r10; \ + pr_reg[3] = regs->r14; \ + pr_reg[4] = regs->r15; \ + pr_reg[5] = regs->r13; \ + pr_reg[6] = regs->r8; \ + pr_reg[7] = regs->r16 & 0xffff; \ + pr_reg[8] = (regs->r16 >> 16) & 0xffff; \ + pr_reg[9] = (regs->r16 >> 32) & 0xffff; \ + pr_reg[10] = (regs->r16 >> 48) & 0xffff; \ + pr_reg[11] = regs->r1; \ + pr_reg[12] = regs->cr_iip; \ + pr_reg[13] = regs->r17 & 0xffff; \ + asm volatile ("mov %0=ar.eflag ;;" \ + : "=r"(pr_reg[14])); \ + pr_reg[15] = regs->r12; \ + pr_reg[16] = (regs->r17 >> 16) & 0xffff; + +static inline void elf_core_copy_regs(elf_gregset_t *elfregs, + struct pt_regs *regs) +{ + ELF_CORE_COPY_REGS((*elfregs), regs) +} + +static inline int elf_core_copy_task_regs(struct task_struct *t, + elf_gregset_t* elfregs) +{ + struct pt_regs *pp = ia64_task_regs(t); + ELF_CORE_COPY_REGS((*elfregs), pp); + return 1; +} + +static inline int +elf_core_copy_task_fpregs(struct task_struct *tsk, elf_fpregset_t *fpu) +{ + struct ia32_user_i387_struct *fpstate = (void*)fpu; + + if (!tsk->used_math) + return 0; + + save_ia32_fpstate(tsk, fpstate); + + return 1; +} + +#define ELF_CORE_COPY_XFPREGS 1 +static inline int +elf_core_copy_task_xfpregs(struct task_struct *tsk, elf_fpxregset_t *xfpu) +{ + struct ia32_user_fxsr_struct *fpxstate = (void*) xfpu; + + if (!tsk->used_math) + return 0; + + save_ia32_fpxstate(tsk, fpxstate); + + return 1; +} + +#endif /* _ELFCORE32_H_ */ diff -urN linux-2.4.26/arch/ia64/ia32/sys_ia32.c linux-2.4.27/arch/ia64/ia32/sys_ia32.c --- linux-2.4.26/arch/ia64/ia32/sys_ia32.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.27/arch/ia64/ia32/sys_ia32.c 2004-08-07 16:26:04.568343244 -0700 @@ -2949,7 +2949,7 @@ return; } -static int +int save_ia32_fpstate (struct task_struct *tsk, struct ia32_user_i387_struct *save) { struct switch_stack *swp; @@ -3011,7 +3011,7 @@ return 0; } -static int +int save_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *save) { struct switch_stack *swp; diff -urN linux-2.4.26/arch/ia64/kernel/efi.c linux-2.4.27/arch/ia64/kernel/efi.c --- linux-2.4.26/arch/ia64/kernel/efi.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.27/arch/ia64/kernel/efi.c 2004-08-07 16:26:04.569343285 -0700 @@ -673,8 +673,7 @@ for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { md = p; if (md->type == EFI_MEMORY_MAPPED_IO_PORT_SPACE) { - /* paranoia attribute checking */ - if (md->attribute == (EFI_MEMORY_UC | EFI_MEMORY_RUNTIME)) + if (md->attribute & EFI_MEMORY_UC) return md->phys_addr; } } diff -urN linux-2.4.26/arch/ia64/kernel/efivars.c linux-2.4.27/arch/ia64/kernel/efivars.c --- linux-2.4.26/arch/ia64/kernel/efivars.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.27/arch/ia64/kernel/efivars.c 2004-08-07 16:26:04.570343326 -0700 @@ -364,6 +364,7 @@ int ret; const int max_nr_entries = 7; /* num ptrs to tables we could expose */ const int max_line_len = 80; + loff_t pos = *ppos; if (!efi.systab) return 0; @@ -388,13 +389,13 @@ if (efi.boot_info) length += sprintf(proc_buffer + length, "BOOTINFO=0x%lx\n", __pa(efi.boot_info)); - if (*ppos >= length) { + if (pos != (unsigned) pos || pos >= length) { ret = 0; goto out; } - data = proc_buffer + file->f_pos; - size = length - file->f_pos; + data = proc_buffer + pos; + size = length - pos; if (size > count) size = count; if (copy_to_user(buffer, data, size)) { @@ -402,7 +403,7 @@ goto out; } - *ppos += size; + *ppos = pos + size; ret = size; out: diff -urN linux-2.4.26/arch/ia64/kernel/palinfo.c linux-2.4.27/arch/ia64/kernel/palinfo.c --- linux-2.4.26/arch/ia64/kernel/palinfo.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.27/arch/ia64/kernel/palinfo.c 2004-08-07 16:26:04.570343326 -0700 @@ -509,10 +509,10 @@ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - "Enable Cache Line Repl. Exclusive", "Enable Cache Line Repl. Shared", + "Enable Cache Line Repl. Exclusive", "Disable Transaction Queuing", - "Disable Reponse Error Checking", + "Disable Response Error Checking", "Disable Bus Error Checking", "Disable Bus Requester Internal Error Signalling", "Disable Bus Requester Error Signalling", diff -urN linux-2.4.26/arch/ia64/kernel/perfmon.c linux-2.4.27/arch/ia64/kernel/perfmon.c --- linux-2.4.26/arch/ia64/kernel/perfmon.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.27/arch/ia64/kernel/perfmon.c 2004-08-07 16:26:04.574343490 -0700 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -887,6 +888,8 @@ DBprintk(("Cannot allocate vma\n")); goto error_kmem; } + memset(vma, 0, sizeof(*vma)); + /* * partially initialize the vma for the sampling buffer * @@ -3166,62 +3169,111 @@ } } -/* for debug only */ -static int -pfm_proc_info(char *page) +#define PFM_PROC_SHOW_HEADER ((void *)NR_CPUS+1) + +static void * +pfm_proc_start(struct seq_file *m, loff_t *pos) { - char *p = page; - int i; - - p += sprintf(p, "fastctxsw : %s\n", pfm_sysctl.fastctxsw > 0 ? "Yes": "No"); - p += sprintf(p, "ovfl_mask : 0x%lx\n", pmu_conf.ovfl_val); - - for(i=0; i < NR_CPUS; i++) { - if (cpu_online(i) == 0) continue; - p += sprintf(p, "CPU%-2d overflow intrs : %lu\n", i, pfm_stats[i].pfm_ovfl_intr_count); - p += sprintf(p, "CPU%-2d spurious intrs : %lu\n", i, pfm_stats[i].pfm_spurious_ovfl_intr_count); - p += sprintf(p, "CPU%-2d recorded samples : %lu\n", i, pfm_stats[i].pfm_recorded_samples_count); - p += sprintf(p, "CPU%-2d smpl buffer full : %lu\n", i, pfm_stats[i].pfm_full_smpl_buffer_count); - p += sprintf(p, "CPU%-2d syst_wide : %d\n", i, cpu_data(i)->pfm_syst_info & PFM_CPUINFO_SYST_WIDE ? 1 : 0); - p += sprintf(p, "CPU%-2d dcr_pp : %d\n", i, cpu_data(i)->pfm_syst_info & PFM_CPUINFO_DCR_PP ? 1 : 0); - p += sprintf(p, "CPU%-2d exclude idle : %d\n", i, cpu_data(i)->pfm_syst_info & PFM_CPUINFO_EXCL_IDLE ? 1 : 0); - p += sprintf(p, "CPU%-2d owner : %d\n", i, pmu_owners[i].owner ? pmu_owners[i].owner->pid: -1); - p += sprintf(p, "CPU%-2d activations : %lu\n", i, pmu_owners[i].activation_number); + if (*pos == 0) { + return PFM_PROC_SHOW_HEADER; } - LOCK_PFS(); - - p += sprintf(p, "proc_sessions : %u\n" - "sys_sessions : %u\n" - "sys_use_dbregs : %u\n" - "ptrace_use_dbregs : %u\n", - pfm_sessions.pfs_task_sessions, - pfm_sessions.pfs_sys_sessions, - pfm_sessions.pfs_sys_use_dbregs, - pfm_sessions.pfs_ptrace_use_dbregs); - - UNLOCK_PFS(); - - return p - page; + while (*pos <= NR_CPUS) { + if (cpu_online(*pos - 1)) { + return (void *)*pos; + } + ++*pos; + } + return NULL; +} + +static void * +pfm_proc_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return pfm_proc_start(m, pos); +} + +static void +pfm_proc_stop(struct seq_file *m, void *v) +{ } -/* /proc interface, for debug only */ +static void +pfm_proc_show_header(struct seq_file *m) +{ + seq_printf(m, + "perfmon version : %u.%u\n" + "fastctxsw : %s\n" + "ovfl_mask : 0x%lx\n", + PFM_VERSION_MAJ, PFM_VERSION_MIN, + pfm_sysctl.fastctxsw > 0 ? "Yes": "No", + pmu_conf.ovfl_val); + + LOCK_PFS(); + + seq_printf(m, + "proc_sessions : %u\n" + "sys_sessions : %u\n" + "sys_use_dbregs : %u\n" + "ptrace_use_dbregs : %u\n", + pfm_sessions.pfs_task_sessions, + pfm_sessions.pfs_sys_sessions, + pfm_sessions.pfs_sys_use_dbregs, + pfm_sessions.pfs_ptrace_use_dbregs); + + UNLOCK_PFS(); +} + static int -perfmon_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data) +pfm_proc_show(struct seq_file *m, void *v) { - int len = pfm_proc_info(page); + int cpu; - if (len <= off+count) *eof = 1; + if (v == PFM_PROC_SHOW_HEADER) { + pfm_proc_show_header(m); + return 0; + } - *start = page + off; - len -= off; + /* show info for CPU (v - 1) */ - if (len>count) len = count; - if (len<0) len = 0; + cpu = (long)v - 1; + seq_printf(m, + "CPU%-2d overflow intrs : %lu\n" + "CPU%-2d spurious intrs : %lu\n" + "CPU%-2d recorded samples : %lu\n" + "CPU%-2d smpl buffer full : %lu\n" + "CPU%-2d syst_wide : %d\n" + "CPU%-2d dcr_pp : %d\n" + "CPU%-2d exclude idle : %d\n" + "CPU%-2d owner : %d\n" + "CPU%-2d activations : %lu\n", + cpu, pfm_stats[cpu].pfm_ovfl_intr_count, + cpu, pfm_stats[cpu].pfm_spurious_ovfl_intr_count, + cpu, pfm_stats[cpu].pfm_recorded_samples_count, + cpu, pfm_stats[cpu].pfm_full_smpl_buffer_count, + cpu, cpu_data(cpu)->pfm_syst_info & PFM_CPUINFO_SYST_WIDE ? 1 : 0, + cpu, cpu_data(cpu)->pfm_syst_info & PFM_CPUINFO_DCR_PP ? 1 : 0, + cpu, cpu_data(cpu)->pfm_syst_info & PFM_CPUINFO_EXCL_IDLE ? 1 : 0, + cpu, pmu_owners[cpu].owner ? pmu_owners[cpu].owner->pid: -1, + cpu, pmu_owners[cpu].activation_number); - return len; + return 0; } - + +struct seq_operations pfm_seq_ops = { + .start = pfm_proc_start, + .next = pfm_proc_next, + .stop = pfm_proc_stop, + .show = pfm_proc_show +}; + +static int +pfm_proc_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &pfm_seq_ops); +} + /* * we come here as soon as local_cpu_data->pfm_syst_wide is set. this happens * during pfm_enable() hence before pfm_start(). We cannot assume monitoring @@ -4448,6 +4500,13 @@ return 0; } +static struct file_operations pfm_proc_fops = { + .open = pfm_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + /* * perfmon initialization routine, called from the initcall() table */ @@ -4498,11 +4557,15 @@ /* * for now here for debug purposes */ - perfmon_dir = create_proc_read_entry ("perfmon", 0, 0, perfmon_read_entry, NULL); + perfmon_dir = create_proc_entry("perfmon", S_IRUGO, NULL); if (perfmon_dir == NULL) { printk(KERN_ERR "perfmon: cannot create /proc entry, perfmon disabled\n"); return -1; } + /* + * install customized file operations for /proc/perfmon entry + */ + perfmon_dir->proc_fops = &pfm_proc_fops; /* * create /proc/sys/kernel/perfmon diff -urN linux-2.4.26/arch/ia64/kernel/salinfo.c linux-2.4.27/arch/ia64/kernel/salinfo.c --- linux-2.4.26/arch/ia64/kernel/salinfo.c 2004-04-14 06:05:26.000000000 -0700 +++ linux-2.4.27/arch/ia64/kernel/salinfo.c 2004-08-07 16:26:04.574343490 -0700 @@ -451,6 +451,7 @@ size_t size; u8 *buf; u64 bufsize; + loff_t pos = *ppos; if (data->state == STATE_LOG_RECORD) { buf = data->log_buffer; @@ -462,17 +463,17 @@ buf = NULL; bufsize = 0; } - if (*ppos >= bufsize) + if (pos != (unsigned)pos || pos >= bufsize) return 0; - saldata = buf + file->f_pos; - size = bufsize - file->f_pos; + saldata = buf + pos; + size = bufsize - pos; if (size > count) size = count; if (copy_to_user(buffer, saldata, size)) return -EFAULT; - *ppos += size; + *ppos = pos + size; return size; } diff -urN linux-2.4.26/arch/ia64/kernel/unwind.c linux-2.4.27/arch/ia64/kernel/unwind.c --- linux-2.4.26/arch/ia64/kernel/unwind.c 2004-04-14 06:05:26.000000000 -0700 +++ linux-2.4.27/arch/ia64/kernel/unwind.c 2004-08-07 16:26:04.576343572 -0700 @@ -1750,7 +1750,7 @@ if (!state->pri_unat_loc) state->pri_unat_loc = &state->sw->ar_unat; /* register off. is a multiple of 8, so the least 3 bits (type) are 0 */ - s[dst+1] = (*state->pri_unat_loc - s[dst]) | UNW_NAT_MEMSTK; + s[dst+1] = ((unsigned long) state->pri_unat_loc - s[dst]) | UNW_NAT_MEMSTK; break; case UNW_INSN_SETNAT_TYPE: diff -urN linux-2.4.26/arch/ia64/mm/hugetlbpage.c linux-2.4.27/arch/ia64/mm/hugetlbpage.c --- linux-2.4.26/arch/ia64/mm/hugetlbpage.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.27/arch/ia64/mm/hugetlbpage.c 2004-08-07 16:26:04.577343613 -0700 @@ -73,8 +73,12 @@ pte_t *pte = NULL; pgd = pgd_offset(mm, taddr); - pmd = pmd_offset(pgd, taddr); - pte = pte_offset(pmd, taddr); + if (pgd_present(*pgd)) { + pmd = pmd_offset(pgd, taddr); + if (pmd_present(*pmd)) + pte = pte_offset(pmd, taddr); + } + return pte; } @@ -269,7 +273,7 @@ for (address = start; address < end; address += HPAGE_SIZE) { pte = huge_pte_offset(mm, address); - if (pte_none(*pte)) + if (!pte || pte_none(*pte)) continue; page = pte_page(*pte); huge_page_release(page); diff -urN linux-2.4.26/arch/m68k/ifpsp060/iskeleton.S linux-2.4.27/arch/m68k/ifpsp060/iskeleton.S --- linux-2.4.26/arch/m68k/ifpsp060/iskeleton.S 2003-06-13 07:51:31.000000000 -0700 +++ linux-2.4.27/arch/m68k/ifpsp060/iskeleton.S 2004-08-07 16:26:04.577343613 -0700 @@ -196,14 +196,58 @@ | Expected outputs: | d0 = 0 -> success; non-zero -> failure | -| Linux/68k: As long as ints are disabled, no swapping out should -| occur (hopefully...) +| Linux/m68k: Make sure the page is properly paged in, so we use +| plpaw and handle any exception here. The kernel must not be +| preempted until _060_unlock_page(), so that the page stays mapped. | .global _060_real_lock_page _060_real_lock_page: - clr.l %d0 + move.l %d2,-(%sp) + | load sfc/dfc + tst.b %d0 + jne 1f + moveq #1,%d0 + jra 2f +1: moveq #5,%d0 +2: movec.l %dfc,%d2 + movec.l %d0,%dfc + movec.l %d0,%sfc + + clr.l %d0 + | prefetch address + .chip 68060 + move.l %a0,%a1 +1: plpaw (%a1) + addq.w #1,%a0 + tst.b %d1 + jeq 2f + addq.w #2,%a0 +2: plpaw (%a0) +3: .chip 68k + + | restore sfc/dfc + movec.l %d2,%dfc + movec.l %d2,%sfc + move.l (%sp)+,%d2 rts +.section __ex_table,"a" + .align 4 + .long 1b,11f + .long 2b,21f +.previous +.section .fixup,"ax" + .even +11: move.l #0x020003c0,%d0 + or.l %d2,%d0 + swap %d0 + jra 3b +21: move.l #0x02000bc0,%d0 + or.l %d2,%d0 + swap %d0 + jra 3b +.previous + | | _060_unlock_page(): | @@ -216,8 +260,7 @@ | d0 = `xxxxxxff -> supervisor; `xxxxxx00 -> user | d1 = `xxxxxxff -> longword; `xxxxxx00 -> word | -| Linux/68k: As we do no special locking operation, also no unlocking -| is needed... +| Linux/m68k: perhaps reenable preemption here... .global _060_real_unlock_page _060_real_unlock_page: diff -urN linux-2.4.26/arch/m68k/kernel/setup.c linux-2.4.27/arch/m68k/kernel/setup.c --- linux-2.4.26/arch/m68k/kernel/setup.c 2003-06-13 07:51:31.000000000 -0700 +++ linux-2.4.27/arch/m68k/kernel/setup.c 2004-08-07 16:26:04.578343655 -0700 @@ -244,6 +244,18 @@ else if (CPU_IS_060) m68k_is040or060 = 6; + if (CPU_IS_060) { + u32 pcr; + + asm (".chip 68060; movec %%pcr,%0; .chip 68k" + : "=d" (pcr)); + if (((pcr >> 8) & 0xff) <= 5) { + printk("Enabling workaround for errata I14\n"); + asm (".chip 68060; movec %0,%%pcr; .chip 68k" + : : "d" (pcr | 0x20)); + } + } + /* FIXME: m68k_fputype is passed in by Penguin booter, which can * be confused by software FPU emulation. BEWARE. * We should really do our own FPU check at startup. diff -urN linux-2.4.26/arch/m68k/mac/iop.c linux-2.4.27/arch/m68k/mac/iop.c --- linux-2.4.26/arch/m68k/mac/iop.c 2003-06-13 07:51:31.000000000 -0700 +++ linux-2.4.27/arch/m68k/mac/iop.c 2004-08-07 16:26:04.579343696 -0700 @@ -261,7 +261,7 @@ } else { iop_base[IOP_NUM_ISM] = (struct mac_iop *) ISM_IOP_BASE_QUADRA; } - iop_base[IOP_NUM_SCC]->status_ctrl = 0; + iop_base[IOP_NUM_ISM]->status_ctrl = 0; iop_ism_present = 1; } else { iop_base[IOP_NUM_ISM] = NULL; diff -urN linux-2.4.26/arch/mips/sibyte/sb1250/bcm1250_tbprof.c linux-2.4.27/arch/mips/sibyte/sb1250/bcm1250_tbprof.c --- linux-2.4.26/arch/mips/sibyte/sb1250/bcm1250_tbprof.c 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.27/arch/mips/sibyte/sb1250/bcm1250_tbprof.c 2004-08-07 16:26:04.579343696 -0700 @@ -300,6 +300,9 @@ char *dest = buf; long cur_off = *offp; + if (cur_off < 0) + return -EINVAL; + count = 0; cur_sample = cur_off / TB_SAMPLE_SIZE; sample_off = cur_off % TB_SAMPLE_SIZE; diff -urN linux-2.4.26/arch/ppc/boot/simple/m8260_tty.c linux-2.4.27/arch/ppc/boot/simple/m8260_tty.c --- linux-2.4.26/arch/ppc/boot/simple/m8260_tty.c 2004-04-14 06:05:27.000000000 -0700 +++ linux-2.4.27/arch/ppc/boot/simple/m8260_tty.c 2004-08-07 16:26:04.580343737 -0700 @@ -156,7 +156,7 @@ sccp->scc_sccm = 0; sccp->scc_scce = 0xffff; sccp->scc_dsr = 0x7e7e; - sccp->scc_pmsr = 0x3000; + sccp->scc_psmr = 0x3000; /* Wire BRG1 to SCC1. The console driver will take care of * others. diff -urN linux-2.4.26/arch/ppc/config.in linux-2.4.27/arch/ppc/config.in --- linux-2.4.26/arch/ppc/config.in 2004-04-14 06:05:27.000000000 -0700 +++ linux-2.4.27/arch/ppc/config.in 2004-08-07 16:26:04.580343737 -0700 @@ -410,7 +410,6 @@ if [ "$CONFIG_ALL_PPC" = "y" ]; then bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE - bool 'Support for RTAS (RunTime Abstraction Services) in /proc' CONFIG_PPC_RTAS bool 'Support for PReP Residual Data' CONFIG_PREP_RESIDUAL dep_bool ' Support for reading of PReP Residual Data in /proc' CONFIG_PROC_PREPRESIDUAL $CONFIG_PREP_RESIDUAL define_bool CONFIG_PPCBUG_NVRAM y diff -urN linux-2.4.26/arch/ppc/cpm2_io/fcc_enet.c linux-2.4.27/arch/ppc/cpm2_io/fcc_enet.c --- linux-2.4.26/arch/ppc/cpm2_io/fcc_enet.c 2004-04-14 06:05:27.000000000 -0700 +++ linux-2.4.27/arch/ppc/cpm2_io/fcc_enet.c 2004-08-07 16:26:04.582343819 -0700 @@ -305,6 +305,8 @@ ushort skb_cur; ushort skb_dirty; + atomic_t n_pkts; /* Number of packets in tx ring */ + /* CPM dual port RAM relative addresses. */ cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */ @@ -396,13 +398,15 @@ bdp->cbd_datlen = skb->len; bdp->cbd_bufaddr = __pa(skb->data); + spin_lock_irq(&cep->lock); + /* Save skb pointer. */ cep->tx_skbuff[cep->skb_cur] = skb; cep->stats.tx_bytes += skb->len; cep->skb_cur = (cep->skb_cur+1) & TX_RING_MOD_MASK; - spin_lock_irq(&cep->lock); + atomic_inc(&cep->n_pkts); /* Send it on its way. Tell CPM its ready, interrupt when done, * its the last BD of the frame, and to put the CRC on the end. @@ -421,9 +425,12 @@ else bdp++; - if (bdp->cbd_sc & BD_ENET_TX_READY) { - netif_stop_queue(dev); + /* If the tx_ring is full, stop the queue */ + if (atomic_read(&cep->n_pkts) >= (TX_RING_SIZE-1)) { + if (!netif_queue_stopped(dev)) { + netif_stop_queue(dev); cep->tx_full = 1; + } } cep->cur_tx = (cbd_t *)bdp; @@ -542,6 +549,8 @@ dev_kfree_skb_irq(cep->tx_skbuff[cep->skb_dirty]); cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK; + atomic_dec(&cep->n_pkts); + /* Update pointer to next buffer descriptor to be transmitted. */ if (bdp->cbd_sc & BD_ENET_TX_WRAP) bdp = cep->tx_bd_base; @@ -1782,6 +1791,7 @@ while (cp->cp_cpcr & CPM_CR_FLG); cep->skb_cur = cep->skb_dirty = 0; + atomic_set(&cep->n_pkts, 0); } /* Let 'er rip. diff -urN linux-2.4.26/arch/ppc/kernel/head_44x.S linux-2.4.27/arch/ppc/kernel/head_44x.S --- linux-2.4.26/arch/ppc/kernel/head_44x.S 2004-04-14 06:05:27.000000000 -0700 +++ linux-2.4.27/arch/ppc/kernel/head_44x.S 2004-08-07 16:26:04.583343860 -0700 @@ -3,9 +3,26 @@ * * Kernel execution entry point code. * - * Matt Porter - * - * Copyright 2002-2003 MontaVista Software, Inc. + * Copyright (c) 1995-1996 Gary Thomas + * Initial PowerPC version. + * Copyright (c) 1996 Cort Dougan + * Rewritten for PReP + * Copyright (c) 1996 Paul Mackerras + * Low-level exception handers, MMU support, and rewrite. + * Copyright (c) 1997 Dan Malek + * PowerPC 8xx modifications. + * Copyright (c) 1998-1999 TiVo, Inc. + * PowerPC 403GCX modifications. + * Copyright (c) 1999 Grant Erickson + * PowerPC 403GCX/405GP modifications. + * Copyright 2000 MontaVista Software Inc. + * PPC405 modifications + * PowerPC 403GCX/405GP modifications. + * Author: MontaVista Software, Inc. + * frank_rowand@mvista.com or source@mvista.com + * debbie_chu@mvista.com + * Copyright 2002-2004 MontaVista Software, Inc. + * PowerPC 44x support, Matt Porter * * 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 diff -urN linux-2.4.26/arch/ppc/kernel/m8260_setup.c linux-2.4.27/arch/ppc/kernel/m8260_setup.c --- linux-2.4.26/arch/ppc/kernel/m8260_setup.c 2004-04-14 06:05:27.000000000 -0700 +++ linux-2.4.27/arch/ppc/kernel/m8260_setup.c 2004-08-07 16:26:04.584343901 -0700 @@ -93,7 +93,7 @@ */ static uint rtc_time; -static static int +static int m8260_set_rtc_time(unsigned long time) { rtc_time = time; diff -urN linux-2.4.26/arch/ppc/kernel/ppc_htab.c linux-2.4.27/arch/ppc/kernel/ppc_htab.c --- linux-2.4.26/arch/ppc/kernel/ppc_htab.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.27/arch/ppc/kernel/ppc_htab.c 2004-08-07 16:26:04.584343901 -0700 @@ -112,6 +112,7 @@ size_t count, loff_t *ppos) { unsigned long mmcr0 = 0, pmc1 = 0, pmc2 = 0; + loff_t pos = *ppos; int n = 0; #if defined(CONFIG_PPC_STD_MMU) && !defined(CONFIG_PPC64BRIDGE) int valid; @@ -219,14 +220,14 @@ "Non-error misses: %lu\n" "Error misses\t: %lu\n", pte_misses, pte_errors); - if (*ppos >= strlen(buffer)) + if (pos != (unsigned)pos || pos >= strlen(buffer)) return 0; - if (n > strlen(buffer) - *ppos) - n = strlen(buffer) - *ppos; + if (n > strlen(buffer) - pos) + n = strlen(buffer) - pos; if (n > count) n = count; - copy_to_user(buf, buffer + *ppos, n); - *ppos += n; + copy_to_user(buf, buffer + pos, n); + *ppos = pos + n; return n; } diff -urN linux-2.4.26/arch/ppc/platforms/Makefile linux-2.4.27/arch/ppc/platforms/Makefile --- linux-2.4.26/arch/ppc/platforms/Makefile 2004-04-14 06:05:27.000000000 -0700 +++ linux-2.4.27/arch/ppc/platforms/Makefile 2004-08-07 16:26:04.585343942 -0700 @@ -51,7 +51,6 @@ prep_time.o prep_setup.o pmac_sleep.o \ pmac_nvram.o obj-$(CONFIG_PMAC_BACKLIGHT) += pmac_backlight.o -obj-$(CONFIG_PPC_RTAS) += error_log.o proc_rtas.o obj-$(CONFIG_PREP_RESIDUAL) += residual.o obj-$(CONFIG_GEMINI) += gemini_pci.o gemini_setup.o gemini_prom.o obj-$(CONFIG_LOPEC) += lopec_setup.o lopec_pci.o diff -urN linux-2.4.26/arch/ppc/platforms/error_log.c linux-2.4.27/arch/ppc/platforms/error_log.c --- linux-2.4.26/arch/ppc/platforms/error_log.c 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.27/arch/ppc/platforms/error_log.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,183 +0,0 @@ -/* - * arch/ppc/kernel/error_log.c - * - * Copyright (c) 2000 Tilmann Bitterberg - * (tilmann@bitterberg.de) - * - * Error processing of errors found by rtas even-scan routine - * which is done with every heartbeat. (chrp_setup.c) - */ - -#include - -#include - -#include "error_log.h" - -/* ****************************************************************** */ -/* - * EVENT-SCAN - * The whole stuff below here doesn't take any action when it found - * an error, it just prints as much information as possible and - * then its up to the user to decide what to do. - * - * Returns 0 if no errors were found - * Returns 1 if there may be more errors - */ -int ppc_rtas_errorlog_scan(void) -{ -const char *_errlog_severity[] = { -#ifdef VERBOSE_ERRORS - "No Error\n\t\ -Should require no further information", - "Event\n\t\ -This is not really an error, it is an event. I use events\n\t\ -to communicate with RTAS back and forth.", - "Warning\n\t\ -Indicates a non-state-losing error, either fully recovered\n\t\ -by RTAS or not needing recovery. Ignore it.", - "Error sync\n\t\ -May only be fatal to a certain program or thread. Recovery\n\t\ -and continuation is possible, if I only had a handler for\n\t\ -this. Less serious", - "Error\n\t\ -Less serious, but still causing a loss of data and state.\n\t\ -I can't tell you exactly what to do, You have to decide\n\t\ -with help from the target and initiator field, what kind\n\t\ -of further actions may take place.", - "Fatal\n\t\ -Represent a permanent hardware failure and I believe this\n\t\ -affects my overall performance and behaviour. I would not\n\t\ -attempt to continue normal operation." -#else - "No Error", - "Event", - "Warning", - "Error sync", - "Error", - "Fatal" -#endif /* VERBOSE_ERRORS */ -}; - -#if 0 /* unused?? */ -const char *_errlog_disposition[] = { -#ifdef VERBOSE_ERRORS - "Fully recovered\n\t\ -There was an error, but it is fully recovered by RTAS.", - "Limited recovery\n\t\ -RTAS was able to recover the state of the machine, but some\n\t\ -feature of the machine has been disabled or lost (for example\n\t\ -error checking) or performance may suffer.", - "Not recovered\n\t\ -Whether RTAS did not try to recover anything or recovery failed:\n\t\ -HOUSTON, WE HAVE A PROBLEM!" -#else - "Fully recovered", - "Limited recovery", - "Not recovered" -#endif /* VERBOSE_ERRORS */ -}; -#endif - -const char *_errlog_extended[] = { -#ifdef VERBOSE_ERRORS - "Not present\n\t\ -Sad, the RTAS call didn't return an extended error log.", - "Present\n\t\ -The extended log is present and hopefully it contains a lot of\n\t\ -useful information, which leads to the solution of the problem." -#else - "Not present", - "Present" -#endif /* VERBOSE_ERRORS */ -}; - -const char *_errlog_initiator[] = { - "Unknown or not applicable", - "CPU", - "PCI", - "ISA", - "Memory", - "Power management" -}; - -const char *_errlog_target[] = { - "Unknown or not applicable", - "CPU", - "PCI", - "ISA", - "Memory", - "Power management" -}; - rtas_error_log error_log; - char logdata[1024]; - int error; -#if 0 /* unused?? */ - int retries = 0; /* if HW error, try 10 times */ -#endif - - error = call_rtas ("event-scan", 4, 1, (unsigned long *)&error_log, - INTERNAL_ERROR | EPOW_WARNING, - 0, __pa(logdata), 1024); - - if (error == 1) /* no errors found */ - return 0; - - if (error == -1) { - printk(KERN_ERR "Unable to get errors. Do you a favor and throw this box away\n"); - return 0; - } - if (error_log.version != 1) - printk(KERN_WARNING "Unknown version (%d), please implement me\n", - error_log.version); - - switch (error_log.disposition) { - case DISP_FULLY_RECOVERED: - /* there was an error, but everything is fine now */ - return 0; - case DISP_NOT_RECOVERED: - printk("We have a really serious Problem!\n"); - case DISP_LIMITED_RECOVERY: - printk("Error classification\n"); - printk("Severity : %s\n", - ppc_rtas_errorlog_check_severity (error_log)); - printk("Initiator : %s\n", - ppc_rtas_errorlog_check_initiator (error_log)); - printk("Target : %s\n", - ppc_rtas_errorlog_check_target (error_log)); - printk("Type : %s\n", - ppc_rtas_errorlog_check_type (error_log)); - printk("Ext. log : %s\n", - ppc_rtas_errorlog_check_extended (error_log)); - if (error_log.extended) - ppc_rtas_errorlog_disect_extended (logdata); - return 1; - default: - /* nothing */ - break; - } - return 0; -} -/* ****************************************************************** */ -const char * ppc_rtas_errorlog_check_type (rtas_error_log error_log) -{ - const char *_errlog_type[] = { - "unknown type", - "too many tries failed", - "TCE error", - "RTAS device failed", - "target timed out", - "parity error on data", /* 5 */ - "parity error on address", - "parity error on external cache", - "access to invalid address", - "uncorrectable ECC error", - "corrected ECC error" /* 10 */ - }; - if (error_log.type == TYPE_EPOW) - return "EPOW"; - if (error_log.type >= TYPE_PMGM_POWER_SW_ON) - return "PowerMGM Event (not handled right now)"; - return _errlog_type[error_log.type]; -} - diff -urN linux-2.4.26/arch/ppc/platforms/error_log.h linux-2.4.27/arch/ppc/platforms/error_log.h --- linux-2.4.26/arch/ppc/platforms/error_log.h 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.27/arch/ppc/platforms/error_log.h 1969-12-31 16:00:00.000000000 -0800 @@ -1,95 +0,0 @@ -#ifndef __ERROR_LOG_H__ -#define __ERROR_LOG_H__ - -#define VERBOSE_ERRORS 1 /* Maybe I enlarge the kernel too much */ -#undef VERBOSE_ERRORS - -/* Event classes */ -/* XXX: Endianess correct? NOW*/ -#define INTERNAL_ERROR 0x80000000 /* set bit 0 */ -#define EPOW_WARNING 0x40000000 /* set bit 1 */ -#define POWERMGM_EVENTS 0x20000000 /* set bit 2 */ - -/* event-scan returns */ -#define SEVERITY_FATAL 0x5 -#define SEVERITY_ERROR 0x4 -#define SEVERITY_ERROR_SYNC 0x3 -#define SEVERITY_WARNING 0x2 -#define SEVERITY_EVENT 0x1 -#define SEVERITY_NO_ERROR 0x0 -#define DISP_FULLY_RECOVERED 0x0 -#define DISP_LIMITED_RECOVERY 0x1 -#define DISP_NOT_RECOVERED 0x2 -#define PART_PRESENT 0x0 -#define PART_NOT_PRESENT 0x1 -#define INITIATOR_UNKNOWN 0x0 -#define INITIATOR_CPU 0x1 -#define INITIATOR_PCI 0x2 -#define INITIATOR_ISA 0x3 -#define INITIATOR_MEMORY 0x4 -#define INITIATOR_POWERMGM 0x5 -#define TARGET_UNKNOWN 0x0 -#define TARGET_CPU 0x1 -#define TARGET_PCI 0x2 -#define TARGET_ISA 0x3 -#define TARGET_MEMORY 0x4 -#define TARGET_POWERMGM 0x5 -#define TYPE_RETRY 0x01 -#define TYPE_TCE_ERR 0x02 -#define TYPE_INTERN_DEV_FAIL 0x03 -#define TYPE_TIMEOUT 0x04 -#define TYPE_DATA_PARITY 0x05 -#define TYPE_ADDR_PARITY 0x06 -#define TYPE_CACHE_PARITY 0x07 -#define TYPE_ADDR_INVALID 0x08 -#define TYPE_ECC_UNCORR 0x09 -#define TYPE_ECC_CORR 0x0a -#define TYPE_EPOW 0x40 -/* I don't add PowerMGM events right now, this is a different topic */ -#define TYPE_PMGM_POWER_SW_ON 0x60 -#define TYPE_PMGM_POWER_SW_OFF 0x61 -#define TYPE_PMGM_LID_OPEN 0x62 -#define TYPE_PMGM_LID_CLOSE 0x63 -#define TYPE_PMGM_SLEEP_BTN 0x64 -#define TYPE_PMGM_WAKE_BTN 0x65 -#define TYPE_PMGM_BATTERY_WARN 0x66 -#define TYPE_PMGM_BATTERY_CRIT 0x67 -#define TYPE_PMGM_SWITCH_TO_BAT 0x68 -#define TYPE_PMGM_SWITCH_TO_AC 0x69 -#define TYPE_PMGM_KBD_OR_MOUSE 0x6a -#define TYPE_PMGM_ENCLOS_OPEN 0x6b -#define TYPE_PMGM_ENCLOS_CLOSED 0x6c -#define TYPE_PMGM_RING_INDICATE 0x6d -#define TYPE_PMGM_LAN_ATTENTION 0x6e -#define TYPE_PMGM_TIME_ALARM 0x6f -#define TYPE_PMGM_CONFIG_CHANGE 0x70 -#define TYPE_PMGM_SERVICE_PROC 0x71 - -typedef struct _rtas_error_log { - unsigned long version:8; /* Architectural version */ - unsigned long severity:3; /* Severity level of error */ - unsigned long disposition:2; /* Degree of recovery */ - unsigned long extended:1; /* extended log present? */ - unsigned long /* reserved */ :2; /* Reserved for future use */ - unsigned long initiator:4; /* Initiator of event */ - unsigned long target:4; /* Target of failed operation */ - unsigned long type:8; /* General event or error*/ - unsigned long extended_log_length:32; /* length in bytes */ -} rtas_error_log; - -/* ****************************************************************** */ -#define ppc_rtas_errorlog_check_severity(x) \ - (_errlog_severity[x.severity]) -#define ppc_rtas_errorlog_check_target(x) \ - (_errlog_target[x.target]) -#define ppc_rtas_errorlog_check_initiator(x) \ - (_errlog_initiator[x.initiator]) -#define ppc_rtas_errorlog_check_extended(x) \ - (_errlog_extended[x.extended]) -#define ppc_rtas_errorlog_disect_extended(x) \ - do { /* implement me */ } while(0) -extern const char * ppc_rtas_errorlog_check_type (rtas_error_log error_log); -extern int ppc_rtas_errorlog_scan(void); - - -#endif /* __ERROR_LOG_H__ */ diff -urN linux-2.4.26/arch/ppc/platforms/proc_rtas.c linux-2.4.27/arch/ppc/platforms/proc_rtas.c --- linux-2.4.26/arch/ppc/platforms/proc_rtas.c 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.27/arch/ppc/platforms/proc_rtas.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,784 +0,0 @@ -/* - * arch/ppc/kernel/proc_rtas.c - * Copyright (C) 2000 Tilmann Bitterberg - * (tilmann@bitterberg.de) - * - * RTAS (Runtime Abstraction Services) stuff - * Intention is to provide a clean user interface - * to use the RTAS. - * - * TODO: - * Split off a header file and maybe move it to a different - * location. Write Documentation on what the /proc/rtas/ entries - * actually do. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include /* for ppc_md */ -#include - -/* Token for Sensors */ -#define KEY_SWITCH 0x0001 -#define ENCLOSURE_SWITCH 0x0002 -#define THERMAL_SENSOR 0x0003 -#define LID_STATUS 0x0004 -#define POWER_SOURCE 0x0005 -#define BATTERY_VOLTAGE 0x0006 -#define BATTERY_REMAINING 0x0007 -#define BATTERY_PERCENTAGE 0x0008 -#define EPOW_SENSOR 0x0009 -#define BATTERY_CYCLESTATE 0x000a -#define BATTERY_CHARGING 0x000b - -/* IBM specific sensors */ -#define IBM_SURVEILLANCE 0x2328 /* 9000 */ -#define IBM_FANRPM 0x2329 /* 9001 */ -#define IBM_VOLTAGE 0x232a /* 9002 */ -#define IBM_DRCONNECTOR 0x232b /* 9003 */ -#define IBM_POWERSUPPLY 0x232c /* 9004 */ -#define IBM_INTQUEUE 0x232d /* 9005 */ - -/* Status return values */ -#define SENSOR_CRITICAL_HIGH 13 -#define SENSOR_WARNING_HIGH 12 -#define SENSOR_NORMAL 11 -#define SENSOR_WARNING_LOW 10 -#define SENSOR_CRITICAL_LOW 9 -#define SENSOR_SUCCESS 0 -#define SENSOR_HW_ERROR -1 -#define SENSOR_BUSY -2 -#define SENSOR_NOT_EXIST -3 -#define SENSOR_DR_ENTITY -9000 - -/* Location Codes */ -#define LOC_SCSI_DEV_ADDR 'A' -#define LOC_SCSI_DEV_LOC 'B' -#define LOC_CPU 'C' -#define LOC_DISKETTE 'D' -#define LOC_ETHERNET 'E' -#define LOC_FAN 'F' -#define LOC_GRAPHICS 'G' -/* reserved / not used 'H' */ -#define LOC_IO_ADAPTER 'I' -/* reserved / not used 'J' */ -#define LOC_KEYBOARD 'K' -#define LOC_LCD 'L' -#define LOC_MEMORY 'M' -#define LOC_NV_MEMORY 'N' -#define LOC_MOUSE 'O' -#define LOC_PLANAR 'P' -#define LOC_OTHER_IO 'Q' -#define LOC_PARALLEL 'R' -#define LOC_SERIAL 'S' -#define LOC_DEAD_RING 'T' -#define LOC_RACKMOUNTED 'U' /* for _u_nit is rack mounted */ -#define LOC_VOLTAGE 'V' -#define LOC_SWITCH_ADAPTER 'W' -#define LOC_OTHER 'X' -#define LOC_FIRMWARE 'Y' -#define LOC_SCSI 'Z' - -/* Tokens for indicators */ -#define TONE_FREQUENCY 0x0001 /* 0 - 1000 (HZ)*/ -#define TONE_VOLUME 0x0002 /* 0 - 100 (%) */ -#define SYSTEM_POWER_STATE 0x0003 -#define WARNING_LIGHT 0x0004 -#define DISK_ACTIVITY_LIGHT 0x0005 -#define HEX_DISPLAY_UNIT 0x0006 -#define BATTERY_WARNING_TIME 0x0007 -#define CONDITION_CYCLE_REQUEST 0x0008 -#define SURVEILLANCE_INDICATOR 0x2328 /* 9000 */ -#define DR_ACTION 0x2329 /* 9001 */ -#define DR_INDICATOR 0x232a /* 9002 */ -/* 9003 - 9004: Vendor specific */ -#define GLOBAL_INTERRUPT_QUEUE 0x232d /* 9005 */ -/* 9006 - 9999: Vendor specific */ - -/* other */ -#define MAX_SENSORS 17 /* I only know of 17 sensors */ -#define MAX_LINELENGTH 256 -#define SENSOR_PREFIX "ibm,sensor-" -#define cel_to_fahr(x) ((x*9/5)+32) - - -/* Globals */ -static struct proc_dir_entry *proc_rtas; -static struct rtas_sensors sensors; -static struct device_node *rtas; -static unsigned long power_on_time = 0; /* Save the time the user set */ -static char progress_led[MAX_LINELENGTH]; - -static unsigned long rtas_tone_frequency = 1000; -static unsigned long rtas_tone_volume = 0; - -/* ****************STRUCTS******************************************* */ -struct individual_sensor { - unsigned int token; - unsigned int quant; -}; - -struct rtas_sensors { - struct individual_sensor sensor[MAX_SENSORS]; - unsigned int quant; -}; - -/* ****************************************************************** */ -/* Declarations */ -static int ppc_rtas_sensor_read(char * buf, char ** start, off_t off, - int count, int *eof, void *data); -static ssize_t ppc_rtas_clock_read(struct file * file, char * buf, - size_t count, loff_t *ppos); -static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf, - size_t count, loff_t *ppos); -static ssize_t ppc_rtas_progress_read(struct file * file, char * buf, - size_t count, loff_t *ppos); -static ssize_t ppc_rtas_progress_write(struct file * file, const char * buf, - size_t count, loff_t *ppos); -static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf, - size_t count, loff_t *ppos); -static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf, - size_t count, loff_t *ppos); - -static ssize_t ppc_rtas_tone_freq_write(struct file * file, const char * buf, - size_t count, loff_t *ppos); -static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf, - size_t count, loff_t *ppos); -static ssize_t ppc_rtas_tone_volume_write(struct file * file, const char * buf, - size_t count, loff_t *ppos); -static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf, - size_t count, loff_t *ppos); - -struct file_operations ppc_rtas_poweron_operations = { - read: ppc_rtas_poweron_read, - write: ppc_rtas_poweron_write -}; -struct file_operations ppc_rtas_progress_operations = { - read: ppc_rtas_progress_read, - write: ppc_rtas_progress_write -}; - -struct file_operations ppc_rtas_clock_operations = { - read: ppc_rtas_clock_read, - write: ppc_rtas_clock_write -}; - -struct file_operations ppc_rtas_tone_freq_operations = { - read: ppc_rtas_tone_freq_read, - write: ppc_rtas_tone_freq_write -}; -struct file_operations ppc_rtas_tone_volume_operations = { - read: ppc_rtas_tone_volume_read, - write: ppc_rtas_tone_volume_write -}; - -int ppc_rtas_find_all_sensors (void); -int ppc_rtas_process_sensor(struct individual_sensor s, int state, - int error, char * buf); -char * ppc_rtas_process_error(int error); -int get_location_code(struct individual_sensor s, char * buf); -int check_location_string (char *c, char * buf); -int check_location (char *c, int idx, char * buf); - -/* ****************************************************************** */ -/* MAIN */ -/* ****************************************************************** */ -void proc_rtas_init(void) -{ - struct proc_dir_entry *entry; - - rtas = find_devices("rtas"); - if ((rtas == 0) || (_machine != _MACH_chrp)) { - return; - } - - proc_rtas = proc_mkdir("rtas", 0); - if (proc_rtas == 0) - return; - - /* /proc/rtas entries */ - - entry = create_proc_entry("progress", S_IRUGO|S_IWUSR, proc_rtas); - if (entry) entry->proc_fops = &ppc_rtas_progress_operations; - - entry = create_proc_entry("clock", S_IRUGO|S_IWUSR, proc_rtas); - if (entry) entry->proc_fops = &ppc_rtas_clock_operations; - - entry = create_proc_entry("poweron", S_IWUSR|S_IRUGO, proc_rtas); - if (entry) entry->proc_fops = &ppc_rtas_poweron_operations; - - create_proc_read_entry("sensors", S_IRUGO, proc_rtas, - ppc_rtas_sensor_read, NULL); - - entry = create_proc_entry("frequency", S_IWUSR|S_IRUGO, proc_rtas); - if (entry) entry->proc_fops = &ppc_rtas_tone_freq_operations; - - entry = create_proc_entry("volume", S_IWUSR|S_IRUGO, proc_rtas); - if (entry) entry->proc_fops = &ppc_rtas_tone_volume_operations; -} - -/* ****************************************************************** */ -/* POWER-ON-TIME */ -/* ****************************************************************** */ -static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf, - size_t count, loff_t *ppos) -{ - struct rtc_time tm; - unsigned long nowtime; - char *dest; - int error; - - nowtime = simple_strtoul(buf, &dest, 10); - if (*dest != '\0' && *dest != '\n') { - printk("ppc_rtas_poweron_write: Invalid time\n"); - return count; - } - power_on_time = nowtime; /* save the time */ - - to_tm(nowtime, &tm); - - error = call_rtas("set-time-for-power-on", 7, 1, NULL, - tm.tm_year, tm.tm_mon, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, 0 /* nano */); - if (error != 0) - printk(KERN_WARNING "error: setting poweron time returned: %s\n", - ppc_rtas_process_error(error)); - return count; -} -/* ****************************************************************** */ -static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf, - size_t count, loff_t *ppos) -{ - int n; - if (power_on_time == 0) - n = sprintf(buf, "Power on time not set\n"); - else - n = sprintf(buf, "%lu\n", power_on_time); - - if (*ppos >= strlen(buf)) - return 0; - if (n > strlen(buf) - *ppos) - n = strlen(buf) - *ppos; - if (n > count) - n = count; - *ppos += n; - return n; -} - -/* ****************************************************************** */ -/* PROGRESS */ -/* ****************************************************************** */ -static ssize_t ppc_rtas_progress_write(struct file * file, const char * buf, - size_t count, loff_t *ppos) -{ - unsigned long hex; - - strcpy(progress_led, buf); /* save the string */ - /* Lets see if the user passed hexdigits */ - hex = simple_strtoul(buf, NULL, 10); - - ppc_md.progress ((char *)buf, hex); - return count; - - /* clear the line */ /* ppc_md.progress(" ", 0xffff);*/ -} -/* ****************************************************************** */ -static ssize_t ppc_rtas_progress_read(struct file * file, char * buf, - size_t count, loff_t *ppos) -{ - int n = 0; - if (progress_led != NULL) - n = sprintf (buf, "%s\n", progress_led); - if (*ppos >= strlen(buf)) - return 0; - if (n > strlen(buf) - *ppos) - n = strlen(buf) - *ppos; - if (n > count) - n = count; - *ppos += n; - return n; -} - -/* ****************************************************************** */ -/* CLOCK */ -/* ****************************************************************** */ -static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf, - size_t count, loff_t *ppos) -{ - struct rtc_time tm; - unsigned long nowtime; - char *dest; - int error; - - nowtime = simple_strtoul(buf, &dest, 10); - if (*dest != '\0' && *dest != '\n') { - printk("ppc_rtas_clock_write: Invalid time\n"); - return count; - } - - to_tm(nowtime, &tm); - error = call_rtas("set-time-of-day", 7, 1, NULL, - tm.tm_year, tm.tm_mon, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, 0); - if (error != 0) - printk(KERN_WARNING "error: setting the clock returned: %s\n", - ppc_rtas_process_error(error)); - return count; -} -/* ****************************************************************** */ -static ssize_t ppc_rtas_clock_read(struct file * file, char * buf, - size_t count, loff_t *ppos) -{ - unsigned int year, mon, day, hour, min, sec; - unsigned long *ret = kmalloc(4*8, GFP_KERNEL); - int n, error; - - error = call_rtas("get-time-of-day", 0, 8, ret); - - year = ret[0]; mon = ret[1]; day = ret[2]; - hour = ret[3]; min = ret[4]; sec = ret[5]; - - if (error != 0){ - printk(KERN_WARNING "error: reading the clock returned: %s\n", - ppc_rtas_process_error(error)); - n = sprintf (buf, "0"); - } else { - n = sprintf (buf, "%lu\n", mktime(year, mon, day, hour, min, sec)); - } - kfree(ret); - - if (*ppos >= strlen(buf)) - return 0; - if (n > strlen(buf) - *ppos) - n = strlen(buf) - *ppos; - if (n > count) - n = count; - *ppos += n; - return n; -} - -/* ****************************************************************** */ -/* SENSOR STUFF */ -/* ****************************************************************** */ -static int ppc_rtas_sensor_read(char * buf, char ** start, off_t off, - int count, int *eof, void *data) -{ - int i,j,n; - unsigned long ret; - int state, error; - char buffer[MAX_LINELENGTH*MAX_SENSORS]; /* May not be enough */ - - if (count < 0) - return -EINVAL; - - n = sprintf ( buffer , "RTAS (RunTime Abstraction Services) Sensor Information\n"); - n += sprintf ( buffer+n, "Sensor\t\tValue\t\tCondition\tLocation\n"); - n += sprintf ( buffer+n, "********************************************************\n"); - - if (ppc_rtas_find_all_sensors() != 0) { - n += sprintf ( buffer+n, "\nNo sensors are available\n"); - goto return_string; - } - - for (i=0; i= 0) { - error = call_rtas("get-sensor-state", 2, 2, &ret, - sensors.sensor[i].token, sensors.sensor[i].quant-j); - state = (int) ret; - n += ppc_rtas_process_sensor(sensors.sensor[i], state, error, buffer+n ); - n += sprintf (buffer+n, "\n"); - j--; - } /* while */ - } /* for */ - -return_string: - if (off >= strlen(buffer)) { - *eof = 1; - return 0; - } - if (n > strlen(buffer) - off) - n = strlen(buffer) - off; - if (n > count) - n = count; - else - *eof = 1; - memcpy(buf, buffer + off, n); - *start = buf; - return n; -} - -/* ****************************************************************** */ - -int ppc_rtas_find_all_sensors (void) -{ - unsigned long *utmp; - int len, i, j; - - utmp = (unsigned long *) get_property(rtas, "rtas-sensors", &len); - if (utmp == NULL) { - printk (KERN_ERR "error: could not get rtas-sensors\n"); - return 1; - } - - sensors.quant = len / 8; /* int + int */ - - for (i=0, j=0; j= llen) pos=0; - } - return n; -} -/* ****************************************************************** */ -/* INDICATORS - Tone Frequency */ -/* ****************************************************************** */ -static ssize_t ppc_rtas_tone_freq_write(struct file * file, const char * buf, - size_t count, loff_t *ppos) -{ - unsigned long freq; - char *dest; - int error; - freq = simple_strtoul(buf, &dest, 10); - if (*dest != '\0' && *dest != '\n') { - printk("ppc_rtas_tone_freq_write: Invalid tone freqency\n"); - return count; - } - if (freq < 0) freq = 0; - rtas_tone_frequency = freq; /* save it for later */ - error = call_rtas("set-indicator", 3, 1, NULL, - TONE_FREQUENCY, 0, freq); - if (error != 0) - printk(KERN_WARNING "error: setting tone frequency returned: %s\n", - ppc_rtas_process_error(error)); - return count; -} -/* ****************************************************************** */ -static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf, - size_t count, loff_t *ppos) -{ - int n; - n = sprintf(buf, "%lu\n", rtas_tone_frequency); - - if (*ppos >= strlen(buf)) - return 0; - if (n > strlen(buf) - *ppos) - n = strlen(buf) - *ppos; - if (n > count) - n = count; - *ppos += n; - return n; -} -/* ****************************************************************** */ -/* INDICATORS - Tone Volume */ -/* ****************************************************************** */ -static ssize_t ppc_rtas_tone_volume_write(struct file * file, const char * buf, - size_t count, loff_t *ppos) -{ - unsigned long volume; - char *dest; - int error; - volume = simple_strtoul(buf, &dest, 10); - if (*dest != '\0' && *dest != '\n') { - printk("ppc_rtas_tone_volume_write: Invalid tone volume\n"); - return count; - } - if (volume < 0) volume = 0; - if (volume > 100) volume = 100; - - rtas_tone_volume = volume; /* save it for later */ - error = call_rtas("set-indicator", 3, 1, NULL, - TONE_VOLUME, 0, volume); - if (error != 0) - printk(KERN_WARNING "error: setting tone volume returned: %s\n", - ppc_rtas_process_error(error)); - return count; -} -/* ****************************************************************** */ -static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf, - size_t count, loff_t *ppos) -{ - int n; - n = sprintf(buf, "%lu\n", rtas_tone_volume); - - if (*ppos >= strlen(buf)) - return 0; - if (n > strlen(buf) - *ppos) - n = strlen(buf) - *ppos; - if (n > count) - n = count; - *ppos += n; - return n; -} diff -urN linux-2.4.26/arch/ppc64/kernel/lparcfg.c linux-2.4.27/arch/ppc64/kernel/lparcfg.c --- linux-2.4.26/arch/ppc64/kernel/lparcfg.c 2004-04-14 06:05:27.000000000 -0700 +++ linux-2.4.27/arch/ppc64/kernel/lparcfg.c 2004-08-07 16:26:04.593344271 -0700 @@ -415,7 +415,7 @@ pnt = (char *)(data) + p; copy_to_user(buf, (void *)pnt, count); read += count; - *ppos += read; + *ppos = p + read; return read; } diff -urN linux-2.4.26/arch/ppc64/kernel/nvram.c linux-2.4.27/arch/ppc64/kernel/nvram.c --- linux-2.4.26/arch/ppc64/kernel/nvram.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.27/arch/ppc64/kernel/nvram.c 2004-08-07 16:26:04.594344312 -0700 @@ -78,11 +78,12 @@ size_t count, loff_t *ppos) { unsigned long len; - char *tmp_buffer; + char *tmp_buffer; + loff_t pos = *ppos; if (verify_area(VERIFY_WRITE, buf, count)) return -EFAULT; - if (*ppos >= rtas_nvram_size) + if ((unsigned)pos != pos || pos >= rtas_nvram_size) return 0; if (count > rtas_nvram_size) count = rtas_nvram_size; @@ -93,7 +94,7 @@ return 0; } - len = read_nvram(tmp_buffer, count, ppos); + len = read_nvram(tmp_buffer, count, &pos); if ((long)len <= 0) { kfree(tmp_buffer); return len; @@ -105,6 +106,7 @@ } kfree(tmp_buffer); + *ppos = pos; return len; } @@ -114,10 +116,11 @@ { unsigned long len; char * tmp_buffer; + loff_t pos = *ppos; if (verify_area(VERIFY_READ, buf, count)) return -EFAULT; - if (*ppos >= rtas_nvram_size) + if (pos != (unsigned) pos || pos >= rtas_nvram_size) return 0; if (count > rtas_nvram_size) count = rtas_nvram_size; @@ -133,7 +136,8 @@ return -EFAULT; } - len = write_nvram(tmp_buffer, count, ppos); + len = write_nvram(tmp_buffer, count, &pos); + *ppos = pos; kfree(tmp_buffer); return len; diff -urN linux-2.4.26/arch/ppc64/kernel/proc_pmc.c linux-2.4.27/arch/ppc64/kernel/proc_pmc.c --- linux-2.4.26/arch/ppc64/kernel/proc_pmc.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.27/arch/ppc64/kernel/proc_pmc.c 2004-08-07 16:26:04.595344353 -0700 @@ -445,8 +445,9 @@ } pnt = (char *)(perfmon_base.profile_buffer) + p - sizeof(unsigned int); copy_to_user(buf,(void *)pnt,count); + p += count; read += count; - *ppos += read; + *ppos = p; return read; } @@ -460,19 +461,17 @@ size_t count, loff_t *ppos) { unsigned long p = *ppos; - ssize_t read; char * pnt; if (p >= (perfmon_base.trace_length)) return 0; if (count > (perfmon_base.trace_length) - p) count = (perfmon_base.trace_length) - p; - read = 0; pnt = (char *)(perfmon_base.trace_buffer) + p; copy_to_user(buf,(void *)pnt,count); - read += count; - *ppos += read; - return read; + p += count; + *ppos = p; + return count; } static ssize_t write_trace(struct file * file, const char * buf, @@ -491,13 +490,11 @@ if (p >= (perfmon_base.timeslice_length)) return 0; if (count > (perfmon_base.timeslice_length) - p) count = (perfmon_base.timeslice_length) - p; - read = 0; pnt = (char *)(perfmon_base.timeslice_buffer) + p; copy_to_user(buf,(void *)pnt,count); - read += count; - *ppos += read; - return read; + *ppos = p + count; + return count; } static ssize_t write_timeslice(struct file * file, const char * buf, diff -urN linux-2.4.26/arch/ppc64/kernel/rtas-proc.c linux-2.4.27/arch/ppc64/kernel/rtas-proc.c --- linux-2.4.26/arch/ppc64/kernel/rtas-proc.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.27/arch/ppc64/kernel/rtas-proc.c 2004-08-07 16:26:04.596344394 -0700 @@ -337,6 +337,7 @@ { char stkbuf[40]; /* its small, its on stack */ int n; + loff_t pos = *ppos; if (power_on_time == 0) n = snprintf(stkbuf, 40, "Power on time not set\n"); @@ -344,15 +345,15 @@ n = snprintf(stkbuf, 40, "%lu\n", power_on_time); int sn = strlen(stkbuf) +1; - if (*ppos >= sn) + if (pos != (unsigned)pos || pos >= sn) return 0; - if (n > sn - *ppos) - n = sn - *ppos; + if (n > sn - pos) + n = sn - pos; if (n > count) n = count; - if (copy_to_user(buf, stkbuf + (*ppos), n)) + if (copy_to_user(buf, stkbuf + pos, n)) return -EFAULT; - *ppos += n; + *ppos = pos + n; return n; } @@ -384,6 +385,7 @@ size_t count, loff_t *ppos) { int n = 0, sn; + loff_t pos = *ppos; if (progress_led == NULL) return 0; @@ -396,20 +398,20 @@ n = sprintf (tmpbuf, "%s\n", progress_led); sn = strlen (tmpbuf) +1; - if (*ppos >= sn) { + if (pos != (unsigned)pos || pos >= sn) { kfree(tmpbuf); return 0; } - if (n > sn - *ppos) - n = sn - *ppos; + if (n > sn - pos) + n = sn - pos; if (n > count) n = count; - if (copy_to_user(buf, tmpbuf + (*ppos), n)) { + if (copy_to_user(buf, tmpbuf + pos), n) { kfree(tmpbuf); return -EFAULT; } kfree(tmpbuf); - *ppos += n; + *ppos = pos + n; return n; } @@ -453,6 +455,7 @@ unsigned int year, mon, day, hour, min, sec; unsigned long *ret = kmalloc(4*8, GFP_KERNEL); int n, error; + loff_t pos = *ppos; error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret); @@ -471,16 +474,16 @@ kfree(ret); int sn = strlen(stkbuf) +1; - if (*ppos >= sn) + if (pos != (unsigned)pos || pos >= sn) return 0; - if (n > sn - *ppos) - n = sn - *ppos; + if (n > sn - pos) + n = sn - pos; if (n > count) n = count; - if (copy_to_user(buf, stkbuf + (*ppos), n)) + if (copy_to_user(buf, stkbuf + pos, n)) return -EFAULT; - *ppos += n; + *ppos = pos + n; return n; } @@ -878,20 +881,21 @@ { int n, sn; char stkbuf[40]; /* its small, its on stack */ + loff_t pos = *ppos; n = snprintf(stkbuf, 40, "%lu\n", rtas_tone_frequency); sn = strlen(stkbuf) +1; - if (*ppos >= sn) + if (pos != (unsigned)pos || pos >= sn) return 0; - if (n > sn - *ppos) - n = sn - *ppos; + if (n > sn - pos) + n = sn - pos; if (n > count) n = count; - if (copy_to_user(buf, stkbuf + (*ppos), n)) + if (copy_to_user(buf, stkbuf + pos, n)) return -EFAULT; - *ppos += n; + *ppos = pos + n; return n; } /* ****************************************************************** */ @@ -933,19 +937,20 @@ { int n, sn; char stkbuf[40]; /* its small, its on stack */ + loff_t pos = *ppos; n = snprintf(stkbuf, 40, "%lu\n", rtas_tone_volume); sn = strlen(stkbuf) +1; - if (*ppos >= sn) + if (pos != (unsigned)pos || pos >= sn) return 0; - if (n > sn - *ppos) - n = sn - *ppos; + if (n > sn - pos) + n = sn - pos; if (n > count) n = count; - if (copy_to_user(buf, stkbuf + (*ppos), n)) + if (copy_to_user(buf, stkbuf + pos, n)) return -EFAULT; - *ppos += n; + *ppos = pos + n; return n; } @@ -1064,6 +1069,7 @@ char * buffer; int i, sn; int n = 0; + loff_t pos = *ppos; int m = MAX_ERRINJCT_TOKENS * (ERRINJCT_TOKEN_LEN+1); buffer = (char *)kmalloc(m, GFP_KERNEL); @@ -1078,22 +1084,22 @@ } sn = strlen(buffer) +1; - if (*ppos >= sn) { + if (pos != (unsigned)pos || pos >= sn) { kfree(buffer); return 0; } - if (n > sn - *ppos) - n = sn - *ppos; + if (n > sn - pos) + n = sn - pos; if (n > count) n = count; - if (copy_to_user(buf, buffer + *ppos, n)) { + if (copy_to_user(buf, buffer + pos, n)) { kfree(buffer); return -EFAULT; } - *ppos += n; + *ppos = pos + n; kfree(buffer); return n; diff -urN linux-2.4.26/arch/s390/kernel/debug.c linux-2.4.27/arch/s390/kernel/debug.c --- linux-2.4.26/arch/s390/kernel/debug.c 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.27/arch/s390/kernel/debug.c 2004-08-07 16:26:04.597344435 -0700 @@ -470,8 +470,8 @@ goto out; } out: - p_info->offset = *offset + count; - p_info->act_entry_offset = size; + p_info->offset += count; + p_info->act_entry_offset = size; *offset = p_info->offset; return count; } @@ -1068,7 +1068,7 @@ input_buf[0]); } out: - *offset += in_buf_size; + *offset = in_buf_size; return rc; /* number of input characters */ } @@ -1135,7 +1135,7 @@ printk(KERN_INFO "debug: area `%c` is not valid\n", input_buf[0]); out: - *offset += in_buf_size; + *offset = in_buf_size; return rc; /* number of input characters */ } diff -urN linux-2.4.26/arch/s390x/kernel/debug.c linux-2.4.27/arch/s390x/kernel/debug.c --- linux-2.4.26/arch/s390x/kernel/debug.c 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.27/arch/s390x/kernel/debug.c 2004-08-07 16:26:04.598344476 -0700 @@ -470,7 +470,7 @@ goto out; } out: - p_info->offset = *offset + count; + p_info->offset += count; p_info->act_entry_offset = size; *offset = p_info->offset; return count; @@ -1068,7 +1068,7 @@ input_buf[0]); } out: - *offset += in_buf_size; + *offset = in_buf_size; return rc; /* number of input characters */ } @@ -1135,7 +1135,7 @@ printk(KERN_INFO "debug: area `%c` is not valid\n", input_buf[0]); out: - *offset += in_buf_size; + *offset = in_buf_size; return rc; /* number of input characters */ } diff -urN linux-2.4.26/arch/sh64/config.in linux-2.4.27/arch/sh64/config.in --- linux-2.4.26/arch/sh64/config.in 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.27/arch/sh64/config.in 2004-08-07 16:26:04.599344517 -0700 @@ -58,8 +58,7 @@ # Use 32-bit addressing for now. # EMI based. -# P2 (UNCACHED) required to use identity mapping -# P1 (CACHED) assumes non-identity. +# (CACHED) assumes non-identity. # # Memory options @@ -68,7 +67,6 @@ int 'Memory size (in MB)' CONFIG_MEMORY_SIZE_IN_MB 64 hex 'Cached Area Offset' CONFIG_CACHED_MEMORY_OFFSET 20000000 -hex 'Uncached Area Offset' CONFIG_UNCACHED_MEMORY_OFFSET 00000000 hex 'Physical memory start address' CONFIG_MEMORY_START 80000000 # @@ -304,6 +302,7 @@ bool "Debug: audit page tables on return from syscall/exception/interrupt" CONFIG_SH64_PAGE_TABLE_AUDIT dep_bool "Debug: report TLB fill/purge activity through /proc/tlb" CONFIG_SH64_PROC_TLB $CONFIG_PROC_FS dep_bool "Debug: report ASIDS through /proc/asids" CONFIG_SH64_PROC_ASIDS $CONFIG_PROC_FS +bool "Debug: set SR.WATCH to enable hardware watchpoints and trace" CONFIG_SH64_SR_WATCH int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0 diff -urN linux-2.4.26/arch/sh64/defconfig linux-2.4.27/arch/sh64/defconfig --- linux-2.4.26/arch/sh64/defconfig 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.27/arch/sh64/defconfig 2004-08-07 16:26:04.599344517 -0700 @@ -490,6 +490,7 @@ # CONFIG_SH64_PAGE_TABLE_AUDIT is not set # CONFIG_SH64_PROC_TLB is not set # CONFIG_SH64_PROC_ASIDS is not set +# CONFIG_SH64_SR_WATCH is not set # # Library routines diff -urN linux-2.4.26/arch/sh64/kernel/entry.S linux-2.4.27/arch/sh64/kernel/entry.S --- linux-2.4.26/arch/sh64/kernel/entry.S 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.27/arch/sh64/kernel/entry.S 2004-08-07 16:26:04.601344600 -0700 @@ -1607,12 +1607,6 @@ shlli r36, 31, r36 andc r1, r36, r1 /* turn sr.mmu off in real mode section */ - /* Bodge : force sr.watch high on return. Can't understand why else this - isn't happening. */ - movi 1, r38 - shlli r38, 26, r38 - or r38, r0, r0 - putcon r1, ssr _loada .poke0-CONFIG_CACHED_MEMORY_OFFSET, r36 /* real mode target address */ _loada 1f, r37 /* virtual mode return addr */ diff -urN linux-2.4.26/arch/sh64/kernel/head.S linux-2.4.27/arch/sh64/kernel/head.S --- linux-2.4.26/arch/sh64/kernel/head.S 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.27/arch/sh64/kernel/head.S 2004-08-07 16:26:04.601344600 -0700 @@ -37,18 +37,29 @@ #define MMUDR_END DTLB_LAST_VAR_UNRESTRICTED+TLB_STEP #define MMUDR_STEP TLB_STEP +/* Safety check : CONFIG_CACHED_MEMORY_OFFSET has to be a multiple of 512Mb */ +#if (CONFIG_CACHED_MEMORY_OFFSET & ((1UL<<29)-1)) +#error "CONFIG_CACHED_MEMORY_OFFSET must be a multiple of 512Mb" +#endif + /* * MMU defines: Fixed TLBs. */ -#define MMUIR_TEXT_H 0x0000000000000003 | (CONFIG_CACHED_MEMORY_OFFSET + CONFIG_MEMORY_START) +/* Deal safely with the case where the base of RAM is not 512Mb aligned */ + +#define ALIGN_512M_MASK (0xffffffffe0000000) +#define ALIGNED_EFFECTIVE ((CONFIG_CACHED_MEMORY_OFFSET + CONFIG_MEMORY_START) & ALIGN_512M_MASK) +#define ALIGNED_PHYSICAL (CONFIG_MEMORY_START & ALIGN_512M_MASK) + +#define MMUIR_TEXT_H (0x0000000000000003 | ALIGNED_EFFECTIVE) /* Enabled, Shared, ASID 0, Eff. Add. 0xA0000000 */ -#define MMUIR_TEXT_L 0x000000000000009a | (CONFIG_MEMORY_START) +#define MMUIR_TEXT_L (0x000000000000009a | ALIGNED_PHYSICAL) /* 512 Mb, Cacheable, Write-back, execute, Not User, Ph. Add. */ -#define MMUDR_CACHED_H 0x0000000000000003 | (CONFIG_CACHED_MEMORY_OFFSET + CONFIG_MEMORY_START) +#define MMUDR_CACHED_H 0x0000000000000003 | ALIGNED_EFFECTIVE /* Enabled, Shared, ASID 0, Eff. Add. 0xA0000000 */ -#define MMUDR_CACHED_L 0x000000000000015a | (CONFIG_MEMORY_START) +#define MMUDR_CACHED_L 0x000000000000015a | ALIGNED_PHYSICAL /* 512 Mb, Cacheable, Write-back, read/write, Not User, Ph. Add. */ #ifdef CONFIG_ICACHE_DISABLED @@ -209,15 +220,19 @@ /* Map one big (512Mb) page for ITLB */ movi MMUIR_FIRST, r21 movi MMUIR_TEXT_L, r22 /* PTEL first */ + add.l r22, r63, r22 /* Sign extend */ putcfg r21, 1, r22 /* Set MMUIR[0].PTEL */ movi MMUIR_TEXT_H, r22 /* PTEH last */ + add.l r22, r63, r22 /* Sign extend */ putcfg r21, 0, r22 /* Set MMUIR[0].PTEH */ /* Map one big CACHED (512Mb) page for DTLB */ movi MMUDR_FIRST, r21 movi MMUDR_CACHED_L, r22 /* PTEL first */ + add.l r22, r63, r22 /* Sign extend */ putcfg r21, 1, r22 /* Set MMUDR[0].PTEL */ movi MMUDR_CACHED_H, r22 /* PTEH last */ + add.l r22, r63, r22 /* Sign extend */ putcfg r21, 0, r22 /* Set MMUDR[0].PTEH */ /* diff -urN linux-2.4.26/arch/sh64/kernel/pci_sh5.c linux-2.4.27/arch/sh64/kernel/pci_sh5.c --- linux-2.4.26/arch/sh64/kernel/pci_sh5.c 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.27/arch/sh64/kernel/pci_sh5.c 2004-08-07 16:26:04.602344641 -0700 @@ -320,43 +320,70 @@ { int result = -1; - if (dev->bus->number == 0) { - switch ((slot + (pin-1)) & 3) { - case 0: - result = IRQ_INTA; - break; - case 1: - result = IRQ_INTB; - break; - case 2: - result = IRQ_INTC; - break; - case 3: - result = IRQ_INTD; - break; - } - } - - if (dev->bus->number == 2) { - switch((slot + (pin-1)) & 3) { - case 0: - result = IRQ_P2INTA; - break; - case 1: - result = IRQ_P2INTB; - break; - case 2: - result = IRQ_P2INTC; - break; - case 3: - result = IRQ_P2INTD; - break; - } - } - - dprintk("map_cayman_irq for dev %d on bus %d slot %d, pin is %d : irq=%d\n", - dev->devfn,dev->bus->number,slot,pin,result); + /* The complication here is that the PCI IRQ lines from the Cayman's 2 + 5V slots get into the CPU via a different path from the IRQ lines + from the 3 3.3V slots. Thus, we have to detect whether the card's + interrupts go via the 5V or 3.3V path, i.e. the 'bridge swizzling' + at the point where we cross from 5V to 3.3V is not the normal case. + + The added complication is that we don't know that the 5V slots are + always bus 2, because a card containing a PCI-PCI bridge may be + plugged into a 3.3V slot, and this changes the bus numbering. + + Also, the Cayman has an intermediate PCI bus that goes a custom + expansion board header (and to the secondary bridge). This bus has + never been used in practice. + + The 1ary onboard PCI-PCI bridge is device 3 on bus 0 + The 2ary onboard PCI-PCI bridge is device 0 on the 2ary bus of the 1ary bridge. + */ + + struct slot_pin { + int slot; + int pin; + } path[4]; + int i=0; + int base; + + while (dev->bus->number > 0) { + + slot = path[i].slot = PCI_SLOT(dev->devfn); + pin = path[i].pin = bridge_swizzle(pin, slot); + dev = dev->bus->self; + i++; + if (i > 3) panic("PCI path to root bus too long!\n"); + } + slot = PCI_SLOT(dev->devfn); + /* This is the slot on bus 0 through which the device is eventually + reachable. */ + + /* Now work back up. */ + if ((slot < 3) || (i == 0)) { + /* Bus 0 (incl. PCI-PCI bridge itself) : perform the final + swizzle now. */ + result = IRQ_INTA + bridge_swizzle(pin, slot) - 1; + } else { + i--; + slot = path[i].slot; + pin = path[i].pin; + if (slot > 0) { + panic("PCI expansion bus device found - not handled!\n"); + } else { + if (i > 0) { + /* 5V slots */ + i--; + slot = path[i].slot; + pin = path[i].pin; + /* 'pin' was swizzled earlier wrt slot, don't do it again. */ + result = IRQ_P2INTA + (pin - 1); + } else { + /* IRQ for 2ary PCI-PCI bridge : unused */ + result = -1; + } + } + } + return result; } diff -urN linux-2.4.26/arch/sh64/kernel/time.c linux-2.4.27/arch/sh64/kernel/time.c --- linux-2.4.26/arch/sh64/kernel/time.c 2004-02-18 05:36:30.000000000 -0800 +++ linux-2.4.27/arch/sh64/kernel/time.c 2004-08-07 16:26:04.603344682 -0700 @@ -404,13 +404,14 @@ { unsigned int count; unsigned long __dummy; - + unsigned long ctc_val_init, ctc_val; + /* ** Regardless the toolchain, force the compiler to use the ** arbitrary register r3 as a clock tick counter. ** NOTE: r3 must be in accordance with rtc_interrupt() */ - register unsigned long long __clock_tick_count __asm__ ("r3"); + register unsigned long long __rtc_irq_flag __asm__ ("r3"); sti(); do {} while (ctrl_inb(R64CNT) != 0); @@ -419,13 +420,17 @@ /* * r3 is arbitrary. CDC does not support "=z". */ + ctc_val_init = 0xffffffff; + ctc_val = ctc_val_init; + asm volatile("gettr " __t0 ", %1\n\t" + "putcon %0, cr62\n\t" "and %2, r63, %2\n\t" "_pta 4, " __t0 "\n\t" - "addi %0, 1, %0\n\t" "beq/l %2, r63, " __t0 "\n\t" "ptabs %1, " __t0 "\n\t" - : "=r"(count), "=r" (__dummy), "=r" (__clock_tick_count) + "getcon cr62, %0\n\t" + : "=r"(ctc_val), "=r" (__dummy), "=r" (__rtc_irq_flag) : "0" (0)); cli(); /* @@ -445,11 +450,13 @@ * .... * * SH-5: - * CPU clock = 2 stages * loop - * .... + * Use CTC register to count. This approach returns the right value + * even if the I-cache is disabled (e.g. whilst debugging.) * */ + count = ctc_val_init - ctc_val; /* CTC counts down */ + #if defined (CONFIG_SH_SIMULATOR) /* * Let's pretend we are a 5MHz SH-5 to avoid a too @@ -457,18 +464,13 @@ * calibration within a reasonable time. */ return 5000000; -#elif defined (CONFIG_ICACHE_DISABLED) - /* - * Let's pretend we are a 300MHz SH-5. - */ - return 300000000; #else /* * This really is count by the number of clock cycles - * per loop (2) by the ratio between a complete R64CNT + * by the ratio between a complete R64CNT * wrap-around (128) and CUI interrupt being raised (64). */ - return count*2*2; + return count*2; #endif } diff -urN linux-2.4.26/arch/sh64/lib/io.c linux-2.4.27/arch/sh64/lib/io.c --- linux-2.4.26/arch/sh64/lib/io.c 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.27/arch/sh64/lib/io.c 2004-08-07 16:26:04.603344682 -0700 @@ -27,17 +27,23 @@ #define dprintk(x...) -//#define io_addr(x) (((unsigned)(x) & 0x000fffff)| PCI_ST50_IO_ADDR ) - +static int io_addr(int x) { + if (x < 0x400) { #ifdef CONFIG_SH_CAYMAN -extern unsigned long smsc_virt; -extern unsigned long pciio_virt; -#define io_addr(x) ( ((x)<0x400) ? \ - (((x) << 2)|smsc_virt) : \ - ((unsigned long)(x)+pciio_virt) ) + return (x << 2) | smsc_superio_virt; +#else + panic ("Illegal access to I/O port 0x%04x\n", x); + return 0; +#endif + } else { +#ifdef CONFIG_PCI + return (x + pciio_virt); #else -#define io_addr(x) ((unsigned long)(x)+pciio_virt) + panic ("Illegal access to I/O port 0x%04x\n", x); + return 0; #endif + } +} unsigned long inb(unsigned long port) { diff -urN linux-2.4.26/arch/sh64/mach-cayman/irq.c linux-2.4.27/arch/sh64/mach-cayman/irq.c --- linux-2.4.26/arch/sh64/mach-cayman/irq.c 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.27/arch/sh64/mach-cayman/irq.c 2004-08-07 16:26:04.604344723 -0700 @@ -27,9 +27,12 @@ #define EPLD_STATUS_BASE (epld_virt + 0x10) #define EPLD_MASK_BASE (epld_virt + 0x20) +/* Note the SMSC SuperIO chip and SMSC LAN chip interrupts are all muxed onto + the same SH-5 interrupt */ + static void cayman_interrupt_smsc(int irq, void *dev_id, struct pt_regs *regs) { - printk(KERN_INFO "CAYMAN: spurious interrupt\n"); + printk(KERN_INFO "CAYMAN: spurious SMSC interrupt\n"); } static void cayman_interrupt_pci2(int irq, void *dev_id, struct pt_regs *regs) diff -urN linux-2.4.26/arch/sh64/mach-cayman/setup.c linux-2.4.27/arch/sh64/mach-cayman/setup.c --- linux-2.4.26/arch/sh64/mach-cayman/setup.c 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.27/arch/sh64/mach-cayman/setup.c 2004-08-07 16:26:04.604344723 -0700 @@ -74,7 +74,7 @@ #define ITI TOP_PRIORITY /* WDT Ints */ /* Setup for the SMSC FDC37C935 */ -#define SMSC_BASE 0x04000000 +#define SMSC_SUPERIO_BASE 0x04000000 #define SMSC_CONFIG_PORT_ADDR 0x3f0 #define SMSC_INDEX_PORT_ADDR SMSC_CONFIG_PORT_ADDR #define SMSC_DATA_PORT_ADDR 0x3f1 @@ -91,14 +91,14 @@ #define SMSC_KEYBOARD_DEVICE 7 -#define SMSC_READ_INDEXED(index) ({ \ +#define SMSC_SUPERIO_READ_INDEXED(index) ({ \ outb((index), SMSC_INDEX_PORT_ADDR); \ inb(SMSC_DATA_PORT_ADDR); }) -#define SMSC_WRITE_INDEXED(val, index) ({ \ +#define SMSC_SUPERIO_WRITE_INDEXED(val, index) ({ \ outb((index), SMSC_INDEX_PORT_ADDR); \ outb((val), SMSC_DATA_PORT_ADDR); }) -unsigned long smsc_virt; +unsigned long smsc_superio_virt; /* * Platform dependent structures: maps and parms block. @@ -145,13 +145,13 @@ RES, RES, RES, RES, RES, RES, RES, ITI, /* IRQ 56-63 */ }; -static int __init smsc_setup(void) +static int __init smsc_superio_setup(void) { unsigned char devid, devrev; - smsc_virt = onchip_remap(SMSC_BASE, 1024, "SMSC"); - if (!smsc_virt) { - panic("Unable to remap SMSC\n"); + smsc_superio_virt = onchip_remap(SMSC_SUPERIO_BASE, 1024, "SMSC SuperIO"); + if (!smsc_superio_virt) { + panic("Unable to remap SMSC SuperIO\n"); } /* Initially the chip is in run state */ @@ -160,20 +160,20 @@ outb(SMSC_ENTER_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR); /* Read device ID info */ - devid = SMSC_READ_INDEXED(SMSC_DEVICE_ID_INDEX); - devrev = SMSC_READ_INDEXED(SMSC_DEVICE_REV_INDEX); - printk("SMSC devid %02x rev %02x\n", devid, devrev); + devid = SMSC_SUPERIO_READ_INDEXED(SMSC_DEVICE_ID_INDEX); + devrev = SMSC_SUPERIO_READ_INDEXED(SMSC_DEVICE_REV_INDEX); + printk("SMSC SuperIO devid %02x rev %02x\n", devid, devrev); /* Select the keyboard device */ - SMSC_WRITE_INDEXED(SMSC_KEYBOARD_DEVICE, SMCS_LOGICAL_DEV_INDEX); + SMSC_SUPERIO_WRITE_INDEXED(SMSC_KEYBOARD_DEVICE, SMCS_LOGICAL_DEV_INDEX); /* enable it */ - SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX); + SMSC_SUPERIO_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX); /* Select the interrupts */ /* On a PC keyboard is IRQ1, mouse is IRQ12 */ - SMSC_WRITE_INDEXED(1, SMSC_PRIMARY_INT_INDEX); - SMSC_WRITE_INDEXED(12, SMSC_SECONDARY_INT_INDEX); + SMSC_SUPERIO_WRITE_INDEXED(1, SMSC_PRIMARY_INT_INDEX); + SMSC_SUPERIO_WRITE_INDEXED(12, SMSC_SECONDARY_INT_INDEX); /* Exit the configuraton state */ outb(SMSC_EXIT_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR); @@ -184,7 +184,7 @@ /* This is grotty, but, because kernel is always referenced on the link line * before any devices, this is safe. */ -__initcall(smsc_setup); +__initcall(smsc_superio_setup); void __init platform_setup(void) { diff -urN linux-2.4.26/arch/sh64/mm/cache.c linux-2.4.27/arch/sh64/mm/cache.c --- linux-2.4.26/arch/sh64/mm/cache.c 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.27/arch/sh64/mm/cache.c 2004-08-07 16:26:04.605344764 -0700 @@ -474,7 +474,7 @@ /* Assumes this address (+ (2**n_synbits) pages up from it) aren't used for anything else in the kernel */ -#define MAGIC_PAGE0_START 0xffffffffe0000000ULL +#define MAGIC_PAGE0_START 0xffffffffec000000ULL static void sh64_dcache_purge_coloured_phy_page(unsigned long paddr, unsigned long eaddr) { @@ -740,8 +740,8 @@ /****************************************************************************/ /* These *MUST* lie in an area of virtual address space that's otherwise unused. */ -#define UNIQUE_EADDR_START 0xc0000000UL -#define UNIQUE_EADDR_END 0xd0000000UL +#define UNIQUE_EADDR_START 0xe0000000UL +#define UNIQUE_EADDR_END 0xe8000000UL static unsigned long sh64_make_unique_eaddr(unsigned long user_eaddr, unsigned long paddr) { diff -urN linux-2.4.26/arch/sh64/vmlinux.lds.S linux-2.4.27/arch/sh64/vmlinux.lds.S --- linux-2.4.26/arch/sh64/vmlinux.lds.S 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.27/arch/sh64/vmlinux.lds.S 2004-08-07 16:26:04.606344805 -0700 @@ -38,7 +38,6 @@ OUTPUT_ARCH(sh:sh5) #define C_PHYS(x) AT (ADDR(x) - CONFIG_CACHED_MEMORY_OFFSET) -#define U_PHYS(x) AT (ADDR(x) - CONFIG_UNCACHED_MEMORY_OFFSET) ENTRY(__start) SECTIONS diff -urN linux-2.4.26/arch/sparc/Makefile linux-2.4.27/arch/sparc/Makefile --- linux-2.4.26/arch/sparc/Makefile 2001-07-28 12:12:37.000000000 -0700 +++ linux-2.4.27/arch/sparc/Makefile 2004-08-07 16:26:04.606344805 -0700 @@ -16,7 +16,7 @@ # debugging of the kernel to get the proper debugging information. IS_EGCS := $(shell if $(CC) -m32 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo y; else echo n; fi; ) -NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi) +NEW_GAS := $(shell if $(LD) -V 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi) ifeq ($(NEW_GAS),y) AS := $(AS) -32 diff -urN linux-2.4.26/arch/sparc/kernel/process.c linux-2.4.27/arch/sparc/kernel/process.c --- linux-2.4.26/arch/sparc/kernel/process.c 2003-06-13 07:51:32.000000000 -0700 +++ linux-2.4.27/arch/sparc/kernel/process.c 2004-08-07 16:26:04.607344846 -0700 @@ -54,6 +54,12 @@ */ void (*pm_power_off)(void); +/* + * sysctl - toggle power-off restriction for serial console + * systems in machine_power_off() + */ +int scons_pwroff = 1; + extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *); struct task_struct *last_task_used_math = NULL; @@ -189,7 +195,7 @@ void machine_power_off(void) { #ifdef CONFIG_SUN_AUXIO - if (auxio_power_register && !serial_console) + if (auxio_power_register && (!serial_console || scons_pwroff)) *auxio_power_register |= AUXIO_POWER_OFF; #endif machine_halt(); diff -urN linux-2.4.26/arch/sparc/kernel/unaligned.c linux-2.4.27/arch/sparc/kernel/unaligned.c --- linux-2.4.26/arch/sparc/kernel/unaligned.c 2002-02-25 11:37:56.000000000 -0800 +++ linux-2.4.27/arch/sparc/kernel/unaligned.c 2004-08-07 16:26:04.608344887 -0700 @@ -136,8 +136,8 @@ return &win->locals[reg - 16]; } -static inline unsigned long compute_effective_address(struct pt_regs *regs, - unsigned int insn) +static unsigned long compute_effective_address(struct pt_regs *regs, + unsigned int insn) { unsigned int rs1 = (insn >> 14) & 0x1f; unsigned int rs2 = insn & 0x1f; @@ -152,8 +152,8 @@ } } -static inline unsigned long safe_compute_effective_address(struct pt_regs *regs, - unsigned int insn) +unsigned long safe_compute_effective_address(struct pt_regs *regs, + unsigned int insn) { unsigned int rs1 = (insn >> 14) & 0x1f; unsigned int rs2 = insn & 0x1f; diff -urN linux-2.4.26/arch/sparc/mm/fault.c linux-2.4.27/arch/sparc/mm/fault.c --- linux-2.4.26/arch/sparc/mm/fault.c 2003-06-13 07:51:32.000000000 -0700 +++ linux-2.4.27/arch/sparc/mm/fault.c 2004-08-07 16:26:04.609344928 -0700 @@ -200,6 +200,25 @@ return 0; } +extern unsigned long safe_compute_effective_address(struct pt_regs *, + unsigned int); + +static unsigned long compute_si_addr(struct pt_regs *regs, int text_fault) +{ + unsigned int insn; + + if (text_fault) + return regs->pc; + + if (regs->psr & PSR_PS) { + insn = *(unsigned int *) regs->pc; + } else { + __get_user(insn, (unsigned int *) regs->pc); + } + + return safe_compute_effective_address(regs, insn); +} + asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, unsigned long address) { @@ -306,7 +325,7 @@ info.si_errno = 0; /* info.si_code set above to make clear whether this was a SEGV_MAPERR or SEGV_ACCERR fault. */ - info.si_addr = (void *)address; + info.si_addr = (void *) compute_si_addr(regs, text_fault); info.si_trapno = 0; force_sig_info (SIGSEGV, &info, tsk); return; @@ -360,7 +379,7 @@ info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRERR; - info.si_addr = (void *)address; + info.si_addr = (void *) compute_si_addr(regs, text_fault); info.si_trapno = 0; force_sig_info (SIGBUS, &info, tsk); if (!from_user) @@ -523,7 +542,7 @@ info.si_errno = 0; /* info.si_code set above to make clear whether this was a SEGV_MAPERR or SEGV_ACCERR fault. */ - info.si_addr = (void *)address; + info.si_addr = (void *) address; info.si_trapno = 0; force_sig_info (SIGSEGV, &info, tsk); return; @@ -533,7 +552,7 @@ info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRERR; - info.si_addr = (void *)address; + info.si_addr = (void *) address; info.si_trapno = 0; force_sig_info (SIGBUS, &info, tsk); } diff -urN linux-2.4.26/arch/sparc/prom/memory.c linux-2.4.27/arch/sparc/prom/memory.c --- linux-2.4.26/arch/sparc/prom/memory.c 2000-01-31 23:37:19.000000000 -0800 +++ linux-2.4.27/arch/sparc/prom/memory.c 2004-08-07 16:26:04.609344928 -0700 @@ -156,7 +156,7 @@ prom_prom_taken[iter].num_bytes = (unsigned long) prom_reg_memlist[iter].reg_size; prom_prom_taken[iter].theres_more = - &prom_phys_total[iter+1]; + &prom_prom_taken[iter+1]; } prom_prom_taken[iter-1].theres_more = 0x0; diff -urN linux-2.4.26/arch/sparc64/Makefile linux-2.4.27/arch/sparc64/Makefile --- linux-2.4.26/arch/sparc64/Makefile 2003-06-13 07:51:32.000000000 -0700 +++ linux-2.4.27/arch/sparc64/Makefile 2004-08-07 16:26:04.610344969 -0700 @@ -12,7 +12,7 @@ # line... SHELL =/bin/bash -CC := $(shell if gcc -m64 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo gcc; else echo sparc64-linux-gcc; fi ) +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_GAS := $(shell if $(LD) -V 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi) diff -urN linux-2.4.26/arch/sparc64/config.in linux-2.4.27/arch/sparc64/config.in --- linux-2.4.26/arch/sparc64/config.in 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.27/arch/sparc64/config.in 2004-08-07 16:26:04.610344969 -0700 @@ -21,6 +21,8 @@ mainmenu_option next_comment comment 'General setup' +source drivers/i2c/Config.in + tristate 'UltraSPARC-III bootbus i2c controller driver' CONFIG_BBC_I2C define_bool CONFIG_VT y diff -urN linux-2.4.26/arch/sparc64/defconfig linux-2.4.27/arch/sparc64/defconfig --- linux-2.4.26/arch/sparc64/defconfig 2004-04-14 06:05:27.000000000 -0700 +++ linux-2.4.27/arch/sparc64/defconfig 2004-08-07 16:26:04.611345011 -0700 @@ -17,6 +17,20 @@ # # General setup # + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_ALGOBIT=y +# CONFIG_I2C_PHILIPSPAR is not set +# CONFIG_I2C_ELV is not set +# CONFIG_I2C_VELLEMAN is not set +# CONFIG_SCx200_I2C is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_PROC=y CONFIG_BBC_I2C=m CONFIG_VT=y CONFIG_VT_CONSOLE=y @@ -428,6 +442,7 @@ # CONFIG_WDC_ALI15X3 is not set CONFIG_BLK_DEV_AMD74XX=m # CONFIG_AMD74XX_OVERRIDE is not set +CONFIG_BLK_DEV_ATIIXP=m CONFIG_BLK_DEV_CMD64X=y # CONFIG_BLK_DEV_TRIFLEX is not set CONFIG_BLK_DEV_CY82C693=m @@ -1121,6 +1136,7 @@ CONFIG_CRYPTO_CAST6=m CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_MICHAEL_MIC=m # CONFIG_CRYPTO_TEST is not set # diff -urN linux-2.4.26/arch/sparc64/kernel/ioctl32.c linux-2.4.27/arch/sparc64/kernel/ioctl32.c --- linux-2.4.26/arch/sparc64/kernel/ioctl32.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.27/arch/sparc64/kernel/ioctl32.c 2004-08-07 16:26:04.615345175 -0700 @@ -1271,6 +1271,7 @@ case FDGETPRM32: { struct floppy_struct *f; + u32 u_name; f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL); if (!karg) @@ -1286,7 +1287,8 @@ err |= __get_user(f->rate, &((struct floppy_struct32 *)arg)->rate); err |= __get_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1); err |= __get_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap); - err |= __get_user((u64)f->name, &((struct floppy_struct32 *)arg)->name); + err |= __get_user(u_name, &((struct floppy_struct32 *)arg)->name); + f->name = (void *) (long) u_name; if (err) { err = -EFAULT; goto out; @@ -3810,13 +3812,15 @@ { struct blkpg_ioctl_arg a; struct blkpg_partition p; + u32 u_data; int err; mm_segment_t old_fs = get_fs(); err = get_user(a.op, &arg->op); err |= __get_user(a.flags, &arg->flags); err |= __get_user(a.datalen, &arg->datalen); - err |= __get_user((long)a.data, &arg->data); + err |= __get_user(u_data, &arg->data); + a.data = (void *) (long) u_data; if (err) return err; switch (a.op) { case BLKPG_ADD_PARTITION: @@ -4416,6 +4420,7 @@ COMPATIBLE_IOCTL(HDIO_SET_32BIT) COMPATIBLE_IOCTL(HDIO_SET_MULTCOUNT) COMPATIBLE_IOCTL(HDIO_DRIVE_CMD) +COMPATIBLE_IOCTL(HDIO_DRIVE_TASK) COMPATIBLE_IOCTL(HDIO_SET_PIO_MODE) COMPATIBLE_IOCTL(HDIO_SCAN_HWIF) COMPATIBLE_IOCTL(HDIO_SET_NICE) diff -urN linux-2.4.26/arch/sparc64/kernel/power.c linux-2.4.27/arch/sparc64/kernel/power.c --- linux-2.4.26/arch/sparc64/kernel/power.c 2003-06-13 07:51:32.000000000 -0700 +++ linux-2.4.27/arch/sparc64/kernel/power.c 2004-08-07 16:26:04.616345216 -0700 @@ -17,6 +17,12 @@ #define __KERNEL_SYSCALLS__ #include +/* + * sysctl - toggle power-off restriction for serial console + * systems in machine_power_off() + */ +int scons_pwroff = 1; + #ifdef CONFIG_PCI static unsigned long power_reg = 0UL; @@ -40,7 +46,7 @@ void machine_power_off(void) { - if (!serial_console) { + if (!serial_console || scons_pwroff) { #ifdef CONFIG_PCI if (power_reg != 0UL) { /* Both register bits seem to have the diff -urN linux-2.4.26/arch/sparc64/kernel/process.c linux-2.4.27/arch/sparc64/kernel/process.c --- linux-2.4.26/arch/sparc64/kernel/process.c 2003-06-13 07:51:32.000000000 -0700 +++ linux-2.4.27/arch/sparc64/kernel/process.c 2004-08-07 16:26:04.616345216 -0700 @@ -453,7 +453,7 @@ page = pmd_alloc_one(NULL, 0); pgd_set(pgd0, page); } - pgd_cache = pgd_val(*pgd0) << 11UL; + pgd_cache = ((unsigned long) pgd_val(*pgd0)) << 11UL; } __asm__ __volatile__("stxa %0, [%1] %2\n\t" "membar #Sync" diff -urN linux-2.4.26/arch/sparc64/kernel/signal32.c linux-2.4.27/arch/sparc64/kernel/signal32.c --- linux-2.4.26/arch/sparc64/kernel/signal32.c 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.27/arch/sparc64/kernel/signal32.c 2004-08-07 16:26:04.618345298 -0700 @@ -393,7 +393,7 @@ { struct rt_signal_frame32 *sf; unsigned int psr; - unsigned pc, npc, fpu_save; + unsigned pc, npc, fpu_save, u_ss_sp; mm_segment_t old_fs; sigset_t set; sigset_t32 seta; @@ -444,7 +444,8 @@ if (fpu_save) err |= restore_fpu_state32(regs, &sf->fpu_state); err |= copy_from_user(&seta, &sf->mask, sizeof(sigset_t32)); - err |= __get_user((long)st.ss_sp, &sf->stack.ss_sp); + err |= __get_user(u_ss_sp, &sf->stack.ss_sp); + st.ss_sp = (void *) (long) u_ss_sp; err |= __get_user(st.ss_flags, &sf->stack.ss_flags); err |= __get_user(st.ss_size, &sf->stack.ss_size); if (err) @@ -1030,7 +1031,7 @@ struct thread_struct *tp = ¤t->thread; svr4_gregset_t *gr; mm_segment_t old_fs; - u32 pc, npc, psr; + u32 pc, npc, psr, u_ss_sp; sigset_t set; svr4_sigset_t setv; int i, err; @@ -1075,7 +1076,8 @@ if (_NSIG_WORDS >= 2) set.sig[1] = setv.sigbits[2] | (((long)setv.sigbits[3]) << 32); - err |= __get_user((long)st.ss_sp, &c->stack.sp); + err |= __get_user(u_ss_sp, &c->stack.sp); + st.ss_sp = (void *) (long) u_ss_sp; err |= __get_user(st.ss_flags, &c->stack.flags); err |= __get_user(st.ss_size, &c->stack.size); if (err) @@ -1545,9 +1547,9 @@ /* Now see if we want to update the new state. */ if (ssptr) { - void *ss_sp; + u32 ss_sp; - if (get_user((long)ss_sp, &ssptr->the_stack)) + if (get_user(ss_sp, &ssptr->the_stack)) goto out; /* If the current stack was set with sigaltstack, don't swap stacks while we are on it. */ @@ -1570,13 +1572,15 @@ asmlinkage int do_sys32_sigaltstack(u32 ussa, u32 uossa, unsigned long sp) { stack_t uss, uoss; + u32 u_ss_sp = 0; int ret; mm_segment_t old_fs; - if (ussa && (get_user((long)uss.ss_sp, &((stack_t32 *)(long)ussa)->ss_sp) || + if (ussa && (get_user(u_ss_sp, &((stack_t32 *)(long)ussa)->ss_sp) || __get_user(uss.ss_flags, &((stack_t32 *)(long)ussa)->ss_flags) || __get_user(uss.ss_size, &((stack_t32 *)(long)ussa)->ss_size))) return -EFAULT; + uss.ss_sp = (void *) (long) u_ss_sp; old_fs = get_fs(); set_fs(KERNEL_DS); ret = do_sigaltstack(ussa ? &uss : NULL, uossa ? &uoss : NULL, sp); diff -urN linux-2.4.26/arch/sparc64/kernel/sparc64_ksyms.c linux-2.4.27/arch/sparc64/kernel/sparc64_ksyms.c --- linux-2.4.26/arch/sparc64/kernel/sparc64_ksyms.c 2003-06-13 07:51:32.000000000 -0700 +++ linux-2.4.27/arch/sparc64/kernel/sparc64_ksyms.c 2004-08-07 16:26:04.618345298 -0700 @@ -89,6 +89,7 @@ extern int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *)); extern int unregister_ioctl32_conversion(unsigned int cmd); extern int io_remap_page_range(unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space); +extern void (*prom_palette)(int); extern int __ashrdi3(int, int); @@ -371,3 +372,5 @@ #endif EXPORT_SYMBOL(tick_ops); + +EXPORT_SYMBOL(prom_palette); diff -urN linux-2.4.26/arch/sparc64/kernel/sys_sparc32.c linux-2.4.27/arch/sparc64/kernel/sys_sparc32.c --- linux-2.4.26/arch/sparc64/kernel/sys_sparc32.c 2004-04-14 06:05:27.000000000 -0700 +++ linux-2.4.27/arch/sparc64/kernel/sys_sparc32.c 2004-08-07 16:26:04.621345421 -0700 @@ -1316,7 +1316,7 @@ put_user(reclen, &dirent->d_reclen); copy_to_user(dirent->d_name, name, namlen); put_user(0, dirent->d_name + namlen); - ((char *) dirent) += reclen; + dirent = (void *) dirent + reclen; buf->current_dir = dirent; buf->count -= reclen; return 0; @@ -3056,9 +3056,12 @@ if (act) { old_sigset_t32 mask; + u32 u_handler, u_restorer; - ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler); - ret |= __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer); + ret = get_user(u_handler, &act->sa_handler); + new_ka.sa.sa_handler = (void *) (long) u_handler; + ret |= __get_user(u_restorer, &act->sa_restorer); + new_ka.sa.sa_restorer = (void *) (long) u_restorer; ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); ret |= __get_user(mask, &act->sa_mask); if (ret) @@ -3097,8 +3100,11 @@ current->thread.flags |= SPARC_FLAG_NEWSIGNALS; if (act) { + u32 u_handler, u_restorer; + new_ka.ka_restorer = restorer; - ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler); + ret = get_user(u_handler, &act->sa_handler); + new_ka.sa.sa_handler = (void *) (long) u_handler; ret |= __copy_from_user(&set32, &act->sa_mask, sizeof(sigset_t32)); switch (_NSIG_WORDS) { case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] | (((long)set32.sig[7]) << 32); @@ -3107,7 +3113,8 @@ case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0] | (((long)set32.sig[1]) << 32); } ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); - ret |= __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer); + ret |= __get_user(u_restorer, &act->sa_restorer); + new_ka.sa.sa_restorer = (void *) (long) u_restorer; if (ret) return -EFAULT; } diff -urN linux-2.4.26/arch/sparc64/kernel/sys_sunos32.c linux-2.4.27/arch/sparc64/kernel/sys_sunos32.c --- linux-2.4.26/arch/sparc64/kernel/sys_sunos32.c 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.27/arch/sparc64/kernel/sys_sunos32.c 2004-08-07 16:26:04.622345463 -0700 @@ -296,7 +296,7 @@ put_user(reclen, &dirent->d_reclen); copy_to_user(dirent->d_name, name, namlen); put_user(0, dirent->d_name + namlen); - ((char *) dirent) += reclen; + dirent = (void *) dirent + reclen; buf->curr = dirent; buf->count -= reclen; return 0; @@ -376,7 +376,7 @@ put_user(reclen, &dirent->d_reclen); copy_to_user(dirent->d_name, name, namlen); put_user(0, dirent->d_name + namlen); - ((char *) dirent) += reclen; + dirent = (void *) dirent + reclen; buf->curr = dirent; buf->count -= reclen; return 0; @@ -1309,10 +1309,12 @@ if (act) { old_sigset_t32 mask; + u32 u_handler; - if (get_user((long)new_ka.sa.sa_handler, &((struct old_sigaction32 *)A(act))->sa_handler) || + if (get_user(u_handler, &((struct old_sigaction32 *)A(act))->sa_handler) || __get_user(new_ka.sa.sa_flags, &((struct old_sigaction32 *)A(act))->sa_flags)) return -EFAULT; + new_ka.sa.sa_handler = (void *) (long) u_handler; __get_user(mask, &((struct old_sigaction32 *)A(act))->sa_mask); new_ka.sa.sa_restorer = NULL; new_ka.ka_restorer = NULL; diff -urN linux-2.4.26/arch/sparc64/kernel/unaligned.c linux-2.4.27/arch/sparc64/kernel/unaligned.c --- linux-2.4.26/arch/sparc64/kernel/unaligned.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.27/arch/sparc64/kernel/unaligned.c 2004-08-07 16:26:04.623345504 -0700 @@ -149,8 +149,8 @@ } } -static inline unsigned long compute_effective_address(struct pt_regs *regs, - unsigned int insn, unsigned int rd) +unsigned long compute_effective_address(struct pt_regs *regs, + unsigned int insn, unsigned int rd) { unsigned int rs1 = (insn >> 14) & 0x1f; unsigned int rs2 = insn & 0x1f; @@ -166,7 +166,7 @@ } /* This is just to make gcc think die_if_kernel does return... */ -static void unaligned_panic(char *str, struct pt_regs *regs) +static void __attribute_used__ unaligned_panic(char *str, struct pt_regs *regs) { die_if_kernel(str, regs); } diff -urN linux-2.4.26/arch/sparc64/mm/fault.c linux-2.4.27/arch/sparc64/mm/fault.c --- linux-2.4.26/arch/sparc64/mm/fault.c 2002-11-28 15:53:12.000000000 -0800 +++ linux-2.4.27/arch/sparc64/mm/fault.c 2004-08-07 16:26:04.624345545 -0700 @@ -203,14 +203,21 @@ return insn; } -static void do_fault_siginfo(int code, int sig, unsigned long address) +extern unsigned long compute_effective_address(struct pt_regs *, unsigned int, unsigned int); + +static void do_fault_siginfo(int code, int sig, struct pt_regs *regs, + unsigned int insn, int fault_code) { siginfo_t info; info.si_code = code; info.si_signo = sig; info.si_errno = 0; - info.si_addr = (void *) address; + if (fault_code & FAULT_CODE_ITLB) + info.si_addr = (void *) regs->tpc; + else + info.si_addr = (void *) + compute_effective_address(regs, insn, 0); info.si_trapno = 0; force_sig_info(sig, &info, current); } @@ -291,7 +298,7 @@ /* The si_code was set to make clear whether * this was a SEGV_MAPERR or SEGV_ACCERR fault. */ - do_fault_siginfo(si_code, SIGSEGV, address); + do_fault_siginfo(si_code, SIGSEGV, regs, insn, fault_code); return; } @@ -467,7 +474,7 @@ * Send a sigbus, regardless of whether we were in kernel * or user mode. */ - do_fault_siginfo(BUS_ADRERR, SIGBUS, address); + do_fault_siginfo(BUS_ADRERR, SIGBUS, regs, insn, fault_code); /* Kernel mode? Handle exceptions or die */ if (regs->tstate & TSTATE_PRIV) diff -urN linux-2.4.26/arch/sparc64/mm/init.c linux-2.4.27/arch/sparc64/mm/init.c --- linux-2.4.26/arch/sparc64/mm/init.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.27/arch/sparc64/mm/init.c 2004-08-07 16:26:04.625345586 -0700 @@ -1433,8 +1433,10 @@ /* Now can init the kernel/bad page tables. */ pgd_set(&swapper_pg_dir[0], swapper_pmd_dir + (shift / sizeof(pgd_t))); - sparc64_vpte_patchme1[0] |= (pgd_val(init_mm.pgd[0]) >> 10); - sparc64_vpte_patchme2[0] |= (pgd_val(init_mm.pgd[0]) & 0x3ff); + sparc64_vpte_patchme1[0] |= + (((unsigned long)pgd_val(init_mm.pgd[0])) >> 10); + sparc64_vpte_patchme2[0] |= + (((unsigned long)pgd_val(init_mm.pgd[0])) & 0x3ff); flushi((long)&sparc64_vpte_patchme1[0]); /* Setup bootmem... */ diff -urN linux-2.4.26/arch/sparc64/prom/memory.c linux-2.4.27/arch/sparc64/prom/memory.c --- linux-2.4.26/arch/sparc64/prom/memory.c 1999-08-31 11:23:30.000000000 -0700 +++ linux-2.4.27/arch/sparc64/prom/memory.c 2004-08-07 16:26:04.626345627 -0700 @@ -114,7 +114,7 @@ prom_prom_taken[iter].num_bytes = prom_reg_memlist[iter].reg_size; prom_prom_taken[iter].theres_more = - &prom_phys_total[iter+1]; + &prom_prom_taken[iter+1]; } prom_prom_taken[iter-1].theres_more = 0x0; diff -urN linux-2.4.26/arch/x86_64/boot/bootsect.S linux-2.4.27/arch/x86_64/boot/bootsect.S --- linux-2.4.26/arch/x86_64/boot/bootsect.S 2003-06-13 07:51:32.000000000 -0700 +++ linux-2.4.27/arch/x86_64/boot/bootsect.S 2004-08-07 16:26:04.626345627 -0700 @@ -234,9 +234,10 @@ die: jne die # %es must be at 64kB boundary xorw %bx, %bx # %bx is starting address within segment rp_read: -#ifdef __BIG_KERNEL__ # look in setup.S for bootsect_kludge +#ifdef __BIG_KERNEL__ + # look in setup.S for bootsect_kludge bootsect_kludge = 0x220 # 0x200 + 0x20 which is the size of the - lcall bootsect_kludge # bootsector + bootsect_kludge offset + lcall *bootsect_kludge # bootsector + bootsect_kludge offset #else movw %es, %ax subw $SYSSEG, %ax diff -urN linux-2.4.26/arch/x86_64/ia32/ia32entry.S linux-2.4.27/arch/x86_64/ia32/ia32entry.S --- linux-2.4.26/arch/x86_64/ia32/ia32entry.S 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.27/arch/x86_64/ia32/ia32entry.S 2004-08-07 16:26:04.627345668 -0700 @@ -71,7 +71,7 @@ movq %rsp,%rdi /* &pt_regs -> arg1 */ call syscall_trace LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ - addq $ARGOFFSET,%rsp + RESTORE_REST cmpl $(IA32_NR_syscalls),%eax jae 1f IA32_ARG_FIXUP @@ -81,7 +81,7 @@ 1: SAVE_REST movq %rsp,%rdi /* &pt_regs -> arg1 */ call syscall_trace - addq $ARGOFFSET,%rsp + RESTORE_REST jmp int_ret_from_sys_call ia32_badsys: diff -urN linux-2.4.26/arch/x86_64/kernel/Makefile linux-2.4.27/arch/x86_64/kernel/Makefile --- linux-2.4.26/arch/x86_64/kernel/Makefile 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.27/arch/x86_64/kernel/Makefile 2004-08-07 16:26:04.627345668 -0700 @@ -14,7 +14,8 @@ O_TARGET := kernel.o -export-objs := mtrr.o msr.o cpuid.o x8664_ksyms.o pci-gart.o setup.o swiotlb.o +export-objs := mtrr.o msr.o cpuid.o x8664_ksyms.o pci-gart.o setup.o \ + swiotlb.o bluesmoke.o 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 \ diff -urN linux-2.4.26/arch/x86_64/kernel/acpi.c linux-2.4.27/arch/x86_64/kernel/acpi.c --- linux-2.4.26/arch/x86_64/kernel/acpi.c 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.27/arch/x86_64/kernel/acpi.c 2004-08-07 16:26:04.628345709 -0700 @@ -56,7 +56,10 @@ /* -------------------------------------------------------------------------- Boot-time Configuration -------------------------------------------------------------------------- */ - +#ifdef CONFIG_ACPI_PCI +int acpi_noirq __initdata; /* skip ACPI IRQ initialization */ +int acpi_pci_disabled __initdata; /* skip ACPI PCI scan and IRQ initialization */ +#endif int acpi_ht __initdata = 1; /* enable HT */ enum acpi_irq_model_id acpi_irq_model; @@ -119,11 +122,40 @@ #endif } +#ifdef CONFIG_ACPI_MMCONFIG + +u32 pci_mmcfg_base_addr; + +static int __init +acpi_parse_mcfg(unsigned long phys_addr, + unsigned long size) +{ + struct acpi_table_mcfg *mcfg = NULL; + + if (!phys_addr || !size) + return -EINVAL; + + mcfg = (struct acpi_table_mcfg *) __acpi_map_table(phys_addr, size); + if (!mcfg) { + printk(KERN_WARNING PREFIX "Unable to map MCFG\n"); + return -ENODEV; + } + + if (mcfg->base_reserved) { + printk(KERN_ERR PREFIX "MMCONFIG not in low 4GB of memory\n"); + return -ENODEV; + } + + pci_mmcfg_base_addr = mcfg->base_address; + + return 0; +} +#endif /* CONFIG_ACPI_MMCONFIG */ + #ifdef CONFIG_X86_LOCAL_APIC static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE; - static int __init acpi_parse_madt ( unsigned long phys_addr, @@ -330,7 +362,7 @@ #endif /*CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER*/ - +#ifdef CONFIG_HPET_TIMER static int __init acpi_parse_hpet ( unsigned long phys_addr, @@ -351,6 +383,7 @@ return 0; } +#endif /* CONFIG_HPET_TIMER */ #ifdef CONFIG_ACPI_BUS /* @@ -457,17 +490,16 @@ return result; } -#ifdef CONFIG_X86_LOCAL_APIC +#ifdef CONFIG_ACPI_MMCONFIG + result = acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); + if (result < 0) { + printk(KERN_ERR PREFIX "Error %d parsing MCFG\n", result); + } else if (result > 1) { + printk(KERN_WARNING PREFIX "Multiple MCFG tables exist\n"); + } +#endif - /* this check should not need to be here -lenb */ - /* If "nolocalapic" is specified don't look further */ - extern int apic_disabled; - if (apic_disabled) { - printk(KERN_INFO PREFIX "Skipping Local/IO-APIC probe due to \"nolocalapic\"\n"); - return 0; - } - printk(KERN_INFO PREFIX "Parsing Local APIC info in MADT\n"); - +#ifdef CONFIG_X86_LOCAL_APIC /* * MADT @@ -573,9 +605,6 @@ return result; } - /* Build a default routing table for legacy (ISA) interrupts. */ - mp_config_acpi_legacy_irqs(); - /* Record sci_int for use when looking for MADT sci_int override */ acpi_table_parse(ACPI_FADT, acpi_parse_fadt); @@ -593,6 +622,9 @@ if (!acpi_sci_override_gsi) acpi_sci_ioapic_setup(acpi_fadt.sci_int, 0, 0); + /* Fill in identity legacy mapings where no override */ + mp_config_acpi_legacy_irqs(); + result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); @@ -609,9 +641,11 @@ if (acpi_lapic && acpi_ioapic) smp_found_config = 1; +#ifdef CONFIG_HPET_TIMER result = acpi_table_parse(ACPI_HPET, acpi_parse_hpet); if (result < 0) printk("ACPI: no HPET table found (%d).\n", result); +#endif #endif /*CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER*/ diff -urN linux-2.4.26/arch/x86_64/kernel/bluesmoke.c linux-2.4.27/arch/x86_64/kernel/bluesmoke.c --- linux-2.4.26/arch/x86_64/kernel/bluesmoke.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.27/arch/x86_64/kernel/bluesmoke.c 2004-08-07 16:26:04.630345791 -0700 @@ -1,19 +1,25 @@ /* * Machine check handler. * K8 parts Copyright 2002,2003 Andi Kleen, SuSE Labs. - * Rest from unknown author(s). + * Additional K8 decoding and simplification Copyright 2003 Eric Morton, Newisys Inc + * Rest from unknown author(s). */ +#include +#include #include #include #include #include #include #include +#include +#include +#include +#include #include #include #include -#include -#include +#include static int mce_disabled __initdata; static unsigned long mce_cpus; @@ -25,18 +31,27 @@ static int banks; static unsigned long ignored_banks, disabled_banks; +struct notifier_block *mc_notifier_list = NULL; +EXPORT_SYMBOL(mc_notifier_list); + static void generic_machine_check(struct pt_regs * regs, long error_code) { int recover=1; u32 alow, ahigh, high, low; u32 mcgstl, mcgsth; int i; - + struct notifier_mc_err mc_err; + rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth); if(mcgstl&(1<<0)) /* Recoverable ? */ recover=0; - printk(KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n", smp_processor_id(), mcgsth, mcgstl); + /* Make sure unrecoverable MCEs reach the console */ + if(recover & 3) + oops_in_progress++; + + printk(KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n", + smp_processor_id(), mcgsth, mcgstl); if (regs && (mcgstl & 2)) printk(KERN_EMERG "RIP <%02lx>:%016lx RSP %016lx\n", @@ -50,6 +65,10 @@ rdmsr(MSR_IA32_MC0_STATUS+i*4,low, high); if(high&(1<<31)) { + memset(&mc_err, 0x00, sizeof(mc_err)); + mc_err.cpunum = safe_smp_processor_id(); + mc_err.banknum = i; + mc_err.mci_status = ((u64)high << 32) | low; if(high&(1<<29)) recover|=1; if(high&(1<<25)) @@ -59,19 +78,26 @@ if(high&(1<<27)) { rdmsr(MSR_IA32_MC0_MISC+i*4, alow, ahigh); + mc_err.mci_misc = ((u64)ahigh << 32) | alow; printk("[%08x%08x]", alow, ahigh); } if(high&(1<<26)) { rdmsr(MSR_IA32_MC0_ADDR+i*4, alow, ahigh); - printk(" at %08x%08x", + mc_err.mci_addr = ((u64)ahigh << 32) | alow; + printk(" at %08x%08x", ahigh, alow); } + rdmsr(MSR_IA32_MC0_CTL+i*4, alow, ahigh); + mc_err.mci_ctl = ((u64)ahigh << 32) | alow; + printk("\n"); + /* Clear it */ wrmsr(MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL); /* Serialize */ wmb(); + notifier_call_chain(&mc_notifier_list, X86_VENDOR_INTEL, &mc_err); } } @@ -105,56 +131,51 @@ * K8 machine check. */ -static struct pci_dev *find_k8_nb(void) -{ - struct pci_dev *dev; - int cpu = smp_processor_id(); - pci_for_each_dev(dev) { - if (dev->bus->number==0 && PCI_FUNC(dev->devfn)==3 && - PCI_SLOT(dev->devfn) == (24+cpu)) - return dev; - } - return NULL; -} - +static char *k8bank[] = { + "data cache", + "instruction cache", + "bus unit", + "load/store unit", + "northbridge" +}; static char *transaction[] = { "instruction", "data", "generic", "reserved" }; static char *cachelevel[] = { - "level 0", "level 1", "level 2", "level generic" + "0", "1", "2", "generic" }; static char *memtrans[] = { "generic error", "generic read", "generic write", "data read", - "data write", "instruction fetch", "prefetch", "snoop", + "data write", "instruction fetch", "prefetch", "evict", "snoop", "?", "?", "?", "?", "?", "?", "?" }; static char *partproc[] = { "local node origin", "local node response", - "local node observed", "generic" + "local node observed", "generic participation" }; static char *timeout[] = { "request didn't time out", "request timed out" }; static char *memoryio[] = { - "memory access", "res.", "i/o access", "generic" -}; -static char *extendederr[] = { - "ecc error", - "crc error", - "sync error", - "mst abort", - "tgt abort", - "gart error", - "rmw error", - "wdog error", - "chipkill ecc error", + "memory", "res.", "i/o", "generic" +}; +static char *nbextendederr[] = { + "ECC error", + "CRC error", + "Sync error", + "Master abort", + "Target abort", + "GART error", + "RMW error", + "Watchdog error", + "Chipkill ECC error", "<9>","<10>","<11>","<12>", "<13>","<14>","<15>" -}; +}; static char *highbits[32] = { - [31] = "previous error lost", - [30] = "error overflow", + [31] = "valid", + [30] = "error overflow (multiple errors)", [29] = "error uncorrected", [28] = "error enable", [27] = "misc error valid", @@ -169,128 +190,290 @@ [11] = "res11", [10] = "res10", [9] = "res9", - [8] = "dram scrub error", + [8] = "error found by scrub", [7] = "res7", /* 6-4 ht link number of error */ [3] = "res3", [2] = "res2", - [1] = "err cpu0", - [0] = "err cpu1", + [1] = "err cpu1", + [0] = "err cpu0", }; -static void check_k8_nb(int header) -{ - struct pci_dev *nb; - nb = find_k8_nb(); - if (nb == NULL) - return; - - u32 statuslow, statushigh; - pci_read_config_dword(nb, 0x48, &statuslow); - pci_read_config_dword(nb, 0x4c, &statushigh); - if (!(statushigh & (1<<31))) - return; - if (header) - printk(KERN_ERR "CPU %d: Silent Northbridge MCE\n", smp_processor_id()); - printk(KERN_ERR "Northbridge status %08x:%08x\n", - statushigh,statuslow); +static void decode_k8_generic_errcode(unsigned int cpunum, u64 status) +{ + unsigned short errcode = status & 0xffff; + int i; - printk(KERN_ERR " Error %s\n", extendederr[(statuslow >> 16) & 0xf]); + for (i=0; i<32; i++) { + if (i==31 || i==28 || i==26) + continue; + if (highbits[i] && (status & (1UL<<(i+32)))) { + printk(KERN_ERR "CPU%d: bit%d = %s\n", cpunum, i+32, highbits[i]); + } + } - unsigned short errcode = statuslow & 0xffff; - switch ((statuslow >> 16) & 0xF) { - case 5: - printk(KERN_ERR " GART TLB error %s %s\n", - transaction[(errcode >> 2) & 3], + if ((errcode & 0xFFF0) == 0x0010) { + printk(KERN_ERR "CPU%d: TLB error '%s transaction, level %s'\n", + cpunum, + transaction[(errcode >> 2) & 3], cachelevel[errcode & 3]); - break; - case 8: - printk(KERN_ERR " ECC error syndrome %x\n", - (((statuslow >> 24) & 0xff) << 8) | ((statushigh >> 15) & 0x7f)); - /*FALL THROUGH*/ - default: - printk(KERN_ERR " bus error %s, %s\n %s\n %s, %s\n", + } + else if ((errcode & 0xFF00) == 0x0100) { + printk(KERN_ERR "CPU%d: memory/cache error '%s mem transaction, %s transaction, level %s'\n", + cpunum, + memtrans[(errcode >> 4) & 0xf], + transaction[(errcode >> 2) & 3], + cachelevel[errcode & 3]); + } + else if ((errcode & 0xF800) == 0x0800) { + printk(KERN_ERR "CPU%d: bus error '%s, %s\n %s mem transaction\n %s access, level %s'\n", + cpunum, partproc[(errcode >> 9) & 0x3], timeout[(errcode >> 8) & 1], - memtrans[(errcode >> 4) & 0xf], - memoryio[(errcode >> 2) & 0x3], - cachelevel[(errcode & 0x3)]); - /* should only print when it was a HyperTransport related error. */ - printk(KERN_ERR " link number %x\n", (statushigh >> 4) & 3); + memtrans[(errcode >> 4) & 0xf], + memoryio[(errcode >> 2) & 0x3], + cachelevel[(errcode & 0x3)]); + } +} + +static void decode_k8_dc_mc(unsigned int cpunum, u64 status) +{ + unsigned short exterrcode = (status >> 16) & 0x0f; + unsigned short errcode = status & 0xffff; + + if(status&(3UL<<45)) { + printk(KERN_ERR "CPU%d: Data cache ECC error (syndrome %x)", + cpunum, + (u32) (status >> 47) & 0xff); + if(status&(1UL<<40)) { + printk(" found by scrubber"); + } + printk("\n"); + } + + if ((errcode & 0xFFF0) == 0x0010) { + printk(KERN_ERR "CPU%d: TLB parity error in %s array\n", + cpunum, + (exterrcode == 0) ? "physical" : "virtual"); + } + + decode_k8_generic_errcode(cpunum, status); +} + +static void decode_k8_ic_mc(unsigned int cpunum, u64 status) +{ + unsigned short exterrcode = (status >> 16) & 0x0f; + unsigned short errcode = status & 0xffff; + + if(status&(3UL<<45)) { + printk(KERN_ERR "CPU%d: Instruction cache ECC error\n", + cpunum); + } + + if ((errcode & 0xFFF0) == 0x0010) { + printk(KERN_ERR "CPU%d: TLB parity error in %s array\n", + cpunum, + (exterrcode == 0) ? "physical" : "virtual"); + } + + decode_k8_generic_errcode(cpunum, status); +} + +static void decode_k8_bu_mc(unsigned int cpunum, u64 status) +{ + unsigned short exterrcode = (status >> 16) & 0x0f; + + if(status&(3UL<<45)) { + printk(KERN_ERR "CPU%d: L2 cache ECC error\n", + cpunum); + } + + printk(KERN_ERR "CPU%d: %s array error\n", + cpunum, + (exterrcode == 0) ? "Bus or cache" : "Cache tag"); + + decode_k8_generic_errcode(cpunum, status); +} + +static void decode_k8_ls_mc(unsigned int cpunum, u64 status) +{ + decode_k8_generic_errcode(cpunum, status); +} + +static void decode_k8_nb_mc(unsigned int cpunum, u64 status) +{ + unsigned short exterrcode = (status >> 16) & 0x0f; + + printk(KERN_ERR "CPU%d: Northbridge %s\n", cpunum, nbextendederr[exterrcode]); + + switch (exterrcode) { + case 0: + printk(KERN_ERR "CPU%d: ECC syndrome = %x\n", + cpunum, + (u32) (status >> 47) & 0xff); break; - } - + case 8: + printk(KERN_ERR "CPU%d: Chipkill ECC syndrome = %x\n", + cpunum, + (u32) ((((status >> 24) & 0xff) << 8) | ((status >> 47) & 0xff))); + break; + case 1: + case 2: + case 3: + case 4: + case 6: + printk(KERN_ERR "CPU%d: link number = %x\n", + cpunum, + (u32) (status >> 36) & 0x7); + break; + } - int i; - for (i = 0; i < 32; i++) { - if (i == 26 || i == 28) - continue; - if (highbits[i] && (statushigh & (1<:%016lx RSP %016lx %s\n", + cpunum, regs->cs, regs->rip, regs->rsp, + (mcgst & 1) ? "" : "!INEXACT!"); + } - rdmsrl(MSR_IA32_MC0_STATUS+4*4, nbstatus); - if ((nbstatus & (1UL<<63)) == 0) - goto others; - - printk(KERN_EMERG "Northbridge Machine Check %s %016lx %lx\n", - regs ? "exception" : "timer", - (unsigned long)nbstatus, error_code); - if (nbstatus & (1UL<<62)) - printk(KERN_EMERG "Lost at least one NB error condition\n"); - if (nbstatus & (1UL<<61)) - printk(KERN_EMERG "Uncorrectable condition\n"); - if (nbstatus & (1UL<57)) - printk(KERN_EMERG "Unrecoverable condition\n"); - - check_k8_nb(0); + for(banknum=0; banknum>16)&0x0f)==7)) { + /* NB watchdog, address reg has details but validity bit is not set */ + rdmsrl(MSR_IA32_MC0_ADDR+banknum*4, addr); + mc_err.mci_addr = addr; + printk(" error details %016Lx", addr); + } + printk("\n"); + rdmsrl(MSR_IA32_MC0_CTL+banknum*4, ctl); + mc_err.mci_ctl = ctl; + /* Clear it */ + /* Can't write anything but zeros to status, or K8 will GPF */ + wrmsrl(MSR_IA32_MC0_STATUS+banknum*4, 0UL); + /* Serialize */ + wmb(); + notifier_call_chain(&mc_notifier_list, X86_VENDOR_AMD, &mc_err); + } + } - if (nbstatus & (1UL<<58)) { - u64 adr; - rdmsrl(MSR_IA32_MC0_ADDR+4*4, adr); - printk(KERN_EMERG "Address: %016lx\n", (unsigned long)adr); + if(norecover&2) { + panic("CPU context corrupt"); } - - wrmsrl(MSR_IA32_MC0_STATUS+4*4, 0); - wrmsrl(MSR_IA32_MCG_STATUS, 0); - - others: - generic_machine_check(regs, error_code); -} + if(norecover&1) { + panic("Unable to continue"); + } + printk(KERN_EMERG "Attempting to continue.\n"); + mcgst&=~(1UL<<2); + wrmsrl(MSR_IA32_MCG_STATUS,mcgst); +} static struct timer_list mcheck_timer; -int mcheck_interval = 30*HZ; +int mcheck_interval = 60*HZ; #ifndef CONFIG_SMP static void mcheck_timer_handler(unsigned long data) { - k8_machine_check(NULL,0); + k8_poll_machine_check(); mcheck_timer.expires = jiffies + mcheck_interval; add_timer(&mcheck_timer); } @@ -301,13 +484,13 @@ static void mcheck_timer_other(void *data) { - k8_machine_check(NULL, 0); + k8_poll_machine_check(); } static void mcheck_timer_dist(void *data) { smp_call_function(mcheck_timer_other,0,0,0); - k8_machine_check(NULL, 0); + k8_poll_machine_check(); mcheck_timer.expires = jiffies + mcheck_interval; add_timer(&mcheck_timer); } @@ -334,17 +517,20 @@ rdmsrl(MSR_IA32_MCG_CAP, cap); banks = cap&0xff; - machine_check_vector = k8_machine_check; for (i = 0; i < banks; i++) { u64 val = ((1UL<x86 == 15 && !nok8) { k8_mcheck_init(c); - break; + } else { + generic_mcheck_init(c); } + break; /* FALL THROUGH */ default: case X86_VENDOR_INTEL: @@ -447,13 +636,13 @@ char *p; while ((p = strsep(&str,",")) != NULL) { if (isdigit(*p)) - mcheck_interval = simple_strtol(p,NULL,0) * HZ; + mcheck_interval = simple_strtol(p,NULL,0) * HZ; else if (!strcmp(p,"off")) mce_disabled = 1; else if (!strncmp(p,"enable",6)) - disabled_banks &= ~(1< #include +#include #include #include #include @@ -439,6 +440,7 @@ #endif #ifndef CONFIG_VISWS - setup_irq(2, &irq2); + if (!acpi_ioapic) + setup_irq(2, &irq2); #endif } diff -urN linux-2.4.26/arch/x86_64/kernel/io_apic.c linux-2.4.27/arch/x86_64/kernel/io_apic.c --- linux-2.4.26/arch/x86_64/kernel/io_apic.c 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.27/arch/x86_64/kernel/io_apic.c 2004-08-07 16:26:04.633345915 -0700 @@ -256,8 +256,9 @@ PCI_VENDOR_ID); vendor &= 0xffff; switch (vendor) { - case PCI_VENDOR_ID_NVIDIA: case PCI_VENDOR_ID_VIA: + return; + case PCI_VENDOR_ID_NVIDIA: printk(KERN_INFO "PCI bridge %02x:%02x from %x found. Setting \"noapic\". Overwrite with \"apic\"\n", num,slot,vendor); @@ -1684,18 +1685,10 @@ /* * - * IRQ's that are handled by the old PIC in all cases: + * IRQ's that are handled by the PIC in the MPS IOAPIC case. * - IRQ2 is the cascade IRQ, and cannot be a io-apic IRQ. * Linux doesn't really care, as it's not actually used * for any interrupt handling anyway. - * - There used to be IRQ13 here as well, but all - * MPS-compliant must not use it for FPU coupling and we - * want to use exception 16 anyway. And there are - * systems who connect it to an I/O APIC for other uses. - * Thus we don't mark it special any longer. - * - * Additionally, something is definitely wrong with irq9 - * on PIIX4 boards. */ #define PIC_IRQS (1<<2) @@ -1703,7 +1696,11 @@ { enable_IO_APIC(); - io_apic_irqs = ~PIC_IRQS; + if (acpi_ioapic) + io_apic_irqs = ~0; /* all IRQs go through IOAPIC */ + else + io_apic_irqs = ~PIC_IRQS; + printk("ENABLING IO-APIC IRQs\n"); /* @@ -1858,7 +1855,7 @@ entry.vector = assign_irq_vector(irq); - printk(KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> " + 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); diff -urN linux-2.4.26/arch/x86_64/kernel/mpparse.c linux-2.4.27/arch/x86_64/kernel/mpparse.c --- linux-2.4.26/arch/x86_64/kernel/mpparse.c 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.27/arch/x86_64/kernel/mpparse.c 2004-08-07 16:26:04.634345956 -0700 @@ -793,8 +793,6 @@ u32 global_irq) { struct mpc_config_intsrc intsrc; - int i = 0; - int found = 0; int ioapic = -1; int pin = -1; @@ -827,23 +825,9 @@ (intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus, intsrc.mpc_srcbusirq, intsrc.mpc_dstapic, intsrc.mpc_dstirq); - /* - * If an existing [IOAPIC.PIN -> IRQ] routing entry exists we override it. - * Otherwise create a new entry (e.g. global_irq == 2). - */ - for (i = 0; i < mp_irq_entries; i++) { - if ((mp_irqs[i].mpc_srcbus == intsrc.mpc_srcbus) - && (mp_irqs[i].mpc_dstirq == intsrc.mpc_dstirq)) { - mp_irqs[i] = intsrc; - found = 1; - break; - } - } - if (!found) { - mp_irqs[mp_irq_entries] = intsrc; - if (++mp_irq_entries == MAX_IRQ_SOURCES) - panic("Max # of irq sources exceeded!\n"); - } + mp_irqs[mp_irq_entries] = intsrc; + if (++mp_irq_entries == MAX_IRQ_SOURCES) + panic("Max # of irq sources exceeded!\n"); return; } @@ -874,13 +858,23 @@ intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid; /* - * Use the default configuration for the IRQs 0-15. These may be + * Use the default configuration for the IRQs 0-15. Unless * overriden by (MADT) interrupt source override entries. */ for (i = 0; i < 16; i++) { + int idx; - if (i == 2) - continue; /* Don't connect IRQ2 */ + for (idx = 0; idx < mp_irq_entries; idx++) + if (mp_irqs[idx].mpc_srcbus == MP_ISA_BUS && + (mp_irqs[idx].mpc_dstapic == intsrc.mpc_dstapic) && + (mp_irqs[idx].mpc_srcbusirq == i || + mp_irqs[idx].mpc_dstirq == i)) + break; + + if (idx != mp_irq_entries) { + printk(KERN_DEBUG "ACPI: IRQ%d used by override.\n", i); + continue; /* IRQ already used */ + } intsrc.mpc_irqtype = mp_INT; intsrc.mpc_srcbusirq = i; /* Identity mapped */ @@ -942,8 +936,6 @@ irq = entry->link.index; } - irq = entry->link.index; - /* Don't set up the ACPI SCI because it's already set up */ if (acpi_fadt.sci_int == irq) { entry->irq = irq; /*we still need to set entry's irq*/ @@ -982,10 +974,11 @@ entry->irq = irq; printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> vector 0x%02x" - " -> IRQ %d\n", entry->id.segment, entry->id.bus, - entry->id.device, ('A' + entry->pin), - mp_ioapic_routing[ioapic].apic_id, ioapic_pin, vector, - entry->irq); + " -> IRQ %d %s %s\n", entry->id.segment, entry->id.bus, + entry->id.device, ('A' + entry->pin), + mp_ioapic_routing[ioapic].apic_id, ioapic_pin, vector, + entry->irq, edge_level ? "level" : "edge", + active_high_low ? "low" : "high"); } print_IO_APIC(); diff -urN linux-2.4.26/arch/x86_64/kernel/mtrr.c linux-2.4.27/arch/x86_64/kernel/mtrr.c --- linux-2.4.26/arch/x86_64/kernel/mtrr.c 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.27/arch/x86_64/kernel/mtrr.c 2004-08-07 16:26:04.635345997 -0700 @@ -961,16 +961,19 @@ static ssize_t mtrr_read (struct file *file, char *buf, size_t len, loff_t * ppos) { - if (*ppos >= ascii_buf_bytes) + loff_t n = *ppos; + unsigned pos = n; + + if (pos != n || pos >= ascii_buf_bytes) return 0; - if (*ppos + len > ascii_buf_bytes) - len = ascii_buf_bytes - *ppos; + if (len > ascii_buf_bytes - pos) + len = ascii_buf_bytes - pos; - if (copy_to_user (buf, ascii_buffer + *ppos, len)) + if (copy_to_user (buf, ascii_buffer + pos, len)) return -EFAULT; - *ppos += len; + *ppos = pos + len; return len; } diff -urN linux-2.4.26/arch/x86_64/kernel/pci-gart.c linux-2.4.27/arch/x86_64/kernel/pci-gart.c --- linux-2.4.26/arch/x86_64/kernel/pci-gart.c 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.27/arch/x86_64/kernel/pci-gart.c 2004-08-07 16:26:04.635345997 -0700 @@ -503,12 +503,13 @@ no_agp = no_agp || (agp_init() < 0) || (agp_copy_info(&info) < 0); #endif +#ifdef CONFIG_SWIOTLB if (swiotlb) { no_iommu = 1; printk(KERN_INFO "PCI-DMA: Using SWIOTLB\n"); return; - } - + } +#endif if (no_iommu || (!force_mmu && end_pfn < 0xffffffff>>PAGE_SHIFT) || !iommu_aperture) { printk(KERN_INFO "PCI-DMA: Disabling IOMMU.\n"); diff -urN linux-2.4.26/arch/x86_64/kernel/pci-pc.c linux-2.4.27/arch/x86_64/kernel/pci-pc.c --- linux-2.4.26/arch/x86_64/kernel/pci-pc.c 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.27/arch/x86_64/kernel/pci-pc.c 2004-08-07 16:26:04.636346038 -0700 @@ -646,7 +646,7 @@ pcibios_last_bus = simple_strtol(str+8, NULL, 0); return NULL; } else if (!strncmp(str, "noacpi", 6)) { - acpi_noirq_set(); + acpi_disable_pci(); return NULL; } return str; diff -urN linux-2.4.26/arch/x86_64/kernel/setup.c linux-2.4.27/arch/x86_64/kernel/setup.c --- linux-2.4.26/arch/x86_64/kernel/setup.c 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.27/arch/x86_64/kernel/setup.c 2004-08-07 16:26:04.637346079 -0700 @@ -48,11 +48,8 @@ #include #include -int acpi_disabled = 0; -#ifdef CONFIG_ACPI_BOOT -int acpi_noirq __initdata = 0; /* skip ACPI IRQ initialization */ -#endif - +int acpi_disabled; +EXPORT_SYMBOL(acpi_disabled); int swiotlb; diff -urN linux-2.4.26/crypto/Config.in linux-2.4.27/crypto/Config.in --- linux-2.4.26/crypto/Config.in 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.27/crypto/Config.in 2004-08-07 16:26:04.637346079 -0700 @@ -72,6 +72,7 @@ tristate ' AES cipher algorithms' CONFIG_CRYPTO_AES tristate ' CAST5 (CAST-128) cipher algorithm' CONFIG_CRYPTO_CAST5 tristate ' CAST6 (CAST-256) cipher algorithm' CONFIG_CRYPTO_CAST6 + tristate ' TEA and XTEA cipher algorithms' CONFIG_CRYPTO_TEA tristate ' ARC4 cipher algorithm' CONFIG_CRYPTO_ARC4 if [ "$CONFIG_INET_IPCOMP" = "y" -o \ "$CONFIG_INET_IPCOMP" = "m" -o \ @@ -81,6 +82,7 @@ else tristate ' Deflate compression algorithm' CONFIG_CRYPTO_DEFLATE fi + tristate ' Michael MIC keyed digest algorithm' CONFIG_CRYPTO_MICHAEL_MIC tristate ' Testing module' CONFIG_CRYPTO_TEST fi diff -urN linux-2.4.26/crypto/Makefile linux-2.4.27/crypto/Makefile --- linux-2.4.26/crypto/Makefile 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.27/crypto/Makefile 2004-08-07 16:26:04.638346120 -0700 @@ -27,7 +27,9 @@ obj-$(CONFIG_CRYPTO_CAST5) += cast5.o obj-$(CONFIG_CRYPTO_CAST6) += cast6.o obj-$(CONFIG_CRYPTO_ARC4) += arc4.o +obj-$(CONFIG_CRYPTO_TEA) += tea.o obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o +obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o diff -urN linux-2.4.26/crypto/cipher.c linux-2.4.27/crypto/cipher.c --- linux-2.4.26/crypto/cipher.c 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.27/crypto/cipher.c 2004-08-07 16:26:04.638346120 -0700 @@ -52,8 +52,8 @@ { struct scatter_walk walk_in, walk_out; const unsigned int bsize = crypto_tfm_alg_blocksize(tfm); - u8 tmp_src[nbytes > src->length ? bsize : 0]; - u8 tmp_dst[nbytes > dst->length ? bsize : 0]; + u8 tmp_src[bsize]; + u8 tmp_dst[bsize]; if (!nbytes) return 0; @@ -68,19 +68,20 @@ for(;;) { u8 *src_p, *dst_p; + int in_place; scatterwalk_map(&walk_in, 0); scatterwalk_map(&walk_out, 1); src_p = scatterwalk_whichbuf(&walk_in, bsize, tmp_src); dst_p = scatterwalk_whichbuf(&walk_out, bsize, tmp_dst); + in_place = scatterwalk_samebuf(&walk_in, &walk_out, + src_p, dst_p); nbytes -= bsize; scatterwalk_copychunks(src_p, &walk_in, bsize, 0); - prfn(tfm, dst_p, src_p, crfn, enc, info, - scatterwalk_samebuf(&walk_in, &walk_out, - src_p, dst_p)); + prfn(tfm, dst_p, src_p, crfn, enc, info, in_place); scatterwalk_done(&walk_in, 0, nbytes); diff -urN linux-2.4.26/crypto/digest.c linux-2.4.27/crypto/digest.c --- linux-2.4.26/crypto/digest.c 2003-08-25 04:44:40.000000000 -0700 +++ linux-2.4.27/crypto/digest.c 2004-08-07 16:26:04.639346161 -0700 @@ -27,13 +27,28 @@ struct scatterlist *sg, unsigned int nsg) { unsigned int i; - + for (i = 0; i < nsg; i++) { - char *p = crypto_kmap(sg[i].page, 0) + sg[i].offset; - tfm->__crt_alg->cra_digest.dia_update(crypto_tfm_ctx(tfm), - p, sg[i].length); - crypto_kunmap(p, 0); - crypto_yield(tfm); + + struct page *pg = sg[i].page; + unsigned int offset = sg[i].offset; + unsigned int l = sg[i].length; + + do { + unsigned int bytes_from_page = min(l, ((unsigned int) + (PAGE_SIZE)) - + offset); + char *p = crypto_kmap(pg, 0) + offset; + + tfm->__crt_alg->cra_digest.dia_update + (crypto_tfm_ctx(tfm), p, + bytes_from_page); + crypto_kunmap(p, 0); + crypto_yield(tfm); + offset = 0; + pg++; + l -= bytes_from_page; + } while (l > 0); } } @@ -42,6 +57,15 @@ tfm->__crt_alg->cra_digest.dia_final(crypto_tfm_ctx(tfm), out); } +static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) +{ + u32 flags; + if (tfm->__crt_alg->cra_digest.dia_setkey == NULL) + return -ENOSYS; + return tfm->__crt_alg->cra_digest.dia_setkey(crypto_tfm_ctx(tfm), + key, keylen, &flags); +} + static void digest(struct crypto_tfm *tfm, struct scatterlist *sg, unsigned int nsg, u8 *out) { @@ -72,6 +96,7 @@ ops->dit_update = update; ops->dit_final = final; ops->dit_digest = digest; + ops->dit_setkey = setkey; return crypto_alloc_hmac_block(tfm); } diff -urN linux-2.4.26/crypto/michael_mic.c linux-2.4.27/crypto/michael_mic.c --- linux-2.4.26/crypto/michael_mic.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.27/crypto/michael_mic.c 2004-08-07 16:26:04.640346202 -0700 @@ -0,0 +1,193 @@ +/* + * Cryptographic API + * + * Michael MIC (IEEE 802.11i/TKIP) keyed digest + * + * Copyright (c) 2004 Jouni Malinen + * + * 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 + + +struct michael_mic_ctx { + u8 pending[4]; + size_t pending_len; + + u32 l, r; +}; + + +static inline u32 rotl(u32 val, int bits) +{ + return (val << bits) | (val >> (32 - bits)); +} + + +static inline u32 rotr(u32 val, int bits) +{ + return (val >> bits) | (val << (32 - bits)); +} + + +static inline u32 xswap(u32 val) +{ + return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8); +} + + +#define michael_block(l, r) \ +do { \ + r ^= rotl(l, 17); \ + l += r; \ + r ^= xswap(l); \ + l += r; \ + r ^= rotl(l, 3); \ + l += r; \ + r ^= rotr(l, 2); \ + l += r; \ +} while (0) + + +static inline u32 get_le32(const u8 *p) +{ + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +} + + +static inline void put_le32(u8 *p, u32 v) +{ + p[0] = v; + p[1] = v >> 8; + p[2] = v >> 16; + p[3] = v >> 24; +} + + +static void michael_init(void *ctx) +{ + struct michael_mic_ctx *mctx = ctx; + mctx->pending_len = 0; +} + + +static void michael_update(void *ctx, const u8 *data, unsigned int len) +{ + struct michael_mic_ctx *mctx = ctx; + + if (mctx->pending_len) { + int flen = 4 - mctx->pending_len; + if (flen > len) + flen = len; + memcpy(&mctx->pending[mctx->pending_len], data, flen); + mctx->pending_len += flen; + data += flen; + len -= flen; + + if (mctx->pending_len < 4) + return; + + mctx->l ^= get_le32(mctx->pending); + michael_block(mctx->l, mctx->r); + mctx->pending_len = 0; + } + + while (len >= 4) { + mctx->l ^= get_le32(data); + michael_block(mctx->l, mctx->r); + data += 4; + len -= 4; + } + + if (len > 0) { + mctx->pending_len = len; + memcpy(mctx->pending, data, len); + } +} + + +static void michael_final(void *ctx, u8 *out) +{ + struct michael_mic_ctx *mctx = ctx; + u8 *data = mctx->pending; + + /* Last block and padding (0x5a, 4..7 x 0) */ + switch (mctx->pending_len) { + case 0: + mctx->l ^= 0x5a; + break; + case 1: + mctx->l ^= data[0] | 0x5a00; + break; + case 2: + mctx->l ^= data[0] | (data[1] << 8) | 0x5a0000; + break; + case 3: + mctx->l ^= data[0] | (data[1] << 8) | (data[2] << 16) | + 0x5a000000; + break; + } + michael_block(mctx->l, mctx->r); + /* l ^= 0; */ + michael_block(mctx->l, mctx->r); + + put_le32(out, mctx->l); + put_le32(out + 4, mctx->r); +} + + +static int michael_setkey(void *ctx, const u8 *key, unsigned int keylen, + u32 *flags) +{ + struct michael_mic_ctx *mctx = ctx; + if (keylen != 8) { + if (flags) + *flags = CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + mctx->l = get_le32(key); + mctx->r = get_le32(key + 4); + return 0; +} + + +static struct crypto_alg michael_mic_alg = { + .cra_name = "michael_mic", + .cra_flags = CRYPTO_ALG_TYPE_DIGEST, + .cra_blocksize = 8, + .cra_ctxsize = sizeof(struct michael_mic_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(michael_mic_alg.cra_list), + .cra_u = { .digest = { + .dia_digestsize = 8, + .dia_init = michael_init, + .dia_update = michael_update, + .dia_final = michael_final, + .dia_setkey = michael_setkey } } +}; + + +static int __init michael_mic_init(void) +{ + return crypto_register_alg(&michael_mic_alg); +} + + +static void __exit michael_mic_exit(void) +{ + crypto_unregister_alg(&michael_mic_alg); +} + + +module_init(michael_mic_init); +module_exit(michael_mic_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Michael MIC"); +MODULE_AUTHOR("Jouni Malinen "); diff -urN linux-2.4.26/crypto/scatterwalk.h linux-2.4.27/crypto/scatterwalk.h --- linux-2.4.26/crypto/scatterwalk.h 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.27/crypto/scatterwalk.h 2004-08-07 16:26:04.640346202 -0700 @@ -38,6 +38,7 @@ void *src_p, void *dst_p) { return walk_in->page == walk_out->page && + walk_in->offset == walk_out->offset && walk_in->data == src_p && walk_out->data == dst_p; } diff -urN linux-2.4.26/crypto/tcrypt.c linux-2.4.27/crypto/tcrypt.c --- linux-2.4.26/crypto/tcrypt.c 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.27/crypto/tcrypt.c 2004-08-07 16:26:04.641346243 -0700 @@ -63,7 +63,7 @@ static char *check[] = { "des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish", "twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6", - "arc4", "deflate", NULL + "arc4", "michael_mic", "deflate", "tea", "xtea", NULL }; static void @@ -114,6 +114,10 @@ sg[0].length = hash_tv[i].psize; crypto_digest_init (tfm); + if (tfm->crt_u.digest.dit_setkey) { + crypto_digest_setkey (tfm, hash_tv[i].key, + hash_tv[i].ksize); + } crypto_digest_update (tfm, sg, 1); crypto_digest_final (tfm, result); @@ -562,6 +566,15 @@ test_cipher ("arc4", MODE_ECB, ENCRYPT, arc4_enc_tv_template, ARC4_ENC_TEST_VECTORS); test_cipher ("arc4", MODE_ECB, DECRYPT, arc4_dec_tv_template, ARC4_DEC_TEST_VECTORS); + //TEA + test_cipher ("tea", MODE_ECB, ENCRYPT, tea_enc_tv_template, TEA_ENC_TEST_VECTORS); + test_cipher ("tea", MODE_ECB, DECRYPT, tea_dec_tv_template, TEA_DEC_TEST_VECTORS); + + + //XTEA + test_cipher ("xtea", MODE_ECB, ENCRYPT, xtea_enc_tv_template, XTEA_ENC_TEST_VECTORS); + test_cipher ("xtea", MODE_ECB, DECRYPT, xtea_dec_tv_template, XTEA_DEC_TEST_VECTORS); + test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS); test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS); test_deflate(); @@ -570,6 +583,8 @@ test_hmac("sha1", hmac_sha1_tv_template, HMAC_SHA1_TEST_VECTORS); test_hmac("sha256", hmac_sha256_tv_template, HMAC_SHA256_TEST_VECTORS); #endif + + test_hash("michael_mic", michael_mic_tv_template, MICHAEL_MIC_TEST_VECTORS); break; case 1: @@ -649,6 +664,20 @@ test_cipher ("arc4", MODE_ECB, DECRYPT, arc4_dec_tv_template, ARC4_DEC_TEST_VECTORS); break; + case 17: + test_hash("michael_mic", michael_mic_tv_template, MICHAEL_MIC_TEST_VECTORS); + break; + + case 19: + test_cipher ("tea", MODE_ECB, ENCRYPT, tea_enc_tv_template, TEA_ENC_TEST_VECTORS); + test_cipher ("tea", MODE_ECB, DECRYPT, tea_dec_tv_template, TEA_DEC_TEST_VECTORS); + break; + + case 20: + test_cipher ("xtea", MODE_ECB, ENCRYPT, xtea_enc_tv_template, XTEA_ENC_TEST_VECTORS); + test_cipher ("xtea", MODE_ECB, DECRYPT, xtea_dec_tv_template, XTEA_DEC_TEST_VECTORS); + break; + #ifdef CONFIG_CRYPTO_HMAC case 100: test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS); diff -urN linux-2.4.26/crypto/tcrypt.h linux-2.4.27/crypto/tcrypt.h --- linux-2.4.26/crypto/tcrypt.h 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.27/crypto/tcrypt.h 2004-08-07 16:26:04.643346325 -0700 @@ -30,6 +30,8 @@ char digest[MAX_DIGEST_SIZE]; unsigned char np; unsigned char tap[MAX_TAP]; + char key[128]; /* only used with keyed hash algorithms */ + unsigned char ksize; }; struct hmac_testvec { @@ -1628,6 +1630,195 @@ }, }; +/* + * TEA test vectors + */ +#define TEA_ENC_TEST_VECTORS 4 +#define TEA_DEC_TEST_VECTORS 4 + +struct cipher_testvec tea_enc_tv_template[] = +{ + { + .key = { [0 ... 15] = 0x00 }, + .klen = 16, + .input = { [0 ... 8] = 0x00 }, + .ilen = 8, + .result = { 0x0a, 0x3a, 0xea, 0x41, 0x40, 0xa9, 0xba, 0x94 }, + .rlen = 8, + }, { + .key = { 0x2b, 0x02, 0x05, 0x68, 0x06, 0x14, 0x49, 0x76, + 0x77, 0x5d, 0x0e, 0x26, 0x6c, 0x28, 0x78, 0x43 }, + .klen = 16, + .input = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x2e }, + .ilen = 8, + .result = { 0x77, 0x5d, 0x2a, 0x6a, 0xf6, 0xce, 0x92, 0x09 }, + .rlen = 8, + }, { + .key = { 0x09, 0x65, 0x43, 0x11, 0x66, 0x44, 0x39, 0x25, + 0x51, 0x3a, 0x16, 0x10, 0x0a, 0x08, 0x12, 0x6e }, + .klen = 16, + .input = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74, + 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x63, 0x74 }, + .ilen = 16, + .result = { 0xbe, 0x7a, 0xbb, 0x81, 0x95, 0x2d, 0x1f, 0x1e, + 0xdd, 0x89, 0xa1, 0x25, 0x04, 0x21, 0xdf, 0x95 }, + .rlen = 16, + }, { + .key = { 0x4d, 0x76, 0x32, 0x17, 0x05, 0x3f, 0x75, 0x2c, + 0x5d, 0x04, 0x16, 0x36, 0x15, 0x72, 0x63, 0x2f }, + .klen = 16, + .input = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67, + 0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72, + 0x65, 0x61, 0x6c, 0x6c, 0x79, 0x21, 0x21, 0x21 }, + .ilen = 32, + .result = { 0xe0, 0x4d, 0x5d, 0x3c, 0xb7, 0x8c, 0x36, 0x47, + 0x94, 0x18, 0x95, 0x91, 0xa9, 0xfc, 0x49, 0xf8, + 0x44, 0xd1, 0x2d, 0xc2, 0x99, 0xb8, 0x08, 0x2a, + 0x07, 0x89, 0x73, 0xc2, 0x45, 0x92, 0xc6, 0x90 }, + .rlen = 32, + } +}; + +struct cipher_testvec tea_dec_tv_template[] = +{ + { + .key = { [0 ... 15] = 0x00 }, + .klen = 16, + .input = { 0x0a, 0x3a, 0xea, 0x41, 0x40, 0xa9, 0xba, 0x94 }, + .ilen = 8, + .result = { [0 ... 8] = 0x00 }, + .rlen = 8, + }, { + .key = { 0x2b, 0x02, 0x05, 0x68, 0x06, 0x14, 0x49, 0x76, + 0x77, 0x5d, 0x0e, 0x26, 0x6c, 0x28, 0x78, 0x43 }, + .klen = 16, + .input = { 0x77, 0x5d, 0x2a, 0x6a, 0xf6, 0xce, 0x92, 0x09 }, + .ilen = 8, + .result = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x2e }, + .rlen = 8, + }, { + .key = { 0x09, 0x65, 0x43, 0x11, 0x66, 0x44, 0x39, 0x25, + 0x51, 0x3a, 0x16, 0x10, 0x0a, 0x08, 0x12, 0x6e }, + .klen = 16, + .input = { 0xbe, 0x7a, 0xbb, 0x81, 0x95, 0x2d, 0x1f, 0x1e, + 0xdd, 0x89, 0xa1, 0x25, 0x04, 0x21, 0xdf, 0x95 }, + .ilen = 16, + .result = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74, + 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x63, 0x74 }, + .rlen = 16, + }, { + .key = { 0x4d, 0x76, 0x32, 0x17, 0x05, 0x3f, 0x75, 0x2c, + 0x5d, 0x04, 0x16, 0x36, 0x15, 0x72, 0x63, 0x2f }, + .klen = 16, + .input = { 0xe0, 0x4d, 0x5d, 0x3c, 0xb7, 0x8c, 0x36, 0x47, + 0x94, 0x18, 0x95, 0x91, 0xa9, 0xfc, 0x49, 0xf8, + 0x44, 0xd1, 0x2d, 0xc2, 0x99, 0xb8, 0x08, 0x2a, + 0x07, 0x89, 0x73, 0xc2, 0x45, 0x92, 0xc6, 0x90 }, + .ilen = 32, + .result = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67, + 0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72, + 0x65, 0x61, 0x6c, 0x6c, 0x79, 0x21, 0x21, 0x21 }, + .rlen = 32, + } +}; + +/* + * XTEA test vectors + */ +#define XTEA_ENC_TEST_VECTORS 4 +#define XTEA_DEC_TEST_VECTORS 4 + +struct cipher_testvec xtea_enc_tv_template[] = +{ + { + .key = { [0 ... 15] = 0x00 }, + .klen = 16, + .input = { [0 ... 8] = 0x00 }, + .ilen = 8, + .result = { 0xaa, 0x22, 0x96, 0xe5, 0x6c, 0x61, 0xf3, 0x45 }, + .rlen = 8, + }, { + .key = { 0x2b, 0x02, 0x05, 0x68, 0x06, 0x14, 0x49, 0x76, + 0x77, 0x5d, 0x0e, 0x26, 0x6c, 0x28, 0x78, 0x43 }, + .klen = 16, + .input = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x2e }, + .ilen = 8, + .result = { 0x82, 0x3e, 0xeb, 0x35, 0xdc, 0xdd, 0xd9, 0xc3 }, + .rlen = 8, + }, { + .key = { 0x09, 0x65, 0x43, 0x11, 0x66, 0x44, 0x39, 0x25, + 0x51, 0x3a, 0x16, 0x10, 0x0a, 0x08, 0x12, 0x6e }, + .klen = 16, + .input = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74, + 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x63, 0x74 }, + .ilen = 16, + .result = { 0xe2, 0x04, 0xdb, 0xf2, 0x89, 0x85, 0x9e, 0xea, + 0x61, 0x35, 0xaa, 0xed, 0xb5, 0xcb, 0x71, 0x2c }, + .rlen = 16, + }, { + .key = { 0x4d, 0x76, 0x32, 0x17, 0x05, 0x3f, 0x75, 0x2c, + 0x5d, 0x04, 0x16, 0x36, 0x15, 0x72, 0x63, 0x2f }, + .klen = 16, + .input = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67, + 0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72, + 0x65, 0x61, 0x6c, 0x6c, 0x79, 0x21, 0x21, 0x21 }, + .ilen = 32, + .result = { 0x0b, 0x03, 0xcd, 0x8a, 0xbe, 0x95, 0xfd, 0xb1, + 0xc1, 0x44, 0x91, 0x0b, 0xa5, 0xc9, 0x1b, 0xb4, + 0xa9, 0xda, 0x1e, 0x9e, 0xb1, 0x3e, 0x2a, 0x8f, + 0xea, 0xa5, 0x6a, 0x85, 0xd1, 0xf4, 0xa8, 0xa5 }, + .rlen = 32, + } +}; + +struct cipher_testvec xtea_dec_tv_template[] = +{ + { + .key = { [0 ... 15] = 0x00 }, + .klen = 16, + .input = { 0xaa, 0x22, 0x96, 0xe5, 0x6c, 0x61, 0xf3, 0x45 }, + .ilen = 8, + .result = { [0 ... 8] = 0x00 }, + .rlen = 8, + }, { + .key = { 0x2b, 0x02, 0x05, 0x68, 0x06, 0x14, 0x49, 0x76, + 0x77, 0x5d, 0x0e, 0x26, 0x6c, 0x28, 0x78, 0x43 }, + .klen = 16, + .input = { 0x82, 0x3e, 0xeb, 0x35, 0xdc, 0xdd, 0xd9, 0xc3 }, + .ilen = 8, + .result = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x2e }, + .rlen = 8, + }, { + .key = { 0x09, 0x65, 0x43, 0x11, 0x66, 0x44, 0x39, 0x25, + 0x51, 0x3a, 0x16, 0x10, 0x0a, 0x08, 0x12, 0x6e }, + .klen = 16, + .input = { 0xe2, 0x04, 0xdb, 0xf2, 0x89, 0x85, 0x9e, 0xea, + 0x61, 0x35, 0xaa, 0xed, 0xb5, 0xcb, 0x71, 0x2c }, + .ilen = 16, + .result = { 0x6c, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x5f, 0x74, + 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x63, 0x74 }, + .rlen = 16, + }, { + .key = { 0x4d, 0x76, 0x32, 0x17, 0x05, 0x3f, 0x75, 0x2c, + 0x5d, 0x04, 0x16, 0x36, 0x15, 0x72, 0x63, 0x2f }, + .klen = 16, + .input = { 0x0b, 0x03, 0xcd, 0x8a, 0xbe, 0x95, 0xfd, 0xb1, + 0xc1, 0x44, 0x91, 0x0b, 0xa5, 0xc9, 0x1b, 0xb4, + 0xa9, 0xda, 0x1e, 0x9e, 0xb1, 0x3e, 0x2a, 0x8f, + 0xea, 0xa5, 0x6a, 0x85, 0xd1, 0xf4, 0xa8, 0xa5 }, + .ilen = 32, + .result = { 0x54, 0x65, 0x61, 0x20, 0x69, 0x73, 0x20, 0x67, + 0x6f, 0x6f, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x79, 0x6f, 0x75, 0x21, 0x21, 0x21, 0x20, 0x72, + 0x65, 0x61, 0x6c, 0x6c, 0x79, 0x21, 0x21, 0x21 }, + .rlen = 32, + } +}; + + /* * Compression stuff. @@ -1719,4 +1910,55 @@ }, }; +/* + * Michael MIC test vectors from IEEE 802.11i + */ +#define MICHAEL_MIC_TEST_VECTORS 6 + +struct hash_testvec michael_mic_tv_template[] = +{ + { + .key = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .ksize = 8, + .plaintext = { }, + .psize = 0, + .digest = { 0x82, 0x92, 0x5c, 0x1c, 0xa1, 0xd1, 0x30, 0xb8 } + }, + { + .key = { 0x82, 0x92, 0x5c, 0x1c, 0xa1, 0xd1, 0x30, 0xb8 }, + .ksize = 8, + .plaintext = { 'M' }, + .psize = 1, + .digest = { 0x43, 0x47, 0x21, 0xca, 0x40, 0x63, 0x9b, 0x3f } + }, + { + .key = { 0x43, 0x47, 0x21, 0xca, 0x40, 0x63, 0x9b, 0x3f }, + .ksize = 8, + .plaintext = { 'M', 'i' }, + .psize = 2, + .digest = { 0xe8, 0xf9, 0xbe, 0xca, 0xe9, 0x7e, 0x5d, 0x29 } + }, + { + .key = { 0xe8, 0xf9, 0xbe, 0xca, 0xe9, 0x7e, 0x5d, 0x29 }, + .ksize = 8, + .plaintext = { 'M', 'i', 'c' }, + .psize = 3, + .digest = { 0x90, 0x03, 0x8f, 0xc6, 0xcf, 0x13, 0xc1, 0xdb } + }, + { + .key = { 0x90, 0x03, 0x8f, 0xc6, 0xcf, 0x13, 0xc1, 0xdb }, + .ksize = 8, + .plaintext = { 'M', 'i', 'c', 'h' }, + .psize = 4, + .digest = { 0xd5, 0x5e, 0x10, 0x05, 0x10, 0x12, 0x89, 0x86 } + }, + { + .key = { 0xd5, 0x5e, 0x10, 0x05, 0x10, 0x12, 0x89, 0x86 }, + .ksize = 8, + .plaintext = { 'M', 'i', 'c', 'h', 'a', 'e', 'l' }, + .psize = 7, + .digest = { 0x0a, 0x94, 0x2b, 0x12, 0x4e, 0xca, 0xa5, 0x46 }, + } +}; + #endif /* _CRYPTO_TCRYPT_H */ diff -urN linux-2.4.26/crypto/tea.c linux-2.4.27/crypto/tea.c --- linux-2.4.26/crypto/tea.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.27/crypto/tea.c 2004-08-07 16:26:04.644346367 -0700 @@ -0,0 +1,246 @@ +/* + * Cryptographic API. + * + * TEA and Xtended TEA Algorithms + * + * The TEA and Xtended TEA algorithms were developed by David Wheeler + * and Roger Needham at the Computer Laboratory of Cambridge University. + * + * Copyright (c) 2004 Aaron Grothe ajgrothe@yahoo.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. + * + */ + +#include +#include +#include +#include +#include + +#define TEA_KEY_SIZE 16 +#define TEA_BLOCK_SIZE 8 +#define TEA_ROUNDS 32 +#define TEA_DELTA 0x9e3779b9 + +#define XTEA_KEY_SIZE 16 +#define XTEA_BLOCK_SIZE 8 +#define XTEA_ROUNDS 32 +#define XTEA_DELTA 0x9e3779b9 + +#define u32_in(x) le32_to_cpu(*(const u32 *)(x)) +#define u32_out(to, from) (*(u32 *)(to) = cpu_to_le32(from)) + +struct tea_ctx { + u32 KEY[4]; +}; + +struct xtea_ctx { + u32 KEY[4]; +}; + +static int tea_setkey(void *ctx_arg, const u8 *in_key, + unsigned int key_len, u32 *flags) +{ + + struct tea_ctx *ctx = ctx_arg; + + if (key_len != 16) + { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + ctx->KEY[0] = u32_in (in_key); + ctx->KEY[1] = u32_in (in_key + 4); + ctx->KEY[2] = u32_in (in_key + 8); + ctx->KEY[3] = u32_in (in_key + 12); + + return 0; + +} + +static void tea_encrypt(void *ctx_arg, u8 *dst, const u8 *src) +{ + u32 y, z, n, sum = 0; + u32 k0, k1, k2, k3; + + struct tea_ctx *ctx = ctx_arg; + + y = u32_in (src); + z = u32_in (src + 4); + + k0 = ctx->KEY[0]; + k1 = ctx->KEY[1]; + k2 = ctx->KEY[2]; + k3 = ctx->KEY[3]; + + n = TEA_ROUNDS; + + while (n-- > 0) { + sum += TEA_DELTA; + y += ((z << 4) + k0) ^ (z + sum) ^ ((z >> 5) + k1); + z += ((y << 4) + k2) ^ (y + sum) ^ ((y >> 5) + k3); + } + + u32_out (dst, y); + u32_out (dst + 4, z); +} + +static void tea_decrypt(void *ctx_arg, u8 *dst, const u8 *src) +{ + u32 y, z, n, sum; + u32 k0, k1, k2, k3; + + struct tea_ctx *ctx = ctx_arg; + + y = u32_in (src); + z = u32_in (src + 4); + + k0 = ctx->KEY[0]; + k1 = ctx->KEY[1]; + k2 = ctx->KEY[2]; + k3 = ctx->KEY[3]; + + sum = TEA_DELTA << 5; + + n = TEA_ROUNDS; + + while (n-- > 0) { + z -= ((y << 4) + k2) ^ (y + sum) ^ ((y >> 5) + k3); + y -= ((z << 4) + k0) ^ (z + sum) ^ ((z >> 5) + k1); + sum -= TEA_DELTA; + } + + u32_out (dst, y); + u32_out (dst + 4, z); + +} + +static int xtea_setkey(void *ctx_arg, const u8 *in_key, + unsigned int key_len, u32 *flags) +{ + + struct xtea_ctx *ctx = ctx_arg; + + if (key_len != 16) + { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + ctx->KEY[0] = u32_in (in_key); + ctx->KEY[1] = u32_in (in_key + 4); + ctx->KEY[2] = u32_in (in_key + 8); + ctx->KEY[3] = u32_in (in_key + 12); + + return 0; + +} + +static void xtea_encrypt(void *ctx_arg, u8 *dst, const u8 *src) +{ + + u32 y, z, sum = 0; + u32 limit = XTEA_DELTA * XTEA_ROUNDS; + + struct xtea_ctx *ctx = ctx_arg; + + y = u32_in (src); + z = u32_in (src + 4); + + while (sum != limit) { + y += (z << 4 ^ z >> 5) + (z ^ sum) + ctx->KEY[sum&3]; + sum += TEA_DELTA; + z += (y << 4 ^ y >> 5) + (y ^ sum) + ctx->KEY[sum>>11 &3]; + } + + u32_out (dst, y); + u32_out (dst + 4, z); + +} + +static void xtea_decrypt(void *ctx_arg, u8 *dst, const u8 *src) +{ + + u32 y, z, sum; + struct tea_ctx *ctx = ctx_arg; + + y = u32_in (src); + z = u32_in (src + 4); + + sum = XTEA_DELTA * XTEA_ROUNDS; + + while (sum) { + z -= (y << 4 ^ y >> 5) + (y ^ sum) + ctx->KEY[sum>>11 & 3]; + sum -= XTEA_DELTA; + y -= (z << 4 ^ z >> 5) + (z ^ sum) + ctx->KEY[sum & 3]; + } + + u32_out (dst, y); + u32_out (dst + 4, z); + +} + +static struct crypto_alg tea_alg = { + .cra_name = "tea", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = TEA_BLOCK_SIZE, + .cra_ctxsize = sizeof (struct tea_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(tea_alg.cra_list), + .cra_u = { .cipher = { + .cia_min_keysize = TEA_KEY_SIZE, + .cia_max_keysize = TEA_KEY_SIZE, + .cia_setkey = tea_setkey, + .cia_encrypt = tea_encrypt, + .cia_decrypt = tea_decrypt } } +}; + +static struct crypto_alg xtea_alg = { + .cra_name = "xtea", + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = XTEA_BLOCK_SIZE, + .cra_ctxsize = sizeof (struct xtea_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(xtea_alg.cra_list), + .cra_u = { .cipher = { + .cia_min_keysize = XTEA_KEY_SIZE, + .cia_max_keysize = XTEA_KEY_SIZE, + .cia_setkey = xtea_setkey, + .cia_encrypt = xtea_encrypt, + .cia_decrypt = xtea_decrypt } } +}; + +static int __init init(void) +{ + int ret = 0; + + ret = crypto_register_alg(&tea_alg); + if (ret < 0) + goto out; + + ret = crypto_register_alg(&xtea_alg); + if (ret < 0) { + crypto_unregister_alg(&tea_alg); + goto out; + } + +out: + return ret; +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&tea_alg); + crypto_unregister_alg(&xtea_alg); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("TEA & XTEA Cryptographic Algorithms"); diff -urN linux-2.4.26/crypto/twofish.c linux-2.4.27/crypto/twofish.c --- linux-2.4.26/crypto/twofish.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.27/crypto/twofish.c 2004-08-07 16:26:04.644346367 -0700 @@ -663,7 +663,10 @@ /* Check key length. */ if (key_len != 16 && key_len != 24 && key_len != 32) + { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; return -EINVAL; /* unsupported key length */ + } /* Compute the first two words of the S vector. The magic numbers are * the entries of the RS matrix, preprocessed through poly_to_exp. The diff -urN linux-2.4.26/drivers/acpi/Config.in linux-2.4.27/drivers/acpi/Config.in --- linux-2.4.26/drivers/acpi/Config.in 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.27/drivers/acpi/Config.in 2004-08-07 16:26:04.645346408 -0700 @@ -16,6 +16,7 @@ define_bool CONFIG_ACPI_POWER y if [ "$CONFIG_PCI" = "y" ]; then define_bool CONFIG_ACPI_PCI y + define_bool CONFIG_ACPI_MMCONFIG y fi define_bool CONFIG_ACPI_SLEEP y define_bool CONFIG_ACPI_SYSTEM y @@ -28,7 +29,6 @@ tristate ' ASUS Laptop Extras' CONFIG_ACPI_ASUS tristate ' Toshiba Laptop Extras' CONFIG_ACPI_TOSHIBA bool ' Debug Statements' CONFIG_ACPI_DEBUG - bool ' Relaxed AML Checking' CONFIG_ACPI_RELAXED_AML else if [ "$CONFIG_SMP" = "y" ]; then define_bool CONFIG_ACPI_BOOT y diff -urN linux-2.4.26/drivers/acpi/ac.c linux-2.4.27/drivers/acpi/ac.c --- linux-2.4.26/drivers/acpi/ac.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.27/drivers/acpi/ac.c 2004-08-07 16:26:04.646346449 -0700 @@ -156,6 +156,7 @@ acpi_ac_dir); if (!acpi_device_dir(device)) return_VALUE(-ENODEV); + acpi_device_dir(device)->owner = THIS_MODULE; } /* 'state' [R] */ @@ -168,6 +169,7 @@ else { entry->read_proc = acpi_ac_read_state; entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; } return_VALUE(0); @@ -181,6 +183,8 @@ ACPI_FUNCTION_TRACE("acpi_ac_remove_fs"); if (acpi_device_dir(device)) { + remove_proc_entry(ACPI_AC_FILE_STATE, + acpi_device_dir(device)); remove_proc_entry(acpi_device_bid(device), acpi_ac_dir); acpi_device_dir(device) = NULL; } @@ -318,6 +322,7 @@ acpi_ac_dir = proc_mkdir(ACPI_AC_CLASS, acpi_root_dir); if (!acpi_ac_dir) return_VALUE(-ENODEV); + acpi_ac_dir->owner = THIS_MODULE; result = acpi_bus_register_driver(&acpi_ac_driver); if (result < 0) { diff -urN linux-2.4.26/drivers/acpi/asus_acpi.c linux-2.4.27/drivers/acpi/asus_acpi.c --- linux-2.4.26/drivers/acpi/asus_acpi.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.27/drivers/acpi/asus_acpi.c 2004-08-07 16:26:04.648346531 -0700 @@ -40,8 +40,9 @@ #include #include #include +#include -#define ASUS_ACPI_VERSION "0.27" +#define ASUS_ACPI_VERSION "0.28" #define PROC_ASUS "asus" //the directory #define PROC_MLED "mled" @@ -125,12 +126,11 @@ L5x, //L5800C L8L, //L8400L M1A, //M1300A - M2E, //M2400E + M2E, //M2400E, L4400L + P30, //Samsung P30 S1x, //S1300A, but also L1400B and M2400A (L84F) S2x, //S200 (J1 reported), Victor MP-XP7210 - //TODO A1370D does not seem to have an ATK device - // L8400 model doesn't have ATK - xxN, //M2400N, M3700N, S1300N (Centrino) + xxN, //M2400N, M3700N, M6800N, S1300N, S5200N (Centrino) END_MODEL } model; //Models currently supported u16 event_count[128]; //count for each event TODO make this better @@ -140,6 +140,7 @@ #define A1x_PREFIX "\\_SB.PCI0.ISA.EC0." #define L3C_PREFIX "\\_SB.PCI0.PX40.ECD0." #define M1A_PREFIX "\\_SB.PCI0.PX40.EC0." +#define P30_PREFIX "\\_SB.PCI0.LPCB.EC0." #define S1x_PREFIX "\\_SB.PCI0.PX40." #define S2x_PREFIX A1x_PREFIX #define xxN_PREFIX "\\_SB.PCI0.SBRG.EC0." @@ -166,7 +167,7 @@ .mt_lcd_switch = A1x_PREFIX "_Q10", .lcd_status = "\\BKLI", .brightness_up = A1x_PREFIX "_Q0E", - .brightness_down = A1x_PREFIX "_Q0F", + .brightness_down = A1x_PREFIX "_Q0F" }, { @@ -176,11 +177,8 @@ .wled_status = "\\SG66", .mt_lcd_switch = "\\Q10", .lcd_status = "\\BAOF", - .brightness_up = "\\Q0E", - .brightness_down = "\\Q0F", .brightness_set = "SPLV", .brightness_get = "GPLV", - .brightness_status = "\\CMOD", .display_set = "SDSP", .display_get = "\\INFB" }, @@ -217,11 +215,8 @@ .mt_wled = "WLED", .mt_lcd_switch = L3C_PREFIX "_Q10", .lcd_status = "\\GL32", - .brightness_up = L3C_PREFIX "_Q0F", - .brightness_down = L3C_PREFIX "_Q0E", .brightness_set = "SPLV", .brightness_get = "GPLV", - .brightness_status = "\\BLVL", .display_set = "SDSP", .display_get = "\\_SB.PCI0.PCI1.VGAC.NMAP" }, @@ -233,11 +228,8 @@ .mt_wled = "WLED", .mt_lcd_switch = "\\Q10", .lcd_status = "\\BKLG", - .brightness_up = "\\Q0E", - .brightness_down = "\\Q0F", .brightness_set = "SPLV", .brightness_get = "GPLV", - .brightness_status = "\\BLVL", .display_set = "SDSP", .display_get = "\\INFB" }, @@ -257,14 +249,10 @@ { .name = "L5x", .mt_mled = "MLED", -// .mt_wled = "WLED", -// .wled_status = "\\WRED", -/* Present, but not controlled by ACPI */ +/* WLED present, but not controlled by ACPI */ .mt_tled = "TLED", .mt_lcd_switch = "\\Q0D", .lcd_status = "\\BAOF", - .brightness_up = "\\Q0C", - .brightness_down = "\\Q0B", .brightness_set = "SPLV", .brightness_get = "GPLV", .display_set = "SDSP", @@ -294,8 +282,6 @@ .mt_wled = "WLED", .mt_lcd_switch = "\\Q10", .lcd_status = "\\GP06", - .brightness_up = "\\Q0E", - .brightness_down = "\\Q0F", .brightness_set = "SPLV", .brightness_get = "GPLV", .display_set = "SDSP", @@ -303,17 +289,26 @@ }, { + .name = "P30", + .mt_wled = "WLED", + .mt_lcd_switch = P30_PREFIX "_Q0E", + .lcd_status = "\\BKLT", + .brightness_up = P30_PREFIX "_Q68", + .brightness_down = P30_PREFIX "_Q69", + .brightness_get = "GPLV", + .display_set = "SDSP", + .display_get = "\\DNXT" + }, + + { .name = "S1x", .mt_mled = "MLED", .mled_status = "\\EMLE", .mt_wled = "WLED", .mt_lcd_switch = S1x_PREFIX "Q10" , .lcd_status = "\\PNOF", - .brightness_up = S1x_PREFIX "Q0F", - .brightness_down = S1x_PREFIX "Q0E", .brightness_set = "SPLV", - .brightness_get = "GPLV", - .brightness_status = "\\BRIT", + .brightness_get = "GPLV" }, { @@ -323,22 +318,17 @@ .mt_lcd_switch = S2x_PREFIX "_Q10", .lcd_status = "\\BKLI", .brightness_up = S2x_PREFIX "_Q0B", - .brightness_down = S2x_PREFIX "_Q0A", + .brightness_down = S2x_PREFIX "_Q0A" }, { .name = "xxN", .mt_mled = "MLED", -// .mt_wled = "WLED", -// .wled_status = "\\PO33", -/* Present, but not controlled by ACPI */ +/* WLED present, but not controlled by ACPI */ .mt_lcd_switch = xxN_PREFIX "_Q10", .lcd_status = "\\BKLT", - .brightness_up = xxN_PREFIX "_Q0F", - .brightness_down = xxN_PREFIX "_Q0E", .brightness_set = "SPLV", .brightness_get = "GPLV", - .brightness_status = "\\LBTN", .display_set = "SDSP", .display_get = "\\ADVG" } @@ -466,6 +456,21 @@ return len; } + +static int parse_arg(const char *buf, unsigned long count, int *val) +{ + char s[32]; + if (!count) + return 0; + if (count > 31) + return -EINVAL; + if (copy_from_user(s, buf, count)) + return -EFAULT; + s[count] = 0; + if (sscanf(s, "%i", val) != 1) + return -EINVAL; + return count; +} /* @@ -497,11 +502,14 @@ write_led(const char *buffer, unsigned long count, struct asus_hotk *hotk, char *ledname, int ledmask, int invert) { - int value; + int value, retval; int led_out = 0; - if (sscanf(buffer, "%i", &value) == 1) - led_out = value ? 1 : 0; + retval = parse_arg(buffer, count, &value); + if (retval <= 0) + return retval; + count = retval; + led_out = value ? 1 : 0; hotk->status = (led_out) ? (hotk->status | ledmask) : (hotk->status & ~ledmask); @@ -654,15 +662,33 @@ proc_write_lcd(struct file *file, const char *buffer, unsigned long count, void *data) { - int value; + int value, retval; struct asus_hotk *hotk = (struct asus_hotk *) data; - if (sscanf(buffer, "%i", &value) == 1) + retval = parse_arg(buffer, count, &value); + if (retval > 0) set_lcd_state(hotk, value); - return count; + return retval; } +static int read_brightness(struct asus_hotk *hotk) +{ + int value; + + if(hotk->methods->brightness_get) { /* SPLV/GPLV laptop */ + if (!read_acpi_int(hotk->handle, hotk->methods->brightness_get, + &value)) + printk(KERN_WARNING "Asus ACPI: Error reading brightness\n"); + } else if (hotk->methods->brightness_status) { /* For D1 for example */ + if (!read_acpi_int(NULL, hotk->methods->brightness_status, + &value)) + printk(KERN_WARNING "Asus ACPI: Error reading brightness\n"); + } else /* No GPLV method */ + value = hotk->brightness; + return value; +} + /* * Change the brightness level */ @@ -679,7 +705,7 @@ } /* No SPLV method if we are here, act as appropriate */ - value -= hotk->brightness; + value -= read_brightness(hotk); while (value != 0) { status = acpi_evaluate_object(NULL, (value > 0) ? hotk->methods->brightness_up : @@ -692,23 +718,6 @@ return; } -static int read_brightness(struct asus_hotk *hotk) -{ - int value; - - if(hotk->methods->brightness_get) { /* SPLV/GPLV laptop */ - if (!read_acpi_int(hotk->handle, hotk->methods->brightness_get, - &value)) - printk(KERN_WARNING "Asus ACPI: Error reading brightness\n"); - } else if (hotk->methods->brightness_status) { /* For D1 for example */ - if (!read_acpi_int(NULL, hotk->methods->brightness_status, - &value)) - printk(KERN_WARNING "Asus ACPI: Error reading brightness\n"); - } else /* No GPLV method */ - value = hotk->brightness; - return value; -} - static int proc_read_brn(char *page, char **start, off_t off, int count, int *eof, void *data) @@ -721,10 +730,11 @@ proc_write_brn(struct file *file, const char *buffer, unsigned long count, void *data) { - int value; + int value, retval; struct asus_hotk *hotk = (struct asus_hotk *) data; - if (sscanf(buffer, "%d", &value) == 1) { + retval = parse_arg(buffer, count, &value); + if (retval > 0) { value = (0 < value) ? ((15 < value) ? 15 : value) : 0; /* 0 <= value <= 15 */ set_brightness(value, hotk); @@ -732,7 +742,7 @@ printk(KERN_WARNING "Asus ACPI: Error reading user input\n"); } - return count; + return retval; } static void set_display(int value, struct asus_hotk *hotk) @@ -770,16 +780,17 @@ proc_write_disp(struct file *file, const char *buffer, unsigned long count, void *data) { - int value; + int value, retval; struct asus_hotk *hotk = (struct asus_hotk *) data; - if (sscanf(buffer, "%d", &value) == 1) + retval = parse_arg(buffer, count, &value); + if (retval > 0) set_display(value, hotk); else { printk(KERN_WARNING "Asus ACPI: Error reading user input\n"); } - return count; + return retval; } @@ -874,6 +885,28 @@ return 0; } +static int asus_hotk_remove_fs(struct acpi_device* device) +{ + struct asus_hotk* hotk = acpi_driver_data(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)); + if (hotk->methods->mt_mled) + 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) + 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)) + remove_proc_entry(PROC_BRN, acpi_device_dir(device)); + if (hotk->methods->display_set) + remove_proc_entry(PROC_DISP, acpi_device_dir(device)); + } + return 0; +} + static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) { @@ -929,12 +962,29 @@ return -ENODEV; } - /* For testing purposes */ + /* This needs to be called for some laptops to init properly */ if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result)) printk(KERN_WARNING " Error calling BSTS\n"); else if (bsts_result) printk(KERN_NOTICE " BSTS called, 0x%02x returned\n", bsts_result); + /* Samsung P30 has a device with a valid _HID whose INIT does not + * return anything. Catch this one and any similar here */ + if (buffer.pointer == NULL) { + if (asus_info && /* Samsung P30 */ + strncmp(asus_info->oem_table_id, "ODEM", 4) == 0) { + hotk->model = P30; + printk(KERN_NOTICE " Samsung P30 detected, supported\n"); + } else { + hotk->model = M2E; + printk(KERN_WARNING " no string returned by INIT\n"); + printk(KERN_WARNING " trying default values, supply " + "the developers with your DSDT\n"); + } + hotk->methods = &model_conf[hotk->model]; + return AE_OK; + } + model = (union acpi_object *) buffer.pointer; if (model->type == ACPI_TYPE_STRING) { printk(KERN_NOTICE " %s model detected, ", model->string.pointer); @@ -953,12 +1003,14 @@ hotk->model = L8L; else if (strncmp(model->string.pointer, "M2N", 3) == 0 || strncmp(model->string.pointer, "M3N", 3) == 0 || + strncmp(model->string.pointer, "M6N", 3) == 0 || strncmp(model->string.pointer, "S1N", 3) == 0 || strncmp(model->string.pointer, "S5N", 3) == 0) hotk->model = xxN; else if (strncmp(model->string.pointer, "M1", 2) == 0) hotk->model = M1A; - else if (strncmp(model->string.pointer, "M2", 2) == 0) + else if (strncmp(model->string.pointer, "M2", 2) == 0 || + strncmp(model->string.pointer, "L4E", 3) == 0) hotk->model = M2E; else if (strncmp(model->string.pointer, "L2", 2) == 0) hotk->model = L2D; @@ -994,6 +1046,13 @@ else if (strncmp(model->string.pointer, "S5N", 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 */ + } else if (asus_info) { if (strncmp(asus_info->oem_table_id, "L1", 2) == 0) hotk->methods->mled_status = NULL; @@ -1049,8 +1108,8 @@ memset(hotk, 0, sizeof(struct asus_hotk)); hotk->handle = device->handle; - sprintf(acpi_device_name(device), "%s", ACPI_HOTK_DEVICE_NAME); - sprintf(acpi_device_class(device), "%s", ACPI_HOTK_CLASS); + strcpy(acpi_device_name(device), ACPI_HOTK_DEVICE_NAME); + strcpy(acpi_device_class(device), ACPI_HOTK_CLASS); acpi_driver_data(device) = hotk; hotk->device = device; @@ -1112,6 +1171,8 @@ if (ACPI_FAILURE(status)) printk(KERN_ERR "Asus ACPI: Error removing notify handler\n"); + asus_hotk_remove_fs(device); + kfree(hotk); return(0); diff -urN linux-2.4.26/drivers/acpi/battery.c linux-2.4.27/drivers/acpi/battery.c --- linux-2.4.26/drivers/acpi/battery.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.27/drivers/acpi/battery.c 2004-08-07 16:26:04.649346572 -0700 @@ -474,14 +474,18 @@ else p += sprintf(p, "capacity state: critical\n"); - if ((bst->state & 0x01) && (bst->state & 0x02)) + if ((bst->state & 0x01) && (bst->state & 0x02)){ p += sprintf(p, "charging state: charging/discharging\n"); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Battery Charging and Discharging?\n")); + } else if (bst->state & 0x01) p += sprintf(p, "charging state: discharging\n"); else if (bst->state & 0x02) p += sprintf(p, "charging state: charging\n"); - else - p += sprintf(p, "charging state: unknown\n"); + else { + p += sprintf(p, "charging state: charged\n"); + } if (bst->present_rate == ACPI_BATTERY_VALUE_UNKNOWN) p += sprintf(p, "present rate: unknown\n"); @@ -609,6 +613,7 @@ acpi_battery_dir); if (!acpi_device_dir(device)) return_VALUE(-ENODEV); + acpi_device_dir(device)->owner = THIS_MODULE; } /* 'info' [R] */ @@ -621,6 +626,7 @@ else { entry->read_proc = acpi_battery_read_info; entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; } /* 'status' [R] */ @@ -633,6 +639,7 @@ else { entry->read_proc = acpi_battery_read_state; entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; } /* 'alarm' [R/W] */ @@ -646,6 +653,7 @@ entry->read_proc = acpi_battery_read_alarm; entry->write_proc = acpi_battery_write_alarm; entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; } return_VALUE(0); @@ -659,6 +667,12 @@ ACPI_FUNCTION_TRACE("acpi_battery_remove_fs"); if (acpi_device_dir(device)) { + remove_proc_entry(ACPI_BATTERY_FILE_ALARM, + acpi_device_dir(device)); + remove_proc_entry(ACPI_BATTERY_FILE_STATUS, + acpi_device_dir(device)); + remove_proc_entry(ACPI_BATTERY_FILE_INFO, + acpi_device_dir(device)); remove_proc_entry(acpi_device_bid(device), acpi_battery_dir); acpi_device_dir(device) = NULL; } @@ -797,6 +811,7 @@ acpi_battery_dir = proc_mkdir(ACPI_BATTERY_CLASS, acpi_root_dir); if (!acpi_battery_dir) return_VALUE(-ENODEV); + acpi_battery_dir->owner = THIS_MODULE; result = acpi_bus_register_driver(&acpi_battery_driver); if (result < 0) { diff -urN linux-2.4.26/drivers/acpi/bus.c linux-2.4.27/drivers/acpi/bus.c --- linux-2.4.26/drivers/acpi/bus.c 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.27/drivers/acpi/bus.c 2004-08-07 16:26:04.650346613 -0700 @@ -1964,8 +1964,10 @@ acpi_ec_init(); /* ACPI Embedded Controller */ #endif #ifdef CONFIG_ACPI_PCI - acpi_pci_link_init(); /* ACPI PCI Interrupt Link */ - acpi_pci_root_init(); /* ACPI PCI Root Bridge */ + if (!acpi_pci_disabled) { + acpi_pci_link_init(); /* ACPI PCI Interrupt Link */ + acpi_pci_root_init(); /* ACPI PCI Root Bridge */ + } #endif /* * Enumerate devices in the ACPI namespace. diff -urN linux-2.4.26/drivers/acpi/button.c linux-2.4.27/drivers/acpi/button.c --- linux-2.4.26/drivers/acpi/button.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.27/drivers/acpi/button.c 2004-08-07 16:26:04.651346654 -0700 @@ -171,10 +171,15 @@ acpi_button_dir); break; } + + if (!entry) + return_VALUE(-ENODEV); + entry->owner = THIS_MODULE; acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry); if (!acpi_device_dir(device)) return_VALUE(-ENODEV); + acpi_device_dir(device)->owner = THIS_MODULE; /* 'info' [R] */ entry = create_proc_entry(ACPI_BUTTON_FILE_INFO, @@ -186,6 +191,7 @@ else { entry->read_proc = acpi_button_read_info; entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; } if (button->type==ACPI_BUTTON_TYPE_LID){ @@ -199,6 +205,7 @@ else { entry->read_proc = acpi_button_lid_read_state; entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; } } @@ -210,10 +217,37 @@ acpi_button_remove_fs ( struct acpi_device *device) { + struct acpi_button *button = NULL; + ACPI_FUNCTION_TRACE("acpi_button_remove_fs"); + button = acpi_driver_data(device); if (acpi_device_dir(device)) { - remove_proc_entry(acpi_device_bid(device), acpi_button_dir); + if (button->type == ACPI_BUTTON_TYPE_LID) + remove_proc_entry(ACPI_BUTTON_FILE_STATE, + acpi_device_dir(device)); + remove_proc_entry(ACPI_BUTTON_FILE_INFO, + acpi_device_dir(device)); + + remove_proc_entry(acpi_device_bid(device), + acpi_device_dir(device)->parent); + + switch (button->type) { + case ACPI_BUTTON_TYPE_POWER: + case ACPI_BUTTON_TYPE_POWERF: + remove_proc_entry(ACPI_BUTTON_SUBCLASS_POWER, + acpi_button_dir); + break; + case ACPI_BUTTON_TYPE_SLEEP: + case ACPI_BUTTON_TYPE_SLEEPF: + remove_proc_entry(ACPI_BUTTON_SUBCLASS_SLEEP, + acpi_button_dir); + break; + case ACPI_BUTTON_TYPE_LID: + remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, + acpi_button_dir); + break; + } acpi_device_dir(device) = NULL; } @@ -470,6 +504,7 @@ acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir); if (!acpi_button_dir) return_VALUE(-ENODEV); + acpi_button_dir->owner = THIS_MODULE; result = acpi_bus_register_driver(&acpi_button_driver); if (result < 0) { diff -urN linux-2.4.26/drivers/acpi/ec.c linux-2.4.27/drivers/acpi/ec.c --- linux-2.4.26/drivers/acpi/ec.c 2004-04-14 06:05:28.000000000 -0700 +++ linux-2.4.27/drivers/acpi/ec.c 2004-08-07 16:26:04.651346654 -0700 @@ -544,6 +544,12 @@ { ACPI_FUNCTION_TRACE("acpi_ec_remove_fs"); + if (acpi_device_dir(device)) { + remove_proc_entry(ACPI_EC_FILE_INFO, acpi_device_dir(device)); + remove_proc_entry(acpi_device_bid(device), acpi_ec_dir); + acpi_device_dir(device) = NULL; + } + return_VALUE(0); } diff -urN linux-2.4.26/drivers/acpi/fan.c linux-2.4.27/drivers/acpi/fan.c --- linux-2.4.26/drivers/acpi/fan.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.27/drivers/acpi/fan.c 2004-08-07 16:26:04.652346695 -0700 @@ -151,6 +151,7 @@ acpi_fan_dir); if (!acpi_device_dir(device)) return_VALUE(-ENODEV); + acpi_device_dir(device)->owner = THIS_MODULE; } /* 'status' [R/W] */ @@ -164,6 +165,7 @@ entry->read_proc = acpi_fan_read_state; entry->write_proc = acpi_fan_write_state; entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; } return_VALUE(0); @@ -177,6 +179,8 @@ ACPI_FUNCTION_TRACE("acpi_fan_remove_fs"); if (acpi_device_dir(device)) { + remove_proc_entry(ACPI_FAN_FILE_STATE, + acpi_device_dir(device)); remove_proc_entry(acpi_device_bid(device), acpi_fan_dir); acpi_device_dir(device) = NULL; } @@ -267,6 +271,7 @@ acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir); if (!acpi_fan_dir) return_VALUE(-ENODEV); + acpi_fan_dir->owner = THIS_MODULE; result = acpi_bus_register_driver(&acpi_fan_driver); if (result < 0) { diff -urN linux-2.4.26/drivers/acpi/pci_irq.c linux-2.4.27/drivers/acpi/pci_irq.c --- linux-2.4.26/drivers/acpi/pci_irq.c 2004-04-14 06:05:29.000000000 -0700 +++ linux-2.4.27/drivers/acpi/pci_irq.c 2004-08-07 16:26:04.653346736 -0700 @@ -373,7 +373,7 @@ if (!irq) { printk(KERN_WARNING PREFIX "No IRQ known for interrupt pin %c of device %s", ('A' + pin), dev->slot_name); /* Interrupt Line values above 0xF are forbidden */ - if (dev->irq && dev->irq >= 0xF) { + if (dev->irq && (dev->irq <= 0xF)) { printk(" - using IRQ %d\n", dev->irq); return_VALUE(dev->irq); } diff -urN linux-2.4.26/drivers/acpi/pci_link.c linux-2.4.27/drivers/acpi/pci_link.c --- linux-2.4.26/drivers/acpi/pci_link.c 2004-04-14 06:05:29.000000000 -0700 +++ linux-2.4.27/drivers/acpi/pci_link.c 2004-08-07 16:26:04.654346777 -0700 @@ -90,6 +90,9 @@ PCI Link Device Management -------------------------------------------------------------------------- */ +/* + * set context (link) possible list from resource list + */ static acpi_status acpi_pci_link_check_possible ( struct acpi_resource *resource, @@ -128,7 +131,7 @@ struct acpi_resource_ext_irq *p = &resource->data.extended_irq; if (!p || !p->number_of_interrupts) { ACPI_DEBUG_PRINT((ACPI_DB_WARN, - "Blank IRQ resource\n")); + "Blank EXT IRQ resource\n")); return AE_OK; } for (i = 0; (inumber_of_interrupts && idata.irq; if (!p || !p->number_of_interrupts) { - ACPI_DEBUG_PRINT((ACPI_DB_WARN, - "Blank IRQ resource\n")); + /* + * IRQ descriptors may have no IRQ# bits set, + * particularly those those w/ _STA disabled + */ + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Blank IRQ resource\n")); return AE_OK; } *irq = p->interrupts[0]; @@ -204,8 +211,12 @@ { struct acpi_resource_ext_irq *p = &resource->data.extended_irq; if (!p || !p->number_of_interrupts) { + /* + * extended IRQ descriptors must + * return at least 1 IRQ + */ ACPI_DEBUG_PRINT((ACPI_DB_WARN, - "Blank IRQ resource\n")); + "Blank EXT IRQ resource\n")); return AE_OK; } *irq = p->interrupts[0]; @@ -219,6 +230,13 @@ return AE_CTRL_TERMINATE; } +/* + * Run _CRS and set link->irq.active + * + * return value: + * 0 - success + * !0 - failure + */ static int acpi_pci_link_get_current ( struct acpi_pci_link *link) @@ -234,15 +252,19 @@ link->irq.active = 0; - /* Make sure the link is enabled (no use querying if it isn't). */ - result = acpi_bus_get_status(link->device); - if (result) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n")); - goto end; - } - if (!link->device->status.enabled) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled\n")); - return_VALUE(0); + /* in practice, status disabled is meaningless, ignore it */ + if (acpi_strict) { + /* Query _STA, set link->device->status */ + result = acpi_bus_get_status(link->device); + if (result) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n")); + goto end; + } + + if (!link->device->status.enabled) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled\n")); + return_VALUE(0); + } } /* @@ -257,18 +279,11 @@ goto end; } - if (!irq) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No IRQ resource found\n")); + if (acpi_strict && !irq) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "_CRS returned 0\n")); result = -ENODEV; - goto end; } - /* - * Note that we don't validate that the current IRQ (_CRS) exists - * within the possible IRQs (_PRS): we blindly assume that whatever - * IRQ a boot-enabled Link device is set to is the correct one. - * (Required to support systems such as the Toshiba 5005-S504.) - */ link->irq.active = irq; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d \n", link->irq.active)); @@ -278,32 +293,6 @@ } static int -acpi_pci_link_try_get_current ( - struct acpi_pci_link *link, - int irq) -{ - int result; - - ACPI_FUNCTION_TRACE("acpi_pci_link_try_get_current"); - - result = acpi_pci_link_get_current(link); - if (result && link->irq.active) { - return_VALUE(result); - } - - if (!link->irq.active) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No active IRQ resource found\n")); - printk(KERN_WARNING "_CRS returns NULL! Using IRQ %d for" - "device (%s [%s]).\n", irq, - acpi_device_name(link->device), - acpi_device_bid(link->device)); - link->irq.active = irq; - } - - return 0; -} - -static int acpi_pci_link_set ( struct acpi_pci_link *link, int irq) @@ -315,59 +304,24 @@ struct acpi_resource end; } resource; struct acpi_buffer buffer = {sizeof(resource)+1, &resource}; - int i = 0; - int valid = 0; - int resource_type = 0; - + ACPI_FUNCTION_TRACE("acpi_pci_link_set"); if (!link || !irq) return_VALUE(-EINVAL); - /* We don't check irqs the first time around */ - if (link->irq.setonboot) { - /* See if we're already at the target IRQ. */ - if (irq == link->irq.active) - return_VALUE(0); - - /* Make sure the target IRQ in the list of possible IRQs. */ - for (i=0; iirq.possible_count; i++) { - if (irq == link->irq.possible[i]) - valid = 1; - } - if (!valid) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Target IRQ %d invalid\n", irq)); - return_VALUE(-EINVAL); - } - } - - resource_type = link->irq.resource_type; - - if (resource_type != ACPI_RSTYPE_IRQ && - resource_type != ACPI_RSTYPE_EXT_IRQ){ - /* If IRQ<=15, first try with a "normal" IRQ descriptor. If that fails, try with - * an extended one */ - if (irq <= 15) { - resource_type = ACPI_RSTYPE_IRQ; - } else { - resource_type = ACPI_RSTYPE_EXT_IRQ; - } - } - -retry_programming: - memset(&resource, 0, sizeof(resource)); - /* NOTE: PCI interrupts are always level / active_low / shared. But not all - interrupts > 15 are PCI interrupts. Rely on the ACPI IRQ definition for - parameters */ - switch(resource_type) { + switch(link->irq.resource_type) { case ACPI_RSTYPE_IRQ: resource.res.id = ACPI_RSTYPE_IRQ; resource.res.length = sizeof(struct acpi_resource); resource.res.data.irq.edge_level = link->irq.edge_level; resource.res.data.irq.active_high_low = link->irq.active_high_low; - resource.res.data.irq.shared_exclusive = ACPI_SHARED; + if (link->irq.edge_level == ACPI_EDGE_SENSITIVE) + resource.res.data.irq.shared_exclusive = ACPI_EXCLUSIVE; + else + resource.res.data.irq.shared_exclusive = ACPI_SHARED; resource.res.data.irq.number_of_interrupts = 1; resource.res.data.irq.interrupts[0] = irq; break; @@ -378,55 +332,63 @@ resource.res.data.extended_irq.producer_consumer = ACPI_CONSUMER; resource.res.data.extended_irq.edge_level = link->irq.edge_level; resource.res.data.extended_irq.active_high_low = link->irq.active_high_low; - resource.res.data.extended_irq.shared_exclusive = ACPI_SHARED; + if (link->irq.edge_level == ACPI_EDGE_SENSITIVE) + resource.res.data.irq.shared_exclusive = ACPI_EXCLUSIVE; + else + resource.res.data.irq.shared_exclusive = ACPI_SHARED; resource.res.data.extended_irq.number_of_interrupts = 1; resource.res.data.extended_irq.interrupts[0] = irq; /* ignore resource_source, it's optional */ break; + default: + printk("ACPI BUG: resource_type %d\n", link->irq.resource_type); + return_VALUE(-EINVAL); } resource.end.id = ACPI_RSTYPE_END_TAG; /* Attempt to set the resource */ status = acpi_set_current_resources(link->handle, &buffer); - - /* if we failed and IRQ <= 15, try again with an extended descriptor */ - if (ACPI_FAILURE(status) && (resource_type == ACPI_RSTYPE_IRQ)) { - resource_type = ACPI_RSTYPE_EXT_IRQ; - printk(PREFIX "Retrying with extended IRQ descriptor\n"); - goto retry_programming; - } - /* check for total failure */ if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _SRS\n")); return_VALUE(-ENODEV); } - /* Make sure the device is enabled. */ + /* Query _STA, set device->status */ result = acpi_bus_get_status(link->device); if (result) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n")); return_VALUE(result); } if (!link->device->status.enabled) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link disabled\n")); - return_VALUE(-ENODEV); + printk(KERN_WARNING PREFIX + "%s [%s] disabled and referenced, BIOS bug.\n", + acpi_device_name(link->device), + acpi_device_bid(link->device)); } - /* Make sure the active IRQ is the one we requested. */ - result = acpi_pci_link_try_get_current(link, irq); + /* Query _CRS, set link->irq.active */ + result = acpi_pci_link_get_current(link); if (result) { return_VALUE(result); } - + + /* + * Is current setting not what we set? + * set link->irq.active + */ if (link->irq.active != irq) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, - "Attempt to enable at IRQ %d resulted in IRQ %d\n", - irq, link->irq.active)); - link->irq.active = 0; - acpi_ut_evaluate_object (link->handle, "_DIS", 0, NULL); - return_VALUE(-ENODEV); + /* + * policy: when _CRS doesn't return what we just _SRS + * assume _SRS worked and override _CRS value. + */ + printk(KERN_WARNING PREFIX + "%s [%s] BIOS reported IRQ %d, using IRQ %d\n", + acpi_device_name(link->device), + acpi_device_bid(link->device), + link->irq.active, irq); + link->irq.active = irq; } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d\n", link->irq.active)); @@ -480,7 +442,7 @@ #define PIRQ_PENALTY_ISA_USED (16*16*16*16*16) #define PIRQ_PENALTY_ISA_ALWAYS (16*16*16*16*16*16) -static int acpi_irq_penalty[ACPI_MAX_IRQS] = { +static int __initdata acpi_irq_penalty[ACPI_MAX_IRQS] = { PIRQ_PENALTY_ISA_ALWAYS, /* IRQ0 timer */ PIRQ_PENALTY_ISA_ALWAYS, /* IRQ1 keyboard */ PIRQ_PENALTY_ISA_ALWAYS, /* IRQ2 cascade */ @@ -493,7 +455,7 @@ PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ9 PCI, often acpi */ PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ10 PCI */ PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ11 PCI */ - PIRQ_PENALTY_ISA_TYPICAL, /* IRQ12 mouse */ + PIRQ_PENALTY_ISA_USED, /* IRQ12 mouse */ PIRQ_PENALTY_ISA_USED, /* IRQ13 fpe, sometimes */ PIRQ_PENALTY_ISA_USED, /* IRQ14 ide0 */ PIRQ_PENALTY_ISA_USED, /* IRQ15 ide1 */ @@ -553,10 +515,30 @@ if (link->irq.setonboot) return_VALUE(0); + /* + * search for active IRQ in list of possible IRQs. + */ + for (i = 0; i < link->irq.possible_count; ++i) { + if (link->irq.active == link->irq.possible[i]) + break; + } + /* + * forget active IRQ that is not in possible list + */ + if (i == link->irq.possible_count) { + if (acpi_strict) + printk(KERN_WARNING PREFIX "_CRS %d not found" + " in _PRS\n", link->irq.active); + link->irq.active = 0; + } + + /* + * if active found, use it; else pick entry from end of possible list. + */ if (link->irq.active) { irq = link->irq.active; } else { - irq = link->irq.possible[0]; + irq = link->irq.possible[link->irq.possible_count - 1]; } if (acpi_irq_balance || !link->irq.active) { @@ -572,7 +554,8 @@ /* Attempt to enable the link device at this IRQ. */ if (acpi_pci_link_set(link, irq)) { - printk(PREFIX "Unable to set IRQ for %s [%s] (likely buggy ACPI BIOS). Aborting ACPI-based IRQ routing. Try pci=noacpi or acpi=off\n", + printk(PREFIX "Unable to set IRQ for %s [%s] (likely buggy ACPI BIOS).\n" + "Try pci=noacpi or acpi=off\n", acpi_device_name(link->device), acpi_device_bid(link->device)); return_VALUE(-ENODEV); @@ -624,7 +607,7 @@ return_VALUE(0); if (!link->irq.active) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link disabled\n")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link active IRQ is 0!\n")); return_VALUE(0); } @@ -670,7 +653,6 @@ /* query and set link->irq.active */ acpi_pci_link_get_current(link); -//#ifdef CONFIG_ACPI_DEBUG printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device), acpi_device_bid(device)); for (i = 0; i < link->irq.possible_count; i++) { @@ -681,14 +663,25 @@ else printk(" %d", link->irq.possible[i]); } - printk(")\n"); -//#endif /* CONFIG_ACPI_DEBUG */ + + printk(")"); + + if (!found) + printk(" *%d", link->irq.active); + + if(!link->device->status.enabled) + printk(", disabled."); + + printk("\n"); /* TBD: Acquire/release lock */ list_add_tail(&link->node, &acpi_link.entries); acpi_link.count++; end: + /* disable all links -- to be activated on use */ + acpi_ut_evaluate_object(link->handle, "_DIS", 0, NULL); + if (result) kfree(link); diff -urN linux-2.4.26/drivers/acpi/pci_root.c linux-2.4.27/drivers/acpi/pci_root.c --- linux-2.4.26/drivers/acpi/pci_root.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.27/drivers/acpi/pci_root.c 2004-08-07 16:26:04.655346819 -0700 @@ -112,12 +112,47 @@ } } +static acpi_status +get_root_bridge_busnr_callback (struct acpi_resource *resource, void *data) +{ + int *busnr = (int *)data; + struct acpi_resource_address64 address; + + if (resource->id != ACPI_RSTYPE_ADDRESS16 && + resource->id != ACPI_RSTYPE_ADDRESS32 && + resource->id != ACPI_RSTYPE_ADDRESS64) + return AE_OK; + + acpi_resource_to_address64(resource, &address); + if ((address.address_length > 0) && + (address.resource_type == ACPI_BUS_NUMBER_RANGE)) + *busnr = address.min_address_range; + + return AE_OK; +} + +static acpi_status +try_get_root_bridge_busnr(acpi_handle handle, int *busnum) +{ + acpi_status status; + + *busnum = -1; + status = acpi_walk_resources(handle, METHOD_NAME__CRS, get_root_bridge_busnr_callback, busnum); + if (ACPI_FAILURE(status)) + return status; + /* Check if we really get a bus number from _CRS */ + if (*busnum == -1) + return AE_ERROR; + return AE_OK; +} + static int acpi_pci_root_add ( struct acpi_device *device) { int result = 0; struct acpi_pci_root *root = NULL; + struct acpi_pci_root *tmp; acpi_status status = AE_OK; unsigned long value = 0; acpi_handle handle = NULL; @@ -152,8 +187,6 @@ switch (status) { case AE_OK: root->id.segment = (u16) value; - printk("_SEG exists! Unsupported. Abort.\n"); - BUG(); break; case AE_NOT_FOUND: ACPI_DEBUG_PRINT((ACPI_DB_INFO, @@ -187,6 +220,27 @@ goto end; } + /* Some systems have wrong _BBN */ + list_for_each_entry(tmp, &acpi_pci_roots, node) { + if ((tmp->id.segment == root->id.segment) + && (tmp->id.bus == root->id.bus)) { + int bus = 0; + acpi_status status; + + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Wrong _BBN value, please reboot and using option 'pci=noacpi'\n")); + + status = try_get_root_bridge_busnr(root->handle, &bus); + if (ACPI_FAILURE(status)) + break; + if (bus != root->id.bus) { + printk(KERN_INFO PREFIX "PCI _CRS %d overrides _BBN 0\n", bus); + root->id.bus = bus; + } + break; + } + } + /* * Device & Function * ----------------- @@ -213,7 +267,12 @@ * PCI namespace does not get created until this call is made (and * thus the root bridge's pci_dev does not exist). */ +#ifdef CONFIG_X86 root->bus = pcibios_scan_root(root->id.bus); +#else + root->bus = pcibios_scan_root(root->handle, + root->id.segment, root->id.bus); +#endif if (!root->bus) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Bus %02x:%02x not present in PCI namespace\n", diff -urN linux-2.4.26/drivers/acpi/power.c linux-2.4.27/drivers/acpi/power.c --- linux-2.4.26/drivers/acpi/power.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.27/drivers/acpi/power.c 2004-08-07 16:26:04.656346860 -0700 @@ -469,6 +469,8 @@ ACPI_FUNCTION_TRACE("acpi_power_remove_fs"); if (acpi_device_dir(device)) { + remove_proc_entry(ACPI_POWER_FILE_STATUS, + acpi_device_dir(device)); remove_proc_entry(acpi_device_bid(device), acpi_power_dir); acpi_device_dir(device) = NULL; } diff -urN linux-2.4.26/drivers/acpi/processor.c linux-2.4.27/drivers/acpi/processor.c --- linux-2.4.26/drivers/acpi/processor.c 2004-04-14 06:05:29.000000000 -0700 +++ linux-2.4.27/drivers/acpi/processor.c 2004-08-07 16:26:04.657346901 -0700 @@ -2011,6 +2011,7 @@ if (!acpi_device_dir(device)) return_VALUE(-ENODEV); } + acpi_device_dir(device)->owner = THIS_MODULE; /* 'info' [R] */ entry = create_proc_entry(ACPI_PROCESSOR_FILE_INFO, @@ -2022,6 +2023,7 @@ else { entry->read_proc = acpi_processor_read_info; entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; } /* 'power' [R] */ @@ -2034,6 +2036,7 @@ else { entry->read_proc = acpi_processor_read_power; entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; } /* 'performance' [R/W] */ @@ -2047,6 +2050,7 @@ entry->read_proc = acpi_processor_read_performance; entry->write_proc = acpi_processor_write_performance; entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; } /* 'throttling' [R/W] */ @@ -2060,6 +2064,7 @@ entry->read_proc = acpi_processor_read_throttling; entry->write_proc = acpi_processor_write_throttling; entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; } /* 'limit' [R/W] */ @@ -2073,6 +2078,7 @@ entry->read_proc = acpi_processor_read_limit; entry->write_proc = acpi_processor_write_limit; entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; } return_VALUE(0); @@ -2349,6 +2355,7 @@ acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir); if (!acpi_processor_dir) return_VALUE(-ENODEV); + acpi_processor_dir->owner = THIS_MODULE; result = acpi_bus_register_driver(&acpi_processor_driver); if (result < 0) { diff -urN linux-2.4.26/drivers/acpi/tables.c linux-2.4.27/drivers/acpi/tables.c --- linux-2.4.26/drivers/acpi/tables.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.27/drivers/acpi/tables.c 2004-08-07 16:26:04.658346942 -0700 @@ -58,6 +58,7 @@ [ACPI_SSDT] = "SSDT", [ACPI_SPMI] = "SPMI", [ACPI_HPET] = "HPET", + [ACPI_MCFG] = "MCFG", }; static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" }; diff -urN linux-2.4.26/drivers/acpi/thermal.c linux-2.4.27/drivers/acpi/thermal.c --- linux-2.4.26/drivers/acpi/thermal.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.27/drivers/acpi/thermal.c 2004-08-07 16:26:04.659346983 -0700 @@ -227,6 +227,13 @@ 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); } @@ -1051,6 +1058,7 @@ acpi_thermal_dir); if (!acpi_device_dir(device)) return_VALUE(-ENODEV); + acpi_device_dir(device)->owner = THIS_MODULE; } /* 'state' [R] */ @@ -1063,6 +1071,7 @@ else { entry->read_proc = acpi_thermal_read_state; entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; } /* 'temperature' [R] */ @@ -1075,6 +1084,7 @@ else { entry->read_proc = acpi_thermal_read_temperature; entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; } /* 'trip_points' [R/W] */ @@ -1088,6 +1098,7 @@ entry->read_proc = acpi_thermal_read_trip_points; entry->write_proc = acpi_thermal_write_trip_points; entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; } /* 'cooling_mode' [R/W] */ @@ -1101,6 +1112,7 @@ entry->read_proc = acpi_thermal_read_cooling_mode; entry->write_proc = acpi_thermal_write_cooling_mode; entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; } /* 'polling_frequency' [R/W] */ @@ -1114,6 +1126,7 @@ entry->read_proc = acpi_thermal_read_polling; entry->write_proc = acpi_thermal_write_polling; entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; } return_VALUE(0); @@ -1127,6 +1140,16 @@ ACPI_FUNCTION_TRACE("acpi_thermal_remove_fs"); if (acpi_device_dir(device)) { + remove_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ, + acpi_device_dir(device)); + remove_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE, + acpi_device_dir(device)); + remove_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS, + acpi_device_dir(device)); + remove_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE, + acpi_device_dir(device)); + remove_proc_entry(ACPI_THERMAL_FILE_STATE, + acpi_device_dir(device)); remove_proc_entry(acpi_device_bid(device), acpi_thermal_dir); acpi_device_dir(device) = NULL; } @@ -1332,6 +1355,7 @@ acpi_thermal_dir = proc_mkdir(ACPI_THERMAL_CLASS, acpi_root_dir); if (!acpi_thermal_dir) return_VALUE(-ENODEV); + acpi_thermal_dir->owner = THIS_MODULE; result = acpi_bus_register_driver(&acpi_thermal_driver); if (result < 0) { diff -urN linux-2.4.26/drivers/acpi/toshiba_acpi.c linux-2.4.27/drivers/acpi/toshiba_acpi.c --- linux-2.4.26/drivers/acpi/toshiba_acpi.c 2004-04-14 06:05:29.000000000 -0700 +++ linux-2.4.27/drivers/acpi/toshiba_acpi.c 2004-08-07 16:26:04.660347024 -0700 @@ -503,6 +503,8 @@ proc = create_proc_read_entry(item->name, S_IFREG | S_IRUGO | S_IWUSR, toshiba_proc_dir, (read_proc_t*)dispatch_read, item); + if (proc) + proc->owner = THIS_MODULE; if (proc && item->write_func) proc->write_proc = (write_proc_t*)dispatch_write; } @@ -526,6 +528,8 @@ acpi_status status = AE_OK; u32 hci_result; + if (acpi_disabled) + return -ENODEV; /* simple device detection: look for HCI method */ if (is_valid_acpi_path(METHOD_HCI_1)) method_hci = METHOD_HCI_1; @@ -548,6 +552,7 @@ if (!toshiba_proc_dir) { status = AE_ERROR; } else { + toshiba_proc_dir->owner = THIS_MODULE; status = add_device(); if (ACPI_FAILURE(status)) remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); diff -urN linux-2.4.26/drivers/atm/Config.in linux-2.4.27/drivers/atm/Config.in --- linux-2.4.26/drivers/atm/Config.in 2003-08-25 04:44:41.000000000 -0700 +++ linux-2.4.27/drivers/atm/Config.in 2004-08-07 16:26:04.660347024 -0700 @@ -83,6 +83,7 @@ fi if [ "$CONFIG_ATM_FORE200E_PCA" = "y" -o "$CONFIG_ATM_FORE200E_SBA" = "y" ]; \ then + bool ' Defer interrupt work to a tasklet' CONFIG_ATM_FORE200E_USE_TASKLET int ' Maximum number of tx retries' CONFIG_ATM_FORE200E_TX_RETRY 16 int ' Debugging level (0-3)' CONFIG_ATM_FORE200E_DEBUG 0 if [ "$CONFIG_ATM_FORE200E_MAYBE" = "y" ]; then diff -urN linux-2.4.26/drivers/atm/fore200e.c linux-2.4.27/drivers/atm/fore200e.c --- linux-2.4.26/drivers/atm/fore200e.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.27/drivers/atm/fore200e.c 2004-08-07 16:26:04.666347271 -0700 @@ -2,7 +2,7 @@ $Id: fore200e.c,v 1.5 2000/04/14 10:10:34 davem Exp $ A FORE Systems 200E-series driver for ATM on Linux. - Christophe Lizzi (lizzi@cnam.fr), October 1999-March 2000. + Christophe Lizzi (lizzi@cnam.fr), October 1999-March 2003. Based on the PCA-200E driver from Uwe Dannowski (Uwe.Dannowski@inf.tu-dresden.de). @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include #include #include @@ -46,7 +48,6 @@ #include #include #include -#include #ifdef CONFIG_ATM_FORE200E_SBA #include @@ -56,25 +57,33 @@ #include #endif -#include +#if defined(CONFIG_ATM_FORE200E_USE_TASKLET) /* defer interrupt work to a tasklet */ +#define FORE200E_USE_TASKLET +#endif -#include "fore200e.h" -#include "suni.h" +#if 0 /* enable the debugging code of the buffer supply queues */ +#define FORE200E_BSQ_DEBUG +#endif -#if 1 /* ensure correct handling of 52-byte AAL0 SDUs used by atmdump-like apps */ +#if 1 /* ensure correct handling of 52-byte AAL0 SDUs expected by atmdump-like apps */ #define FORE200E_52BYTE_AAL0_SDU #endif -#define FORE200E_VERSION "0.2d" +#include "fore200e.h" +#include "suni.h" +#define FORE200E_VERSION "0.3e" #define FORE200E "fore200e: " +#if 0 /* override .config */ +#define CONFIG_ATM_FORE200E_DEBUG 1 +#endif #if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG > 0) #define DPRINTK(level, format, args...) do { if (CONFIG_ATM_FORE200E_DEBUG >= (level)) \ - printk(FORE200E format, ##args); } while(0) + printk(FORE200E format, ##args); } while (0) #else -#define DPRINTK(level, format, args...) while(0) +#define DPRINTK(level, format, args...) do {} while (0) #endif @@ -85,18 +94,28 @@ #define FORE200E_INDEX(virt_addr, type, index) (&((type *)(virt_addr))[ index ]) -#define FORE200E_NEXT_ENTRY(index, modulo) (index = ++(index) % (modulo)) +#define FORE200E_NEXT_ENTRY(index, modulo) (index = ++(index) % (modulo)) #define MSECS(ms) (((ms)*HZ/1000)+1) +#if 1 +#define ASSERT(expr) if (!(expr)) { \ + printk(FORE200E "assertion failed! %s[%d]: %s\n", \ + __FUNCTION__, __LINE__, #expr); \ + panic(FORE200E "%s", __FUNCTION__); \ + } +#else +#define ASSERT(expr) do {} while (0) +#endif + + extern const struct atmdev_ops fore200e_ops; extern const struct fore200e_bus fore200e_bus[]; static struct fore200e* fore200e_boards = NULL; - #ifdef MODULE MODULE_AUTHOR("Christophe Lizzi - credits to Uwe Dannowski and Heikki Vatiainen"); MODULE_DESCRIPTION("FORE Systems 200E-series ATM driver - version " FORE200E_VERSION); @@ -225,29 +244,6 @@ } - -#if 0 /* currently unused */ -static int -fore200e_checkup(struct fore200e* fore200e) -{ - u32 hb1, hb2; - - hb1 = fore200e->bus->read(&fore200e->cp_queues->heartbeat); - fore200e_spin(10); - hb2 = fore200e->bus->read(&fore200e->cp_queues->heartbeat); - - if (hb2 <= hb1) { - printk(FORE200E "device %s heartbeat is not counting upwards, hb1 = %x; hb2 = %x\n", - fore200e->name, hb1, hb2); - return -EIO; - } - printk(FORE200E "device %s heartbeat is ok\n", fore200e->name); - - return 0; -} -#endif - - static void fore200e_spin(int msecs) { @@ -444,7 +440,6 @@ } - #ifdef CONFIG_ATM_FORE200E_PCA static u32 fore200e_pca_read(volatile u32* addr) @@ -501,20 +496,16 @@ fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int nbr, int alignment) { -#if defined(__sparc_v9__) /* returned chunks are page-aligned */ + chunk->alloc_size = size * nbr; chunk->alloc_addr = pci_alloc_consistent((struct pci_dev*)fore200e->bus_dev, chunk->alloc_size, &chunk->dma_addr); - if (chunk->alloc_addr == NULL || chunk->dma_addr == 0) + if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0)) return -ENOMEM; chunk->align_addr = chunk->alloc_addr; -#else - if (fore200e_chunk_alloc(fore200e, chunk, size * nbr, alignment, FORE200E_DMA_BIDIRECTIONAL) < 0) - return -ENOMEM; -#endif return 0; } @@ -525,14 +516,10 @@ static void fore200e_pca_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk) { -#if defined(__sparc_v9__) pci_free_consistent((struct pci_dev*)fore200e->bus_dev, chunk->alloc_size, chunk->alloc_addr, chunk->dma_addr); -#else - fore200e_chunk_free(fore200e, chunk); -#endif } @@ -540,7 +527,15 @@ fore200e_pca_irq_check(struct fore200e* fore200e) { /* this is a 1 bit register */ - return readl(fore200e->regs.pca.psr); + int irq_posted = readl(fore200e->regs.pca.psr); + +#if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG == 2) + if (irq_posted && (readl(fore200e->regs.pca.hcr) & PCA200E_HCR_OUTFULL)) { + DPRINTK(2,"FIFO OUT full, device %d\n", fore200e->atm_dev->number); + } +#endif + + return irq_posted; } @@ -574,7 +569,7 @@ DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base); - /* gain access to the PCA-200E specific registers */ + /* gain access to the PCA specific registers */ fore200e->regs.pca.hcr = (u32*)(fore200e->virt_base + PCA200E_HCR_OFFSET); fore200e->regs.pca.imr = (u32*)(fore200e->virt_base + PCA200E_IMR_OFFSET); fore200e->regs.pca.psr = (u32*)(fore200e->virt_base + PCA200E_PSR_OFFSET); @@ -589,8 +584,6 @@ { DPRINTK(2, "device %s being unmapped from memory\n", fore200e->name); - /* XXX iounmap() does nothing on PowerPC (at least in 2.2.12 and 2.3.41), - this leads to a kernel panic if the module is loaded and unloaded several times */ if (fore200e->virt_base != NULL) iounmap(fore200e->virt_base); } @@ -600,7 +593,7 @@ fore200e_pca_configure(struct fore200e* fore200e) { struct pci_dev* pci_dev = (struct pci_dev*)fore200e->bus_dev; - u8 master_ctrl; + u8 master_ctrl, latency; DPRINTK(2, "device %s being configured\n", fore200e->name); @@ -609,21 +602,29 @@ return -EIO; } - pci_read_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, &master_ctrl); + pci_read_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, &master_ctrl); master_ctrl = master_ctrl -#if 0 - | PCA200E_CTRL_DIS_CACHE_RD - | PCA200E_CTRL_DIS_WRT_INVAL -#endif #if defined(__BIG_ENDIAN) /* request the PCA board to convert the endianess of slave RAM accesses */ | PCA200E_CTRL_CONVERT_ENDIAN #endif +#if 0 + | PCA200E_CTRL_DIS_CACHE_RD + | PCA200E_CTRL_DIS_WRT_INVAL + | PCA200E_CTRL_ENA_CONT_REQ_MODE + | PCA200E_CTRL_2_CACHE_WRT_INVAL +#endif | PCA200E_CTRL_LARGE_PCI_BURSTS; pci_write_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, master_ctrl); + /* raise latency from 32 (default) to 192, as this seems to prevent NIC + lockups (under heavy rx loads) due to continuous 'FIFO OUT full' condition. + this may impact the performances of other PCI devices on the same bus, though */ + latency = 192; + pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency); + fore200e->state = FORE200E_STATE_CONFIGURE; return 0; } @@ -657,11 +658,7 @@ fore200e->bus = bus; fore200e->bus_dev = pci_dev; fore200e->irq = pci_dev->irq; - fore200e->phys_base = pci_resource_start (pci_dev, 0); - -#if defined(__powerpc__) - fore200e->phys_base += KERNELBASE; -#endif + fore200e->phys_base = pci_resource_start(pci_dev, 0); sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1); @@ -729,8 +726,6 @@ #endif /* CONFIG_ATM_FORE200E_PCA */ - - #ifdef CONFIG_ATM_FORE200E_SBA static u32 @@ -792,7 +787,7 @@ chunk->alloc_size, &chunk->dma_addr); - if (chunk->alloc_addr == NULL || chunk->dma_addr == 0) + if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0)) return -ENOMEM; chunk->align_addr = chunk->alloc_addr; @@ -851,8 +846,7 @@ struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev; unsigned int bursts; - /* gain access to the SBA-200E specific registers */ - + /* gain access to the SBA specific registers */ fore200e->regs.sba.hcr = (u32*)sbus_ioremap(&sbus_dev->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR"); fore200e->regs.sba.bsr = (u32*)sbus_ioremap(&sbus_dev->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR"); fore200e->regs.sba.isr = (u32*)sbus_ioremap(&sbus_dev->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR"); @@ -873,17 +867,6 @@ if (sbus_can_dma_64bit(sbus_dev)) sbus_set_sbus64(sbus_dev, bursts); -#if 0 - if (bursts & DMA_BURST16) - fore200e->bus->write(SBA200E_BSR_BURST16, fore200e->regs.sba.bsr); - else - if (bursts & DMA_BURST8) - fore200e->bus->write(SBA200E_BSR_BURST8, fore200e->regs.sba.bsr); - else - if (bursts & DMA_BURST4) - fore200e->bus->write(SBA200E_BSR_BURST4, fore200e->regs.sba.bsr); -#endif - fore200e->state = FORE200E_STATE_MAP; return 0; } @@ -928,13 +911,11 @@ return NULL; found: -#if 1 if (sbus_dev->num_registers != 4) { printk(FORE200E "this %s device has %d instead of 4 registers\n", bus->model_name, sbus_dev->num_registers); return NULL; } -#endif fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL); if (fore200e == NULL) @@ -987,46 +968,143 @@ static void -fore200e_irq_tx(struct fore200e* fore200e) +fore200e_tx_irq(struct fore200e* fore200e) { - struct host_txq_entry* entry; - int i; - - entry = fore200e->host_txq.host_entry; + struct host_txq* txq = &fore200e->host_txq; + struct host_txq_entry* entry; + struct atm_vcc* vcc; + struct fore200e_vc_map* vc_map; - for (i = 0; i < QUEUE_SIZE_TX; i++) { + if (fore200e->host_txq.txing == 0) + return; + + for (;;) { + + entry = &txq->host_entry[ txq->tail ]; - if (*entry->status & STATUS_COMPLETE) { + if ((*entry->status & STATUS_COMPLETE) == 0) { + break; + } - DPRINTK(3, "TX COMPLETED: entry = %p, vcc = %p, skb = %p\n", entry, entry->vcc, entry->skb); + DPRINTK(3, "TX COMPLETED: entry = %p [tail = %d], vc_map = %p, skb = %p\n", + entry, txq->tail, entry->vc_map, entry->skb); - /* free copy of misaligned data */ - if (entry->data) - kfree(entry->data); + /* free copy of misaligned data */ + if (entry->data) + kfree(entry->data); + + /* remove DMA mapping */ + fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length, + FORE200E_DMA_TODEVICE); - /* remove DMA mapping */ - fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length, - FORE200E_DMA_TODEVICE); + vc_map = entry->vc_map; - /* notify tx completion */ - if (entry->vcc->pop) - entry->vcc->pop(entry->vcc, entry->skb); - else - dev_kfree_skb_irq(entry->skb); + /* vcc closed since the time the entry was submitted for tx? */ + if ((vc_map->vcc == NULL) || + (test_bit(ATM_VF_READY, &vc_map->vcc->flags) == 0)) { - /* check error condition */ - if (*entry->status & STATUS_ERROR) - atomic_inc(&entry->vcc->stats->tx_err); - else - atomic_inc(&entry->vcc->stats->tx); + DPRINTK(1, "no ready vcc found for PDU sent on device %d\n", + fore200e->atm_dev->number); - *entry->status = STATUS_FREE; - - fore200e->host_txq.txing--; + dev_kfree_skb_any(entry->skb); + } + else { + ASSERT(vc_map->vcc); + + /* vcc closed then immediately re-opened? */ + if (vc_map->incarn != entry->incarn) { + + /* when a vcc is closed, some PDUs may be still pending in the tx queue. + if the same vcc is immediately re-opened, those pending PDUs must + not be popped after the completion of their emission, as they refer + to the prior incarnation of that vcc. otherwise, vcc->sk->wmem_alloc + would be decremented by the size of the (unrelated) skb, possibly + leading to a negative sk->wmem_alloc count, ultimately freezing the vcc. + we thus bind the tx entry to the current incarnation of the vcc + when the entry is submitted for tx. When the tx later completes, + if the incarnation number of the tx entry does not match the one + of the vcc, then this implies that the vcc has been closed then re-opened. + we thus just drop the skb here. */ + + DPRINTK(1, "vcc closed-then-re-opened; dropping PDU sent on device %d\n", + fore200e->atm_dev->number); + + dev_kfree_skb_any(entry->skb); + } + else { + vcc = vc_map->vcc; + ASSERT(vcc); + + /* notify tx completion */ + if (vcc->pop) { + vcc->pop(vcc, entry->skb); + } + else { + dev_kfree_skb_any(entry->skb); + } +#if 1 + /* race fixed by the above incarnation mechanism, but... */ + if (atomic_read(&vcc->sk->wmem_alloc) < 0) { + atomic_set(&vcc->sk->wmem_alloc, 0); + } +#endif + /* check error condition */ + if (*entry->status & STATUS_ERROR) + atomic_inc(&vcc->stats->tx_err); + else + atomic_inc(&vcc->stats->tx); + } + } + + *entry->status = STATUS_FREE; + + fore200e->host_txq.txing--; + + FORE200E_NEXT_ENTRY(txq->tail, QUEUE_SIZE_TX); + } +} + + +#ifdef FORE200E_BSQ_DEBUG +int bsq_audit(int where, struct host_bsq* bsq, int scheme, int magn) +{ + struct buffer* buffer; + int count = 0; + + buffer = bsq->freebuf; + while (buffer) { + + if (buffer->supplied) { + printk(FORE200E "bsq_audit(%d): queue %d.%d, buffer %ld supplied but in free list!\n", + where, scheme, magn, buffer->index); + } + + if (buffer->magn != magn) { + printk(FORE200E "bsq_audit(%d): queue %d.%d, buffer %ld, unexpected magn = %d\n", + where, scheme, magn, buffer->index, buffer->magn); + } + + if (buffer->scheme != scheme) { + printk(FORE200E "bsq_audit(%d): queue %d.%d, buffer %ld, unexpected scheme = %d\n", + where, scheme, magn, buffer->index, buffer->scheme); + } + + if ((buffer->index < 0) || (buffer->index >= fore200e_rx_buf_nbr[ scheme ][ magn ])) { + printk(FORE200E "bsq_audit(%d): queue %d.%d, out of range buffer index = %ld !\n", + where, scheme, magn, buffer->index); } - entry++; + + count++; + buffer = buffer->next; + } + + if (count != bsq->freebuf_count) { + printk(FORE200E "bsq_audit(%d): queue %d.%d, %d bufs in free list, but freebuf_count = %d\n", + where, scheme, magn, count, bsq->freebuf_count); } + return 0; } +#endif static void @@ -1043,28 +1121,42 @@ bsq = &fore200e->host_bsq[ scheme ][ magn ]; - if (fore200e_rx_buf_nbr[ scheme ][ magn ] - bsq->count > RBD_BLK_SIZE) { +#ifdef FORE200E_BSQ_DEBUG + bsq_audit(1, bsq, scheme, magn); +#endif + while (bsq->freebuf_count >= RBD_BLK_SIZE) { - DPRINTK(2, "supplying rx buffers to queue %d / %d, count = %d\n", - scheme, magn, bsq->count); + DPRINTK(2, "supplying %d rx buffers to queue %d / %d, freebuf_count = %d\n", + RBD_BLK_SIZE, scheme, magn, bsq->freebuf_count); entry = &bsq->host_entry[ bsq->head ]; - - FORE200E_NEXT_ENTRY(bsq->head, QUEUE_SIZE_BS); for (i = 0; i < RBD_BLK_SIZE; i++) { - buffer = &bsq->buffer[ bsq->free ]; - - FORE200E_NEXT_ENTRY(bsq->free, fore200e_rx_buf_nbr[ scheme ][ magn ]); + /* take the first buffer in the free buffer list */ + buffer = bsq->freebuf; + if (!buffer) { + printk(FORE200E "no more free bufs in queue %d.%d, but freebuf_count = %d\n", + scheme, magn, bsq->freebuf_count); + return; + } + bsq->freebuf = buffer->next; +#ifdef FORE200E_BSQ_DEBUG + if (buffer->supplied) + printk(FORE200E "queue %d.%d, buffer %lu already supplied\n", + scheme, magn, buffer->index); + buffer->supplied = 1; +#endif entry->rbd_block->rbd[ i ].buffer_haddr = buffer->data.dma_addr; entry->rbd_block->rbd[ i ].handle = FORE200E_BUF2HDL(buffer); } - /* increase the number of supplied rx buffers */ - bsq->count += RBD_BLK_SIZE; - + FORE200E_NEXT_ENTRY(bsq->head, QUEUE_SIZE_BS); + + /* decrease accordingly the number of free rx buffers */ + bsq->freebuf_count -= RBD_BLK_SIZE; + *entry->status = STATUS_PENDING; fore200e->bus->write(entry->rbd_block_dma, &entry->cp_entry->rbd_block_haddr); } @@ -1073,33 +1165,9 @@ } - -static struct atm_vcc* -fore200e_find_vcc(struct fore200e* fore200e, struct rpd* rpd) -{ - struct sock *s; - struct atm_vcc* vcc; - - read_lock(&vcc_sklist_lock); - for(s = vcc_sklist; s; s = s->next) { - vcc = s->protinfo.af_atm; - if (vcc->dev != fore200e->atm_dev) - continue; - if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci) { - read_unlock(&vcc_sklist_lock); - return vcc; - } - } - read_unlock(&vcc_sklist_lock); - - return NULL; -} - - -static void -fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd) +static int +fore200e_push_rpd(struct fore200e* fore200e, struct atm_vcc* vcc, struct rpd* rpd) { - struct atm_vcc* vcc; struct sk_buff* skb; struct buffer* buffer; struct fore200e_vcc* fore200e_vcc; @@ -1108,15 +1176,10 @@ u32 cell_header = 0; #endif - vcc = fore200e_find_vcc(fore200e, rpd); - if (vcc == NULL) { - - printk(FORE200E "no vcc found for PDU received on %d.%d.%d\n", - fore200e->atm_dev->number, rpd->atm_header.vpi, rpd->atm_header.vci); - return; - } - + ASSERT(vcc); + fore200e_vcc = FORE200E_VCC(vcc); + ASSERT(fore200e_vcc); #ifdef FORE200E_52BYTE_AAL0_SDU if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.rxtp.max_sdu == ATM_AAL0_SDU)) { @@ -1136,10 +1199,10 @@ skb = alloc_skb(pdu_len, GFP_ATOMIC); if (skb == NULL) { - - printk(FORE200E "unable to alloc new skb, rx PDU length = %d\n", pdu_len); + DPRINTK(2, "unable to alloc new skb, rx PDU length = %d\n", pdu_len); + atomic_inc(&vcc->stats->rx_drop); - return; + return -ENOMEM; } skb->stamp = xtime; @@ -1161,13 +1224,14 @@ memcpy(skb_put(skb, rpd->rsd[ i ].length), buffer->data.align_addr, rpd->rsd[ i ].length); } - + DPRINTK(3, "rx skb: len = %d, truesize = %d\n", skb->len, skb->truesize); if (pdu_len < fore200e_vcc->rx_min_pdu) fore200e_vcc->rx_min_pdu = pdu_len; if (pdu_len > fore200e_vcc->rx_max_pdu) fore200e_vcc->rx_max_pdu = pdu_len; + fore200e_vcc->rx_pdu++; /* push PDU */ if (atm_charge(vcc, skb->truesize) == 0) { @@ -1175,37 +1239,63 @@ DPRINTK(2, "receive buffers saturated for %d.%d.%d - PDU dropped\n", vcc->itf, vcc->vpi, vcc->vci); - dev_kfree_skb_irq(skb); - return; + dev_kfree_skb_any(skb); + + atomic_inc(&vcc->stats->rx_drop); + return -ENOMEM; } + ASSERT(atomic_read(&vcc->sk->wmem_alloc) >= 0); + vcc->push(vcc, skb); atomic_inc(&vcc->stats->rx); + + ASSERT(atomic_read(&vcc->sk->wmem_alloc) >= 0); + + return 0; } static void fore200e_collect_rpd(struct fore200e* fore200e, struct rpd* rpd) { - struct buffer* buffer; - int i; + struct host_bsq* bsq; + struct buffer* buffer; + int i; for (i = 0; i < rpd->nseg; i++) { /* rebuild rx buffer address from rsd handle */ buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle); - /* decrease the number of supplied rx buffers */ - fore200e->host_bsq[ buffer->scheme ][ buffer->magn ].count--; + bsq = &fore200e->host_bsq[ buffer->scheme ][ buffer->magn ]; + +#ifdef FORE200E_BSQ_DEBUG + bsq_audit(2, bsq, buffer->scheme, buffer->magn); + + if (buffer->supplied == 0) + printk(FORE200E "queue %d.%d, buffer %ld was not supplied\n", + buffer->scheme, buffer->magn, buffer->index); + buffer->supplied = 0; +#endif + + /* re-insert the buffer into the free buffer list */ + buffer->next = bsq->freebuf; + bsq->freebuf = buffer; + + /* then increment the number of free rx buffers */ + bsq->freebuf_count++; } } static void -fore200e_irq_rx(struct fore200e* fore200e) +fore200e_rx_irq(struct fore200e* fore200e) { - struct host_rxq* rxq = &fore200e->host_rxq; - struct host_rxq_entry* entry; + struct host_rxq* rxq = &fore200e->host_rxq; + struct host_rxq_entry* entry; + struct atm_vcc* vcc; + struct fore200e_vc_map* vc_map; for (;;) { @@ -1215,28 +1305,61 @@ if ((*entry->status & STATUS_COMPLETE) == 0) break; - FORE200E_NEXT_ENTRY(rxq->head, QUEUE_SIZE_RX); + vc_map = FORE200E_VC_MAP(fore200e, entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci); - if ((*entry->status & STATUS_ERROR) == 0) { + if ((vc_map->vcc == NULL) || + (test_bit(ATM_VF_READY, &vc_map->vcc->flags) == 0)) { - fore200e_push_rpd(fore200e, entry->rpd); + DPRINTK(1, "no ready VC found for PDU received on %d.%d.%d\n", + fore200e->atm_dev->number, + entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci); } else { - printk(FORE200E "damaged PDU on %d.%d.%d\n", - fore200e->atm_dev->number, entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci); + vcc = vc_map->vcc; + ASSERT(vcc); + + if ((*entry->status & STATUS_ERROR) == 0) { + + fore200e_push_rpd(fore200e, vcc, entry->rpd); + } + else { + DPRINTK(2, "damaged PDU on %d.%d.%d\n", + fore200e->atm_dev->number, + entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci); + atomic_inc(&vcc->stats->rx_err); + } } - fore200e_collect_rpd(fore200e, entry->rpd); + FORE200E_NEXT_ENTRY(rxq->head, QUEUE_SIZE_RX); - fore200e_supply(fore200e); + fore200e_collect_rpd(fore200e, entry->rpd); /* rewrite the rpd address to ack the received PDU */ fore200e->bus->write(entry->rpd_dma, &entry->cp_entry->rpd_haddr); *entry->status = STATUS_FREE; + + fore200e_supply(fore200e); } } +#ifndef FORE200E_USE_TASKLET +static void +fore200e_irq(struct fore200e* fore200e) +{ + unsigned long flags; + + spin_lock_irqsave(&fore200e->q_lock, flags); + fore200e_rx_irq(fore200e); + spin_unlock_irqrestore(&fore200e->q_lock, flags); + + spin_lock_irqsave(&fore200e->q_lock, flags); + fore200e_tx_irq(fore200e); + spin_unlock_irqrestore(&fore200e->q_lock, flags); +} +#endif + + static void fore200e_interrupt(int irq, void* dev, struct pt_regs* regs) { @@ -1244,57 +1367,65 @@ if (fore200e->bus->irq_check(fore200e) == 0) { - DPRINTK(3, "unexpected interrupt on device %c\n", fore200e->name[9]); + DPRINTK(3, "interrupt NOT triggered by device %d\n", fore200e->atm_dev->number); return; } - DPRINTK(3, "valid interrupt on device %c\n", fore200e->name[9]); + DPRINTK(3, "interrupt triggered by device %d\n", fore200e->atm_dev->number); - tasklet_schedule(&fore200e->tasklet); +#ifdef FORE200E_USE_TASKLET + tasklet_schedule(&fore200e->tx_tasklet); + tasklet_schedule(&fore200e->rx_tasklet); +#else + fore200e_irq(fore200e); +#endif fore200e->bus->irq_ack(fore200e); } +#ifdef FORE200E_USE_TASKLET static void -fore200e_tasklet(unsigned long data) +fore200e_tx_tasklet(unsigned long data) { struct fore200e* fore200e = (struct fore200e*) data; + unsigned long flags; - fore200e_irq_rx(fore200e); - - if (fore200e->host_txq.txing) - fore200e_irq_tx(fore200e); + DPRINTK(3, "tx tasklet scheduled for device %d\n", fore200e->atm_dev->number); + + spin_lock_irqsave(&fore200e->q_lock, flags); + fore200e_tx_irq(fore200e); + spin_unlock_irqrestore(&fore200e->q_lock, flags); } +static void +fore200e_rx_tasklet(unsigned long data) +{ + struct fore200e* fore200e = (struct fore200e*) data; + unsigned long flags; + + DPRINTK(3, "rx tasklet scheduled for device %d\n", fore200e->atm_dev->number); + + spin_lock_irqsave(&fore200e->q_lock, flags); + fore200e_rx_irq((struct fore200e*) data); + spin_unlock_irqrestore(&fore200e->q_lock, flags); +} +#endif + static int fore200e_select_scheme(struct atm_vcc* vcc) { - int scheme; - -#if 1 - /* fairly balance VCs over (identical) buffer schemes */ - scheme = vcc->vci % 2 ? BUFFER_SCHEME_ONE : BUFFER_SCHEME_TWO; -#else - /* bit 7 of VPI magically selects the second buffer scheme */ - if (vcc->vpi & (1<<7)) { - vcc->vpi &= ((1<<7) - 1); /* reset the magic bit */ - scheme = BUFFER_SCHEME_TWO; - } - else { - scheme = BUFFER_SCHEME_ONE; - } -#endif + /* fairly balance the VCs over (identical) buffer schemes */ + int scheme = vcc->vci % 2 ? BUFFER_SCHEME_ONE : BUFFER_SCHEME_TWO; - DPRINTK(1, "vpvc %d.%d.%d uses the %s buffer scheme\n", - vcc->itf, vcc->vpi, vcc->vci, scheme == BUFFER_SCHEME_ONE ? "first" : "second"); + DPRINTK(1, "VC %d.%d.%d uses buffer scheme %d\n", + vcc->itf, vcc->vpi, vcc->vci, scheme); return scheme; } - static int fore200e_activate_vcin(struct fore200e* fore200e, int activate, struct atm_vcc* vcc, int mtu) { @@ -1331,7 +1462,7 @@ #ifdef FORE200E_52BYTE_AAL0_SDU mtu = 48; #endif - /* the MTU is unused by the cp, except in the case of AAL0 */ + /* the MTU is not used by the cp, except in the case of AAL0 */ fore200e->bus->write(mtu, &entry->cp_entry->cmd.activate_block.mtu); fore200e->bus->write(*(u32*)&vpvc, (u32*)&entry->cp_entry->cmd.activate_block.vpvc); fore200e->bus->write(*(u32*)&activ_opcode, (u32*)&entry->cp_entry->cmd.activate_block.opcode); @@ -1346,13 +1477,13 @@ *entry->status = STATUS_FREE; if (ok == 0) { - printk(FORE200E "unable to %s vpvc %d.%d on device %s\n", - activate ? "open" : "close", vcc->vpi, vcc->vci, fore200e->name); + printk(FORE200E "unable to %s VC %d.%d.%d\n", + activate ? "open" : "close", vcc->itf, vcc->vpi, vcc->vci); return -EIO; } - DPRINTK(1, "vpvc %d.%d %sed on device %s\n", vcc->vpi, vcc->vci, - activate ? "open" : "clos", fore200e->name); + DPRINTK(1, "VC %d.%d.%d %sed\n", vcc->itf, vcc->vpi, vcc->vci, + activate ? "open" : "clos"); return 0; } @@ -1410,7 +1541,7 @@ { if (qos->txtp.max_pcr < ATM_OC3_PCR) { - /* compute the data cells to idle cells ratio from the PCR */ + /* compute the data cells to idle cells ratio from the tx PCR */ rate->data_cells = qos->txtp.max_pcr * FORE200E_MAX_BACK2BACK_CELLS / ATM_OC3_PCR; rate->idle_cells = FORE200E_MAX_BACK2BACK_CELLS - rate->data_cells; } @@ -1424,21 +1555,38 @@ static int fore200e_open(struct atm_vcc *vcc, short vpi, int vci) { - struct fore200e* fore200e = FORE200E_DEV(vcc->dev); - struct fore200e_vcc* fore200e_vcc; - - /* find a free VPI/VCI */ + struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + struct fore200e_vcc* fore200e_vcc; + struct fore200e_vc_map* vc_map; + unsigned long flags; + fore200e_walk_vccs(vcc, &vpi, &vci); + + ASSERT((vpi >= 0) && (vpi < 1<= 0) && (vci < 1<vpi = vpi; - vcc->vci = vci; + spin_lock_irqsave(&fore200e->q_lock, flags); - /* ressource checking only? */ - if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) - return 0; + vc_map = FORE200E_VC_MAP(fore200e, vpi, vci); + if (vc_map->vcc) { - set_bit(ATM_VF_ADDR, &vcc->flags); - vcc->itf = vcc->dev->number; + spin_unlock_irqrestore(&fore200e->q_lock, flags); + + printk(FORE200E "VC %d.%d.%d already in use\n", + fore200e->atm_dev->number, vpi, vci); + + return -EINVAL; + } + + vc_map->vcc = vcc; + + spin_unlock_irqrestore(&fore200e->q_lock, flags); + + fore200e_vcc = fore200e_kmalloc(sizeof(struct fore200e_vcc), GFP_ATOMIC); + if (fore200e_vcc == NULL) { + vc_map->vcc = NULL; + return -ENOMEM; + } DPRINTK(2, "opening %d.%d.%d:%d QoS = (tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; " "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d)\n", @@ -1448,44 +1596,52 @@ fore200e_traffic_class[ vcc->qos.rxtp.traffic_class ], vcc->qos.rxtp.min_pcr, vcc->qos.rxtp.max_pcr, vcc->qos.rxtp.max_cdv, vcc->qos.rxtp.max_sdu); + /* pseudo-CBR bandwidth requested? */ if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { down(&fore200e->rate_sf); if (fore200e->available_cell_rate < vcc->qos.txtp.max_pcr) { up(&fore200e->rate_sf); + + fore200e_kfree(fore200e_vcc); + vc_map->vcc = NULL; return -EAGAIN; } - /* reserving the pseudo-CBR bandwidth at this point grants us - to reduce the length of the critical section protected - by 'rate_sf'. in counterpart, we have to reset the available - bandwidth if we later encounter an error */ + /* reserve bandwidth */ fore200e->available_cell_rate -= vcc->qos.txtp.max_pcr; up(&fore200e->rate_sf); } - - fore200e_vcc = fore200e_kmalloc(sizeof(struct fore200e_vcc), GFP_KERNEL); - if (fore200e_vcc == NULL) { - down(&fore200e->rate_sf); - fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; - up(&fore200e->rate_sf); - return -ENOMEM; - } + + vcc->itf = vcc->dev->number; + vcc->vpi = vpi; + vcc->vci = vci; + + set_bit(ATM_VF_PARTIAL,&vcc->flags); + set_bit(ATM_VF_ADDR, &vcc->flags); FORE200E_VCC(vcc) = fore200e_vcc; - + if (fore200e_activate_vcin(fore200e, 1, vcc, vcc->qos.rxtp.max_sdu) < 0) { - kfree(fore200e_vcc); - down(&fore200e->rate_sf); + + vc_map->vcc = NULL; + + clear_bit(ATM_VF_ADDR, &vcc->flags); + clear_bit(ATM_VF_PARTIAL,&vcc->flags); + + FORE200E_VCC(vcc) = NULL; + fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; - up(&fore200e->rate_sf); - return -EBUSY; + + fore200e_kfree(fore200e_vcc); + return -EINVAL; } /* compute rate control parameters */ if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { fore200e_rate_ctrl(&vcc->qos, &fore200e_vcc->rate); + set_bit(ATM_VF_HASQOS, &vcc->flags); DPRINTK(3, "tx on %d.%d.%d:%d, tx PCR = %d, rx PCR = %d, data_cells = %u, idle_cells = %u\n", vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), @@ -1493,57 +1649,99 @@ fore200e_vcc->rate.data_cells, fore200e_vcc->rate.idle_cells); } - fore200e_vcc->tx_min_pdu = fore200e_vcc->rx_min_pdu = 65536; + fore200e_vcc->tx_min_pdu = fore200e_vcc->rx_min_pdu = MAX_PDU_SIZE + 1; fore200e_vcc->tx_max_pdu = fore200e_vcc->rx_max_pdu = 0; - + fore200e_vcc->tx_pdu = fore200e_vcc->rx_pdu = 0; + + /* new incarnation of the vcc */ + vc_map->incarn = ++fore200e->incarn_count; + + /* VC unusable before this flag is set */ set_bit(ATM_VF_READY, &vcc->flags); + return 0; } - static void fore200e_close(struct atm_vcc* vcc) { - struct fore200e* fore200e = FORE200E_DEV(vcc->dev); - + struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + struct fore200e_vcc* fore200e_vcc; + struct fore200e_vc_map* vc_map; + unsigned long flags; + + ASSERT(vcc); + ASSERT((vcc->vpi >= 0) && (vcc->vpi < 1<vci >= 0) && (vcc->vci < 1<itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal)); - + + clear_bit(ATM_VF_READY, &vcc->flags); + fore200e_activate_vcin(fore200e, 0, vcc, 0); - - kfree(FORE200E_VCC(vcc)); - + + spin_lock_irqsave(&fore200e->q_lock, flags); + + vc_map = FORE200E_VC_MAP(fore200e, vcc->vpi, vcc->vci); + + /* the vc is no longer considered as "in use" by fore200e_open() */ + vc_map->vcc = NULL; + + vcc->itf = vcc->vci = vcc->vpi = 0; + + fore200e_vcc = FORE200E_VCC(vcc); + FORE200E_VCC(vcc) = NULL; + + spin_unlock_irqrestore(&fore200e->q_lock, flags); + + /* release reserved bandwidth, if any */ if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { + down(&fore200e->rate_sf); fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; up(&fore200e->rate_sf); - } - clear_bit(ATM_VF_READY, &vcc->flags); -} + clear_bit(ATM_VF_HASQOS, &vcc->flags); + } + clear_bit(ATM_VF_ADDR, &vcc->flags); + clear_bit(ATM_VF_PARTIAL,&vcc->flags); -#if 0 -#define FORE200E_SYNC_SEND /* wait tx completion before returning */ -#endif + ASSERT(fore200e_vcc); + fore200e_kfree(fore200e_vcc); +} static int fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) { - struct fore200e* fore200e = FORE200E_DEV(vcc->dev); - struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc); - struct host_txq* txq = &fore200e->host_txq; - struct host_txq_entry* entry; - struct tpd* tpd; - struct tpd_haddr tpd_haddr; - //unsigned long flags; - int retry = CONFIG_ATM_FORE200E_TX_RETRY; - int tx_copy = 0; - int tx_len = skb->len; - u32* cell_header = NULL; - unsigned char* skb_data; - int skb_len; + struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc); + struct fore200e_vc_map* vc_map; + struct host_txq* txq = &fore200e->host_txq; + struct host_txq_entry* entry; + struct tpd* tpd; + struct tpd_haddr tpd_haddr; + int retry = CONFIG_ATM_FORE200E_TX_RETRY; + int tx_copy = 0; + int tx_len = skb->len; + u32* cell_header = NULL; + unsigned char* skb_data; + int skb_len; + unsigned char* data; + unsigned long flags; + + ASSERT(vcc); + ASSERT(atomic_read(&vcc->sk->wmem_alloc) >= 0); + ASSERT(fore200e); + ASSERT(fore200e_vcc); + + if (!test_bit(ATM_VF_READY, &vcc->flags)) { + DPRINTK(1, "VC %d.%d.%d not ready for tx\n", vcc->itf, vcc->vpi, vcc->vpi); + dev_kfree_skb_any(skb); + return -EINVAL; + } #ifdef FORE200E_52BYTE_AAL0_SDU if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.txtp.max_sdu == ATM_AAL0_SDU)) { @@ -1551,7 +1749,7 @@ skb_data = skb->data + 4; /* skip 4-byte cell header */ skb_len = tx_len = skb->len - 4; - DPRINTK(3, "skipping user-supplied cell header 0x%08x", *cell_header); + DPRINTK(3, "user-supplied cell header = 0x%08x\n", *cell_header); } else #endif @@ -1560,39 +1758,6 @@ skb_len = skb->len; } - retry_here: - - tasklet_disable(&fore200e->tasklet); - - entry = &txq->host_entry[ txq->head ]; - - if (*entry->status != STATUS_FREE) { - - /* try to free completed tx queue entries */ - fore200e_irq_tx(fore200e); - - if (*entry->status != STATUS_FREE) { - - tasklet_enable(&fore200e->tasklet); - - /* retry once again? */ - if(--retry > 0) - goto retry_here; - - atomic_inc(&vcc->stats->tx_err); - - printk(FORE200E "tx queue of device %s is saturated, PDU dropped - heartbeat is %08x\n", - fore200e->name, fore200e->cp_queues->heartbeat); - if (vcc->pop) - vcc->pop(vcc, skb); - else - dev_kfree_skb(skb); - return -EIO; - } - } - - tpd = entry->tpd; - if (((unsigned long)skb_data) & 0x3) { DPRINTK(2, "misaligned tx PDU on device %s\n", fore200e->name); @@ -1602,43 +1767,87 @@ if ((vcc->qos.aal == ATM_AAL0) && (skb_len % ATM_CELL_PAYLOAD)) { - /* this simply NUKES the PCA-200E board */ + /* this simply NUKES the PCA board */ DPRINTK(2, "incomplete tx AAL0 PDU on device %s\n", fore200e->name); tx_copy = 1; tx_len = ((skb_len / ATM_CELL_PAYLOAD) + 1) * ATM_CELL_PAYLOAD; } if (tx_copy) { - - entry->data = kmalloc(tx_len, GFP_ATOMIC | GFP_DMA); - if (entry->data == NULL) { - - tasklet_enable(&fore200e->tasklet); - if (vcc->pop) + data = kmalloc(tx_len, GFP_ATOMIC | GFP_DMA); + if (data == NULL) { + if (vcc->pop) { vcc->pop(vcc, skb); - else - dev_kfree_skb(skb); + } + else { + dev_kfree_skb_any(skb); + } return -ENOMEM; } - memcpy(entry->data, skb_data, skb_len); + memcpy(data, skb_data, skb_len); if (skb_len < tx_len) - memset(entry->data + skb_len, 0x00, tx_len - skb_len); - - tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, entry->data, tx_len, FORE200E_DMA_TODEVICE); + memset(data + skb_len, 0x00, tx_len - skb_len); } else { - entry->data = NULL; - tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, skb_data, tx_len, FORE200E_DMA_TODEVICE); + data = skb_data; } + vc_map = FORE200E_VC_MAP(fore200e, vcc->vpi, vcc->vci); + ASSERT(vc_map->vcc == vcc); + + retry_here: + + spin_lock_irqsave(&fore200e->q_lock, flags); + + entry = &txq->host_entry[ txq->head ]; + + if ((*entry->status != STATUS_FREE) || (txq->txing >= QUEUE_SIZE_TX - 2)) { + + /* try to free completed tx queue entries */ + fore200e_tx_irq(fore200e); + + if (*entry->status != STATUS_FREE) { + + spin_unlock_irqrestore(&fore200e->q_lock, flags); + + /* retry once again? */ + if(--retry > 0) { + schedule(); + goto retry_here; + } + + atomic_inc(&vcc->stats->tx_err); + + fore200e->tx_sat++; + DPRINTK(2, "tx queue of device %s is saturated, PDU dropped - heartbeat is %08x\n", + fore200e->name, fore200e->cp_queues->heartbeat); + if (vcc->pop) { + vcc->pop(vcc, skb); + } + else { + dev_kfree_skb_any(skb); + } + + if (tx_copy) + kfree(data); + + return -ENOBUFS; + } + } + + entry->incarn = vc_map->incarn; + entry->vc_map = vc_map; + entry->skb = skb; + entry->data = tx_copy ? data : NULL; + + tpd = entry->tpd; + tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, data, tx_len, FORE200E_DMA_TODEVICE); tpd->tsd[ 0 ].length = tx_len; FORE200E_NEXT_ENTRY(txq->head, QUEUE_SIZE_TX); txq->txing++; - tasklet_enable(&fore200e->tasklet); - /* ensure DMA synchronisation */ fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length, FORE200E_DMA_TODEVICE); @@ -1650,9 +1859,7 @@ fore200e_vcc->tx_min_pdu = skb_len; if (skb_len > fore200e_vcc->tx_max_pdu) fore200e_vcc->tx_max_pdu = skb_len; - - entry->vcc = vcc; - entry->skb = skb; + fore200e_vcc->tx_pdu++; /* set tx rate control information */ tpd->rate.data_cells = fore200e_vcc->rate.data_cells; @@ -1677,49 +1884,16 @@ tpd->spec.length = tx_len; tpd->spec.nseg = 1; tpd->spec.aal = fore200e_atm2fore_aal(vcc->qos.aal); -#ifdef FORE200E_SYNC_SEND - tpd->spec.intr = 0; -#else tpd->spec.intr = 1; -#endif - tpd_haddr.size = sizeof(struct tpd) / 32; /* size is expressed in 32 byte blocks */ + tpd_haddr.size = sizeof(struct tpd) / (1<tpd_dma >> 5; /* shift the address, as we are in a bitfield */ + tpd_haddr.haddr = entry->tpd_dma >> TPD_HADDR_SHIFT; /* shift the address, as we are in a bitfield */ *entry->status = STATUS_PENDING; fore200e->bus->write(*(u32*)&tpd_haddr, (u32*)&entry->cp_entry->tpd_haddr); - -#ifdef FORE200E_SYNC_SEND - { - int ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 10); - - fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length, - FORE200E_DMA_TODEVICE); - - /* free tmp copy of misaligned data */ - if (entry->data) - kfree(entry->data); - - /* notify tx completion */ - if (vcc->pop) - vcc->pop(vcc, skb); - else - dev_kfree_skb(skb); - - if (ok == 0) { - printk(FORE200E "synchronous tx on %d:%d:%d failed\n", vcc->itf, vcc->vpi, vcc->vci); - - atomic_inc(&entry->vcc->stats->tx_err); - return -EIO; - } - atomic_inc(&entry->vcc->stats->tx); - - DPRINTK(3, "synchronous tx on %d:%d:%d succeeded\n", vcc->itf, vcc->vpi, vcc->vci); - - } -#endif + spin_unlock_irqrestore(&fore200e->q_lock, flags); return 0; } @@ -1740,7 +1914,8 @@ return -ENOMEM; } - stats_dma_addr = fore200e->bus->dma_map(fore200e, fore200e->stats, sizeof(struct stats), FORE200E_DMA_FROMDEVICE); + stats_dma_addr = fore200e->bus->dma_map(fore200e, fore200e->stats, + sizeof(struct stats), FORE200E_DMA_FROMDEVICE); FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); @@ -1769,9 +1944,9 @@ static int -fore200e_getsockopt (struct atm_vcc* vcc, int level, int optname, void* optval, int optlen) +fore200e_getsockopt(struct atm_vcc* vcc, int level, int optname, void* optval, int optlen) { - // struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + /* struct fore200e* fore200e = FORE200E_DEV(vcc->dev); */ DPRINTK(2, "getsockopt %d.%d.%d, level = %d, optname = 0x%x, optval = 0x%p, optlen = %d\n", vcc->itf, vcc->vpi, vcc->vci, level, optname, optval, optlen); @@ -1783,7 +1958,7 @@ static int fore200e_setsockopt(struct atm_vcc* vcc, int level, int optname, void* optval, int optlen) { - // struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + /* struct fore200e* fore200e = FORE200E_DEV(vcc->dev); */ DPRINTK(2, "setsockopt %d.%d.%d, level = %d, optname = 0x%x, optval = 0x%p, optlen = %d\n", vcc->itf, vcc->vpi, vcc->vci, level, optname, optval, optlen); @@ -1841,6 +2016,8 @@ struct oc3_opcode opcode; int ok; + DPRINTK(2, "set OC-3 reg = 0x%02x, value = 0x%02x, mask = 0x%02x\n", reg, value, mask); + FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); opcode.opcode = OPCODE_SET_OC3; @@ -1896,7 +2073,7 @@ } error = fore200e_set_oc3(fore200e, SUNI_MCT, mct_value, mct_mask); - if ( error == 0) + if (error == 0) fore200e->loop_mode = loop_mode; return error; @@ -1978,6 +2155,11 @@ struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc); struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + if (!test_bit(ATM_VF_READY, &vcc->flags)) { + DPRINTK(1, "VC %d.%d.%d not ready for QoS change\n", vcc->itf, vcc->vpi, vcc->vpi); + return -EINVAL; + } + DPRINTK(2, "change_qos %d.%d.%d, " "(tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; " "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d), flags = 0x%x\n" @@ -1999,6 +2181,7 @@ fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; fore200e->available_cell_rate -= qos->txtp.max_pcr; + up(&fore200e->rate_sf); memcpy(&vcc->qos, qos, sizeof(struct atm_qos)); @@ -2007,6 +2190,7 @@ fore200e_rate_ctrl(qos, &fore200e_vcc->rate); set_bit(ATM_VF_HASQOS, &vcc->flags); + return 0; } @@ -2027,7 +2211,10 @@ printk(FORE200E "IRQ %s reserved for device %s\n", fore200e_irq_itoa(fore200e->irq), fore200e->name); - tasklet_init(&fore200e->tasklet, fore200e_tasklet, (unsigned long)fore200e); +#ifdef FORE200E_USE_TASKLET + tasklet_init(&fore200e->tx_tasklet, fore200e_tx_tasklet, (unsigned long)fore200e); + tasklet_init(&fore200e->rx_tasklet, fore200e_rx_tasklet, (unsigned long)fore200e); +#endif fore200e->state = FORE200E_STATE_IRQ; return 0; @@ -2042,6 +2229,7 @@ if (!prom) return -ENOMEM; + ok = fore200e->bus->prom_read(fore200e, prom); if (ok < 0) { fore200e_kfree(prom); @@ -2089,10 +2277,16 @@ if (buffer == NULL) return -ENOMEM; + bsq->freebuf = NULL; + for (i = 0; i < nbr; i++) { buffer[ i ].scheme = scheme; buffer[ i ].magn = magn; +#ifdef FORE200E_BSQ_DEBUG + buffer[ i ].index = i; + buffer[ i ].supplied = 0; +#endif /* allocate the receive buffer body */ if (fore200e_chunk_alloc(fore200e, @@ -2105,9 +2299,17 @@ return -ENOMEM; } + + /* insert the buffer into the free buffer list */ + buffer[ i ].next = bsq->freebuf; + bsq->freebuf = &buffer[ i ]; } - /* set next free buffer index */ - bsq->free = 0; + /* all the buffers are free, initially */ + bsq->freebuf_count = nbr; + +#ifdef FORE200E_BSQ_DEBUG + bsq_audit(3, bsq, scheme, magn); +#endif } } @@ -2164,9 +2366,9 @@ FORE200E_INDEX(bsq->rbd_block.align_addr, struct rbd_block, i); bsq->host_entry[ i ].rbd_block_dma = FORE200E_DMA_INDEX(bsq->rbd_block.dma_addr, struct rbd_block, i); - bsq->host_entry[ i ].cp_entry = &cp_entry[ i ]; + bsq->host_entry[ i ].cp_entry = &cp_entry[ i ]; - *bsq->host_entry[ i ].status = STATUS_FREE; + *bsq->host_entry[ i ].status = STATUS_FREE; fore200e->bus->write(FORE200E_DMA_INDEX(bsq->status.dma_addr, enum status, i), &cp_entry[ i ].status_haddr); @@ -2293,10 +2495,11 @@ we do not write here the DMA (physical) base address of each tpd into the related cp resident entry, because the cp relies on this write operation to detect that a new pdu has been submitted for tx */ -} + } - /* set the head entry of the queue */ + /* set the head and tail entries of the queue */ txq->head = 0; + txq->tail = 0; fore200e->state = FORE200E_STATE_INIT_TXQ; return 0; @@ -2315,9 +2518,9 @@ /* allocate and align the array of status words */ if (fore200e->bus->dma_chunk_alloc(fore200e, &cmdq->status, - sizeof(enum status), - QUEUE_SIZE_CMD, - fore200e->bus->status_alignment) < 0) { + sizeof(enum status), + QUEUE_SIZE_CMD, + fore200e->bus->status_alignment) < 0) { return -ENOMEM; } @@ -2353,12 +2556,6 @@ { struct bs_spec* bs_spec = &fore200e->cp_queues->init.bs_spec[ scheme ][ magn ]; - /* dumb value; the firmware doesn't allow us to activate a VC while - selecting a buffer scheme with zero-sized rbd pools */ - - if (pool_size == 0) - pool_size = 64; - fore200e->bus->write(queue_length, &bs_spec->queue_length); fore200e->bus->write(fore200e_rx_buf_size[ scheme ][ magn ], &bs_spec->buffer_size); fore200e->bus->write(pool_size, &bs_spec->pool_size); @@ -2375,7 +2572,8 @@ DPRINTK(2, "device %s being initialized\n", fore200e->name); init_MUTEX(&fore200e->rate_sf); - + spin_lock_init(&fore200e->q_lock); + cpq = fore200e->cp_queues = (struct cp_queues*) (fore200e->virt_base + FORE200E_CP_QUEUES_OFFSET); /* enable cp to host interrupts */ @@ -2457,7 +2655,7 @@ static void __init fore200e_monitor_puts(struct fore200e* fore200e, char* str) { - while(*str) { + while (*str) { /* the i960 monitor doesn't accept any new character if it has something to say */ while (fore200e_monitor_getc(fore200e) >= 0); @@ -2478,6 +2676,11 @@ DPRINTK(2, "device %s firmware being started\n", fore200e->name); +#if defined(__sparc_v9__) + /* reported to be required by SBA cards on some sparc64 hosts */ + fore200e_spin(100); +#endif + sprintf(cmd, "\rgo %x\r", le32_to_cpu(fw_header->start_offset)); fore200e_monitor_puts(fore200e, cmd); @@ -2508,12 +2711,10 @@ DPRINTK(2, "device %s firmware being loaded at 0x%p (%d words)\n", fore200e->name, load_addr, fw_size); -#if 1 if (le32_to_cpu(fw_header->magic) != FW_HEADER_MAGIC) { printk(FORE200E "corrupted %s firmware image\n", fore200e->bus->model_name); return -ENODEV; } -#endif for (; fw_size--; fw_data++, load_addr++) fore200e->bus->write(le32_to_cpu(*fw_data), load_addr); @@ -2540,8 +2741,8 @@ FORE200E_DEV(atm_dev) = fore200e; fore200e->atm_dev = atm_dev; - atm_dev->ci_range.vpi_bits = 8; - atm_dev->ci_range.vci_bits = 10; + atm_dev->ci_range.vpi_bits = FORE200E_VPI_BITS; + atm_dev->ci_range.vci_bits = FORE200E_VCI_BITS; fore200e->available_cell_rate = ATM_OC3_PCR; @@ -2610,7 +2811,7 @@ struct fore200e* fore200e; int index, link; - printk(FORE200E "FORE Systems 200E-series driver - version " FORE200E_VERSION "\n"); + printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n"); /* for each configured bus interface */ for (link = 0, bus = fore200e_bus; bus->model_name; bus++) { @@ -2657,11 +2858,13 @@ static int -fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page) +fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page) { - struct sock *s; - struct fore200e* fore200e = FORE200E_DEV(dev); - int len, left = *pos; + struct fore200e* fore200e = FORE200E_DEV(dev); + struct fore200e_vcc* fore200e_vcc; + struct atm_vcc* vcc; + int i, len, left = *pos; + unsigned long flags; if (!left--) { @@ -2694,14 +2897,15 @@ if (!left--) return sprintf(page, - " supplied small bufs (1):\t%d\n" - " supplied large bufs (1):\t%d\n" - " supplied small bufs (2):\t%d\n" - " supplied large bufs (2):\t%d\n", - fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_SMALL ].count, - fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_LARGE ].count, - fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_SMALL ].count, - fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_LARGE ].count); + " free small bufs, scheme 1:\t%d\n" + " free large bufs, scheme 1:\t%d\n" + " free small bufs, scheme 2:\t%d\n" + " free large bufs, scheme 2:\t%d\n", + fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_SMALL ].freebuf_count, + fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_LARGE ].freebuf_count, + fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_SMALL ].freebuf_count, + fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_LARGE ].freebuf_count); + if (!left--) { u32 hb = fore200e->bus->read(&fore200e->cp_queues->heartbeat); @@ -2740,7 +2944,7 @@ u32 media_index = FORE200E_MEDIA_INDEX(fore200e->bus->read(&fore200e->cp_queues->media_type)); u32 oc3_index; - if (media_index < 0 || media_index > 4) + if ((media_index < 0) || (media_index > 4)) media_index = 5; switch (fore200e->loop_mode) { @@ -2887,49 +3091,60 @@ " large b1:\t\t\t%10u\n" " small b2:\t\t\t%10u\n" " large b2:\t\t\t%10u\n" - " RX PDUs:\t\t\t%10u\n", + " RX PDUs:\t\t\t%10u\n" + " TX PDUs:\t\t\t%10lu\n", fore200e_swap(fore200e->stats->aux.small_b1_failed), fore200e_swap(fore200e->stats->aux.large_b1_failed), fore200e_swap(fore200e->stats->aux.small_b2_failed), fore200e_swap(fore200e->stats->aux.large_b2_failed), - fore200e_swap(fore200e->stats->aux.rpd_alloc_failed)); - + fore200e_swap(fore200e->stats->aux.rpd_alloc_failed), + fore200e->tx_sat); + if (!left--) return sprintf(page,"\n" " receive carrier:\t\t\t%s\n", fore200e->stats->aux.receive_carrier ? "ON" : "OFF!"); if (!left--) { - struct atm_vcc *vcc; - struct fore200e_vcc* fore200e_vcc; - - len = sprintf(page,"\n" - " VCCs:\n address\tVPI.VCI:AAL\t(min/max tx PDU size) (min/max rx PDU size)\n"); - - read_lock(&vcc_sklist_lock); - for (s = vcc_sklist; s; s = s->next) { - vcc = s->protinfo.af_atm; + return sprintf(page,"\n" + " VCCs:\n address VPI VCI AAL " + "TX PDUs TX min/max size RX PDUs RX min/max size\n"); + } - if (vcc->dev != fore200e->atm_dev) - continue; + + for (i = 0; i < NBR_CONNECT; i++) { + + vcc = fore200e->vc_map[i].vcc; + + if (vcc == NULL) + continue; + + spin_lock_irqsave(&fore200e->q_lock, flags); + + if (vcc && test_bit(ATM_VF_READY, &vcc->flags) && !left--) { fore200e_vcc = FORE200E_VCC(vcc); - - len += sprintf(page + len, - " %x\t%d.%d:%d\t\t(%d/%d)\t(%d/%d)\n", + ASSERT(fore200e_vcc); + + len = sprintf(page, + " %08x %03d %05d %1d %09lu %05d/%05d %09lu %05d/%05d\n", (u32)(unsigned long)vcc, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), + fore200e_vcc->tx_pdu, fore200e_vcc->tx_min_pdu > 0xFFFF ? 0 : fore200e_vcc->tx_min_pdu, fore200e_vcc->tx_max_pdu, + fore200e_vcc->rx_pdu, fore200e_vcc->rx_min_pdu > 0xFFFF ? 0 : fore200e_vcc->rx_min_pdu, fore200e_vcc->rx_max_pdu ); + + spin_unlock_irqrestore(&fore200e->q_lock, flags); + return len; } - read_unlock(&vcc_sklist_lock); - return len; + spin_unlock_irqrestore(&fore200e->q_lock, flags); } - + return 0; } @@ -2966,7 +3181,7 @@ send: fore200e_send, change_qos: fore200e_change_qos, proc_read: fore200e_proc_read, - owner: THIS_MODULE, + owner: THIS_MODULE }; @@ -3027,4 +3242,6 @@ {} }; +#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); +#endif diff -urN linux-2.4.26/drivers/atm/fore200e.h linux-2.4.27/drivers/atm/fore200e.h --- linux-2.4.26/drivers/atm/fore200e.h 2000-12-11 13:22:12.000000000 -0800 +++ linux-2.4.27/drivers/atm/fore200e.h 2004-08-07 16:26:04.667347312 -0700 @@ -23,19 +23,21 @@ #define BUFFER_S2_SIZE SMALL_BUFFER_SIZE /* size of small buffers, scheme 2 */ #define BUFFER_L2_SIZE LARGE_BUFFER_SIZE /* size of large buffers, scheme 2 */ -#define BUFFER_S1_NBR (RBD_BLK_SIZE * 2) -#define BUFFER_L1_NBR (RBD_BLK_SIZE * 2) +#define BUFFER_S1_NBR (RBD_BLK_SIZE * 6) +#define BUFFER_L1_NBR (RBD_BLK_SIZE * 4) -#define BUFFER_S2_NBR (RBD_BLK_SIZE * 2) -#define BUFFER_L2_NBR (RBD_BLK_SIZE * 2) +#define BUFFER_S2_NBR (RBD_BLK_SIZE * 6) +#define BUFFER_L2_NBR (RBD_BLK_SIZE * 4) #define QUEUE_SIZE_CMD 16 /* command queue capacity */ #define QUEUE_SIZE_RX 64 /* receive queue capacity */ #define QUEUE_SIZE_TX 256 /* transmit queue capacity */ -#define QUEUE_SIZE_BS 16 /* buffer supply queue capacity */ +#define QUEUE_SIZE_BS 32 /* buffer supply queue capacity */ -#define NBR_CONNECT 1024 /* number of ATM connections */ +#define FORE200E_VPI_BITS 0 +#define FORE200E_VCI_BITS 10 +#define NBR_CONNECT (1 << (FORE200E_VPI_BITS + FORE200E_VCI_BITS)) /* number of connections */ #define TSD_FIXED 2 @@ -207,6 +209,7 @@ ) } tpd_haddr_t; +#define TPD_HADDR_SHIFT 5 /* addr aligned on 32 byte boundary */ /* cp resident transmit queue entry */ @@ -517,13 +520,15 @@ /* host resident transmit queue entry */ typedef struct host_txq_entry { - struct cp_txq_entry* cp_entry; /* addr of cp resident tx queue entry */ - enum status* status; /* addr of host resident status */ - struct tpd* tpd; /* addr of transmit PDU descriptor */ - u32 tpd_dma; /* DMA address of tpd */ - struct sk_buff* skb; /* related skb */ - struct atm_vcc* vcc; /* related vcc */ - void* data; /* copy of misaligned data */ + struct cp_txq_entry* cp_entry; /* addr of cp resident tx queue entry */ + enum status* status; /* addr of host resident status */ + struct tpd* tpd; /* addr of transmit PDU descriptor */ + u32 tpd_dma; /* DMA address of tpd */ + struct sk_buff* skb; /* related skb */ + void* data; /* copy of misaligned data */ + unsigned long incarn; /* vc_map incarnation when submitted for tx */ + struct fore200e_vc_map* vc_map; + } host_txq_entry_t; @@ -576,6 +581,10 @@ enum buffer_scheme scheme; /* buffer scheme */ enum buffer_magn magn; /* buffer magnitude */ struct chunk data; /* data buffer */ +#ifdef FORE200E_BSQ_DEBUG + unsigned long index; /* buffer # in queue */ + int supplied; /* 'buffer supplied' flag */ +#endif } buffer_t; @@ -602,6 +611,7 @@ typedef struct host_txq { struct host_txq_entry host_entry[ QUEUE_SIZE_TX ]; /* host resident tx queue entries */ int head; /* head of tx queue */ + int tail; /* tail of tx queue */ struct chunk tpd; /* array of tpds */ struct chunk status; /* arry of completion status */ int txing; /* number of pending PDUs in tx queue */ @@ -626,8 +636,8 @@ struct chunk rbd_block; /* array of rbds */ struct chunk status; /* array of completion status */ struct buffer* buffer; /* array of rx buffers */ - int free; /* index of first free rx buffer */ - volatile int count; /* count of supplied rx buffers */ + struct buffer* freebuf; /* list of free rx buffers */ + volatile int freebuf_count; /* count of free rx buffers */ } host_bsq_t; @@ -846,6 +856,17 @@ #endif +/* vc mapping */ + +typedef struct fore200e_vc_map { + struct atm_vcc* vcc; /* vcc entry */ + unsigned long incarn; /* vcc incarnation number */ +} fore200e_vc_map_t; + +#define FORE200E_VC_MAP(fore200e, vpi, vci) \ + (& (fore200e)->vc_map[ ((vpi) << FORE200E_VCI_BITS) | (vci) ]) + + /* per-device data */ typedef struct fore200e { @@ -879,20 +900,29 @@ struct stats* stats; /* last snapshot of the stats */ struct semaphore rate_sf; /* protects rate reservation ops */ - struct tasklet_struct tasklet; /* performs interrupt work */ + spinlock_t q_lock; /* protects queue ops */ +#ifdef FORE200E_USE_TASKLET + struct tasklet_struct tx_tasklet; /* performs tx interrupt work */ + struct tasklet_struct rx_tasklet; /* performs rx interrupt work */ +#endif + unsigned long tx_sat; /* tx queue saturation count */ + unsigned long incarn_count; + struct fore200e_vc_map vc_map[ NBR_CONNECT ]; /* vc mapping */ } fore200e_t; /* per-vcc data */ typedef struct fore200e_vcc { - enum buffer_scheme scheme; /* rx buffer scheme */ - struct tpd_rate rate; /* tx rate control data */ - int rx_min_pdu; /* size of smallest PDU received */ - int rx_max_pdu; /* size of largest PDU received */ - int tx_min_pdu; /* size of smallest PDU transmitted */ - int tx_max_pdu; /* size of largest PDU transmitted */ + enum buffer_scheme scheme; /* rx buffer scheme */ + struct tpd_rate rate; /* tx rate control data */ + int rx_min_pdu; /* size of smallest PDU received */ + int rx_max_pdu; /* size of largest PDU received */ + int tx_min_pdu; /* size of smallest PDU transmitted */ + int tx_max_pdu; /* size of largest PDU transmitted */ + unsigned long tx_pdu; /* nbr of tx pdus */ + unsigned long rx_pdu; /* nbr of rx pdus */ } fore200e_vcc_t; diff -urN linux-2.4.26/drivers/atm/nicstar.c linux-2.4.27/drivers/atm/nicstar.c --- linux-2.4.26/drivers/atm/nicstar.c 2004-04-14 06:05:29.000000000 -0700 +++ linux-2.4.27/drivers/atm/nicstar.c 2004-08-07 16:26:04.670347435 -0700 @@ -760,7 +760,7 @@ for (j = 0; j < NUM_HB; j++) { struct sk_buff *hb; - hb = alloc_skb(NS_HBUFSIZE, GFP_KERNEL); + hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL); if (hb == NULL) { printk("nicstar%d: can't allocate %dth of %d huge buffers.\n", @@ -780,7 +780,7 @@ for (j = 0; j < NUM_LB; j++) { struct sk_buff *lb; - lb = alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); + lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); if (lb == NULL) { printk("nicstar%d: can't allocate %dth of %d large buffers.\n", @@ -816,7 +816,7 @@ for (j = 0; j < NUM_SB; j++) { struct sk_buff *sb; - sb = alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); + sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); if (sb == NULL) { printk("nicstar%d: can't allocate %dth of %d small buffers.\n", @@ -1318,7 +1318,7 @@ card->index); for (i = 0; i < card->sbnr.min; i++) { - sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC); + sb = dev_alloc_skb(NS_SMSKBSIZE); if (sb == NULL) { writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG); @@ -1344,7 +1344,7 @@ card->index); for (i = 0; i < card->lbnr.min; i++) { - lb = alloc_skb(NS_LGSKBSIZE, GFP_ATOMIC); + lb = dev_alloc_skb(NS_LGSKBSIZE); if (lb == NULL) { writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG); @@ -2167,7 +2167,7 @@ cell = skb->data; for (i = ns_rsqe_cellcount(rsqe); i; i--) { - if ((sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC)) == NULL) + if ((sb = dev_alloc_skb(NS_SMSKBSIZE)) == NULL) { printk("nicstar%d: Can't allocate buffers for aal0.\n", card->index); @@ -2399,7 +2399,7 @@ if (hb == NULL) /* No buffers in the queue */ { - hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC); + hb = dev_alloc_skb(NS_HBUFSIZE); if (hb == NULL) { printk("nicstar%d: Out of huge buffers.\n", card->index); @@ -2413,7 +2413,7 @@ else if (card->hbpool.count < card->hbnr.min) { struct sk_buff *new_hb; - if ((new_hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC)) != NULL) + if ((new_hb = dev_alloc_skb(NS_HBUFSIZE)) != NULL) { skb_queue_tail(&card->hbpool.queue, new_hb); card->hbpool.count++; @@ -2424,14 +2424,14 @@ if (--card->hbpool.count < card->hbnr.min) { struct sk_buff *new_hb; - if ((new_hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC)) != NULL) + if ((new_hb = dev_alloc_skb(NS_HBUFSIZE)) != NULL) { skb_queue_tail(&card->hbpool.queue, new_hb); card->hbpool.count++; } if (card->hbpool.count < card->hbnr.min) { - if ((new_hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC)) != NULL) + if ((new_hb = dev_alloc_skb(NS_HBUFSIZE)) != NULL) { skb_queue_tail(&card->hbpool.queue, new_hb); card->hbpool.count++; @@ -2513,7 +2513,7 @@ do { - sb = alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); + sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); if (sb == NULL) break; skb_queue_tail(&card->sbpool.queue, sb); @@ -2536,7 +2536,7 @@ do { - lb = alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); + lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); if (lb == NULL) break; skb_queue_tail(&card->lbpool.queue, lb); @@ -2555,7 +2555,7 @@ while (card->hbpool.count < card->hbnr.init) { - hb = alloc_skb(NS_HBUFSIZE, GFP_KERNEL); + hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL); if (hb == NULL) break; skb_queue_tail(&card->hbpool.queue, hb); @@ -2627,7 +2627,7 @@ if (card->sbfqc < card->sbnr.init) { struct sk_buff *new_sb; - if ((new_sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC)) != NULL) + if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL) { skb_queue_tail(&card->sbpool.queue, new_sb); skb_reserve(new_sb, NS_AAL0_HEADER); @@ -2639,7 +2639,7 @@ #endif /* NS_USE_DESTRUCTORS */ { struct sk_buff *new_sb; - if ((new_sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC)) != NULL) + if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL) { skb_queue_tail(&card->sbpool.queue, new_sb); skb_reserve(new_sb, NS_AAL0_HEADER); @@ -2660,7 +2660,7 @@ if (card->lbfqc < card->lbnr.init) { struct sk_buff *new_lb; - if ((new_lb = alloc_skb(NS_LGSKBSIZE, GFP_ATOMIC)) != NULL) + if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL) { skb_queue_tail(&card->lbpool.queue, new_lb); skb_reserve(new_lb, NS_SMBUFSIZE); @@ -2672,7 +2672,7 @@ #endif /* NS_USE_DESTRUCTORS */ { struct sk_buff *new_lb; - if ((new_lb = alloc_skb(NS_LGSKBSIZE, GFP_ATOMIC)) != NULL) + if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL) { skb_queue_tail(&card->lbpool.queue, new_lb); skb_reserve(new_lb, NS_SMBUFSIZE); @@ -2866,7 +2866,7 @@ { struct sk_buff *sb; - sb = alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); + sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); if (sb == NULL) return -ENOMEM; skb_queue_tail(&card->sbpool.queue, sb); @@ -2880,7 +2880,7 @@ { struct sk_buff *lb; - lb = alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); + lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); if (lb == NULL) return -ENOMEM; skb_queue_tail(&card->lbpool.queue, lb); @@ -2909,7 +2909,7 @@ { struct sk_buff *hb; - hb = alloc_skb(NS_HBUFSIZE, GFP_KERNEL); + hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL); if (hb == NULL) return -ENOMEM; ns_grab_int_lock(card, flags); diff -urN linux-2.4.26/drivers/block/Config.in linux-2.4.27/drivers/block/Config.in --- linux-2.4.26/drivers/block/Config.in 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.27/drivers/block/Config.in 2004-08-07 16:26:04.671347476 -0700 @@ -39,6 +39,7 @@ dep_mbool ' Enable monitor thread' CONFIG_CISS_MONITOR_THREAD $CONFIG_BLK_CPQ_CISS_DA dep_tristate 'Mylex DAC960/DAC1100 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960 $CONFIG_PCI dep_tristate 'Micro Memory MM5415 Battery Backed RAM support (EXPERIMENTAL)' CONFIG_BLK_DEV_UMEM $CONFIG_PCI $CONFIG_EXPERIMENTAL +dep_tristate 'Promise SATA SX8 support' CONFIG_BLK_DEV_SX8 $CONFIG_PCI tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET diff -urN linux-2.4.26/drivers/block/Makefile linux-2.4.27/drivers/block/Makefile --- linux-2.4.26/drivers/block/Makefile 2003-06-13 07:51:32.000000000 -0700 +++ linux-2.4.27/drivers/block/Makefile 2004-08-07 16:26:04.671347476 -0700 @@ -31,6 +31,7 @@ obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o obj-$(CONFIG_BLK_DEV_UMEM) += umem.o obj-$(CONFIG_BLK_DEV_NBD) += nbd.o +obj-$(CONFIG_BLK_DEV_SX8) += sx8.o subdir-$(CONFIG_PARIDE) += paride diff -urN linux-2.4.26/drivers/block/acsi_slm.c linux-2.4.27/drivers/block/acsi_slm.c --- linux-2.4.26/drivers/block/acsi_slm.c 2002-11-28 15:53:12.000000000 -0800 +++ linux-2.4.27/drivers/block/acsi_slm.c 2004-08-07 16:26:04.672347517 -0700 @@ -367,6 +367,7 @@ { struct inode *node = file->f_dentry->d_inode; + loff_t pos = *ppos; unsigned long page; int length; int end; @@ -381,18 +382,18 @@ count = length; goto out; } - if (file->f_pos >= length) { + if (pos != (unsigned) pos || pos >= length) { count = 0; goto out; } - if (count + file->f_pos > length) - count = length - file->f_pos; - end = count + file->f_pos; - if (copy_to_user(buf, (char *)page + file->f_pos, count)) { + if (count > length - pos) + count = length - pos; + end = count + pos; + if (copy_to_user(buf, (char *)page + pos, count)) { count = -EFAULT; goto out; } - file->f_pos = end; + *ppos = end; out: free_page( page ); return( count ); } diff -urN linux-2.4.26/drivers/block/cciss.c linux-2.4.27/drivers/block/cciss.c --- linux-2.4.26/drivers/block/cciss.c 2004-04-14 06:05:29.000000000 -0700 +++ linux-2.4.27/drivers/block/cciss.c 2004-08-07 16:26:04.675347640 -0700 @@ -45,13 +45,13 @@ #include #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) -#define DRIVER_NAME "HP CISS Driver (v 2.4.50)" -#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,50) +#define DRIVER_NAME "HP CISS Driver (v 2.4.52)" +#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,52) /* Embedded module documentation macros - see modules.h */ MODULE_AUTHOR("Hewlett-Packard Company"); -MODULE_DESCRIPTION("Driver for HP SA5xxx SA6xxx Controllers version 2.4.50"); -MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400 6i"); +MODULE_DESCRIPTION("Driver for HP SA5xxx SA6xxx Controllers version 2.4.52"); +MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400 6i SA6422 V100"); MODULE_LICENSE("GPL"); #include "cciss_cmd.h" @@ -78,6 +78,10 @@ 0x0E11, 0x409D, 0, 0, 0}, { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 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, + 0x103C, 0x3211, 0, 0, 0}, {0,} }; MODULE_DEVICE_TABLE(pci, cciss_pci_device_id); @@ -98,6 +102,8 @@ { 0x409C0E11, "Smart Array 6400", &SA5_access}, { 0x409D0E11, "Smart Array 6400 EM", &SA5_access}, { 0x40910E11, "Smart Array 6i", &SA5_access}, + { 0x409E0E11, "Smart Array 6422", &SA5_access}, + { 0x3211103C, "Smart Array V100", &SA5_access}, }; /* How long to wait (in millesconds) for board to go into simple mode */ @@ -487,6 +493,142 @@ return 0; } +#ifdef __x86_64__ +/* for AMD 64 bit kernel compatibility with 32-bit userland ioctls */ +extern int sys_ioctl(unsigned int fd, unsigned cmd, unsigned long arg); + +extern int +register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, + unsigned int, unsigned long, struct file *)); +extern int unregister_ioctl32_conversion(unsigned int cmd); + +static int cciss_ioctl32_passthru(unsigned int fd, unsigned cmd, unsigned long arg, struct file *file); +static int cciss_ioctl32_big_passthru(unsigned int fd, unsigned cmd, unsigned long arg, + struct file *file); + +typedef long (*handler type) (unsigned int, unsigned int, unsigned long, + struct file *); + +static struct ioctl32_map { + unsigned int cmd; + handler_type handler; + int registered; +} cciss_ioctl32_map[] = { + { CCISS_GETPCIINFO, (handler_type) sys_ioctl, 0 }, + { CCISS_GETINTINFO, (handler_type) sys_ioctl, 0 }, + { CCISS_SETINTINFO, (handler_type) sys_ioctl, 0 }, + { CCISS_GETNODENAME, (handler_type) sys_ioctl, 0 }, + { CCISS_SETNODENAME, (handler_type) sys_ioctl, 0 }, + { CCISS_GETHEARTBEAT, (handler_type) sys_ioctl, 0 }, + { CCISS_GETBUSTYPES, (handler_type) sys_ioctl, 0 }, + { CCISS_GETFIRMVER, (handler_type) sys_ioctl, 0 }, + { CCISS_GETDRIVVER, (handler_type) sys_ioctl, 0 }, + { CCISS_REVALIDVOLS, (handler_type) sys_ioctl, 0 }, + { CCISS_PASSTHRU32, cciss_ioctl32_passthru, 0 }, + { CCISS_DEREGDISK, (handler_type) sys_ioctl, 0 }, + { CCISS_REGNEWDISK, (handler_type) sys_ioctl, 0 }, + { CCISS_REGNEWD, (handler_type) sys_ioctl, 0 }, + { CCISS_RESCANDISK, (handler_type) sys_ioctl, 0 }, + { CCISS_GETLUNINFO, (handler_type) sys_ioctl, 0 }, + { CCISS_BIG_PASSTHRU32, cciss_ioctl32_big_passthru, 0 }, +}; +#define NCCISS_IOCTL32_ENTRIES (sizeof(cciss_ioctl32_map) / sizeof(cciss_ioctl32_map[0])) +static void register_cciss_ioctl32(void) +{ + int i, rc; + + for (i=0; i < NCCISS_IOCTL32_ENTRIES; i++) { + rc = register_ioctl32_conversion( + cciss_ioctl32_map[i].cmd, + cciss_ioctl32_map[i].handler); + if (rc != 0) { + printk(KERN_WARNING "cciss: failed to register " + "32 bit compatible ioctl 0x%08x\n", + cciss_ioctl32_map[i].cmd); + cciss_ioctl32_map[i].registered = 0; + } else + cciss_ioctl32_map[i].registered = 1; + } +} +static void unregister_cciss_ioctl32(void) +{ + int i, rc; + + for (i=0; i < NCCISS_IOCTL32_ENTRIES; i++) { + if (!cciss_ioctl32_map[i].registered) + continue; + rc = unregister_ioctl32_conversion( + cciss_ioctl32_map[i].cmd); + if (rc == 0) { + cciss_ioctl32_map[i].registered = 0; + continue; + } + printk(KERN_WARNING "cciss: failed to unregister " + "32 bit compatible ioctl 0x%08x\n", + cciss_ioctl32_map[i].cmd); + } +} +int cciss_ioctl32_passthru(unsigned int fd, unsigned cmd, unsigned long arg, + struct file *file) +{ + IOCTL32_Command_struct *arg32 = + (IOCTL32_Command_struct *) arg; + IOCTL_Command_struct arg64; + mm_segment_t old_fs; + int err; + + err = 0; + err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, sizeof(arg64.LUN_info)); + err |= copy_from_user(&arg64.Request, &arg32->Request, sizeof(arg64.Request)); + err |= copy_from_user(&arg64.error_info, &arg32->error_info, sizeof(arg64.error_info)); + err |= get_user(arg64.buf_size, &arg32->buf_size); + err |= get_user(arg64.buf, &arg32->buf); + if (err) + return -EFAULT; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_ioctl(fd, CCISS_PASSTHRU, (unsigned long) &arg64); + set_fs(old_fs); + if (err) + return err; + err |= copy_to_user(&arg32->error_info, &arg64.error_info, sizeof(&arg32->error_info)); + if (err) + return -EFAULT; + return err; +} +int cciss_ioctl32_big_passthru(unsigned int fd, unsigned cmd, unsigned long arg, + struct file *file) +{ + BIG_IOCTL32_Command_struct *arg32 = + (BIG_IOCTL32_Command_struct *) arg; + BIG_IOCTL_Command_struct arg64; + mm_segment_t old_fs; + int err; + + err = 0; + err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, sizeof(arg64.LUN_info)); + err |= copy_from_user(&arg64.Request, &arg32->Request, sizeof(arg64.Request)); + err |= copy_from_user(&arg64.error_info, &arg32->error_info, sizeof(arg64.error_info)); + err |= get_user(arg64.buf_size, &arg32->buf_size); + err |= get_user(arg64.malloc_size, &arg32->malloc_size); + err |= get_user(arg64.buf, &arg32->buf); + if (err) return -EFAULT; + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_ioctl(fd, CCISS_BIG_PASSTHRU, (unsigned long) &arg64); + set_fs(old_fs); + if (err) + return err; + err |= copy_to_user(&arg32->error_info, &arg64.error_info, sizeof(&arg32->error_info)); + if (err) + return -EFAULT; + return err; +} +#else +static inline void register_cciss_ioctl32(void) {} +static inline void unregister_cciss_ioctl32(void) {} +#endif /* * ioctl */ @@ -3317,7 +3459,7 @@ EXPORT_NO_SYMBOLS; static int __init init_cciss_module(void) { - + register_cciss_ioctl32(); return cciss_init(); } @@ -3325,6 +3467,7 @@ { int i; + unregister_cciss_ioctl32(); pci_unregister_driver(&cciss_pci_driver); /* double check that all controller entrys have been removed */ for (i=0; i< MAX_CTLR; i++) { diff -urN linux-2.4.26/drivers/block/cciss_scsi.c linux-2.4.27/drivers/block/cciss_scsi.c --- linux-2.4.26/drivers/block/cciss_scsi.c 2004-04-14 06:05:29.000000000 -0700 +++ linux-2.4.27/drivers/block/cciss_scsi.c 2004-08-07 16:26:04.676347681 -0700 @@ -1569,7 +1569,7 @@ cciss_proc_tape_report(int ctlr, unsigned char *buffer, off_t *pos, off_t *len) { int size; - unsigned int flags; + unsigned long flags; *pos = *pos -1; *len = *len - 1; // cut off the last trailing newline diff -urN linux-2.4.26/drivers/block/rd.c linux-2.4.27/drivers/block/rd.c --- linux-2.4.26/drivers/block/rd.c 2002-11-28 15:53:12.000000000 -0800 +++ linux-2.4.27/drivers/block/rd.c 2004-08-07 16:26:04.677347723 -0700 @@ -320,14 +320,19 @@ static ssize_t initrd_read(struct file *file, char *buf, size_t count, loff_t *ppos) { - int left; + loff_t n = *ppos; + unsigned pos = n; + unsigned left = initrd_end - initrd_start; - left = initrd_end - initrd_start - *ppos; + if (pos != n || pos >= left) + return 0; + + left -= pos; if (count > left) count = left; if (count == 0) return 0; - if (copy_to_user(buf, (char *)initrd_start + *ppos, count)) + if (copy_to_user(buf, (char *)initrd_start + pos, count)) return -EFAULT; - *ppos += count; + *ppos = pos + count; return count; } diff -urN linux-2.4.26/drivers/block/sx8.c linux-2.4.27/drivers/block/sx8.c --- linux-2.4.26/drivers/block/sx8.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.27/drivers/block/sx8.c 2004-08-07 16:26:04.680347846 -0700 @@ -0,0 +1,2083 @@ +/* + * carmel.c: Driver for Promise SATA SX8 looks-like-I2O hardware + * + * Copyright 2004 Red Hat, Inc. + * + * Author/maintainer: Jeff Garzik + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Jeff Garzik"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Promise SATA SX8 (carmel) block driver"); + +#if 0 +#define CARM_DEBUG +#define CARM_VERBOSE_DEBUG +#else +#undef CARM_DEBUG +#undef CARM_VERBOSE_DEBUG +#endif +#undef CARM_NDEBUG + +#define DRV_NAME "carmel" +#define DRV_VERSION "0.8-24.1" +#define PFX DRV_NAME ": " + +#define NEXT_RESP(idx) ((idx + 1) % RMSG_Q_LEN) + +/* 0xf is just arbitrary, non-zero noise; this is sorta like poisoning */ +#define TAG_ENCODE(tag) (((tag) << 16) | 0xf) +#define TAG_DECODE(tag) (((tag) >> 16) & 0x1f) +#define TAG_VALID(tag) ((((tag) & 0xf) == 0xf) && (TAG_DECODE(tag) < 32)) + +/* note: prints function name for you */ +#ifdef CARM_DEBUG +#define DPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args) +#ifdef CARM_VERBOSE_DEBUG +#define VPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args) +#else +#define VPRINTK(fmt, args...) +#endif /* CARM_VERBOSE_DEBUG */ +#else +#define DPRINTK(fmt, args...) +#define VPRINTK(fmt, args...) +#endif /* CARM_DEBUG */ + +#ifdef CARM_NDEBUG +#define assert(expr) +#else +#define assert(expr) \ + if(unlikely(!(expr))) { \ + printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \ + #expr,__FILE__,__FUNCTION__,__LINE__); \ + } +#endif + +/* defines only for the constants which don't work well as enums */ +struct carm_host; + +enum { + /* adapter-wide limits */ + CARM_MAX_PORTS = 8, + CARM_SHM_SIZE = (4096 << 7), + CARM_PART_SHIFT = 5, + CARM_MINORS_PER_MAJOR = (1 << CARM_PART_SHIFT), + CARM_MAX_WAIT_Q = CARM_MAX_PORTS + 1, + + /* command message queue limits */ + CARM_MAX_REQ = 64, /* max command msgs per host */ + CARM_MAX_Q = 1, /* one command at a time */ + CARM_MSG_LOW_WATER = (CARM_MAX_REQ / 4), /* refill mark */ + + /* S/G limits, host-wide and per-request */ + CARM_MAX_REQ_SG = 32, /* max s/g entries per request */ + CARM_SG_BOUNDARY = 0xffffUL, /* s/g segment boundary */ + CARM_MAX_HOST_SG = 600, /* max s/g entries per host */ + CARM_SG_LOW_WATER = (CARM_MAX_HOST_SG / 4), /* re-fill mark */ + + /* hardware registers */ + CARM_IHQP = 0x1c, + CARM_INT_STAT = 0x10, /* interrupt status */ + CARM_INT_MASK = 0x14, /* interrupt mask */ + CARM_HMUC = 0x18, /* host message unit control */ + RBUF_ADDR_LO = 0x20, /* response msg DMA buf low 32 bits */ + RBUF_ADDR_HI = 0x24, /* response msg DMA buf high 32 bits */ + RBUF_BYTE_SZ = 0x28, + CARM_RESP_IDX = 0x2c, + CARM_CMS0 = 0x30, /* command message size reg 0 */ + CARM_LMUC = 0x48, + CARM_HMPHA = 0x6c, + CARM_INITC = 0xb5, + + /* bits in CARM_INT_{STAT,MASK} */ + INT_RESERVED = 0xfffffff0, + INT_WATCHDOG = (1 << 3), /* watchdog timer */ + INT_Q_OVERFLOW = (1 << 2), /* cmd msg q overflow */ + INT_Q_AVAILABLE = (1 << 1), /* cmd msg q has free space */ + INT_RESPONSE = (1 << 0), /* response msg available */ + INT_ACK_MASK = INT_WATCHDOG | INT_Q_OVERFLOW, + INT_DEF_MASK = INT_RESERVED | INT_Q_OVERFLOW | + INT_RESPONSE, + + /* command messages, and related register bits */ + CARM_HAVE_RESP = 0x01, + CARM_MSG_READ = 1, + CARM_MSG_WRITE = 2, + CARM_MSG_VERIFY = 3, + CARM_MSG_GET_CAPACITY = 4, + CARM_MSG_FLUSH = 5, + CARM_MSG_IOCTL = 6, + CARM_MSG_ARRAY = 8, + CARM_MSG_MISC = 9, + CARM_CME = (1 << 2), + CARM_RME = (1 << 1), + CARM_WZBC = (1 << 0), + CARM_RMI = (1 << 0), + CARM_Q_FULL = (1 << 3), + CARM_MSG_SIZE = 288, + CARM_Q_LEN = 48, + + /* CARM_MSG_IOCTL messages */ + CARM_IOC_SCAN_CHAN = 5, /* scan channels for devices */ + CARM_IOC_GET_TCQ = 13, /* get tcq/ncq depth */ + CARM_IOC_SET_TCQ = 14, /* set tcq/ncq depth */ + + IOC_SCAN_CHAN_NODEV = 0x1f, + IOC_SCAN_CHAN_OFFSET = 0x40, + + /* CARM_MSG_ARRAY messages */ + CARM_ARRAY_INFO = 0, + + ARRAY_NO_EXIST = (1 << 31), + + /* response messages */ + RMSG_SZ = 8, /* sizeof(struct carm_response) */ + RMSG_Q_LEN = 48, /* resp. msg list length */ + RMSG_OK = 1, /* bit indicating msg was successful */ + /* length of entire resp. msg buffer */ + RBUF_LEN = RMSG_SZ * RMSG_Q_LEN, + + PDC_SHM_SIZE = (4096 << 7), /* length of entire h/w buffer */ + + /* CARM_MSG_MISC messages */ + MISC_GET_FW_VER = 2, + MISC_ALLOC_MEM = 3, + MISC_SET_TIME = 5, + + /* MISC_GET_FW_VER feature bits */ + FW_VER_4PORT = (1 << 2), /* 1=4 ports, 0=8 ports */ + FW_VER_NON_RAID = (1 << 1), /* 1=non-RAID firmware, 0=RAID */ + FW_VER_ZCR = (1 << 0), /* zero channel RAID (whatever that is) */ + + /* carm_host flags */ + FL_NON_RAID = FW_VER_NON_RAID, + FL_4PORT = FW_VER_4PORT, + FL_FW_VER_MASK = (FW_VER_NON_RAID | FW_VER_4PORT), + FL_DAC = (1 << 16), + FL_DYN_MAJOR = (1 << 17), +}; + +enum carm_magic_numbers { + CARM_MAGIC_HOST = 0xdeadbeefUL, + CARM_MAGIC_PORT = 0xbedac0edUL, +}; + +enum scatter_gather_types { + SGT_32BIT = 0, + SGT_64BIT = 1, +}; + +enum host_states { + HST_INVALID, /* invalid state; never used */ + HST_ALLOC_BUF, /* setting up master SHM area */ + HST_ERROR, /* we never leave here */ + HST_PORT_SCAN, /* start dev scan */ + HST_DEV_SCAN_START, /* start per-device probe */ + HST_DEV_SCAN, /* continue per-device probe */ + HST_DEV_ACTIVATE, /* activate devices we found */ + HST_PROBE_FINISHED, /* probe is complete */ + HST_PROBE_START, /* initiate probe */ + HST_SYNC_TIME, /* tell firmware what time it is */ + HST_GET_FW_VER, /* get firmware version, adapter port cnt */ +}; + +#ifdef CARM_DEBUG +static const char *state_name[] = { + "HST_INVALID", + "HST_ALLOC_BUF", + "HST_ERROR", + "HST_PORT_SCAN", + "HST_DEV_SCAN_START", + "HST_DEV_SCAN", + "HST_DEV_ACTIVATE", + "HST_PROBE_FINISHED", + "HST_PROBE_START", + "HST_SYNC_TIME", + "HST_GET_FW_VER", +}; +#endif + +struct carm_port { + unsigned long magic; + unsigned int port_no; + unsigned int n_queued; + struct carm_host *host; + struct tasklet_struct tasklet; + request_queue_t q; + + /* attached device characteristics */ + u64 capacity; + char name[41]; + u16 dev_geom_head; + u16 dev_geom_sect; + u16 dev_geom_cyl; +}; + +struct carm_request { + unsigned int tag; + int n_elem; + unsigned int msg_type; + unsigned int msg_subtype; + unsigned int msg_bucket; + struct request *rq; + struct carm_port *port; + struct request special_rq; + struct scatterlist sg[CARM_MAX_REQ_SG]; +}; + +struct carm_host { + unsigned long magic; + unsigned long flags; + void *mmio; + void *shm; + dma_addr_t shm_dma; + + int major; + int id; + char name[32]; + + struct pci_dev *pdev; + unsigned int state; + u32 fw_ver; + + request_queue_t oob_q; + unsigned int n_oob; + struct tasklet_struct oob_tasklet; + + unsigned int hw_sg_used; + + unsigned int resp_idx; + + unsigned int wait_q_prod; + unsigned int wait_q_cons; + request_queue_t *wait_q[CARM_MAX_WAIT_Q]; + + unsigned int n_msgs; + u64 msg_alloc; + struct carm_request req[CARM_MAX_REQ]; + void *msg_base; + dma_addr_t msg_dma; + + int cur_scan_dev; + unsigned long dev_active; + unsigned long dev_present; + struct carm_port port[CARM_MAX_PORTS]; + + struct tq_struct fsm_task; + + struct semaphore probe_sem; + + struct gendisk gendisk; + struct hd_struct gendisk_hd[256]; + int blk_sizes[256]; + int blk_block_sizes[256]; + int blk_sect_sizes[256]; + + struct list_head host_list_node; +}; + +struct carm_response { + u32 ret_handle; + u32 status; +} __attribute__((packed)); + +struct carm_msg_sg { + u32 start; + u32 len; +} __attribute__((packed)); + +struct carm_msg_rw { + u8 type; + u8 id; + u8 sg_count; + u8 sg_type; + u32 handle; + u32 lba; + u16 lba_count; + u16 lba_high; + struct carm_msg_sg sg[32]; +} __attribute__((packed)); + +struct carm_msg_allocbuf { + u8 type; + 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; + struct carm_msg_sg sg[8]; +} __attribute__((packed)); + +struct carm_msg_ioctl { + u8 type; + u8 subtype; + u8 array_id; + u8 reserved1; + u32 handle; + u32 data_addr; + u32 reserved2; +} __attribute__((packed)); + +struct carm_msg_sync_time { + u8 type; + u8 subtype; + u16 reserved1; + u32 handle; + u32 reserved2; + u32 timestamp; +} __attribute__((packed)); + +struct carm_msg_get_fw_ver { + u8 type; + u8 subtype; + u16 reserved1; + u32 handle; + u32 data_addr; + u32 reserved2; +} __attribute__((packed)); + +struct carm_fw_ver { + u32 version; + u8 features; + u8 reserved1; + u16 reserved2; +} __attribute__((packed)); + +struct carm_array_info { + u32 size; + + u16 size_hi; + u16 stripe_size; + + u32 mode; + + u16 stripe_blk_sz; + u16 reserved1; + + u16 cyl; + u16 head; + + u16 sect; + u8 array_id; + u8 reserved2; + + char name[40]; + + u32 array_status; + + /* device list continues beyond this point? */ +} __attribute__((packed)); + +static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); +static void carm_remove_one (struct pci_dev *pdev); +static int carm_bdev_ioctl(struct inode *ino, struct file *fil, + unsigned int cmd, unsigned long arg); +static request_queue_t *carm_find_queue(kdev_t device); +static int carm_revalidate_disk(kdev_t dev); + +static struct pci_device_id carm_pci_tbl[] = { + { PCI_VENDOR_ID_PROMISE, 0x8000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + { PCI_VENDOR_ID_PROMISE, 0x8002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + { } /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci, carm_pci_tbl); + +static struct pci_driver carm_driver = { + .name = DRV_NAME, + .id_table = carm_pci_tbl, + .probe = carm_init_one, + .remove = carm_remove_one, +}; + +static struct block_device_operations carm_bd_ops = { + .owner = THIS_MODULE, + .ioctl = carm_bdev_ioctl, +}; + +static unsigned int carm_host_id; +static unsigned long carm_major_alloc; + + +static struct carm_host *carm_from_dev(kdev_t dev, struct carm_port **port_out) +{ + struct carm_host *host; + struct carm_port *port; + request_queue_t *q; + + q = carm_find_queue(dev); + if (!q || !q->queuedata) { + printk(KERN_ERR PFX "queue not found for major %d minor %d\n", + MAJOR(dev), MINOR(dev)); + return NULL; + } + + port = q->queuedata; + if (unlikely(port->magic != CARM_MAGIC_PORT)) { + printk(KERN_ERR PFX "bad port magic number for major %d minor %d\n", + MAJOR(dev), MINOR(dev)); + return NULL; + } + + host = port->host; + if (unlikely(host->magic != CARM_MAGIC_HOST)) { + printk(KERN_ERR PFX "bad host magic number for major %d minor %d\n", + MAJOR(dev), MINOR(dev)); + return NULL; + } + + if (port_out) + *port_out = port; + return host; +} + +static int carm_bdev_ioctl(struct inode *ino, struct file *fil, + unsigned int cmd, unsigned long arg) +{ + void *usermem = (void *) arg; + struct carm_port *port = NULL; + struct carm_host *host; + + host = carm_from_dev(ino->i_rdev, &port); + if (!host) + return -EINVAL; + + switch (cmd) { + case HDIO_GETGEO: { + struct hd_geometry geom; + + if (!usermem) + return -EINVAL; + + if (port->dev_geom_cyl) { + geom.heads = port->dev_geom_head; + geom.sectors = port->dev_geom_sect; + geom.cylinders = port->dev_geom_cyl; + } else { + u32 tmp = ((u32)port->capacity) / (0xff * 0x3f); + geom.heads = 0xff; + geom.sectors = 0x3f; + if (tmp > 65536) + geom.cylinders = 0xffff; + else + geom.cylinders = tmp; + } + geom.start = host->gendisk_hd[MINOR(ino->i_rdev)].start_sect; + + if (copy_to_user(usermem, &geom, sizeof(geom))) + return -EFAULT; + return 0; + } + + case HDIO_GETGEO_BIG: { + struct hd_big_geometry geom; + + if (!usermem) + return -EINVAL; + + if (port->dev_geom_cyl) { + geom.heads = port->dev_geom_head; + geom.sectors = port->dev_geom_sect; + geom.cylinders = port->dev_geom_cyl; + } else { + geom.heads = 0xff; + geom.sectors = 0x3f; + geom.cylinders = ((u32)port->capacity) / (0xff * 0x3f); + } + geom.start = host->gendisk_hd[MINOR(ino->i_rdev)].start_sect; + + if (copy_to_user(usermem, &geom, sizeof(geom))) + return -EFAULT; + return 0; + } + + case BLKRRPART: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + return carm_revalidate_disk(ino->i_rdev); + + case BLKGETSIZE: + case BLKGETSIZE64: + case BLKFLSBUF: + case BLKBSZSET: + case BLKBSZGET: + case BLKROSET: + case BLKROGET: + case BLKRASET: + case BLKRAGET: + case BLKPG: + case BLKELVGET: + case BLKELVSET: + return blk_ioctl(ino->i_rdev, cmd, arg); + + default: + break; + } + + return -EOPNOTSUPP; +} + +static inline unsigned long msecs_to_jiffies(unsigned long msecs) +{ + return ((HZ * msecs + 999) / 1000); +} + +static void msleep(unsigned long msecs) +{ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(msecs) + 1); +} + +static const u32 msg_sizes[] = { 32, 64, 128, CARM_MSG_SIZE }; + +static inline int carm_lookup_bucket(u32 msg_size) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(msg_sizes); i++) + if (msg_size <= msg_sizes[i]) + return i; + + return -ENOENT; +} + +static void carm_init_buckets(void *mmio) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(msg_sizes); i++) + writel(msg_sizes[i], mmio + CARM_CMS0 + (4 * i)); +} + +static inline void *carm_ref_msg(struct carm_host *host, + unsigned int msg_idx) +{ + return host->msg_base + (msg_idx * CARM_MSG_SIZE); +} + +static inline dma_addr_t carm_ref_msg_dma(struct carm_host *host, + unsigned int msg_idx) +{ + return host->msg_dma + (msg_idx * CARM_MSG_SIZE); +} + +static int carm_send_msg(struct carm_host *host, + struct carm_request *crq) +{ + void *mmio = host->mmio; + u32 msg = (u32) carm_ref_msg_dma(host, crq->tag); + u32 cm_bucket = crq->msg_bucket; + u32 tmp; + int rc = 0; + + VPRINTK("ENTER\n"); + + tmp = readl(mmio + CARM_HMUC); + if (tmp & CARM_Q_FULL) { +#if 0 + tmp = readl(mmio + CARM_INT_MASK); + tmp |= INT_Q_AVAILABLE; + writel(tmp, mmio + CARM_INT_MASK); + readl(mmio + CARM_INT_MASK); /* flush */ +#endif + DPRINTK("host msg queue full\n"); + rc = -EBUSY; + } else { + writel(msg | (cm_bucket << 1), mmio + CARM_IHQP); + readl(mmio + CARM_IHQP); /* flush */ + } + + return rc; +} + +static struct carm_request *carm_get_request(struct carm_host *host) +{ + unsigned int i; + + /* obey global hardware limit on S/G entries */ + if (host->hw_sg_used >= (CARM_MAX_HOST_SG - CARM_MAX_REQ_SG)) + return NULL; + + for (i = 0; i < CARM_MAX_Q; i++) + if ((host->msg_alloc & (1ULL << i)) == 0) { + struct carm_request *crq = &host->req[i]; + crq->port = NULL; + crq->n_elem = 0; + + host->msg_alloc |= (1ULL << i); + host->n_msgs++; + + assert(host->n_msgs <= CARM_MAX_REQ); + return crq; + } + + DPRINTK("no request available, returning NULL\n"); + return NULL; +} + +static int carm_put_request(struct carm_host *host, struct carm_request *crq) +{ + assert(crq->tag < CARM_MAX_Q); + + if (unlikely((host->msg_alloc & (1ULL << crq->tag)) == 0)) + return -EINVAL; /* tried to clear a tag that was not active */ + + assert(host->hw_sg_used >= crq->n_elem); + + host->msg_alloc &= ~(1ULL << crq->tag); + host->hw_sg_used -= crq->n_elem; + host->n_msgs--; + + return 0; +} + +static void carm_insert_special(request_queue_t *q, struct request *rq, + void *data, int at_head) +{ + unsigned long flags; + + rq->cmd = SPECIAL; + rq->special = data; + rq->q = NULL; + rq->nr_segments = 0; + rq->elevator_sequence = 0; + + spin_lock_irqsave(&io_request_lock, flags); + if (at_head) + list_add(&rq->queue, &q->queue_head); + else + list_add_tail(&rq->queue, &q->queue_head); + q->request_fn(q); + spin_unlock_irqrestore(&io_request_lock, flags); +} + +static struct carm_request *carm_get_special(struct carm_host *host) +{ + unsigned long flags; + struct carm_request *crq = NULL; + int tries = 5000; + + while (tries-- > 0) { + spin_lock_irqsave(&io_request_lock, flags); + crq = carm_get_request(host); + spin_unlock_irqrestore(&io_request_lock, flags); + + if (crq) + break; + msleep(10); + } + + if (!crq) + return NULL; + + crq->rq = &crq->special_rq; + return crq; +} + +static int carm_array_info (struct carm_host *host, unsigned int array_idx) +{ + struct carm_msg_ioctl *ioc; + unsigned int idx; + u32 msg_data; + dma_addr_t msg_dma; + struct carm_request *crq; + int rc; + unsigned long flags; + + crq = carm_get_special(host); + if (!crq) { + rc = -ENOMEM; + goto err_out; + } + + idx = crq->tag; + + ioc = carm_ref_msg(host, idx); + msg_dma = carm_ref_msg_dma(host, idx); + msg_data = (u32) (msg_dma + sizeof(struct carm_array_info)); + + crq->msg_type = CARM_MSG_ARRAY; + crq->msg_subtype = CARM_ARRAY_INFO; + rc = carm_lookup_bucket(sizeof(struct carm_msg_ioctl) + + sizeof(struct carm_array_info)); + BUG_ON(rc < 0); + crq->msg_bucket = (u32) rc; + + memset(ioc, 0, sizeof(*ioc)); + ioc->type = CARM_MSG_ARRAY; + ioc->subtype = CARM_ARRAY_INFO; + ioc->array_id = (u8) array_idx; + ioc->handle = cpu_to_le32(TAG_ENCODE(idx)); + ioc->data_addr = cpu_to_le32(msg_data); + + assert(host->state == HST_DEV_SCAN_START || + host->state == HST_DEV_SCAN); + + DPRINTK("blk_insert_request, tag == %u\n", idx); + carm_insert_special(&host->oob_q, crq->rq, crq, 1); + + return 0; + +err_out: + spin_lock_irqsave(&io_request_lock, flags); + host->state = HST_ERROR; + spin_unlock_irqrestore(&io_request_lock, flags); + return rc; +} + +typedef unsigned int (*carm_sspc_t)(struct carm_host *, unsigned int, void *); + +static int carm_send_special (struct carm_host *host, carm_sspc_t func) +{ + struct carm_request *crq; + struct carm_msg_ioctl *ioc; + void *mem; + unsigned int idx, msg_size; + int rc; + + crq = carm_get_special(host); + if (!crq) + return -ENOMEM; + + idx = crq->tag; + + mem = carm_ref_msg(host, idx); + + msg_size = func(host, idx, mem); + + ioc = mem; + crq->msg_type = ioc->type; + crq->msg_subtype = ioc->subtype; + rc = carm_lookup_bucket(msg_size); + BUG_ON(rc < 0); + crq->msg_bucket = (u32) rc; + + DPRINTK("blk_insert_request, tag == %u\n", idx); + carm_insert_special(&host->oob_q, crq->rq, crq, 1); + + return 0; +} + +static unsigned int carm_fill_sync_time(struct carm_host *host, + unsigned int idx, void *mem) +{ + struct timeval tv; + struct carm_msg_sync_time *st = mem; + + do_gettimeofday(&tv); + + memset(st, 0, sizeof(*st)); + st->type = CARM_MSG_MISC; + st->subtype = MISC_SET_TIME; + st->handle = cpu_to_le32(TAG_ENCODE(idx)); + st->timestamp = cpu_to_le32(tv.tv_sec); + + return sizeof(struct carm_msg_sync_time); +} + +static unsigned int carm_fill_alloc_buf(struct carm_host *host, + unsigned int idx, void *mem) +{ + struct carm_msg_allocbuf *ab = mem; + + memset(ab, 0, sizeof(*ab)); + ab->type = CARM_MSG_MISC; + ab->subtype = MISC_ALLOC_MEM; + ab->handle = cpu_to_le32(TAG_ENCODE(idx)); + ab->n_sg = 1; + ab->sg_type = SGT_32BIT; + ab->addr = cpu_to_le32(host->shm_dma + (PDC_SHM_SIZE >> 1)); + ab->len = cpu_to_le32(PDC_SHM_SIZE >> 1); + ab->evt_pool = cpu_to_le32(host->shm_dma + (16 * 1024)); + ab->n_evt = cpu_to_le32(1024); + ab->rbuf_pool = cpu_to_le32(host->shm_dma); + ab->n_rbuf = cpu_to_le32(RMSG_Q_LEN); + ab->msg_pool = cpu_to_le32(host->shm_dma + RBUF_LEN); + ab->n_msg = cpu_to_le32(CARM_Q_LEN); + ab->sg[0].start = cpu_to_le32(host->shm_dma + (PDC_SHM_SIZE >> 1)); + ab->sg[0].len = cpu_to_le32(65536); + + return sizeof(struct carm_msg_allocbuf); +} + +static unsigned int carm_fill_scan_channels(struct carm_host *host, + unsigned int idx, void *mem) +{ + struct carm_msg_ioctl *ioc = mem; + u32 msg_data = (u32) (carm_ref_msg_dma(host, idx) + + IOC_SCAN_CHAN_OFFSET); + + memset(ioc, 0, sizeof(*ioc)); + ioc->type = CARM_MSG_IOCTL; + ioc->subtype = CARM_IOC_SCAN_CHAN; + ioc->handle = cpu_to_le32(TAG_ENCODE(idx)); + ioc->data_addr = cpu_to_le32(msg_data); + + /* fill output data area with "no device" default values */ + mem += IOC_SCAN_CHAN_OFFSET; + memset(mem, IOC_SCAN_CHAN_NODEV, CARM_MAX_PORTS); + + return IOC_SCAN_CHAN_OFFSET + CARM_MAX_PORTS; +} + +static unsigned int carm_fill_get_fw_ver(struct carm_host *host, + unsigned int idx, void *mem) +{ + struct carm_msg_get_fw_ver *ioc = mem; + u32 msg_data = (u32) (carm_ref_msg_dma(host, idx) + sizeof(*ioc)); + + memset(ioc, 0, sizeof(*ioc)); + ioc->type = CARM_MSG_MISC; + ioc->subtype = MISC_GET_FW_VER; + ioc->handle = cpu_to_le32(TAG_ENCODE(idx)); + ioc->data_addr = cpu_to_le32(msg_data); + + return sizeof(struct carm_msg_get_fw_ver) + + sizeof(struct carm_fw_ver); +} + +static void carm_activate_disk(struct carm_host *host, + struct carm_port *port) +{ + int minor_start = port->port_no << CARM_PART_SHIFT; + int start, end, i; + + host->gendisk_hd[minor_start].nr_sects = port->capacity; + host->blk_sizes[minor_start] = port->capacity; + + start = minor_start; + end = minor_start + CARM_MINORS_PER_MAJOR; + for (i = start; i < end; i++) { + invalidate_device(MKDEV(host->major, i), 1); + host->gendisk.part[i].start_sect = 0; + host->gendisk.part[i].nr_sects = 0; + host->blk_block_sizes[i] = 512; + host->blk_sect_sizes[i] = 512; + } + + grok_partitions(&host->gendisk, port->port_no, + CARM_MINORS_PER_MAJOR, + port->capacity); +} + +static int carm_revalidate_disk(kdev_t dev) +{ + struct carm_host *host; + struct carm_port *port = NULL; + + host = carm_from_dev(dev, &port); + if (!host) + return -EINVAL; + + carm_activate_disk(host, port); + + return 0; +} + +static inline void complete_buffers(struct buffer_head *bh, int status) +{ + struct buffer_head *xbh; + + while (bh) { + xbh = bh->b_reqnext; + bh->b_reqnext = NULL; + blk_finished_io(bh->b_size >> 9); + bh->b_end_io(bh, status); + bh = xbh; + } +} + +static inline void carm_end_request_queued(struct carm_host *host, + struct carm_request *crq, + int uptodate) +{ + struct request *req = crq->rq; + int rc; + + complete_buffers(req->bh, uptodate); + end_that_request_last(req); + + rc = carm_put_request(host, crq); + assert(rc == 0); +} + +static inline void carm_push_q (struct carm_host *host, request_queue_t *q) +{ + unsigned int idx = host->wait_q_prod % CARM_MAX_WAIT_Q; + + VPRINTK("STOPPED QUEUE %p\n", q); + + host->wait_q[idx] = q; + host->wait_q_prod++; + BUG_ON(host->wait_q_prod == host->wait_q_cons); /* overrun */ +} + +static inline request_queue_t *carm_pop_q(struct carm_host *host) +{ + unsigned int idx; + + if (host->wait_q_prod == host->wait_q_cons) + return NULL; + + idx = host->wait_q_cons % CARM_MAX_WAIT_Q; + host->wait_q_cons++; + + return host->wait_q[idx]; +} + +static inline void carm_round_robin(struct carm_host *host) +{ + request_queue_t *q = carm_pop_q(host); + if (q) { + struct tasklet_struct *tasklet; + if (q == &host->oob_q) + tasklet = &host->oob_tasklet; + else { + struct carm_port *port = q->queuedata; + tasklet = &port->tasklet; + } + tasklet_schedule(tasklet); + VPRINTK("STARTED QUEUE %p\n", q); + } +} + +static inline void carm_end_rq(struct carm_host *host, struct carm_request *crq, + int is_ok) +{ + carm_end_request_queued(host, crq, is_ok); + if (CARM_MAX_Q == 1) + carm_round_robin(host); + else if ((host->n_msgs <= CARM_MSG_LOW_WATER) && + (host->hw_sg_used <= CARM_SG_LOW_WATER)) { + carm_round_robin(host); + } +} + +static inline int carm_new_segment(request_queue_t *q, struct request *rq) +{ + if (rq->nr_segments < CARM_MAX_REQ_SG) { + rq->nr_segments++; + return 1; + } + return 0; +} + +static int carm_back_merge_fn(request_queue_t *q, struct request *rq, + struct buffer_head *bh, int max_segments) +{ + if (blk_seg_merge_ok(rq->bhtail, bh)) + return 1; + return carm_new_segment(q, rq); +} + +static int carm_front_merge_fn(request_queue_t *q, struct request *rq, + struct buffer_head *bh, int max_segments) +{ + if (blk_seg_merge_ok(bh, rq->bh)) + return 1; + return carm_new_segment(q, rq); +} + +static int carm_merge_requests_fn(request_queue_t *q, struct request *rq, + struct request *nxt, int max_segments) +{ + int total_segments = rq->nr_segments + nxt->nr_segments; + + if (blk_seg_merge_ok(rq->bhtail, nxt->bh)) + total_segments--; + + if (total_segments > CARM_MAX_REQ_SG) + return 0; + + rq->nr_segments = total_segments; + return 1; +} + +static void carm_oob_rq_fn(request_queue_t *q) +{ + struct carm_host *host = q->queuedata; + + tasklet_schedule(&host->oob_tasklet); +} + +static void carm_rq_fn(request_queue_t *q) +{ + struct carm_port *port = q->queuedata; + + tasklet_schedule(&port->tasklet); +} + +static void carm_oob_tasklet(unsigned long _data) +{ + struct carm_host *host = (void *) _data; + request_queue_t *q = &host->oob_q; + struct carm_request *crq; + struct request *rq; + int rc, have_work = 1; + struct list_head *queue_head = &q->queue_head; + unsigned long flags; + + spin_lock_irqsave(&io_request_lock, flags); + if (q->plugged || list_empty(queue_head)) + have_work = 0; + + if (!have_work) + goto out; + + while (1) { + DPRINTK("get req\n"); + if (list_empty(queue_head)) + break; + + rq = blkdev_entry_next_request(queue_head); + + crq = rq->special; + assert(crq != NULL); + assert(crq->rq == rq); + + crq->n_elem = 0; + + DPRINTK("send req\n"); + rc = carm_send_msg(host, crq); + if (rc) { + carm_push_q(host, q); + break; /* call us again later, eventually */ + } else + blkdev_dequeue_request(rq); + } + +out: + spin_unlock_irqrestore(&io_request_lock, flags); +} + +static int blk_rq_map_sg(request_queue_t *q, struct request *rq, + struct scatterlist *sg) +{ + int n_elem = 0; + struct buffer_head *bh = rq->bh; + u64 last_phys = ~0ULL; + + while (bh) { + if (bh_phys(bh) == last_phys) { + sg[n_elem - 1].length += bh->b_size; + last_phys += bh->b_size; + } else { + if (unlikely(n_elem == CARM_MAX_REQ_SG)) + BUG(); + sg[n_elem].page = bh->b_page; + sg[n_elem].length = bh->b_size; + sg[n_elem].offset = bh_offset(bh); + last_phys = bh_phys(bh) + bh->b_size; + n_elem++; + } + + bh = bh->b_reqnext; + } + + return n_elem; +} + +static void carm_rw_tasklet(unsigned long _data) +{ + struct carm_port *port = (void *) _data; + struct carm_host *host = port->host; + request_queue_t *q = &port->q; + struct carm_msg_rw *msg; + struct carm_request *crq; + struct request *rq; + struct scatterlist *sg; + int writing = 0, pci_dir, i, n_elem, rc, have_work = 1; + u32 tmp; + unsigned int msg_size; + unsigned long flags; + struct list_head *queue_head = &q->queue_head; + unsigned long start_sector; + + spin_lock_irqsave(&io_request_lock, flags); + if (q->plugged || list_empty(queue_head)) + have_work = 0; + + if (!have_work) + goto out; + +queue_one_request: + VPRINTK("get req\n"); + if (list_empty(queue_head)) + goto out; + + rq = blkdev_entry_next_request(queue_head); + + crq = carm_get_request(host); + if (!crq) { + carm_push_q(host, q); + goto out; /* call us again later, eventually */ + } + crq->rq = rq; + + if (rq_data_dir(rq) == WRITE) { + writing = 1; + pci_dir = PCI_DMA_TODEVICE; + } else { + pci_dir = PCI_DMA_FROMDEVICE; + } + + /* get scatterlist from block layer */ + sg = &crq->sg[0]; + n_elem = blk_rq_map_sg(q, rq, sg); + if (n_elem <= 0) { + carm_end_rq(host, crq, 0); + goto out; /* request with no s/g entries? */ + } + + /* map scatterlist to PCI bus addresses */ + n_elem = pci_map_sg(host->pdev, sg, n_elem, pci_dir); + if (n_elem <= 0) { + carm_end_rq(host, crq, 0); + goto out; /* request with no s/g entries? */ + } + crq->n_elem = n_elem; + crq->port = port; + host->hw_sg_used += n_elem; + + /* + * build read/write message + */ + + VPRINTK("build msg\n"); + msg = (struct carm_msg_rw *) carm_ref_msg(host, crq->tag); + + if (writing) { + msg->type = CARM_MSG_WRITE; + crq->msg_type = CARM_MSG_WRITE; + } else { + msg->type = CARM_MSG_READ; + crq->msg_type = CARM_MSG_READ; + } + + start_sector = rq->sector; + start_sector += host->gendisk_hd[MINOR(rq->rq_dev)].start_sect; + + msg->id = port->port_no; + msg->sg_count = n_elem; + msg->sg_type = SGT_32BIT; + msg->handle = cpu_to_le32(TAG_ENCODE(crq->tag)); + msg->lba = cpu_to_le32(start_sector & 0xffffffff); + tmp = (start_sector >> 16) >> 16; + msg->lba_high = cpu_to_le16( (u16) tmp ); + msg->lba_count = cpu_to_le16(rq->nr_sectors); + + msg_size = sizeof(struct carm_msg_rw) - sizeof(msg->sg); + for (i = 0; i < n_elem; i++) { + struct carm_msg_sg *carm_sg = &msg->sg[i]; + carm_sg->start = cpu_to_le32(sg_dma_address(&crq->sg[i])); + carm_sg->len = cpu_to_le32(sg_dma_len(&crq->sg[i])); + msg_size += sizeof(struct carm_msg_sg); + } + + rc = carm_lookup_bucket(msg_size); + BUG_ON(rc < 0); + crq->msg_bucket = (u32) rc; + + /* + * queue read/write message to hardware + */ + + VPRINTK("send msg, tag == %u\n", crq->tag); + rc = carm_send_msg(host, crq); + if (rc) { + carm_put_request(host, crq); + carm_push_q(host, q); + goto out; /* call us again later, eventually */ + } else + blkdev_dequeue_request(rq); + + goto queue_one_request; + +out: + spin_unlock_irqrestore(&io_request_lock, flags); +} + +static void carm_handle_array_info(struct carm_host *host, + struct carm_request *crq, u8 *mem, + int is_ok) +{ + struct carm_port *port; + u8 *msg_data = mem + sizeof(struct carm_array_info); + struct carm_array_info *desc = (struct carm_array_info *) msg_data; + u64 lo, hi; + int cur_port; + size_t slen; + + DPRINTK("ENTER\n"); + + carm_end_rq(host, crq, is_ok); + + if (!is_ok) + goto out; + if (le32_to_cpu(desc->array_status) & ARRAY_NO_EXIST) + goto out; + + cur_port = host->cur_scan_dev; + + /* should never occur */ + if ((cur_port < 0) || (cur_port >= CARM_MAX_PORTS)) { + printk(KERN_ERR PFX "BUG: cur_scan_dev==%d, array_id==%d\n", + cur_port, (int) desc->array_id); + goto out; + } + + port = &host->port[cur_port]; + + lo = (u64) le32_to_cpu(desc->size); + hi = (u64) le32_to_cpu(desc->size_hi); + + port->capacity = lo | (hi << 32); + port->dev_geom_head = le16_to_cpu(desc->head); + port->dev_geom_sect = le16_to_cpu(desc->sect); + port->dev_geom_cyl = le16_to_cpu(desc->cyl); + + host->dev_active |= (1 << cur_port); + + strncpy(port->name, desc->name, sizeof(port->name)); + port->name[sizeof(port->name) - 1] = 0; + slen = strlen(port->name); + while (slen && (port->name[slen - 1] == ' ')) { + port->name[slen - 1] = 0; + slen--; + } + + printk(KERN_INFO DRV_NAME "(%s): port %u device %Lu sectors\n", + pci_name(host->pdev), port->port_no, port->capacity); + printk(KERN_INFO DRV_NAME "(%s): port %u device \"%s\"\n", + pci_name(host->pdev), port->port_no, port->name); + +out: + assert(host->state == HST_DEV_SCAN); + schedule_task(&host->fsm_task); +} + +static void carm_handle_scan_chan(struct carm_host *host, + struct carm_request *crq, u8 *mem, + int is_ok) +{ + u8 *msg_data = mem + IOC_SCAN_CHAN_OFFSET; + unsigned int i, dev_count = 0; + int new_state = HST_DEV_SCAN_START; + + DPRINTK("ENTER\n"); + + carm_end_rq(host, crq, is_ok); + + if (!is_ok) { + new_state = HST_ERROR; + goto out; + } + + /* TODO: scan and support non-disk devices */ + for (i = 0; i < 8; i++) + if (msg_data[i] == 0) { /* direct-access device (disk) */ + host->dev_present |= (1 << i); + dev_count++; + } + + printk(KERN_INFO DRV_NAME "(%s): found %u interesting devices\n", + pci_name(host->pdev), dev_count); + +out: + assert(host->state == HST_PORT_SCAN); + host->state = new_state; + schedule_task(&host->fsm_task); +} + +static void carm_handle_generic(struct carm_host *host, + struct carm_request *crq, int is_ok, + int cur_state, int next_state) +{ + DPRINTK("ENTER\n"); + + carm_end_rq(host, crq, is_ok); + + assert(host->state == cur_state); + if (is_ok) + host->state = next_state; + else + host->state = HST_ERROR; + schedule_task(&host->fsm_task); +} + +static inline void carm_handle_rw(struct carm_host *host, + struct carm_request *crq, int is_ok) +{ + int pci_dir; + + VPRINTK("ENTER\n"); + + if (rq_data_dir(crq->rq) == WRITE) + pci_dir = PCI_DMA_TODEVICE; + else + pci_dir = PCI_DMA_FROMDEVICE; + + pci_unmap_sg(host->pdev, &crq->sg[0], crq->n_elem, pci_dir); + + carm_end_rq(host, crq, is_ok); +} + +static inline void carm_handle_resp(struct carm_host *host, + u32 ret_handle_le, u32 status) +{ + u32 handle = le32_to_cpu(ret_handle_le); + unsigned int msg_idx; + struct carm_request *crq; + int is_ok = (status == RMSG_OK); + u8 *mem; + + VPRINTK("ENTER, handle == 0x%x\n", handle); + + if (unlikely(!TAG_VALID(handle))) { + printk(KERN_ERR DRV_NAME "(%s): BUG: invalid tag 0x%x\n", + pci_name(host->pdev), handle); + return; + } + + msg_idx = TAG_DECODE(handle); + VPRINTK("tag == %u\n", msg_idx); + + crq = &host->req[msg_idx]; + + /* fast path */ + if (likely(crq->msg_type == CARM_MSG_READ || + crq->msg_type == CARM_MSG_WRITE)) { + carm_handle_rw(host, crq, is_ok); + return; + } + + mem = carm_ref_msg(host, msg_idx); + + switch (crq->msg_type) { + case CARM_MSG_IOCTL: { + switch (crq->msg_subtype) { + case CARM_IOC_SCAN_CHAN: + carm_handle_scan_chan(host, crq, mem, is_ok); + break; + default: + /* unknown / invalid response */ + goto err_out; + } + break; + } + + case CARM_MSG_MISC: { + switch (crq->msg_subtype) { + case MISC_ALLOC_MEM: + carm_handle_generic(host, crq, is_ok, + HST_ALLOC_BUF, HST_SYNC_TIME); + break; + case MISC_SET_TIME: + carm_handle_generic(host, crq, is_ok, + HST_SYNC_TIME, HST_GET_FW_VER); + break; + case MISC_GET_FW_VER: { + struct carm_fw_ver *ver = (struct carm_fw_ver *) + mem + sizeof(struct carm_msg_get_fw_ver); + if (is_ok) { + host->fw_ver = le32_to_cpu(ver->version); + host->flags |= (ver->features & FL_FW_VER_MASK); + } + carm_handle_generic(host, crq, is_ok, + HST_GET_FW_VER, HST_PORT_SCAN); + break; + } + default: + /* unknown / invalid response */ + goto err_out; + } + break; + } + + case CARM_MSG_ARRAY: { + switch (crq->msg_subtype) { + case CARM_ARRAY_INFO: + carm_handle_array_info(host, crq, mem, is_ok); + break; + default: + /* unknown / invalid response */ + goto err_out; + } + break; + } + + default: + /* unknown / invalid response */ + goto err_out; + } + + return; + +err_out: + printk(KERN_WARNING DRV_NAME "(%s): BUG: unhandled message type %d/%d\n", + pci_name(host->pdev), crq->msg_type, crq->msg_subtype); + carm_end_rq(host, crq, 0); +} + +static inline void carm_handle_responses(struct carm_host *host) +{ + void *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; + + while (1) { + u32 status = le32_to_cpu(resp[idx].status); + + if (status == 0xffffffff) { + VPRINTK("ending response on index %u\n", idx); + writel(idx << 3, mmio + CARM_RESP_IDX); + break; + } + + /* response to a message we sent */ + 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; + } + + /* asynchronous events the hardware throws our way */ + else if ((status & 0xff000000) == (1 << 31)) { + u8 *evt_type_ptr = (u8 *) &resp[idx]; + 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; + } + + idx = NEXT_RESP(idx); + work++; + } + + VPRINTK("EXIT, work==%u\n", work); + host->resp_idx += work; +} + +static irqreturn_t carm_interrupt(int irq, void *__host, struct pt_regs *regs) +{ + struct carm_host *host = __host; + void *mmio; + u32 mask; + int handled = 0; + unsigned long flags; + + if (!host) { + VPRINTK("no host\n"); + return IRQ_NONE; + } + + spin_lock_irqsave(&io_request_lock, flags); + + mmio = host->mmio; + + /* reading should also clear interrupts */ + mask = readl(mmio + CARM_INT_STAT); + + if (mask == 0 || mask == 0xffffffff) { + VPRINTK("no work, mask == 0x%x\n", mask); + goto out; + } + + if (mask & INT_ACK_MASK) + writel(mask, mmio + CARM_INT_STAT); + + if (unlikely(host->state == HST_INVALID)) { + VPRINTK("not initialized yet, mask = 0x%x\n", mask); + goto out; + } + + if (mask & CARM_HAVE_RESP) { + handled = 1; + carm_handle_responses(host); + } + +out: + spin_unlock_irqrestore(&io_request_lock, flags); + VPRINTK("EXIT\n"); + return IRQ_RETVAL(handled); +} + +static void carm_fsm_task (void *_data) +{ + struct carm_host *host = _data; + unsigned long flags; + unsigned int state; + int rc, i, next_dev; + int reschedule = 0; + int new_state = HST_INVALID; + + spin_lock_irqsave(&io_request_lock, flags); + state = host->state; + spin_unlock_irqrestore(&io_request_lock, flags); + + DPRINTK("ENTER, state == %s\n", state_name[state]); + + switch (state) { + case HST_PROBE_START: + new_state = HST_ALLOC_BUF; + reschedule = 1; + break; + + case HST_ALLOC_BUF: + rc = carm_send_special(host, carm_fill_alloc_buf); + if (rc) { + new_state = HST_ERROR; + reschedule = 1; + } + break; + + case HST_SYNC_TIME: + rc = carm_send_special(host, carm_fill_sync_time); + if (rc) { + new_state = HST_ERROR; + reschedule = 1; + } + break; + + case HST_GET_FW_VER: + rc = carm_send_special(host, carm_fill_get_fw_ver); + if (rc) { + new_state = HST_ERROR; + reschedule = 1; + } + break; + + case HST_PORT_SCAN: + rc = carm_send_special(host, carm_fill_scan_channels); + if (rc) { + new_state = HST_ERROR; + reschedule = 1; + } + break; + + case HST_DEV_SCAN_START: + host->cur_scan_dev = -1; + new_state = HST_DEV_SCAN; + reschedule = 1; + break; + + case HST_DEV_SCAN: + next_dev = -1; + for (i = host->cur_scan_dev + 1; i < CARM_MAX_PORTS; i++) + if (host->dev_present & (1 << i)) { + next_dev = i; + break; + } + + if (next_dev >= 0) { + host->cur_scan_dev = next_dev; + rc = carm_array_info(host, next_dev); + if (rc) { + new_state = HST_ERROR; + reschedule = 1; + } + } else { + new_state = HST_DEV_ACTIVATE; + reschedule = 1; + } + break; + + case HST_DEV_ACTIVATE: { + int activated = 0; + for (i = 0; i < CARM_MAX_PORTS; i++) + if (host->dev_active & (1 << i)) { + carm_activate_disk(host, &host->port[i]); + activated++; + } + + printk(KERN_INFO DRV_NAME "(%s): %d ports activated\n", + pci_name(host->pdev), activated); + + new_state = HST_PROBE_FINISHED; + reschedule = 1; + break; + } + + case HST_PROBE_FINISHED: + up(&host->probe_sem); + break; + + case HST_ERROR: + /* FIXME: TODO */ + break; + + default: + /* should never occur */ + printk(KERN_ERR PFX "BUG: unknown state %d\n", state); + assert(0); + break; + } + + if (new_state != HST_INVALID) { + spin_lock_irqsave(&io_request_lock, flags); + host->state = new_state; + spin_unlock_irqrestore(&io_request_lock, flags); + } + if (reschedule) + schedule_task(&host->fsm_task); +} + +static int carm_init_wait(void *mmio, u32 bits, unsigned int test_bit) +{ + unsigned int i; + + for (i = 0; i < 50000; i++) { + u32 tmp = readl(mmio + CARM_LMUC); + udelay(100); + + if (test_bit) { + if ((tmp & bits) == bits) + return 0; + } else { + if ((tmp & bits) == 0) + return 0; + } + + cond_resched(); + } + + printk(KERN_ERR PFX "carm_init_wait timeout, bits == 0x%x, test_bit == %s\n", + bits, test_bit ? "yes" : "no"); + return -EBUSY; +} + +static void carm_init_responses(struct carm_host *host) +{ + void *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; + + writel(0, mmio + CARM_RESP_IDX); +} + +static int carm_init_host(struct carm_host *host) +{ + void *mmio = host->mmio; + u32 tmp; + u8 tmp8; + int rc; + unsigned long flags; + + DPRINTK("ENTER\n"); + + writel(0, mmio + CARM_INT_MASK); + + tmp8 = readb(mmio + CARM_INITC); + if (tmp8 & 0x01) { + tmp8 &= ~0x01; + writeb(tmp8, CARM_INITC); + readb(mmio + CARM_INITC); /* flush */ + + DPRINTK("snooze...\n"); + msleep(5000); + } + + tmp = readl(mmio + CARM_HMUC); + if (tmp & CARM_CME) { + DPRINTK("CME bit present, waiting\n"); + rc = carm_init_wait(mmio, CARM_CME, 1); + if (rc) { + DPRINTK("EXIT, carm_init_wait 1 failed\n"); + return rc; + } + } + if (tmp & CARM_RME) { + DPRINTK("RME bit present, waiting\n"); + rc = carm_init_wait(mmio, CARM_RME, 1); + if (rc) { + DPRINTK("EXIT, carm_init_wait 2 failed\n"); + return rc; + } + } + + tmp &= ~(CARM_RME | CARM_CME); + writel(tmp, mmio + CARM_HMUC); + readl(mmio + CARM_HMUC); /* flush */ + + rc = carm_init_wait(mmio, CARM_RME | CARM_CME, 0); + if (rc) { + DPRINTK("EXIT, carm_init_wait 3 failed\n"); + return rc; + } + + carm_init_buckets(mmio); + + writel(host->shm_dma & 0xffffffff, mmio + RBUF_ADDR_LO); + writel((host->shm_dma >> 16) >> 16, mmio + RBUF_ADDR_HI); + writel(RBUF_LEN, mmio + RBUF_BYTE_SZ); + + tmp = readl(mmio + CARM_HMUC); + tmp |= (CARM_RME | CARM_CME | CARM_WZBC); + writel(tmp, mmio + CARM_HMUC); + readl(mmio + CARM_HMUC); /* flush */ + + rc = carm_init_wait(mmio, CARM_RME | CARM_CME, 1); + if (rc) { + DPRINTK("EXIT, carm_init_wait 4 failed\n"); + return rc; + } + + writel(0, mmio + CARM_HMPHA); + writel(INT_DEF_MASK, mmio + CARM_INT_MASK); + + carm_init_responses(host); + + /* start initialization, probing state machine */ + spin_lock_irqsave(&io_request_lock, flags); + assert(host->state == HST_INVALID); + host->state = HST_PROBE_START; + spin_unlock_irqrestore(&io_request_lock, flags); + + schedule_task(&host->fsm_task); + + DPRINTK("EXIT\n"); + return 0; +} + +static void carm_init_ports (struct carm_host *host) +{ + struct carm_port *port; + request_queue_t *q; + unsigned int i; + + for (i = 0; i < CARM_MAX_PORTS; i++) { + port = &host->port[i]; + port->magic = CARM_MAGIC_PORT; + port->host = host; + port->port_no = i; + tasklet_init(&port->tasklet, carm_rw_tasklet, + (unsigned long) port); + + q = &port->q; + + blk_init_queue(q, carm_rq_fn); + q->queuedata = port; + blk_queue_bounce_limit(q, host->pdev->dma_mask); + blk_queue_headactive(q, 0); + + q->back_merge_fn = carm_back_merge_fn; + q->front_merge_fn = carm_front_merge_fn; + q->merge_requests_fn = carm_merge_requests_fn; + } +} + +static request_queue_t *carm_find_queue(kdev_t device) +{ + struct carm_host *host; + + host = blk_dev[MAJOR(device)].data; + if (!host) + return NULL; + if (host->magic != CARM_MAGIC_HOST) + return NULL; + + DPRINTK("match: major %d, minor %d\n", + MAJOR(device), MINOR(device)); + return &host->port[MINOR(device) >> CARM_PART_SHIFT].q; +} + +static int carm_init_disks(struct carm_host *host) +{ + host->gendisk.major = host->major; + host->gendisk.major_name = host->name; + host->gendisk.minor_shift = CARM_PART_SHIFT; + host->gendisk.max_p = CARM_MINORS_PER_MAJOR; + host->gendisk.part = host->gendisk_hd; + host->gendisk.sizes = host->blk_sizes; + host->gendisk.nr_real = CARM_MAX_PORTS; + host->gendisk.fops = &carm_bd_ops; + + blk_dev[host->major].queue = carm_find_queue; + blk_dev[host->major].data = host; + blk_size[host->major] = host->blk_sizes; + blksize_size[host->major] = host->blk_block_sizes; + hardsect_size[host->major] = host->blk_sect_sizes; + + add_gendisk(&host->gendisk); + + return 0; +} + +static void carm_free_disks(struct carm_host *host) +{ + unsigned int i; + + del_gendisk(&host->gendisk); + + for (i = 0; i < CARM_MAX_PORTS; i++) { + struct carm_port *port = &host->port[i]; + + blk_cleanup_queue(&port->q); + } + + blk_dev[host->major].queue = NULL; + blk_dev[host->major].data = NULL; + blk_size[host->major] = NULL; + blksize_size[host->major] = NULL; + hardsect_size[host->major] = NULL; +} + +static void carm_stop_tasklets(struct carm_host *host) +{ + unsigned int i; + + tasklet_kill(&host->oob_tasklet); + + for (i = 0; i < CARM_MAX_PORTS; i++) { + struct carm_port *port = &host->port[i]; + tasklet_kill(&port->tasklet); + } +} + +static int carm_init_shm(struct carm_host *host) +{ + host->shm = pci_alloc_consistent(host->pdev, CARM_SHM_SIZE, + &host->shm_dma); + if (!host->shm) + return -ENOMEM; + + host->msg_base = host->shm + RBUF_LEN; + host->msg_dma = host->shm_dma + RBUF_LEN; + + memset(host->shm, 0xff, RBUF_LEN); + memset(host->msg_base, 0, PDC_SHM_SIZE - RBUF_LEN); + + return 0; +} + +static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static unsigned int printed_version; + struct carm_host *host; + unsigned int pci_dac; + int rc; + unsigned int i; + + if (!printed_version++) + printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + + rc = pci_enable_device(pdev); + if (rc) + return rc; + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_out; + +#if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */ + rc = pci_set_dma_mask(pdev, 0xffffffffffffffffULL); + if (!rc) { + rc = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL); + if (rc) { + printk(KERN_ERR DRV_NAME "(%s): consistent DMA mask failure\n", + pci_name(pdev)); + goto err_out_regions; + } + pci_dac = 1; + } else { +#endif + rc = pci_set_dma_mask(pdev, 0xffffffffULL); + if (rc) { + printk(KERN_ERR DRV_NAME "(%s): DMA mask failure\n", + pci_name(pdev)); + goto err_out_regions; + } + pci_dac = 0; +#if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */ + } +#endif + + host = kmalloc(sizeof(*host), GFP_KERNEL); + if (!host) { + printk(KERN_ERR DRV_NAME "(%s): memory alloc failure\n", + pci_name(pdev)); + rc = -ENOMEM; + goto err_out_regions; + } + + memset(host, 0, sizeof(*host)); + host->magic = CARM_MAGIC_HOST; + host->pdev = pdev; + host->flags = pci_dac ? FL_DAC : 0; + INIT_TQUEUE(&host->fsm_task, carm_fsm_task, host); + INIT_LIST_HEAD(&host->host_list_node); + init_MUTEX_LOCKED(&host->probe_sem); + tasklet_init(&host->oob_tasklet, carm_oob_tasklet, + (unsigned long) host); + carm_init_ports(host); + + for (i = 0; i < ARRAY_SIZE(host->req); i++) + host->req[i].tag = i; + + host->mmio = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (!host->mmio) { + printk(KERN_ERR DRV_NAME "(%s): MMIO alloc failure\n", + pci_name(pdev)); + rc = -ENOMEM; + goto err_out_kfree; + } + + rc = carm_init_shm(host); + if (rc) { + printk(KERN_ERR DRV_NAME "(%s): DMA SHM alloc failure\n", + pci_name(pdev)); + goto err_out_iounmap; + } + + blk_init_queue(&host->oob_q, carm_oob_rq_fn); + host->oob_q.queuedata = host; + blk_queue_bounce_limit(&host->oob_q, pdev->dma_mask); + blk_queue_headactive(&host->oob_q, 0); + + /* + * Figure out which major to use: 160, 161, or dynamic + */ + if (!test_and_set_bit(0, &carm_major_alloc)) + host->major = 160; + else if (!test_and_set_bit(1, &carm_major_alloc)) + host->major = 161; + else + host->flags |= FL_DYN_MAJOR; + + host->id = carm_host_id; + sprintf(host->name, DRV_NAME "%d", carm_host_id); + + rc = register_blkdev(host->major, host->name, &carm_bd_ops); + if (rc < 0) + goto err_out_free_majors; + if (host->flags & FL_DYN_MAJOR) + host->major = rc; + + rc = carm_init_disks(host); + if (rc) + goto err_out_blkdev_disks; + + pci_set_master(pdev); + + rc = request_irq(pdev->irq, carm_interrupt, SA_SHIRQ, DRV_NAME, host); + if (rc) { + printk(KERN_ERR DRV_NAME "(%s): irq alloc failure\n", + pci_name(pdev)); + goto err_out_blkdev_disks; + } + + rc = carm_init_host(host); + if (rc) + goto err_out_free_irq; + + DPRINTK("waiting for probe_sem\n"); + down(&host->probe_sem); + + printk(KERN_INFO "%s: pci %s, ports %d, io %lx, irq %u, major %d\n", + host->name, pci_name(pdev), (int) CARM_MAX_PORTS, + pci_resource_start(pdev, 0), pdev->irq, host->major); + + carm_host_id++; + pci_set_drvdata(pdev, host); + return 0; + +err_out_free_irq: + free_irq(pdev->irq, host); +err_out_blkdev_disks: + carm_free_disks(host); + unregister_blkdev(host->major, host->name); +err_out_free_majors: + if (host->major == 160) + clear_bit(0, &carm_major_alloc); + else if (host->major == 161) + clear_bit(1, &carm_major_alloc); + blk_cleanup_queue(&host->oob_q); + pci_free_consistent(pdev, CARM_SHM_SIZE, host->shm, host->shm_dma); +err_out_iounmap: + iounmap(host->mmio); +err_out_kfree: + kfree(host); +err_out_regions: + pci_release_regions(pdev); +err_out: + pci_disable_device(pdev); + return rc; +} + +static void carm_remove_one (struct pci_dev *pdev) +{ + struct carm_host *host = pci_get_drvdata(pdev); + + if (!host) { + printk(KERN_ERR PFX "BUG: no host data for PCI(%s)\n", + pci_name(pdev)); + return; + } + + free_irq(pdev->irq, host); + carm_stop_tasklets(host); + carm_free_disks(host); + unregister_blkdev(host->major, host->name); + if (host->major == 160) + clear_bit(0, &carm_major_alloc); + else if (host->major == 161) + clear_bit(1, &carm_major_alloc); + blk_cleanup_queue(&host->oob_q); + pci_free_consistent(pdev, CARM_SHM_SIZE, host->shm, host->shm_dma); + iounmap(host->mmio); + kfree(host); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} + +static int __init carm_init(void) +{ + return pci_module_init(&carm_driver); +} + +static void __exit carm_exit(void) +{ + pci_unregister_driver(&carm_driver); +} + +module_init(carm_init); +module_exit(carm_exit); + + diff -urN linux-2.4.26/drivers/bluetooth/Makefile.lib linux-2.4.27/drivers/bluetooth/Makefile.lib --- linux-2.4.26/drivers/bluetooth/Makefile.lib 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.27/drivers/bluetooth/Makefile.lib 2004-08-07 16:26:04.680347846 -0700 @@ -1 +1,2 @@ -obj-$(CONFIG_BLUEZ_HCIBFUSB) += firmware_class.o +obj-$(CONFIG_BLUEZ_HCIBFUSB) += firmware_class.o +obj-$(CONFIG_BLUEZ_HCIBT3C) += firmware_class.o diff -urN linux-2.4.26/drivers/bluetooth/bfusb.c linux-2.4.27/drivers/bluetooth/bfusb.c --- linux-2.4.26/drivers/bluetooth/bfusb.c 2003-11-28 10:26:19.000000000 -0800 +++ linux-2.4.27/drivers/bluetooth/bfusb.c 2004-08-07 16:26:04.681347887 -0700 @@ -359,11 +359,11 @@ BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len); - if (!test_bit(HCI_RUNNING, &bfusb->hdev.flags)) - return; - read_lock(&bfusb->lock); + if (!test_bit(HCI_RUNNING, &bfusb->hdev.flags)) + goto unlock; + if (urb->status || !count) goto resubmit; @@ -414,6 +414,7 @@ bfusb->hdev.name, urb, err); } +unlock: read_unlock(&bfusb->lock); } diff -urN linux-2.4.26/drivers/bluetooth/bluecard_cs.c linux-2.4.27/drivers/bluetooth/bluecard_cs.c --- linux-2.4.26/drivers/bluetooth/bluecard_cs.c 2002-11-28 15:53:12.000000000 -0800 +++ linux-2.4.27/drivers/bluetooth/bluecard_cs.c 2004-08-07 16:26:04.682347928 -0700 @@ -803,6 +803,9 @@ unsigned int iobase = info->link.io.BasePort1; struct hci_dev *hdev = &(info->hdev); + if (info->link.state & DEV_CONFIG_PENDING) + return -ENODEV; + bluecard_hci_close(hdev); clear_bit(CARD_READY, &(info->hw_state)); diff -urN linux-2.4.26/drivers/bluetooth/bt3c_cs.c linux-2.4.27/drivers/bluetooth/bt3c_cs.c --- linux-2.4.26/drivers/bluetooth/bt3c_cs.c 2002-11-28 15:53:12.000000000 -0800 +++ linux-2.4.27/drivers/bluetooth/bt3c_cs.c 2004-08-07 16:26:04.683347969 -0700 @@ -24,8 +24,6 @@ #include #include -#define __KERNEL_SYSCALLS__ - #include #include #include @@ -48,6 +46,8 @@ #include #include +#include + #include #include #include @@ -485,78 +485,101 @@ -/* ======================== User mode firmware loader ======================== */ +/* ======================== Card services HCI interaction ======================== */ -#define FW_LOADER "/sbin/bluefw" -static int errno; +static int bt3c_load_firmware(bt3c_info_t *info, unsigned char *firmware, int count) +{ + char *ptr = (char *) firmware; + char b[9]; + unsigned int iobase, size, addr, fcs, tmp; + int i, err = 0; + iobase = info->link.io.BasePort1; -static int bt3c_fw_loader_exec(void *dev) -{ - char *argv[] = { FW_LOADER, "pccard", dev, NULL }; - char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; - int err; + /* Reset */ - err = exec_usermodehelper(FW_LOADER, argv, envp); - if (err) - printk(KERN_WARNING "bt3c_cs: Failed to exec \"%s pccard %s\".\n", FW_LOADER, (char *)dev); + bt3c_io_write(iobase, 0x8040, 0x0404); + bt3c_io_write(iobase, 0x8040, 0x0400); - return err; -} + udelay(1); + bt3c_io_write(iobase, 0x8040, 0x0404); -static int bt3c_firmware_load(bt3c_info_t *info) -{ - sigset_t tmpsig; - char dev[16]; - pid_t pid; - int result; + udelay(17); - /* Check if root fs is mounted */ - if (!current->fs->root) { - printk(KERN_WARNING "bt3c_cs: Root filesystem is not mounted.\n"); - return -EPERM; - } + /* Load */ - sprintf(dev, "%04x", info->link.io.BasePort1); + while (count) { + if (ptr[0] != 'S') { + printk(KERN_WARNING "bt3c_cs: Bad address in firmware.\n"); + err = -EFAULT; + goto error; + } - pid = kernel_thread(bt3c_fw_loader_exec, (void *)dev, 0); - if (pid < 0) { - printk(KERN_WARNING "bt3c_cs: Forking of kernel thread failed (errno=%d).\n", -pid); - return pid; - } + memset(b, 0, sizeof(b)); + memcpy(b, ptr + 2, 2); + size = simple_strtol(b, NULL, 16); + + memset(b, 0, sizeof(b)); + memcpy(b, ptr + 4, 8); + addr = simple_strtol(b, NULL, 16); + + memset(b, 0, sizeof(b)); + memcpy(b, ptr + (size * 2) + 2, 2); + fcs = simple_strtol(b, NULL, 16); + + memset(b, 0, sizeof(b)); + for (tmp = 0, i = 0; i < size; i++) { + memcpy(b, ptr + (i * 2) + 2, 2); + tmp += simple_strtol(b, NULL, 16); + } - /* Block signals, everything but SIGKILL/SIGSTOP */ - spin_lock_irq(¤t->sigmask_lock); - tmpsig = current->blocked; - siginitsetinv(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP)); - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); + if (((tmp + fcs) & 0xff) != 0xff) { + printk(KERN_WARNING "bt3c_cs: Checksum error in firmware.\n"); + err = -EILSEQ; + goto error; + } - result = waitpid(pid, NULL, __WCLONE); + if (ptr[1] == '3') { + bt3c_address(iobase, addr); - /* Allow signals again */ - spin_lock_irq(¤t->sigmask_lock); - current->blocked = tmpsig; - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); + memset(b, 0, sizeof(b)); + for (i = 0; i < (size - 4) / 2; i++) { + memcpy(b, ptr + (i * 4) + 12, 4); + tmp = simple_strtol(b, NULL, 16); + bt3c_put(iobase, tmp); + } + } - if (result != pid) { - printk(KERN_WARNING "bt3c_cs: Waiting for pid %d failed (errno=%d).\n", pid, -result); - return -result; + ptr += (size * 2) + 6; + count -= (size * 2) + 6; } - return 0; -} + udelay(17); + /* Boot */ + bt3c_address(iobase, 0x3000); + outb(inb(iobase + CONTROL) | 0x40, iobase + CONTROL); -/* ======================== Card services HCI interaction ======================== */ +error: + udelay(17); + + /* Clear */ + + bt3c_io_write(iobase, 0x7006, 0x0000); + bt3c_io_write(iobase, 0x7005, 0x0000); + bt3c_io_write(iobase, 0x7001, 0x0000); + + return err; +} int bt3c_open(bt3c_info_t *info) { + const struct firmware *firmware; + char device[16]; struct hci_dev *hdev; int err; @@ -570,8 +593,22 @@ /* Load firmware */ - if ((err = bt3c_firmware_load(info)) < 0) + snprintf(device, sizeof(device), "bt3c%4.4x", info->link.io.BasePort1); + + err = request_firmware(&firmware, "BT3CPCC.bin", device); + if (err < 0) { + printk(KERN_WARNING "bt3c_cs: Firmware request failed.\n"); return err; + } + + err = bt3c_load_firmware(info, firmware->data, firmware->size); + + release_firmware(firmware); + + if (err < 0) { + printk(KERN_WARNING "bt3c_cs: Firmware loading failed.\n"); + return err; + } /* Timeout before it is safe to send the first HCI packet */ @@ -606,6 +643,9 @@ { struct hci_dev *hdev = &(info->hdev); + if (info->link.state & DEV_CONFIG_PENDING) + return -ENODEV; + bt3c_hci_close(hdev); if (hci_unregister_dev(hdev) < 0) diff -urN linux-2.4.26/drivers/bluetooth/btuart_cs.c linux-2.4.27/drivers/bluetooth/btuart_cs.c --- linux-2.4.26/drivers/bluetooth/btuart_cs.c 2003-06-13 07:51:32.000000000 -0700 +++ linux-2.4.27/drivers/bluetooth/btuart_cs.c 2004-08-07 16:26:04.684348010 -0700 @@ -556,6 +556,9 @@ unsigned int iobase = info->link.io.BasePort1; struct hci_dev *hdev = &(info->hdev); + if (info->link.state & DEV_CONFIG_PENDING) + return -ENODEV; + btuart_hci_close(hdev); spin_lock_irqsave(&(info->lock), flags); diff -urN linux-2.4.26/drivers/bluetooth/dtl1_cs.c linux-2.4.27/drivers/bluetooth/dtl1_cs.c --- linux-2.4.26/drivers/bluetooth/dtl1_cs.c 2002-11-28 15:53:12.000000000 -0800 +++ linux-2.4.27/drivers/bluetooth/dtl1_cs.c 2004-08-07 16:26:04.685348051 -0700 @@ -535,6 +535,9 @@ unsigned int iobase = info->link.io.BasePort1; struct hci_dev *hdev = &(info->hdev); + if (info->link.state & DEV_CONFIG_PENDING) + return -ENODEV; + dtl1_hci_close(hdev); spin_lock_irqsave(&(info->lock), flags); diff -urN linux-2.4.26/drivers/bluetooth/hci_bcsp.c linux-2.4.27/drivers/bluetooth/hci_bcsp.c --- linux-2.4.26/drivers/bluetooth/hci_bcsp.c 2003-06-13 07:51:32.000000000 -0700 +++ linux-2.4.27/drivers/bluetooth/hci_bcsp.c 2004-08-07 16:26:04.685348051 -0700 @@ -34,7 +34,6 @@ #include #include -#include #include #include #include @@ -635,7 +634,8 @@ struct sk_buff *skb; unsigned long flags; - BT_ERR("Timeout, retransmitting %u pkts", bcsp->unack.qlen); + BT_DBG("hu %p retransmitting %u pkts", hu, bcsp->unack.qlen); + spin_lock_irqsave(&bcsp->unack.lock, flags); while ((skb = __skb_dequeue_tail(&bcsp->unack)) != NULL) { diff -urN linux-2.4.26/drivers/bluetooth/hci_ldisc.c linux-2.4.27/drivers/bluetooth/hci_ldisc.c --- linux-2.4.26/drivers/bluetooth/hci_ldisc.c 2003-06-13 07:51:32.000000000 -0700 +++ linux-2.4.27/drivers/bluetooth/hci_ldisc.c 2004-08-07 16:26:04.686348092 -0700 @@ -33,7 +33,6 @@ #include #include -#include #include #include #include diff -urN linux-2.4.26/drivers/bluetooth/hci_uart.h linux-2.4.27/drivers/bluetooth/hci_uart.h --- linux-2.4.26/drivers/bluetooth/hci_uart.h 2003-06-13 07:51:32.000000000 -0700 +++ linux-2.4.27/drivers/bluetooth/hci_uart.h 2004-08-07 16:26:04.686348092 -0700 @@ -35,11 +35,12 @@ #define HCIUARTGETPROTO _IOR('U', 201, int) /* UART protocols */ -#define HCI_UART_MAX_PROTO 3 +#define HCI_UART_MAX_PROTO 4 #define HCI_UART_H4 0 #define HCI_UART_BCSP 1 -#define HCI_UART_NCSP 2 +#define HCI_UART_3WIRE 2 +#define HCI_UART_H4DS 3 #ifdef __KERNEL__ struct hci_uart; diff -urN linux-2.4.26/drivers/bluetooth/hci_usb.c linux-2.4.27/drivers/bluetooth/hci_usb.c --- linux-2.4.26/drivers/bluetooth/hci_usb.c 2004-04-14 06:05:29.000000000 -0700 +++ linux-2.4.27/drivers/bluetooth/hci_usb.c 2004-08-07 16:26:04.687348133 -0700 @@ -30,7 +30,7 @@ * * $Id: hci_usb.c,v 1.8 2002/07/18 17:23:09 maxk Exp $ */ -#define VERSION "2.5" +#define VERSION "2.7" #include #include @@ -76,14 +76,15 @@ /* AVM BlueFRITZ! USB v2.0 */ { USB_DEVICE(0x057c, 0x3800) }, - /* Ericsson with non-standard id */ - { USB_DEVICE(0x0bdb, 0x1002) }, + /* Bluetooth Ultraport Module from IBM */ + { USB_DEVICE(0x04bf, 0x030a) }, - /* ALPS Module with non-standard id */ + /* ALPS Modules with non-standard id */ + { USB_DEVICE(0x044e, 0x3001) }, { USB_DEVICE(0x044e, 0x3002) }, - /* Bluetooth Ultraport Module from IBM */ - { USB_DEVICE(0x04bf, 0x030a) }, + /* Ericsson with non-standard id */ + { USB_DEVICE(0x0bdb, 0x1002) }, { } /* Terminating entry */ }; @@ -97,9 +98,15 @@ /* Broadcom BCM2035 */ { USB_DEVICE(0x0a5c, 0x200a), driver_info: HCI_RESET }, + /* ISSC Bluetooth Adapter v3.1 */ + { USB_DEVICE(0x1131, 0x1001), driver_info: HCI_RESET }, + /* Digianswer device */ { USB_DEVICE(0x08fd, 0x0001), driver_info: HCI_DIGIANSWER }, + /* RTX Telecom based adapter with buggy SCO support */ + { USB_DEVICE(0x0400, 0x0807), driver_info: HCI_BROKEN_ISOC }, + { } /* Terminating entry */ }; @@ -699,11 +706,11 @@ BT_DBG("%s urb %p type %d status %d count %d flags %x", hdev->name, urb, _urb->type, urb->status, count, urb->transfer_flags); - if (!test_bit(HCI_RUNNING, &hdev->flags)) - return; - read_lock(&husb->completion_lock); + if (!test_bit(HCI_RUNNING, &hdev->flags)) + goto unlock; + if (urb->status || !count) goto resubmit; @@ -740,6 +747,8 @@ BT_DBG("%s urb %p type %d resubmit status %d", hdev->name, urb, _urb->type, err); } + +unlock: read_unlock(&husb->completion_lock); } @@ -876,7 +885,7 @@ } #ifdef CONFIG_BLUEZ_HCIUSB_SCO - if (!isoc_in_ep[1] || !isoc_out_ep[1]) { + if (id->driver_info & HCI_BROKEN_ISOC || !isoc_in_ep[1] || !isoc_out_ep[1]) { BT_DBG("Isoc endpoints not found"); isoc_iface = NULL; } diff -urN linux-2.4.26/drivers/bluetooth/hci_usb.h linux-2.4.27/drivers/bluetooth/hci_usb.h --- linux-2.4.26/drivers/bluetooth/hci_usb.h 2004-04-14 06:05:29.000000000 -0700 +++ linux-2.4.27/drivers/bluetooth/hci_usb.h 2004-08-07 16:26:04.688348174 -0700 @@ -40,6 +40,7 @@ #define HCI_IGNORE 0x01 #define HCI_RESET 0x02 #define HCI_DIGIANSWER 0x04 +#define HCI_BROKEN_ISOC 0x08 #define HCI_MAX_IFACE_NUM 3 diff -urN linux-2.4.26/drivers/char/ChangeLog linux-2.4.27/drivers/char/ChangeLog --- linux-2.4.26/drivers/char/ChangeLog 2002-11-28 15:53:12.000000000 -0800 +++ linux-2.4.27/drivers/char/ChangeLog 2004-08-07 16:26:04.689348216 -0700 @@ -1,3 +1,8 @@ +2002-09-21 Marek Michalkiewicz + + * parport_serial.c: Move from ../parport/ here, must be initialised + after serial.c for register_serial to work. + 2001-08-11 Tim Waugh * serial.c (get_pci_port): Deal with awkward Titan cards. diff -urN linux-2.4.26/drivers/char/Config.in linux-2.4.27/drivers/char/Config.in --- linux-2.4.26/drivers/char/Config.in 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.27/drivers/char/Config.in 2004-08-07 16:26:04.689348216 -0700 @@ -273,7 +273,6 @@ if [ "$CONFIG_SGI_IP22" = "y" ]; then dep_tristate ' Indy/I2 Hardware Watchdog' CONFIG_INDYDOG $CONFIG_SGI_IP22 fi - dep_tristate ' AMD 766/768 TCO Timer/Watchdog' CONFIG_AMD7XX_TCO $CONFIG_EXPERIMENTAL if [ "$CONFIG_8xx" = "y" ]; then tristate ' MPC8xx Watchdog Timer' CONFIG_8xx_WDT fi diff -urN linux-2.4.26/drivers/char/Makefile linux-2.4.27/drivers/char/Makefile --- linux-2.4.26/drivers/char/Makefile 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.27/drivers/char/Makefile 2004-08-07 16:26:04.690348257 -0700 @@ -171,6 +171,7 @@ obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o obj-$(CONFIG_SERIAL) += $(SERIAL) +obj-$(CONFIG_PARPORT_SERIAL) += parport_serial.o obj-$(CONFIG_SERIAL_HCDP) += hcdp_serial.o obj-$(CONFIG_SERIAL_21285) += serial_21285.o obj-$(CONFIG_SERIAL_SA1100) += serial_sa1100.o @@ -320,7 +321,6 @@ obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o -obj-$(CONFIG_AMD7XX_TCO) += amd7xx_tco.o obj-$(CONFIG_INDYDOG) += indydog.o obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o diff -urN linux-2.4.26/drivers/char/agp/agp.h linux-2.4.27/drivers/char/agp/agp.h --- linux-2.4.26/drivers/char/agp/agp.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.27/drivers/char/agp/agp.h 2004-08-07 16:26:04.691348298 -0700 @@ -316,6 +316,9 @@ #ifndef PCI_DEVICE_ID_ATI_RS200 #define PCI_DEVICE_ID_ATI_RS200 0xcab2 #endif +#ifndef PCI_DEVICE_ID_ATI_RS200_REV2 +#define PCI_DEVICE_ID_ATI_RS200_REV2 0xcbb2 +#endif #ifndef PCI_DEVICE_ID_ATI_RS250 #define PCI_DEVICE_ID_ATI_RS250 0xcab3 #endif diff -urN linux-2.4.26/drivers/char/agp/agpgart_be.c linux-2.4.27/drivers/char/agp/agpgart_be.c --- linux-2.4.26/drivers/char/agp/agpgart_be.c 2004-04-14 06:05:29.000000000 -0700 +++ linux-2.4.27/drivers/char/agp/agpgart_be.c 2004-08-07 16:26:04.695348462 -0700 @@ -5738,6 +5738,7 @@ if ((agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS100) || (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200) || + (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200_REV2) || (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200_B) || (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS250)) { pci_read_config_dword(agp_bridge.dev, ATI_RS100_APSIZE, &temp); @@ -5792,6 +5793,7 @@ if ((agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS100) || (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200) || + (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200_REV2) || (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200_B) || (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS250)) { pci_read_config_dword(agp_bridge.dev, ATI_RS100_APSIZE, &temp); @@ -5825,6 +5827,7 @@ if ((agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS100) || (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200) || + (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200_REV2) || (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200_B) || (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS250)) { pci_write_config_dword(agp_bridge.dev, ATI_RS100_IG_AGPMODE, 0x20000); @@ -5863,6 +5866,7 @@ /* Write back the previous size and disable gart translation */ if ((agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS100) || (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200) || + (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200_REV2) || (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS200_B) || (agp_bridge.dev->device == PCI_DEVICE_ID_ATI_RS250)) { pci_read_config_dword(agp_bridge.dev, ATI_RS100_APSIZE, &temp); @@ -6426,6 +6430,12 @@ "ATI", "IGP330/340/345/350/M", ati_generic_setup }, + { PCI_DEVICE_ID_ATI_RS200_REV2, + PCI_VENDOR_ID_ATI, + ATI_RS200, + "ATI", + "IGP345M (rev 2)", + ati_generic_setup }, { PCI_DEVICE_ID_ATI_RS200_B, PCI_VENDOR_ID_ATI, ATI_RS200, diff -urN linux-2.4.26/drivers/char/amd7xx_tco.c linux-2.4.27/drivers/char/amd7xx_tco.c --- linux-2.4.26/drivers/char/amd7xx_tco.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.27/drivers/char/amd7xx_tco.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,387 +0,0 @@ -/* - * AMD 766/768 TCO Timer Driver - * (c) Copyright 2002 Zwane Mwaikambo - * All Rights Reserved. - * - * Parts from; - * Hardware driver for the AMD 768 Random Number Generator (RNG) - * (c) Copyright 2001 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 version 2 - * as published by the Free Software Foundation. - * - * The author(s) of this software shall not be held liable for damages - * of any nature resulting due to the use of this software. This - * software is provided AS-IS with no warranties. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define AMDTCO_MODULE_VER "build 20021116" -#define AMDTCO_MODULE_NAME "amd7xx_tco" -#define PFX AMDTCO_MODULE_NAME ": " - -#define MAX_TIMEOUT 38 /* max of 38 seconds, although the system will only - * reset itself after the second timeout */ - -/* pmbase registers */ -#define TCO_RELOAD_REG 0x40 /* bits 0-5 are current count, 6-7 are reserved */ -#define TCO_INITVAL_REG 0x41 /* bits 0-5 are value to load, 6-7 are reserved */ -#define TCO_TIMEOUT_MASK 0x3f -#define TCO_STATUS1_REG 0x44 -#define TCO_STATUS2_REG 0x46 -#define NDTO_STS2 (1 << 1) /* we're interested in the second timeout */ -#define BOOT_STS (1 << 2) /* will be set if NDTO_STS2 was set before reboot */ -#define TCO_CTRL1_REG 0x48 -#define TCO_HALT (1 << 11) -#define NO_REBOOT (1 << 10) /* in DevB:3x48 */ - -static char banner[] __initdata = KERN_INFO PFX AMDTCO_MODULE_VER "\n"; -static int timeout = 38; -static u32 pmbase; /* PMxx I/O base */ -static struct pci_dev *dev; -static struct semaphore open_sem; -static spinlock_t amdtco_lock; /* only for device access */ -static int expect_close = 0; - -MODULE_PARM(timeout, "i"); -MODULE_PARM_DESC(timeout, "range is 0-38 seconds, default is 38"); - -static inline u8 seconds_to_ticks(int seconds) -{ - /* the internal timer is stored as ticks which decrement - * every 0.6 seconds */ - return (seconds * 10) / 6; -} - -static inline int ticks_to_seconds(u8 ticks) -{ - return (ticks * 6) / 10; -} - -static inline int amdtco_status(void) -{ - u16 reg; - int status = 0; - - reg = inb(pmbase+TCO_CTRL1_REG); - if ((reg & TCO_HALT) == 0) - status |= WDIOF_KEEPALIVEPING; - - reg = inb(pmbase+TCO_STATUS2_REG); - if (reg & BOOT_STS) - status |= WDIOF_CARDRESET; - - return status; -} - -static inline void amdtco_ping(void) -{ - outb(1, pmbase+TCO_RELOAD_REG); -} - -static inline int amdtco_gettimeout(void) -{ - u8 reg = inb(pmbase+TCO_RELOAD_REG) & TCO_TIMEOUT_MASK; - return ticks_to_seconds(reg); -} - -static inline void amdtco_settimeout(unsigned int timeout) -{ - u8 reg = seconds_to_ticks(timeout) & TCO_TIMEOUT_MASK; - outb(reg, pmbase+TCO_INITVAL_REG); -} - -static inline void amdtco_global_enable(void) -{ - u16 reg; - - spin_lock(&amdtco_lock); - - /* clear NO_REBOOT on DevB:3x48 p97 */ - pci_read_config_word(dev, 0x48, ®); - reg &= ~NO_REBOOT; - pci_write_config_word(dev, 0x48, reg); - - spin_unlock(&amdtco_lock); -} - -static inline void amdtco_enable(void) -{ - u16 reg; - - spin_lock(&amdtco_lock); - reg = inw(pmbase+TCO_CTRL1_REG); - reg &= ~TCO_HALT; - outw(reg, pmbase+TCO_CTRL1_REG); - spin_unlock(&amdtco_lock); -} - -static inline void amdtco_disable(void) -{ - u16 reg; - - spin_lock(&amdtco_lock); - reg = inw(pmbase+TCO_CTRL1_REG); - reg |= TCO_HALT; - outw(reg, pmbase+TCO_CTRL1_REG); - spin_unlock(&amdtco_lock); -} - -static int amdtco_fop_open(struct inode *inode, struct file *file) -{ - if (down_trylock(&open_sem)) - return -EBUSY; - -#ifdef CONFIG_WATCHDOG_NOWAYOUT - MOD_INC_USE_COUNT; -#endif - - if (timeout > MAX_TIMEOUT) - timeout = MAX_TIMEOUT; - - amdtco_disable(); - amdtco_settimeout(timeout); - amdtco_global_enable(); - amdtco_enable(); - amdtco_ping(); - printk(KERN_INFO PFX "Watchdog enabled, timeout = %ds of %ds\n", - amdtco_gettimeout(), timeout); - - return 0; -} - - -static int amdtco_fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - int new_timeout; - int tmp; - - static struct watchdog_info ident = { - options: WDIOF_SETTIMEOUT | WDIOF_CARDRESET, - identity: "AMD 766/768" - }; - - switch (cmd) { - default: - return -ENOTTY; - - case WDIOC_GETSUPPORT: - if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof ident)) - return -EFAULT; - return 0; - - case WDIOC_GETSTATUS: - return put_user(amdtco_status(), (int *)arg); - - case WDIOC_KEEPALIVE: - amdtco_ping(); - return 0; - - case WDIOC_SETTIMEOUT: - if (get_user(new_timeout, (int *)arg)) - return -EFAULT; - - if (new_timeout < 0) - return -EINVAL; - - if (new_timeout > MAX_TIMEOUT) - new_timeout = MAX_TIMEOUT; - - timeout = new_timeout; - amdtco_settimeout(timeout); - /* fall through and return the new timeout */ - - case WDIOC_GETTIMEOUT: - return put_user(amdtco_gettimeout(), (int *)arg); - - case WDIOC_SETOPTIONS: - if (copy_from_user(&tmp, (int *)arg, sizeof tmp)) - return -EFAULT; - - if (tmp & WDIOS_DISABLECARD) - amdtco_disable(); - - if (tmp & WDIOS_ENABLECARD) - amdtco_enable(); - - return 0; - } -} - - -static int amdtco_fop_release(struct inode *inode, struct file *file) -{ - if (expect_close) { - amdtco_disable(); - printk(KERN_INFO PFX "Watchdog disabled\n"); - } else { - amdtco_ping(); - printk(KERN_CRIT PFX "Unexpected close!, timeout in %d seconds\n", timeout); - } - - up(&open_sem); - return 0; -} - - -static ssize_t amdtco_fop_write(struct file *file, const char *data, size_t len, loff_t *ppos) -{ - if (ppos != &file->f_pos) - return -ESPIPE; - - if (len) { -#ifndef CONFIG_WATCHDOG_NOWAYOUT - size_t i; - char c; - expect_close = 0; - - for (i = 0; i != len; i++) { - if (get_user(c, data + i)) - return -EFAULT; - - if (c == 'V') - expect_close = 1; - } -#endif - amdtco_ping(); - } - - return len; -} - - -static int amdtco_notify_sys(struct notifier_block *this, unsigned long code, void *unused) -{ - if (code == SYS_DOWN || code == SYS_HALT) - amdtco_disable(); - - return NOTIFY_DONE; -} - - -static struct notifier_block amdtco_notifier = -{ - notifier_call: amdtco_notify_sys -}; - -static struct file_operations amdtco_fops = -{ - owner: THIS_MODULE, - write: amdtco_fop_write, - ioctl: amdtco_fop_ioctl, - open: amdtco_fop_open, - release: amdtco_fop_release -}; - -static struct miscdevice amdtco_miscdev = -{ - minor: WATCHDOG_MINOR, - name: "watchdog", - fops: &amdtco_fops -}; - -static struct pci_device_id amdtco_pci_tbl[] __initdata = { - { 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, }, - { 0, } -}; - -MODULE_DEVICE_TABLE (pci, amdtco_pci_tbl); - -static int __init amdtco_init(void) -{ - int ret; - - sema_init(&open_sem, 1); - spin_lock_init(&amdtco_lock); - - pci_for_each_dev(dev) { - if (pci_match_device (amdtco_pci_tbl, dev) != NULL) - goto found_one; - } - - return -ENODEV; - -found_one: - - if ((ret = register_reboot_notifier(&amdtco_notifier))) { - printk(KERN_ERR PFX "Unable to register reboot notifier err = %d\n", ret); - goto out_clean; - } - - if ((ret = misc_register(&amdtco_miscdev))) { - printk(KERN_ERR PFX "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR); - goto out_unreg_reboot; - } - - pci_read_config_dword(dev, 0x58, &pmbase); - pmbase &= 0x0000FF00; - - if (pmbase == 0) { - printk (KERN_ERR PFX "power management base not set\n"); - ret = -EIO; - goto out_unreg_misc; - } - - /* ret = 0; */ - printk(banner); - goto out_clean; - -out_unreg_misc: - misc_deregister(&amdtco_miscdev); -out_unreg_reboot: - unregister_reboot_notifier(&amdtco_notifier); -out_clean: - return ret; -} - -static void __exit amdtco_exit(void) -{ - misc_deregister(&amdtco_miscdev); - unregister_reboot_notifier(&amdtco_notifier); -} - - -#ifndef MODULE -static int __init amdtco_setup(char *str) -{ - int ints[4]; - - str = get_options (str, ARRAY_SIZE(ints), ints); - if (ints[0] > 0) - timeout = ints[1]; - - if (!timeout || timeout > 38) - timeout = MAX_TIMEOUT; - - return 1; -} - -__setup("amd7xx_tco=", amdtco_setup); -#endif - -module_init(amdtco_init); -module_exit(amdtco_exit); - -MODULE_AUTHOR("Zwane Mwaikambo "); -MODULE_DESCRIPTION("AMD 766/768 TCO Timer Driver"); -MODULE_LICENSE("GPL"); -EXPORT_NO_SYMBOLS; - diff -urN linux-2.4.26/drivers/char/drm/drmP.h linux-2.4.27/drivers/char/drm/drmP.h --- linux-2.4.26/drivers/char/drm/drmP.h 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.27/drivers/char/drm/drmP.h 2004-08-07 16:26:04.700348668 -0700 @@ -52,6 +52,7 @@ #include #include #include /* For (un)lock_kernel */ +#include /* for cmpxchg() */ #include #include #if defined(__alpha__) || defined(__powerpc__) @@ -174,38 +175,7 @@ (unsigned long)_n_, sizeof(*(ptr))); \ }) -#elif __i386__ -static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, - unsigned long new, int size) -{ - unsigned long prev; - switch (size) { - case 1: - __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2" - : "=a"(prev) - : "q"(new), "m"(*__xg(ptr)), "0"(old) - : "memory"); - return prev; - case 2: - __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2" - : "=a"(prev) - : "q"(new), "m"(*__xg(ptr)), "0"(old) - : "memory"); - return prev; - case 4: - __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2" - : "=a"(prev) - : "q"(new), "m"(*__xg(ptr)), "0"(old) - : "memory"); - return prev; - } - return old; -} - -#define cmpxchg(ptr,o,n) \ - ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o), \ - (unsigned long)(n),sizeof(*(ptr)))) -#endif /* i386 & alpha */ +#endif /* alpha */ #endif #define __REALLY_HAVE_SG (__HAVE_SG) diff -urN linux-2.4.26/drivers/char/drm/sis_mm.c linux-2.4.27/drivers/char/drm/sis_mm.c --- linux-2.4.26/drivers/char/drm/sis_mm.c 2002-11-28 15:53:12.000000000 -0800 +++ linux-2.4.27/drivers/char/drm/sis_mm.c 2004-08-07 16:26:04.701348709 -0700 @@ -120,7 +120,7 @@ return -1; } - sis_free(fb.free); + sis_free((u32)fb.free); if(!del_alloc_set(fb.context, VIDEO_TYPE, fb.free)) retval = -1; diff -urN linux-2.4.26/drivers/char/i8k.c linux-2.4.27/drivers/char/i8k.c --- linux-2.4.26/drivers/char/i8k.c 2002-11-28 15:53:12.000000000 -0800 +++ linux-2.4.27/drivers/char/i8k.c 2004-08-07 16:26:04.701348709 -0700 @@ -493,6 +493,7 @@ static ssize_t i8k_read(struct file *f, char *buffer, size_t len, loff_t *fpos) { + loff_t pos = *fpos; int n; char info[128]; @@ -501,19 +502,19 @@ return n; } - if (*fpos >= n) { + if (pos != (unsigned)pos || pos >= n) { return 0; } - if ((*fpos + len) >= n) { - len = n - *fpos; + if (len >= n - pos) { + len = n - pos; } if (copy_to_user(buffer, info, len) != 0) { return -EFAULT; } - *fpos += len; + *fpos = pos + len; return len; } diff -urN linux-2.4.26/drivers/char/istallion.c linux-2.4.27/drivers/char/istallion.c --- linux-2.4.26/drivers/char/istallion.c 2002-08-02 17:39:43.000000000 -0700 +++ linux-2.4.27/drivers/char/istallion.c 2004-08-07 16:26:04.705348873 -0700 @@ -4854,6 +4854,7 @@ void *memptr; stlibrd_t *brdp; int brdnr, size, n; + loff_t pos = *offp; #if DEBUG printk(KERN_DEBUG "stli_memread(fp=%x,buf=%x,count=%x,offp=%x)\n", @@ -4868,25 +4869,26 @@ return(-ENODEV); if (brdp->state == 0) return(-ENODEV); - if (fp->f_pos >= brdp->memsize) + if (pos != (unsigned)pos || pos >= brdp->memsize) return(0); - size = MIN(count, (brdp->memsize - fp->f_pos)); + size = MIN(count, (brdp->memsize - pos)); save_flags(flags); cli(); EBRDENABLE(brdp); while (size > 0) { - memptr = (void *) EBRDGETMEMPTR(brdp, fp->f_pos); - n = MIN(size, (brdp->pagesize - (((unsigned long) fp->f_pos) % brdp->pagesize))); + memptr = (void *) EBRDGETMEMPTR(brdp, pos); + n = MIN(size, (brdp->pagesize - (((unsigned long) pos) % brdp->pagesize))); if (copy_to_user(buf, memptr, n)) { count = -EFAULT; goto out; } - fp->f_pos += n; + pos += n; buf += n; size -= n; } + *offp = pos; out: EBRDDISABLE(brdp); restore_flags(flags); @@ -4909,6 +4911,7 @@ stlibrd_t *brdp; char *chbuf; int brdnr, size, n; + loff_t pos = *offp; #if DEBUG printk(KERN_DEBUG "stli_memwrite(fp=%x,buf=%x,count=%x,offp=%x)\n", @@ -4923,26 +4926,27 @@ return(-ENODEV); if (brdp->state == 0) return(-ENODEV); - if (fp->f_pos >= brdp->memsize) + if (pos != (unsigned)pos || pos >= brdp->memsize) return(0); chbuf = (char *) buf; - size = MIN(count, (brdp->memsize - fp->f_pos)); + size = MIN(count, (brdp->memsize - pos)); save_flags(flags); cli(); EBRDENABLE(brdp); while (size > 0) { - memptr = (void *) EBRDGETMEMPTR(brdp, fp->f_pos); - n = MIN(size, (brdp->pagesize - (((unsigned long) fp->f_pos) % brdp->pagesize))); + memptr = (void *) EBRDGETMEMPTR(brdp, pos); + n = MIN(size, (brdp->pagesize - (((unsigned long) pos) % brdp->pagesize))); if (copy_from_user(memptr, chbuf, n)) { count = -EFAULT; goto out; } - fp->f_pos += n; + pos += n; chbuf += n; size -= n; } + *offp = pos; out: EBRDDISABLE(brdp); restore_flags(flags); diff -urN linux-2.4.26/drivers/char/mem.c linux-2.4.27/drivers/char/mem.c --- linux-2.4.26/drivers/char/mem.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.27/drivers/char/mem.c 2004-08-07 16:26:04.715349284 -0700 @@ -64,7 +64,7 @@ if (copy_from_user(p, buf, count)) return -EFAULT; written += count; - *ppos += written; + *ppos = realp + written; return written; } @@ -105,7 +105,7 @@ if (copy_to_user(buf, __va(p), count)) return -EFAULT; read += count; - *ppos += read; + *ppos = p + read; return read; } diff -urN linux-2.4.26/drivers/char/nvram.c linux-2.4.27/drivers/char/nvram.c --- linux-2.4.26/drivers/char/nvram.c 2003-06-13 07:51:33.000000000 -0700 +++ linux-2.4.27/drivers/char/nvram.c 2004-08-07 16:26:04.716349325 -0700 @@ -252,9 +252,13 @@ nvram_read(struct file *file, char *buf, size_t count, loff_t *ppos) { unsigned char contents[NVRAM_BYTES]; - unsigned i = *ppos; + loff_t n = *ppos; + unsigned i = n; unsigned char *tmp; + if (i != n || i >= NVRAM_BYTES) + return 0; + spin_lock_irq(&rtc_lock); if (!__nvram_check_checksum()) @@ -281,10 +285,14 @@ nvram_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { unsigned char contents[NVRAM_BYTES]; - unsigned i = *ppos; + loff_t n = *ppos; + unsigned i = n; unsigned char *tmp; int len; + if (i != n || i >= NVRAM_BYTES) + return 0; + len = (NVRAM_BYTES - i) < count ? (NVRAM_BYTES - i) : count; if (copy_from_user(contents, buf, len)) return -EFAULT; diff -urN linux-2.4.26/drivers/char/nwflash.c linux-2.4.27/drivers/char/nwflash.c --- linux-2.4.26/drivers/char/nwflash.c 2001-10-12 13:48:42.000000000 -0700 +++ linux-2.4.27/drivers/char/nwflash.c 2004-08-07 16:26:04.717349366 -0700 @@ -133,7 +133,8 @@ static ssize_t flash_read(struct file *file, char *buf, size_t size, loff_t * ppos) { - unsigned long p = *ppos; + loff_t n = *ppos; + unsigned long p = n; unsigned int count = size; int ret = 0; @@ -144,7 +145,7 @@ if (count) ret = -ENXIO; - if (p < gbFlashSize) { + if (n == p && p < gbFlashSize) { if (count > gbFlashSize - p) count = gbFlashSize - p; @@ -157,7 +158,7 @@ ret = copy_to_user(buf, (void *)(FLASH_BASE + p), count); if (ret == 0) { ret = count; - *ppos += count; + *ppos = p + count; } up(&nwflash_sem); } @@ -166,7 +167,8 @@ static ssize_t flash_write(struct file *file, const char *buf, size_t size, loff_t * ppos) { - unsigned long p = *ppos; + loff_t n = *ppos; + unsigned long p = n; unsigned int count = size; int written; int nBlock, temp, rc; @@ -185,7 +187,7 @@ /* * check for out of range pos or count */ - if (p >= gbFlashSize) + if (p != n || p >= gbFlashSize) return count ? -ENXIO : 0; if (count > gbFlashSize - p) @@ -274,7 +276,7 @@ p += rc; buf += rc; written += rc; - *ppos += rc; + *ppos = p; if (flashdebug) printk(KERN_DEBUG "flash_write: written 0x%X bytes OK.\n", written); diff -urN linux-2.4.26/drivers/char/parport_serial.c linux-2.4.27/drivers/char/parport_serial.c --- linux-2.4.26/drivers/char/parport_serial.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.27/drivers/char/parport_serial.c 2004-08-07 16:26:04.718349407 -0700 @@ -0,0 +1,436 @@ +/* + * Support for common PCI multi-I/O cards (which is most of them) + * + * Copyright (C) 2001 Tim Waugh + * + * 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. + * + * + * Multi-function PCI cards are supposed to present separate logical + * devices on the bus. A common thing to do seems to be to just use + * one logical device with lots of base address registers for both + * parallel ports and serial ports. This driver is for dealing with + * that. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +enum parport_pc_pci_cards { + titan_110l = 0, + titan_210l, + netmos_9735, + netmos_9835, + avlab_1s1p, + avlab_1s1p_650, + avlab_1s1p_850, + avlab_1s2p, + avlab_1s2p_650, + avlab_1s2p_850, + avlab_2s1p, + avlab_2s1p_650, + avlab_2s1p_850, + siig_1s1p_10x, + siig_2s1p_10x, + siig_2p1s_20x, + siig_1s1p_20x, + siig_2s1p_20x, +}; + + +/* each element directly indexed from enum list, above */ +static struct parport_pc_pci { + int numports; + struct { /* BAR (base address registers) numbers in the config + space header */ + int lo; + int hi; /* -1 if not there, >6 for offset-method (max + BAR is 6) */ + } addr[4]; + + /* If set, this is called immediately after pci_enable_device. + * If it returns non-zero, no probing will take place and the + * ports will not be used. */ + int (*preinit_hook) (struct pci_dev *pdev, int autoirq, int autodma); + + /* If set, this is called after probing for ports. If 'failed' + * is non-zero we couldn't use any of the ports. */ + void (*postinit_hook) (struct pci_dev *pdev, int failed); +} cards[] __devinitdata = { + /* titan_110l */ { 1, { { 3, -1 }, } }, + /* titan_210l */ { 1, { { 3, -1 }, } }, + /* netmos_9735 (not tested) */ { 1, { { 2, -1 }, } }, + /* netmos_9835 */ { 1, { { 2, -1 }, } }, + /* avlab_1s1p */ { 1, { { 1, 2}, } }, + /* avlab_1s1p_650 */ { 1, { { 1, 2}, } }, + /* avlab_1s1p_850 */ { 1, { { 1, 2}, } }, + /* avlab_1s2p */ { 2, { { 1, 2}, { 3, 4 },} }, + /* avlab_1s2p_650 */ { 2, { { 1, 2}, { 3, 4 },} }, + /* avlab_1s2p_850 */ { 2, { { 1, 2}, { 3, 4 },} }, + /* avlab_2s1p */ { 1, { { 2, 3}, } }, + /* avlab_2s1p_650 */ { 1, { { 2, 3}, } }, + /* avlab_2s1p_850 */ { 1, { { 2, 3}, } }, + /* siig_1s1p_10x */ { 1, { { 3, 4 }, } }, + /* siig_2s1p_10x */ { 1, { { 4, 5 }, } }, + /* siig_2p1s_20x */ { 2, { { 1, 2 }, { 3, 4 }, } }, + /* siig_1s1p_20x */ { 1, { { 1, 2 }, } }, + /* siig_2s1p_20x */ { 1, { { 2, 3 }, } }, +}; + +static struct pci_device_id parport_serial_pci_tbl[] __devinitdata = { + /* PCI cards */ + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_110L, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_110l }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_210L, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_210l }, + { 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_AVLAB/Intek21 has another bunch of cards ...*/ + { 0x14db, 0x2110, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p}, + { 0x14db, 0x2111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p_650}, + { 0x14db, 0x2112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s1p_850}, + { 0x14db, 0x2140, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p}, + { 0x14db, 0x2141, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p_650}, + { 0x14db, 0x2142, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1s2p_850}, + { 0x14db, 0x2160, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p}, + { 0x14db, 0x2161, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p_650}, + { 0x14db, 0x2162, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2s1p_850}, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_10x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_10x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p1s_20x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1s1p_20x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x }, + + { 0, } /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl); + +struct pci_board_no_ids { + int flags; + int num_ports; + int base_baud; + int uart_offset; + int reg_shift; + int (*init_fn)(struct pci_dev *dev, struct pci_board_no_ids *board, + int enable); + int first_uart_offset; +}; + +static int __devinit siig10x_init_fn(struct pci_dev *dev, struct pci_board_no_ids *board, int enable) +{ + return pci_siig10x_fn(dev, NULL, enable); +} + +static int __devinit siig20x_init_fn(struct pci_dev *dev, struct pci_board_no_ids *board, int enable) +{ + return pci_siig20x_fn(dev, NULL, enable); +} + +static struct pci_board_no_ids pci_boards[] __devinitdata = { + /* + * PCI Flags, Number of Ports, Base (Maximum) Baud Rate, + * Offset to get to next UART's registers, + * Register shift to use for memory-mapped I/O, + * Initialization function, first UART offset + */ + +// Cards not tested are marked n/t +// If you have one of these cards and it works for you, please tell me.. + +/* titan_110l */ { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 1, 921600 }, +/* titan_210l */ { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600 }, +/* netmos_9735 (n/t)*/ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, +/* netmos_9835 */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, +/* avlab_1s1p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, +/* avlab_1s1p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, +/* avlab_1s1p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, +/* avlab_1s2p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, +/* avlab_1s2p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, +/* avlab_1s2p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, +/* avlab_2s1p (n/t) */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, +/* avlab_2s1p_650 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, +/* avlab_2s1p_850 (nt)*/{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, +/* siig_1s1p_10x */ { SPCI_FL_BASE2, 1, 460800, 0, 0, siig10x_init_fn }, +/* siig_2s1p_10x */ { SPCI_FL_BASE2, 1, 921600, 0, 0, siig10x_init_fn }, +/* siig_2p1s_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn }, +/* siig_1s1p_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn }, +/* siig_2s1p_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn }, +}; + +struct parport_serial_private { + int num_ser; + int line[20]; + struct pci_board_no_ids ser; + int num_par; + struct parport *port[PARPORT_MAX]; +}; + +static int __devinit get_pci_port (struct pci_dev *dev, + struct pci_board_no_ids *board, + struct serial_struct *req, + int idx) +{ + unsigned long port; + int base_idx; + int max_port; + int offset; + + base_idx = SPCI_FL_GET_BASE(board->flags); + if (board->flags & SPCI_FL_BASE_TABLE) + base_idx += idx; + + if (board->flags & SPCI_FL_REGION_SZ_CAP) { + max_port = pci_resource_len(dev, base_idx) / 8; + if (idx >= max_port) + return 1; + } + + offset = board->first_uart_offset; + + /* Timedia/SUNIX uses a mixture of BARs and offsets */ + /* Ugh, this is ugly as all hell --- TYT */ + if(dev->vendor == PCI_VENDOR_ID_TIMEDIA ) /* 0x1409 */ + switch(idx) { + case 0: base_idx=0; + break; + case 1: base_idx=0; offset=8; + break; + case 2: base_idx=1; + break; + case 3: base_idx=1; offset=8; + break; + case 4: /* BAR 2*/ + case 5: /* BAR 3 */ + case 6: /* BAR 4*/ + case 7: base_idx=idx-2; /* BAR 5*/ + } + + port = pci_resource_start(dev, base_idx) + offset; + + if ((board->flags & SPCI_FL_BASE_TABLE) == 0) + port += idx * (board->uart_offset ? board->uart_offset : 8); + + if (pci_resource_flags (dev, base_idx) & IORESOURCE_IO) { + int high_bits_offset = ((sizeof(long)-sizeof(int))*8); + req->port = port; + if (high_bits_offset) + req->port_high = port >> high_bits_offset; + else + req->port_high = 0; + return 0; + } + req->io_type = SERIAL_IO_MEM; + req->iomem_base = ioremap(port, board->uart_offset); + req->iomem_reg_shift = board->reg_shift; + req->port = 0; + return req->iomem_base ? 0 : 1; +} + +/* Register the serial port(s) of a PCI card. */ +static int __devinit serial_register (struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct pci_board_no_ids *board = &pci_boards[id->driver_data]; + struct parport_serial_private *priv = pci_get_drvdata (dev); + struct serial_struct serial_req; + int base_baud; + int k; + int success = 0; + + priv->ser = *board; + if (board->init_fn && ((board->init_fn) (dev, board, 1) != 0)) + return 1; + + base_baud = board->base_baud; + if (!base_baud) + base_baud = BASE_BAUD; + memset (&serial_req, 0, sizeof (serial_req)); + + for (k = 0; k < board->num_ports; k++) { + int line; + serial_req.irq = dev->irq; + if (get_pci_port (dev, board, &serial_req, k)) + break; + serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE; + serial_req.baud_base = base_baud; + line = register_serial (&serial_req); + if (line < 0) { + printk (KERN_DEBUG + "parport_serial: register_serial failed\n"); + continue; + } + priv->line[priv->num_ser++] = line; + success = 1; + } + + return success ? 0 : 1; +} + +/* Register the parallel port(s) of a PCI card. */ +static int __devinit parport_register (struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct parport_serial_private *priv = pci_get_drvdata (dev); + int i = id->driver_data, n; + int success = 0; + + if (cards[i].preinit_hook && + cards[i].preinit_hook (dev, PARPORT_IRQ_NONE, PARPORT_DMA_NONE)) + return -ENODEV; + + for (n = 0; n < cards[i].numports; n++) { + struct parport *port; + int lo = cards[i].addr[n].lo; + int hi = cards[i].addr[n].hi; + unsigned long io_lo, io_hi; + io_lo = pci_resource_start (dev, lo); + io_hi = 0; + if ((hi >= 0) && (hi <= 6)) + io_hi = pci_resource_start (dev, hi); + else if (hi > 6) + io_lo += hi; /* Reinterpret the meaning of + "hi" as an offset (see SYBA + def.) */ + /* TODO: test if sharing interrupts works */ + printk (KERN_DEBUG "PCI parallel port detected: %04x:%04x, " + "I/O at %#lx(%#lx)\n", + parport_serial_pci_tbl[i].vendor, + parport_serial_pci_tbl[i].device, io_lo, io_hi); + port = parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE, + PARPORT_DMA_NONE, dev); + if (port) { + priv->port[priv->num_par++] = port; + success = 1; + } + } + + if (cards[i].postinit_hook) + cards[i].postinit_hook (dev, !success); + + return success ? 0 : 1; +} + +static int __devinit parport_serial_pci_probe (struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct parport_serial_private *priv; + int err; + + priv = kmalloc (sizeof *priv, GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->num_ser = priv->num_par = 0; + pci_set_drvdata (dev, priv); + + err = pci_enable_device (dev); + if (err) { + pci_set_drvdata (dev, NULL); + kfree (priv); + return err; + } + + if (parport_register (dev, id)) { + pci_set_drvdata (dev, NULL); + kfree (priv); + return -ENODEV; + } + + if (serial_register (dev, id)) { + int i; + for (i = 0; i < priv->num_par; i++) + parport_pc_unregister_port (priv->port[i]); + pci_set_drvdata (dev, NULL); + kfree (priv); + return -ENODEV; + } + + return 0; +} + +static void __devexit parport_serial_pci_remove (struct pci_dev *dev) +{ + struct parport_serial_private *priv = pci_get_drvdata (dev); + int i; + + // Serial ports + for (i = 0; i < priv->num_ser; i++) { + unregister_serial (priv->line[i]); + + if (priv->ser.init_fn) + (priv->ser.init_fn) (dev, &priv->ser, 0); + } + pci_set_drvdata (dev, NULL); + + // Parallel ports + for (i = 0; i < priv->num_par; i++) + parport_pc_unregister_port (priv->port[i]); + + kfree (priv); + return; +} + +static struct pci_driver parport_serial_pci_driver = { + name: "parport_serial", + id_table: parport_serial_pci_tbl, + probe: parport_serial_pci_probe, + remove: __devexit_p(parport_serial_pci_remove), +}; + + +static int __init parport_serial_init (void) +{ + return pci_module_init (&parport_serial_pci_driver); +} + +static void __exit parport_serial_exit (void) +{ + pci_unregister_driver (&parport_serial_pci_driver); + return; +} + +MODULE_AUTHOR("Tim Waugh "); +MODULE_DESCRIPTION("Driver for common parallel+serial multi-I/O PCI cards"); +MODULE_LICENSE("GPL"); + +module_init(parport_serial_init); +module_exit(parport_serial_exit); diff -urN linux-2.4.26/drivers/char/raw.c linux-2.4.27/drivers/char/raw.c --- linux-2.4.26/drivers/char/raw.c 2003-06-13 07:51:33.000000000 -0700 +++ linux-2.4.27/drivers/char/raw.c 2004-08-07 16:26:04.719349448 -0700 @@ -301,6 +301,7 @@ int minor; kdev_t dev; unsigned long limit; + loff_t off = *offp; int sector_size, sector_bits, sector_mask; int max_sectors; @@ -338,12 +339,12 @@ MAJOR(dev), MINOR(dev), limit); err = -EINVAL; - if ((*offp & sector_mask) || (size & sector_mask)) + if ((off & sector_mask) || (size & sector_mask)) goto out_free; err = 0; if (size) err = -ENXIO; - if ((*offp >> sector_bits) >= limit) + if ((off >> sector_bits) >= limit) goto out_free; /* @@ -353,7 +354,7 @@ */ transferred = 0; - blocknr = *offp >> sector_bits; + blocknr = off >> sector_bits; while (size > 0) { blocks = size >> sector_bits; if (blocks > max_sectors) @@ -390,7 +391,7 @@ } if (transferred) { - *offp += transferred; + *offp = off + transferred; err = transferred; } diff -urN linux-2.4.26/drivers/char/sysrq.c linux-2.4.27/drivers/char/sysrq.c --- linux-2.4.26/drivers/char/sysrq.c 2003-08-25 04:44:41.000000000 -0700 +++ linux-2.4.27/drivers/char/sysrq.c 2004-08-07 16:26:04.720349489 -0700 @@ -365,7 +365,7 @@ /* v */ NULL, /* w */ NULL, /* x */ NULL, -/* w */ NULL, +/* y */ NULL, /* z */ NULL }; diff -urN linux-2.4.26/drivers/char/tipar.c linux-2.4.27/drivers/char/tipar.c --- linux-2.4.26/drivers/char/tipar.c 2004-02-18 05:36:31.000000000 -0800 +++ linux-2.4.27/drivers/char/tipar.c 2004-08-07 16:26:04.720349489 -0700 @@ -66,7 +66,7 @@ /* * Version Information */ -#define DRIVER_VERSION "1.18" +#define DRIVER_VERSION "1.19" #define DRIVER_AUTHOR "Romain Lievin " #define DRIVER_DESC "Device driver for TI/PC parallel link cables" #define DRIVER_LICENSE "GPL" @@ -124,7 +124,7 @@ /* ----- global defines ----------------------------------------------- */ -#define START(x) { x=jiffies+HZ/(timeout/10); } +#define START(x) { x = jiffies + (HZ * timeout) / 10; } #define WAIT(x) { \ if (time_before((x), jiffies)) return -1; \ if (need_resched()) schedule(); } @@ -366,11 +366,14 @@ switch (cmd) { case IOCTL_TIPAR_DELAY: - delay = (int)arg; //get_user(delay, &arg); - break; + delay = (int)arg; //get_user(delay, &arg); + break; case IOCTL_TIPAR_TIMEOUT: - timeout = (int)arg; //get_user(timeout, &arg); - break; + if (arg != 0) + timeout = (int)arg; + else + retval = -EINVAL; + break; default: retval = -ENOTTY; break; @@ -404,7 +407,10 @@ str = get_options(str, ARRAY_SIZE(ints), ints); if (ints[0] > 0) { - timeout = ints[1]; + if (ints[1] != 0) + timeout = ints[1]; + else + printk("tipar: wrong timeout value (0), using default value instead."); if (ints[0] > 1) { delay = ints[2]; } diff -urN linux-2.4.26/drivers/char/tpqic02.c linux-2.4.27/drivers/char/tpqic02.c --- linux-2.4.26/drivers/char/tpqic02.c 2002-11-28 15:53:12.000000000 -0800 +++ linux-2.4.27/drivers/char/tpqic02.c 2004-08-07 16:26:04.722349572 -0700 @@ -1818,6 +1818,7 @@ kdev_t dev = filp->f_dentry->d_inode->i_rdev; unsigned short flags = filp->f_flags; unsigned long bytes_todo, bytes_done, total_bytes_done = 0; + loff_t pos = *ppos; int stat; if (status_zombie == YES) { @@ -1898,6 +1899,7 @@ /*****************************/ if (bytes_todo == 0) { + *ppos = pos; return total_bytes_done; } @@ -1966,7 +1968,7 @@ if (bytes_done > 0) { status_bytes_rd = YES; buf += bytes_done; - *ppos += bytes_done; + pos += bytes_done; total_bytes_done += bytes_done; count -= bytes_done; } diff -urN linux-2.4.26/drivers/char/vc_screen.c linux-2.4.27/drivers/char/vc_screen.c --- linux-2.4.26/drivers/char/vc_screen.c 2001-09-16 21:22:40.000000000 -0700 +++ linux-2.4.27/drivers/char/vc_screen.c 2004-08-07 16:26:04.723349613 -0700 @@ -64,12 +64,25 @@ return size; } +/* We share this temporary buffer with the console write code + * so that we can easily avoid touching user space while holding the + * console spinlock. + */ +extern char con_buf[PAGE_SIZE]; +#define CON_BUF_SIZE PAGE_SIZE +extern struct semaphore con_buf_sem; + static loff_t vcs_lseek(struct file *file, loff_t offset, int orig) { - int size = vcs_size(file->f_dentry->d_inode); + int size; + + down(&con_buf_sem); + + size = vcs_size(file->f_dentry->d_inode); switch (orig) { default: + up(&con_buf_sem); return -EINVAL; case 2: offset += size; @@ -79,26 +92,22 @@ case 0: break; } - if (offset < 0 || offset > size) + if (offset < 0 || offset > size) { + up(&con_buf_sem); return -EINVAL; + } file->f_pos = offset; + up (&con_buf_sem); return file->f_pos; } -/* We share this temporary buffer with the console write code - * so that we can easily avoid touching user space while holding the - * console spinlock. - */ -extern char con_buf[PAGE_SIZE]; -#define CON_BUF_SIZE PAGE_SIZE -extern struct semaphore con_buf_sem; - static ssize_t vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; unsigned int currcons = MINOR(inode->i_rdev); - long pos = *ppos; + loff_t n; + unsigned pos; long viewed, attr, read; int col, maxcol; unsigned short *org = NULL; @@ -106,6 +115,9 @@ down(&con_buf_sem); + n = *ppos; + pos = n; + /* Select the proper current console and verify * sanity of the situation under the console lock. */ @@ -124,11 +136,10 @@ if (!vc_cons_allocated(currcons)) goto unlock_out; - ret = -EINVAL; - if (pos < 0) - goto unlock_out; read = 0; ret = 0; + if (pos != n) + goto unlock_out; while (count) { char *con_buf0, *con_buf_start; long this_round, size; @@ -244,16 +255,15 @@ acquire_console_sem(); if (ret) { - read += (orig_count - ret); ret = -EFAULT; - break; + goto unlock_out; } buf += orig_count; pos += orig_count; read += orig_count; count -= orig_count; } - *ppos += read; + *ppos = pos; if (read) ret = read; unlock_out: @@ -267,7 +277,8 @@ { struct inode *inode = file->f_dentry->d_inode; unsigned int currcons = MINOR(inode->i_rdev); - long pos = *ppos; + loff_t n; + unsigned pos; long viewed, attr, size, written; char *con_buf0; int col, maxcol; @@ -276,6 +287,9 @@ down(&con_buf_sem); + n = *ppos; + pos = n; + /* Select the proper current console and verify * sanity of the situation under the console lock. */ @@ -297,7 +311,7 @@ size = vcs_size(inode); ret = -EINVAL; - if (pos < 0 || pos > size) + if (pos != n || pos > size) goto unlock_out; if (count > size - pos) count = size - pos; @@ -435,7 +449,7 @@ if (org0) update_region(currcons, (unsigned long)(org0), org-org0); } - *ppos += written; + *ppos = pos; ret = written; unlock_out: diff -urN linux-2.4.26/drivers/gsc/eisa_eeprom.c linux-2.4.27/drivers/gsc/eisa_eeprom.c --- linux-2.4.26/drivers/gsc/eisa_eeprom.c 2002-11-28 15:53:12.000000000 -0800 +++ linux-2.4.27/drivers/gsc/eisa_eeprom.c 2004-08-07 16:26:04.733350024 -0700 @@ -34,24 +34,30 @@ unsigned char *tmp; ssize_t ret; int i; + loff_t n = *ppos; + unsigned pos = n; - if (*ppos >= HPEE_MAX_LENGTH) + if (n != pos || pos >= HPEE_MAX_LENGTH) return 0; - count = *ppos + count < HPEE_MAX_LENGTH ? count : HPEE_MAX_LENGTH - *ppos; + if (count > HPEE_MAX_LENGTH - pos) + count = HPEE_MAX_LENGTH - pos; + tmp = kmalloc(count, GFP_KERNEL); if (tmp) { for (i = 0; i < count; i++) - tmp[i] = gsc_readb(eeprom_addr+(*ppos)++); + tmp[i] = gsc_readb(eeprom_addr+(pos)++); if (copy_to_user (buf, tmp, count)) ret = -EFAULT; - else + else { ret = count; + *ppos = pos; + } kfree (tmp); } else ret = -ENOMEM; - + return ret; } diff -urN linux-2.4.26/drivers/hotplug/Config.in linux-2.4.27/drivers/hotplug/Config.in --- linux-2.4.26/drivers/hotplug/Config.in 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.27/drivers/hotplug/Config.in 2004-08-07 16:26:04.733350024 -0700 @@ -14,4 +14,11 @@ if [ "$CONFIG_ACPI_INTERPRETER" = "y" ]; then dep_tristate ' ACPI PCI Hotplug driver' CONFIG_HOTPLUG_PCI_ACPI $CONFIG_HOTPLUG_PCI fi +dep_tristate ' SHPC PCI Hotplug driver' CONFIG_HOTPLUG_PCI_SHPC $CONFIG_HOTPLUG_PCI +dep_mbool ' Use polling mechanism for hot-plug events (for testing purpose)' CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE $CONFIG_HOTPLUG_PCI_SHPC +if [ "$CONFIG_ACPI" = "n" ]; then +dep_mbool ' For AMD SHPC only: Use HRT for resource/configuration' CONFIG_HOTPLUG_PCI_SHPC_PHPRM_LEGACY $CONFIG_HOTPLUG_PCI_SHPC +fi +dep_tristate ' PCI Express Hotplug driver' CONFIG_HOTPLUG_PCI_PCIE $CONFIG_HOTPLUG_PCI +dep_mbool ' Use polling mechanism for hot-plug events (for testing purpose)' CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE $CONFIG_HOTPLUG_PCI_PCIE endmenu diff -urN linux-2.4.26/drivers/hotplug/Makefile linux-2.4.27/drivers/hotplug/Makefile --- linux-2.4.26/drivers/hotplug/Makefile 2003-08-25 04:44:41.000000000 -0700 +++ linux-2.4.27/drivers/hotplug/Makefile 2004-08-07 16:26:04.734350065 -0700 @@ -4,7 +4,7 @@ O_TARGET := vmlinux-obj.o -list-multi := cpqphp.o pci_hotplug.o ibmphp.o acpiphp.o +list-multi := cpqphp.o pci_hotplug.o ibmphp.o acpiphp.o shpchp.o pciehp.o export-objs := pci_hotplug_core.o pci_hotplug_util.o @@ -12,6 +12,8 @@ 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_SHPC) += shpchp.o +obj-$(CONFIG_HOTPLUG_PCI_PCIE) += pciehp.o pci_hotplug-objs := pci_hotplug_core.o \ pci_hotplug_util.o @@ -32,11 +34,36 @@ acpiphp_pci.o \ acpiphp_res.o +pciehp-objs := pciehp_core.o \ + pciehp_ctrl.o \ + pciehp_hpc.o \ + pciehp_pci.o +ifdef CONFIG_ACPI_INTERPRETER + pciehp-objs += pciehprm_acpi.o +else + pciehp-objs += pciehprm_nonacpi.o + EXTRA_CFLAGS += -D_LINUX -I$(TOPDIR)/drivers/acpi +endif + +shpchp-objs := shpchp_core.o \ + shpchp_ctrl.o \ + shpchp_hpc.o \ + shpchp_pci.o +ifdef CONFIG_ACPI_INTERPRETER + shpchp-objs += shpchprm_acpi.o + EXTRA_CFLAGS += -D_LINUX -I$(TOPDIR)/drivers/acpi +else + ifdef CONFIG_HOTPLUG_PCI_SHPC_PHPRM_LEGACY + shpchp-objs += shpchprm_legacy.o + else + shpchp-objs += shpchprm_nonacpi.o + endif +endif + ifeq ($(CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM),y) cpqphp-objs += cpqphp_nvram.o endif - include $(TOPDIR)/Rules.make pci_hotplug.o: $(pci_hotplug-objs) @@ -50,3 +77,10 @@ acpiphp.o: $(acpiphp_objs) $(LD) -r -o $@ $(acpiphp_objs) + +pciehp.o: $(pciehp-objs) + $(LD) -r -o $@ $(pciehp-objs) + +shpchp.o: $(shpchp-objs) + $(LD) -r -o $@ $(shpchp-objs) + diff -urN linux-2.4.26/drivers/hotplug/acpiphp.h linux-2.4.27/drivers/hotplug/acpiphp.h --- linux-2.4.26/drivers/hotplug/acpiphp.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.27/drivers/hotplug/acpiphp.h 2004-08-07 16:26:04.734350065 -0700 @@ -36,63 +36,7 @@ #include #include "pci_hotplug.h" -#if ACPI_CA_VERSION < 0x20020201 -/* until we get a new version of the ACPI driver for both ia32 and ia64 ... */ -#define acpi_util_eval_error(h,p,s) - -static acpi_status -acpi_evaluate_integer ( - acpi_handle handle, - acpi_string pathname, - acpi_object_list *arguments, - unsigned long *data) -{ - acpi_status status = AE_OK; - acpi_object element; - acpi_buffer buffer = {sizeof(acpi_object), &element}; - - if (!data) - return AE_BAD_PARAMETER; - - status = acpi_evaluate_object(handle, pathname, arguments, &buffer); - if (ACPI_FAILURE(status)) { - acpi_util_eval_error(handle, pathname, status); - return status; - } - - if (element.type != ACPI_TYPE_INTEGER) { - acpi_util_eval_error(handle, pathname, AE_BAD_DATA); - return AE_BAD_DATA; - } - - *data = element.integer.value; - - return AE_OK; -} -#else /* ACPI_CA_VERSION < 0x20020201 */ #include -#endif - -/* compatibility stuff for ACPI CA */ -#ifndef ACPI_MEMORY_RANGE -#define ACPI_MEMORY_RANGE MEMORY_RANGE -#endif - -#ifndef ACPI_IO_RANGE -#define ACPI_IO_RANGE IO_RANGE -#endif - -#ifndef ACPI_BUS_NUMBER_RANGE -#define ACPI_BUS_NUMBER_RANGE BUS_NUMBER_RANGE -#endif - -#ifndef ACPI_PREFETCHABLE_MEMORY -#define ACPI_PREFETCHABLE_MEMORY PREFETCHABLE_MEMORY -#endif - -#ifndef ACPI_PRODUCER -#define ACPI_PRODUCER PRODUCER -#endif #define dbg(format, arg...) \ do { \ @@ -258,7 +202,7 @@ #define SLOT_POWEREDON (0x00000001) #define SLOT_ENABLED (0x00000002) -#define SLOT_MULTIFUNCTION (x000000004) +#define SLOT_MULTIFUNCTION (0x00000004) /* function flags */ @@ -269,8 +213,6 @@ #define FUNC_HAS_PS2 (0x00000040) #define FUNC_HAS_PS3 (0x00000080) -#define FUNC_EXISTS (0x10000000) /* to make sure we call _EJ0 only for existing funcs */ - /* function prototypes */ /* acpiphp_glue.c */ @@ -288,6 +230,7 @@ extern u8 acpiphp_get_attention_status (struct acpiphp_slot *slot); extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot); extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot); +extern u32 acpiphp_get_address (struct acpiphp_slot *slot); /* acpiphp_pci.c */ extern struct pci_dev *acpiphp_allocate_pcidev (struct pci_bus *pbus, int dev, int fn); diff -urN linux-2.4.26/drivers/hotplug/acpiphp_core.c linux-2.4.27/drivers/hotplug/acpiphp_core.c --- linux-2.4.26/drivers/hotplug/acpiphp_core.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.27/drivers/hotplug/acpiphp_core.c 2004-08-07 16:26:04.735350106 -0700 @@ -30,14 +30,14 @@ * */ -#include -#include +#include #include + +#include #include #include #include #include -#include #include "pci_hotplug.h" #include "acpiphp.h" @@ -73,6 +73,7 @@ static int get_attention_status (struct hotplug_slot *slot, u8 *value); static int get_latch_status (struct hotplug_slot *slot, u8 *value); static int get_adapter_status (struct hotplug_slot *slot, u8 *value); +static int get_address (struct hotplug_slot *slot, u32 *value); static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value); static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value); @@ -86,6 +87,7 @@ .get_attention_status = get_attention_status, .get_latch_status = get_latch_status, .get_adapter_status = get_adapter_status, + .get_address = get_address, .get_max_bus_speed = get_max_bus_speed, .get_cur_bus_speed = get_cur_bus_speed, }; @@ -322,6 +324,28 @@ } +/** + * get_address - get pci address of a slot + * @hotplug_slot: slot to get status + * @busdev: pointer to struct pci_busdev (seg, bus, dev) + * + */ +static int get_address (struct hotplug_slot *hotplug_slot, u32 *value) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + *value = acpiphp_get_address(slot->acpi_slot); + + return retval; +} + + /* return dummy value because ACPI doesn't provide any method... */ static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) { diff -urN linux-2.4.26/drivers/hotplug/acpiphp_glue.c linux-2.4.27/drivers/hotplug/acpiphp_glue.c --- linux-2.4.26/drivers/hotplug/acpiphp_glue.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.27/drivers/hotplug/acpiphp_glue.c 2004-08-07 16:26:04.737350188 -0700 @@ -26,12 +26,12 @@ * */ -#include -#include +#include #include + +#include #include #include -#include #include #include "pci_hotplug.h" @@ -389,12 +389,8 @@ static void decode_hpp(struct acpiphp_bridge *bridge) { acpi_status status; -#if ACPI_CA_VERSION < 0x20020201 - acpi_buffer buffer; -#else struct acpi_buffer buffer = { .length = ACPI_ALLOCATE_BUFFER, .pointer = NULL}; -#endif union acpi_object *package; int i; @@ -404,21 +400,7 @@ bridge->hpp.enable_SERR = 0; bridge->hpp.enable_PERR = 0; -#if ACPI_CA_VERSION < 0x20020201 - buffer.length = 0; - buffer.pointer = NULL; - - status = acpi_evaluate_object(bridge->handle, "_HPP", NULL, &buffer); - - if (status == AE_BUFFER_OVERFLOW) { - buffer.pointer = kmalloc(buffer.length, GFP_KERNEL); - if (!buffer.pointer) - return; - status = acpi_evaluate_object(bridge->handle, "_HPP", NULL, &buffer); - } -#else status = acpi_evaluate_object(bridge->handle, "_HPP", NULL, &buffer); -#endif if (ACPI_FAILURE(status)) { dbg("_HPP evaluation failed\n"); @@ -494,12 +476,8 @@ static void add_host_bridge (acpi_handle *handle, int seg, int bus) { acpi_status status; -#if ACPI_CA_VERSION < 0x20020201 - acpi_buffer buffer; -#else struct acpi_buffer buffer = { .length = ACPI_ALLOCATE_BUFFER, .pointer = NULL}; -#endif struct acpiphp_bridge *bridge; bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); @@ -522,22 +500,8 @@ /* decode resources */ -#if ACPI_CA_VERSION < 0x20020201 - buffer.length = 0; - buffer.pointer = NULL; - status = acpi_get_current_resources(handle, &buffer); - if (status == AE_BUFFER_OVERFLOW) { - buffer.pointer = kmalloc(buffer.length, GFP_KERNEL); - if (!buffer.pointer) - return; - status = acpi_get_current_resources(handle, &buffer); - } -#else - status = acpi_get_current_resources(handle, &buffer); -#endif - if (ACPI_FAILURE(status)) { err("failed to decode bridge resources\n"); kfree(bridge); @@ -819,7 +783,7 @@ struct list_head *l; int retval = 0; - /* is this already enabled? */ + /* if already enabled, just skip */ if (slot->flags & SLOT_POWEREDON) goto err_exit; @@ -827,14 +791,14 @@ func = list_entry(l, struct acpiphp_func, sibling); if (func->flags & FUNC_HAS_PS0) { - dbg("%s: executing _PS0 on %s\n", __FUNCTION__, - func->pci_dev->slot_name); + dbg("%s: executing _PS0\n", __FUNCTION__); status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL); if (ACPI_FAILURE(status)) { warn("%s: _PS0 failed\n", __FUNCTION__); retval = -1; goto err_exit; - } + } else + break; } } @@ -857,20 +821,21 @@ int retval = 0; - /* is this already enabled? */ + /* if already disabled, just skip */ if ((slot->flags & SLOT_POWEREDON) == 0) goto err_exit; list_for_each (l, &slot->funcs) { func = list_entry(l, struct acpiphp_func, sibling); - if (func->flags & (FUNC_HAS_PS3 | FUNC_EXISTS)) { + if (func->pci_dev && (func->flags & FUNC_HAS_PS3)) { status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); if (ACPI_FAILURE(status)) { warn("%s: _PS3 failed\n", __FUNCTION__); retval = -1; goto err_exit; - } + } else + break; } } @@ -878,20 +843,19 @@ func = list_entry(l, struct acpiphp_func, sibling); /* We don't want to call _EJ0 on non-existing functions. */ - if (func->flags & (FUNC_HAS_EJ0 | FUNC_EXISTS)) { + if (func->pci_dev && (func->flags & FUNC_HAS_EJ0)) { /* _EJ0 method take one argument */ arg_list.count = 1; arg_list.pointer = &arg; arg.type = ACPI_TYPE_INTEGER; arg.integer.value = 1; - status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL); if (ACPI_FAILURE(status)) { warn("%s: _EJ0 failed\n", __FUNCTION__); retval = -1; goto err_exit; - } - func->flags &= (~FUNC_EXISTS); + } else + break; } } @@ -973,8 +937,6 @@ retval = acpiphp_configure_function(func); if (retval) goto err_exit; - - func->flags |= FUNC_EXISTS; } slot->flags |= SLOT_ENABLED; @@ -1003,15 +965,12 @@ list_for_each (l, &slot->funcs) { func = list_entry(l, struct acpiphp_func, sibling); - if (func->pci_dev) { - if (acpiphp_unconfigure_function(func) == 0) { - func->pci_dev = NULL; - } else { + if (func->pci_dev) + if (acpiphp_unconfigure_function(func)) { err("failed to unconfigure device\n"); retval = -1; goto err_exit; } - } } slot->flags &= (~SLOT_ENABLED); @@ -1391,7 +1350,7 @@ up(&slot->crit_sect); goto err_exit; } - enabled++; + disabled++; } } else { /* if disabled but present, enable */ @@ -1402,7 +1361,7 @@ up(&slot->crit_sect); goto err_exit; } - disabled++; + enabled++; } } } @@ -1468,3 +1427,18 @@ return (sta == 0) ? 0 : 1; } + + +/* + * pci address (seg/bus/dev) + */ +u32 acpiphp_get_address (struct acpiphp_slot *slot) +{ + u32 address; + + address = ((slot->bridge->seg) << 16) | + ((slot->bridge->bus) << 8) | + slot->device; + + return address; +} diff -urN linux-2.4.26/drivers/hotplug/acpiphp_pci.c linux-2.4.27/drivers/hotplug/acpiphp_pci.c --- linux-2.4.26/drivers/hotplug/acpiphp_pci.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.27/drivers/hotplug/acpiphp_pci.c 2004-08-07 16:26:04.737350188 -0700 @@ -29,11 +29,11 @@ * */ -#include -#include +#include #include + +#include #include -#include #include "pci_hotplug.h" #include "acpiphp.h" @@ -78,8 +78,8 @@ if (bar & PCI_BASE_ADDRESS_SPACE_IO) { /* This is IO */ - len = bar & 0xFFFFFFFC; - len = ~len + 1; + len = bar & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF); + len = len & ~(len - 1); dbg("len in IO %x, BAR %d\n", len, count); @@ -340,8 +340,8 @@ if (len & PCI_BASE_ADDRESS_SPACE_IO) { /* This is IO */ base = bar & 0xFFFFFFFC; - len &= 0xFFFFFFFC; - len = ~len + 1; + len = len & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF); + len = len & ~(len - 1); dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1); @@ -465,8 +465,8 @@ if (len & PCI_BASE_ADDRESS_SPACE_IO) { /* This is IO */ base = bar & 0xFFFFFFFC; - len &= 0xFFFFFFFC; - len = ~len + 1; + len = len & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF); + len = len & ~(len - 1); dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1); diff -urN linux-2.4.26/drivers/hotplug/acpiphp_res.c linux-2.4.27/drivers/hotplug/acpiphp_res.c --- linux-2.4.26/drivers/hotplug/acpiphp_res.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.27/drivers/hotplug/acpiphp_res.c 2004-08-07 16:26:04.738350229 -0700 @@ -29,7 +29,7 @@ * */ -#include +#include #include #include @@ -39,7 +39,6 @@ #include #include #include -#include #include #include @@ -225,7 +224,7 @@ } /* End of too big on top end */ /* For IO make sure it's not in the ISA aliasing space */ - if (node->base & 0x300L) + if ((node->base & 0x300L) && !(node->base & 0xfffff000)) continue; /* If we got here, then it is the right size diff -urN linux-2.4.26/drivers/hotplug/pci_hotplug.h linux-2.4.27/drivers/hotplug/pci_hotplug.h --- linux-2.4.26/drivers/hotplug/pci_hotplug.h 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.27/drivers/hotplug/pci_hotplug.h 2004-08-07 16:26:04.739350270 -0700 @@ -36,15 +36,36 @@ PCI_SPEED_66MHz_PCIX = 0x02, PCI_SPEED_100MHz_PCIX = 0x03, PCI_SPEED_133MHz_PCIX = 0x04, + PCI_SPEED_66MHz_PCIX_ECC = 0x05, + PCI_SPEED_100MHz_PCIX_ECC = 0x06, + PCI_SPEED_133MHz_PCIX_ECC = 0x07, PCI_SPEED_66MHz_PCIX_266 = 0x09, PCI_SPEED_100MHz_PCIX_266 = 0x0a, PCI_SPEED_133MHz_PCIX_266 = 0x0b, PCI_SPEED_66MHz_PCIX_533 = 0x11, - PCI_SPEED_100MHz_PCIX_533 = 0X12, + PCI_SPEED_100MHz_PCIX_533 = 0x12, PCI_SPEED_133MHz_PCIX_533 = 0x13, PCI_SPEED_UNKNOWN = 0xff, }; +/* These values come from the PCI Express Spec */ +enum pcie_link_width { + PCIE_LNK_WIDTH_RESRV = 0x00, + PCIE_LNK_X1 = 0x01, + PCIE_LNK_X2 = 0x02, + PCIE_LNK_X4 = 0x04, + PCIE_LNK_X8 = 0x08, + PCIE_LNK_X12 = 0x0C, + PCIE_LNK_X16 = 0x10, + PCIE_LNK_X32 = 0x20, + PCIE_LNK_WIDTH_UNKNOWN = 0xFF, +}; + +enum pcie_link_speed { + PCIE_2PT5GB = 0x14, + PCIE_LNK_SPEED_UNKNOWN = 0xFF, +}; + struct hotplug_slot; struct hotplug_slot_core; @@ -69,6 +90,9 @@ * @get_adapter_status: Called to get see if an adapter is present in the slot or not. * If this field is NULL, the value passed in the struct hotplug_slot_info * will be used when this value is requested by a user. + * @get_address: Called to get pci address of a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. * @get_max_bus_speed: Called to get the max bus speed for a slot. * If this field is NULL, the value passed in the struct hotplug_slot_info * will be used when this value is requested by a user. @@ -91,6 +115,7 @@ int (*get_attention_status) (struct hotplug_slot *slot, u8 *value); int (*get_latch_status) (struct hotplug_slot *slot, u8 *value); int (*get_adapter_status) (struct hotplug_slot *slot, u8 *value); + int (*get_address) (struct hotplug_slot *slot, u32 *value); int (*get_max_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); int (*get_cur_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); }; @@ -101,6 +126,7 @@ * @attention_status: if the attention light is enabled or not (1/0) * @latch_status: if the latch (if any) is open or closed (1/0) * @adapter_present: if there is a pci board present in the slot or not (1/0) + * @address: (domain << 16 | bus << 8 | dev) * * Used to notify the hotplug pci core of the status of a specific slot. */ @@ -109,6 +135,7 @@ u8 attention_status; u8 latch_status; u8 adapter_status; + u32 address; enum pci_bus_speed max_bus_speed; enum pci_bus_speed cur_bus_speed; }; diff -urN linux-2.4.26/drivers/hotplug/pci_hotplug_core.c linux-2.4.27/drivers/hotplug/pci_hotplug_core.c --- linux-2.4.26/drivers/hotplug/pci_hotplug_core.c 2003-11-28 10:26:20.000000000 -0800 +++ linux-2.4.27/drivers/hotplug/pci_hotplug_core.c 2004-08-07 16:26:04.740350311 -0700 @@ -74,6 +74,7 @@ struct dentry *attention_dentry; struct dentry *latch_dentry; struct dentry *adapter_dentry; + struct dentry *address_dentry; struct dentry *test_dentry; struct dentry *max_bus_speed_dentry; struct dentry *cur_bus_speed_dentry; @@ -111,6 +112,7 @@ "66 MHz PCIX 533", /* 0x11 */ "100 MHz PCIX 533", /* 0x12 */ "133 MHz PCIX 533", /* 0x13 */ + "25 GBps PCI-E", /* 0x14 */ }; static int pcihpfs_statfs (struct super_block *sb, struct statfs *buf) @@ -312,6 +314,15 @@ llseek: default_file_lseek, }; +/* file ops for the "address" files */ +static ssize_t address_read_file (struct file *file, char *buf, size_t count, loff_t *offset); +static struct file_operations address_file_operations = { + read: address_read_file, + write: default_write_file, + open: default_open, + llseek: default_file_lseek, +}; + /* file ops for the "max bus speed" files */ static ssize_t max_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset); static struct file_operations max_bus_speed_file_operations = { @@ -566,6 +577,7 @@ GET_STATUS(attention_status, u8) GET_STATUS(latch_status, u8) GET_STATUS(adapter_status, u8) +GET_STATUS(address, u32) GET_STATUS(max_bus_speed, enum pci_bus_speed) GET_STATUS(cur_bus_speed, enum pci_bus_speed) @@ -604,7 +616,7 @@ retval = -EFAULT; goto exit; } - *offset += len; + *offset = len; retval = len; exit: @@ -715,7 +727,7 @@ retval = -EFAULT; goto exit; } - *offset += len; + *offset = len; retval = len; exit: @@ -780,14 +792,15 @@ int retval; int len; u8 value; + loff_t off = *offset; - dbg("count = %d, offset = %lld\n", count, *offset); + dbg("count = %d, offset = %lld\n", count, off); - if (*offset < 0) + if (off < 0) return -EINVAL; if (count <= 0) return 0; - if (*offset != 0) + if (off != 0) return 0; if (slot == NULL) { @@ -808,7 +821,7 @@ retval = -EFAULT; goto exit; } - *offset += len; + *offset = off + len; retval = len; exit: @@ -823,14 +836,15 @@ int retval; int len; u8 value; + loff_t off = *offset; dbg("count = %d, offset = %lld\n", count, *offset); - if (*offset < 0) + if (off < 0) return -EINVAL; if (count <= 0) return 0; - if (*offset != 0) + if (off != 0) return 0; if (slot == NULL) { @@ -851,7 +865,54 @@ retval = -EFAULT; goto exit; } - *offset += len; + *offset = off + len; + retval = len; + +exit: + free_page((unsigned long)page); + return retval; +} + +static ssize_t address_read_file (struct file *file, char *buf, size_t count, loff_t *offset) +{ + struct hotplug_slot *slot = file->private_data; + unsigned char *page; + int retval; + int len; + u32 address; + loff_t off = *offset; + + dbg("count = %d, offset = %lld\n", count, off); + + if (off < 0) + return -EINVAL; + if (count <= 0) + return 0; + if (off != 0) + return 0; + + if (slot == NULL) { + dbg("slot == NULL???\n"); + return -ENODEV; + } + + page = (unsigned char *)__get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + retval = get_address (slot, &address); + if (retval) + goto exit; + len = sprintf (page, "%04x:%02x:%02x\n", + (address >> 16) & 0xffff, + (address >> 8) & 0xff, + address & 0xff); + + if (copy_to_user (buf, page, len)) { + retval = -EFAULT; + goto exit; + } + *offset = off + len; retval = len; exit: @@ -869,14 +930,15 @@ int retval; int len = 0; enum pci_bus_speed value; + loff_t off = *offset; - dbg ("count = %d, offset = %lld\n", count, *offset); + dbg ("count = %d, offset = %lld\n", count, off); - if (*offset < 0) + if (off < 0) return -EINVAL; if (count <= 0) return 0; - if (*offset != 0) + if (off != 0) return 0; if (slot == NULL) { @@ -903,7 +965,7 @@ retval = -EFAULT; goto exit; } - *offset += len; + *offset = off + len; retval = len; exit: @@ -919,14 +981,15 @@ int retval; int len = 0; enum pci_bus_speed value; + loff_t off = *offset; - dbg ("count = %d, offset = %lld\n", count, *offset); + dbg ("count = %d, offset = %lld\n", count, off); - if (*offset < 0) + if (off < 0) return -EINVAL; if (count <= 0) return 0; - if (*offset != 0) + if (off != 0) return 0; if (slot == NULL) { @@ -953,7 +1016,7 @@ retval = -EFAULT; goto exit; } - *offset += len; + *offset = off + len; retval = len; exit: @@ -1055,6 +1118,13 @@ core->dir_dentry, slot, &presence_file_operations); + if (slot->ops->get_address) + core->address_dentry = + fs_create_file ("address", + S_IFREG | S_IRUGO, + core->dir_dentry, slot, + &address_file_operations); + if (slot->ops->get_max_bus_speed) core->max_bus_speed_dentry = fs_create_file ("max_bus_speed", @@ -1092,6 +1162,8 @@ fs_remove_file (core->latch_dentry); if (core->adapter_dentry) fs_remove_file (core->adapter_dentry); + if (core->address_dentry) + fs_remove_file (core->address_dentry); if (core->max_bus_speed_dentry) fs_remove_file (core->max_bus_speed_dentry); if (core->cur_bus_speed_dentry) @@ -1243,6 +1315,9 @@ if ((core->adapter_dentry) && (temp->info->adapter_status != info->adapter_status)) update_dentry_inode_time (core->adapter_dentry); + if ((core->address_dentry) && + (temp->info->address != info->address)) + update_dentry_inode_time (core->address_dentry); if ((core->cur_bus_speed_dentry) && (temp->info->cur_bus_speed != info->cur_bus_speed)) update_dentry_inode_time (core->cur_bus_speed_dentry); diff -urN linux-2.4.26/drivers/hotplug/pciehp.h linux-2.4.27/drivers/hotplug/pciehp.h --- linux-2.4.26/drivers/hotplug/pciehp.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.27/drivers/hotplug/pciehp.h 2004-08-07 16:26:04.742350393 -0700 @@ -0,0 +1,383 @@ +/* + * PCI Express Hot Plug Controller Driver + * + * Copyright (C) 1995,2001 Compaq Computer Corporation + * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2001 IBM Corp. + * Copyright (C) 2003-2004 Intel Corporation + * + * 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 , + * + */ +#ifndef _PCIEHP_H +#define _PCIEHP_H + +#include +#include +#include +#include +#include "pci_hotplug.h" + +#if !defined(CONFIG_HOTPLUG_PCI_PCIE_MODULE) + #define MY_NAME "pciehp.o" +#else + #define MY_NAME THIS_MODULE->name +#endif + +extern int pciehp_poll_mode; +extern int pciehp_poll_time; +extern int pciehp_debug; + +extern int pciehp_msi_quirk; + +/*#define dbg(format, arg...) do { if (pciehp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/ +#define dbg(format, arg...) do { if (pciehp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) + +struct pci_func { + struct pci_func *next; + u8 bus; + u8 device; + u8 function; + u8 is_a_board; + u16 status; + u8 configured; + u8 switch_save; + u8 presence_save; + u32 base_length[0x06]; + u8 base_type[0x06]; + u16 reserved2; + u32 config_space[0x20]; + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; + struct pci_dev* pci_dev; +}; + +#define SLOT_MAGIC 0x67267321 +struct slot { + u32 magic; + struct slot *next; + u8 bus; + u8 device; + u32 number; + u8 is_a_board; + u8 configured; + u8 state; + u8 switch_save; + u8 presence_save; + u32 capabilities; + u16 reserved2; + struct timer_list task_event; + u8 hp_slot; + struct controller *ctrl; + struct hpc_ops *hpc_ops; + struct hotplug_slot *hotplug_slot; + struct list_head slot_list; +}; + +struct pci_resource { + struct pci_resource * next; + u32 base; + u32 length; +}; + +struct event_info { + u32 event_type; + u8 hp_slot; +}; + +struct controller { + struct controller *next; + struct semaphore crit_sect; /* critical section semaphore */ + void * hpc_ctlr_handle; /* HPC controller handle */ + int num_slots; /* Number of slots on ctlr */ + int slot_num_inc; /* 1 or -1 */ + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; + struct pci_dev *pci_dev; + struct pci_bus *pci_bus; + struct event_info event_queue[10]; + struct slot *slot; + struct hpc_ops *hpc_ops; + wait_queue_head_t queue; /* sleep & wake process */ + u8 next_event; + u8 seg; + u8 bus; + u8 device; + u8 function; + u8 rev; + u8 slot_device_offset; + u8 add_support; + enum pci_bus_speed speed; + u32 first_slot; /* First physical slot number; PCI-E only has 1 slot */ + u8 slot_bus; /* Bus where the slots handled by this controller sit */ + u8 push_flag; + u16 ctlrcap; + u16 vendor_id; +}; + +struct irq_mapping { + u8 barber_pole; + u8 valid_INT; + u8 interrupt[4]; +}; + +struct resource_lists { + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; + struct irq_mapping *irqs; +}; + +#define INT_BUTTON_IGNORE 0 +#define INT_PRESENCE_ON 1 +#define INT_PRESENCE_OFF 2 +#define INT_SWITCH_CLOSE 3 +#define INT_SWITCH_OPEN 4 +#define INT_POWER_FAULT 5 +#define INT_POWER_FAULT_CLEAR 6 +#define INT_BUTTON_PRESS 7 +#define INT_BUTTON_RELEASE 8 +#define INT_BUTTON_CANCEL 9 + +#define STATIC_STATE 0 +#define BLINKINGON_STATE 1 +#define BLINKINGOFF_STATE 2 +#define POWERON_STATE 3 +#define POWEROFF_STATE 4 + +#define PCI_TO_PCI_BRIDGE_CLASS 0x00060400 + +/* Error messages */ +#define INTERLOCK_OPEN 0x00000002 +#define ADD_NOT_SUPPORTED 0x00000003 +#define CARD_FUNCTIONING 0x00000005 +#define ADAPTER_NOT_SAME 0x00000006 +#define NO_ADAPTER_PRESENT 0x00000009 +#define NOT_ENOUGH_RESOURCES 0x0000000B +#define DEVICE_TYPE_NOT_SUPPORTED 0x0000000C +#define WRONG_BUS_FREQUENCY 0x0000000D +#define POWER_FAILURE 0x0000000E + +#define REMOVE_NOT_SUPPORTED 0x00000003 + +#define DISABLE_CARD 1 + +/* + * error Messages + */ +#define msg_initialization_err "Initialization failure, error=%d\n" +#define msg_HPC_rev_error "Unsupported revision of the PCI hot plug controller found.\n" +#define msg_HPC_non_pcie "The PCI hot plug controller is not supported by this driver.\n" +#define msg_HPC_not_supported "This system is not supported by this version of pciephd mdoule. Upgrade to a newer version of pciehpd\n" +#define msg_unable_to_save "Unable to store PCI hot plug add resource information. This system must be rebooted before adding any PCI devices.\n" +#define msg_button_on "PCI slot #%d - powering on due to button press.\n" +#define msg_button_off "PCI slot #%d - powering off due to button press.\n" +#define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" +#define msg_button_ignore "PCI slot #%d - button press ignored. (action in progress...)\n" + +/* controller functions */ +extern void pciehp_pushbutton_thread (unsigned long event_pointer); +extern int pciehprm_find_available_resources (struct controller *ctrl); +extern int pciehp_event_start_thread (void); +extern void pciehp_event_stop_thread (void); +extern struct pci_func *pciehp_slot_create (unsigned char busnumber); +extern struct pci_func *pciehp_slot_find (unsigned char bus, unsigned char device, unsigned char index); +extern int pciehp_enable_slot (struct slot *slot); +extern int pciehp_disable_slot (struct slot *slot); + +extern u8 pciehp_handle_attention_button (u8 hp_slot, void *inst_id); +extern u8 pciehp_handle_switch_change (u8 hp_slot, void *inst_id); +extern u8 pciehp_handle_presence_change (u8 hp_slot, void *inst_id); +extern u8 pciehp_handle_power_fault (u8 hp_slot, void *inst_id); +/* extern void long_delay (int delay); */ + +/* resource functions */ +extern int pciehp_resource_sort_and_combine (struct pci_resource **head); + +/* pci functions */ +extern int pciehp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num); +extern int pciehp_save_config (struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num); +extern int pciehp_save_used_resources (struct controller *ctrl, struct pci_func * func, int flag); +extern int pciehp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot); +extern void pciehp_destroy_board_resources (struct pci_func * func); +extern int pciehp_return_board_resources (struct pci_func * func, struct resource_lists * resources); +extern void pciehp_destroy_resource_list (struct resource_lists * resources); +extern int pciehp_configure_device (struct controller* ctrl, struct pci_func* func); +extern int pciehp_unconfigure_device (struct pci_func* func); + + +/* Global variables */ +extern struct controller *pciehp_ctrl_list; +extern struct pci_func *pciehp_slot_list[256]; + +/* Inline functions */ + + +/* Inline functions to check the sanity of a pointer that is passed to us */ +static inline int slot_paranoia_check (struct slot *slot, const char *function) +{ + if (!slot) { + dbg("%s - slot == NULL", function); + return -1; + } + if (slot->magic != SLOT_MAGIC) { + dbg("%s - bad magic number for slot", function); + return -1; + } + if (!slot->hotplug_slot) { + dbg("%s - slot->hotplug_slot == NULL!", function); + return -1; + } + return 0; +} + +static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function) +{ + struct slot *slot; + + if (!hotplug_slot) { + dbg("%s - hotplug_slot == NULL\n", function); + return NULL; + } + + slot = (struct slot *)hotplug_slot->private; + if (slot_paranoia_check (slot, function)) + return NULL; + return slot; +} + +static inline struct slot *pciehp_find_slot (struct controller *ctrl, u8 device) +{ + struct slot *p_slot, *tmp_slot = NULL; + + if (!ctrl) + return NULL; + + p_slot = ctrl->slot; + + dbg("p_slot = %p\n", p_slot); + + while (p_slot && (p_slot->device != device)) { + tmp_slot = p_slot; + p_slot = p_slot->next; + dbg("In while loop, p_slot = %p\n", p_slot); + } + if (p_slot == NULL) { + err("ERROR: pciehp_find_slot device=0x%x\n", device); + p_slot = tmp_slot; + } + + return (p_slot); +} + +static inline int wait_for_ctrl_irq (struct controller *ctrl) +{ + int retval = 0; + + DECLARE_WAITQUEUE(wait, current); + + dbg("%s : start\n", __FUNCTION__); + add_wait_queue(&ctrl->queue, &wait); + set_current_state(TASK_INTERRUPTIBLE); + if (!pciehp_poll_mode) { + /* Sleep for up to 1 second */ + schedule_timeout(1*HZ); + } else + schedule_timeout(2.5*HZ); + set_current_state(TASK_RUNNING); + remove_wait_queue(&ctrl->queue, &wait); + if (signal_pending(current)) + retval = -EINTR; + + dbg("%s : end\n", __FUNCTION__); + + return retval; +} + + +/* Puts node back in the resource list pointed to by head */ +static inline void return_resource(struct pci_resource **head, struct pci_resource *node) +{ + if (!node || !head) + return; + node->next = *head; + *head = node; +} + +#define SLOT_NAME_SIZE 10 + +static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot) +{ + snprintf(buffer, buffer_size, "%d", slot->number); +} + +enum php_ctlr_type { + PCI, + ISA, + ACPI +}; + +typedef u8(*php_intr_callback_t) (unsigned int change_id, void *instance_id); + +int pcie_init( struct controller *ctrl, struct pci_dev *pdev, + php_intr_callback_t attention_button_callback, + php_intr_callback_t switch_change_callback, + php_intr_callback_t presence_change_callback, + php_intr_callback_t power_fault_callback); + +/* This has no meaning for PCI Express, as there is only 1 slot per port */ +int pcie_get_ctlr_slot_config( struct controller *ctrl, + int *num_ctlr_slots, + int *first_device_num, + int *physical_slot_num, + int *updown, + int *flags); + +struct hpc_ops { + int (*power_on_slot ) (struct slot *slot); + int (*power_off_slot ) (struct slot *slot); + int (*get_power_status) (struct slot *slot, u8 *status); + int (*get_attention_status) (struct slot *slot, u8 *status); + int (*set_attention_status) (struct slot *slot, u8 status); + int (*get_latch_status) (struct slot *slot, u8 *status); + int (*get_adapter_status) (struct slot *slot, u8 *status); + + int (*get_max_bus_speed) (struct slot *slot, enum pci_bus_speed *speed); + int (*get_cur_bus_speed) (struct slot *slot, enum pci_bus_speed *speed); + int (*get_max_lnk_width) (struct slot *slot, enum pcie_link_width *value); + int (*get_cur_lnk_width) (struct slot *slot, enum pcie_link_width *value); + + int (*query_power_fault) (struct slot *slot); + void (*green_led_on) (struct slot *slot); + void (*green_led_off) (struct slot *slot); + void (*green_led_blink) (struct slot *slot); + void (*release_ctlr) (struct controller *ctrl); + int (*check_lnk_status) (struct controller *ctrl); +}; + +#endif /* _PCIEHP_H */ diff -urN linux-2.4.26/drivers/hotplug/pciehp_core.c linux-2.4.27/drivers/hotplug/pciehp_core.c --- linux-2.4.26/drivers/hotplug/pciehp_core.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.4.27/drivers/hotplug/pciehp_core.c 2004-08-07 16:26:04.743350434 -0700 @@ -0,0 +1,703 @@ +/* + * PCI Express Hot Plug Controller Driver + * + * Copyright (C) 1995,2001 Compaq Computer Corporation + * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2001 IBM Corp. + * Copyright (C) 2003-2004 Intel Corporation + * + * 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 +#include +#include +#include "pciehp.h" +#include "pciehprm.h" + +/* Global variables */ +int pciehp_debug; +int pciehp_poll_mode; +int pciehp_poll_time; +struct controller *pciehp_ctrl_list; /* = NULL */ +struct pci_func *pciehp_slot_list[256]; + +#define DRIVER_VERSION "0.5" +#define DRIVER_AUTHOR "Dan Zink , Greg Kroah-Hartman , Dely Sy " +#define DRIVER_DESC "PCI Express Hot Plug Controller Driver" + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +MODULE_PARM(pciehp_debug, "i"); +MODULE_PARM(pciehp_poll_mode, "i"); +MODULE_PARM(pciehp_poll_time, "i"); +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"); + +#define PCIE_MODULE_NAME "pciehp.o" + +static int pcie_start_thread (void); +static int set_attention_status (struct hotplug_slot *slot, u8 value); +static int enable_slot (struct hotplug_slot *slot); +static int disable_slot (struct hotplug_slot *slot); +static int hardware_test (struct hotplug_slot *slot, u32 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_latch_status (struct hotplug_slot *slot, u8 *value); +static int get_adapter_status (struct hotplug_slot *slot, u8 *value); +static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); +static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); + +static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { + .owner = THIS_MODULE, + .set_attention_status = set_attention_status, + .enable_slot = enable_slot, + .disable_slot = disable_slot, + .hardware_test = hardware_test, + .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_max_bus_speed = get_max_bus_speed, + .get_cur_bus_speed = get_cur_bus_speed, +}; + +static int init_slots(struct controller *ctrl) +{ + struct slot *new_slot; + u8 number_of_slo