diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/Documentation/CodingStyle linux-2.4.27-pre5/Documentation/CodingStyle --- linux-2.4.26/Documentation/CodingStyle 2001-09-09 23:40:43.000000000 +0000 +++ linux-2.4.27-pre5/Documentation/CodingStyle 2004-06-03 01:33:29.000000000 +0000 @@ -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 @@ opening brace at the beginning of the ne 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 @@ and } 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 @@ understand what the function is all abou 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 @@ two lines, this mode will be automatical 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 @@ automagically when you edit source files 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 @@ support for file-systems, for instance) 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 @@ when there are users of different "class 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/Documentation/Configure.help linux-2.4.27-pre5/Documentation/Configure.help --- linux-2.4.26/Documentation/Configure.help 2004-04-14 13:05:24.000000000 +0000 +++ linux-2.4.27-pre5/Documentation/Configure.help 2004-06-03 01:35:54.213967608 +0000 @@ -569,6 +569,19 @@ CONFIG_BLK_DEV_UMEM The umem driver has been allocated block major number 116. See Documentation/devices.txt for recommended device naming. +Promise SATA SX8 (carmel) support +CONFIG_BLK_DEV_CARMEL + Saying Y or M here will enable support for the + Promise SATA SX8 (carmel) 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 carmel.o. + + The carmel 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 @@ -4286,6 +4299,46 @@ CONFIG_HOTPLUG_PCI_ACPI 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 @@ -13407,6 +13460,16 @@ CONFIG_HIPPI 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. @@ -17427,13 +17490,10 @@ Tracing support (EXPERIMENTAL) 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) @@ -23167,9 +23227,6 @@ CONFIG_BLUEZ_HCIBT3C 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). @@ -28784,9 +28841,10 @@ CONFIG_CRYPTO_CAST6 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 +28852,12 @@ CONFIG_CRYPTO_DEFLATE 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/Documentation/DocBook/Makefile linux-2.4.27-pre5/Documentation/DocBook/Makefile --- linux-2.4.26/Documentation/DocBook/Makefile 2002-11-28 23:53:08.000000000 +0000 +++ linux-2.4.27-pre5/Documentation/DocBook/Makefile 2004-06-03 01:34:10.000000000 +0000 @@ -2,7 +2,7 @@ BOOKS := wanbook.sgml z8530book.sgml mca 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 @@ mcabook.sgml: mcabook.tmpl $(TOPDIR)/arc $(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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/Documentation/DocBook/libata.tmpl linux-2.4.27-pre5/Documentation/DocBook/libata.tmpl --- linux-2.4.26/Documentation/DocBook/libata.tmpl 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/Documentation/DocBook/libata.tmpl 2004-06-03 01:33:40.000000000 +0000 @@ -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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/Documentation/cciss.txt linux-2.4.27-pre5/Documentation/cciss.txt --- linux-2.4.26/Documentation/cciss.txt 2003-11-28 18:26:19.000000000 +0000 +++ linux-2.4.27-pre5/Documentation/cciss.txt 2004-06-03 01:32:45.000000000 +0000 @@ -14,6 +14,8 @@ This driver is known to work with the fo * 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/Documentation/crypto/api-intro.txt linux-2.4.27-pre5/Documentation/crypto/api-intro.txt --- linux-2.4.26/Documentation/crypto/api-intro.txt 2004-04-14 13:05:24.000000000 +0000 +++ linux-2.4.27-pre5/Documentation/crypto/api-intro.txt 2004-06-03 01:36:18.672249384 +0000 @@ -187,6 +187,7 @@ Original developers of the crypto algori Brian Gladman (AES) Kartikey Mahendra Bhatt (CAST6) Jon Oberheide (ARC4) + Jouni Malinen (Michael MIC) SHA1 algorithm contributors: Jean-Francois Dive diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/Documentation/filesystems/xfs.txt linux-2.4.27-pre5/Documentation/filesystems/xfs.txt --- linux-2.4.26/Documentation/filesystems/xfs.txt 2004-02-18 13:36:30.000000000 +0000 +++ linux-2.4.27-pre5/Documentation/filesystems/xfs.txt 2004-06-03 01:32:59.000000000 +0000 @@ -123,9 +123,15 @@ The following sysctls are available for 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 @@ The following sysctls are available for 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/Documentation/kernel-parameters.txt linux-2.4.27-pre5/Documentation/kernel-parameters.txt --- linux-2.4.26/Documentation/kernel-parameters.txt 2004-04-14 13:05:24.000000000 +0000 +++ linux-2.4.27-pre5/Documentation/kernel-parameters.txt 2004-06-03 01:36:27.754868616 +0000 @@ -69,8 +69,9 @@ running once the system is up. 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/Documentation/networking/bridge.txt linux-2.4.27-pre5/Documentation/networking/bridge.txt --- linux-2.4.26/Documentation/networking/bridge.txt 2000-11-09 23:57:53.000000000 +0000 +++ linux-2.4.27-pre5/Documentation/networking/bridge.txt 2004-06-03 01:34:42.000000000 +0000 @@ -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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/Documentation/networking/ip-sysctl.txt linux-2.4.27-pre5/Documentation/networking/ip-sysctl.txt --- linux-2.4.26/Documentation/networking/ip-sysctl.txt 2004-04-14 13:05:25.000000000 +0000 +++ linux-2.4.27-pre5/Documentation/networking/ip-sysctl.txt 2004-06-03 01:34:00.000000000 +0000 @@ -289,6 +289,44 @@ tcp_low_latency - BOOLEAN 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 diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/Documentation/usb/silverlink.txt linux-2.4.27-pre5/Documentation/usb/silverlink.txt --- linux-2.4.26/Documentation/usb/silverlink.txt 2002-11-28 23:53:08.000000000 +0000 +++ linux-2.4.27-pre5/Documentation/usb/silverlink.txt 2004-06-03 01:32:44.000000000 +0000 @@ -8,7 +8,7 @@ Homepage: http://lpg.ticalc.org/prj_usb 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 @@ at the above URL. 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 @@ MODULE PARAMETERS: 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 @@ this driver but he better knows the Mac 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/MAINTAINERS linux-2.4.27-pre5/MAINTAINERS --- linux-2.4.26/MAINTAINERS 2004-04-14 13:05:25.000000000 +0000 +++ linux-2.4.27-pre5/MAINTAINERS 2004-06-03 01:34:32.000000000 +0000 @@ -113,6 +113,12 @@ M: jgarzik@pobox.com 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 @@ -954,11 +960,21 @@ P: Tigran Aivazian 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 @@ -1638,6 +1654,12 @@ M: christer@weinigel.se 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 +2183,7 @@ S: Maintained 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/Makefile linux-2.4.27-pre5/Makefile --- linux-2.4.26/Makefile 2004-04-14 13:05:41.000000000 +0000 +++ linux-2.4.27-pre5/Makefile 2004-06-03 01:34:49.000000000 +0000 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 -SUBLEVEL = 26 -EXTRAVERSION = +SUBLEVEL = 27 +EXTRAVERSION = -pre5 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/i386/kernel/acpi.c linux-2.4.27-pre5/arch/i386/kernel/acpi.c --- linux-2.4.26/arch/i386/kernel/acpi.c 2004-04-14 13:05:25.000000000 +0000 +++ linux-2.4.27-pre5/arch/i386/kernel/acpi.c 2004-06-03 01:35:15.000000000 +0000 @@ -59,7 +59,10 @@ int acpi_sci_override_gsi __initdata; 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 @@ char *__acpi_map_table(unsigned long phy 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 @@ acpi_boot_init (void) 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 /* @@ -502,9 +543,6 @@ acpi_boot_init (void) 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 +560,9 @@ acpi_boot_init (void) 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/i386/kernel/i8259.c linux-2.4.27-pre5/arch/i386/kernel/i8259.c --- linux-2.4.26/arch/i386/kernel/i8259.c 2001-09-18 06:03:09.000000000 +0000 +++ linux-2.4.27-pre5/arch/i386/kernel/i8259.c 2004-06-03 01:35:54.231964872 +0000 @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -498,7 +499,8 @@ void __init init_IRQ(void) outb(LATCH >> 8 , 0x40); /* MSB */ #ifndef CONFIG_VISWS - setup_irq(2, &irq2); + if (!acpi_ioapic) + setup_irq(2, &irq2); #endif /* diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/i386/kernel/io_apic.c linux-2.4.27-pre5/arch/i386/kernel/io_apic.c --- linux-2.4.26/arch/i386/kernel/io_apic.c 2004-04-14 13:05:25.000000000 +0000 +++ linux-2.4.27-pre5/arch/i386/kernel/io_apic.c 2004-06-03 01:33:30.000000000 +0000 @@ -1691,18 +1691,10 @@ static inline void check_timer(void) /* * - * 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 @@ void __init setup_IO_APIC(void) { 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 @@ int io_apic_set_pci_routing (int ioapic, 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/i386/kernel/mpparse.c linux-2.4.27-pre5/arch/i386/kernel/mpparse.c --- linux-2.4.26/arch/i386/kernel/mpparse.c 2004-04-14 13:05:25.000000000 +0000 +++ linux-2.4.27-pre5/arch/i386/kernel/mpparse.c 2004-06-03 01:33:26.000000000 +0000 @@ -1111,8 +1111,6 @@ void __init mp_override_legacy_irq ( u32 global_irq) { struct mpc_config_intsrc intsrc; - int i = 0; - int found = 0; int ioapic = -1; int pin = -1; @@ -1145,23 +1143,9 @@ void __init mp_override_legacy_irq ( (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; } @@ -1206,13 +1190,19 @@ void __init mp_config_acpi_legacy_irqs ( 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_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 +1298,13 @@ void __init mp_parse_prt (void) 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/i386/kernel/pci-irq.c linux-2.4.27-pre5/arch/i386/kernel/pci-irq.c --- linux-2.4.26/arch/i386/kernel/pci-irq.c 2004-04-14 13:05:25.000000000 +0000 +++ linux-2.4.27-pre5/arch/i386/kernel/pci-irq.c 2004-06-03 01:36:16.578567672 +0000 @@ -1067,6 +1067,7 @@ void pcibios_enable_irq(struct pci_dev * { 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 @@ void pcibios_enable_irq(struct pci_dev * 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/i386/kernel/pci-pc.c linux-2.4.27-pre5/arch/i386/kernel/pci-pc.c --- linux-2.4.26/arch/i386/kernel/pci-pc.c 2003-11-28 18:26:19.000000000 +0000 +++ linux-2.4.27-pre5/arch/i386/kernel/pci-pc.c 2004-06-03 01:33:55.000000000 +0000 @@ -1321,13 +1321,46 @@ static void __init pci_fixup_via_northbr * 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 0x1F01FF01 0x1F0FFF01 + * C18D 0x9F01FF01 0x9F0FFF01 + */ + 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 @@ struct pci_fixup pcibios_fixups[] = { { 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 @@ void __init pcibios_init(void) 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/i386/kernel/setup.c linux-2.4.27-pre5/arch/i386/kernel/setup.c --- linux-2.4.26/arch/i386/kernel/setup.c 2004-04-14 13:05:25.000000000 +0000 +++ linux-2.4.27-pre5/arch/i386/kernel/setup.c 2004-06-03 01:34:10.000000000 +0000 @@ -2333,6 +2333,7 @@ static struct _cache_table cache_table[] { 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 @@ static void __init init_intel(struct cpu 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/i386/mm/fault.c linux-2.4.27-pre5/arch/i386/mm/fault.c --- linux-2.4.26/arch/i386/mm/fault.c 2004-02-18 13:36:30.000000000 +0000 +++ linux-2.4.27-pre5/arch/i386/mm/fault.c 2004-06-03 01:32:24.000000000 +0000 @@ -71,7 +71,7 @@ good_area: if (!vma || vma->vm_start != start) goto bad_area; if (!(vma->vm_flags & VM_WRITE)) - goto bad_area;; + goto bad_area; } return 1; diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/i386/mm/pageattr.c linux-2.4.27-pre5/arch/i386/mm/pageattr.c --- linux-2.4.26/arch/i386/mm/pageattr.c 2002-11-28 23:53:09.000000000 +0000 +++ linux-2.4.27-pre5/arch/i386/mm/pageattr.c 2004-06-03 01:33:28.000000000 +0000 @@ -52,11 +52,9 @@ static struct page *split_large_page(uns 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/configs/dig linux-2.4.27-pre5/arch/ia64/configs/dig --- linux-2.4.26/arch/ia64/configs/dig 2004-02-18 13:36:30.000000000 +0000 +++ linux-2.4.27-pre5/arch/ia64/configs/dig 2004-06-03 01:34:38.000000000 +0000 @@ -28,9 +28,9 @@ CONFIG_ITANIUM=y # 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 @@ CONFIG_INET=y # # 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_BLK_DEV_IDEDMA=y # 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_PIIX=y # 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_EEPRO100=y # 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_X=1024 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 @@ CONFIG_INPUT_SERPORT=y # 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_EXT2_FS=y # 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_HIDDEV=y # 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/configs/generic linux-2.4.27-pre5/arch/ia64/configs/generic --- linux-2.4.26/arch/ia64/configs/generic 2004-02-18 13:36:30.000000000 +0000 +++ linux-2.4.27-pre5/arch/ia64/configs/generic 2004-06-03 01:32:36.000000000 +0000 @@ -28,9 +28,9 @@ CONFIG_ITANIUM=y # 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 @@ CONFIG_INET=y # # 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_BLK_DEV_IDEDMA=y # 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_PIIX=y # 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_EEPRO100=y # 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_X=1024 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 @@ CONFIG_INPUT_SERPORT=y # 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_EXT2_FS=y # 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_HIDDEV=y # 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/configs/numa linux-2.4.27-pre5/arch/ia64/configs/numa --- linux-2.4.26/arch/ia64/configs/numa 2004-02-18 13:36:30.000000000 +0000 +++ linux-2.4.27-pre5/arch/ia64/configs/numa 2004-06-03 01:34:28.000000000 +0000 @@ -28,9 +28,9 @@ CONFIG_ITANIUM=y # 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 @@ CONFIG_INET=y # # 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_BLK_DEV_IDEDMA=y # 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_PIIX=y # 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_EEPRO100=y # 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_X=1024 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 @@ CONFIG_INPUT_SERPORT=y # 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_EXT2_FS=y # 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_HIDDEV=y # 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/configs/ski linux-2.4.27-pre5/arch/ia64/configs/ski --- linux-2.4.26/arch/ia64/configs/ski 2004-02-18 13:36:30.000000000 +0000 +++ linux-2.4.27-pre5/arch/ia64/configs/ski 2004-06-03 01:33:08.000000000 +0000 @@ -28,9 +28,9 @@ CONFIG_ITANIUM=y # 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 @@ CONFIG_INET=y # # 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_SCSI_LOGGING=y # 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 @@ CONFIG_PSMOUSE=y # 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_EXT2_FS=y # 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/configs/zx1 linux-2.4.27-pre5/arch/ia64/configs/zx1 --- linux-2.4.26/arch/ia64/configs/zx1 2004-02-18 13:36:30.000000000 +0000 +++ linux-2.4.27-pre5/arch/ia64/configs/zx1 2004-06-03 01:35:26.000000000 +0000 @@ -28,9 +28,9 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y 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 @@ CONFIG_INET=y # # 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_BLK_DEV_IDEDMA=y # 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_PIIX=y # 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_EEPRO100=y # 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_X=1024 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 @@ CONFIG_INPUT_SERPORT=y # 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_EXT2_FS=y # 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_HIDDEV=y # 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/defconfig linux-2.4.27-pre5/arch/ia64/defconfig --- linux-2.4.26/arch/ia64/defconfig 2004-02-18 13:36:30.000000000 +0000 +++ linux-2.4.27-pre5/arch/ia64/defconfig 2004-06-03 01:32:39.000000000 +0000 @@ -28,9 +28,9 @@ CONFIG_ITANIUM=y # 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 @@ CONFIG_INET=y # # 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_BLK_DEV_IDEDMA=y # 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_PIIX=y # 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_EEPRO100=y # 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_X=1024 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 @@ CONFIG_INPUT_SERPORT=y # 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_EXT2_FS=y # 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_HIDDEV=y # 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/ia32/binfmt_elf32.c linux-2.4.27-pre5/arch/ia64/ia32/binfmt_elf32.c --- linux-2.4.26/arch/ia64/ia32/binfmt_elf32.c 2003-11-28 18:26:19.000000000 +0000 +++ linux-2.4.27-pre5/arch/ia64/ia32/binfmt_elf32.c 2004-06-03 01:35:54.234964416 +0000 @@ -17,6 +17,8 @@ #include #include +#include "elfcore32.h" + #define CONFIG_BINFMT_ELF32 /* Override some function names */ diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/ia32/elfcore32.h linux-2.4.27-pre5/arch/ia64/ia32/elfcore32.h --- linux-2.4.26/arch/ia64/ia32/elfcore32.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/arch/ia64/ia32/elfcore32.h 2004-06-03 01:35:45.000000000 +0000 @@ -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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/ia32/sys_ia32.c linux-2.4.27-pre5/arch/ia64/ia32/sys_ia32.c --- linux-2.4.26/arch/ia64/ia32/sys_ia32.c 2004-02-18 13:36:30.000000000 +0000 +++ linux-2.4.27-pre5/arch/ia64/ia32/sys_ia32.c 2004-06-03 01:34:36.000000000 +0000 @@ -2949,7 +2949,7 @@ get_fpreg (int regno, struct _fpreg_ia32 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 @@ restore_ia32_fpstate (struct task_struct return 0; } -static int +int save_ia32_fpxstate (struct task_struct *tsk, struct ia32_user_fxsr_struct *save) { struct switch_stack *swp; diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/kernel/efi.c linux-2.4.27-pre5/arch/ia64/kernel/efi.c --- linux-2.4.26/arch/ia64/kernel/efi.c 2004-02-18 13:36:30.000000000 +0000 +++ linux-2.4.27-pre5/arch/ia64/kernel/efi.c 2004-06-03 01:32:32.000000000 +0000 @@ -673,8 +673,7 @@ efi_get_iobase (void) 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/kernel/perfmon.c linux-2.4.27-pre5/arch/ia64/kernel/perfmon.c --- linux-2.4.26/arch/ia64/kernel/perfmon.c 2004-02-18 13:36:30.000000000 +0000 +++ linux-2.4.27-pre5/arch/ia64/kernel/perfmon.c 2004-06-03 01:35:55.234812416 +0000 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -3166,62 +3167,111 @@ pfm_interrupt_handler(int irq, void *arg } } -/* 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 +4498,13 @@ pfm_remove_alternate_syswide_subsystem(p 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 +4555,15 @@ pfm_init(void) /* * 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/kernel/unwind.c linux-2.4.27-pre5/arch/ia64/kernel/unwind.c --- linux-2.4.26/arch/ia64/kernel/unwind.c 2004-04-14 13:05:26.000000000 +0000 +++ linux-2.4.27-pre5/arch/ia64/kernel/unwind.c 2004-06-03 01:36:27.857852960 +0000 @@ -1750,7 +1750,7 @@ run_script (struct unw_script *script, s 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ia64/mm/hugetlbpage.c linux-2.4.27-pre5/arch/ia64/mm/hugetlbpage.c --- linux-2.4.26/arch/ia64/mm/hugetlbpage.c 2004-02-18 13:36:30.000000000 +0000 +++ linux-2.4.27-pre5/arch/ia64/mm/hugetlbpage.c 2004-06-03 01:33:43.000000000 +0000 @@ -73,8 +73,12 @@ huge_pte_offset (struct mm_struct *mm, u 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 @@ void unmap_hugepage_range(struct vm_area 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/ppc/kernel/head_44x.S linux-2.4.27-pre5/arch/ppc/kernel/head_44x.S --- linux-2.4.26/arch/ppc/kernel/head_44x.S 2004-04-14 13:05:27.000000000 +0000 +++ linux-2.4.27-pre5/arch/ppc/kernel/head_44x.S 2004-06-03 01:32:25.000000000 +0000 @@ -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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sh64/config.in linux-2.4.27-pre5/arch/sh64/config.in --- linux-2.4.26/arch/sh64/config.in 2004-02-18 13:36:30.000000000 +0000 +++ linux-2.4.27-pre5/arch/sh64/config.in 2004-06-03 01:36:21.220861936 +0000 @@ -58,8 +58,7 @@ bool 'Fixup misaligned loads/stores occu # 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 @@ comment 'Memory options' 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 'GDB Stub kernel debug' CONFIG_DEBU 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sh64/defconfig linux-2.4.27-pre5/arch/sh64/defconfig --- linux-2.4.26/arch/sh64/defconfig 2004-02-18 13:36:30.000000000 +0000 +++ linux-2.4.27-pre5/arch/sh64/defconfig 2004-06-03 01:35:58.000000000 +0000 @@ -490,6 +490,7 @@ CONFIG_FONT_8x16=y # 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sh64/kernel/entry.S linux-2.4.27-pre5/arch/sh64/kernel/entry.S --- linux-2.4.26/arch/sh64/kernel/entry.S 2003-08-25 11:44:40.000000000 +0000 +++ linux-2.4.27-pre5/arch/sh64/kernel/entry.S 2004-06-03 01:34:38.000000000 +0000 @@ -1607,12 +1607,6 @@ poke_real_address_q: 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sh64/kernel/head.S linux-2.4.27-pre5/arch/sh64/kernel/head.S --- linux-2.4.26/arch/sh64/kernel/head.S 2003-08-25 11:44:40.000000000 +0000 +++ linux-2.4.27-pre5/arch/sh64/kernel/head.S 2004-06-03 01:33:43.000000000 +0000 @@ -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 @@ clear_DTLB: /* 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sh64/kernel/pci_sh5.c linux-2.4.27-pre5/arch/sh64/kernel/pci_sh5.c --- linux-2.4.26/arch/sh64/kernel/pci_sh5.c 2003-08-25 11:44:40.000000000 +0000 +++ linux-2.4.27-pre5/arch/sh64/kernel/pci_sh5.c 2004-06-03 01:32:21.000000000 +0000 @@ -320,43 +320,70 @@ static int __init map_cayman_irq(struct { 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sh64/kernel/time.c linux-2.4.27-pre5/arch/sh64/kernel/time.c --- linux-2.4.26/arch/sh64/kernel/time.c 2004-02-18 13:36:30.000000000 +0000 +++ linux-2.4.27-pre5/arch/sh64/kernel/time.c 2004-06-03 01:34:53.000000000 +0000 @@ -404,13 +404,14 @@ static __init unsigned int get_cpu_mhz(v { 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 @@ static __init unsigned int get_cpu_mhz(v /* * 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 @@ static __init unsigned int get_cpu_mhz(v * .... * * 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 @@ static __init unsigned int get_cpu_mhz(v * 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sh64/lib/io.c linux-2.4.27-pre5/arch/sh64/lib/io.c --- linux-2.4.26/arch/sh64/lib/io.c 2003-08-25 11:44:40.000000000 +0000 +++ linux-2.4.27-pre5/arch/sh64/lib/io.c 2004-06-03 01:32:37.000000000 +0000 @@ -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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sh64/mach-cayman/irq.c linux-2.4.27-pre5/arch/sh64/mach-cayman/irq.c --- linux-2.4.26/arch/sh64/mach-cayman/irq.c 2003-08-25 11:44:40.000000000 +0000 +++ linux-2.4.27-pre5/arch/sh64/mach-cayman/irq.c 2004-06-03 01:35:08.000000000 +0000 @@ -27,9 +27,12 @@ unsigned long epld_virt; #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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sh64/mach-cayman/setup.c linux-2.4.27-pre5/arch/sh64/mach-cayman/setup.c --- linux-2.4.26/arch/sh64/mach-cayman/setup.c 2003-08-25 11:44:40.000000000 +0000 +++ linux-2.4.27-pre5/arch/sh64/mach-cayman/setup.c 2004-06-03 01:32:35.000000000 +0000 @@ -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 @@ int platform_int_priority[NR_INTC_IRQS] 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 @@ static int __init smsc_setup(void) 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 @@ static int __init smsc_setup(void) /* 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sh64/mm/cache.c linux-2.4.27-pre5/arch/sh64/mm/cache.c --- linux-2.4.26/arch/sh64/mm/cache.c 2003-08-25 11:44:40.000000000 +0000 +++ linux-2.4.27-pre5/arch/sh64/mm/cache.c 2004-06-03 01:34:14.000000000 +0000 @@ -474,7 +474,7 @@ static void sh64_dcache_purge_kernel_ran /* 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 @@ static void sh64_dcache_wback_current_us /****************************************************************************/ /* 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sh64/vmlinux.lds.S linux-2.4.27-pre5/arch/sh64/vmlinux.lds.S --- linux-2.4.26/arch/sh64/vmlinux.lds.S 2003-08-25 11:44:40.000000000 +0000 +++ linux-2.4.27-pre5/arch/sh64/vmlinux.lds.S 2004-06-03 01:33:31.000000000 +0000 @@ -38,7 +38,6 @@ OUTPUT_FORMAT("elf32-sh64", "elf32-sh64" 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc/Makefile linux-2.4.27-pre5/arch/sparc/Makefile --- linux-2.4.26/arch/sparc/Makefile 2001-07-28 19:12:37.000000000 +0000 +++ linux-2.4.27-pre5/arch/sparc/Makefile 2004-06-03 01:32:46.000000000 +0000 @@ -16,7 +16,7 @@ SHELL =/bin/bash # 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc/kernel/process.c linux-2.4.27-pre5/arch/sparc/kernel/process.c --- linux-2.4.26/arch/sparc/kernel/process.c 2003-06-13 14:51:32.000000000 +0000 +++ linux-2.4.27-pre5/arch/sparc/kernel/process.c 2004-06-03 01:32:47.000000000 +0000 @@ -54,6 +54,12 @@ void (*pm_idle)(void); */ 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_restart(char * cmd) 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc/prom/memory.c linux-2.4.27-pre5/arch/sparc/prom/memory.c --- linux-2.4.26/arch/sparc/prom/memory.c 2000-02-01 07:37:19.000000000 +0000 +++ linux-2.4.27-pre5/arch/sparc/prom/memory.c 2004-06-03 01:36:21.000000000 +0000 @@ -156,7 +156,7 @@ void __init prom_meminit(void) 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc64/Makefile linux-2.4.27-pre5/arch/sparc64/Makefile --- linux-2.4.26/arch/sparc64/Makefile 2003-06-13 14:51:32.000000000 +0000 +++ linux-2.4.27-pre5/arch/sparc64/Makefile 2004-06-03 01:36:09.000000000 +0000 @@ -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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc64/config.in linux-2.4.27-pre5/arch/sparc64/config.in --- linux-2.4.26/arch/sparc64/config.in 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/arch/sparc64/config.in 2004-06-03 01:33:24.000000000 +0000 @@ -21,6 +21,8 @@ endmenu 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc64/defconfig linux-2.4.27-pre5/arch/sparc64/defconfig --- linux-2.4.26/arch/sparc64/defconfig 2004-04-14 13:05:27.000000000 +0000 +++ linux-2.4.27-pre5/arch/sparc64/defconfig 2004-06-03 01:33:31.000000000 +0000 @@ -17,6 +17,20 @@ CONFIG_KMOD=y # # 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_BLK_DEV_ALI15X3=y # 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_CAST5=m CONFIG_CRYPTO_CAST6=m CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_MICHAEL_MIC=m # CONFIG_CRYPTO_TEST is not set # diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc64/kernel/ioctl32.c linux-2.4.27-pre5/arch/sparc64/kernel/ioctl32.c --- linux-2.4.26/arch/sparc64/kernel/ioctl32.c 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/arch/sparc64/kernel/ioctl32.c 2004-06-03 01:35:48.000000000 +0000 @@ -1271,6 +1271,7 @@ static int fd_ioctl_trans(unsigned int f case FDGETPRM32: { struct floppy_struct *f; + u32 u_name; f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL); if (!karg) @@ -1286,7 +1287,8 @@ static int fd_ioctl_trans(unsigned int f 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 @@ static int blkpg_ioctl_trans(unsigned in { 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_NOWERR) 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc64/kernel/power.c linux-2.4.27-pre5/arch/sparc64/kernel/power.c --- linux-2.4.26/arch/sparc64/kernel/power.c 2003-06-13 14:51:32.000000000 +0000 +++ linux-2.4.27-pre5/arch/sparc64/kernel/power.c 2004-06-03 01:35:46.000000000 +0000 @@ -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 @@ extern int serial_console; 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc64/kernel/process.c linux-2.4.27-pre5/arch/sparc64/kernel/process.c --- linux-2.4.26/arch/sparc64/kernel/process.c 2003-06-13 14:51:32.000000000 +0000 +++ linux-2.4.27-pre5/arch/sparc64/kernel/process.c 2004-06-03 01:34:00.000000000 +0000 @@ -453,7 +453,7 @@ void flush_thread(void) 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc64/kernel/signal32.c linux-2.4.27-pre5/arch/sparc64/kernel/signal32.c --- linux-2.4.26/arch/sparc64/kernel/signal32.c 2003-08-25 11:44:40.000000000 +0000 +++ linux-2.4.27-pre5/arch/sparc64/kernel/signal32.c 2004-06-03 01:32:23.000000000 +0000 @@ -393,7 +393,7 @@ asmlinkage void do_rt_sigreturn32(struct { 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 @@ asmlinkage void do_rt_sigreturn32(struct 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 @@ asmlinkage int svr4_setcontext(svr4_ucon 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 @@ asmlinkage int svr4_setcontext(svr4_ucon 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 @@ asmlinkage int do_sys32_sigstack(u32 u_s /* 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 @@ out: 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc64/kernel/sparc64_ksyms.c linux-2.4.27-pre5/arch/sparc64/kernel/sparc64_ksyms.c --- linux-2.4.26/arch/sparc64/kernel/sparc64_ksyms.c 2003-06-13 14:51:32.000000000 +0000 +++ linux-2.4.27-pre5/arch/sparc64/kernel/sparc64_ksyms.c 2004-06-03 01:35:18.000000000 +0000 @@ -89,6 +89,7 @@ extern long sparc32_open(const char * fi 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 @@ EXPORT_SYMBOL(do_BUG); #endif EXPORT_SYMBOL(tick_ops); + +EXPORT_SYMBOL(prom_palette); diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc64/kernel/sys_sparc32.c linux-2.4.27-pre5/arch/sparc64/kernel/sys_sparc32.c --- linux-2.4.26/arch/sparc64/kernel/sys_sparc32.c 2004-04-14 13:05:27.000000000 +0000 +++ linux-2.4.27-pre5/arch/sparc64/kernel/sys_sparc32.c 2004-06-03 01:34:43.000000000 +0000 @@ -1316,7 +1316,7 @@ static int filldir(void * __buf, const c 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 @@ asmlinkage int sys32_sigaction (int sig, 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 @@ sys32_rt_sigaction(int sig, struct sigac 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 @@ sys32_rt_sigaction(int sig, struct sigac 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc64/kernel/sys_sunos32.c linux-2.4.27-pre5/arch/sparc64/kernel/sys_sunos32.c --- linux-2.4.26/arch/sparc64/kernel/sys_sunos32.c 2004-04-14 13:05:28.000000000 +0000 +++ linux-2.4.27-pre5/arch/sparc64/kernel/sys_sunos32.c 2004-06-03 01:34:36.000000000 +0000 @@ -296,7 +296,7 @@ static int sunos_filldir(void * __buf, c 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 @@ static int sunos_filldirentry(void * __b 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 @@ asmlinkage int sunos_sigaction (int sig, 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc64/kernel/unaligned.c linux-2.4.27-pre5/arch/sparc64/kernel/unaligned.c --- linux-2.4.26/arch/sparc64/kernel/unaligned.c 2003-11-28 18:26:19.000000000 +0000 +++ linux-2.4.27-pre5/arch/sparc64/kernel/unaligned.c 2004-06-03 01:33:30.000000000 +0000 @@ -166,7 +166,7 @@ static inline unsigned long compute_effe } /* 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc64/mm/init.c linux-2.4.27-pre5/arch/sparc64/mm/init.c --- linux-2.4.26/arch/sparc64/mm/init.c 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/arch/sparc64/mm/init.c 2004-06-03 01:33:43.000000000 +0000 @@ -1433,8 +1433,10 @@ void __init paging_init(void) /* 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/sparc64/prom/memory.c linux-2.4.27-pre5/arch/sparc64/prom/memory.c --- linux-2.4.26/arch/sparc64/prom/memory.c 1999-08-31 18:23:30.000000000 +0000 +++ linux-2.4.27-pre5/arch/sparc64/prom/memory.c 2004-06-03 01:35:06.000000000 +0000 @@ -114,7 +114,7 @@ void __init prom_meminit(void) 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/x86_64/ia32/ia32entry.S linux-2.4.27-pre5/arch/x86_64/ia32/ia32entry.S --- linux-2.4.26/arch/x86_64/ia32/ia32entry.S 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/arch/x86_64/ia32/ia32entry.S 2004-06-03 01:33:07.000000000 +0000 @@ -71,7 +71,7 @@ ia32_tracesys: 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 @@ ia32_tracesys_end: 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/x86_64/kernel/acpi.c linux-2.4.27-pre5/arch/x86_64/kernel/acpi.c --- linux-2.4.26/arch/x86_64/kernel/acpi.c 2004-04-14 13:05:28.000000000 +0000 +++ linux-2.4.27-pre5/arch/x86_64/kernel/acpi.c 2004-06-03 01:36:05.000000000 +0000 @@ -56,7 +56,10 @@ int acpi_sci_override_gsi __initdata; /* -------------------------------------------------------------------------- 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 @@ __acpi_map_table ( #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 @@ acpi_parse_nmi_src ( #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 @@ acpi_parse_hpet ( return 0; } +#endif /* CONFIG_HPET_TIMER */ #ifdef CONFIG_ACPI_BUS /* @@ -457,17 +490,16 @@ acpi_boot_init (void) 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 @@ acpi_boot_init (void) 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 @@ acpi_boot_init (void) 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 @@ acpi_boot_init (void) 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/x86_64/kernel/e820.c linux-2.4.27-pre5/arch/x86_64/kernel/e820.c --- linux-2.4.26/arch/x86_64/kernel/e820.c 2004-04-14 13:05:28.000000000 +0000 +++ linux-2.4.27-pre5/arch/x86_64/kernel/e820.c 2004-06-03 01:33:38.000000000 +0000 @@ -567,10 +567,10 @@ void __init parse_mem_cmdline (char ** c acpi_strict = 1; } - else if (!memcmp(from, "pci=noacpi", 10)) { + else if (!memcmp(from, "pci=noacpi", 10)) + acpi_disable_pci(); + else if (!memcmp(from, "acpi=noirq", 10)) acpi_noirq_set(); - } - else if (!memcmp(from, "acpi_sci=edge", 13)) acpi_sci_flags.trigger = 1; else if (!memcmp(from, "acpi_sci=level", 14)) diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/x86_64/kernel/i8259.c linux-2.4.27-pre5/arch/x86_64/kernel/i8259.c --- linux-2.4.26/arch/x86_64/kernel/i8259.c 2003-06-13 14:51:32.000000000 +0000 +++ linux-2.4.27-pre5/arch/x86_64/kernel/i8259.c 2004-06-03 01:34:23.000000000 +0000 @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -439,6 +440,7 @@ void __init init_IRQ(void) #endif #ifndef CONFIG_VISWS - setup_irq(2, &irq2); + if (!acpi_ioapic) + setup_irq(2, &irq2); #endif } diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/x86_64/kernel/io_apic.c linux-2.4.27-pre5/arch/x86_64/kernel/io_apic.c --- linux-2.4.26/arch/x86_64/kernel/io_apic.c 2004-04-14 13:05:28.000000000 +0000 +++ linux-2.4.27-pre5/arch/x86_64/kernel/io_apic.c 2004-06-03 01:35:45.000000000 +0000 @@ -256,8 +256,9 @@ void __init check_ioapic(void) 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 @@ static inline void check_timer(void) /* * - * 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 @@ void __init setup_IO_APIC(void) { 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 @@ int io_apic_set_pci_routing (int ioapic, 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/x86_64/kernel/mpparse.c linux-2.4.27-pre5/arch/x86_64/kernel/mpparse.c --- linux-2.4.26/arch/x86_64/kernel/mpparse.c 2004-04-14 13:05:28.000000000 +0000 +++ linux-2.4.27-pre5/arch/x86_64/kernel/mpparse.c 2004-06-03 01:33:26.000000000 +0000 @@ -793,8 +793,6 @@ void __init mp_override_legacy_irq ( u32 global_irq) { struct mpc_config_intsrc intsrc; - int i = 0; - int found = 0; int ioapic = -1; int pin = -1; @@ -827,23 +825,9 @@ void __init mp_override_legacy_irq ( (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,22 @@ void __init mp_config_acpi_legacy_irqs ( 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_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 +935,6 @@ void __init mp_parse_prt (void) 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 +973,11 @@ void __init mp_parse_prt (void) 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/x86_64/kernel/pci-pc.c linux-2.4.27-pre5/arch/x86_64/kernel/pci-pc.c --- linux-2.4.26/arch/x86_64/kernel/pci-pc.c 2004-04-14 13:05:28.000000000 +0000 +++ linux-2.4.27-pre5/arch/x86_64/kernel/pci-pc.c 2004-06-03 01:34:48.000000000 +0000 @@ -646,7 +646,7 @@ char * __devinit pcibios_setup(char *str 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/arch/x86_64/kernel/setup.c linux-2.4.27-pre5/arch/x86_64/kernel/setup.c --- linux-2.4.26/arch/x86_64/kernel/setup.c 2004-04-14 13:05:28.000000000 +0000 +++ linux-2.4.27-pre5/arch/x86_64/kernel/setup.c 2004-06-03 01:32:59.000000000 +0000 @@ -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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/crypto/Config.in linux-2.4.27-pre5/crypto/Config.in --- linux-2.4.26/crypto/Config.in 2004-04-14 13:05:28.000000000 +0000 +++ linux-2.4.27-pre5/crypto/Config.in 2004-06-03 01:35:48.000000000 +0000 @@ -81,6 +81,7 @@ if [ "$CONFIG_CRYPTO" = "y" ]; then 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/crypto/Makefile linux-2.4.27-pre5/crypto/Makefile --- linux-2.4.26/crypto/Makefile 2004-04-14 13:05:28.000000000 +0000 +++ linux-2.4.27-pre5/crypto/Makefile 2004-06-03 01:33:11.000000000 +0000 @@ -28,6 +28,7 @@ obj-$(CONFIG_CRYPTO_CAST5) += cast5.o obj-$(CONFIG_CRYPTO_CAST6) += cast6.o obj-$(CONFIG_CRYPTO_ARC4) += arc4.o obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o +obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/crypto/cipher.c linux-2.4.27-pre5/crypto/cipher.c --- linux-2.4.26/crypto/cipher.c 2004-04-14 13:05:28.000000000 +0000 +++ linux-2.4.27-pre5/crypto/cipher.c 2004-06-03 01:34:50.000000000 +0000 @@ -68,19 +68,20 @@ static int crypt(struct crypto_tfm *tfm, 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/crypto/digest.c linux-2.4.27-pre5/crypto/digest.c --- linux-2.4.26/crypto/digest.c 2003-08-25 11:44:40.000000000 +0000 +++ linux-2.4.27-pre5/crypto/digest.c 2004-06-03 01:32:44.000000000 +0000 @@ -42,6 +42,15 @@ static void final(struct crypto_tfm *tfm 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 +81,7 @@ int crypto_init_digest_ops(struct crypto ops->dit_update = update; ops->dit_final = final; ops->dit_digest = digest; + ops->dit_setkey = setkey; return crypto_alloc_hmac_block(tfm); } diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/crypto/michael_mic.c linux-2.4.27-pre5/crypto/michael_mic.c --- linux-2.4.26/crypto/michael_mic.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/crypto/michael_mic.c 2004-06-03 01:34:00.000000000 +0000 @@ -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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/crypto/scatterwalk.h linux-2.4.27-pre5/crypto/scatterwalk.h --- linux-2.4.26/crypto/scatterwalk.h 2004-04-14 13:05:28.000000000 +0000 +++ linux-2.4.27-pre5/crypto/scatterwalk.h 2004-06-03 01:34:09.000000000 +0000 @@ -38,6 +38,7 @@ static inline int scatterwalk_samebuf(st 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/crypto/tcrypt.c linux-2.4.27-pre5/crypto/tcrypt.c --- linux-2.4.26/crypto/tcrypt.c 2004-04-14 13:05:28.000000000 +0000 +++ linux-2.4.27-pre5/crypto/tcrypt.c 2004-06-03 01:34:44.000000000 +0000 @@ -63,7 +63,7 @@ static char *tvmem; 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", NULL }; static void @@ -114,6 +114,10 @@ test_hash (char * algo, struct hash_test 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); @@ -570,6 +574,8 @@ do_test(void) 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 +655,10 @@ do_test(void) 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; + #ifdef CONFIG_CRYPTO_HMAC case 100: test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS); diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/crypto/tcrypt.h linux-2.4.27-pre5/crypto/tcrypt.h --- linux-2.4.26/crypto/tcrypt.h 2004-04-14 13:05:28.000000000 +0000 +++ linux-2.4.27-pre5/crypto/tcrypt.h 2004-06-03 01:36:06.000000000 +0000 @@ -30,6 +30,8 @@ struct hash_testvec { 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 { @@ -1719,4 +1721,54 @@ struct comp_testvec deflate_decomp_tv_te }, }; +/* + * 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/Config.in linux-2.4.27-pre5/drivers/acpi/Config.in --- linux-2.4.26/drivers/acpi/Config.in 2004-04-14 13:05:28.000000000 +0000 +++ linux-2.4.27-pre5/drivers/acpi/Config.in 2004-06-03 01:35:27.000000000 +0000 @@ -16,6 +16,7 @@ if [ "$CONFIG_X86" = "y" ]; then 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 @@ if [ "$CONFIG_X86" = "y" ]; then 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/ac.c linux-2.4.27-pre5/drivers/acpi/ac.c --- linux-2.4.26/drivers/acpi/ac.c 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/acpi/ac.c 2004-06-03 01:35:13.000000000 +0000 @@ -156,6 +156,7 @@ acpi_ac_add_fs ( acpi_ac_dir); if (!acpi_device_dir(device)) return_VALUE(-ENODEV); + acpi_device_dir(device)->owner = THIS_MODULE; } /* 'state' [R] */ @@ -168,6 +169,7 @@ acpi_ac_add_fs ( 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_ac_remove_fs ( 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_init (void) 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/asus_acpi.c linux-2.4.27-pre5/drivers/acpi/asus_acpi.c --- linux-2.4.26/drivers/acpi/asus_acpi.c 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/acpi/asus_acpi.c 2004-06-03 01:34:37.000000000 +0000 @@ -41,7 +41,7 @@ #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 +125,11 @@ struct asus_hotk { 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 +139,7 @@ struct asus_hotk { #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 +166,7 @@ static struct model_data model_conf[END_ .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 +176,8 @@ static struct model_data model_conf[END_ .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 +214,8 @@ static struct model_data model_conf[END_ .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 +227,8 @@ static struct model_data model_conf[END_ .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 +248,10 @@ static struct model_data model_conf[END_ { .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 +281,6 @@ static struct model_data model_conf[END_ .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 +288,26 @@ static struct model_data model_conf[END_ }, { + .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 +317,17 @@ static struct model_data model_conf[END_ .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" } @@ -663,6 +652,23 @@ proc_write_lcd(struct file *file, const } +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 +685,7 @@ static void set_brightness(int value, st } /* 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 +698,6 @@ static void set_brightness(int value, st 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) @@ -874,6 +863,28 @@ static int __init asus_hotk_add_fs(struc 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 +940,29 @@ static int __init asus_hotk_get_info(str 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 +981,14 @@ static int __init asus_hotk_get_info(str 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 +1024,13 @@ static int __init asus_hotk_get_info(str 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; @@ -1112,6 +1149,8 @@ static int asus_hotk_remove(struct acpi_ if (ACPI_FAILURE(status)) printk(KERN_ERR "Asus ACPI: Error removing notify handler\n"); + asus_hotk_remove_fs(device); + kfree(hotk); return(0); diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/battery.c linux-2.4.27-pre5/drivers/acpi/battery.c --- linux-2.4.26/drivers/acpi/battery.c 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/acpi/battery.c 2004-06-03 01:35:11.000000000 +0000 @@ -474,14 +474,18 @@ acpi_battery_read_state ( 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_add_fs ( acpi_battery_dir); if (!acpi_device_dir(device)) return_VALUE(-ENODEV); + acpi_device_dir(device)->owner = THIS_MODULE; } /* 'info' [R] */ @@ -621,6 +626,7 @@ acpi_battery_add_fs ( else { entry->read_proc = acpi_battery_read_info; entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; } /* 'status' [R] */ @@ -633,6 +639,7 @@ acpi_battery_add_fs ( 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 @@ acpi_battery_add_fs ( 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_battery_remove_fs ( 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_init (void) 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/bus.c linux-2.4.27-pre5/drivers/acpi/bus.c --- linux-2.4.26/drivers/acpi/bus.c 2004-04-14 13:05:28.000000000 +0000 +++ linux-2.4.27-pre5/drivers/acpi/bus.c 2004-06-03 01:34:25.000000000 +0000 @@ -1964,8 +1964,10 @@ acpi_bus_init (void) 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/button.c linux-2.4.27-pre5/drivers/acpi/button.c --- linux-2.4.26/drivers/acpi/button.c 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/acpi/button.c 2004-06-03 01:35:11.000000000 +0000 @@ -171,10 +171,15 @@ acpi_button_add_fs ( 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 @@ acpi_button_add_fs ( 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 @@ acpi_button_add_fs ( else { entry->read_proc = acpi_button_lid_read_state; entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; } } @@ -210,10 +217,37 @@ static int 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_init (void) 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/ec.c linux-2.4.27-pre5/drivers/acpi/ec.c --- linux-2.4.26/drivers/acpi/ec.c 2004-04-14 13:05:28.000000000 +0000 +++ linux-2.4.27-pre5/drivers/acpi/ec.c 2004-06-03 01:33:10.000000000 +0000 @@ -544,6 +544,12 @@ acpi_ec_remove_fs ( { 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/fan.c linux-2.4.27-pre5/drivers/acpi/fan.c --- linux-2.4.26/drivers/acpi/fan.c 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/acpi/fan.c 2004-06-03 01:32:50.000000000 +0000 @@ -151,6 +151,7 @@ acpi_fan_add_fs ( 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 @@ acpi_fan_add_fs ( 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_fan_remove_fs ( 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_init (void) 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/pci_irq.c linux-2.4.27-pre5/drivers/acpi/pci_irq.c --- linux-2.4.26/drivers/acpi/pci_irq.c 2004-04-14 13:05:29.000000000 +0000 +++ linux-2.4.27-pre5/drivers/acpi/pci_irq.c 2004-06-03 01:36:09.000000000 +0000 @@ -373,7 +373,7 @@ acpi_pci_irq_enable ( 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/pci_link.c linux-2.4.27-pre5/drivers/acpi/pci_link.c --- linux-2.4.26/drivers/acpi/pci_link.c 2004-04-14 13:05:29.000000000 +0000 +++ linux-2.4.27-pre5/drivers/acpi/pci_link.c 2004-06-03 01:36:27.000000000 +0000 @@ -90,6 +90,9 @@ static struct { 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 @@ acpi_pci_link_check_possible ( 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 @@ acpi_pci_link_check_current ( { 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 @@ acpi_pci_link_check_current ( 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 @@ acpi_pci_link_get_current ( 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 @@ acpi_pci_link_get_current ( 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 @@ end: } 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) @@ -317,8 +306,7 @@ acpi_pci_link_set ( 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) @@ -341,33 +329,18 @@ acpi_pci_link_set ( } } - 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 +351,63 @@ retry_programming: 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 +461,7 @@ retry_programming: #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 +474,7 @@ static int acpi_irq_penalty[ACPI_MAX_IRQ 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 +534,30 @@ static int acpi_pci_link_allocate(struct 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 +573,8 @@ static int acpi_pci_link_allocate(struct /* 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 +626,7 @@ acpi_pci_link_get_irq ( 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 +672,6 @@ acpi_pci_link_add ( /* 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,8 +682,16 @@ acpi_pci_link_add ( 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); diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/pci_root.c linux-2.4.27-pre5/drivers/acpi/pci_root.c --- linux-2.4.26/drivers/acpi/pci_root.c 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/acpi/pci_root.c 2004-06-03 01:32:29.000000000 +0000 @@ -118,6 +118,7 @@ acpi_pci_root_add ( { 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 +153,6 @@ acpi_pci_root_add ( 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 +186,14 @@ acpi_pci_root_add ( 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)) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Wrong _BBN value, please reboot and using option 'pci=noacpi'\n")); + } + /* * Device & Function * ----------------- @@ -213,7 +220,12 @@ acpi_pci_root_add ( * 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/power.c linux-2.4.27-pre5/drivers/acpi/power.c --- linux-2.4.26/drivers/acpi/power.c 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/acpi/power.c 2004-06-03 01:32:37.000000000 +0000 @@ -469,6 +469,8 @@ acpi_power_remove_fs ( 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/processor.c linux-2.4.27-pre5/drivers/acpi/processor.c --- linux-2.4.26/drivers/acpi/processor.c 2004-04-14 13:05:29.000000000 +0000 +++ linux-2.4.27-pre5/drivers/acpi/processor.c 2004-06-03 01:34:16.000000000 +0000 @@ -2011,6 +2011,7 @@ acpi_processor_add_fs ( 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 @@ acpi_processor_add_fs ( else { entry->read_proc = acpi_processor_read_info; entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; } /* 'power' [R] */ @@ -2034,6 +2036,7 @@ acpi_processor_add_fs ( 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 @@ acpi_processor_add_fs ( 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 @@ acpi_processor_add_fs ( 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 @@ acpi_processor_add_fs ( 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_init (void) 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/tables.c linux-2.4.27-pre5/drivers/acpi/tables.c --- linux-2.4.26/drivers/acpi/tables.c 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/acpi/tables.c 2004-06-03 01:32:51.000000000 +0000 @@ -58,6 +58,7 @@ static char *acpi_table_signatures[ACPI_ [ACPI_SSDT] = "SSDT", [ACPI_SPMI] = "SPMI", [ACPI_HPET] = "HPET", + [ACPI_MCFG] = "MCFG", }; static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" }; diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/thermal.c linux-2.4.27-pre5/drivers/acpi/thermal.c --- linux-2.4.26/drivers/acpi/thermal.c 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/acpi/thermal.c 2004-06-03 01:34:32.000000000 +0000 @@ -1051,6 +1051,7 @@ acpi_thermal_add_fs ( acpi_thermal_dir); if (!acpi_device_dir(device)) return_VALUE(-ENODEV); + acpi_device_dir(device)->owner = THIS_MODULE; } /* 'state' [R] */ @@ -1063,6 +1064,7 @@ acpi_thermal_add_fs ( else { entry->read_proc = acpi_thermal_read_state; entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; } /* 'temperature' [R] */ @@ -1075,6 +1077,7 @@ acpi_thermal_add_fs ( else { entry->read_proc = acpi_thermal_read_temperature; entry->data = acpi_driver_data(device); + entry->owner = THIS_MODULE; } /* 'trip_points' [R/W] */ @@ -1088,6 +1091,7 @@ acpi_thermal_add_fs ( 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 +1105,7 @@ acpi_thermal_add_fs ( 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 +1119,7 @@ acpi_thermal_add_fs ( 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 +1133,16 @@ acpi_thermal_remove_fs ( 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 +1348,7 @@ acpi_thermal_init (void) 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/acpi/toshiba_acpi.c linux-2.4.27-pre5/drivers/acpi/toshiba_acpi.c --- linux-2.4.26/drivers/acpi/toshiba_acpi.c 2004-04-14 13:05:29.000000000 +0000 +++ linux-2.4.27-pre5/drivers/acpi/toshiba_acpi.c 2004-06-03 01:32:41.000000000 +0000 @@ -503,6 +503,8 @@ add_device(void) 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 @@ toshiba_acpi_init(void) 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 @@ toshiba_acpi_init(void) 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/atm/Config.in linux-2.4.27-pre5/drivers/atm/Config.in --- linux-2.4.26/drivers/atm/Config.in 2003-08-25 11:44:41.000000000 +0000 +++ linux-2.4.27-pre5/drivers/atm/Config.in 2004-06-03 01:35:26.000000000 +0000 @@ -83,6 +83,7 @@ if [ "$CONFIG_PCI" = "y" -o "$CONFIG_SBU 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/atm/fore200e.c linux-2.4.27-pre5/drivers/atm/fore200e.c --- linux-2.4.26/drivers/atm/fore200e.c 2003-11-28 18:26:19.000000000 +0000 +++ linux-2.4.27-pre5/drivers/atm/fore200e.c 2004-06-03 01:36:15.000000000 +0000 @@ -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 @@ fore200e_chunk_free(struct fore200e* for } - -#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 @@ fore200e_shutdown(struct fore200e* fore2 } - #ifdef CONFIG_ATM_FORE200E_PCA static u32 fore200e_pca_read(volatile u32* addr) @@ -501,20 +496,16 @@ static int 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 @@ fore200e_pca_dma_chunk_alloc(struct fore 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 @@ static int 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 @@ fore200e_pca_map(struct fore200e* fore20 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 @@ fore200e_pca_unmap(struct fore200e* fore { 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 @@ static int __init 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 @@ fore200e_pca_configure(struct fore200e* 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_pca_detect(const struct fore200 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 @@ fore200e_pca_proc_read(struct fore200e* #endif /* CONFIG_ATM_FORE200E_PCA */ - - #ifdef CONFIG_ATM_FORE200E_SBA static u32 @@ -792,7 +787,7 @@ fore200e_sba_dma_chunk_alloc(struct fore 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 @@ fore200e_sba_map(struct fore200e* fore20 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 @@ fore200e_sba_map(struct fore200e* fore20 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 @@ fore200e_sba_detect(const struct fore200 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 @@ fore200e_sba_proc_read(struct fore200e* 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 @@ fore200e_supply(struct fore200e* fore200 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 @@ fore200e_supply(struct fore200e* fore200 } - -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 @@ fore200e_push_rpd(struct fore200e* fore2 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 @@ fore200e_push_rpd(struct fore200e* fore2 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 @@ fore200e_push_rpd(struct fore200e* fore2 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 @@ fore200e_push_rpd(struct fore200e* fore2 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 @@ fore200e_irq_rx(struct fore200e* fore200 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 @@ fore200e_interrupt(int irq, void* dev, s 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 @@ fore200e_activate_vcin(struct fore200e* #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 @@ fore200e_activate_vcin(struct fore200e* *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 @@ fore200e_rate_ctrl(struct atm_qos* qos, { 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 @@ fore200e_rate_ctrl(struct atm_qos* qos, 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_open(struct atm_vcc *vcc, short 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_open(struct atm_vcc *vcc, short 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 @@ fore200e_send(struct atm_vcc *vcc, struc 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 @@ fore200e_send(struct atm_vcc *vcc, struc 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 @@ fore200e_send(struct atm_vcc *vcc, struc 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_send(struct atm_vcc *vcc, struc 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 @@ fore200e_send(struct atm_vcc *vcc, struc 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 @@ fore200e_getstats(struct fore200e* fore2 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 @@ fore200e_getstats(struct fore200e* fore2 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 @@ fore200e_getsockopt (struct atm_vcc* vcc 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 @@ fore200e_set_oc3(struct fore200e* fore20 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 @@ fore200e_setloop(struct fore200e* fore20 } 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 @@ fore200e_change_qos(struct atm_vcc* vcc, 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_change_qos(struct atm_vcc* vcc, 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_change_qos(struct atm_vcc* vcc, fore200e_rate_ctrl(qos, &fore200e_vcc->rate); set_bit(ATM_VF_HASQOS, &vcc->flags); + return 0; } @@ -2027,7 +2211,10 @@ fore200e_irq_request(struct fore200e* fo 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 @@ fore200e_get_esi(struct fore200e* fore20 if (!prom) return -ENOMEM; + ok = fore200e->bus->prom_read(fore200e, prom); if (ok < 0) { fore200e_kfree(prom); @@ -2089,10 +2277,16 @@ fore200e_alloc_rx_buf(struct fore200e* f 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 @@ fore200e_alloc_rx_buf(struct fore200e* f 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_init_bs_queue(struct fore200e* 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 @@ fore200e_init_tx_queue(struct fore200e* 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 @@ fore200e_init_cmd_queue(struct fore200e* /* 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 @@ fore200e_param_bs_queue(struct fore200e* { 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 @@ fore200e_initialize(struct fore200e* for 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 @@ fore200e_monitor_getc(struct fore200e* f 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 @@ fore200e_start_fw(struct fore200e* fore2 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 @@ fore200e_load_fw(struct fore200e* fore20 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_register(struct fore200e* fore2 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 @@ fore200e_detect(void) 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 @@ fore200e_cleanup(struct fore200e** head) 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 @@ fore200e_proc_read(struct atm_dev *dev,l 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 @@ fore200e_proc_read(struct atm_dev *dev,l 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 @@ fore200e_proc_read(struct atm_dev *dev,l " 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 @@ static const struct atmdev_ops fore200e_ send: fore200e_send, change_qos: fore200e_change_qos, proc_read: fore200e_proc_read, - owner: THIS_MODULE, + owner: THIS_MODULE }; @@ -3027,4 +3242,6 @@ static const struct fore200e_bus fore200 {} }; +#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); +#endif diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/atm/fore200e.h linux-2.4.27-pre5/drivers/atm/fore200e.h --- linux-2.4.26/drivers/atm/fore200e.h 2000-12-11 21:22:12.000000000 +0000 +++ linux-2.4.27-pre5/drivers/atm/fore200e.h 2004-06-03 01:32:23.000000000 +0000 @@ -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 @@ typedef struct tpd_haddr { ) } tpd_haddr_t; +#define TPD_HADDR_SHIFT 5 /* addr aligned on 32 byte boundary */ /* cp resident transmit queue entry */ @@ -517,13 +520,15 @@ typedef struct cp_cmdq_entry { /* 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 @@ typedef struct buffer { 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_cmdq { 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 @@ typedef struct host_bsq { 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 @@ typedef struct fore200e_bus { #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 @@ typedef struct fore200e { 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/atm/nicstar.c linux-2.4.27-pre5/drivers/atm/nicstar.c --- linux-2.4.26/drivers/atm/nicstar.c 2004-04-14 13:05:29.000000000 +0000 +++ linux-2.4.27-pre5/drivers/atm/nicstar.c 2004-06-03 01:33:01.000000000 +0000 @@ -760,7 +760,7 @@ static int __devinit ns_init_card(int i, 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 @@ static int __devinit ns_init_card(int i, 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 @@ static int __devinit ns_init_card(int i, 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 @@ static void ns_irq_handler(int irq, void 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 @@ static void ns_irq_handler(int irq, void 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 @@ static void dequeue_rx(ns_dev *card, ns_ 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 @@ static void dequeue_rx(ns_dev *card, ns_ 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 @@ static void dequeue_rx(ns_dev *card, ns_ 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 @@ static void dequeue_rx(ns_dev *card, ns_ 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 @@ static void ns_sb_destructor(struct sk_b 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 @@ static void ns_lb_destructor(struct sk_b 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 @@ static void ns_hb_destructor(struct sk_b 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 @@ static void dequeue_sm_buf(ns_dev *card, 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 @@ static void dequeue_sm_buf(ns_dev *card, #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 @@ static void dequeue_lg_buf(ns_dev *card, 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 @@ static void dequeue_lg_buf(ns_dev *card, #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 @@ static int ns_ioctl(struct atm_dev *dev, { 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 @@ static int ns_ioctl(struct atm_dev *dev, { 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 @@ static int ns_ioctl(struct atm_dev *dev, { 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/block/Config.in linux-2.4.27-pre5/drivers/block/Config.in --- linux-2.4.26/drivers/block/Config.in 2003-11-28 18:26:19.000000000 +0000 +++ linux-2.4.27-pre5/drivers/block/Config.in 2004-06-03 01:33:11.000000000 +0000 @@ -39,6 +39,7 @@ dep_mbool ' SCSI tape drive suppor 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 (carmel) support' CONFIG_BLK_DEV_CARMEL $CONFIG_PCI tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/block/Makefile linux-2.4.27-pre5/drivers/block/Makefile --- linux-2.4.26/drivers/block/Makefile 2003-06-13 14:51:32.000000000 +0000 +++ linux-2.4.27-pre5/drivers/block/Makefile 2004-06-03 01:35:13.000000000 +0000 @@ -31,6 +31,7 @@ obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss. 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_CARMEL) += carmel.o subdir-$(CONFIG_PARIDE) += paride diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/block/carmel.c linux-2.4.27-pre5/drivers/block/carmel.c --- linux-2.4.26/drivers/block/carmel.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/block/carmel.c 2004-06-03 01:33:25.000000000 +0000 @@ -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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/block/cciss.c linux-2.4.27-pre5/drivers/block/cciss.c --- linux-2.4.26/drivers/block/cciss.c 2004-04-14 13:05:29.000000000 +0000 +++ linux-2.4.27-pre5/drivers/block/cciss.c 2004-06-03 01:36:07.000000000 +0000 @@ -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 @@ const struct pci_device_id cciss_pci_dev 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 @@ static struct board_type products[] = { { 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 */ diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/block/cciss_scsi.c linux-2.4.27-pre5/drivers/block/cciss_scsi.c --- linux-2.4.26/drivers/block/cciss_scsi.c 2004-04-14 13:05:29.000000000 +0000 +++ linux-2.4.27-pre5/drivers/block/cciss_scsi.c 2004-06-03 01:32:25.000000000 +0000 @@ -1569,7 +1569,7 @@ static void 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/bluetooth/Makefile.lib linux-2.4.27-pre5/drivers/bluetooth/Makefile.lib --- linux-2.4.26/drivers/bluetooth/Makefile.lib 2003-11-28 18:26:19.000000000 +0000 +++ linux-2.4.27-pre5/drivers/bluetooth/Makefile.lib 2004-06-03 01:34:13.000000000 +0000 @@ -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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/bluetooth/bfusb.c linux-2.4.27-pre5/drivers/bluetooth/bfusb.c --- linux-2.4.26/drivers/bluetooth/bfusb.c 2003-11-28 18:26:19.000000000 +0000 +++ linux-2.4.27-pre5/drivers/bluetooth/bfusb.c 2004-06-03 01:32:39.000000000 +0000 @@ -359,11 +359,11 @@ static void bfusb_rx_complete(struct urb 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 @@ resubmit: bfusb->hdev.name, urb, err); } +unlock: read_unlock(&bfusb->lock); } diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/bluetooth/bt3c_cs.c linux-2.4.27-pre5/drivers/bluetooth/bt3c_cs.c --- linux-2.4.26/drivers/bluetooth/bt3c_cs.c 2002-11-28 23:53:12.000000000 +0000 +++ linux-2.4.27-pre5/drivers/bluetooth/bt3c_cs.c 2004-06-03 01:33:45.000000000 +0000 @@ -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 @@ static int bt3c_hci_ioctl(struct hci_dev -/* ======================== 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 @@ int bt3c_open(bt3c_info_t *info) /* 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 */ diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/bluetooth/hci_uart.h linux-2.4.27-pre5/drivers/bluetooth/hci_uart.h --- linux-2.4.26/drivers/bluetooth/hci_uart.h 2003-06-13 14:51:32.000000000 +0000 +++ linux-2.4.27-pre5/drivers/bluetooth/hci_uart.h 2004-06-03 01:34:26.000000000 +0000 @@ -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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/bluetooth/hci_usb.c linux-2.4.27-pre5/drivers/bluetooth/hci_usb.c --- linux-2.4.26/drivers/bluetooth/hci_usb.c 2004-04-14 13:05:29.000000000 +0000 +++ linux-2.4.27-pre5/drivers/bluetooth/hci_usb.c 2004-06-03 01:35:55.000000000 +0000 @@ -699,11 +699,11 @@ static void hci_usb_rx_complete(struct u 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 +740,8 @@ resubmit: BT_DBG("%s urb %p type %d resubmit status %d", hdev->name, urb, _urb->type, err); } + +unlock: read_unlock(&husb->completion_lock); } diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/char/Config.in linux-2.4.27-pre5/drivers/char/Config.in --- linux-2.4.26/drivers/char/Config.in 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/char/Config.in 2004-06-03 01:33:00.000000000 +0000 @@ -273,7 +273,6 @@ if [ "$CONFIG_WATCHDOG" != "n" ]; then 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/char/Makefile linux-2.4.27-pre5/drivers/char/Makefile --- linux-2.4.26/drivers/char/Makefile 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/char/Makefile 2004-06-03 01:35:58.000000000 +0000 @@ -320,7 +320,6 @@ obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/char/agp/agp.h linux-2.4.27-pre5/drivers/char/agp/agp.h --- linux-2.4.26/drivers/char/agp/agp.h 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/char/agp/agp.h 2004-06-03 01:33:58.000000000 +0000 @@ -316,6 +316,9 @@ struct agp_bridge_data { #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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/char/agp/agpgart_be.c linux-2.4.27-pre5/drivers/char/agp/agpgart_be.c --- linux-2.4.26/drivers/char/agp/agpgart_be.c 2004-04-14 13:05:29.000000000 +0000 +++ linux-2.4.27-pre5/drivers/char/agp/agpgart_be.c 2004-06-03 01:32:49.000000000 +0000 @@ -5738,6 +5738,7 @@ static int ati_create_gatt_table(void) 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 @@ static int ati_fetch_size(void) 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 @@ static int ati_configure(void) 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 @@ static void ati_cleanup(void) /* 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 @@ static struct { "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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/char/amd7xx_tco.c linux-2.4.27-pre5/drivers/char/amd7xx_tco.c --- linux-2.4.26/drivers/char/amd7xx_tco.c 2003-11-28 18:26:20.000000000 +0000 +++ linux-2.4.27-pre5/drivers/char/amd7xx_tco.c 1970-01-01 00:00:00.000000000 +0000 @@ -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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/char/drm/drmP.h linux-2.4.27-pre5/drivers/char/drm/drmP.h --- linux-2.4.26/drivers/char/drm/drmP.h 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/char/drm/drmP.h 2004-06-03 01:35:02.000000000 +0000 @@ -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 @@ __cmpxchg(volatile void *ptr, unsigned l (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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/char/tipar.c linux-2.4.27-pre5/drivers/char/tipar.c --- linux-2.4.26/drivers/char/tipar.c 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/char/tipar.c 2004-06-03 01:33:28.000000000 +0000 @@ -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 @@ init_ti_parallel(int minor) /* ----- 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 @@ tipar_ioctl(struct inode *inode, struct 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 @@ tipar_setup(char *str) 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/Config.in linux-2.4.27-pre5/drivers/hotplug/Config.in --- linux-2.4.26/drivers/hotplug/Config.in 2003-11-28 18:26:20.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/Config.in 2004-06-03 01:32:51.000000000 +0000 @@ -14,4 +14,11 @@ fi 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/Makefile linux-2.4.27-pre5/drivers/hotplug/Makefile --- linux-2.4.26/drivers/hotplug/Makefile 2003-08-25 11:44:41.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/Makefile 2004-06-03 01:34:56.000000000 +0000 @@ -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) += pci_hotplu 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_objs := acpiphp_core.o \ 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 @@ ibmphp.o: $(ibmphp-objs) 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/acpiphp.h linux-2.4.27-pre5/drivers/hotplug/acpiphp.h --- linux-2.4.26/drivers/hotplug/acpiphp.h 2003-11-28 18:26:20.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/acpiphp.h 2004-06-03 01:32:27.000000000 +0000 @@ -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 @@ struct acpiphp_func { #define SLOT_POWEREDON (0x00000001) #define SLOT_ENABLED (0x00000002) -#define SLOT_MULTIFUNCTION (x000000004) +#define SLOT_MULTIFUNCTION (0x00000004) /* function flags */ @@ -269,8 +213,6 @@ struct acpiphp_func { #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_power_status (stru 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/acpiphp_core.c linux-2.4.27-pre5/drivers/hotplug/acpiphp_core.c --- linux-2.4.26/drivers/hotplug/acpiphp_core.c 2003-11-28 18:26:20.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/acpiphp_core.c 2004-06-03 01:35:23.000000000 +0000 @@ -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_power_status (struct hotp 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 @@ static struct hotplug_slot_ops acpi_hotp .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 @@ static int get_adapter_status (struct ho } +/** + * 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/acpiphp_glue.c linux-2.4.27-pre5/drivers/hotplug/acpiphp_glue.c --- linux-2.4.26/drivers/hotplug/acpiphp_glue.c 2003-11-28 18:26:20.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/acpiphp_glue.c 2004-06-03 01:35:25.000000000 +0000 @@ -26,12 +26,12 @@ * */ -#include -#include +#include #include + +#include #include #include -#include #include #include "pci_hotplug.h" @@ -389,12 +389,8 @@ static struct pci_bus *find_pci_bus(cons 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 @@ static void decode_hpp(struct acpiphp_br 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 init_bridge_misc (struct acp 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 @@ static void add_host_bridge (acpi_handle /* 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 @@ static int power_on_slot (struct acpiphp 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 @@ static int power_on_slot (struct acpiphp 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 @@ static int power_off_slot (struct acpiph 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 @@ static int power_off_slot (struct acpiph 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 @@ static int enable_device (struct acpiphp retval = acpiphp_configure_function(func); if (retval) goto err_exit; - - func->flags |= FUNC_EXISTS; } slot->flags |= SLOT_ENABLED; @@ -1003,15 +965,12 @@ static int disable_device (struct acpiph 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 @@ int acpiphp_check_bridge (struct acpiphp up(&slot->crit_sect); goto err_exit; } - enabled++; + disabled++; } } else { /* if disabled but present, enable */ @@ -1402,7 +1361,7 @@ int acpiphp_check_bridge (struct acpiphp up(&slot->crit_sect); goto err_exit; } - disabled++; + enabled++; } } } @@ -1468,3 +1427,18 @@ u8 acpiphp_get_adapter_status (struct ac 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/acpiphp_pci.c linux-2.4.27-pre5/drivers/hotplug/acpiphp_pci.c --- linux-2.4.26/drivers/hotplug/acpiphp_pci.c 2003-11-28 18:26:20.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/acpiphp_pci.c 2004-06-03 01:34:00.000000000 +0000 @@ -29,11 +29,11 @@ * */ -#include -#include +#include #include + +#include #include -#include #include "pci_hotplug.h" #include "acpiphp.h" @@ -78,8 +78,8 @@ static int init_config_space (struct acp 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 @@ static int detect_used_resource (struct 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 @@ int acpiphp_init_func_resource (struct a 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/acpiphp_res.c linux-2.4.27-pre5/drivers/hotplug/acpiphp_res.c --- linux-2.4.26/drivers/hotplug/acpiphp_res.c 2003-11-28 18:26:20.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/acpiphp_res.c 2004-06-03 01:34:08.000000000 +0000 @@ -29,7 +29,7 @@ * */ -#include +#include #include #include @@ -39,7 +39,6 @@ #include #include #include -#include #include #include @@ -225,7 +224,7 @@ struct pci_resource *acpiphp_get_io_reso } /* 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/pci_hotplug.h linux-2.4.27-pre5/drivers/hotplug/pci_hotplug.h --- linux-2.4.26/drivers/hotplug/pci_hotplug.h 2003-11-28 18:26:20.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/pci_hotplug.h 2004-06-03 01:33:43.000000000 +0000 @@ -36,15 +36,36 @@ enum pci_bus_speed { 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 @@ struct hotplug_slot_core; * @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 @@ struct hotplug_slot_ops { 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 @@ struct hotplug_slot_ops { * @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 @@ struct hotplug_slot_info { 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/pci_hotplug_core.c linux-2.4.27-pre5/drivers/hotplug/pci_hotplug_core.c --- linux-2.4.26/drivers/hotplug/pci_hotplug_core.c 2003-11-28 18:26:20.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/pci_hotplug_core.c 2004-06-03 01:35:16.000000000 +0000 @@ -74,6 +74,7 @@ struct hotplug_slot_core { 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 @@ static char *pci_bus_speed_strings[] = { "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 @@ static struct file_operations presence_f 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(power_status, u8) 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) @@ -859,6 +871,52 @@ exit: 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; + + dbg("count = %d, offset = %lld\n", count, *offset); + + if (*offset < 0) + return -EINVAL; + if (count <= 0) + return 0; + if (*offset != 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 += len; + retval = len; + +exit: + free_page((unsigned long)page); + return retval; +} + static char *unknown_speed = "Unknown bus speed"; static ssize_t max_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset) @@ -1055,6 +1113,13 @@ static int fs_add_slot (struct hotplug_s 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 +1157,8 @@ static void fs_remove_slot (struct hotpl 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 +1310,9 @@ int pci_hp_change_slot_info (const char 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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/pciehp.h linux-2.4.27-pre5/drivers/hotplug/pciehp.h --- linux-2.4.26/drivers/hotplug/pciehp.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/pciehp.h 2004-06-03 01:36:18.000000000 +0000 @@ -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 -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/pciehp_core.c linux-2.4.27-pre5/drivers/hotplug/pciehp_core.c --- linux-2.4.26/drivers/hotplug/pciehp_core.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/pciehp_core.c 2004-06-03 01:34:59.000000000 +0000 @@ -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_slots; + u8 slot_device; + u32 slot_number; + int result; + + dbg("%s\n",__FUNCTION__); + + number_of_slots = ctrl->num_slots; + slot_device = ctrl->slot_device_offset; + slot_number = ctrl->first_slot; + + while (number_of_slots) { + new_slot = (struct slot *) kmalloc(sizeof(struct slot), GFP_KERNEL); + if (!new_slot) + return -ENOMEM; + + memset(new_slot, 0, sizeof(struct slot)); + new_slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL); + if (!new_slot->hotplug_slot) { + kfree (new_slot); + return -ENOMEM; + } + memset(new_slot->hotplug_slot, 0, sizeof (struct hotplug_slot)); + + new_slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!new_slot->hotplug_slot->info) { + kfree (new_slot->hotplug_slot); + kfree (new_slot); + return -ENOMEM; + } + memset(new_slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info)); + new_slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL); + if (!new_slot->hotplug_slot->name) { + kfree (new_slot->hotplug_slot->info); + kfree (new_slot->hotplug_slot); + kfree (new_slot); + return -ENOMEM; + } + + new_slot->magic = SLOT_MAGIC; + new_slot->ctrl = ctrl; + new_slot->bus = ctrl->slot_bus; + new_slot->device = slot_device; + new_slot->hpc_ops = ctrl->hpc_ops; + + new_slot->number = ctrl->first_slot; + new_slot->hp_slot = slot_device - ctrl->slot_device_offset; + + /* register this slot with the hotplug pci core */ + new_slot->hotplug_slot->private = new_slot; + make_slot_name (new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot); + new_slot->hotplug_slot->ops = &pciehp_hotplug_slot_ops; + + new_slot->hpc_ops->get_power_status(new_slot, &(new_slot->hotplug_slot->info->power_status)); + new_slot->hpc_ops->get_attention_status(new_slot, &(new_slot->hotplug_slot->info->attention_status)); + new_slot->hpc_ops->get_latch_status(new_slot, &(new_slot->hotplug_slot->info->latch_status)); + new_slot->hpc_ops->get_adapter_status(new_slot, &(new_slot->hotplug_slot->info->adapter_status)); + + dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x slot_device_offset=%x\n", + new_slot->bus, new_slot->device, new_slot->hp_slot, new_slot->number, ctrl->slot_device_offset); + result = pci_hp_register (new_slot->hotplug_slot); + if (result) { + err ("pci_hp_register failed with error %d\n", result); + kfree (new_slot->hotplug_slot->info); + kfree (new_slot->hotplug_slot->name); + kfree (new_slot->hotplug_slot); + kfree (new_slot); + return result; + } + + new_slot->next = ctrl->slot; + ctrl->slot = new_slot; + + number_of_slots--; + slot_device++; + slot_number += ctrl->slot_num_inc; + } + + return(0); +} + + +static int cleanup_slots (struct controller * ctrl) +{ + struct slot *old_slot, *next_slot; + + old_slot = ctrl->slot; + ctrl->slot = NULL; + + while (old_slot) { + next_slot = old_slot->next; + pci_hp_deregister (old_slot->hotplug_slot); + kfree(old_slot->hotplug_slot->info); + kfree(old_slot->hotplug_slot->name); + kfree(old_slot->hotplug_slot); + kfree(old_slot); + old_slot = next_slot; + } + + + return(0); +} + +static int get_ctlr_slot_config(struct controller *ctrl) +{ + int num_ctlr_slots; /* Not needed; PCI Express has 1 slot per port */ + int first_device_num; /* Not needed */ + int physical_slot_num; + int updown; /* Not needed */ + int rc; + int flags; /* Not needed */ + + rc = pcie_get_ctlr_slot_config(ctrl, &num_ctlr_slots, &first_device_num, &physical_slot_num, &updown, &flags); + if (rc) { + err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", __FUNCTION__, ctrl->bus, ctrl->device); + return (-1); + } + + ctrl->num_slots = num_ctlr_slots; /* PCI Express has 1 slot per port */ + ctrl->slot_device_offset = first_device_num; + ctrl->first_slot = physical_slot_num; + ctrl->slot_num_inc = updown; /* Not needed */ /* either -1 or 1 */ + + dbg("%s: bus(0x%x) num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) updown(%d) for b:d (%x:%x)\n", + __FUNCTION__, ctrl->slot_bus, num_ctlr_slots, first_device_num, physical_slot_num, updown, + ctrl->bus, ctrl->device); + + return (0); +} + + +/* + * set_attention_status - Turns the Amber LED for a slot on, off or blink + */ +static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + hotplug_slot->info->attention_status = status; + slot->hpc_ops->set_attention_status(slot, status); + + + return 0; +} + + +static int enable_slot (struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + return pciehp_enable_slot(slot); +} + + +static int disable_slot (struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + return pciehp_disable_slot(slot); +} + + +static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value) +{ + return 0; +} + + +static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + retval = slot->hpc_ops->get_power_status(slot, value); + if (retval < 0) + *value = hotplug_slot->info->power_status; + + return 0; +} + +static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + retval = slot->hpc_ops->get_attention_status(slot, value); + if (retval < 0) + *value = hotplug_slot->info->attention_status; + + return 0; +} + +static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + retval = slot->hpc_ops->get_latch_status(slot, value); + if (retval < 0) + *value = hotplug_slot->info->latch_status; + + return 0; +} + +static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + retval = slot->hpc_ops->get_adapter_status(slot, value); + + if (retval < 0) + *value = hotplug_slot->info->adapter_status; + + return 0; +} + +static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + retval = slot->hpc_ops->get_max_bus_speed(slot, value); + if (retval < 0) + *value = PCI_SPEED_UNKNOWN; + + return 0; +} + +static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + retval = slot->hpc_ops->get_cur_bus_speed(slot, value); + if (retval < 0) + *value = PCI_SPEED_UNKNOWN; + + return 0; +} + +static int pcie_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int rc; + struct controller *ctrl; + struct slot *t_slot; + int first_device_num = 0; /* first PCI device number supported by this PCIE */ + int num_ctlr_slots; /* number of slots supported by this HPC */ + u8 value; + + ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL); + if (!ctrl) { + err("%s : out of memory\n", __FUNCTION__); + goto err_out_none; + } + memset(ctrl, 0, sizeof(struct controller)); + + dbg("%s: DRV_thread pid = %d\n", __FUNCTION__, current->pid); + + rc = pcie_init(ctrl, pdev, + (php_intr_callback_t) pciehp_handle_attention_button, + (php_intr_callback_t) pciehp_handle_switch_change, + (php_intr_callback_t) pciehp_handle_presence_change, + (php_intr_callback_t) pciehp_handle_power_fault); + if (rc) { + dbg("%s: controller initialization failed\n", PCIE_MODULE_NAME); + goto err_out_free_ctrl; + } + + ctrl->pci_dev = pdev; + + ctrl->pci_bus = kmalloc (sizeof (*ctrl->pci_bus), GFP_KERNEL); + if (!ctrl->pci_bus) { + err("%s: out of memory\n", __FUNCTION__); + rc = -ENOMEM; + goto err_out_unmap_mmio_region; + } + dbg("%s: ctrl->pci_bus %p\n", __FUNCTION__, ctrl->pci_bus); + memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus)); + + ctrl->bus = pdev->bus->number; /* ctrl bus */ + ctrl->slot_bus = pdev->subordinate->number; /* bus controlled by this HPC */ + + ctrl->device = PCI_SLOT(pdev->devfn); + ctrl->function = PCI_FUNC(pdev->devfn); + dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", __FUNCTION__, + ctrl->bus, ctrl->device, ctrl->function, pdev->irq); + + /* + * Save configuration headers for this and subordinate PCI buses + */ + + rc = get_ctlr_slot_config(ctrl); + if (rc) { + err(msg_initialization_err, rc); + goto err_out_free_ctrl_bus; + } + + first_device_num = ctrl->slot_device_offset; + num_ctlr_slots = ctrl->num_slots; + + + /* Store PCI Config Space for all devices on this bus */ + dbg("%s: Before calling pciehp_save_config, ctrl->bus %x,ctrl->slot_bus %x\n", + __FUNCTION__,ctrl->bus, ctrl->slot_bus); + rc = pciehp_save_config(ctrl, ctrl->slot_bus, num_ctlr_slots, first_device_num); + if (rc) { + err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc); + goto err_out_free_ctrl_bus; + } + + /* Get IO, memory, and IRQ resources for new devices */ + rc = pciehprm_find_available_resources(ctrl); + + ctrl->add_support = !rc; + if (rc) { + dbg("pciehprm_find_available_resources = %#x\n", rc); + err("unable to locate PCI configuration resources for hot plug add.\n"); + goto err_out_free_ctrl_bus; + } + /* Setup the slot information structures */ + rc = init_slots(ctrl); + if (rc) { + err(msg_initialization_err, 6); + goto err_out_free_ctrl_slot; + } + + t_slot = pciehp_find_slot(ctrl, first_device_num); + dbg("%s: t_slot %p\n", __FUNCTION__, t_slot); + + /* Finish setting up the hot plug ctrl device */ + ctrl->next_event = 0; + + if (!pciehp_ctrl_list) { + pciehp_ctrl_list = ctrl; + ctrl->next = NULL; + } else { + ctrl->next = pciehp_ctrl_list; + pciehp_ctrl_list = ctrl; + } + + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */ + dbg("%s: adapter value %x\n", __FUNCTION__, value); + if (!value) { + rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/ + if (rc) { + up(&ctrl->crit_sect); + goto err_out_free_ctrl_slot; + } else + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); + } + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + + return 0; + +err_out_free_ctrl_slot: + cleanup_slots(ctrl); +err_out_free_ctrl_bus: + kfree(ctrl->pci_bus); +err_out_unmap_mmio_region: + ctrl->hpc_ops->release_ctlr(ctrl); +err_out_free_ctrl: + kfree(ctrl); +err_out_none: + return -ENODEV; +} + + +static int pcie_start_thread(void) +{ + int loop; + int retval = 0; + + dbg("Initialize + Start the notification/polling mechanism \n"); + + retval = pciehp_event_start_thread(); + if (retval) { + dbg("pciehp_event_start_thread() failed\n"); + return retval; + } + + dbg("Initialize slot lists\n"); + /* One slot list for each bus in the system */ + for (loop = 0; loop < 256; loop++) { + pciehp_slot_list[loop] = NULL; + } + + return retval; +} + + +static void unload_pciehpd(void) +{ + struct pci_func *next; + struct pci_func *TempSlot; + int loop; + struct controller *ctrl; + struct controller *tctrl; + struct pci_resource *res; + struct pci_resource *tres; + + ctrl = pciehp_ctrl_list; + while (ctrl) { + cleanup_slots(ctrl); + + res = ctrl->io_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = ctrl->mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = ctrl->p_mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = ctrl->bus_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + kfree (ctrl->pci_bus); + + ctrl->hpc_ops->release_ctlr(ctrl); + + tctrl = ctrl; + ctrl = ctrl->next; + + kfree(tctrl); + } + + for (loop = 0; loop < 256; loop++) { + next = pciehp_slot_list[loop]; + while (next != NULL) { + res = next->io_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = next->mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = next->p_mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = next->bus_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + TempSlot = next; + next = next->next; + kfree(TempSlot); + } + } + + /* Stop the notification mechanism */ + pciehp_event_stop_thread(); + +} + + +static struct pci_device_id pcied_pci_tbl[] __devinitdata = { + { + class: ((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), + class_mask: ~0, + vendor: PCI_ANY_ID, + device: PCI_ANY_ID, + subvendor: PCI_ANY_ID, + subdevice: PCI_ANY_ID, + }, + { /* end: all zeroes */ } +}; + +MODULE_DEVICE_TABLE(pci, pcied_pci_tbl); + + + +static struct pci_driver pcie_driver = { + .name = PCIE_MODULE_NAME, + .id_table = pcied_pci_tbl, + .probe = pcie_probe, + /* remove: pcie_remove_one, */ +}; + + + +static int __init pcied_init(void) +{ + int retval = 0; + +#ifdef CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE + pciehp_poll_mode = 1; +#endif + retval = pcie_start_thread(); + if (retval) + goto error_hpc_init; + + retval = pciehprm_init(PCI); + if (!retval) { + retval = pci_module_init(&pcie_driver); + dbg("pci_module_init = %d\n", retval); + info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); + } + +error_hpc_init: + if (retval) { + pciehprm_cleanup(); + pciehp_event_stop_thread(); + } + + return retval; +} + +static void __exit pcied_cleanup(void) +{ + dbg("unload_pciehpd()\n"); + unload_pciehpd(); + + pciehprm_cleanup(); + + dbg("pci_unregister_driver\n"); + pci_unregister_driver(&pcie_driver); + + info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); +} + + +module_init(pcied_init); +module_exit(pcied_cleanup); + + diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/pciehp_ctrl.c linux-2.4.27-pre5/drivers/hotplug/pciehp_ctrl.c --- linux-2.4.26/drivers/hotplug/pciehp_ctrl.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/pciehp_ctrl.c 2004-06-03 01:32:49.000000000 +0000 @@ -0,0 +1,2629 @@ +/* + * 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" + +static u32 configure_new_device(struct controller *ctrl, struct pci_func *func, + u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev); +static int configure_new_function( struct controller *ctrl, struct pci_func *func, + u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev); +static void interrupt_event_handler(struct controller *ctrl); + +static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ +static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */ +static int event_finished; +static unsigned long pushbutton_pending; /* = 0 */ + +u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id) +{ + struct controller *ctrl = (struct controller *) inst_id; + struct slot *p_slot; + u8 rc = 0; + u8 getstatus; + struct pci_func *func; + struct event_info *taskInfo; + + /* Attention Button Change */ + dbg("pciehp: Attention button interrupt received.\n"); + + func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); + + /* This is the structure that tells the worker thread what to do */ + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + + p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); + p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); + + ctrl->next_event = (ctrl->next_event + 1) % 10; + taskInfo->hp_slot = hp_slot; + + rc++; + + /* + * Button pressed - See if need to TAKE ACTION!!! + */ + info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot); + taskInfo->event_type = INT_BUTTON_PRESS; + + if ((p_slot->state == BLINKINGON_STATE) + || (p_slot->state == BLINKINGOFF_STATE)) { + /* Cancel if we are still blinking; this means that we press the + * attention again before the 5 sec. limit expires to cancel hot-add + * or hot-remove + */ + taskInfo->event_type = INT_BUTTON_CANCEL; + info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot); + } else if ((p_slot->state == POWERON_STATE) + || (p_slot->state == POWEROFF_STATE)) { + /* Ignore if the slot is on power-on or power-off state; this + * means that the previous attention button action to hot-add or + * hot-remove is undergoing + */ + taskInfo->event_type = INT_BUTTON_IGNORE; + info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot); + } + if (rc) + up(&event_semaphore); /* signal event thread that new event is posted */ + + return 0; + +} + +u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id) +{ + struct controller *ctrl = (struct controller *) inst_id; + struct slot *p_slot; + u8 rc = 0; + u8 getstatus; + struct pci_func *func; + struct event_info *taskInfo; + + /* Switch Change */ + dbg("pciehp: Switch interrupt received.\n"); + + func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); + + /* this is the structure that tells the worker thread + * what to do + */ + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + ctrl->next_event = (ctrl->next_event + 1) % 10; + taskInfo->hp_slot = hp_slot; + + rc++; + p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); + p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); + + if (getstatus) { + /* + * Switch opened + */ + info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot); + func->switch_save = 0; + taskInfo->event_type = INT_SWITCH_OPEN; + } else { + /* + * Switch closed + */ + info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot); + func->switch_save = 0x10; + taskInfo->event_type = INT_SWITCH_CLOSE; + } + if (rc) + up(&event_semaphore); /* signal event thread that new event is posted */ + + return rc; +} + +u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id) +{ + struct controller *ctrl = (struct controller *) inst_id; + struct slot *p_slot; + u8 rc = 0; + struct pci_func *func; + struct event_info *taskInfo; + + /* Presence Change */ + dbg("pciehp: Presence/Notify input change.\n"); + + func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); + + /* This is the structure that tells the worker thread + * what to do + */ + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + ctrl->next_event = (ctrl->next_event + 1) % 10; + taskInfo->hp_slot = hp_slot; + + rc++; + p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + + /* Switch is open, assume a presence change + * Save the presence state + */ + p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); + if (func->presence_save) { + /* + * Card Present + */ + info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot); + taskInfo->event_type = INT_PRESENCE_ON; + } else { + /* + * Not Present + */ + info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot); + taskInfo->event_type = INT_PRESENCE_OFF; + } + if (rc) + up(&event_semaphore); /* signal event thread that new event is posted */ + + return rc; +} + +u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id) +{ + struct controller *ctrl = (struct controller *) inst_id; + struct slot *p_slot; + u8 rc = 0; + struct pci_func *func; + struct event_info *taskInfo; + + /* power fault */ + dbg("pciehp: Power fault interrupt received.\n"); + + func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); + + /* This is the structure that tells the worker thread + * what to do + */ + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + ctrl->next_event = (ctrl->next_event + 1) % 10; + taskInfo->hp_slot = hp_slot; + + rc++; + p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + + if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { + /* + * Power fault cleared + */ + info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot); + func->status = 0x00; + taskInfo->event_type = INT_POWER_FAULT_CLEAR; + } else { + /* + * Power fault + */ + info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot); + taskInfo->event_type = INT_POWER_FAULT; + /* Set power fault status for this board */ + func->status = 0xFF; + info("power fault bit %x set\n", hp_slot); + } + if (rc) + up(&event_semaphore); /* Signal event thread that new event is posted */ + + return rc; +} + + +/* + * sort_by_size + * + * Sorts nodes on the list by their length. + * Smallest first. + * + */ +static int sort_by_size(struct pci_resource **head) +{ + struct pci_resource *current_res; + struct pci_resource *next_res; + int out_of_order = 1; + + if (!(*head)) + return(1); + + if (!((*head)->next)) + return(0); + + while (out_of_order) { + out_of_order = 0; + + /* Special case for swapping list head */ + if (((*head)->next) && + ((*head)->length > (*head)->next->length)) { + out_of_order++; + current_res = *head; + *head = (*head)->next; + current_res->next = (*head)->next; + (*head)->next = current_res; + } + + current_res = *head; + + while (current_res->next && current_res->next->next) { + if (current_res->next->length > current_res->next->next->length) { + out_of_order++; + next_res = current_res->next; + current_res->next = current_res->next->next; + current_res = current_res->next; + next_res->next = current_res->next; + current_res->next = next_res; + } else + current_res = current_res->next; + } + } /* End of out_of_order loop */ + + return(0); +} + + +/* + * sort_by_max_size + * + * Sorts nodes on the list by their length. + * Largest first. + * + */ +static int sort_by_max_size(struct pci_resource **head) +{ + struct pci_resource *current_res; + struct pci_resource *next_res; + int out_of_order = 1; + + if (!(*head)) + return(1); + + if (!((*head)->next)) + return(0); + + while (out_of_order) { + out_of_order = 0; + + /* Special case for swapping list head */ + if (((*head)->next) && + ((*head)->length < (*head)->next->length)) { + out_of_order++; + current_res = *head; + *head = (*head)->next; + current_res->next = (*head)->next; + (*head)->next = current_res; + } + + current_res = *head; + + while (current_res->next && current_res->next->next) { + if (current_res->next->length < current_res->next->next->length) { + out_of_order++; + next_res = current_res->next; + current_res->next = current_res->next->next; + current_res = current_res->next; + next_res->next = current_res->next; + current_res->next = next_res; + } else + current_res = current_res->next; + } + } /* End of out_of_order loop */ + + return(0); +} + + +/* + * do_pre_bridge_resource_split + * + * Returns zero or one node of resources that aren't in use + * + */ +static struct pci_resource *do_pre_bridge_resource_split (struct pci_resource **head, struct pci_resource **orig_head, u32 alignment) +{ + struct pci_resource *prevnode = NULL; + struct pci_resource *node; + struct pci_resource *split_node; + u32 rc; + u32 temp_dword; + dbg("do_pre_bridge_resource_split\n"); + + if (!(*head) || !(*orig_head)) + return(NULL); + + rc = pciehp_resource_sort_and_combine(head); + + if (rc) + return(NULL); + + if ((*head)->base != (*orig_head)->base) + return(NULL); + + if ((*head)->length == (*orig_head)->length) + return(NULL); + + + /* If we got here, there the bridge requires some of the resource, but + * we may be able to split some off of the front + */ + node = *head; + + if (node->length & (alignment -1)) { + /* This one isn't an aligned length, so we'll make a new entry + * and split it up. + */ + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + temp_dword = (node->length | (alignment-1)) + 1 - alignment; + + split_node->base = node->base; + split_node->length = temp_dword; + + node->length -= temp_dword; + node->base += split_node->length; + + /* Put it in the list */ + *head = split_node; + split_node->next = node; + } + + if (node->length < alignment) { + return(NULL); + } + + /* Now unlink it */ + if (*head == node) { + *head = node->next; + node->next = NULL; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + node->next = NULL; + } + + return(node); +} + + +/* + * do_bridge_resource_split + * + * Returns zero or one node of resources that aren't in use + * + */ +static struct pci_resource *do_bridge_resource_split (struct pci_resource **head, u32 alignment) +{ + struct pci_resource *prevnode = NULL; + struct pci_resource *node; + u32 rc; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + rc = pciehp_resource_sort_and_combine(head); + + if (rc) + return(NULL); + + node = *head; + + while (node->next) { + prevnode = node; + node = node->next; + kfree(prevnode); + } + + if (node->length < alignment) { + kfree(node); + return(NULL); + } + + if (node->base & (alignment - 1)) { + /* Short circuit if adjusted size is too small */ + temp_dword = (node->base | (alignment-1)) + 1; + if ((node->length - (temp_dword - node->base)) < alignment) { + kfree(node); + return(NULL); + } + + node->length -= (temp_dword - node->base); + node->base = temp_dword; + } + + if (node->length & (alignment - 1)) { + /* There's stuff in use after this node */ + kfree(node); + return(NULL); + } + + return(node); +} + + +/* + * get_io_resource + * + * this function sorts the resource list by size and then + * returns the first node of "size" length that is not in the + * ISA aliasing window. If it finds a node larger than "size" + * it will split it up. + * + * size must be a power of two. + */ +static struct pci_resource *get_io_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node = NULL; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if ( pciehp_resource_sort_and_combine(head) ) + return(NULL); + + if ( sort_by_size(head) ) + return(NULL); + + for (node = *head; node; node = node->next) { + if (node->length < size) + continue; + + if (node->base & (size - 1)) { + /* This one isn't base aligned properly + so we'll make a new entry and split it up */ + temp_dword = (node->base | (size-1)) + 1; + + /*/ Short circuit if adjusted size is too small */ + if ((node->length - (temp_dword - node->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base; + split_node->length = temp_dword - node->base; + node->base = temp_dword; + node->length -= split_node->length; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of non-aligned base */ + + /* Don't need to check if too small since we already did */ + if (node->length > size) { + /* This one is longer than we need + so we'll make a new entry and split it up */ + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base + size; + split_node->length = node->length - size; + node->length = size; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of too big on top end */ + + /* For IO make sure it's not in the ISA aliasing space */ + if (node->base & 0x300L) + continue; + + /* If we got here, then it is the right size + Now take it out of the list */ + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + /* Stop looping */ + break; + } + + return(node); +} + + +/* + * get_max_resource + * + * Gets the largest node that is at least "size" big from the + * list pointed to by head. It aligns the node on top and bottom + * to "size" alignment before returning it. + * J.I. modified to put max size limits of; 64M->32M->16M->8M->4M->1M + * This is needed to avoid allocating entire ACPI _CRS res to one child bridge/slot. + */ +static struct pci_resource *get_max_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *max; + struct pci_resource *temp; + struct pci_resource *split_node; + u32 temp_dword; + u32 max_size[] = { 0x4000000, 0x2000000, 0x1000000, 0x0800000, 0x0400000, 0x0200000, 0x0100000, 0x00 }; + int i; + + if (!(*head)) + return(NULL); + + if (pciehp_resource_sort_and_combine(head)) + return(NULL); + + if (sort_by_max_size(head)) + return(NULL); + + for (max = *head;max; max = max->next) { + + /* If not big enough we could probably just bail, + instead we'll continue to the next. */ + if (max->length < size) + continue; + + if (max->base & (size - 1)) { + /* This one isn't base aligned properly + so we'll make a new entry and split it up */ + temp_dword = (max->base | (size-1)) + 1; + + /* Short circuit if adjusted size is too small */ + if ((max->length - (temp_dword - max->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = max->base; + split_node->length = temp_dword - max->base; + max->base = temp_dword; + max->length -= split_node->length; + + /* Put it next in the list */ + split_node->next = max->next; + max->next = split_node; + } + + if ((max->base + max->length) & (size - 1)) { + /* This one isn't end aligned properly at the top + so we'll make a new entry and split it up */ + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + temp_dword = ((max->base + max->length) & ~(size - 1)); + split_node->base = temp_dword; + split_node->length = max->length + max->base + - split_node->base; + max->length -= split_node->length; + + /* Put it in the list */ + split_node->next = max->next; + max->next = split_node; + } + + /* Make sure it didn't shrink too much when we aligned it */ + if (max->length < size) + continue; + + for ( i = 0; max_size[i] > size; i++) { + if (max->length > max_size[i]) { + split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!split_node) + break; /* return (NULL); */ + split_node->base = max->base + max_size[i]; + split_node->length = max->length - max_size[i]; + max->length = max_size[i]; + /* Put it next in the list */ + split_node->next = max->next; + max->next = split_node; + break; + } + } + + /* Now take it out of the list */ + temp = (struct pci_resource*) *head; + if (temp == max) { + *head = max->next; + } else { + while (temp && temp->next != max) { + temp = temp->next; + } + + temp->next = max->next; + } + + max->next = NULL; + return(max); + } + + /* If we get here, we couldn't find one */ + return(NULL); +} + + +/* + * get_resource + * + * this function sorts the resource list by size and then + * returns the first node of "size" length. If it finds a node + * larger than "size" it will split it up. + * + * size must be a power of two. + */ +static struct pci_resource *get_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if ( pciehp_resource_sort_and_combine(head) ) + return(NULL); + + if ( sort_by_size(head) ) + return(NULL); + + for (node = *head; node; node = node->next) { + dbg("%s: req_size =0x%x node=%p, base=0x%x, length=0x%x\n", + __FUNCTION__, size, node, node->base, node->length); + if (node->length < size) + continue; + + if (node->base & (size - 1)) { + dbg("%s: not aligned\n", __FUNCTION__); + /* This one isn't base aligned properly + so we'll make a new entry and split it up */ + temp_dword = (node->base | (size-1)) + 1; + + /* Short circuit if adjusted size is too small */ + if ((node->length - (temp_dword - node->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base; + split_node->length = temp_dword - node->base; + node->base = temp_dword; + node->length -= split_node->length; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of non-aligned base */ + + /* Don't need to check if too small since we already did */ + if (node->length > size) { + dbg("%s: too big\n", __FUNCTION__); + /* This one is longer than we need + so we'll make a new entry and split it up */ + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base + size; + split_node->length = node->length - size; + node->length = size; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of too big on top end */ + + dbg("%s: got one!!!\n", __FUNCTION__); + /* If we got here, then it is the right size + Now take it out of the list */ + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + /* Stop looping */ + break; + } + return(node); +} + + +/* + * pciehp_resource_sort_and_combine + * + * Sorts all of the nodes in the list in ascending order by + * their base addresses. Also does garbage collection by + * combining adjacent nodes. + * + * returns 0 if success + */ +int pciehp_resource_sort_and_combine(struct pci_resource **head) +{ + struct pci_resource *node1; + struct pci_resource *node2; + int out_of_order = 1; + + dbg("%s: head = %p, *head = %p\n", __FUNCTION__, head, *head); + + if (!(*head)) + return(1); + + dbg("*head->next = %p\n",(*head)->next); + + if (!(*head)->next) + return(0); /* Only one item on the list, already sorted! */ + + dbg("*head->base = 0x%x\n",(*head)->base); + dbg("*head->next->base = 0x%x\n",(*head)->next->base); + while (out_of_order) { + out_of_order = 0; + + /* Special case for swapping list head */ + if (((*head)->next) && + ((*head)->base > (*head)->next->base)) { + node1 = *head; + (*head) = (*head)->next; + node1->next = (*head)->next; + (*head)->next = node1; + out_of_order++; + } + + node1 = (*head); + + while (node1->next && node1->next->next) { + if (node1->next->base > node1->next->next->base) { + out_of_order++; + node2 = node1->next; + node1->next = node1->next->next; + node1 = node1->next; + node2->next = node1->next; + node1->next = node2; + } else + node1 = node1->next; + } + } /* End of out_of_order loop */ + + node1 = *head; + + while (node1 && node1->next) { + if ((node1->base + node1->length) == node1->next->base) { + /* Combine */ + dbg("8..\n"); + node1->length += node1->next->length; + node2 = node1->next; + node1->next = node1->next->next; + kfree(node2); + } else + node1 = node1->next; + } + + return(0); +} + + +/** + * pciehp_slot_create - Creates a node and adds it to the proper bus. + * @busnumber - bus where new node is to be located + * + * Returns pointer to the new node or NULL if unsuccessful + */ +struct pci_func *pciehp_slot_create(u8 busnumber) +{ + struct pci_func *new_slot; + struct pci_func *next; + dbg("%s: busnumber %x\n", __FUNCTION__, busnumber); + new_slot = (struct pci_func *) kmalloc(sizeof(struct pci_func), GFP_KERNEL); + + if (new_slot == NULL) { + return(new_slot); + } + + memset(new_slot, 0, sizeof(struct pci_func)); + + new_slot->next = NULL; + new_slot->configured = 1; + + if (pciehp_slot_list[busnumber] == NULL) { + pciehp_slot_list[busnumber] = new_slot; + } else { + next = pciehp_slot_list[busnumber]; + while (next->next != NULL) + next = next->next; + next->next = new_slot; + } + return(new_slot); +} + + +/* + * slot_remove - Removes a node from the linked list of slots. + * @old_slot: slot to remove + * + * Returns 0 if successful, !0 otherwise. + */ +static int slot_remove(struct pci_func * old_slot) +{ + struct pci_func *next; + + if (old_slot == NULL) + return(1); + + next = pciehp_slot_list[old_slot->bus]; + + if (next == NULL) { + return(1); + } + + if (next == old_slot) { + pciehp_slot_list[old_slot->bus] = old_slot->next; + pciehp_destroy_board_resources(old_slot); + kfree(old_slot); + return(0); + } + + while ((next->next != old_slot) && (next->next != NULL)) { + next = next->next; + } + + if (next->next == old_slot) { + next->next = old_slot->next; + pciehp_destroy_board_resources(old_slot); + kfree(old_slot); + return(0); + } else + return(2); +} + + +/** + * bridge_slot_remove - Removes a node from the linked list of slots. + * @bridge: bridge to remove + * + * Returns 0 if successful, !0 otherwise. + */ +static int bridge_slot_remove(struct pci_func *bridge) +{ + u8 subordinateBus, secondaryBus; + u8 tempBus; + struct pci_func *next; + + if (bridge == NULL) + return(1); + + secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF; + subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF; + + for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) { + next = pciehp_slot_list[tempBus]; + + while (!slot_remove(next)) { + next = pciehp_slot_list[tempBus]; + } + } + + next = pciehp_slot_list[bridge->bus]; + + if (next == NULL) { + return(1); + } + + if (next == bridge) { + pciehp_slot_list[bridge->bus] = bridge->next; + kfree(bridge); + return(0); + } + + while ((next->next != bridge) && (next->next != NULL)) { + next = next->next; + } + + if (next->next == bridge) { + next->next = bridge->next; + kfree(bridge); + return(0); + } else + return(2); +} + + +/** + * pciehp_slot_find - Looks for a node by bus, and device, multiple functions accessed + * @bus: bus to find + * @device: device to find + * @index: is 0 for first function found, 1 for the second... + * + * Returns pointer to the node if successful, %NULL otherwise. + */ +struct pci_func *pciehp_slot_find(u8 bus, u8 device, u8 index) +{ + int found = -1; + struct pci_func *func; + + func = pciehp_slot_list[bus]; + dbg("%s: bus %x device %x index %x\n", + __FUNCTION__, bus, device, index); + if (func != NULL) { + dbg("%s: func-> bus %x device %x function %x pci_dev %p\n", + __FUNCTION__, func->bus, func->device, func->function, + func->pci_dev); + } else + dbg("%s: func == NULL\n", __FUNCTION__); + + if ((func == NULL) || ((func->device == device) && (index == 0))) + return(func); + + if (func->device == device) + found++; + + while (func->next != NULL) { + func = func->next; + + dbg("%s: In while loop, func-> bus %x device %x function %x pci_dev %p\n", + __FUNCTION__, func->bus, func->device, func->function, + func->pci_dev); + if (func->device == device) + found++; + dbg("%s: while loop, found %d, index %d\n", __FUNCTION__, + found, index); + + if ((found == index) ||(func->function == index)) { + dbg("%s: Found bus %x dev %x func %x\n", __FUNCTION__, + func->bus, func->device, func->function); + return(func); + } + } + + return(NULL); +} + +static int is_bridge(struct pci_func * func) +{ + /* Check the header type */ + if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01) + return 1; + else + return 0; +} + + +/* the following routines constitute the bulk of the + hotplug controller logic + */ + + +/** + * board_added - Called after a board has been added to the system. + * + * Turns power on for the board + * Configures board + * + */ +static u32 board_added(struct pci_func * func, struct controller * ctrl) +{ + u8 hp_slot; + int index; + u32 temp_register = 0xFFFFFFFF; + u32 retval, rc = 0; + struct pci_func *new_func = NULL; + struct slot *p_slot; + struct resource_lists res_lists; + + p_slot = pciehp_find_slot(ctrl, func->device); + hp_slot = func->device - ctrl->slot_device_offset; + + dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n", + __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot); + + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + /* Power on slot */ + rc = p_slot->hpc_ops->power_on_slot(p_slot); + if (rc) + return -1; + + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + dbg("%s: after power on\n", __FUNCTION__); + + p_slot->hpc_ops->green_led_blink(p_slot); + + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + dbg("%s: after green_led_blink", __FUNCTION__); + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + + /* Wait for ~1 second */ + dbg("%s: before long_delay\n", __FUNCTION__); + wait_for_ctrl_irq (ctrl); + dbg("%s: afterlong_delay\n", __FUNCTION__); + + dbg("%s: before check link status", __FUNCTION__); + /* Make this to check for link training status */ + rc = p_slot->hpc_ops->check_lnk_status(ctrl); + if (rc) { + err("%s: Failed to check link status\n", __FUNCTION__); + return -1; + } + + dbg("%s: func status = %x\n", __FUNCTION__, func->status); + + /* Check for a power fault */ + if (func->status == 0xFF) { + /* power fault occurred, but it was benign */ + temp_register = 0xFFFFFFFF; + dbg("%s: temp register set to %x by power fault\n", + __FUNCTION__, temp_register); + rc = POWER_FAILURE; + func->status = 0; + } else { + /* Get vendor/device ID u32 */ + rc = pci_bus_read_config_dword (ctrl->pci_dev->subordinate, + PCI_DEVFN(func->device, func->function), PCI_VENDOR_ID, &temp_register); + dbg("%s: pci_bus_read_config_dword returns %d\n", __FUNCTION__, rc); + dbg("%s: temp_register is %x\n", __FUNCTION__, temp_register); + + if (rc != 0) { + /* Something's wrong here */ + temp_register = 0xFFFFFFFF; + dbg("%s: temp register set to %x by error\n", __FUNCTION__, + temp_register); + } + /* Preset return code. It will be changed later if things go okay. */ + rc = NO_ADAPTER_PRESENT; + } + + /* All F's is an empty slot or an invalid board */ + if (temp_register != 0xFFFFFFFF) { /* Check for a board in the slot */ + res_lists.io_head = ctrl->io_head; + res_lists.mem_head = ctrl->mem_head; + res_lists.p_mem_head = ctrl->p_mem_head; + res_lists.bus_head = ctrl->bus_head; + res_lists.irqs = NULL; + + rc = configure_new_device(ctrl, func, 0, &res_lists, 0, 0); + dbg("%s: back from configure_new_device\n", __FUNCTION__); + + ctrl->io_head = res_lists.io_head; + ctrl->mem_head = res_lists.mem_head; + ctrl->p_mem_head = res_lists.p_mem_head; + ctrl->bus_head = res_lists.bus_head; + + pciehp_resource_sort_and_combine(&(ctrl->mem_head)); + pciehp_resource_sort_and_combine(&(ctrl->p_mem_head)); + pciehp_resource_sort_and_combine(&(ctrl->io_head)); + pciehp_resource_sort_and_combine(&(ctrl->bus_head)); + + if (rc) { + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + /* Turn off slot, turn on Amber LED, turn off Green LED */ + retval = p_slot->hpc_ops->power_off_slot(p_slot); + /* In PCI Express, just power off slot */ + if (retval) { + err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__); + return retval; + } + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + p_slot->hpc_ops->green_led_off(p_slot); + + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + /* Turn on Amber LED */ + retval = p_slot->hpc_ops->set_attention_status(p_slot, 1); + if (retval) { + err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__); + return retval; + } + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + + return(rc); + } + pciehp_save_slot_config(ctrl, func); + + func->status = 0; + func->switch_save = 0x10; + func->is_a_board = 0x01; + + /* Next, we will instantiate the linux pci_dev structures + * (with appropriate driver notification, if already present) + */ + index = 0; + do { + new_func = pciehp_slot_find(ctrl->slot_bus, func->device, index++); + if (new_func && !new_func->pci_dev) { + dbg("%s:call pci_hp_configure_dev, func %x\n", + __FUNCTION__, index); + pciehp_configure_device(ctrl, new_func); + } + } while (new_func); + + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + p_slot->hpc_ops->green_led_on(p_slot); + + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + + } else { + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + /* Turn off slot, turn on Amber LED, turn off Green LED */ + retval = p_slot->hpc_ops->power_off_slot(p_slot); + /* In PCI Express, just power off slot */ + if (retval) { + err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__); + return retval; + } + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + p_slot->hpc_ops->green_led_off(p_slot); + + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + /* Turn on Amber LED */ + retval = p_slot->hpc_ops->set_attention_status(p_slot, 1); + if (retval) { + err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__); + return retval; + } + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + + return(rc); + } + return 0; +} + + +/** + * remove_board - Turns off slot and LED's + * + */ +static u32 remove_board(struct pci_func *func, struct controller *ctrl) +{ + int index; + u8 skip = 0; + u8 device; + u8 hp_slot; + u32 rc; + struct resource_lists res_lists; + struct pci_func *temp_func; + struct slot *p_slot; + + if (func == NULL) + return(1); + + if (pciehp_unconfigure_device(func)) + return(1); + + device = func->device; + + hp_slot = func->device - ctrl->slot_device_offset; + p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + + dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); + + if ((ctrl->add_support) && + !(func->bus_head || func->mem_head || func->p_mem_head || func->io_head)) { + /* Here we check to see if we've saved any of the board's + * resources already. If so, we'll skip the attempt to + * determine what's being used. + */ + index = 0; + + temp_func = func; + + while ((temp_func = pciehp_slot_find(temp_func->bus, temp_func->device, + index++))) { + if (temp_func->bus_head || temp_func->mem_head + || temp_func->p_mem_head || temp_func->io_head) { + skip = 1; + break; + } + } + + if (!skip) + rc = pciehp_save_used_resources(ctrl, func, DISABLE_CARD); + } + /* Change status to shutdown */ + if (func->is_a_board) + func->status = 0x01; + func->configured = 0; + + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + /* Power off slot */ + rc = p_slot->hpc_ops->power_off_slot(p_slot); + if (rc) { + err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); + return rc; + } + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + /* Turn off Green LED */ + p_slot->hpc_ops->green_led_off(p_slot); + + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + + if (ctrl->add_support) { + while (func) { + res_lists.io_head = ctrl->io_head; + res_lists.mem_head = ctrl->mem_head; + res_lists.p_mem_head = ctrl->p_mem_head; + res_lists.bus_head = ctrl->bus_head; + + dbg("Returning resources to ctlr lists for (B/D/F) = (%#x/%#x/%#x)\n", + func->bus, func->device, func->function); + + pciehp_return_board_resources(func, &res_lists); + + ctrl->io_head = res_lists.io_head; + ctrl->mem_head = res_lists.mem_head; + ctrl->p_mem_head = res_lists.p_mem_head; + ctrl->bus_head = res_lists.bus_head; + + pciehp_resource_sort_and_combine(&(ctrl->mem_head)); + pciehp_resource_sort_and_combine(&(ctrl->p_mem_head)); + pciehp_resource_sort_and_combine(&(ctrl->io_head)); + pciehp_resource_sort_and_combine(&(ctrl->bus_head)); + + if (is_bridge(func)) { + dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", + ctrl->seg, func->bus, func->device, func->function); + bridge_slot_remove(func); + } else + dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", + ctrl->seg, func->bus, func->device, func->function); + slot_remove(func); + + func = pciehp_slot_find(ctrl->slot_bus, device, 0); + } + + /* Setup slot structure with entry for empty slot */ + func = pciehp_slot_create(ctrl->slot_bus); + + if (func == NULL) { + return(1); + } + + func->bus = ctrl->slot_bus; + func->device = device; + func->function = 0; + func->configured = 0; + func->switch_save = 0x10; + func->is_a_board = 0; + } + return 0; +} + + +static void pushbutton_helper_thread (unsigned long data) +{ + pushbutton_pending = data; + up(&event_semaphore); +} + + +/* this is the main worker thread */ +static int event_thread(void* data) +{ + struct controller *ctrl; + lock_kernel(); + daemonize(); + + /* New name */ + strcpy(current->comm, "pciehpd_event"); + + unlock_kernel(); + + while (1) { + dbg("!!!!event_thread sleeping\n"); + down_interruptible (&event_semaphore); + dbg("event_thread woken finished = %d\n", event_finished); + if (event_finished || signal_pending(current)) + break; + /* Do stuff here */ + if (pushbutton_pending) + pciehp_pushbutton_thread(pushbutton_pending); + else + for (ctrl = pciehp_ctrl_list; ctrl; ctrl=ctrl->next) + interrupt_event_handler(ctrl); + } + dbg("event_thread signals exit\n"); + up(&event_exit); + return 0; +} + +int pciehp_event_start_thread (void) +{ + int pid; + + /* Initialize our semaphores */ + init_MUTEX_LOCKED(&event_exit); + event_finished=0; + + init_MUTEX_LOCKED(&event_semaphore); + pid = kernel_thread(event_thread, 0, 0); + + if (pid < 0) { + err ("Can't start up our event thread\n"); + return -1; + } + dbg("Our event thread pid = %d\n", pid); + return 0; +} + + +void pciehp_event_stop_thread (void) +{ + event_finished = 1; + dbg("event_thread finish command given\n"); + up(&event_semaphore); + dbg("wait for event_thread to exit\n"); + down(&event_exit); +} + + +static int update_slot_info (struct slot *slot) +{ + struct hotplug_slot_info *info; + char buffer[SLOT_NAME_SIZE]; + int result; + + info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + make_slot_name (&buffer[0], SLOT_NAME_SIZE, slot); + + slot->hpc_ops->get_power_status(slot, &(info->power_status)); + slot->hpc_ops->get_attention_status(slot, &(info->attention_status)); + slot->hpc_ops->get_latch_status(slot, &(info->latch_status)); + slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status)); + + result = pci_hp_change_slot_info(buffer, info); + kfree (info); + return result; +} + +static void interrupt_event_handler(struct controller *ctrl) +{ + int loop = 0; + int change = 1; + struct pci_func *func; + u8 hp_slot; + u8 getstatus; + struct slot *p_slot; + + while (change) { + change = 0; + + for (loop = 0; loop < 10; loop++) { + if (ctrl->event_queue[loop].event_type != 0) { + hp_slot = ctrl->event_queue[loop].hp_slot; + + func = pciehp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); + + p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + + dbg("hp_slot %d, func %p, p_slot %p\n", hp_slot, func, p_slot); + + if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) { + dbg("button cancel\n"); + del_timer(&p_slot->task_event); + + switch (p_slot->state) { + case BLINKINGOFF_STATE: + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + p_slot->hpc_ops->green_led_on(p_slot); + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + p_slot->hpc_ops->set_attention_status(p_slot, 0); + + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + break; + case BLINKINGON_STATE: + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + p_slot->hpc_ops->green_led_off(p_slot); + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + p_slot->hpc_ops->set_attention_status(p_slot, 0); + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + + break; + default: + warn("Not a valid state\n"); + return; + } + info(msg_button_cancel, p_slot->number); + p_slot->state = STATIC_STATE; + } + /* ***********Button Pressed (No action on 1st press...) */ + else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) { + dbg("Button pressed\n"); + + p_slot->hpc_ops->get_power_status(p_slot, &getstatus); + if (getstatus) { + /* Slot is on */ + dbg("Slot is on\n"); + p_slot->state = BLINKINGOFF_STATE; + info(msg_button_off, p_slot->number); + } else { + /* Slot is off */ + dbg("Slot is off\n"); + p_slot->state = BLINKINGON_STATE; + info(msg_button_on, p_slot->number); + } + + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + /* blink green LED and turn off amber */ + p_slot->hpc_ops->green_led_blink(p_slot); + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + p_slot->hpc_ops->set_attention_status(p_slot, 0); + + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + + init_timer(&p_slot->task_event); + p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */ + p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread; + p_slot->task_event.data = (unsigned long) p_slot; + + dbg("add_timer p_slot = %p\n", (void *) p_slot); + add_timer(&p_slot->task_event); + } + /***********POWER FAULT********************/ + else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) { + dbg("power fault\n"); + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + p_slot->hpc_ops->set_attention_status(p_slot, 1); + p_slot->hpc_ops->green_led_off(p_slot); + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + } else { + /* refresh notification */ + if (p_slot) + update_slot_info(p_slot); + } + + ctrl->event_queue[loop].event_type = 0; + + change = 1; + } + } /* End of FOR loop */ + } + + return; +} + + +/** + * pciehp_pushbutton_thread + * + * Scheduled procedure to handle blocking stuff for the pushbuttons + * Handles all pending events and exits. + * + */ +void pciehp_pushbutton_thread (unsigned long slot) +{ + struct slot *p_slot = (struct slot *) slot; + u8 getstatus; + int rc; + + pushbutton_pending = 0; + + if (!p_slot) { + dbg("%s: Error! slot NULL\n", __FUNCTION__); + return; + } + + p_slot->hpc_ops->get_power_status(p_slot, &getstatus); + if (getstatus) { + p_slot->state = POWEROFF_STATE; + dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device); + + if (pciehp_disable_slot(p_slot)) { + /* Wait for exclusive access to hardware */ + down(&p_slot->ctrl->crit_sect); + + /* Turn on the Attention LED */ + rc = p_slot->hpc_ops->set_attention_status(p_slot, 1); + if (rc) { + err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__); + return; + } + + /* Wait for the command to complete */ + wait_for_ctrl_irq (p_slot->ctrl); + + /* Done with exclusive hardware access */ + up(&p_slot->ctrl->crit_sect); + } + p_slot->state = STATIC_STATE; + } else { + p_slot->state = POWERON_STATE; + dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device); + + if (pciehp_enable_slot(p_slot)) { + /* Wait for exclusive access to hardware */ + down(&p_slot->ctrl->crit_sect); + + /* Turn off the green LED */ + rc = p_slot->hpc_ops->set_attention_status(p_slot, 1); + if (rc) { + err("%s: Issue of Set Attn Indicator On command failed\n", __FUNCTION__); + return; + } + /* Wait for the command to complete */ + wait_for_ctrl_irq (p_slot->ctrl); + + p_slot->hpc_ops->green_led_off(p_slot); + + /* Wait for the command to complete */ + wait_for_ctrl_irq (p_slot->ctrl); + + /* Done with exclusive hardware access */ + up(&p_slot->ctrl->crit_sect); + } + p_slot->state = STATIC_STATE; + } + + return; +} + + +int pciehp_enable_slot (struct slot *p_slot) +{ + u8 getstatus = 0; + int rc; + struct pci_func *func; + + func = pciehp_slot_find(p_slot->bus, p_slot->device, 0); + if (!func) { + dbg("%s: Error! slot NULL\n", __FUNCTION__); + return (1); + } + + /* Check to see if (latch closed, card present, power off) */ + down(&p_slot->ctrl->crit_sect); + rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); + if (rc || !getstatus) { + info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); + up(&p_slot->ctrl->crit_sect); + return (0); + } + + rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); + if (rc || getstatus) { + info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); + up(&p_slot->ctrl->crit_sect); + return (0); + } + + rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); + if (rc || getstatus) { + info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number); + up(&p_slot->ctrl->crit_sect); + return (0); + } + up(&p_slot->ctrl->crit_sect); + + slot_remove(func); + + func = pciehp_slot_create(p_slot->bus); + if (func == NULL) + return (1); + + func->bus = p_slot->bus; + func->device = p_slot->device; + func->function = 0; + func->configured = 0; + func->is_a_board = 1; + + /* We have to save the presence info for these slots */ + p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); + p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); + func->switch_save = !getstatus? 0x10:0; + + rc = board_added(func, p_slot->ctrl); + if (rc) { + if (is_bridge(func)) + bridge_slot_remove(func); + else + slot_remove(func); + + /* Setup slot structure with entry for empty slot */ + func = pciehp_slot_create(p_slot->bus); + if (func == NULL) + return (1); /* Out of memory */ + + func->bus = p_slot->bus; + func->device = p_slot->device; + func->function = 0; + func->configured = 0; + func->is_a_board = 1; + + /* We have to save the presence info for these slots */ + p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); + p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); + func->switch_save = !getstatus? 0x10:0; + } + + if (p_slot) + update_slot_info(p_slot); + + return rc; +} + + +int pciehp_disable_slot (struct slot *p_slot) +{ + u8 class_code, header_type, BCR; + u8 index = 0; + u8 getstatus = 0; + u32 rc = 0; + int ret = 0; + unsigned int devfn; + struct pci_bus *pci_bus = p_slot->ctrl->pci_dev->subordinate; + struct pci_func *func; + + if (!p_slot->ctrl) + return (1); + + /* Check to see if (latch closed, card present, power on) */ + down(&p_slot->ctrl->crit_sect); + + ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); + if (ret || !getstatus) { + info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); + up(&p_slot->ctrl->crit_sect); + return (0); + } + + ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); + if (ret || getstatus) { + info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); + up(&p_slot->ctrl->crit_sect); + return (0); + } + + ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); + if (ret || !getstatus) { + info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); + up(&p_slot->ctrl->crit_sect); + return (0); + } + up(&p_slot->ctrl->crit_sect); + + func = pciehp_slot_find(p_slot->bus, p_slot->device, index++); + + /* Make sure there are no video controllers here + * for all func of p_slot + */ + while (func && !rc) { + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + /* Check the Class Code */ + rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); + if (rc) + return rc; + + if (class_code == PCI_BASE_CLASS_DISPLAY) { + /* Display/Video adapter (not supported) */ + rc = REMOVE_NOT_SUPPORTED; + } else { + /* See if it's a bridge */ + rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; + + /* If it's a bridge, check the VGA Enable bit */ + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR); + if (rc) + return rc; + + /* If the VGA Enable bit is set, remove isn't supported */ + if (BCR & PCI_BRIDGE_CTL_VGA) { + rc = REMOVE_NOT_SUPPORTED; + } + } + } + + func = pciehp_slot_find(p_slot->bus, p_slot->device, index++); + } + + func = pciehp_slot_find(p_slot->bus, p_slot->device, 0); + if ((func != NULL) && !rc) { + rc = remove_board(func, p_slot->ctrl); + } else if (!rc) + rc = 1; + + if (p_slot) + update_slot_info(p_slot); + + return(rc); +} + + +/** + * configure_new_device - Configures the PCI header information of one board. + * + * @ctrl: pointer to controller structure + * @func: pointer to function structure + * @behind_bridge: 1 if this is a recursive call, 0 if not + * @resources: pointer to set of resource lists + * + * Returns 0 if success + * + */ +static u32 configure_new_device (struct controller * ctrl, struct pci_func * func, + u8 behind_bridge, struct resource_lists * resources, u8 bridge_bus, u8 bridge_dev) +{ + u8 temp_byte, function, max_functions, stop_it; + int rc; + u32 ID; + struct pci_func *new_slot; + struct pci_bus lpci_bus, *pci_bus; + int index; + + new_slot = func; + + dbg("%s\n", __FUNCTION__); + + memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); + pci_bus = &lpci_bus; + pci_bus->number = func->bus; + + /* Check for Multi-function device */ + rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(func->device, func->function), 0x0E, &temp_byte); + if (rc) { + dbg("%s: rc = %d\n", __FUNCTION__, rc); + return rc; + } + + if (temp_byte & 0x80) /* Multi-function device */ + max_functions = 8; + else + max_functions = 1; + + function = 0; + + do { + rc = configure_new_function(ctrl, new_slot, behind_bridge, resources, bridge_bus, bridge_dev); + + if (rc) { + dbg("configure_new_function failed %d\n",rc); + index = 0; + + while (new_slot) { + new_slot = pciehp_slot_find(new_slot->bus, new_slot->device, index++); + + if (new_slot) + pciehp_return_board_resources(new_slot, resources); + } + + return(rc); + } + + function++; + + stop_it = 0; + + /* The following loop skips to the next present function + * and creates a board structure + */ + + while ((function < max_functions) && (!stop_it)) { + pci_bus_read_config_dword(pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID); + + if (ID == 0xFFFFFFFF) { /* There's nothing there. */ + function++; + } else { /* There's something there */ + /* Setup slot structure. */ + new_slot = pciehp_slot_create(func->bus); + + if (new_slot == NULL) { + /* Out of memory */ + return(1); + } + + new_slot->bus = func->bus; + new_slot->device = func->device; + new_slot->function = function; + new_slot->is_a_board = 1; + new_slot->status = 0; + + stop_it++; + } + } + + } while (function < max_functions); + dbg("returning from configure_new_device\n"); + + return 0; +} + + +/* + * Configuration logic that involves the hotplug data structures and + * their bookkeeping + */ + + +/** + * configure_new_function - Configures the PCI header information of one device + * + * @ctrl: pointer to controller structure + * @func: pointer to function structure + * @behind_bridge: 1 if this is a recursive call, 0 if not + * @resources: pointer to set of resource lists + * + * Calls itself recursively for bridged devices. + * Returns 0 if success + * + */ +static int configure_new_function (struct controller * ctrl, struct pci_func * func, + u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev) +{ + int cloop; + u8 temp_byte; + u8 device; + u8 class_code; + u16 temp_word; + u32 rc; + u32 temp_register; + u32 base; + u32 ID; + unsigned int devfn; + struct pci_resource *mem_node; + struct pci_resource *p_mem_node; + struct pci_resource *io_node; + struct pci_resource *bus_node; + struct pci_resource *hold_mem_node; + struct pci_resource *hold_p_mem_node; + struct pci_resource *hold_IO_node; + struct pci_resource *hold_bus_node; + struct irq_mapping irqs; + struct pci_func *new_slot; + struct pci_bus lpci_bus, *pci_bus; + struct resource_lists temp_resources; + + memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); + pci_bus = &lpci_bus; + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + /* Check for Bridge */ + rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &temp_byte); + if (rc) + return rc; + dbg("%s: bus %x dev %x func %x temp_byte = %x\n", __FUNCTION__, + func->bus, func->device, func->function, temp_byte); + + if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */ + /* Set Primary bus */ + dbg("set Primary bus = 0x%x\n", func->bus); + rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func->bus); + if (rc) + return rc; + + /* Find range of busses to use */ + bus_node = get_max_resource(&resources->bus_head, 1L); + + /* If we don't have any busses to allocate, we can't continue */ + if (!bus_node) { + err("Got NO bus resource to use\n"); + return -ENOMEM; + } + dbg("Got ranges of buses to use: base:len=0x%x:%x\n", bus_node->base, bus_node->length); + + /* Set Secondary bus */ + dbg("set Secondary bus = 0x%x\n", temp_byte); + dbg("func->bus %x\n", func->bus); + + temp_byte = (u8)bus_node->base; + dbg("set Secondary bus = 0x%x\n", temp_byte); + rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, temp_byte); + if (rc) + return rc; + + /* set subordinate bus */ + temp_byte = (u8)(bus_node->base + bus_node->length - 1); + dbg("set subordinate bus = 0x%x\n", temp_byte); + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte); + if (rc) + return rc; + + /* Set HP parameters (Cache Line Size, Latency Timer) */ + rc = pciehprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_BRIDGE); + if (rc) + return rc; + + /* Setup the IO, memory, and prefetchable windows */ + + io_node = get_max_resource(&(resources->io_head), 0x1000L); + if (io_node) { + dbg("io_node(base, len, next) (%x, %x, %p)\n", io_node->base, io_node->length, io_node->next); + } + + mem_node = get_max_resource(&(resources->mem_head), 0x100000L); + if (mem_node) { + dbg("mem_node(base, len, next) (%x, %x, %p)\n", mem_node->base, mem_node->length, mem_node->next); + } + + if (resources->p_mem_head) + p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000L); + else { + /* + * In some platform implementation, MEM and PMEM are not + * distinguished, and hence ACPI _CRS has only MEM entries + * for both MEM and PMEM. + */ + dbg("using MEM for PMEM\n"); + p_mem_node = get_max_resource(&(resources->mem_head), 0x100000L); + } + if (p_mem_node) { + dbg("p_mem_node(base, len, next) (%x, %x, %p)\n", p_mem_node->base, p_mem_node->length, p_mem_node->next); + } + + /* Set up the IRQ info */ + if (!resources->irqs) { + irqs.barber_pole = 0; + irqs.interrupt[0] = 0; + irqs.interrupt[1] = 0; + irqs.interrupt[2] = 0; + irqs.interrupt[3] = 0; + irqs.valid_INT = 0; + } else { + irqs.barber_pole = resources->irqs->barber_pole; + irqs.interrupt[0] = resources->irqs->interrupt[0]; + irqs.interrupt[1] = resources->irqs->interrupt[1]; + irqs.interrupt[2] = resources->irqs->interrupt[2]; + irqs.interrupt[3] = resources->irqs->interrupt[3]; + irqs.valid_INT = resources->irqs->valid_INT; + } + + /* Set up resource lists that are now aligned on top and bottom + * for anything behind the bridge. + */ + temp_resources.bus_head = bus_node; + temp_resources.io_head = io_node; + temp_resources.mem_head = mem_node; + temp_resources.p_mem_head = p_mem_node; + temp_resources.irqs = &irqs; + + /* Make copies of the nodes we are going to pass down so that + * if there is a problem,we can just use these to free resources + */ + hold_bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + hold_IO_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + hold_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + hold_p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) { + if (hold_bus_node) + kfree(hold_bus_node); + if (hold_IO_node) + kfree(hold_IO_node); + if (hold_mem_node) + kfree(hold_mem_node); + if (hold_p_mem_node) + kfree(hold_p_mem_node); + + return(1); + } + + memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource)); + + bus_node->base += 1; + bus_node->length -= 1; + bus_node->next = NULL; + + /* If we have IO resources copy them and fill in the bridge's + * IO range registers + */ + if (io_node) { + memcpy(hold_IO_node, io_node, sizeof(struct pci_resource)); + io_node->next = NULL; + + /* set IO base and Limit registers */ + RES_CHECK(io_node->base, 8); + temp_byte = (u8)(io_node->base >> 8); + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte); + + RES_CHECK(io_node->base + io_node->length - 1, 8); + temp_byte = (u8)((io_node->base + io_node->length - 1) >> 8); + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte); + } else { + kfree(hold_IO_node); + hold_IO_node = NULL; + } + + /* If we have memory resources copy them and fill in the bridge's + * memory range registers. Otherwise, fill in the range + * registers with values that disable them. + */ + if (mem_node) { + memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource)); + mem_node->next = NULL; + + /* set Mem base and Limit registers */ + RES_CHECK(mem_node->base, 16); + temp_word = (u32)(mem_node->base >> 16); + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); + + RES_CHECK(mem_node->base + mem_node->length - 1, 16); + temp_word = (u32)((mem_node->base + mem_node->length - 1) >> 16); + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); + } else { + temp_word = 0xFFFF; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); + + temp_word = 0x0000; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); + + kfree(hold_mem_node); + hold_mem_node = NULL; + } + + /* If we have prefetchable memory resources copy them and + * fill in the bridge's memory range registers. Otherwise, + * fill in the range registers with values that disable them. + */ + if (p_mem_node) { + memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource)); + p_mem_node->next = NULL; + + /* Set Pre Mem base and Limit registers */ + RES_CHECK(p_mem_node->base, 16); + temp_word = (u32)(p_mem_node->base >> 16); + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); + + RES_CHECK(p_mem_node->base + p_mem_node->length - 1, 16); + temp_word = (u32)((p_mem_node->base + p_mem_node->length - 1) >> 16); + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); + } else { + temp_word = 0xFFFF; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); + + temp_word = 0x0000; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); + + kfree(hold_p_mem_node); + hold_p_mem_node = NULL; + } + + /* Adjust this to compensate for extra adjustment in first loop */ + irqs.barber_pole--; + + rc = 0; + + /* Here we actually find the devices and configure them */ + for (device = 0; (device <= 0x1F) && !rc; device++) { + irqs.barber_pole = (irqs.barber_pole + 1) & 0x03; + + ID = 0xFFFFFFFF; + pci_bus->number = hold_bus_node->base; + pci_bus_read_config_dword (pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID); + pci_bus->number = func->bus; + + if (ID != 0xFFFFFFFF) { /* device Present */ + /* Setup slot structure. */ + new_slot = pciehp_slot_create(hold_bus_node->base); + + if (new_slot == NULL) { + /* Out of memory */ + rc = -ENOMEM; + continue; + } + + new_slot->bus = hold_bus_node->base; + new_slot->device = device; + new_slot->function = 0; + new_slot->is_a_board = 1; + new_slot->status = 0; + + rc = configure_new_device(ctrl, new_slot, 1, &temp_resources, func->bus, func->device); + dbg("configure_new_device rc=0x%x\n",rc); + } /* End of IF (device in slot?) */ + } /* End of FOR loop */ + + if (rc) { + pciehp_destroy_resource_list(&temp_resources); + + return_resource(&(resources->bus_head), hold_bus_node); + return_resource(&(resources->io_head), hold_IO_node); + return_resource(&(resources->mem_head), hold_mem_node); + return_resource(&(resources->p_mem_head), hold_p_mem_node); + return(rc); + } + + /* Save the interrupt routing information */ + if (resources->irqs) { + resources->irqs->interrupt[0] = irqs.interrupt[0]; + resources->irqs->interrupt[1] = irqs.interrupt[1]; + resources->irqs->interrupt[2] = irqs.interrupt[2]; + resources->irqs->interrupt[3] = irqs.interrupt[3]; + resources->irqs->valid_INT = irqs.valid_INT; + } else if (!behind_bridge) { + /* We need to hook up the interrupts here */ + for (cloop = 0; cloop < 4; cloop++) { + if (irqs.valid_INT & (0x01 << cloop)) { + rc = pciehp_set_irq(func->bus, func->device, + 0x0A + cloop, irqs.interrupt[cloop]); + if (rc) { + pciehp_destroy_resource_list (&temp_resources); + return_resource(&(resources->bus_head), hold_bus_node); + return_resource(&(resources->io_head), hold_IO_node); + return_resource(&(resources->mem_head), hold_mem_node); + return_resource(&(resources->p_mem_head), hold_p_mem_node); + return rc; + } + } + } /* end of for loop */ + } + + /* Return unused bus resources + * First use the temporary node to store information for the board + */ + if (hold_bus_node && bus_node && temp_resources.bus_head) { + hold_bus_node->length = bus_node->base - hold_bus_node->base; + + hold_bus_node->next = func->bus_head; + func->bus_head = hold_bus_node; + + temp_byte = (u8)(temp_resources.bus_head->base - 1); + + /* Set subordinate bus */ + dbg("re-set subordinate bus = 0x%x\n", temp_byte); + + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte); + + if (temp_resources.bus_head->length == 0) { + kfree(temp_resources.bus_head); + temp_resources.bus_head = NULL; + } else { + dbg("return bus res of b:d(0x%x:%x) base:len(0x%x:%x)\n", + func->bus, func->device, temp_resources.bus_head->base, temp_resources.bus_head->length); + return_resource(&(resources->bus_head), temp_resources.bus_head); + } + } + + /* If we have IO space available and there is some left, + * return the unused portion + */ + if (hold_IO_node && temp_resources.io_head) { + io_node = do_pre_bridge_resource_split(&(temp_resources.io_head), + &hold_IO_node, 0x1000); + + /* Check if we were able to split something off */ + if (io_node) { + hold_IO_node->base = io_node->base + io_node->length; + + RES_CHECK(hold_IO_node->base, 8); + temp_byte = (u8)((hold_IO_node->base) >> 8); + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte); + + return_resource(&(resources->io_head), io_node); + } + + io_node = do_bridge_resource_split(&(temp_resources.io_head), 0x1000); + + /* Check if we were able to split something off */ + if (io_node) { + /* First use the temporary node to store information for the board */ + hold_IO_node->length = io_node->base - hold_IO_node->base; + + /* If we used any, add it to the board's list */ + if (hold_IO_node->length) { + hold_IO_node->next = func->io_head; + func->io_head = hold_IO_node; + + RES_CHECK(io_node->base - 1, 8); + temp_byte = (u8)((io_node->base - 1) >> 8); + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte); + + return_resource(&(resources->io_head), io_node); + } else { + /* It doesn't need any IO */ + temp_byte = 0x00; + rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte); + + return_resource(&(resources->io_head), io_node); + kfree(hold_IO_node); + } + } else { + /* It used most of the range */ + hold_IO_node->next = func->io_head; + func->io_head = hold_IO_node; + } + } else if (hold_IO_node) { + /* It used the whole range */ + hold_IO_node->next = func->io_head; + func->io_head = hold_IO_node; + } + + /* If we have memory space available and there is some left, + * return the unused portion + */ + if (hold_mem_node && temp_resources.mem_head) { + mem_node = do_pre_bridge_resource_split(&(temp_resources.mem_head), &hold_mem_node, 0x100000L); + + /* Check if we were able to split something off */ + if (mem_node) { + hold_mem_node->base = mem_node->base + mem_node->length; + + RES_CHECK(hold_mem_node->base, 16); + temp_word = (u32)((hold_mem_node->base) >> 16); + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); + + return_resource(&(resources->mem_head), mem_node); + } + + mem_node = do_bridge_resource_split(&(temp_resources.mem_head), 0x100000L); + + /* Check if we were able to split something off */ + if (mem_node) { + /* First use the temporary node to store information for the board */ + hold_mem_node->length = mem_node->base - hold_mem_node->base; + + if (hold_mem_node->length) { + hold_mem_node->next = func->mem_head; + func->mem_head = hold_mem_node; + + /* Configure end address */ + RES_CHECK(mem_node->base - 1, 16); + temp_word = (u32)((mem_node->base - 1) >> 16); + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); + + /* Return unused resources to the pool */ + return_resource(&(resources->mem_head), mem_node); + } else { + /* It doesn't need any Mem */ + temp_word = 0x0000; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); + + return_resource(&(resources->mem_head), mem_node); + kfree(hold_mem_node); + } + } else { + /* It used most of the range */ + hold_mem_node->next = func->mem_head; + func->mem_head = hold_mem_node; + } + } else if (hold_mem_node) { + /* It used the whole range */ + hold_mem_node->next = func->mem_head; + func->mem_head = hold_mem_node; + } + + /* If we have prefetchable memory space available and there is some + * left at the end, return the unused portion + */ + if (hold_p_mem_node && temp_resources.p_mem_head) { + p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head), + &hold_p_mem_node, 0x100000L); + + /* Check if we were able to split something off */ + if (p_mem_node) { + hold_p_mem_node->base = p_mem_node->base + p_mem_node->length; + + RES_CHECK(hold_p_mem_node->base, 16); + temp_word = (u32)((hold_p_mem_node->base) >> 16); + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); + + return_resource(&(resources->p_mem_head), p_mem_node); + } + + p_mem_node = do_bridge_resource_split(&(temp_resources.p_mem_head), 0x100000L); + + /* Check if we were able to split something off */ + if (p_mem_node) { + /* First use the temporary node to store information for the board */ + hold_p_mem_node->length = p_mem_node->base - hold_p_mem_node->base; + + /* If we used any, add it to the board's list */ + if (hold_p_mem_node->length) { + hold_p_mem_node->next = func->p_mem_head; + func->p_mem_head = hold_p_mem_node; + + RES_CHECK(p_mem_node->base - 1, 16); + temp_word = (u32)((p_mem_node->base - 1) >> 16); + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); + + return_resource(&(resources->p_mem_head), p_mem_node); + } else { + /* It doesn't need any PMem */ + temp_word = 0x0000; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); + + return_resource(&(resources->p_mem_head), p_mem_node); + kfree(hold_p_mem_node); + } + } else { + /* It used the most of the range */ + hold_p_mem_node->next = func->p_mem_head; + func->p_mem_head = hold_p_mem_node; + } + } else if (hold_p_mem_node) { + /* It used the whole range */ + hold_p_mem_node->next = func->p_mem_head; + func->p_mem_head = hold_p_mem_node; + } + + /* We should be configuring an IRQ and the bridge's base address + * registers if it needs them. Although we have never seen such + * a device + */ + + pciehprm_enable_card(ctrl, func, PCI_HEADER_TYPE_BRIDGE); + + dbg("PCI Bridge Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, + func->device, func->function); + } else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) { + /* Standard device */ + u64 base64; + rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); + + if (class_code == PCI_BASE_CLASS_DISPLAY) + return (DEVICE_TYPE_NOT_SUPPORTED); + + /* Figure out IO and memory needs */ + for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) { + temp_register = 0xFFFFFFFF; + + rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); + rc = pci_bus_read_config_dword(pci_bus, devfn, cloop, &temp_register); + dbg("Bar[%x]=0x%x on bus:dev:func(0x%x:%x:%x)\n", cloop, temp_register, func->bus, func->device, func->function); + + if (!temp_register) + continue; + + base64 = 0L; + if (temp_register & PCI_BASE_ADDRESS_SPACE_IO) { + /* Map IO */ + + /* Set base = amount of IO space */ + base = temp_register & 0xFFFFFFFC; + base = ~base + 1; + + dbg("NEED IO length(0x%x)\n", base); + io_node = get_io_resource(&(resources->io_head),(ulong)base); + + /* Allocate the resource to the board */ + if (io_node) { + dbg("Got IO base=0x%x(length=0x%x)\n", io_node->base, io_node->length); + base = (u32)io_node->base; + io_node->next = func->io_head; + func->io_head = io_node; + } else { + err("Got NO IO resource(length=0x%x)\n", base); + return -ENOMEM; + } + } else { /* Map MEM */ + int prefetchable = 1; + struct pci_resource **res_node = &func->p_mem_head; + char *res_type_str = "PMEM"; + u32 temp_register2; + + if (!(temp_register & PCI_BASE_ADDRESS_MEM_PREFETCH)) { + prefetchable = 0; + res_node = &func->mem_head; + res_type_str++; + } + + base = temp_register & 0xFFFFFFF0; + base = ~base + 1; + + switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) { + case PCI_BASE_ADDRESS_MEM_TYPE_32: + dbg("NEED 32 %s bar=0x%x(length=0x%x)\n", res_type_str, temp_register, base); + + if (prefetchable && resources->p_mem_head) + mem_node=get_resource(&(resources->p_mem_head), (ulong)base); + else { + if (prefetchable) + dbg("using MEM for PMEM\n"); + mem_node=get_resource(&(resources->mem_head), (ulong)base); + } + + /* Allocate the resource to the board */ + if (mem_node) { + base = (u32)mem_node->base; + mem_node->next = *res_node; + *res_node = mem_node; + dbg("Got 32 %s base=0x%x(length=0x%x)\n", res_type_str, mem_node->base, mem_node->length); + } else { + err("Got NO 32 %s resource(length=0x%x)\n", res_type_str, base); + return -ENOMEM; + } + break; + case PCI_BASE_ADDRESS_MEM_TYPE_64: + rc = pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2); + dbg("NEED 64 %s bar=0x%x:%x(length=0x%x)\n", res_type_str, temp_register2, temp_register, base); + + if (prefetchable && resources->p_mem_head) + mem_node = get_resource(&(resources->p_mem_head), (ulong)base); + else { + if (prefetchable) + dbg("using MEM for PMEM\n"); + mem_node = get_resource(&(resources->mem_head), (ulong)base); + } + + /* Allocate the resource to the board */ + if (mem_node) { + base64 = mem_node->base; + mem_node->next = *res_node; + *res_node = mem_node; + dbg("Got 64 %s base=0x%x:%x(length=%x)\n", res_type_str, (u32)(base64 >> 32), (u32)base64, mem_node->length); + } else { + err("Got NO 64 %s resource(length=0x%x)\n", res_type_str, base); + return -ENOMEM; + } + break; + default: + dbg("reserved BAR type=0x%x\n", temp_register); + break; + } + + } + + if (base64) { + rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64); + cloop += 4; + base64 >>= 32; + + if (base64) { + dbg("%s: high dword of base64(0x%x) set to 0\n", __FUNCTION__, (u32)base64); + base64 = 0x0L; + } + + rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64); + } else { + rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, base); + } + } /* End of base register loop */ + + /* Disable ROM base Address */ + temp_word = 0x00L; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_ROM_ADDRESS, temp_word); + + /* Set HP parameters (Cache Line Size, Latency Timer) */ + rc = pciehprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_NORMAL); + if (rc) + return rc; + + pciehprm_enable_card(ctrl, func, PCI_HEADER_TYPE_NORMAL); + + dbg("PCI function Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, func->function); + } /* End of Not-A-Bridge else */ + else { + /* It's some strange type of PCI adapter (Cardbus?) */ + return(DEVICE_TYPE_NOT_SUPPORTED); + } + + func->configured = 1; + + dbg("%s: exit\n", __FUNCTION__); + + return 0; +} + diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/pciehp_hpc.c linux-2.4.27-pre5/drivers/hotplug/pciehp_hpc.c --- linux-2.4.26/drivers/hotplug/pciehp_hpc.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/pciehp_hpc.c 2004-06-03 01:33:55.000000000 +0000 @@ -0,0 +1,1504 @@ +/* + * PCI Express PCI Hot Plug 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 "pciehp.h" + +#ifdef DEBUG +#define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */ +#define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */ +#define DBG_K_INFO ((unsigned int)0x00000004) /* Info messages */ +#define DBG_K_ERROR ((unsigned int)0x00000008) /* Error messages */ +#define DBG_K_TRACE (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT) +#define DBG_K_STANDARD (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE) +/* Redefine this flagword to set debug level */ +#define DEBUG_LEVEL DBG_K_STANDARD + +#define DEFINE_DBG_BUFFER char __dbg_str_buf[256]; + +#define DBG_PRINT( dbg_flags, args... ) \ + do { \ + if ( DEBUG_LEVEL & ( dbg_flags ) ) \ + { \ + int len; \ + len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \ + __FILE__, __LINE__, __FUNCTION__ ); \ + sprintf( __dbg_str_buf + len, args ); \ + printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \ + } \ + } while (0) + +#define DBG_ENTER_ROUTINE DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]"); +#define DBG_LEAVE_ROUTINE DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]"); +#else +#define DEFINE_DBG_BUFFER +#define DBG_ENTER_ROUTINE +#define DBG_LEAVE_ROUTINE +#endif /* DEBUG */ + +struct ctrl_reg { + u8 cap_id; + u8 nxt_ptr; + u16 cap_reg; + u32 dev_cap; + u16 dev_ctrl; + u16 dev_status; + u32 lnk_cap; + u16 lnk_ctrl; + u16 lnk_status; + u32 slot_cap; + u16 slot_ctrl; + u16 slot_status; + u16 root_ctrl; + u16 rsvp; + u32 root_status; +} __attribute__ ((packed)); + +/* offsets to the controller registers based on the above structure layout */ +enum ctrl_offsets { + PCIECAPID = offsetof(struct ctrl_reg, cap_id), + NXTCAPPTR = offsetof(struct ctrl_reg, nxt_ptr), + CAPREG = offsetof(struct ctrl_reg, cap_reg), + DEVCAP = offsetof(struct ctrl_reg, dev_cap), + DEVCTRL = offsetof(struct ctrl_reg, dev_ctrl), + DEVSTATUS = offsetof(struct ctrl_reg, dev_status), + LNKCAP = offsetof(struct ctrl_reg, lnk_cap), + LNKCTRL = offsetof(struct ctrl_reg, lnk_ctrl), + LNKSTATUS = offsetof(struct ctrl_reg, lnk_status), + SLOTCAP = offsetof(struct ctrl_reg, slot_cap), + SLOTCTRL = offsetof(struct ctrl_reg, slot_ctrl), + SLOTSTATUS = offsetof(struct ctrl_reg, slot_status), + ROOTCTRL = offsetof(struct ctrl_reg, root_ctrl), + ROOTSTATUS = offsetof(struct ctrl_reg, root_status), +}; +static int pcie_cap_base = 0; /* Base of the PCI Express capability item structure */ + +#define PCIE_CAP_ID ( pcie_cap_base + PCIECAPID ) +#define NXT_CAP_PTR ( pcie_cap_base + NXTCAPPTR ) +#define CAP_REG ( pcie_cap_base + CAPREG ) +#define DEV_CAP ( pcie_cap_base + DEVCAP ) +#define DEV_CTRL ( pcie_cap_base + DEVCTRL ) +#define DEV_STATUS ( pcie_cap_base + DEVSTATUS ) +#define LNK_CAP ( pcie_cap_base + LNKCAP ) +#define LNK_CTRL ( pcie_cap_base + LNKCTRL ) +#define LNK_STATUS ( pcie_cap_base + LNKSTATUS ) +#define SLOT_CAP ( pcie_cap_base + SLOTCAP ) +#define SLOT_CTRL ( pcie_cap_base + SLOTCTRL ) +#define SLOT_STATUS ( pcie_cap_base + SLOTSTATUS ) +#define ROOT_CTRL ( pcie_cap_base + ROOTCTRL ) +#define ROOT_STATUS ( pcie_cap_base + ROOTSTATUS ) + +#define hp_register_read_word(pdev, reg , value) \ + pci_read_config_word(pdev, reg, &value) + +#define hp_register_read_dword(pdev, reg , value) \ + pci_read_config_dword(pdev, reg, &value) + +#define hp_register_write_word(pdev, reg , value) \ + pci_write_config_word(pdev, reg, value) + +#define hp_register_dwrite_word(pdev, reg , value) \ + pci_write_config_dword(pdev, reg, value) + +/* Field definitions in PCI Express Capabilities Register */ +#define CAP_VER 0x000F +#define DEV_PORT_TYPE 0x00F0 +#define SLOT_IMPL 0x0100 +#define MSG_NUM 0x3E00 + +/* Device or Port Type */ +#define NAT_ENDPT 0x00 +#define LEG_ENDPT 0x01 +#define ROOT_PORT 0x04 +#define UP_STREAM 0x05 +#define DN_STREAM 0x06 +#define PCIE_PCI_BRDG 0x07 +#define PCI_PCIE_BRDG 0x10 + +/* Field definitions in Device Capabilities Register */ +#define DATTN_BUTTN_PRSN 0x1000 +#define DATTN_LED_PRSN 0x2000 +#define DPWR_LED_PRSN 0x4000 + +/* Field definitions in Link Capabilities Register */ +#define MAX_LNK_SPEED 0x000F +#define MAX_LNK_WIDTH 0x03F0 + +/* Link Width Encoding */ +#define LNK_X1 0x01 +#define LNK_X2 0x02 +#define LNK_X4 0x04 +#define LNK_X8 0x08 +#define LNK_X12 0x0C +#define LNK_X16 0x10 +#define LNK_X32 0x20 + +/*Field definitions of Link Status Register */ +#define LNK_SPEED 0x000F +#define NEG_LINK_WD 0x03F0 +#define LNK_TRN_ERR 0x0400 +#define LNK_TRN 0x0800 +#define SLOT_CLK_CONF 0x1000 + +/* Field definitions in Slot Capabilities Register */ +#define ATTN_BUTTN_PRSN 0x00000001 +#define PWR_CTRL_PRSN 0x00000002 +#define MRL_SENS_PRSN 0x00000004 +#define ATTN_LED_PRSN 0x00000008 +#define PWR_LED_PRSN 0x00000010 +#define HP_SUPR_RM 0x00000020 +#define HP_CAP 0x00000040 +#define SLOT_PWR_VALUE 0x000003F8 +#define SLOT_PWR_LIMIT 0x00000C00 +#define PSN 0xFFF80000 /* PSN: Physical Slot Number */ + +/* Field definitions in Slot Control Register */ +#define ATTN_BUTTN_ENABLE 0x0001 +#define PWR_FAULT_DETECT_ENABLE 0x0002 +#define MRL_DETECT_ENABLE 0x0004 +#define PRSN_DETECT_ENABLE 0x0008 +#define CMD_CMPL_INTR_ENABLE 0x0010 +#define HP_INTR_ENABLE 0x0020 +#define ATTN_LED_CTRL 0x00C0 +#define PWR_LED_CTRL 0x0300 +#define PWR_CTRL 0x0400 + +/* Attention indicator and Power indicator states */ +#define LED_ON 0x01 +#define LED_BLINK 0x10 +#define LED_OFF 0x11 + +/* Power Control Command */ +#define POWER_ON 0 +#define POWER_OFF 0x0400 + +/* Field definitions in Slot Status Register */ +#define ATTN_BUTTN_PRESSED 0x0001 +#define PWR_FAULT_DETECTED 0x0002 +#define MRL_SENS_CHANGED 0x0004 +#define PRSN_DETECT_CHANGED 0x0008 +#define CMD_COMPLETED 0x0010 +#define MRL_STATE 0x0020 +#define PRSN_STATE 0x0040 + +struct php_ctlr_state_s { + struct php_ctlr_state_s *pnext; + struct pci_dev *pci_dev; + unsigned int irq; + unsigned long flags; /* spinlock's */ + u32 slot_device_offset; + u32 num_slots; + struct timer_list int_poll_timer; /* Added for poll event */ + 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; + void *callback_instance_id; + struct ctrl_reg *creg; /* Ptr to controller register space */ +}; + +static spinlock_t hpc_event_lock; + +DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ +static struct php_ctlr_state_s *php_ctlr_list_head = 0; /* HPC state linked list */ +static int ctlr_seq_num = 0; /* Controller sequence # */ +static spinlock_t list_lock; +static void pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs); + +static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds); + +/* This is the interrupt polling timeout function. */ +static void int_poll_timeout(unsigned long lphp_ctlr) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr; + + DBG_ENTER_ROUTINE + + if ( !php_ctlr ) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return; + } + + /* Poll for interrupt events. regs == NULL => polling */ + pcie_isr( 0, (void *)php_ctlr, NULL ); + + init_timer(&php_ctlr->int_poll_timer); + + if (!pciehp_poll_time) + pciehp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/ + + start_int_poll_timer(php_ctlr, pciehp_poll_time); + + return; +} + +/* This function starts the interrupt polling timer. */ +static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds) +{ + if (!php_ctlr) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return; + } + + if ( ( seconds <= 0 ) || ( seconds > 60 ) ) + seconds = 2; /* Clamp to sane value */ + + php_ctlr->int_poll_timer.function = &int_poll_timeout; + php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr; /* Instance data */ + php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ; + add_timer(&php_ctlr->int_poll_timer); + + return; +} + +static int pcie_write_cmd(struct slot *slot, u16 cmd) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + int retval = 0; + u16 slot_status; + + DBG_ENTER_ROUTINE + + dbg("%s : Enter\n", __FUNCTION__); + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + if (retval) { + err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + return retval; + } + dbg("%s : hp_register_read_word SLOT_STATUS %x\n", __FUNCTION__, slot_status); + + if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) { + /* After 1 sec and CMD_COMPLETED still not set, just proceed forward to issue + the next command according to spec. Just print out the error message */ + dbg("%s : CMD_COMPLETED not clear after 1 sec.\n", __FUNCTION__); + } + + dbg("%s : Before hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, cmd); + retval = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, cmd | CMD_CMPL_INTR_ENABLE); + if (retval) { + err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); + return retval; + } + dbg("%s : hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, cmd|CMD_CMPL_INTR_ENABLE); + dbg("%s : Exit\n", __FUNCTION__); + + DBG_LEAVE_ROUTINE + return retval; +} + +static int hpc_check_lnk_status(struct controller *ctrl) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle; + u16 lnk_status; + int retval = 0; + + DBG_ENTER_ROUTINE + + if (!ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS, lnk_status); + + if (retval) { + err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__); + return retval; + } + + if ( (lnk_status & (LNK_TRN | LNK_TRN_ERR)) == 0x0C00) { + err("%s : Link Training Error occurs \n", __FUNCTION__); + retval = -1; + return retval; + } + + DBG_LEAVE_ROUTINE + return retval; +} + + +static int hpc_get_attention_status(struct slot *slot, u8 *status) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u16 slot_ctrl; + u8 atten_led_state; + int retval = 0; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + + if (retval) { + err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + return retval; + } + + dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__,SLOT_CTRL, slot_ctrl); + + atten_led_state = (slot_ctrl & ATTN_LED_CTRL) >> 6; + //atten_led_state = (slot_ctrl & PWR_LED_CTRL) >> 8; + + switch (atten_led_state) { + case 0: + *status = 0xFF; /* Reserved */ + break; + case 1: + *status = 1; /* On */ + break; + case 2: + *status = 2; /* Blink */ + break; + case 3: + *status = 0; /* Off */ + break; + default: + *status = 0xFF; + break; + } + + DBG_LEAVE_ROUTINE + return 0; +} + +static int hpc_get_power_status(struct slot * slot, u8 *status) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u16 slot_ctrl; + u8 pwr_state; + int retval = 0; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + + if (retval) { + err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + return retval; + } + dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, slot_ctrl); + + pwr_state = (slot_ctrl & PWR_CTRL) >> 10; + + switch (pwr_state) { + case 0: + *status = 1; + break; + case 1: + *status = 0; + break; + default: + *status = 0xFF; + break; + } + + DBG_LEAVE_ROUTINE + return retval; +} + + +static int hpc_get_latch_status(struct slot *slot, u8 *status) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u16 slot_status; + int retval = 0; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + + if (retval) { + err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + return retval; + } + + *status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1; + + DBG_LEAVE_ROUTINE + return 0; +} + +static int hpc_get_adapter_status(struct slot *slot, u8 *status) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u16 slot_status; + u8 card_state; + int retval = 0; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + + if (retval) { + err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + return retval; + } + card_state = (u8)((slot_status & PRSN_STATE) >> 6); + *status = (card_state == 1) ? 1 : 0; + + DBG_LEAVE_ROUTINE + return 0; +} + + +static int hpc_query_power_fault(struct slot * slot) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u16 slot_status; + u8 pwr_fault; + int retval = 0; + u8 status; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + + if (retval) { + err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + return retval; + } + pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1); + status = (pwr_fault != 1) ? 1 : 0; + + DBG_LEAVE_ROUTINE + /* Note: Logic 0 => fault */ + return status; +} + +static int hpc_set_attention_status(struct slot *slot, u8 value) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u16 slot_cmd = 0; + u16 slot_ctrl; + int rc = 0; + + dbg("%s: \n", __FUNCTION__); + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + if (slot->hp_slot >= php_ctlr->num_slots) { + err("%s: Invalid HPC slot number!\n", __FUNCTION__); + return -1; + } + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + + if (rc) { + err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + return rc; + } + dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl); + + switch (value) { + case 0 : /* turn off */ + slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x00C0; + //slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0300; + break; + case 1: /* turn on */ + slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x0040; + //slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0100; + break; + case 2: /* turn blink */ + slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x0080; + //slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0200; + break; + default: + return -1; + } + if (!pciehp_poll_mode) + slot_cmd = slot_cmd | HP_INTR_ENABLE; + + pcie_write_cmd(slot, slot_cmd); + dbg("%s: SLOT_CTRL %x write cmd %x\n", + __FUNCTION__, SLOT_CTRL, slot_cmd); + + return rc; +} + + +static void hpc_set_green_led_on(struct slot *slot) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u16 slot_cmd; + u16 slot_ctrl; + int rc = 0; + + dbg("%s: \n", __FUNCTION__); + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return ; + } + + if (slot->hp_slot >= php_ctlr->num_slots) { + err("%s: Invalid HPC slot number!\n", __FUNCTION__); + return ; + } + + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + + if (rc) { + err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + return ; + } + dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl); + slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0100; + //slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x0040; + + if (!pciehp_poll_mode) + slot_cmd = slot_cmd | HP_INTR_ENABLE; + + pcie_write_cmd(slot, slot_cmd); + + dbg("%s: SLOT_CTRL %x write cmd %x\n", + __FUNCTION__, SLOT_CTRL, slot_cmd); + return; +} + +static void hpc_set_green_led_off(struct slot *slot) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u16 slot_cmd; + u16 slot_ctrl; + int rc = 0; + + dbg("%s: \n", __FUNCTION__); + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return ; + } + + if (slot->hp_slot >= php_ctlr->num_slots) { + err("%s: Invalid HPC slot number!\n", __FUNCTION__); + return ; + } + + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + + if (rc) { + err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + return; + } + dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl); + + slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0300; + //slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x00c0; + + if (!pciehp_poll_mode) + slot_cmd = slot_cmd | HP_INTR_ENABLE; + pcie_write_cmd(slot, slot_cmd); + + dbg("%s: SLOT_CTRL %x write cmd %x\n", + __FUNCTION__, SLOT_CTRL, slot_cmd); + return; +} + +static void hpc_set_green_led_blink(struct slot *slot) +{ + struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u16 slot_cmd; + u16 slot_ctrl; + int rc = 0; + + dbg("%s: \n", __FUNCTION__); + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return ; + } + + if (slot->hp_slot >= php_ctlr->num_slots) { + err("%s: Invalid HPC slot number!\n", __FUNCTION__); + return ; + } + + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + + if (rc) { + err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + return; + } + dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl); + + slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0200; + //slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x0080; + + if (!pciehp_poll_mode) + slot_cmd = slot_cmd | HP_INTR_ENABLE; + pcie_write_cmd(slot, slot_cmd); + + dbg("%s: SLOT_CTRL %x write cmd %x\n", + __FUNCTION__, SLOT_CTRL, slot_cmd); + return; +} + +int pcie_get_ctlr_slot_config(struct controller *ctrl, + int *num_ctlr_slots, /* number of slots in this HPC; only 1 in PCIE */ + int *first_device_num, /* PCI dev num of the first slot in this PCIE */ + int *physical_slot_num, /* phy slot num of the first slot in this PCIE */ + int *updown, /* physical_slot_num increament: 1 or -1 */ + int *flags) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle; + u32 slot_cap; + int rc = 0; + + DBG_ENTER_ROUTINE + + if (!ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + *first_device_num = 0; + *num_ctlr_slots = 1; + + rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP, slot_cap); + if (rc) { + err("%s : hp_register_read_dword SLOT_CAP failed\n", __FUNCTION__); + return -1; + } + + *physical_slot_num = slot_cap >> 19; + *updown = -1; + + DBG_LEAVE_ROUTINE + return 0; +} + +static void hpc_release_ctlr(struct controller *ctrl) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *p, *p_prev; + + DBG_ENTER_ROUTINE + + if (!ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return ; + } + + if (pciehp_poll_mode) { + del_timer(&php_ctlr->int_poll_timer); + } else { + if (php_ctlr->irq) { + free_irq(php_ctlr->irq, ctrl); + php_ctlr->irq = 0; + } + } + if (php_ctlr->pci_dev) + php_ctlr->pci_dev = 0; + + spin_lock(&list_lock); + p = php_ctlr_list_head; + p_prev = NULL; + while (p) { + if (p == php_ctlr) { + if (p_prev) + p_prev->pnext = p->pnext; + else + php_ctlr_list_head = p->pnext; + break; + } else { + p_prev = p; + p = p->pnext; + } + } + spin_unlock(&list_lock); + + kfree(php_ctlr); + + DBG_LEAVE_ROUTINE + +} + +static int hpc_power_on_slot(struct slot * slot) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u16 slot_cmd; + u16 slot_ctrl; + + int retval = 0; + + DBG_ENTER_ROUTINE + dbg("%s: \n", __FUNCTION__); + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); + if (slot->hp_slot >= php_ctlr->num_slots) { + err("%s: Invalid HPC slot number!\n", __FUNCTION__); + return -1; + } + + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + + if (retval) { + err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + return retval; + } + dbg("%s: SLOT_CTRL %x, value read %xn", __FUNCTION__, SLOT_CTRL, + slot_ctrl); + + slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_ON; + + if (!pciehp_poll_mode) + slot_cmd = slot_cmd | HP_INTR_ENABLE; + + retval = pcie_write_cmd(slot, slot_cmd); + + if (retval) { + err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd); + return -1; + } + dbg("%s: SLOT_CTRL %x write cmd %x\n", + __FUNCTION__, SLOT_CTRL, slot_cmd); + + DBG_LEAVE_ROUTINE + + return retval; +} + +static int hpc_power_off_slot(struct slot * slot) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u16 slot_cmd; + u16 slot_ctrl; + + int retval = 0; + + DBG_ENTER_ROUTINE + dbg("%s: \n", __FUNCTION__); + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot); + slot->hp_slot = 0; + if (slot->hp_slot >= php_ctlr->num_slots) { + err("%s: Invalid HPC slot number!\n", __FUNCTION__); + return -1; + } + retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + + if (retval) { + err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + return retval; + } + dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__, SLOT_CTRL, + slot_ctrl); + + slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_OFF; + + if (!pciehp_poll_mode) + slot_cmd = slot_cmd | HP_INTR_ENABLE; + + retval = pcie_write_cmd(slot, slot_cmd); + + if (retval) { + err("%s: Write command failed!\n", __FUNCTION__); + return -1; + } + dbg("%s: SLOT_CTRL %x write cmd %x\n", + __FUNCTION__, SLOT_CTRL, slot_cmd); + + DBG_LEAVE_ROUTINE + + return retval; +} + +static void pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs) +{ + struct controller *ctrl = NULL; + struct php_ctlr_state_s *php_ctlr; + u8 schedule_flag = 0; + u16 slot_status, intr_detect, intr_loc; + u16 temp_word; + int hp_slot = 0; /* only 1 slot per PCI Express port */ + int rc = 0; + + if (!dev_id) { + dbg("%s: dev_id == NULL\n", __FUNCTION__); + return; + } + + if (!pciehp_poll_mode) { + ctrl = (struct controller *)dev_id; + php_ctlr = ctrl->hpc_ctlr_handle; + } else { + php_ctlr = (struct php_ctlr_state_s *) dev_id; + ctrl = (struct controller *)php_ctlr->callback_instance_id; + } + + if (!ctrl) { + dbg("%s: dev_id %p ctlr == NULL\n", __FUNCTION__, (void*) dev_id); + return; + } + if (!php_ctlr) { + dbg("%s: php_ctlr == NULL\n", __FUNCTION__); + return; + } + + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + if (rc) { + err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + return; + } + /* dbg("%s: hp_register_read_word SLOT_STATUS with value %x\n", __FUNCTION__, slot_status); */ + + intr_detect = ( ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | MRL_SENS_CHANGED | + PRSN_DETECT_CHANGED | CMD_COMPLETED ); + + intr_loc = slot_status & intr_detect; + + /* Check to see if it was our interrupt */ + if ( !intr_loc ) + return; + + dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc); + + /* Mask Hot-plug Interrupt Enable */ + if (!pciehp_poll_mode) { + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word); + if (rc) { + err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + return; + } + + dbg("%s: Set Mask Hot-plug Interrupt Enable\n", __FUNCTION__); + dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); + temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00; + + rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word); + if (rc) { + err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); + return; + } + dbg("%s: hp_register_write_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); + + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + if (rc) { + err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + return; + } + dbg("%s: hp_register_read_word SLOT_STATUS with value %x\n", __FUNCTION__, slot_status); + + /* Clear command complete interrupt caused by this write */ + temp_word = 0x1f; + rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word); + if (rc) { + err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); + return; + } + dbg("%s: hp_register_write_word SLOT_STATUS with value %x\n", __FUNCTION__, temp_word); + } + + if (intr_loc & CMD_COMPLETED) { + /* + * Command Complete Interrupt Pending + */ + dbg("%s: In Command Complete Interrupt Pending\n", __FUNCTION__); + wake_up_interruptible(&ctrl->queue); + } + if ((php_ctlr->switch_change_callback) && (intr_loc & MRL_SENS_CHANGED)) + schedule_flag += php_ctlr->switch_change_callback( + hp_slot, php_ctlr->callback_instance_id); + if ((php_ctlr->attention_button_callback) && (intr_loc & ATTN_BUTTN_PRESSED)) + schedule_flag += php_ctlr->attention_button_callback( + hp_slot, php_ctlr->callback_instance_id); + if ((php_ctlr->presence_change_callback) && (intr_loc & PRSN_DETECT_CHANGED)) + schedule_flag += php_ctlr->presence_change_callback( + hp_slot , php_ctlr->callback_instance_id); + if ((php_ctlr->power_fault_callback) && (intr_loc & PWR_FAULT_DETECTED)) + schedule_flag += php_ctlr->power_fault_callback( + hp_slot, php_ctlr->callback_instance_id); + + /* Clear all events after serving them */ + temp_word = 0x1F; + rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word); + if (rc) { + err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); + return; + } + + /* Unmask Hot-plug Interrupt Enable */ + if (!pciehp_poll_mode) { + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word); + if (rc) { + err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + return; + } + dbg("%s: Unmask Hot-plug Interrupt Enable\n", __FUNCTION__); + dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); + temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; + + rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word); + if (rc) { + err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); + return; + } + dbg("%s: hp_register_write_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word); + + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + if (rc) { + err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + return; + } + dbg("%s: hp_register_read_word SLOT_STATUS with value %x\n", __FUNCTION__, slot_status); + + /* Clear command complete interrupt caused by this write */ + temp_word = 0x1F; + rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word); + if (rc) { + err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); + return; + } + dbg("%s: hp_register_write_word SLOT_STATUS with value %x\n", __FUNCTION__, temp_word); + } + return; +} + +static int hpc_get_max_lnk_speed (struct slot *slot, enum pcie_link_speed *value) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + enum pcie_link_speed lnk_speed; + u32 lnk_cap; + int retval = 0; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + if (slot->hp_slot >= php_ctlr->num_slots) { + err("%s: Invalid HPC slot number!\n", __FUNCTION__); + return -1; + } + + retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP, lnk_cap); + + if (retval) { + err("%s : hp_register_read_dword LNK_CAP failed\n", __FUNCTION__); + return retval; + } + + switch (lnk_cap & 0x000F) { + case 1: + lnk_speed = PCIE_2PT5GB; + break; + default: + lnk_speed = PCIE_LNK_SPEED_UNKNOWN; + break; + } + + *value = lnk_speed; + dbg("Max link speed = %d\n", lnk_speed); + DBG_LEAVE_ROUTINE + return retval; +} + +static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + enum pcie_link_width lnk_wdth; + u32 lnk_cap; + int retval = 0; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + if (slot->hp_slot >= php_ctlr->num_slots) { + err("%s: Invalid HPC slot number!\n", __FUNCTION__); + return -1; + } + + retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP, lnk_cap); + + if (retval) { + err("%s : hp_register_read_dword LNK_CAP failed\n", __FUNCTION__); + return retval; + } + + switch ((lnk_cap & 0x03F0) >> 4){ + case 0: + lnk_wdth = PCIE_LNK_WIDTH_RESRV; + break; + case 1: + lnk_wdth = PCIE_LNK_X1; + break; + case 2: + lnk_wdth = PCIE_LNK_X2; + break; + case 4: + lnk_wdth = PCIE_LNK_X4; + break; + case 8: + lnk_wdth = PCIE_LNK_X8; + break; + case 12: + lnk_wdth = PCIE_LNK_X12; + break; + case 16: + lnk_wdth = PCIE_LNK_X16; + break; + case 32: + lnk_wdth = PCIE_LNK_X32; + break; + default: + lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN; + break; + } + + *value = lnk_wdth; + dbg("Max link width = %d\n", lnk_wdth); + DBG_LEAVE_ROUTINE + return retval; +} + +static int hpc_get_cur_lnk_speed (struct slot *slot, enum pcie_link_speed *value) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN; + int retval = 0; + u16 lnk_status; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + if (slot->hp_slot >= php_ctlr->num_slots) { + err("%s: Invalid HPC slot number!\n", __FUNCTION__); + return -1; + } + + retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS, lnk_status); + + if (retval) { + err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__); + return retval; + } + + switch (lnk_status & 0x0F) { + case 1: + lnk_speed = PCIE_2PT5GB; + break; + default: + lnk_speed = PCIE_LNK_SPEED_UNKNOWN; + break; + } + + *value = lnk_speed; + dbg("Current link speed = %d\n", lnk_speed); + DBG_LEAVE_ROUTINE + return retval; +} + +static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN; + int retval = 0; + u16 lnk_status; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + if (slot->hp_slot >= php_ctlr->num_slots) { + err("%s: Invalid HPC slot number!\n", __FUNCTION__); + return -1; + } + + retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS, lnk_status); + + if (retval) { + err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__); + return retval; + } + + switch ((lnk_status & 0x03F0) >> 4){ + case 0: + lnk_wdth = PCIE_LNK_WIDTH_RESRV; + break; + case 1: + lnk_wdth = PCIE_LNK_X1; + break; + case 2: + lnk_wdth = PCIE_LNK_X2; + break; + case 4: + lnk_wdth = PCIE_LNK_X4; + break; + case 8: + lnk_wdth = PCIE_LNK_X8; + break; + case 12: + lnk_wdth = PCIE_LNK_X12; + break; + case 16: + lnk_wdth = PCIE_LNK_X16; + break; + case 32: + lnk_wdth = PCIE_LNK_X32; + break; + default: + lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN; + break; + } + + *value = lnk_wdth; + dbg("Current link width = %d\n", lnk_wdth); + DBG_LEAVE_ROUTINE + return retval; +} + +static struct hpc_ops pciehp_hpc_ops = { + .power_on_slot = hpc_power_on_slot, + .power_off_slot = hpc_power_off_slot, + .set_attention_status = hpc_set_attention_status, + .get_power_status = hpc_get_power_status, + .get_attention_status = hpc_get_attention_status, + .get_latch_status = hpc_get_latch_status, + .get_adapter_status = hpc_get_adapter_status, + + .get_max_bus_speed = hpc_get_max_lnk_speed, + .get_cur_bus_speed = hpc_get_cur_lnk_speed, + .get_max_lnk_width = hpc_get_max_lnk_width, + .get_cur_lnk_width = hpc_get_cur_lnk_width, + + .query_power_fault = hpc_query_power_fault, + .green_led_on = hpc_set_green_led_on, + .green_led_off = hpc_set_green_led_off, + .green_led_blink = hpc_set_green_led_blink, + + .release_ctlr = hpc_release_ctlr, + .check_lnk_status = hpc_check_lnk_status, +}; + +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) +{ + struct php_ctlr_state_s *php_ctlr, *p; + void *instance_id = ctrl; + int rc; + static int first = 1; + u16 temp_word; + u16 cap_reg; + u16 intr_enable; + u32 slot_cap; + int cap_base, saved_cap_base; + u16 slot_status, slot_ctrl; + + DBG_ENTER_ROUTINE + + spin_lock_init(&list_lock); + php_ctlr = (struct php_ctlr_state_s *) kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL); + + if (!php_ctlr) { /* Allocate controller state data */ + err("%s: HPC controller memory allocation error!\n", __FUNCTION__); + goto abort; + } + + memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s)); + + php_ctlr->pci_dev = pdev; /* Save pci_dev in context */ + + dbg("%s: pdev->vendor %x pdev->device %x\n", __FUNCTION__, + pdev->vendor, pdev->device); + + saved_cap_base = pcie_cap_base; + + if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) { + dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__); + goto abort_free_ctlr; + } + pcie_cap_base = cap_base; + + dbg("%s: pcie_cap_base %x\n", __FUNCTION__, pcie_cap_base); + + rc = hp_register_read_word(pdev, CAP_REG, cap_reg); + if (rc) { + err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__); + goto abort_free_ctlr; + } + dbg("%s: CAP_REG offset %x cap_reg %x\n", __FUNCTION__, CAP_REG, cap_reg); + + if (((cap_reg & SLOT_IMPL) == 0) || ((cap_reg & DEV_PORT_TYPE) != 0x0040)){ + dbg("%s : This is not a root port or the port is not connected to a slot\n", __FUNCTION__); + goto abort_free_ctlr; + } + + rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP, slot_cap); + if (rc) { + err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__); + goto abort_free_ctlr; + } + dbg("%s: SLOT_CAP offset %x slot_cap %x\n", __FUNCTION__, SLOT_CAP, slot_cap); + + if (!(slot_cap & HP_CAP)) { + dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__); + goto abort_free_ctlr; + } + + /* For debugging purpose */ + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + if (rc) { + err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + goto abort_free_ctlr; + } + dbg("%s: SLOT_STATUS offset %x slot_status %x\n", __FUNCTION__, SLOT_STATUS, slot_status); + + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl); + if (rc) { + err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + goto abort_free_ctlr; + } + dbg("%s: SLOT_CTRL offset %x slot_ctrl %x\n", __FUNCTION__, SLOT_CTRL, slot_ctrl); + + if (first) { + spin_lock_init(&hpc_event_lock); + first = 0; + } + + dbg("pdev = %p: b:d:f:irq=0x%x:%x:%x:%x\n", pdev, pdev->bus->number, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pdev->irq); + for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) + if (pci_resource_len(pdev, rc) > 0) + dbg("pci resource[%d] start=0x%lx(len=0x%lx)\n", rc, + pci_resource_start(pdev, rc), pci_resource_len(pdev, rc)); + + dbg("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, + pdev->subsystem_vendor, pdev->subsystem_device); + + init_MUTEX(&ctrl->crit_sect); + /* Setup wait queue */ + init_waitqueue_head(&ctrl->queue); + + /* Find the IRQ */ + php_ctlr->irq = pdev->irq; + dbg("HPC interrupt = %d\n", php_ctlr->irq); + + /* Save interrupt callback info */ + php_ctlr->attention_button_callback = attention_button_callback; + php_ctlr->switch_change_callback = switch_change_callback; + php_ctlr->presence_change_callback = presence_change_callback; + php_ctlr->power_fault_callback = power_fault_callback; + php_ctlr->callback_instance_id = instance_id; + + /* Return PCI Controller Info */ + php_ctlr->slot_device_offset = 0; + php_ctlr->num_slots = 1; + + /* Mask Hot-plug Interrupt Enable */ + rc = hp_register_read_word(pdev, SLOT_CTRL, temp_word); + if (rc) { + err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + goto abort_free_ctlr; + } + dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, temp_word); + temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00; + + rc = hp_register_write_word(pdev, SLOT_CTRL, temp_word); + if (rc) { + err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); + goto abort_free_ctlr; + } + dbg("%s : Mask HPIE hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, temp_word); + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + if (rc) { + err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + goto abort_free_ctlr; + } + dbg("%s: Mask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, + SLOT_STATUS, slot_status); + + temp_word = 0x1F; /* Clear all events */ + rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word); + if (rc) { + err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); + goto abort_free_ctlr; + } + dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS, temp_word); + + if (pciehp_poll_mode) {/* Install interrupt polling code */ + /* Install and start the interrupt polling timer */ + init_timer(&php_ctlr->int_poll_timer); + start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */ + } else { + /* Installs the interrupt handler */ +#ifdef CONFIG_PCI_USE_VECTOR + if (!pciehp_msi_quirk) { + rc = pci_enable_msi(pdev); + if (rc) { + info("Can't get msi for the hotplug controller\n"); + info("Use INTx for the hotplug controller\n"); + dbg("%s: rc = %x\n", __FUNCTION__, rc); + } else + php_ctlr->irq = pdev->irq; + } +#endif + rc = request_irq(php_ctlr->irq, pcie_isr, SA_SHIRQ, MY_NAME, (void *) ctrl); + dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc); + if (rc) { + err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq); + goto abort_free_ctlr; + } + } + + rc = hp_register_read_word(pdev, SLOT_CTRL, temp_word); + if (rc) { + err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); + goto abort_free_ctlr; + } + dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, temp_word); + + intr_enable = ATTN_BUTTN_ENABLE | PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | + PRSN_DETECT_ENABLE; + + temp_word = (temp_word & ~intr_enable) | intr_enable; + + if (pciehp_poll_mode) { + temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0; + } else { + temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; + } + dbg("%s: temp_word %x\n", __FUNCTION__, temp_word); + + /* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */ + rc = hp_register_write_word(pdev, SLOT_CTRL, temp_word); + if (rc) { + err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); + goto abort_free_ctlr; + } + dbg("%s : Unmask HPIE hp_register_write_word SLOT_CTRL with %x\n", __FUNCTION__, temp_word); + + rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status); + if (rc) { + err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); + goto abort_free_ctlr; + } + dbg("%s: Unmask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, + SLOT_STATUS, slot_status); + + temp_word = 0x1F; /* Clear all events */ + rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word); + if (rc) { + err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); + goto abort_free_ctlr; + } + dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS, temp_word); + + /* Add this HPC instance into the HPC list */ + spin_lock(&list_lock); + if (php_ctlr_list_head == 0) { + php_ctlr_list_head = php_ctlr; + p = php_ctlr_list_head; + p->pnext = 0; + } else { + p = php_ctlr_list_head; + + while (p->pnext) + p = p->pnext; + + p->pnext = php_ctlr; + } + spin_unlock(&list_lock); + + ctlr_seq_num++; + ctrl->hpc_ctlr_handle = php_ctlr; + ctrl->hpc_ops = &pciehp_hpc_ops; + + DBG_LEAVE_ROUTINE + return 0; + + /* We end up here for the many possible ways to fail this API. */ +abort_free_ctlr: + pcie_cap_base = saved_cap_base; + kfree(php_ctlr); +abort: + DBG_LEAVE_ROUTINE + return -1; +} diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/pciehp_pci.c linux-2.4.27-pre5/drivers/hotplug/pciehp_pci.c --- linux-2.4.26/drivers/hotplug/pciehp_pci.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/pciehp_pci.c 2004-06-03 01:34:54.000000000 +0000 @@ -0,0 +1,1052 @@ +/* + * 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 "pciehp.h" +#ifndef CONFIG_IA64 +#include "../../arch/i386/kernel/pci-i386.h" /* horrible hack showing how processor dependant we are... */ +#endif + +static int is_pci_dev_in_use(struct pci_dev* dev) +{ + /* + * dev->driver will be set if the device is in use by a new-style + * driver -- otherwise, check the device's regions to see if any + * driver has claimed them + */ + + int i, inuse=0; + + if (dev->driver) return 1; /* Assume driver feels responsible */ + + for (i = 0; !dev->driver && !inuse && (i < 6); i++) { + if (!pci_resource_start(dev, i)) + continue; + + if (pci_resource_flags(dev, i) & IORESOURCE_IO) + inuse = check_region(pci_resource_start(dev, i), + pci_resource_len(dev, i)); + else if (pci_resource_flags(dev, i) & IORESOURCE_MEM) + inuse = check_mem_region(pci_resource_start(dev, i), + pci_resource_len(dev, i)); + } + + return inuse; + +} + + +static int pci_hp_remove_device(struct pci_dev *dev) +{ + if (is_pci_dev_in_use(dev)) { + err("***Cannot safely power down device -- " + "it appears to be in use***\n"); + return -EBUSY; + } + dbg("%s: dev %p\n", __FUNCTION__, dev); + pci_remove_device(dev); + return 0; +} + + +static int configure_visit_pci_dev (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) +{ + struct pci_bus* bus = wrapped_bus->bus; + struct pci_dev* dev = wrapped_dev->dev; + struct pci_func *temp_func; + int i=0; + + /* We need to fix up the hotplug function representation with the linux representation */ + do { + temp_func = pciehp_slot_find(dev->bus->number, dev->devfn >> 3, i++); + } while (temp_func && (temp_func->function != (dev->devfn & 0x07))); + + if (temp_func) { + temp_func->pci_dev = dev; + } else { + /* We did not even find a hotplug rep of the function, create it + * This code might be taken out if we can guarantee the creation of functions + * in parallel (hotplug and Linux at the same time). + */ + dbg("@@@@@@@@@@@ pciehp_slot_create in %s\n", __FUNCTION__); + temp_func = pciehp_slot_create(bus->number); + if (temp_func == NULL) + return -ENOMEM; + temp_func->pci_dev = dev; + } + + /* Create /proc/bus/pci proc entry for this device and bus device is on */ + /* Notify the drivers of the change */ + if (temp_func->pci_dev) { + dbg("%s: PCI_ID=%04X:%04X\n", __FUNCTION__, temp_func->pci_dev->vendor, + temp_func->pci_dev->device); + dbg("%s: PCI BUS %x DEVFN %x\n", __FUNCTION__, + temp_func->pci_dev->bus->number, temp_func->pci_dev->devfn); + dbg("%s: PCI_SLOT_NAME=%s\n", __FUNCTION__, + temp_func->pci_dev->slot_name); + //pci_enable_device(temp_func->pci_dev); + //dbg("%s: after calling pci_enable_device, irq = %x\n", + // __FUNCTION__, temp_func->pci_dev->irq); + pci_proc_attach_device(temp_func->pci_dev); + pci_announce_device_to_drivers(temp_func->pci_dev); + } + + return 0; +} + + +static int unconfigure_visit_pci_dev_phase2 (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) +{ + struct pci_dev* dev = wrapped_dev->dev; + + struct pci_func *temp_func; + int i=0; + + dbg("%s: dev %p dev->bus->number %x bus->number %x\n", __FUNCTION__, wrapped_dev, + dev->bus->number, wrapped_bus->bus->number); + + /* We need to remove the hotplug function representation with the linux representation */ + do { + temp_func = pciehp_slot_find(dev->bus->number, dev->devfn >> 3, i++); + if (temp_func) { + dbg("%s: temp_func->function = %d\n", __FUNCTION__, temp_func->function); + } + } while (temp_func && (temp_func->function != (dev->devfn & 0x07))); + + /* Now, remove the Linux Representation */ + if (dev) { + if (pci_hp_remove_device(dev) == 0) { + kfree(dev); /* Now, remove */ + } else { + return -1; /* problems while freeing, abort visitation */ + } + } + + if (temp_func) { + temp_func->pci_dev = NULL; + } else { + dbg("No pci_func representation for bus, devfn = %d, %x\n", dev->bus->number, dev->devfn); + } + + return 0; +} + + +static int unconfigure_visit_pci_bus_phase2 (struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_dev) +{ + struct pci_bus* bus = wrapped_bus->bus; + + /* The cleanup code for proc entries regarding buses should be in the kernel...*/ + if (bus->procdir) + dbg("detach_pci_bus %s\n", bus->procdir->name); + pci_proc_detach_bus(bus); + /* The cleanup code should live in the kernel... */ + bus->self->subordinate = NULL; + /* unlink from parent bus */ + list_del(&bus->node); + + /* Now, remove */ + if (bus) + kfree(bus); + + return 0; +} + + +static int unconfigure_visit_pci_dev_phase1 (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) +{ + struct pci_dev* dev = wrapped_dev->dev; + int rc; + + dbg("attempting removal of driver for device (%x, %x, %x)\n", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + /* Now, remove the Linux Driver Representation */ + if (dev->driver) { + if (dev->driver->remove) { + dev->driver->remove(dev); + dbg("driver was properly removed\n"); + } + dev->driver = NULL; + } + + rc = is_pci_dev_in_use(dev); + if (rc) + info("%s: device still in use\n", __FUNCTION__); + return rc; +} + + +static struct pci_visit configure_functions = { + .visit_pci_dev = configure_visit_pci_dev, +}; + + +static struct pci_visit unconfigure_functions_phase1 = { + .post_visit_pci_dev = unconfigure_visit_pci_dev_phase1 +}; + +static struct pci_visit unconfigure_functions_phase2 = { + .post_visit_pci_bus = unconfigure_visit_pci_bus_phase2, + .post_visit_pci_dev = unconfigure_visit_pci_dev_phase2 +}; + + +int pciehp_configure_device (struct controller* ctrl, struct pci_func* func) +{ + unsigned char bus; + struct pci_dev dev0; + struct pci_bus *child; + struct pci_dev* temp; + int rc = 0; + + struct pci_dev_wrapped wrapped_dev; + struct pci_bus_wrapped wrapped_bus; + memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped)); + memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped)); + + memset(&dev0, 0, sizeof(struct pci_dev)); + + dbg("%s: func->pci_dev %p bus %x dev %x func %x\n", __FUNCTION__, + func->pci_dev, func->bus, func->device, func->function); + if (func->pci_dev == NULL) + func->pci_dev = pci_find_slot(func->bus, (func->device << 3) | (func->function & 0x7)); + dbg("%s: func->pci_dev %p bus %x dev %x func %x\n", __FUNCTION__, + func->pci_dev, func->bus, func->device, func->function); + if (func->pci_dev != NULL) { + dbg("%s: pci_dev %p bus %x devfn %x\n", __FUNCTION__, + func->pci_dev, func->pci_dev->bus->number, func->pci_dev->devfn); + } + /* Still NULL ? Well then scan for it ! */ + if (func->pci_dev == NULL) { + dbg("%s: pci_dev still null. do pci_scan_slot\n", __FUNCTION__); + dev0.bus = ctrl->pci_dev->subordinate; + dbg("%s: dev0.bus %p\n", __FUNCTION__, dev0.bus); + dev0.bus->number = func->bus; + dbg("%s: dev0.bus->number %x\n", __FUNCTION__, func->bus); + dev0.devfn = PCI_DEVFN(func->device, func->function); + dev0.sysdata = ctrl->pci_dev->sysdata; + + /* This will generate pci_dev structures for all functions, + * but we will only call this case when lookup fails + */ + func->pci_dev = pci_scan_slot(&dev0); + dbg("%s: func->pci_dev %p\n", __FUNCTION__, func->pci_dev); + if (func->pci_dev == NULL) { + dbg("ERROR: pci_dev still null\n"); + return 0; + } + } + + if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus); + child = (struct pci_bus*) pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus); + dbg("%s: bridge device - func->pci_dev->bus %p func->pci_dev %p bus %x\n", + __FUNCTION__, func->pci_dev->bus,func->pci_dev,bus); + pci_do_scan_bus(child); + + } + + temp = func->pci_dev; + + if (temp) { + wrapped_dev.dev = temp; + wrapped_bus.bus = temp->bus; + rc = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus); + } + return rc; +} + + +int pciehp_unconfigure_device(struct pci_func* func) +{ + int rc = 0; + int j; + struct pci_dev_wrapped wrapped_dev; + struct pci_bus_wrapped wrapped_bus; + + memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped)); + memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped)); + + dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus, func->device, func->function); + + for (j=0; j<8 ; j++) { + struct pci_dev* temp = pci_find_slot(func->bus, (func->device << 3) | j); + dbg("%s: temp %p\n", __FUNCTION__, temp); + if (temp) { + wrapped_dev.dev = temp; + wrapped_bus.bus = temp->bus; + rc = pci_visit_dev(&unconfigure_functions_phase1, &wrapped_dev, &wrapped_bus); + if (rc) + break; + + rc = pci_visit_dev(&unconfigure_functions_phase2, &wrapped_dev, &wrapped_bus); + if (rc) + break; + } + } + return rc; +} + +/* + * pciehp_set_irq + * + * @bus_num: bus number of PCI device + * @dev_num: device number of PCI device + * @slot: pointer to u8 where slot number will be returned + */ +int pciehp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) +{ +#if defined(CONFIG_X86) && !defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64) + int rc; + u16 temp_word; + struct pci_dev fakedev; + struct pci_bus fakebus; + + fakedev.devfn = dev_num << 3; + fakedev.bus = &fakebus; + fakebus.number = bus_num; + dbg("%s: dev %d, bus %d, pin %d, num %d\n", + __FUNCTION__, dev_num, bus_num, int_pin, irq_num); + rc = pcibios_set_irq_routing(&fakedev, int_pin - 0x0a, irq_num); + dbg("%s: rc %d\n", __FUNCTION__, rc); + if (!rc) + return !rc; + + /* set the Edge Level Control Register (ELCR) */ + temp_word = inb(0x4d0); + temp_word |= inb(0x4d1) << 8; + + temp_word |= 0x01 << irq_num; + + /* This should only be for x86 as it sets the Edge Level Control Register */ + outb((u8) (temp_word & 0xFF), 0x4d0); + outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1); +#endif + return 0; +} + +/* More PCI configuration routines; this time centered around hotplug controller */ + + +/* + * pciehp_save_config + * + * Reads configuration for all slots in a PCI bus and saves info. + * + * Note: For non-hot plug busses, the slot # saved is the device # + * + * returns 0 if success + */ +int pciehp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num) +{ + int rc; + u8 class_code; + u8 header_type; + u32 ID; + u8 secondary_bus; + struct pci_func *new_slot; + int sub_bus; + int max_functions; + int function; + u8 DevError; + int device = 0; + int cloop = 0; + int stop_it; + int index; + int is_hot_plug = num_ctlr_slots || first_device_num; + struct pci_bus lpci_bus, *pci_bus; + int FirstSupported, LastSupported; + + dbg("%s: Enter\n", __FUNCTION__); + + memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); + pci_bus = &lpci_bus; + + dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__, num_ctlr_slots, + first_device_num); + + /* Decide which slots are supported */ + if (is_hot_plug) { + /********************************* + * is_hot_plug is the slot mask + *********************************/ + FirstSupported = first_device_num; + LastSupported = FirstSupported + num_ctlr_slots - 1; + } else { + FirstSupported = 0; + LastSupported = 0x1F; + } + + dbg("FirstSupported = %d, LastSupported = %d\n", FirstSupported, LastSupported); + + /* Save PCI configuration space for all devices in supported slots */ + dbg("%s: pci_bus->number = %x\n", __FUNCTION__, pci_bus->number); + pci_bus->number = busnumber; + dbg("%s: bus = %x, dev = %x\n", __FUNCTION__, busnumber, device); + for (device = FirstSupported; device <= LastSupported; device++) { + ID = 0xFFFFFFFF; + rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID); + /* dbg("%s: ID = %x\n", __FUNCTION__, ID);*/ + + if (ID != 0xFFFFFFFF) { /* device in slot */ + dbg("%s: ID = %x\n", __FUNCTION__, ID); + rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code); + if (rc) + return rc; + + rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, + &header_type); + if (rc) + return rc; + + dbg("class_code = %x, header_type = %x\n", class_code, header_type); + + /* If multi-function device, set max_functions to 8 */ + if (header_type & 0x80) + max_functions = 8; + else + max_functions = 1; + + function = 0; + + do { + DevError = 0; + dbg("%s: In do loop\n", __FUNCTION__); + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* P-P Bridge */ + /* Recurse the subordinate bus + * get the subordinate bus number + */ + rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, function), + PCI_SECONDARY_BUS, &secondary_bus); + if (rc) { + return rc; + } else { + sub_bus = (int) secondary_bus; + + /* Save secondary bus cfg spc with this recursive call. */ + rc = pciehp_save_config(ctrl, sub_bus, 0, 0); + if (rc) + return rc; + } + } + + index = 0; + new_slot = pciehp_slot_find(busnumber, device, index++); + + dbg("%s: new_slot = %p bus %x dev %x fun %x\n", + __FUNCTION__, new_slot, busnumber, device, index-1); + + while (new_slot && (new_slot->function != (u8) function)) { + new_slot = pciehp_slot_find(busnumber, device, index++); + dbg("%s: while loop, new_slot = %p bus %x dev %x fun %x\n", + __FUNCTION__, new_slot, busnumber, device, index-1); + } + if (!new_slot) { + /* Setup slot structure. */ + new_slot = pciehp_slot_create(busnumber); + dbg("%s: if, new_slot = %p bus %x dev %x fun %x\n", + __FUNCTION__, new_slot, busnumber, device, function); + + if (new_slot == NULL) + return(1); + } + + new_slot->bus = (u8) busnumber; + new_slot->device = (u8) device; + new_slot->function = (u8) function; + new_slot->is_a_board = 1; + new_slot->switch_save = 0x10; + /* In case of unsupported board */ + new_slot->status = DevError; + new_slot->pci_dev = pci_find_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function); + dbg("new_slot->pci_dev = %p\n", new_slot->pci_dev); + + for (cloop = 0; cloop < 0x20; cloop++) { + rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot->config_space [cloop])); + /* dbg("new_slot->config_space[%x] = %x\n", cloop, new_slot->config_space[cloop]); */ + if (rc) + return rc; + } + + function++; + + stop_it = 0; + + /* This loop skips to the next present function + * reading in Class Code and Header type. + */ + + while ((function < max_functions)&&(!stop_it)) { + dbg("%s: In while loop \n", __FUNCTION__); + rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID); + + if (ID == 0xFFFFFFFF) { /* Nothing there. */ + function++; + dbg("Nothing there\n"); + } else { /* Something there */ + rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code); + if (rc) + return rc; + + rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; + + dbg("class_code = %x, header_type = %x\n", class_code, header_type); + stop_it++; + } + } + + } while (function < max_functions); + } /* End of IF (device in slot?) */ + else if (is_hot_plug) { + /* Setup slot structure with entry for empty slot */ + new_slot = pciehp_slot_create(busnumber); + + if (new_slot == NULL) { + return(1); + } + dbg("new_slot = %p, bus = %x, dev = %x, fun = %x\n", new_slot, + new_slot->bus, new_slot->device, new_slot->function); + + new_slot->bus = (u8) busnumber; + new_slot->device = (u8) device; + new_slot->function = 0; + new_slot->is_a_board = 0; + new_slot->presence_save = 0; + new_slot->switch_save = 0; + } + /* dbg("%s: End of For loop\n", __FUNCTION__); */ + } /* End of FOR loop */ + + dbg("%s: Exit\n", __FUNCTION__); + return(0); +} + + +/* + * pciehp_save_slot_config + * + * Saves configuration info for all PCI devices in a given slot + * including subordinate busses. + * + * returns 0 if success + */ +int pciehp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) +{ + int rc; + u8 class_code; + u8 header_type; + u32 ID; + u8 secondary_bus; + int sub_bus; + int max_functions; + int function; + int cloop = 0; + int stop_it; + struct pci_bus lpci_bus, *pci_bus; + + memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); + pci_bus = &lpci_bus; + pci_bus->number = new_slot->bus; + + ID = 0xFFFFFFFF; + + pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_VENDOR_ID, &ID); + + if (ID != 0xFFFFFFFF) { /* Device in slot */ + pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code); + + pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type); + + if (header_type & 0x80) /* Multi-function device */ + max_functions = 8; + else + max_functions = 1; + + function = 0; + + do { + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */ + /* Recurse the subordinate bus */ + pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus); + + sub_bus = (int) secondary_bus; + + /* Save the config headers for the secondary bus. */ + rc = pciehp_save_config(ctrl, sub_bus, 0, 0); + + if (rc) + return(rc); + + } /* End of IF */ + + new_slot->status = 0; + + for (cloop = 0; cloop < 0x20; cloop++) { + pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot->config_space [cloop])); + } + + function++; + + stop_it = 0; + + /* this loop skips to the next present function + * reading in the Class Code and the Header type. + */ + + while ((function < max_functions) && (!stop_it)) { + pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID); + + if (ID == 0xFFFFFFFF) { /* Nothing there. */ + function++; + } else { /* Something there */ + pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code); + + pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type); + + stop_it++; + } + } + + } while (function < max_functions); + } /* End of IF (device in slot?) */ + else { + return(2); + } + + return(0); +} + + +/* + * pciehp_save_used_resources + * + * Stores used resource information for existing boards. this is + * for boards that were in the system when this driver was loaded. + * this function is for hot plug ADD + * + * returns 0 if success + * if disable == 1(DISABLE_CARD), + * it loops for all functions of the slot and disables them. + * else, it just get resources of the function and return. + */ +int pciehp_save_used_resources (struct controller *ctrl, struct pci_func *func, int disable) +{ + u8 cloop; + u8 header_type; + u8 secondary_bus; + u8 temp_byte; + u16 command; + u16 save_command; + u16 w_base, w_length; + u32 temp_register; + u32 save_base; + u32 base, length; + u64 base64 = 0; + int index = 0; + unsigned int devfn; + struct pci_resource *mem_node = NULL; + struct pci_resource *p_mem_node = NULL; + struct pci_resource *t_mem_node; + struct pci_resource *io_node; + struct pci_resource *bus_node; + struct pci_bus lpci_bus, *pci_bus; + + memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); + pci_bus = &lpci_bus; + + if (disable) + func = pciehp_slot_find(func->bus, func->device, index++); + + while ((func != NULL) && func->is_a_board) { + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + /* Save the command register */ + pci_bus_read_config_word (pci_bus, devfn, PCI_COMMAND, &save_command); + + if (disable) { + /* Disable card */ + command = 0x00; + pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); + } + + /* Check for Bridge */ + pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */ + dbg("Save_used_res of PCI bridge b:d=0x%x:%x, sc=0x%x\n", func->bus, func->device, save_command); + if (disable) { + /* Clear Bridge Control Register */ + command = 0x00; + pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command); + } + + pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); + pci_bus_read_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte); + + bus_node =(struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!bus_node) + return -ENOMEM; + + bus_node->base = (ulong)secondary_bus; + bus_node->length = (ulong)(temp_byte - secondary_bus + 1); + + bus_node->next = func->bus_head; + func->bus_head = bus_node; + + /* Save IO base and Limit registers */ + pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_BASE, &temp_byte); + base = temp_byte; + pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_LIMIT, &temp_byte); + length = temp_byte; + + if ((base <= length) && (!disable || (save_command & PCI_COMMAND_IO))) { + io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!io_node) + return -ENOMEM; + + io_node->base = (ulong)(base & PCI_IO_RANGE_MASK) << 8; + io_node->length = (ulong)(length - base + 0x10) << 8; + + io_node->next = func->io_head; + func->io_head = io_node; + } + + /* Save memory base and Limit registers */ + pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_BASE, &w_base); + pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length); + + if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) { + mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!mem_node) + return -ENOMEM; + + mem_node->base = (ulong)w_base << 16; + mem_node->length = (ulong)(w_length - w_base + 0x10) << 16; + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } + /* Save prefetchable memory base and Limit registers */ + pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base); + pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length); + + if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) { + p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!p_mem_node) + return -ENOMEM; + + p_mem_node->base = (ulong)w_base << 16; + p_mem_node->length = (ulong)(w_length - w_base + 0x10) << 16; + + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } + } else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) { + dbg("Save_used_res of PCI adapter b:d=0x%x:%x, sc=0x%x\n", func->bus, func->device, save_command); + + /* Figure out IO and memory base lengths */ + for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) { + pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base); + + temp_register = 0xFFFFFFFF; + pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); + pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp_register); + + if (!disable) { + pci_bus_write_config_dword (pci_bus, devfn, cloop, save_base); + } + + if (!temp_register) + continue; + + base = temp_register; + + if ((base & PCI_BASE_ADDRESS_SPACE_IO) && (!disable || (save_command & PCI_COMMAND_IO))) { + /* IO base */ + /* Set temp_register = amount of IO space requested */ + base = base & 0xFFFFFFFCL; + base = (~base) + 1; + + io_node = (struct pci_resource *) kmalloc(sizeof (struct pci_resource), GFP_KERNEL); + if (!io_node) + return -ENOMEM; + + io_node->base = (ulong)save_base & PCI_BASE_ADDRESS_IO_MASK; + io_node->length = (ulong)base; + dbg("sur adapter: IO bar=0x%x(length=0x%x)\n", io_node->base, io_node->length); + + io_node->next = func->io_head; + func->io_head = io_node; + } else { /* Map Memory */ + int prefetchable = 1; + /* struct pci_resources **res_node; */ + char *res_type_str = "PMEM"; + u32 temp_register2; + + t_mem_node = (struct pci_resource *) kmalloc(sizeof (struct pci_resource), GFP_KERNEL); + if (!t_mem_node) + return -ENOMEM; + + if (!(base & PCI_BASE_ADDRESS_MEM_PREFETCH) && (!disable || (save_command & PCI_COMMAND_MEMORY))) { + prefetchable = 0; + mem_node = t_mem_node; + res_type_str++; + } else + p_mem_node = t_mem_node; + + base = base & 0xFFFFFFF0L; + base = (~base) + 1; + + switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) { + case PCI_BASE_ADDRESS_MEM_TYPE_32: + if (prefetchable) { + p_mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK; + p_mem_node->length = (ulong)base; + dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n", res_type_str, p_mem_node->base, p_mem_node->length); + + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } else { + mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK; + mem_node->length = (ulong)base; + dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n", res_type_str, mem_node->base, mem_node->length); + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } + break; + case PCI_BASE_ADDRESS_MEM_TYPE_64: + pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2); + base64 = temp_register2; + base64 = (base64 << 32) | save_base; + + if (temp_register2) { + dbg("sur adapter: 64 %s high dword of base64(0x%x:%x) masked to 0\n", res_type_str, temp_register2, (u32)base64); + base64 &= 0x00000000FFFFFFFFL; + } + + if (prefetchable) { + p_mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK; + p_mem_node->length = base; + dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n", res_type_str, p_mem_node->base, p_mem_node->length); + + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } else { + mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK; + mem_node->length = base; + dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n", res_type_str, mem_node->base, mem_node->length); + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } + cloop += 4; + break; + default: + dbg("asur: reserved BAR type=0x%x\n", temp_register); + break; + } + } + } /* End of base register loop */ + } else { /* Some other unknown header type */ + dbg("Save_used_res of PCI unknown type b:d=0x%x:%x. skip.\n", func->bus, func->device); + } + + /* Find the next device in this slot */ + if (!disable) + break; + func = pciehp_slot_find(func->bus, func->device, index++); + } + + return(0); +} + + +/* + * pciehp_return_board_resources + * + * this routine returns all resources allocated to a board to + * the available pool. + * + * returns 0 if success + */ +int pciehp_return_board_resources(struct pci_func * func, struct resource_lists * resources) +{ + int rc = 0; + struct pci_resource *node; + struct pci_resource *t_node; + dbg("%s\n", __FUNCTION__); + + if (!func) + return(1); + + node = func->io_head; + func->io_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->io_head), node); + node = t_node; + } + + node = func->mem_head; + func->mem_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->mem_head), node); + node = t_node; + } + + node = func->p_mem_head; + func->p_mem_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->p_mem_head), node); + node = t_node; + } + + node = func->bus_head; + func->bus_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->bus_head), node); + node = t_node; + } + + rc |= pciehp_resource_sort_and_combine(&(resources->mem_head)); + rc |= pciehp_resource_sort_and_combine(&(resources->p_mem_head)); + rc |= pciehp_resource_sort_and_combine(&(resources->io_head)); + rc |= pciehp_resource_sort_and_combine(&(resources->bus_head)); + + return(rc); +} + + +/* + * pciehp_destroy_resource_list + * + * Puts node back in the resource list pointed to by head + */ +void pciehp_destroy_resource_list (struct resource_lists * resources) +{ + struct pci_resource *res, *tres; + + res = resources->io_head; + resources->io_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = resources->mem_head; + resources->mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = resources->p_mem_head; + resources->p_mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = resources->bus_head; + resources->bus_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } +} + + +/* + * pciehp_destroy_board_resources + * + * Puts node back in the resource list pointed to by head + */ +void pciehp_destroy_board_resources (struct pci_func * func) +{ + struct pci_resource *res, *tres; + + res = func->io_head; + func->io_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = func->mem_head; + func->mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = func->p_mem_head; + func->p_mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = func->bus_head; + func->bus_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } +} + diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/pciehprm.h linux-2.4.27-pre5/drivers/hotplug/pciehprm.h --- linux-2.4.26/drivers/hotplug/pciehprm.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/pciehprm.h 2004-06-03 01:34:32.000000000 +0000 @@ -0,0 +1,54 @@ +/* + * PCIEHPRM : PCIEHP Resource Manager for ACPI/non-ACPI platform + * + * Copyright (C) 1995,2001 Compaq Computer Corporation + * Copyright (C) 2001,2003 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 _PCIEHPRM_H_ +#define _PCIEHPRM_H_ + +#ifdef CONFIG_HOTPLUG_PCI_PCIE_PHPRM_NONACPI +#include "pciehprm_nonacpi.h" +#endif + +int pciehprm_init(enum php_ctlr_type ct); +void pciehprm_cleanup(void); +int pciehprm_print_pirt(void); +void *pciehprm_get_slot(struct slot *slot); +int pciehprm_find_available_resources(struct controller *ctrl); +int pciehprm_set_hpp(struct controller *ctrl, struct pci_func *func, u8 card_type); +void pciehprm_enable_card(struct controller *ctrl, struct pci_func *func, u8 card_type); +int pciehprm_get_interrupt(int seg, int bus, int device, int pin, int *irq); + +#ifdef DEBUG +#define RES_CHECK(this, bits) \ + { if (((this) & (bits - 1))) \ + printk("%s:%d ERR: potential res loss!\n", __FUNCTION__, __LINE__); } +#else +#define RES_CHECK(this, bits) +#endif + +#endif /* _PCIEHPRM_H_ */ diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/pciehprm_acpi.c linux-2.4.27-pre5/drivers/hotplug/pciehprm_acpi.c --- linux-2.4.26/drivers/hotplug/pciehprm_acpi.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/pciehprm_acpi.c 2004-06-03 01:35:48.000000000 +0000 @@ -0,0 +1,1696 @@ +/* + * PCIEHPRM ACPI: PHP Resource Manager for ACPI platform + * + * 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 +#ifdef CONFIG_IA64 +#include +#endif +#include +#include +#include +#include "pciehp.h" +#include "pciehprm.h" + +#define PCI_MAX_BUS 0x100 +#define ACPI_STA_DEVICE_PRESENT 0x01 + +#define METHOD_NAME__SUN "_SUN" +#define METHOD_NAME__HPP "_HPP" +#define METHOD_NAME_OSHP "OSHP" + +#define PHP_RES_BUS 0xA0 +#define PHP_RES_IO 0xA1 +#define PHP_RES_MEM 0xA2 +#define PHP_RES_PMEM 0xA3 + +#define BRIDGE_TYPE_P2P 0x00 +#define BRIDGE_TYPE_HOST 0x01 + +/* this should go to drivers/acpi/include/ */ +struct acpi__hpp { + u8 cache_line_size; + u8 latency_timer; + u8 enable_serr; + u8 enable_perr; +}; + +struct acpi_php_slot { + struct acpi_php_slot *next; + struct acpi_bridge *bridge; + acpi_handle handle; + int seg; + int bus; + int dev; + int fun; + u32 sun; + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; + void *slot_ops; /* _STA, _EJx, etc */ + struct slot *slot; +}; /* per func */ + +struct acpi_bridge { + struct acpi_bridge *parent; + struct acpi_bridge *next; + struct acpi_bridge *child; + acpi_handle handle; + int seg; + int pbus; /* pdev->bus->number */ + int pdevice; /* PCI_SLOT(pdev->devfn) */ + int pfunction; /* PCI_DEVFN(pdev->devfn) */ + int bus; /* pdev->subordinate->number */ + struct acpi__hpp *_hpp; + struct acpi_php_slot *slots; + struct pci_resource *tmem_head; /* total from crs */ + struct pci_resource *tp_mem_head; /* total from crs */ + struct pci_resource *tio_head; /* total from crs */ + struct pci_resource *tbus_head; /* total from crs */ + struct pci_resource *mem_head; /* available */ + struct pci_resource *p_mem_head; /* available */ + struct pci_resource *io_head; /* available */ + struct pci_resource *bus_head; /* available */ + int scanned; + int type; +}; + +static struct acpi_bridge *acpi_bridges_head; + +static u8 * acpi_path_name( acpi_handle handle) +{ + acpi_status status; + static u8 path_name[ACPI_PATHNAME_MAX]; + struct acpi_buffer ret_buf = { ACPI_PATHNAME_MAX, path_name }; + + memset(path_name, 0, sizeof (path_name)); + status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &ret_buf); + + if (ACPI_FAILURE(status)) + return NULL; + else + return path_name; +} + +static void acpi_get__hpp ( struct acpi_bridge *ab); +static void acpi_run_oshp ( struct acpi_bridge *ab); + +static int acpi_add_slot_to_php_slots( + struct acpi_bridge *ab, + int bus_num, + acpi_handle handle, + u32 adr, + u32 sun + ) +{ + struct acpi_php_slot *aps; + static long samesun = -1; + + aps = (struct acpi_php_slot *) kmalloc (sizeof(struct acpi_php_slot), GFP_KERNEL); + if (!aps) { + err ("acpi_pciehprm: alloc for aps fail\n"); + return -1; + } + memset(aps, 0, sizeof(struct acpi_php_slot)); + + aps->handle = handle; + aps->bus = bus_num; + aps->dev = (adr >> 16) & 0xffff; + aps->fun = adr & 0xffff; + aps->sun = sun; + + aps->next = ab->slots; /* cling to the bridge */ + aps->bridge = ab; + ab->slots = aps; + + ab->scanned += 1; + if (!ab->_hpp) + acpi_get__hpp(ab); + + acpi_run_oshp(ab); + if (sun != samesun) { + info("acpi_pciehprm: Slot sun(%x) at s:b:d:f=0x%02x:%02x:%02x:%02x\n", + aps->sun, ab->seg, aps->bus, aps->dev, aps->fun); + samesun = sun; + } + return 0; +} + +static void acpi_get__hpp ( struct acpi_bridge *ab) +{ + acpi_status status; + u8 nui[4]; + struct acpi_buffer ret_buf = { 0, NULL}; + union acpi_object *ext_obj, *package; + u8 *path_name = acpi_path_name(ab->handle); + int i, len = 0; + + /* Get _hpp */ + status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf); + switch (status) { + case AE_BUFFER_OVERFLOW: + ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL); + if (!ret_buf.pointer) { + err ("acpi_pciehprm:%s alloc for _HPP fail\n", path_name); + return; + } + status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf); + if (ACPI_SUCCESS(status)) + break; + default: + if (ACPI_FAILURE(status)) { + err("acpi_pciehprm:%s _HPP fail=0x%x\n", path_name, status); + return; + } + } + + ext_obj = (union acpi_object *) ret_buf.pointer; + if (ext_obj->type != ACPI_TYPE_PACKAGE) { + err ("acpi_pciehprm:%s _HPP obj not a package\n", path_name); + goto free_and_return; + } + + len = ext_obj->package.count; + package = (union acpi_object *) ret_buf.pointer; + for ( i = 0; (i < len) || (i < 4); i++) { + ext_obj = (union acpi_object *) &package->package.elements[i]; + switch (ext_obj->type) { + case ACPI_TYPE_INTEGER: + nui[i] = (u8)ext_obj->integer.value; + break; + default: + err ("acpi_pciehprm:%s _HPP obj type incorrect\n", path_name); + goto free_and_return; + } + } + + ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL); + memset(ab->_hpp, 0, sizeof(struct acpi__hpp)); + + ab->_hpp->cache_line_size = nui[0]; + ab->_hpp->latency_timer = nui[1]; + ab->_hpp->enable_serr = nui[2]; + ab->_hpp->enable_perr = nui[3]; + + dbg(" _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size); + dbg(" _HPP: latency timer =0x%x\n", ab->_hpp->latency_timer); + dbg(" _HPP: enable SERR =0x%x\n", ab->_hpp->enable_serr); + dbg(" _HPP: enable PERR =0x%x\n", ab->_hpp->enable_perr); + +free_and_return: + kfree(ret_buf.pointer); +} +static void acpi_run_oshp ( struct acpi_bridge *ab) +{ + acpi_status status; + u8 *path_name = acpi_path_name(ab->handle); + struct acpi_buffer ret_buf = { 0, NULL}; + + /* Run OSHP */ + status = acpi_evaluate_object(ab->handle, METHOD_NAME_OSHP, NULL, &ret_buf); + if (ACPI_FAILURE(status)) { + err("acpi_pciehprm:%s OSHP fails=0x%x\n", path_name, status); + } else + dbg("acpi_pciehprm:%s OSHP passes =0x%x\n", path_name, status); + return; +} + +static acpi_status acpi_evaluate_crs( + acpi_handle handle, + struct acpi_resource **retbuf + ) +{ + acpi_status status; + struct acpi_buffer crsbuf; + u8 *path_name = acpi_path_name(handle); + + crsbuf.length = 0; + crsbuf.pointer = NULL; + + status = acpi_get_current_resources (handle, &crsbuf); + + switch (status) { + case AE_BUFFER_OVERFLOW: + break; /* Found */ + case AE_NOT_FOUND: + dbg("acpi_pciehprm:%s _CRS not found\n", path_name); + return status; + default: + err ("acpi_pciehprm:%s _CRS fail=0x%x\n", path_name, status); + return status; + } + + crsbuf.pointer = kmalloc (crsbuf.length, GFP_KERNEL); + if (!crsbuf.pointer) { + err ("acpi_pciehprm: alloc %ld bytes for %s _CRS fail\n", (ulong)crsbuf.length, path_name); + return AE_NO_MEMORY; + } + + status = acpi_get_current_resources (handle, &crsbuf); + if (ACPI_FAILURE(status)) { + err("acpi_pciehprm: %s _CRS fail=0x%x.\n", path_name, status); + kfree(crsbuf.pointer); + return status; + } + + *retbuf = crsbuf.pointer; + + return status; +} + +static void free_pci_resource ( struct pci_resource *aprh) +{ + struct pci_resource *res, *next; + + for (res = aprh; res; res = next) { + next = res->next; + kfree(res); + } +} + +static void print_pci_resource ( struct pci_resource *aprh) +{ + struct pci_resource *res; + + for (res = aprh; res; res = res->next) + dbg(" base= 0x%x length= 0x%x\n", res->base, res->length); +} + +static void print_slot_resources( struct acpi_php_slot *aps) +{ + if (aps->bus_head) { + dbg(" BUS Resources:\n"); + print_pci_resource (aps->bus_head); + } + + if (aps->io_head) { + dbg(" IO Resources:\n"); + print_pci_resource (aps->io_head); + } + + if (aps->mem_head) { + dbg(" MEM Resources:\n"); + print_pci_resource (aps->mem_head); + } + + if (aps->p_mem_head) { + dbg(" PMEM Resources:\n"); + print_pci_resource (aps->p_mem_head); + } +} + +static void print_pci_resources( struct acpi_bridge *ab) +{ + if (ab->tbus_head) { + dbg(" Total BUS Resources:\n"); + print_pci_resource (ab->tbus_head); + } + if (ab->bus_head) { + dbg(" BUS Resources:\n"); + print_pci_resource (ab->bus_head); + } + + if (ab->tio_head) { + dbg(" Total IO Resources:\n"); + print_pci_resource (ab->tio_head); + } + if (ab->io_head) { + dbg(" IO Resources:\n"); + print_pci_resource (ab->io_head); + } + + if (ab->tmem_head) { + dbg(" Total MEM Resources:\n"); + print_pci_resource (ab->tmem_head); + } + if (ab->mem_head) { + dbg(" MEM Resources:\n"); + print_pci_resource (ab->mem_head); + } + + if (ab->tp_mem_head) { + dbg(" Total PMEM Resources:\n"); + print_pci_resource (ab->tp_mem_head); + } + if (ab->p_mem_head) { + dbg(" PMEM Resources:\n"); + print_pci_resource (ab->p_mem_head); + } + if (ab->_hpp) { + dbg(" _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size); + dbg(" _HPP: latency timer =0x%x\n", ab->_hpp->latency_timer); + dbg(" _HPP: enable SERR =0x%x\n", ab->_hpp->enable_serr); + dbg(" _HPP: enable PERR =0x%x\n", ab->_hpp->enable_perr); + } +} + +static int pciehprm_delete_resource( + struct pci_resource **aprh, + ulong base, + ulong size) +{ + struct pci_resource *res; + struct pci_resource *prevnode; + struct pci_resource *split_node; + ulong tbase; + + pciehp_resource_sort_and_combine(aprh); + + for (res = *aprh; res; res = res->next) { + if (res->base > base) + continue; + + if ((res->base + res->length) < (base + size)) + continue; + + if (res->base < base) { + tbase = base; + + if ((res->length - (tbase - res->base)) < size) + continue; + + split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!split_node) + return -ENOMEM; + + split_node->base = res->base; + split_node->length = tbase - res->base; + res->base = tbase; + res->length -= split_node->length; + + split_node->next = res->next; + res->next = split_node; + } + + if (res->length >= size) { + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!split_node) + return -ENOMEM; + + split_node->base = res->base + size; + split_node->length = res->length - size; + res->length = size; + + split_node->next = res->next; + res->next = split_node; + } + + if (*aprh == res) { + *aprh = res->next; + } else { + prevnode = *aprh; + while (prevnode->next != res) + prevnode = prevnode->next; + + prevnode->next = res->next; + } + res->next = NULL; + kfree(res); + break; + } + + return 0; +} + +static int pciehprm_delete_resources( + struct pci_resource **aprh, + struct pci_resource *this + ) +{ + struct pci_resource *res; + + for (res = this; res; res = res->next) + pciehprm_delete_resource(aprh, res->base, res->length); + + return 0; +} + +static int pciehprm_add_resource( + struct pci_resource **aprh, + ulong base, + ulong size) +{ + struct pci_resource *res; + + for (res = *aprh; res; res = res->next) { + if ((res->base + res->length) == base) { + res->length += size; + size = 0L; + break; + } + if (res->next == *aprh) + break; + } + + if (size) { + res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!res) { + err ("acpi_pciehprm: alloc for res fail\n"); + return -ENOMEM; + } + memset(res, 0, sizeof (struct pci_resource)); + + res->base = base; + res->length = size; + res->next = *aprh; + *aprh = res; + } + + return 0; +} + +static int pciehprm_add_resources( + struct pci_resource **aprh, + struct pci_resource *this + ) +{ + struct pci_resource *res; + int rc = 0; + + for (res = this; res && !rc; res = res->next) + rc = pciehprm_add_resource(aprh, res->base, res->length); + + return rc; +} + +static void acpi_parse_io ( + struct acpi_bridge *ab, + union acpi_resource_data *data + ) +{ + struct acpi_resource_io *dataio; + dataio = (struct acpi_resource_io *) data; + + dbg("Io Resource\n"); + dbg(" %d bit decode\n", ACPI_DECODE_16 == dataio->io_decode ? 16:10); + dbg(" Range minimum base: %08X\n", dataio->min_base_address); + dbg(" Range maximum base: %08X\n", dataio->max_base_address); + dbg(" Alignment: %08X\n", dataio->alignment); + dbg(" Range Length: %08X\n", dataio->range_length); +} + +static void acpi_parse_fixed_io ( + struct acpi_bridge *ab, + union acpi_resource_data *data + ) +{ + struct acpi_resource_fixed_io *datafio; + datafio = (struct acpi_resource_fixed_io *) data; + + dbg("Fixed Io Resource\n"); + dbg(" Range base address: %08X", datafio->base_address); + dbg(" Range length: %08X", datafio->range_length); +} + +static void acpi_parse_address16_32 ( + struct acpi_bridge *ab, + union acpi_resource_data *data, + acpi_resource_type id + ) +{ + /* + * acpi_resource_address16 == acpi_resource_address32 + * acpi_resource_address16 *data16 = (acpi_resource_address16 *) data; + */ + struct acpi_resource_address32 *data32 = (struct acpi_resource_address32 *) data; + struct pci_resource **aprh, **tprh; + + if (id == ACPI_RSTYPE_ADDRESS16) + dbg("acpi_pciehprm:16-Bit Address Space Resource\n"); + else + dbg("acpi_pciehprm:32-Bit Address Space Resource\n"); + + switch (data32->resource_type) { + case ACPI_MEMORY_RANGE: + dbg(" Resource Type: Memory Range\n"); + aprh = &ab->mem_head; + tprh = &ab->tmem_head; + + switch (data32->attribute.memory.cache_attribute) { + case ACPI_NON_CACHEABLE_MEMORY: + dbg(" Type Specific: Noncacheable memory\n"); + break; + case ACPI_CACHABLE_MEMORY: + dbg(" Type Specific: Cacheable memory\n"); + break; + case ACPI_WRITE_COMBINING_MEMORY: + dbg(" Type Specific: Write-combining memory\n"); + break; + case ACPI_PREFETCHABLE_MEMORY: + aprh = &ab->p_mem_head; + dbg(" Type Specific: Prefetchable memory\n"); + break; + default: + dbg(" Type Specific: Invalid cache attribute\n"); + break; + } + + dbg(" Type Specific: Read%s\n", ACPI_READ_WRITE_MEMORY == data32->attribute.memory.read_write_attribute ? "/Write":" Only"); + break; + + case ACPI_IO_RANGE: + dbg(" Resource Type: I/O Range\n"); + aprh = &ab->io_head; + tprh = &ab->tio_head; + + switch (data32->attribute.io.range_attribute) { + case ACPI_NON_ISA_ONLY_RANGES: + dbg(" Type Specific: Non-ISA Io Addresses\n"); + break; + case ACPI_ISA_ONLY_RANGES: + dbg(" Type Specific: ISA Io Addresses\n"); + break; + case ACPI_ENTIRE_RANGE: + dbg(" Type Specific: ISA and non-ISA Io Addresses\n"); + break; + default: + dbg(" Type Specific: Invalid range attribute\n"); + break; + } + break; + + case ACPI_BUS_NUMBER_RANGE: + dbg(" Resource Type: Bus Number Range(fixed)\n"); + /* Fixup to be compatible with the rest of php driver */ + data32->min_address_range++; + data32->address_length--; + aprh = &ab->bus_head; + tprh = &ab->tbus_head; + break; + default: + dbg(" Resource Type: Invalid resource type. Exiting.\n"); + return; + } + + dbg(" Resource %s\n", ACPI_CONSUMER == data32->producer_consumer ? "Consumer":"Producer"); + dbg(" %s decode\n", ACPI_SUB_DECODE == data32->decode ? "Subtractive":"Positive"); + dbg(" Min address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->min_address_fixed ? "":"not"); + dbg(" Max address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->max_address_fixed ? "":"not"); + dbg(" Granularity: %08X\n", data32->granularity); + dbg(" Address range min: %08X\n", data32->min_address_range); + dbg(" Address range max: %08X\n", data32->max_address_range); + dbg(" Address translation offset: %08X\n", data32->address_translation_offset); + dbg(" Address Length: %08X\n", data32->address_length); + + if (0xFF != data32->resource_source.index) { + dbg(" Resource Source Index: %X\n", data32->resource_source.index); + /* dbg(" Resource Source: %s\n", data32->resource_source.string_ptr); */ + } + + pciehprm_add_resource(aprh, data32->min_address_range, data32->address_length); +} + +static acpi_status acpi_parse_crs( + struct acpi_bridge *ab, + struct acpi_resource *crsbuf + ) +{ + acpi_status status = AE_OK; + struct acpi_resource *resource = crsbuf; + u8 count = 0; + u8 done = 0; + + while (!done) { + dbg("acpi_pciehprm: PCI bus 0x%x Resource structure %x.\n", ab->bus, count++); + switch (resource->id) { + case ACPI_RSTYPE_IRQ: + dbg("Irq -------- Resource\n"); + break; + case ACPI_RSTYPE_DMA: + dbg("DMA -------- Resource\n"); + break; + case ACPI_RSTYPE_START_DPF: + dbg("Start DPF -------- Resource\n"); + break; + case ACPI_RSTYPE_END_DPF: + dbg("End DPF -------- Resource\n"); + break; + case ACPI_RSTYPE_IO: + acpi_parse_io (ab, &resource->data); + break; + case ACPI_RSTYPE_FIXED_IO: + acpi_parse_fixed_io (ab, &resource->data); + break; + case ACPI_RSTYPE_VENDOR: + dbg("Vendor -------- Resource\n"); + break; + case ACPI_RSTYPE_END_TAG: + dbg("End_tag -------- Resource\n"); + done = 1; + break; + case ACPI_RSTYPE_MEM24: + dbg("Mem24 -------- Resource\n"); + break; + case ACPI_RSTYPE_MEM32: + dbg("Mem32 -------- Resource\n"); + break; + case ACPI_RSTYPE_FIXED_MEM32: + dbg("Fixed Mem32 -------- Resource\n"); + break; + case ACPI_RSTYPE_ADDRESS16: + acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS16); + break; + case ACPI_RSTYPE_ADDRESS32: + acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS32); + break; + case ACPI_RSTYPE_ADDRESS64: + info("Address64 -------- Resource unparsed\n"); + break; + case ACPI_RSTYPE_EXT_IRQ: + dbg("Ext Irq -------- Resource\n"); + break; + default: + dbg("Invalid -------- resource type 0x%x\n", resource->id); + break; + } + + resource = (struct acpi_resource *) ((char *)resource + resource->length); + } + + return status; +} + +static acpi_status acpi_get_crs( struct acpi_bridge *ab) +{ + acpi_status status; + struct acpi_resource *crsbuf; + + status = acpi_evaluate_crs(ab->handle, &crsbuf); + if (ACPI_SUCCESS(status)) { + status = acpi_parse_crs(ab, crsbuf); + kfree(crsbuf); + + pciehp_resource_sort_and_combine(&ab->bus_head); + pciehp_resource_sort_and_combine(&ab->io_head); + pciehp_resource_sort_and_combine(&ab->mem_head); + pciehp_resource_sort_and_combine(&ab->p_mem_head); + + pciehprm_add_resources (&ab->tbus_head, ab->bus_head); + pciehprm_add_resources (&ab->tio_head, ab->io_head); + pciehprm_add_resources (&ab->tmem_head, ab->mem_head); + pciehprm_add_resources (&ab->tp_mem_head, ab->p_mem_head); + } + + return status; +} + +/* find acpi_bridge downword from ab. */ +static struct acpi_bridge * +find_acpi_bridge_by_bus( + struct acpi_bridge *ab, + int seg, + int bus /* pdev->subordinate->number */ + ) +{ + struct acpi_bridge *lab = NULL; + + if (!ab) + return NULL; + + if ((ab->bus == bus) && (ab->seg == seg)) + return ab; + + if (ab->child) + lab = find_acpi_bridge_by_bus(ab->child, seg, bus); + + if (!lab) + if (ab->next) + lab = find_acpi_bridge_by_bus(ab->next, seg, bus); + + return lab; +} + +/* + * Build a device tree of ACPI PCI Bridges + */ +static void pciehprm_acpi_register_a_bridge ( + struct acpi_bridge **head, + struct acpi_bridge *pab, /* parent bridge to which child bridge is added */ + struct acpi_bridge *cab /* child bridge to add */ + ) +{ + struct acpi_bridge *lpab; + struct acpi_bridge *lcab; + + lpab = find_acpi_bridge_by_bus(*head, pab->seg, pab->bus); + if (!lpab) { + if (!(pab->type & BRIDGE_TYPE_HOST)) + warn("PCI parent bridge s:b(%x:%x) not in list.\n", pab->seg, pab->bus); + pab->next = *head; + *head = pab; + lpab = pab; + } + + if ((cab->type & BRIDGE_TYPE_HOST) && (pab == cab)) + return; + + lcab = find_acpi_bridge_by_bus(*head, cab->seg, cab->bus); + if (lcab) { + if ((pab->bus != lcab->parent->bus) || (lcab->bus != cab->bus)) + err("PCI child bridge s:b(%x:%x) in list with diff parent.\n", cab->seg, cab->bus); + return; + } else + lcab = cab; + + lcab->parent = lpab; + lcab->next = lpab->child; + lpab->child = lcab; +} + +static acpi_status pciehprm_acpi_build_php_slots_callback( + acpi_handle handle, + u32 Level, + void *context, + void **retval + ) +{ + ulong bus_num; + ulong seg_num; + ulong sun, adr; + ulong padr = 0; + acpi_handle phandle = NULL; + struct acpi_bridge *pab = (struct acpi_bridge *)context; + struct acpi_bridge *lab; + acpi_status status; + u8 *path_name = acpi_path_name(handle); + + /* Get _SUN */ + status = acpi_evaluate_integer(handle, METHOD_NAME__SUN, NULL, &sun); + switch(status) { + case AE_NOT_FOUND: + return AE_OK; + default: + if (ACPI_FAILURE(status)) { + err("acpi_pciehprm:%s _SUN fail=0x%x\n", path_name, status); + return status; + } + } + + /* Get _ADR. _ADR must exist if _SUN exists */ + status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); + if (ACPI_FAILURE(status)) { + err("acpi_pciehprm:%s _ADR fail=0x%x\n", path_name, status); + return status; + } + + dbg("acpi_pciehprm:%s sun=0x%08x adr=0x%08x\n", path_name, (u32)sun, (u32)adr); + + status = acpi_get_parent(handle, &phandle); + if (ACPI_FAILURE(status)) { + err("acpi_pciehprm:%s get_parent fail=0x%x\n", path_name, status); + return (status); + } + + bus_num = pab->bus; + seg_num = pab->seg; + + if (pab->bus == bus_num) { + lab = pab; + } else { + dbg("WARN: pab is not parent\n"); + lab = find_acpi_bridge_by_bus(pab, seg_num, bus_num); + if (!lab) { + dbg("acpi_pciehprm: alloc new P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun); + lab = (struct acpi_bridge *)kmalloc(sizeof(struct acpi_bridge), GFP_KERNEL); + if (!lab) { + err("acpi_pciehprm: alloc for ab fail\n"); + return AE_NO_MEMORY; + } + memset(lab, 0, sizeof(struct acpi_bridge)); + + lab->handle = phandle; + lab->pbus = pab->bus; + lab->pdevice = (int)(padr >> 16) & 0xffff; + lab->pfunction = (int)(padr & 0xffff); + lab->bus = (int)bus_num; + lab->scanned = 0; + lab->type = BRIDGE_TYPE_P2P; + + pciehprm_acpi_register_a_bridge (&acpi_bridges_head, pab, lab); + } else + dbg("acpi_pciehprm: found P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun); + } + + acpi_add_slot_to_php_slots(lab, (int)bus_num, handle, (u32)adr, (u32)sun); + + return (status); +} + +static int pciehprm_acpi_build_php_slots( + struct acpi_bridge *ab, + u32 depth + ) +{ + acpi_status status; + u8 *path_name = acpi_path_name(ab->handle); + + /* Walk down this pci bridge to get _SUNs if any behind P2P */ + status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, + ab->handle, + depth, + pciehprm_acpi_build_php_slots_callback, + ab, + NULL ); + if (ACPI_FAILURE(status)) { + dbg("acpi_pciehprm:%s walk for _SUN on pci bridge seg:bus(%x:%x) fail=0x%x\n", + path_name, ab->seg, ab->bus, status); + return -1; + } + + return 0; +} + +static void build_a_bridge( + struct acpi_bridge *pab, + struct acpi_bridge *ab + ) +{ + u8 *path_name = acpi_path_name(ab->handle); + + pciehprm_acpi_register_a_bridge (&acpi_bridges_head, pab, ab); + + switch (ab->type) { + case BRIDGE_TYPE_HOST: + dbg("acpi_pciehprm: Registered PCI HOST Bridge(%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n", + ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name); + break; + case BRIDGE_TYPE_P2P: + dbg("acpi_pciehprm: Registered PCI P2P Bridge(%02x-%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n", + ab->pbus, ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name); + break; + }; + + /* build any immediate PHP slots under this pci bridge */ + pciehprm_acpi_build_php_slots(ab, 1); +} + +static struct acpi_bridge * add_p2p_bridge( + acpi_handle handle, + struct acpi_bridge *pab, /* parent */ + ulong adr + ) +{ + struct acpi_bridge *ab; + struct pci_dev *pdev; + ulong devnum, funcnum; + u8 *path_name = acpi_path_name(handle); + + ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL); + if (!ab) { + err("acpi_pciehprm: alloc for ab fail\n"); + return NULL; + } + memset(ab, 0, sizeof(struct acpi_bridge)); + + devnum = (adr >> 16) & 0xffff; + funcnum = adr & 0xffff; + + pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum)); + if (!pdev || !pdev->subordinate) { + err("acpi_pciehprm:%s is not a P2P Bridge\n", path_name); + kfree(ab); + return NULL; + } + + ab->handle = handle; + ab->seg = pab->seg; + ab->pbus = pab->bus; /* or pdev->bus->number */ + ab->pdevice = devnum; /* or PCI_SLOT(pdev->devfn) */ + ab->pfunction = funcnum; /* or PCI_FUNC(pdev->devfn) */ + ab->bus = pdev->subordinate->number; + ab->scanned = 0; + ab->type = BRIDGE_TYPE_P2P; + + dbg("acpi_pciehprm: P2P(%x-%x) on pci=b:d:f(%x:%x:%x) acpi=b:d:f(%x:%x:%x) [%s]\n", + pab->bus, ab->bus, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), + pab->bus, (u32)devnum, (u32)funcnum, path_name); + + build_a_bridge(pab, ab); + + return ab; +} + +static acpi_status scan_p2p_bridge( + acpi_handle handle, + u32 Level, + void *context, + void **retval + ) +{ + struct acpi_bridge *pab = (struct acpi_bridge *)context; + struct acpi_bridge *ab; + acpi_status status; + ulong adr = 0; + u8 *path_name = acpi_path_name(handle); + ulong devnum, funcnum; + struct pci_dev *pdev; + + /* Get device, function */ + status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); + if (ACPI_FAILURE(status)) { + if (status != AE_NOT_FOUND) + err("acpi_pciehprm:%s _ADR fail=0x%x\n", path_name, status); + return AE_OK; + } + + devnum = (adr >> 16) & 0xffff; + funcnum = adr & 0xffff; + + pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum)); + if (!pdev) + return AE_OK; + if (!pdev->subordinate) + return AE_OK; + + ab = add_p2p_bridge(handle, pab, adr); + if (ab) { + status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, + handle, + (u32)1, + scan_p2p_bridge, + ab, + NULL); + if (ACPI_FAILURE(status)) + dbg("acpi_pciehprm:%s find_p2p fail=0x%x\n", path_name, status); + } + + return AE_OK; +} + +static struct acpi_bridge * add_host_bridge( + acpi_handle handle, + ulong segnum, + ulong busnum + ) +{ + ulong adr = 0; + acpi_status status; + struct acpi_bridge *ab; + u8 *path_name = acpi_path_name(handle); + + /* get device, function: host br adr is always 0000 though. */ + status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); + if (ACPI_FAILURE(status)) { + err("acpi_pciehprm:%s _ADR fail=0x%x\n", path_name, status); + return NULL; + } + dbg("acpi_pciehprm: ROOT PCI seg(0x%x)bus(0x%x)dev(0x%x)func(0x%x) [%s]\n", (u32)segnum, + (u32)busnum, (u32)(adr >> 16) & 0xffff, (u32)adr & 0xffff, path_name); + + ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL); + if (!ab) { + err("acpi_pciehprm: alloc for ab fail\n"); + return NULL; + } + memset(ab, 0, sizeof(struct acpi_bridge)); + + ab->handle = handle; + ab->seg = (int)segnum; + ab->bus = ab->pbus = (int)busnum; + ab->pdevice = (int)(adr >> 16) & 0xffff; + ab->pfunction = (int)(adr & 0xffff); + ab->scanned = 0; + ab->type = BRIDGE_TYPE_HOST; + + /* get root pci bridge's current resources */ + status = acpi_get_crs(ab); + if (ACPI_FAILURE(status)) { + err("acpi_pciehprm:%s evaluate _CRS fail=0x%x\n", path_name, status); + kfree(ab); + return NULL; + } + build_a_bridge(ab, ab); + + return ab; +} + +static acpi_status acpi_scan_from_root_pci_callback ( + acpi_handle handle, + u32 Level, + void *context, + void **retval + ) +{ + ulong segnum = 0; + ulong busnum = 0; + acpi_status status; + struct acpi_bridge *ab; + u8 *path_name = acpi_path_name(handle); + + /* Get bus number of this pci root bridge */ + status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &segnum); + if (ACPI_FAILURE(status)) { + if (status != AE_NOT_FOUND) { + err("acpi_pciehprm:%s evaluate _SEG fail=0x%x\n", path_name, status); + return status; + } + segnum = 0; + } + + /* Get bus number of this pci root bridge */ + status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, &busnum); + if (ACPI_FAILURE(status)) { + err("acpi_pciehprm:%s evaluate _BBN fail=0x%x\n", path_name, status); + return (status); + } + + ab = add_host_bridge(handle, segnum, busnum); + if (ab) { + status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, + handle, + 1, + scan_p2p_bridge, + ab, + NULL); + if (ACPI_FAILURE(status)) + dbg("acpi_pciehprm:%s find_p2p fail=0x%x\n", path_name, status); + } + + return AE_OK; +} + +static int pciehprm_acpi_scan_pci (void) +{ + acpi_status status; + + /* + * TBD: traverse LDM device tree with the help of + * unified ACPI augmented for php device population. + */ + status = acpi_get_devices ( PCI_ROOT_HID_STRING, + acpi_scan_from_root_pci_callback, + NULL, + NULL ); + if (ACPI_FAILURE(status)) { + err("acpi_pciehprm:get_device PCI ROOT HID fail=0x%x\n", status); + return -1; + } + + return 0; +} + +int pciehprm_init(enum php_ctlr_type ctlr_type) +{ + int rc; + + if (ctlr_type != PCI) + return -ENODEV; + + dbg("pciehprm ACPI init \n"); + acpi_bridges_head = NULL; + + /* Construct PCI bus:device tree of acpi_handles */ + rc = pciehprm_acpi_scan_pci(); + if (rc) + return rc; + + dbg("pciehprm ACPI init %s\n", (rc)?"fail":"success"); + return rc; +} + +static void free_a_slot(struct acpi_php_slot *aps) +{ + dbg(" free a php func of slot(0x%02x) on PCI b:d:f=0x%02x:%02x:%02x\n", aps->sun, aps->bus, aps->dev, aps->fun); + + free_pci_resource (aps->io_head); + free_pci_resource (aps->bus_head); + free_pci_resource (aps->mem_head); + free_pci_resource (aps->p_mem_head); + + kfree(aps); +} + +static void free_a_bridge( struct acpi_bridge *ab) +{ + struct acpi_php_slot *aps, *next; + + switch (ab->type) { + case BRIDGE_TYPE_HOST: + dbg("Free ACPI PCI HOST Bridge(%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n", + ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction); + break; + case BRIDGE_TYPE_P2P: + dbg("Free ACPI PCI P2P Bridge(%x-%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n", + ab->pbus, ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction); + break; + }; + + /* Free slots first */ + for (aps = ab->slots; aps; aps = next) { + next = aps->next; + free_a_slot(aps); + } + + free_pci_resource (ab->io_head); + free_pci_resource (ab->tio_head); + free_pci_resource (ab->bus_head); + free_pci_resource (ab->tbus_head); + free_pci_resource (ab->mem_head); + free_pci_resource (ab->tmem_head); + free_pci_resource (ab->p_mem_head); + free_pci_resource (ab->tp_mem_head); + + kfree(ab); +} + +static void pciehprm_free_bridges ( struct acpi_bridge *ab) +{ + if (!ab) + return; + + if (ab->child) + pciehprm_free_bridges (ab->child); + + if (ab->next) + pciehprm_free_bridges (ab->next); + + free_a_bridge(ab); +} + +void pciehprm_cleanup(void) +{ + pciehprm_free_bridges (acpi_bridges_head); +} + +static int get_number_of_slots ( + struct acpi_bridge *ab, + int selfonly + ) +{ + struct acpi_php_slot *aps; + int prev_slot = -1; + int slot_num = 0; + + for ( aps = ab->slots; aps; aps = aps->next) + if (aps->dev != prev_slot) { + prev_slot = aps->dev; + slot_num++; + } + + if (ab->child) + slot_num += get_number_of_slots (ab->child, 0); + + if (selfonly) + return slot_num; + + if (ab->next) + slot_num += get_number_of_slots (ab->next, 0); + + return slot_num; +} + +static int print_acpi_resources (struct acpi_bridge *ab) +{ + struct acpi_php_slot *aps; + int i; + + switch (ab->type) { + case BRIDGE_TYPE_HOST: + dbg("PCI HOST Bridge (%x) [%s]\n", ab->bus, acpi_path_name(ab->handle)); + break; + case BRIDGE_TYPE_P2P: + dbg("PCI P2P Bridge (%x-%x) [%s]\n", ab->pbus, ab->bus, acpi_path_name(ab->handle)); + break; + }; + + print_pci_resources (ab); + + for ( i = -1, aps = ab->slots; aps; aps = aps->next) { + if (aps->dev == i) + continue; + dbg(" Slot sun(%x) s:b:d:f(%02x:%02x:%02x:%02x)\n", aps->sun, aps->seg, aps->bus, + aps->dev, aps->fun); + print_slot_resources(aps); + i = aps->dev; + } + + if (ab->child) + print_acpi_resources (ab->child); + + if (ab->next) + print_acpi_resources (ab->next); + + return 0; +} + +int pciehprm_print_pirt(void) +{ + dbg("PCIEHPRM ACPI Slots\n"); + if (acpi_bridges_head) + print_acpi_resources (acpi_bridges_head); + + return 0; +} + +static struct acpi_php_slot * get_acpi_slot ( + struct acpi_bridge *ab, + u32 sun + ) +{ + struct acpi_php_slot *aps = NULL; + + for ( aps = ab->slots; aps; aps = aps->next) + if (aps->sun == sun) + return aps; + + if (!aps && ab->child) { + aps = (struct acpi_php_slot *)get_acpi_slot (ab->child, sun); + if (aps) + return aps; + } + + if (!aps && ab->next) { + aps = (struct acpi_php_slot *)get_acpi_slot (ab->next, sun); + if (aps) + return aps; + } + + return aps; + +} + +void * pciehprm_get_slot(struct slot *slot) +{ + struct acpi_bridge *ab = acpi_bridges_head; + struct acpi_php_slot *aps = get_acpi_slot (ab, slot->number); + + aps->slot = slot; + + dbg("Got acpi slot sun(%x): s:b:d:f(%x:%x:%x:%x)\n", aps->sun, aps->seg, aps->bus, + aps->dev, aps->fun); + + return (void *)aps; +} + +static void pciehprm_dump_func_res( struct pci_func *fun) +{ + struct pci_func *func = fun; + + if (func->bus_head) { + dbg(": BUS Resources:\n"); + print_pci_resource (func->bus_head); + } + if (func->io_head) { + dbg(": IO Resources:\n"); + print_pci_resource (func->io_head); + } + if (func->mem_head) { + dbg(": MEM Resources:\n"); + print_pci_resource (func->mem_head); + } + if (func->p_mem_head) { + dbg(": PMEM Resources:\n"); + print_pci_resource (func->p_mem_head); + } +} + +static void pciehprm_dump_ctrl_res( struct controller *ctlr) +{ + struct controller *ctrl = ctlr; + + if (ctrl->bus_head) { + dbg(": BUS Resources:\n"); + print_pci_resource (ctrl->bus_head); + } + if (ctrl->io_head) { + dbg(": IO Resources:\n"); + print_pci_resource (ctrl->io_head); + } + if (ctrl->mem_head) { + dbg(": MEM Resources:\n"); + print_pci_resource (ctrl->mem_head); + } + if (ctrl->p_mem_head) { + dbg(": PMEM Resources:\n"); + print_pci_resource (ctrl->p_mem_head); + } +} + +static int pciehprm_get_used_resources ( + struct controller *ctrl, + struct pci_func *func + ) +{ + return pciehp_save_used_resources (ctrl, func, !DISABLE_CARD); +} + +static int configure_existing_function( + struct controller *ctrl, + struct pci_func *func + ) +{ + int rc; + + /* See how much resources the func has used. */ + rc = pciehprm_get_used_resources (ctrl, func); + + if (!rc) { + /* Subtract the resources used by the func from ctrl resources */ + rc = pciehprm_delete_resources (&ctrl->bus_head, func->bus_head); + rc |= pciehprm_delete_resources (&ctrl->io_head, func->io_head); + rc |= pciehprm_delete_resources (&ctrl->mem_head, func->mem_head); + rc |= pciehprm_delete_resources (&ctrl->p_mem_head, func->p_mem_head); + if (rc) + warn("aCEF: cannot del used resources\n"); + } else + err("aCEF: cannot get used resources\n"); + + return rc; +} + +static int bind_pci_resources_to_slots ( struct controller *ctrl) +{ + struct pci_func *func; + int busn = ctrl->slot_bus; + int devn, funn; + u32 vid; + + for (devn = 0; devn < 32; devn++) { + for (funn = 0; funn < 8; funn++) { + /* + if (devn == ctrl->device && funn == ctrl->function) + continue; + */ + /* Find out if this entry is for an occupied slot */ + vid = 0xFFFFFFFF; + pci_bus_read_config_dword(ctrl->pci_dev->subordinate, PCI_DEVFN(devn, funn), + PCI_VENDOR_ID, &vid); + + if (vid != 0xFFFFFFFF) { + dbg("%s: vid = %x\n", __FUNCTION__, vid); + func = pciehp_slot_find(busn, devn, funn); + if (!func) + continue; + configure_existing_function(ctrl, func); + dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus); + pciehprm_dump_func_res(func); + } + } + } + + return 0; +} + +static int bind_pci_resources( + struct controller *ctrl, + struct acpi_bridge *ab + ) +{ + int status = 0; + + if (ab->bus_head) { + dbg("bapr: BUS Resources add on PCI 0x%x\n", ab->bus); + status = pciehprm_add_resources (&ctrl->bus_head, ab->bus_head); + if (pciehprm_delete_resources (&ab->bus_head, ctrl->bus_head)) + warn("bapr: cannot sub BUS Resource on PCI 0x%x\n", ab->bus); + if (status) { + err("bapr: BUS Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); + return status; + } + } else + info("bapr: No BUS Resource on PCI 0x%x.\n", ab->bus); + + if (ab->io_head) { + dbg("bapr: IO Resources add on PCI 0x%x\n", ab->bus); + status = pciehprm_add_resources (&ctrl->io_head, ab->io_head); + if (pciehprm_delete_resources (&ab->io_head, ctrl->io_head)) + warn("bapr: cannot sub IO Resource on PCI 0x%x\n", ab->bus); + if (status) { + err("bapr: IO Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); + return status; + } + } else + info("bapr: No IO Resource on PCI 0x%x.\n", ab->bus); + + if (ab->mem_head) { + dbg("bapr: MEM Resources add on PCI 0x%x\n", ab->bus); + status = pciehprm_add_resources (&ctrl->mem_head, ab->mem_head); + if (pciehprm_delete_resources (&ab->mem_head, ctrl->mem_head)) + warn("bapr: cannot sub MEM Resource on PCI 0x%x\n", ab->bus); + if (status) { + err("bapr: MEM Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); + return status; + } + } else + info("bapr: No MEM Resource on PCI 0x%x.\n", ab->bus); + + if (ab->p_mem_head) { + dbg("bapr: PMEM Resources add on PCI 0x%x\n", ab->bus); + status = pciehprm_add_resources (&ctrl->p_mem_head, ab->p_mem_head); + if (pciehprm_delete_resources (&ab->p_mem_head, ctrl->p_mem_head)) + warn("bapr: cannot sub PMEM Resource on PCI 0x%x\n", ab->bus); + if (status) { + err("bapr: PMEM Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); + return status; + } + } else + info("bapr: No PMEM Resource on PCI 0x%x.\n", ab->bus); + + return status; +} + +static int no_pci_resources( struct acpi_bridge *ab) +{ + return !(ab->p_mem_head || ab->mem_head || ab->io_head || ab->bus_head); +} + +static int find_pci_bridge_resources ( + struct controller *ctrl, + struct acpi_bridge *ab + ) +{ + int rc = 0; + struct pci_func func; + + memset(&func, 0, sizeof(struct pci_func)); + + func.bus = ab->pbus; + func.device = ab->pdevice; + func.function = ab->pfunction; + func.is_a_board = 1; + + /* Get used resources for this PCI bridge */ + rc = pciehp_save_used_resources (ctrl, &func, !DISABLE_CARD); + + ab->io_head = func.io_head; + ab->mem_head = func.mem_head; + ab->p_mem_head = func.p_mem_head; + ab->bus_head = func.bus_head; + if (ab->bus_head) + pciehprm_delete_resource(&ab->bus_head, ctrl->pci_dev->subordinate->number, 1); + return rc; +} + +static int get_pci_resources_from_bridge( + struct controller *ctrl, + struct acpi_bridge *ab + ) +{ + int rc = 0; + + dbg("grfb: Get Resources for PCI 0x%x from actual PCI bridge 0x%x.\n", ctrl->bus, ab->bus); + + rc = find_pci_bridge_resources (ctrl, ab); + + pciehp_resource_sort_and_combine(&ab->bus_head); + pciehp_resource_sort_and_combine(&ab->io_head); + pciehp_resource_sort_and_combine(&ab->mem_head); + pciehp_resource_sort_and_combine(&ab->p_mem_head); + + pciehprm_add_resources (&ab->tbus_head, ab->bus_head); + pciehprm_add_resources (&ab->tio_head, ab->io_head); + pciehprm_add_resources (&ab->tmem_head, ab->mem_head); + pciehprm_add_resources (&ab->tp_mem_head, ab->p_mem_head); + + return rc; +} + +static int get_pci_resources( + struct controller *ctrl, + struct acpi_bridge *ab + ) +{ + int rc = 0; + + if (no_pci_resources(ab)) { + dbg("spbr:PCI 0x%x has no resources. Get parent resources.\n", ab->bus); + rc = get_pci_resources_from_bridge(ctrl, ab); + } + + return rc; +} + +/* + * Get resources for this ctrl. + * 1. get total resources from ACPI _CRS or bridge (this ctrl) + * 2. find used resources of existing adapters + * 3. subtract used resources from total resources + */ +int pciehprm_find_available_resources( struct controller *ctrl) +{ + int rc = 0; + struct acpi_bridge *ab; + + ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->pci_dev->subordinate->number); + if (!ab) { + err("pfar:cannot locate acpi bridge of PCI 0x%x.\n", ctrl->pci_dev->subordinate->number); + return -1; + } + if (no_pci_resources(ab)) { + rc = get_pci_resources(ctrl, ab); + if (rc) { + err("pfar:cannot get pci resources of PCI 0x%x.\n", ctrl->pci_dev->subordinate->number); + return -1; + } + } + + rc = bind_pci_resources(ctrl, ab); + dbg("pfar:pre-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl->pci_dev->subordinate->number); + pciehprm_dump_ctrl_res(ctrl); + + bind_pci_resources_to_slots (ctrl); + + dbg("pfar:post-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl->pci_dev->subordinate->number); + pciehprm_dump_ctrl_res(ctrl); + + return rc; +} + +int pciehprm_set_hpp( + struct controller *ctrl, + struct pci_func *func, + u8 card_type + ) +{ + struct acpi_bridge *ab; + struct pci_bus lpci_bus, *pci_bus; + int rc = 0; + unsigned int devfn; + u8 cls= 0x08; /* default cache line size */ + u8 lt = 0x40; /* default latency timer */ + u8 ep = 0; + u8 es = 0; + + memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); + pci_bus = &lpci_bus; + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus); + + if (ab) { + if (ab->_hpp) { + lt = (u8)ab->_hpp->latency_timer; + cls = (u8)ab->_hpp->cache_line_size; + ep = (u8)ab->_hpp->enable_perr; + es = (u8)ab->_hpp->enable_serr; + } else + dbg("_hpp: no _hpp for B/D/F=%#x/%#x/%#x. use default value\n", + func->bus, func->device, func->function); + } else + dbg("_hpp: no acpi bridge for B/D/F = %#x/%#x/%#x. use default value\n", + func->bus, func->device, func->function); + + + if (card_type == PCI_HEADER_TYPE_BRIDGE) { + /* Set subordinate Latency Timer */ + rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, lt); + } + + /* Set base Latency Timer */ + rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, lt); + dbg(" set latency timer =0x%02x: %x\n", lt, rc); + + rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, cls); + dbg(" set cache_line_size=0x%02x: %x\n", cls, rc); + + return rc; +} + +void pciehprm_enable_card( + struct controller *ctrl, + struct pci_func *func, + u8 card_type) +{ + u16 command, cmd, bcommand, bcmd; + struct pci_bus lpci_bus, *pci_bus; + struct acpi_bridge *ab; + unsigned int devfn; + int rc; + + memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); + pci_bus = &lpci_bus; + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command); + + if (card_type == PCI_HEADER_TYPE_BRIDGE) { + rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand); + } + + cmd = command = command | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE + | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; + bcmd = bcommand = bcommand | PCI_BRIDGE_CTL_NO_ISA; + + ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus); + if (ab) { + if (ab->_hpp) { + if (ab->_hpp->enable_perr) { + command |= PCI_COMMAND_PARITY; + bcommand |= PCI_BRIDGE_CTL_PARITY; + } else { + command &= ~PCI_COMMAND_PARITY; + bcommand &= ~PCI_BRIDGE_CTL_PARITY; + } + if (ab->_hpp->enable_serr) { + command |= PCI_COMMAND_SERR; + bcommand |= PCI_BRIDGE_CTL_SERR; + } else { + command &= ~PCI_COMMAND_SERR; + bcommand &= ~PCI_BRIDGE_CTL_SERR; + } + } else + dbg("no _hpp for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function); + } else + dbg("no acpi bridge for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function); + + if (command != cmd) { + rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); + } + if ((card_type == PCI_HEADER_TYPE_BRIDGE) && (bcommand != bcmd)) { + rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand); + } +} diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/pciehprm_nonacpi.c linux-2.4.27-pre5/drivers/hotplug/pciehprm_nonacpi.c --- linux-2.4.26/drivers/hotplug/pciehprm_nonacpi.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/pciehprm_nonacpi.c 2004-06-03 01:32:37.000000000 +0000 @@ -0,0 +1,497 @@ +/* + * PCIEHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform + * + * 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 +#ifdef CONFIG_IA64 +#include +#endif +#include "pciehp.h" +#include "pciehprm.h" +#include "pciehprm_nonacpi.h" + + +void pciehprm_cleanup(void) +{ + return; +} + +int pciehprm_print_pirt(void) +{ + return 0; +} + + +void * pciehprm_get_slot(struct slot *slot) +{ + return NULL; +} + +int pciehprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) +{ + + *sun = (u8) (ctrl->first_slot); + return 0; +} + +static void print_pci_resource ( struct pci_resource *aprh) +{ + struct pci_resource *res; + + for (res = aprh; res; res = res->next) + dbg(" base= 0x%x length= 0x%x\n", res->base, res->length); +} + + +static void phprm_dump_func_res( struct pci_func *fun) +{ + struct pci_func *func = fun; + + if (func->bus_head) { + dbg(": BUS Resources:\n"); + print_pci_resource (func->bus_head); + } + if (func->io_head) { + dbg(": IO Resources:\n"); + print_pci_resource (func->io_head); + } + if (func->mem_head) { + dbg(": MEM Resources:\n"); + print_pci_resource (func->mem_head); + } + if (func->p_mem_head) { + dbg(": PMEM Resources:\n"); + print_pci_resource (func->p_mem_head); + } +} + +static int phprm_get_used_resources ( + struct controller *ctrl, + struct pci_func *func + ) +{ + return pciehp_save_used_resources (ctrl, func, !DISABLE_CARD); +} + +static int phprm_delete_resource( + struct pci_resource **aprh, + ulong base, + ulong size) +{ + struct pci_resource *res; + struct pci_resource *prevnode; + struct pci_resource *split_node; + ulong tbase; + + pciehp_resource_sort_and_combine(aprh); + + for (res = *aprh; res; res = res->next) { + if (res->base > base) + continue; + + if ((res->base + res->length) < (base + size)) + continue; + + if (res->base < base) { + tbase = base; + + if ((res->length - (tbase - res->base)) < size) + continue; + + split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!split_node) + return -ENOMEM; + + split_node->base = res->base; + split_node->length = tbase - res->base; + res->base = tbase; + res->length -= split_node->length; + + split_node->next = res->next; + res->next = split_node; + } + + if (res->length >= size) { + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!split_node) + return -ENOMEM; + + split_node->base = res->base + size; + split_node->length = res->length - size; + res->length = size; + + split_node->next = res->next; + res->next = split_node; + } + + if (*aprh == res) { + *aprh = res->next; + } else { + prevnode = *aprh; + while (prevnode->next != res) + prevnode = prevnode->next; + + prevnode->next = res->next; + } + res->next = NULL; + kfree(res); + break; + } + + return 0; +} + + +static int phprm_delete_resources( + struct pci_resource **aprh, + struct pci_resource *this + ) +{ + struct pci_resource *res; + + for (res = this; res; res = res->next) + phprm_delete_resource(aprh, res->base, res->length); + + return 0; +} + + +static int configure_existing_function( + struct controller *ctrl, + struct pci_func *func + ) +{ + int rc; + + /* See how much resources the func has used. */ + rc = phprm_get_used_resources (ctrl, func); + + if (!rc) { + /* Subtract the resources used by the func from ctrl resources */ + rc = phprm_delete_resources (&ctrl->bus_head, func->bus_head); + rc |= phprm_delete_resources (&ctrl->io_head, func->io_head); + rc |= phprm_delete_resources (&ctrl->mem_head, func->mem_head); + rc |= phprm_delete_resources (&ctrl->p_mem_head, func->p_mem_head); + if (rc) + warn("aCEF: cannot del used resources\n"); + } else + err("aCEF: cannot get used resources\n"); + + return rc; +} + +static int pciehprm_delete_resource( + struct pci_resource **aprh, + ulong base, + ulong size) +{ + struct pci_resource *res; + struct pci_resource *prevnode; + struct pci_resource *split_node; + ulong tbase; + + pciehp_resource_sort_and_combine(aprh); + + for (res = *aprh; res; res = res->next) { + if (res->base > base) + continue; + + if ((res->base + res->length) < (base + size)) + continue; + + if (res->base < base) { + tbase = base; + + if ((res->length - (tbase - res->base)) < size) + continue; + + split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!split_node) + return -ENOMEM; + + split_node->base = res->base; + split_node->length = tbase - res->base; + res->base = tbase; + res->length -= split_node->length; + + split_node->next = res->next; + res->next = split_node; + } + + if (res->length >= size) { + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!split_node) + return -ENOMEM; + + split_node->base = res->base + size; + split_node->length = res->length - size; + res->length = size; + + split_node->next = res->next; + res->next = split_node; + } + + if (*aprh == res) { + *aprh = res->next; + } else { + prevnode = *aprh; + while (prevnode->next != res) + prevnode = prevnode->next; + + prevnode->next = res->next; + } + res->next = NULL; + kfree(res); + break; + } + + return 0; +} + +static int bind_pci_resources_to_slots ( struct controller *ctrl) +{ + struct pci_func *func; + int busn = ctrl->slot_bus; + int devn, funn; + u32 vid; + + for (devn = 0; devn < 32; devn++) { + for (funn = 0; funn < 8; funn++) { + /* + if (devn == ctrl->device && funn == ctrl->function) + continue; + */ + /* Find out if this entry is for an occupied slot */ + vid = 0xFFFFFFFF; + + pci_bus_read_config_dword(ctrl->pci_dev->subordinate, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &vid); + if (vid != 0xFFFFFFFF) { + dbg("%s: vid = %x bus %x dev %x fun %x\n", __FUNCTION__, + vid, busn, devn, funn); + func = pciehp_slot_find(busn, devn, funn); + dbg("%s: func = %p\n", __FUNCTION__,func); + if (!func) + continue; + configure_existing_function(ctrl, func); + dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus); + phprm_dump_func_res(func); + } + } + } + + return 0; +} + +static void phprm_dump_ctrl_res( struct controller *ctlr) +{ + struct controller *ctrl = ctlr; + + if (ctrl->bus_head) { + dbg(": BUS Resources:\n"); + print_pci_resource (ctrl->bus_head); + } + if (ctrl->io_head) { + dbg(": IO Resources:\n"); + print_pci_resource (ctrl->io_head); + } + if (ctrl->mem_head) { + dbg(": MEM Resources:\n"); + print_pci_resource (ctrl->mem_head); + } + if (ctrl->p_mem_head) { + dbg(": PMEM Resources:\n"); + print_pci_resource (ctrl->p_mem_head); + } +} + +/* + * phprm_find_available_resources + * + * Finds available memory, IO, and IRQ resources for programming + * devices which may be added to the system + * this function is for hot plug ADD! + * + * returns 0 if success + */ +int pciehprm_find_available_resources(struct controller *ctrl) +{ + struct pci_func func; + u32 rc; + + memset(&func, 0, sizeof(struct pci_func)); + + func.bus = ctrl->bus; + func.device = ctrl->device; + func.function = ctrl->function; + func.is_a_board = 1; + + /* Get resources for this PCI bridge */ + rc = pciehp_save_used_resources (ctrl, &func, !DISABLE_CARD); + dbg("%s: pciehp_save_used_resources rc = %d\n", __FUNCTION__, rc); + + if (func.mem_head) + func.mem_head->next = ctrl->mem_head; + ctrl->mem_head = func.mem_head; + + if (func.p_mem_head) + func.p_mem_head->next = ctrl->p_mem_head; + ctrl->p_mem_head = func.p_mem_head; + + if (func.io_head) + func.io_head->next = ctrl->io_head; + ctrl->io_head = func.io_head; + + if (func.bus_head) + func.bus_head->next = ctrl->bus_head; + ctrl->bus_head = func.bus_head; + if (ctrl->bus_head) + pciehprm_delete_resource(&ctrl->bus_head, ctrl->pci_dev->subordinate->number, 1); + + dbg("%s:pre-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl->bus); + phprm_dump_ctrl_res(ctrl); + + dbg("%s: before bind_pci_resources_to slots\n", __FUNCTION__); + + bind_pci_resources_to_slots (ctrl); + + dbg("%s:post-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl->bus); + phprm_dump_ctrl_res(ctrl); + + return (rc); +} + +int pciehprm_set_hpp( + struct controller *ctrl, + struct pci_func *func, + u8 card_type) +{ + u32 rc; + u8 temp_byte; + struct pci_bus lpci_bus, *pci_bus; + unsigned int devfn; + memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); + pci_bus = &lpci_bus; + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + temp_byte = 0x40; /* Hard coded value for LT */ + if (card_type == PCI_HEADER_TYPE_BRIDGE) { + /* Set subordinate Latency Timer */ + rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte); + + if (rc) { + dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); + return rc; + } + } + + /* Set base Latency Timer */ + rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte); + + if (rc) { + dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, + func->device, func->function); + return rc; + } + + /* set Cache Line size */ + temp_byte = 0x08; /* hard coded value for CLS */ + + rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte); + + if (rc) { + dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, + func->device, func->function); + } + + /* set enable_perr */ + /* set enable_serr */ + + return rc; +} + +void pciehprm_enable_card( + struct controller *ctrl, + struct pci_func *func, + u8 card_type) +{ + u16 command, bcommand; + struct pci_bus lpci_bus, *pci_bus; + unsigned int devfn; + int rc; + + memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); + pci_bus = &lpci_bus; + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command); + + command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR + | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE + | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; + + rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); + + if (card_type == PCI_HEADER_TYPE_BRIDGE) { + + rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand); + + bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR + | PCI_BRIDGE_CTL_NO_ISA; + + rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand); + } +} + +static int legacy_pciehprm_init_pci(void) +{ + return 0; +} + +int pciehprm_init(enum php_ctlr_type ctrl_type) +{ + int retval; + + switch (ctrl_type) { + case PCI: + retval = legacy_pciehprm_init_pci(); + break; + default: + retval = -ENODEV; + break; + } + + return retval; +} diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/pciehprm_nonacpi.h linux-2.4.27-pre5/drivers/hotplug/pciehprm_nonacpi.h --- linux-2.4.26/drivers/hotplug/pciehprm_nonacpi.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/pciehprm_nonacpi.h 2004-06-03 01:34:01.000000000 +0000 @@ -0,0 +1,56 @@ +/* + * PCIEHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform + * + * 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 _PCIEHPRM_NONACPI_H_ +#define _PCIEHPRM_NONACPI_H_ + +struct irq_info { + u8 bus, devfn; /* bus, device and function */ + struct { + u8 link; /* IRQ line ID, chipset dependent, 0=not routed */ + u16 bitmap; /* Available IRQs */ + } __attribute__ ((packed)) irq[4]; + u8 slot; /* slot number, 0=onboard */ + u8 rfu; +} __attribute__ ((packed)); + +struct irq_routing_table { + u32 signature; /* PIRQ_SIGNATURE should be here */ + u16 version; /* PIRQ_VERSION */ + u16 size; /* Table size in bytes */ + u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */ + u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */ + u16 rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */ + u32 miniport_data; /* Crap */ + u8 rfu[11]; + u8 checksum; /* Modulo 256 checksum must give zero */ + struct irq_info slots[0]; +} __attribute__ ((packed)); + +#endif /* _PCIEHPRM_NONACPI_H_ */ diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/shpchp.h linux-2.4.27-pre5/drivers/hotplug/shpchp.h --- linux-2.4.26/drivers/hotplug/shpchp.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/shpchp.h 2004-06-03 01:33:41.000000000 +0000 @@ -0,0 +1,464 @@ +/* + * Standard Hot Plug Controller Driver + * + * Copyright (C) 1995,2001 Compaq Computer Corporation + * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2001 IBM + * 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 _SHPCHP_H +#define _SHPCHP_H + +#include +#include +#include +#include +#include "pci_hotplug.h" + +#if !defined(CONFIG_HOTPLUG_PCI_SHPC_MODULE) + #define MY_NAME "shpchp.o" +#else + #define MY_NAME THIS_MODULE->name +#endif + +extern int shpchp_poll_mode; +extern int shpchp_poll_time; +extern int shpchp_debug; + +/*#define dbg(format, arg...) do { if (shpchp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/ +#define dbg(format, arg...) do { if (shpchp_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 */ + 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 AMD SHPC ID */ +#define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450 + +/* Define SHPC CAP ID - not defined in kernel yet */ +#define PCI_CAP_ID_SHPC 0x0C + +#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_shpc "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 shpcphd mdoule. Upgrade to a newer version of shpchpd\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 shpchp_pushbutton_thread (unsigned long event_pointer); +extern int shpchprm_find_available_resources (struct controller *ctrl); +extern int shpchp_event_start_thread (void); +extern void shpchp_event_stop_thread (void); +extern struct pci_func *shpchp_slot_create (unsigned char busnumber); +extern struct pci_func *shpchp_slot_find (unsigned char bus, unsigned char device, unsigned char index); +extern int shpchp_enable_slot (struct slot *slot); +extern int shpchp_disable_slot (struct slot *slot); + +extern u8 shpchp_handle_attention_button (u8 hp_slot, void *inst_id); +extern u8 shpchp_handle_switch_change (u8 hp_slot, void *inst_id); +extern u8 shpchp_handle_presence_change (u8 hp_slot, void *inst_id); +extern u8 shpchp_handle_power_fault (u8 hp_slot, void *inst_id); + +/* resource functions */ +extern int shpchp_resource_sort_and_combine (struct pci_resource **head); + +/* pci functions */ +extern int shpchp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num); +extern int shpchp_get_bus_dev (struct controller *ctrl, u8 *bus_num, u8 *dev_num, struct slot *slot); +extern int shpchp_save_config (struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num); +extern int shpchp_save_used_resources (struct controller *ctrl, struct pci_func * func, int flag); +extern int shpchp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot); +extern void shpchp_destroy_board_resources (struct pci_func * func); +extern int shpchp_return_board_resources (struct pci_func * func, struct resource_lists * resources); +extern void shpchp_destroy_resource_list (struct resource_lists * resources); +extern int shpchp_configure_device (struct controller* ctrl, struct pci_func* func); +extern int shpchp_unconfigure_device (struct pci_func* func); + + +/* Global variables */ +extern struct controller *shpchp_ctrl_list; +extern struct pci_func *shpchp_slot_list[256]; + +/* These are added to support AMD SHPC */ +extern u8 shpchp_nic_irq; +extern u8 shpchp_disk_irq; + +struct ctrl_reg { + volatile u32 base_offset; + volatile u32 slot_avail1; + volatile u32 slot_avail2; + volatile u32 slot_config; + volatile u16 sec_bus_config; + volatile u8 msi_ctrl; + volatile u8 prog_interface; + volatile u16 cmd; + volatile u16 cmd_status; + volatile u32 intr_loc; + volatile u32 serr_loc; + volatile u32 serr_intr_enable; + volatile u32 slot1; + volatile u32 slot2; + volatile u32 slot3; + volatile u32 slot4; + volatile u32 slot5; + volatile u32 slot6; + volatile u32 slot7; + volatile u32 slot8; + volatile u32 slot9; + volatile u32 slot10; + volatile u32 slot11; + volatile u32 slot12; +} __attribute__ ((packed)); + +/* Offsets to the controller registers based on the above structure layout */ +enum ctrl_offsets { + BASE_OFFSET = offsetof(struct ctrl_reg, base_offset), + SLOT_AVAIL1 = offsetof(struct ctrl_reg, slot_avail1), + SLOT_AVAIL2 = offsetof(struct ctrl_reg, slot_avail2), + SLOT_CONFIG = offsetof(struct ctrl_reg, slot_config), + SEC_BUS_CONFIG = offsetof(struct ctrl_reg, sec_bus_config), + MSI_CTRL = offsetof(struct ctrl_reg, msi_ctrl), + PROG_INTERFACE = offsetof(struct ctrl_reg, prog_interface), + CMD = offsetof(struct ctrl_reg, cmd), + CMD_STATUS = offsetof(struct ctrl_reg, cmd_status), + INTR_LOC = offsetof(struct ctrl_reg, intr_loc), + SERR_LOC = offsetof(struct ctrl_reg, serr_loc), + SERR_INTR_ENABLE = offsetof(struct ctrl_reg, serr_intr_enable), + SLOT1 = offsetof(struct ctrl_reg, slot1), + SLOT2 = offsetof(struct ctrl_reg, slot2), + SLOT3 = offsetof(struct ctrl_reg, slot3), + SLOT4 = offsetof(struct ctrl_reg, slot4), + SLOT5 = offsetof(struct ctrl_reg, slot5), + SLOT6 = offsetof(struct ctrl_reg, slot6), + SLOT7 = offsetof(struct ctrl_reg, slot7), + SLOT8 = offsetof(struct ctrl_reg, slot8), + SLOT9 = offsetof(struct ctrl_reg, slot9), + SLOT10 = offsetof(struct ctrl_reg, slot10), + SLOT11 = offsetof(struct ctrl_reg, slot11), + SLOT12 = offsetof(struct ctrl_reg, slot12), +}; +typedef u8(*php_intr_callback_t) (unsigned int change_id, void *instance_id); +struct php_ctlr_state_s { + struct php_ctlr_state_s *pnext; + struct pci_dev *pci_dev; + unsigned int irq; + unsigned long flags; /* spinlock's */ + u32 slot_device_offset; + u32 num_slots; + struct timer_list int_poll_timer; /* Added for poll event */ + 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; + void *callback_instance_id; + void *creg; /* Ptr to controller register space */ +}; +/* 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 *shpchp_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: shpchp_find_slot device=0x%x\n", device); + p_slot = tmp_slot; + } + + return (p_slot); +} + +static inline int wait_for_ctrl_irq (struct controller *ctrl) +{ + DECLARE_WAITQUEUE(wait, current); + int retval = 0; + + dbg("%s : start\n",__FUNCTION__); + + add_wait_queue(&ctrl->queue, &wait); + set_current_state(TASK_INTERRUPTIBLE); + if (!shpchp_poll_mode) { + /* Sleep for up to 1 second */ + schedule_timeout(1*HZ); + } else { + /* Sleep for up to 2 second */ + schedule_timeout(2*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 +}; + +int shpc_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); + + +int shpc_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 (*slot_enable ) (struct slot *slot); + int (*slot_disable ) (struct slot *slot); + int (*enable_all_slots) (struct slot *slot); + int (*pwr_on_all_slots) (struct slot *slot); + int (*set_bus_speed_mode) (struct slot *slot, enum pci_bus_speed speed); + 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_adapter_speed) (struct slot *slot, enum pci_bus_speed *speed); + int (*get_mode1_ECC_cap) (struct slot *slot, u8 *mode); + int (*get_prog_int) (struct slot *slot, u8 *prog_int); + + 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_cmd_status) (struct controller *ctrl); +}; + +#endif /* _SHPCHP_H */ diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/shpchp_core.c linux-2.4.27-pre5/drivers/hotplug/shpchp_core.c --- linux-2.4.26/drivers/hotplug/shpchp_core.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/shpchp_core.c 2004-06-03 01:32:51.000000000 +0000 @@ -0,0 +1,700 @@ +/* + * Standard 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 "shpchp.h" +#include "shpchprm.h" + +/* Global variables */ +int shpchp_debug; +int shpchp_poll_mode; +int shpchp_poll_time; +struct controller *shpchp_ctrl_list; /* = NULL */ +struct pci_func *shpchp_slot_list[256]; + +#define DRIVER_VERSION "0.4" +#define DRIVER_AUTHOR "Dan Zink , Greg Kroah-Hartman , Dely Sy " +#define DRIVER_DESC "Standard Hot Plug PCI Controller Driver" + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +MODULE_PARM(shpchp_debug, "i"); +MODULE_PARM(shpchp_poll_mode, "i"); +MODULE_PARM(shpchp_poll_time, "i"); +MODULE_PARM_DESC(shpchp_debug, "Debugging mode enabled or not"); +MODULE_PARM_DESC(shpchp_poll_mode, "Using polling mechanism for hot-plug events or not"); +MODULE_PARM_DESC(shpchp_poll_time, "Polling mechanism frequency, in seconds"); + +#define SHPC_MODULE_NAME "shpchp.o" + +static int shpc_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 shpchp_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_slots; + u8 slot_device; + u32 slot_number, sun; + int result; + + dbg("%s\n",__FUNCTION__); + + number_of_slots = ctrl->num_slots; + slot_device = ctrl->slot_device_offset; + slot_number = ctrl->first_slot; + + while (number_of_slots) { + new_slot = (struct slot *) kmalloc(sizeof(struct slot), GFP_KERNEL); + if (!new_slot) + return -ENOMEM; + + memset(new_slot, 0, sizeof(struct slot)); + new_slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL); + if (!new_slot->hotplug_slot) { + kfree (new_slot); + return -ENOMEM; + } + memset(new_slot->hotplug_slot, 0, sizeof (struct hotplug_slot)); + + new_slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!new_slot->hotplug_slot->info) { + kfree (new_slot->hotplug_slot); + kfree (new_slot); + return -ENOMEM; + } + memset(new_slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info)); + new_slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL); + if (!new_slot->hotplug_slot->name) { + kfree (new_slot->hotplug_slot->info); + kfree (new_slot->hotplug_slot); + kfree (new_slot); + return -ENOMEM; + } + + new_slot->magic = SLOT_MAGIC; + new_slot->ctrl = ctrl; + new_slot->bus = ctrl->slot_bus; + new_slot->device = slot_device; + new_slot->hpc_ops = ctrl->hpc_ops; + + if (shpchprm_get_physical_slot_number(ctrl, &sun, new_slot->bus, new_slot->device)) { + kfree (new_slot->hotplug_slot->info); + kfree (new_slot->hotplug_slot); + kfree (new_slot); + return -ENOMEM; + } + + new_slot->number = sun; + new_slot->hp_slot = slot_device - ctrl->slot_device_offset; + + /* Register this slot with the hotplug pci core */ + new_slot->hotplug_slot->private = new_slot; + make_slot_name (new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot); + new_slot->hotplug_slot->ops = &shpchp_hotplug_slot_ops; + + new_slot->hpc_ops->get_power_status(new_slot, &(new_slot->hotplug_slot->info->power_status)); + new_slot->hpc_ops->get_attention_status(new_slot, &(new_slot->hotplug_slot->info->attention_status)); + new_slot->hpc_ops->get_latch_status(new_slot, &(new_slot->hotplug_slot->info->latch_status)); + new_slot->hpc_ops->get_adapter_status(new_slot, &(new_slot->hotplug_slot->info->adapter_status)); + + dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x slot_device_offset=%x\n", new_slot->bus, new_slot->device, new_slot->hp_slot, new_slot->number, ctrl->slot_device_offset); + result = pci_hp_register (new_slot->hotplug_slot); + if (result) { + err ("pci_hp_register failed with error %d\n", result); + kfree (new_slot->hotplug_slot->info); + kfree (new_slot->hotplug_slot->name); + kfree (new_slot->hotplug_slot); + kfree (new_slot); + return result; + } + + new_slot->next = ctrl->slot; + ctrl->slot = new_slot; + + number_of_slots--; + slot_device++; + slot_number += ctrl->slot_num_inc; + } + + return(0); +} + + +static int cleanup_slots (struct controller * ctrl) +{ + struct slot *old_slot, *next_slot; + + old_slot = ctrl->slot; + ctrl->slot = NULL; + + while (old_slot) { + next_slot = old_slot->next; + pci_hp_deregister (old_slot->hotplug_slot); + kfree(old_slot->hotplug_slot->info); + kfree(old_slot->hotplug_slot->name); + kfree(old_slot->hotplug_slot); + kfree(old_slot); + old_slot = next_slot; + } + + + return(0); +} + +static int get_ctlr_slot_config(struct controller *ctrl) +{ + int num_ctlr_slots; + int first_device_num; + int physical_slot_num; + int updown; + int rc; + int flags; + + rc = shpc_get_ctlr_slot_config(ctrl, &num_ctlr_slots, &first_device_num, &physical_slot_num, + &updown, &flags); + if (rc) { + err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", __FUNCTION__, ctrl->bus, ctrl->device); + return (-1); + } + + ctrl->num_slots = num_ctlr_slots; + ctrl->slot_device_offset = first_device_num; + ctrl->first_slot = physical_slot_num; + ctrl->slot_num_inc = updown; /* either -1 or 1 */ + + dbg("%s: num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) updown(%d) for b:d (%x:%x)\n", + __FUNCTION__, num_ctlr_slots, first_device_num, physical_slot_num, updown, + ctrl->bus, ctrl->device); + + return (0); +} + + +/* + * set_attention_status - Turns the Amber LED for a slot on, off or blink + */ +static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + hotplug_slot->info->attention_status = status; + slot->hpc_ops->set_attention_status(slot, status); + + + return 0; +} + + +static int enable_slot (struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + return shpchp_enable_slot(slot); +} + + +static int disable_slot (struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + return shpchp_disable_slot(slot); +} + + +static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value) +{ + return 0; +} + + +static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + retval = slot->hpc_ops->get_power_status(slot, value); + if (retval < 0) + *value = hotplug_slot->info->power_status; + + return 0; +} + +static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + retval = slot->hpc_ops->get_attention_status(slot, value); + if (retval < 0) + *value = hotplug_slot->info->attention_status; + + return 0; +} + +static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + retval = slot->hpc_ops->get_latch_status(slot, value); + if (retval < 0) + *value = hotplug_slot->info->latch_status; + + return 0; +} + +static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + retval = slot->hpc_ops->get_adapter_status(slot, value); + + if (retval < 0) + *value = hotplug_slot->info->adapter_status; + + return 0; +} + +static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + retval = slot->hpc_ops->get_max_bus_speed(slot, value); + if (retval < 0) + *value = PCI_SPEED_UNKNOWN; + + return 0; +} + +static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + retval = slot->hpc_ops->get_cur_bus_speed(slot, value); + if (retval < 0) + *value = PCI_SPEED_UNKNOWN; + + return 0; +} + +static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int rc; + struct controller *ctrl; + struct slot *t_slot; + int first_device_num; /* first PCI device number supported by this SHPC */ + int num_ctlr_slots; /* number of slots supported by this SHPC */ + + ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL); + if (!ctrl) { + err("%s : out of memory\n", __FUNCTION__); + goto err_out_none; + } + memset(ctrl, 0, sizeof(struct controller)); + + dbg("DRV_thread pid = %d\n", current->pid); + + rc = shpc_init(ctrl, pdev, + (php_intr_callback_t) shpchp_handle_attention_button, + (php_intr_callback_t) shpchp_handle_switch_change, + (php_intr_callback_t) shpchp_handle_presence_change, + (php_intr_callback_t) shpchp_handle_power_fault); + if (rc) { + dbg("%s: controller initialization failed\n", SHPC_MODULE_NAME); + goto err_out_free_ctrl; + } + + dbg("%s: controller initialization success\n", __FUNCTION__); + ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */ + + ctrl->pci_bus = kmalloc (sizeof (*ctrl->pci_bus), GFP_KERNEL); + if (!ctrl->pci_bus) { + err("out of memory\n"); + rc = -ENOMEM; + goto err_out_unmap_mmio_region; + } + memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus)); + ctrl->bus = pdev->bus->number; + ctrl->slot_bus = pdev->subordinate->number; + + ctrl->device = PCI_SLOT(pdev->devfn); + ctrl->function = PCI_FUNC(pdev->devfn); + dbg("ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", ctrl->bus, ctrl->device, + ctrl->function, pdev->irq); + + /* + * Save configuration headers for this and subordinate PCI buses + */ + + rc = get_ctlr_slot_config(ctrl); + if (rc) { + err(msg_initialization_err, rc); + goto err_out_free_ctrl_bus; + } + first_device_num = ctrl->slot_device_offset; + num_ctlr_slots = ctrl->num_slots; + + /* Store PCI Config Space for all devices on this bus */ + rc = shpchp_save_config(ctrl, ctrl->slot_bus, num_ctlr_slots, first_device_num); + if (rc) { + err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc); + goto err_out_free_ctrl_bus; + } + + /* Get IO, memory, and IRQ resources for new devices */ + rc = shpchprm_find_available_resources(ctrl); + ctrl->add_support = !rc; + + if (rc) { + dbg("shpchprm_find_available_resources = %#x\n", rc); + err("unable to locate PCI configuration resources for hot plug add.\n"); + goto err_out_free_ctrl_bus; + } + + /* Setup the slot information structures */ + rc = init_slots(ctrl); + if (rc) { + err(msg_initialization_err, 6); + goto err_out_free_ctrl_slot; + } + + /* Now hpc_functions (slot->hpc_ops->functions) are ready */ + t_slot = shpchp_find_slot(ctrl, first_device_num); + + /* Check for operation bus speed */ + rc = t_slot->hpc_ops->get_cur_bus_speed(t_slot, &ctrl->speed); + dbg("%s: t_slot->hp_slot %x\n", __FUNCTION__,t_slot->hp_slot); + + if (rc || ctrl->speed == PCI_SPEED_UNKNOWN) { + err(SHPC_MODULE_NAME ": Can't get current bus speed. Set to 33MHz PCI.\n"); + ctrl->speed = PCI_SPEED_33MHz; + } + + /* Finish setting up the hot plug ctrl device */ + ctrl->next_event = 0; + + if (!shpchp_ctrl_list) { + shpchp_ctrl_list = ctrl; + ctrl->next = NULL; + } else { + ctrl->next = shpchp_ctrl_list; + shpchp_ctrl_list = ctrl; + } + + return 0; + +err_out_free_ctrl_slot: + cleanup_slots(ctrl); +err_out_free_ctrl_bus: + kfree(ctrl->pci_bus); +err_out_unmap_mmio_region: + ctrl->hpc_ops->release_ctlr(ctrl); +err_out_free_ctrl: + kfree(ctrl); +err_out_none: + return -ENODEV; +} + + +static int shpc_start_thread(void) +{ + int loop; + int retval = 0; + + dbg("Initialize + Start the notification/polling mechanism \n"); + + retval = shpchp_event_start_thread(); + if (retval) { + dbg("shpchp_event_start_thread() failed\n"); + return retval; + } + + dbg("Initialize slot lists\n"); + /* One slot list for each bus in the system */ + for (loop = 0; loop < 256; loop++) { + shpchp_slot_list[loop] = NULL; + } + + return retval; +} + + +static void unload_shpchpd(void) +{ + struct pci_func *next; + struct pci_func *TempSlot; + int loop; + struct controller *ctrl; + struct controller *tctrl; + struct pci_resource *res; + struct pci_resource *tres; + + ctrl = shpchp_ctrl_list; + + while (ctrl) { + cleanup_slots(ctrl); + + res = ctrl->io_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = ctrl->mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = ctrl->p_mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = ctrl->bus_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + kfree (ctrl->pci_bus); + + dbg("%s: calling release_ctlr\n", __FUNCTION__); + ctrl->hpc_ops->release_ctlr(ctrl); + + tctrl = ctrl; + ctrl = ctrl->next; + + kfree(tctrl); + } + + for (loop = 0; loop < 256; loop++) { + next = shpchp_slot_list[loop]; + while (next != NULL) { + res = next->io_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = next->mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = next->p_mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = next->bus_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + TempSlot = next; + next = next->next; + kfree(TempSlot); + } + } + + /* Stop the notification mechanism */ + shpchp_event_stop_thread(); + +} + + +static struct pci_device_id shpcd_pci_tbl[] __devinitdata = { + { + .class = ((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), + .class_mask = ~0, + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { /* end: all zeroes */ } +}; + +MODULE_DEVICE_TABLE(pci, shpcd_pci_tbl); + + + +static struct pci_driver shpc_driver = { + .name = SHPC_MODULE_NAME, + .id_table = shpcd_pci_tbl, + .probe = shpc_probe, + /* remove: shpc_remove_one, */ +}; + + + +static int __init shpcd_init(void) +{ + int retval = 0; + +#ifdef CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE + shpchp_poll_mode = 1; +#endif + + retval = shpc_start_thread(); + if (retval) + goto error_hpc_init; + + retval = shpchprm_init(PCI); + if (!retval) { + retval = pci_module_init(&shpc_driver); + dbg("%s: pci_module_init = %d\n", __FUNCTION__,retval); + info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); + } + +error_hpc_init: + if (retval) { + shpchprm_cleanup(); + shpchp_event_stop_thread(); + } else + shpchprm_print_pirt(); + + return retval; +} + +static void __exit shpcd_cleanup(void) +{ + dbg("unload_shpchpd()\n"); + unload_shpchpd(); + + shpchprm_cleanup(); + + dbg("pci_unregister_driver\n"); + pci_unregister_driver(&shpc_driver); + + info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); +} + + +module_init(shpcd_init); +module_exit(shpcd_cleanup); + + diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/shpchp_ctrl.c linux-2.4.27-pre5/drivers/hotplug/shpchp_ctrl.c --- linux-2.4.26/drivers/hotplug/shpchp_ctrl.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/shpchp_ctrl.c 2004-06-03 01:35:59.000000000 +0000 @@ -0,0 +1,3071 @@ +/* + * Standard 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 "shpchp.h" +#include "shpchprm.h" + +static u32 configure_new_device(struct controller *ctrl, struct pci_func *func, + u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev); +static int configure_new_function( struct controller *ctrl, struct pci_func *func, + u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev); +static void interrupt_event_handler(struct controller *ctrl); + +static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ +static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */ +static int event_finished; +static unsigned long pushbutton_pending; /* = 0 */ + +u8 shpchp_disk_irq; +u8 shpchp_nic_irq; + +u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id) +{ + struct controller *ctrl = (struct controller *) inst_id; + struct slot *p_slot; + u8 rc = 0; + u8 getstatus; + struct pci_func *func; + struct event_info *taskInfo; + + /* Attention Button Change */ + dbg("shpchp: Attention button interrupt received.\n"); + + func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); + + /* This is the structure that tells the worker thread what to do */ + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + + p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); + p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); + + ctrl->next_event = (ctrl->next_event + 1) % 10; + taskInfo->hp_slot = hp_slot; + + rc++; + + /* + * Button pressed - See if need to TAKE ACTION!!! + */ + info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot); + taskInfo->event_type = INT_BUTTON_PRESS; + + if ((p_slot->state == BLINKINGON_STATE) + || (p_slot->state == BLINKINGOFF_STATE)) { + /* Cancel if we are still blinking; this means that we press the + * attention again before the 5 sec. limit expires to cancel hot-add + * or hot-remove + */ + taskInfo->event_type = INT_BUTTON_CANCEL; + info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot); + } else if ((p_slot->state == POWERON_STATE) + || (p_slot->state == POWEROFF_STATE)) { + /* Ignore if the slot is on power-on or power-off state; this + * means that the previous attention button action to hot-add or + * hot-remove is undergoing + */ + taskInfo->event_type = INT_BUTTON_IGNORE; + info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot); + } + + if (rc) + up(&event_semaphore); /* Signal event thread that new event is posted */ + + return 0; + +} + +u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) +{ + struct controller *ctrl = (struct controller *) inst_id; + struct slot *p_slot; + u8 rc = 0; + u8 getstatus; + struct pci_func *func; + struct event_info *taskInfo; + + /* Switch Change */ + dbg("shpchp: Switch interrupt received.\n"); + + func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); + + /* This is the structure that tells the worker thread + * what to do + */ + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + ctrl->next_event = (ctrl->next_event + 1) % 10; + taskInfo->hp_slot = hp_slot; + + rc++; + p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); + p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); + + if (getstatus) { + /* + * Switch opened + */ + info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot); + func->switch_save = 0; + taskInfo->event_type = INT_SWITCH_OPEN; + } else { + /* + * Switch closed + */ + info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot); + func->switch_save = 0x10; + taskInfo->event_type = INT_SWITCH_CLOSE; + } + + if (rc) + up(&event_semaphore); /* Signal event thread that new event is posted */ + + return rc; +} + +u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id) +{ + struct controller *ctrl = (struct controller *) inst_id; + struct slot *p_slot; + u8 rc = 0; + struct pci_func *func; + struct event_info *taskInfo; + + /* Presence Change */ + dbg("shpchp: Presence/Notify input change.\n"); + + func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); + + /* This is the structure that tells the worker thread + * what to do + */ + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + ctrl->next_event = (ctrl->next_event + 1) % 10; + taskInfo->hp_slot = hp_slot; + + rc++; + p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + + /* + * Save the presence state + */ + p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); + if (func->presence_save) { + /* + * Card Present + */ + info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot); + taskInfo->event_type = INT_PRESENCE_ON; + } else { + /* + * Not Present + */ + info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot); + taskInfo->event_type = INT_PRESENCE_OFF; + } + + if (rc) + up(&event_semaphore); /* Signal event thread that new event is posted */ + + return rc; +} + +u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) +{ + struct controller *ctrl = (struct controller *) inst_id; + struct slot *p_slot; + u8 rc = 0; + struct pci_func *func; + struct event_info *taskInfo; + + /* Power fault */ + dbg("shpchp: Power fault interrupt received.\n"); + + func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); + + /* This is the structure that tells the worker thread + * what to do + */ + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + ctrl->next_event = (ctrl->next_event + 1) % 10; + taskInfo->hp_slot = hp_slot; + + rc++; + p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + + if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { + /* + * Power fault Cleared + */ + info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot); + func->status = 0x00; + taskInfo->event_type = INT_POWER_FAULT_CLEAR; + } else { + /* + * Power fault + */ + info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot); + taskInfo->event_type = INT_POWER_FAULT; + /* Set power fault status for this board */ + func->status = 0xFF; + info("power fault bit %x set\n", hp_slot); + } + if (rc) + up(&event_semaphore); /* Signal event thread that new event is posted */ + + return rc; +} + + +/* + * sort_by_size + * + * Sorts nodes on the list by their length. + * Smallest first. + * + */ +static int sort_by_size(struct pci_resource **head) +{ + struct pci_resource *current_res; + struct pci_resource *next_res; + int out_of_order = 1; + + if (!(*head)) + return(1); + + if (!((*head)->next)) + return(0); + + while (out_of_order) { + out_of_order = 0; + + /* Special case for swapping list head */ + if (((*head)->next) && + ((*head)->length > (*head)->next->length)) { + out_of_order++; + current_res = *head; + *head = (*head)->next; + current_res->next = (*head)->next; + (*head)->next = current_res; + } + + current_res = *head; + + while (current_res->next && current_res->next->next) { + if (current_res->next->length > current_res->next->next->length) { + out_of_order++; + next_res = current_res->next; + current_res->next = current_res->next->next; + current_res = current_res->next; + next_res->next = current_res->next; + current_res->next = next_res; + } else + current_res = current_res->next; + } + } /* End of out_of_order loop */ + + return(0); +} + + +/* + * sort_by_max_size + * + * Sorts nodes on the list by their length. + * Largest first. + * + */ +static int sort_by_max_size(struct pci_resource **head) +{ + struct pci_resource *current_res; + struct pci_resource *next_res; + int out_of_order = 1; + + if (!(*head)) + return(1); + + if (!((*head)->next)) + return(0); + + while (out_of_order) { + out_of_order = 0; + + /* Special case for swapping list head */ + if (((*head)->next) && + ((*head)->length < (*head)->next->length)) { + out_of_order++; + current_res = *head; + *head = (*head)->next; + current_res->next = (*head)->next; + (*head)->next = current_res; + } + + current_res = *head; + + while (current_res->next && current_res->next->next) { + if (current_res->next->length < current_res->next->next->length) { + out_of_order++; + next_res = current_res->next; + current_res->next = current_res->next->next; + current_res = current_res->next; + next_res->next = current_res->next; + current_res->next = next_res; + } else + current_res = current_res->next; + } + } /* End of out_of_order loop */ + + return(0); +} + + +/* + * do_pre_bridge_resource_split + * + * Returns zero or one node of resources that aren't in use + * + */ +static struct pci_resource *do_pre_bridge_resource_split (struct pci_resource **head, struct pci_resource **orig_head, u32 alignment) +{ + struct pci_resource *prevnode = NULL; + struct pci_resource *node; + struct pci_resource *split_node; + u32 rc; + u32 temp_dword; + dbg("do_pre_bridge_resource_split\n"); + + if (!(*head) || !(*orig_head)) + return(NULL); + + rc = shpchp_resource_sort_and_combine(head); + + if (rc) + return(NULL); + + if ((*head)->base != (*orig_head)->base) + return(NULL); + + if ((*head)->length == (*orig_head)->length) + return(NULL); + + + /* If we got here, there the bridge requires some of the resource, but + * we may be able to split some off of the front + */ + node = *head; + + if (node->length & (alignment -1)) { + /* This one isn't an aligned length, so we'll make a new entry + * and split it up. + */ + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + temp_dword = (node->length | (alignment-1)) + 1 - alignment; + + split_node->base = node->base; + split_node->length = temp_dword; + + node->length -= temp_dword; + node->base += split_node->length; + + /* Put it in the list */ + *head = split_node; + split_node->next = node; + } + + if (node->length < alignment) { + return(NULL); + } + + /* Now unlink it */ + if (*head == node) { + *head = node->next; + node->next = NULL; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + node->next = NULL; + } + + return(node); +} + + +/* + * do_bridge_resource_split + * + * Returns zero or one node of resources that aren't in use + * + */ +static struct pci_resource *do_bridge_resource_split (struct pci_resource **head, u32 alignment) +{ + struct pci_resource *prevnode = NULL; + struct pci_resource *node; + u32 rc; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + rc = shpchp_resource_sort_and_combine(head); + + if (rc) + return(NULL); + + node = *head; + + while (node->next) { + prevnode = node; + node = node->next; + kfree(prevnode); + } + + if (node->length < alignment) { + kfree(node); + return(NULL); + } + + if (node->base & (alignment - 1)) { + /* Short circuit if adjusted size is too small */ + temp_dword = (node->base | (alignment-1)) + 1; + if ((node->length - (temp_dword - node->base)) < alignment) { + kfree(node); + return(NULL); + } + + node->length -= (temp_dword - node->base); + node->base = temp_dword; + } + + if (node->length & (alignment - 1)) { + /* There's stuff in use after this node */ + kfree(node); + return(NULL); + } + + return(node); +} + + +/* + * get_io_resource + * + * this function sorts the resource list by size and then + * returns the first node of "size" length that is not in the + * ISA aliasing window. If it finds a node larger than "size" + * it will split it up. + * + * size must be a power of two. + */ +static struct pci_resource *get_io_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node = NULL; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if ( shpchp_resource_sort_and_combine(head) ) + return(NULL); + + if ( sort_by_size(head) ) + return(NULL); + + for (node = *head; node; node = node->next) { + if (node->length < size) + continue; + + if (node->base & (size - 1)) { + /* This one isn't base aligned properly + so we'll make a new entry and split it up */ + temp_dword = (node->base | (size-1)) + 1; + + /*/ Short circuit if adjusted size is too small */ + if ((node->length - (temp_dword - node->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base; + split_node->length = temp_dword - node->base; + node->base = temp_dword; + node->length -= split_node->length; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of non-aligned base */ + + /* Don't need to check if too small since we already did */ + if (node->length > size) { + /* This one is longer than we need + so we'll make a new entry and split it up */ + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base + size; + split_node->length = node->length - size; + node->length = size; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of too big on top end */ + + /* For IO make sure it's not in the ISA aliasing space */ + if (node->base & 0x300L) + continue; + + /* If we got here, then it is the right size + Now take it out of the list */ + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + /* Stop looping */ + break; + } + + return(node); +} + + +/* + * get_max_resource + * + * Gets the largest node that is at least "size" big from the + * list pointed to by head. It aligns the node on top and bottom + * to "size" alignment before returning it. + * J.I. modified to put max size limits of; 64M->32M->16M->8M->4M->1M + * This is needed to avoid allocating entire ACPI _CRS res to one child bridge/slot. + */ +static struct pci_resource *get_max_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *max; + struct pci_resource *temp; + struct pci_resource *split_node; + u32 temp_dword; + u32 max_size[] = { 0x4000000, 0x2000000, 0x1000000, 0x0800000, 0x0400000, 0x0200000, 0x0100000, 0x00 }; + int i; + + if (!(*head)) + return(NULL); + + if (shpchp_resource_sort_and_combine(head)) + return(NULL); + + if (sort_by_max_size(head)) + return(NULL); + + for (max = *head;max; max = max->next) { + + /* If not big enough we could probably just bail, + instead we'll continue to the next. */ + if (max->length < size) + continue; + + if (max->base & (size - 1)) { + /* this one isn't base aligned properly + so we'll make a new entry and split it up */ + temp_dword = (max->base | (size-1)) + 1; + + /* Short circuit if adjusted size is too small */ + if ((max->length - (temp_dword - max->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = max->base; + split_node->length = temp_dword - max->base; + max->base = temp_dword; + max->length -= split_node->length; + + /* Put it next in the list */ + split_node->next = max->next; + max->next = split_node; + } + + if ((max->base + max->length) & (size - 1)) { + /* this one isn't end aligned properly at the top + so we'll make a new entry and split it up */ + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + temp_dword = ((max->base + max->length) & ~(size - 1)); + split_node->base = temp_dword; + split_node->length = max->length + max->base + - split_node->base; + max->length -= split_node->length; + + /* Put it in the list */ + split_node->next = max->next; + max->next = split_node; + } + + /* Make sure it didn't shrink too much when we aligned it */ + if (max->length < size) + continue; + + for ( i = 0; max_size[i] > size; i++) { + if (max->length > max_size[i]) { + split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), + GFP_KERNEL); + if (!split_node) + break; /* return (NULL); */ + split_node->base = max->base + max_size[i]; + split_node->length = max->length - max_size[i]; + max->length = max_size[i]; + /* Put it next in the list */ + split_node->next = max->next; + max->next = split_node; + break; + } + } + + /* Now take it out of the list */ + temp = (struct pci_resource*) *head; + if (temp == max) { + *head = max->next; + } else { + while (temp && temp->next != max) { + temp = temp->next; + } + + temp->next = max->next; + } + + max->next = NULL; + return(max); + } + + /* If we get here, we couldn't find one */ + return(NULL); +} + + +/* + * get_resource + * + * this function sorts the resource list by size and then + * returns the first node of "size" length. If it finds a node + * larger than "size" it will split it up. + * + * size must be a power of two. + */ +static struct pci_resource *get_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if ( shpchp_resource_sort_and_combine(head) ) + return(NULL); + + if ( sort_by_size(head) ) + return(NULL); + + for (node = *head; node; node = node->next) { + dbg("%s: req_size =0x%x node=%p, base=0x%x, length=0x%x\n", + __FUNCTION__, size, node, node->base, node->length); + if (node->length < size) + continue; + + if (node->base & (size - 1)) { + dbg("%s: not aligned\n", __FUNCTION__); + /* This one isn't base aligned properly + so we'll make a new entry and split it up */ + temp_dword = (node->base | (size-1)) + 1; + + /* Short circuit if adjusted size is too small */ + if ((node->length - (temp_dword - node->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base; + split_node->length = temp_dword - node->base; + node->base = temp_dword; + node->length -= split_node->length; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of non-aligned base */ + + /* Don't need to check if too small since we already did */ + if (node->length > size) { + dbg("%s: too big\n", __FUNCTION__); + /* This one is longer than we need + so we'll make a new entry and split it up */ + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base + size; + split_node->length = node->length - size; + node->length = size; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of too big on top end */ + + dbg("%s: got one!!!\n", __FUNCTION__); + /* If we got here, then it is the right size + Now take it out of the list */ + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + /* Stop looping */ + break; + } + return(node); +} + + +/* + * shpchp_resource_sort_and_combine + * + * Sorts all of the nodes in the list in ascending order by + * their base addresses. Also does garbage collection by + * combining adjacent nodes. + * + * returns 0 if success + */ +int shpchp_resource_sort_and_combine(struct pci_resource **head) +{ + struct pci_resource *node1; + struct pci_resource *node2; + int out_of_order = 1; + + dbg("%s: head = %p, *head = %p\n", __FUNCTION__, head, *head); + + if (!(*head)) + return(1); + + dbg("*head->next = %p\n",(*head)->next); + + if (!(*head)->next) + return(0); /* only one item on the list, already sorted! */ + + dbg("*head->base = 0x%x\n",(*head)->base); + dbg("*head->next->base = 0x%x\n",(*head)->next->base); + while (out_of_order) { + out_of_order = 0; + + /* Special case for swapping list head */ + if (((*head)->next) && + ((*head)->base > (*head)->next->base)) { + node1 = *head; + (*head) = (*head)->next; + node1->next = (*head)->next; + (*head)->next = node1; + out_of_order++; + } + + node1 = (*head); + + while (node1->next && node1->next->next) { + if (node1->next->base > node1->next->next->base) { + out_of_order++; + node2 = node1->next; + node1->next = node1->next->next; + node1 = node1->next; + node2->next = node1->next; + node1->next = node2; + } else + node1 = node1->next; + } + } /* End of out_of_order loop */ + + node1 = *head; + + while (node1 && node1->next) { + if ((node1->base + node1->length) == node1->next->base) { + /* Combine */ + dbg("8..\n"); + node1->length += node1->next->length; + node2 = node1->next; + node1->next = node1->next->next; + kfree(node2); + } else + node1 = node1->next; + } + + return(0); +} + + +/** + * shpchp_slot_create - Creates a node and adds it to the proper bus. + * @busnumber - bus where new node is to be located + * + * Returns pointer to the new node or NULL if unsuccessful + */ +struct pci_func *shpchp_slot_create(u8 busnumber) +{ + struct pci_func *new_slot; + struct pci_func *next; + + new_slot = (struct pci_func *) kmalloc(sizeof(struct pci_func), GFP_KERNEL); + + if (new_slot == NULL) { + return(new_slot); + } + + memset(new_slot, 0, sizeof(struct pci_func)); + + new_slot->next = NULL; + new_slot->configured = 1; + + if (shpchp_slot_list[busnumber] == NULL) { + shpchp_slot_list[busnumber] = new_slot; + } else { + next = shpchp_slot_list[busnumber]; + while (next->next != NULL) + next = next->next; + next->next = new_slot; + } + return(new_slot); +} + + +/* + * slot_remove - Removes a node from the linked list of slots. + * @old_slot: slot to remove + * + * Returns 0 if successful, !0 otherwise. + */ +static int slot_remove(struct pci_func * old_slot) +{ + struct pci_func *next; + + if (old_slot == NULL) + return(1); + + next = shpchp_slot_list[old_slot->bus]; + + if (next == NULL) { + return(1); + } + + if (next == old_slot) { + shpchp_slot_list[old_slot->bus] = old_slot->next; + shpchp_destroy_board_resources(old_slot); + kfree(old_slot); + return(0); + } + + while ((next->next != old_slot) && (next->next != NULL)) { + next = next->next; + } + + if (next->next == old_slot) { + next->next = old_slot->next; + shpchp_destroy_board_resources(old_slot); + kfree(old_slot); + return(0); + } else + return(2); +} + + +/** + * bridge_slot_remove - Removes a node from the linked list of slots. + * @bridge: bridge to remove + * + * Returns 0 if successful, !0 otherwise. + */ +static int bridge_slot_remove(struct pci_func *bridge) +{ + u8 subordinateBus, secondaryBus; + u8 tempBus; + struct pci_func *next; + + if (bridge == NULL) + return(1); + + secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF; + subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF; + + for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) { + next = shpchp_slot_list[tempBus]; + + while (!slot_remove(next)) { + next = shpchp_slot_list[tempBus]; + } + } + + next = shpchp_slot_list[bridge->bus]; + + if (next == NULL) { + return(1); + } + + if (next == bridge) { + shpchp_slot_list[bridge->bus] = bridge->next; + kfree(bridge); + return(0); + } + + while ((next->next != bridge) && (next->next != NULL)) { + next = next->next; + } + + if (next->next == bridge) { + next->next = bridge->next; + kfree(bridge); + return(0); + } else + return(2); +} + + +/** + * shpchp_slot_find - Looks for a node by bus, and device, multiple functions accessed + * @bus: bus to find + * @device: device to find + * @index: is 0 for first function found, 1 for the second... + * + * Returns pointer to the node if successful, %NULL otherwise. + */ +struct pci_func *shpchp_slot_find(u8 bus, u8 device, u8 index) +{ + int found = -1; + struct pci_func *func; + + func = shpchp_slot_list[bus]; + + if ((func == NULL) || ((func->device == device) && (index == 0))) + return(func); + + if (func->device == device) + found++; + + while (func->next != NULL) { + func = func->next; + + if (func->device == device) + found++; + + if (found == index) + return(func); + } + + return(NULL); +} + +static int is_bridge(struct pci_func * func) +{ + /* Check the header type */ + if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01) { + dbg("%s: Is a bridge\n", __FUNCTION__); + return 1; + } else { + dbg("%s: Not a bridge\n", __FUNCTION__); + return 0; + } +} + + +/* the following routines constitute the bulk of the + hotplug controller logic + */ + + +/** + * board_added - Called after a board has been added to the system. + * + * Turns power on for the board + * Configures board + * + */ +static u32 board_added(struct pci_func * func, struct controller * ctrl) +{ + u8 hp_slot, slot; + u8 slots_not_empty = 0; + int index; + u32 temp_register = 0xFFFFFFFF; + u32 retval, rc = 0; + struct pci_func *new_func = NULL; + struct pci_func *t_func = NULL; + struct slot *p_slot, *pslot; + struct resource_lists res_lists; + enum pci_bus_speed adapter_speed, bus_speed, max_bus_speed; + u8 pi, mode; + + p_slot = shpchp_find_slot(ctrl, func->device); + hp_slot = func->device - ctrl->slot_device_offset; + + dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n", __FUNCTION__, + func->device, ctrl->slot_device_offset, hp_slot); + + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + /* Power on slot without connecting to bus */ + rc = p_slot->hpc_ops->power_on_slot(p_slot); + if (rc) { + err("%s: Failed to power on slot\n", __FUNCTION__); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return -1; + } + + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + rc = p_slot->hpc_ops->check_cmd_status(ctrl); + if (rc) { + err("%s: Failed to power on slot, error code(%d)\n", __FUNCTION__, rc); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return -1; + } + + rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &adapter_speed); + /* 0 = PCI 33Mhz, 1 = PCI 66 Mhz, 2 = PCI-X 66 PA, 4 = PCI-X 66 ECC, */ + /* 5 = PCI-X 133 PA, 7 = PCI-X 133 ECC, 0xa = PCI-X 133 Mhz 266, */ + /* 0xd = PCI-X 133 Mhz 533 */ + /* This encoding is different from the one used in cur_bus_speed & */ + /* max_bus_speed */ + + if (rc || adapter_speed == PCI_SPEED_UNKNOWN) { + err("%s: Can't get adapter speed or bus mode mismatch\n", __FUNCTION__); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return WRONG_BUS_FREQUENCY; + } + + rc = p_slot->hpc_ops->get_cur_bus_speed(p_slot, &bus_speed); + if (rc || bus_speed == PCI_SPEED_UNKNOWN) { + err("%s: Can't get bus operation speed\n", __FUNCTION__); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return WRONG_BUS_FREQUENCY; + } + + rc = p_slot->hpc_ops->get_max_bus_speed(p_slot, &max_bus_speed); + if (rc || max_bus_speed == PCI_SPEED_UNKNOWN) { + err("%s: Can't get max bus operation speed\n", __FUNCTION__); + max_bus_speed = bus_speed; + } + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + + rc = p_slot->hpc_ops->get_prog_int(p_slot, &pi); + if (rc) { + err("%s: Can't get controller programming interface, set it to 1\n", __FUNCTION__); + pi = 1; + } + + if (pi == 2) { + for ( slot = 0; slot < ctrl->num_slots; slot++) { + if (slot != hp_slot) { + pslot = shpchp_find_slot(ctrl, slot + ctrl->slot_device_offset); + t_func = shpchp_slot_find(pslot->bus, pslot->device, 0); + slots_not_empty |= t_func->is_a_board; + } + } + + switch (adapter_speed) { + case PCI_SPEED_133MHz_PCIX_533: + case PCI_SPEED_133MHz_PCIX_266: + if ((( bus_speed < 0xa ) || (bus_speed < 0xd)) && (max_bus_speed > bus_speed) && + ((max_bus_speed <= 0xa) || (max_bus_speed <= 0xd)) && (!slots_not_empty)) { + + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, max_bus_speed); + if (rc) { + err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return WRONG_BUS_FREQUENCY; + } + + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); + + rc = p_slot->hpc_ops->check_cmd_status(ctrl); + if (rc) { + err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n", + __FUNCTION__); + err("%s: Error code (%d)\n", __FUNCTION__, rc); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return WRONG_BUS_FREQUENCY; + } + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + } + break; + case PCI_SPEED_133MHz_PCIX_ECC: + case PCI_SPEED_133MHz_PCIX: + + rc = p_slot->hpc_ops->get_mode1_ECC_cap(p_slot, &mode); + + if (rc) { + err("%s: PI is 1 \n", __FUNCTION__); + return WRONG_BUS_FREQUENCY; + } + + if (mode) { /* Bus - Mode 1 ECC */ + + if (bus_speed > 0x7) { + err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed); + return WRONG_BUS_FREQUENCY; + } + + if ((bus_speed < 0x7) && (max_bus_speed <= 0x7) && + (bus_speed < max_bus_speed) && (!slots_not_empty)) { + + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, max_bus_speed); + if (rc) { + err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return WRONG_BUS_FREQUENCY; + } + + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); + + rc = p_slot->hpc_ops->check_cmd_status(ctrl); + if (rc) { + err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n", + __FUNCTION__); + err("%s: Error code (%d)\n", __FUNCTION__, rc); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return WRONG_BUS_FREQUENCY; + } + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + } + } else { + if (bus_speed > 0x4) { + err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed); + return WRONG_BUS_FREQUENCY; + } + + if ((bus_speed < 0x4) && (max_bus_speed <= 0x4) && + (bus_speed < max_bus_speed) && (!slots_not_empty)) { + + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, max_bus_speed); + if (rc) { + err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return WRONG_BUS_FREQUENCY; + } + + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); + + rc = p_slot->hpc_ops->check_cmd_status(ctrl); + if (rc) { + err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n", + __FUNCTION__); + err("%s: Error code (%d)\n", __FUNCTION__, rc); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return WRONG_BUS_FREQUENCY; + } + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + } + } + break; + case PCI_SPEED_66MHz_PCIX_ECC: + case PCI_SPEED_66MHz_PCIX: + + rc = p_slot->hpc_ops->get_mode1_ECC_cap(p_slot, &mode); + + if (rc) { + err("%s: PI is 1 \n", __FUNCTION__); + return WRONG_BUS_FREQUENCY; + } + + if (mode) { /* Bus - Mode 1 ECC */ + + if (bus_speed > 0x5) { + err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed); + return WRONG_BUS_FREQUENCY; + } + + if ((bus_speed < 0x5) && (max_bus_speed <= 0x5) && + (bus_speed < max_bus_speed) && (!slots_not_empty)) { + + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, max_bus_speed); + if (rc) { + err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return WRONG_BUS_FREQUENCY; + } + + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); + + rc = p_slot->hpc_ops->check_cmd_status(ctrl); + if (rc) { + err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n", + __FUNCTION__); + err("%s: Error code (%d)\n", __FUNCTION__, rc); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return WRONG_BUS_FREQUENCY; + } + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + } + } else { + if (bus_speed > 0x2) { + err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed); + return WRONG_BUS_FREQUENCY; + } + + if ((bus_speed < 0x2) && (max_bus_speed <= 0x2) && + (bus_speed < max_bus_speed) && (!slots_not_empty)) { + + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, max_bus_speed); + if (rc) { + err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return WRONG_BUS_FREQUENCY; + } + + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); + + rc = p_slot->hpc_ops->check_cmd_status(ctrl); + if (rc) { + err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n", + __FUNCTION__); + err("%s: Error code (%d)\n", __FUNCTION__, rc); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return WRONG_BUS_FREQUENCY; + } + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + } + } + break; + case PCI_SPEED_66MHz: + if (bus_speed > 0x1) { + err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed); + return WRONG_BUS_FREQUENCY; + } + if (bus_speed == 0x1) + ; + if ((bus_speed == 0x0) && ( max_bus_speed == 0x1)) { + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, max_bus_speed); + if (rc) { + err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return WRONG_BUS_FREQUENCY; + } + + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); + + rc = p_slot->hpc_ops->check_cmd_status(ctrl); + if (rc) { + err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n", + __FUNCTION__); + err("%s: Error code (%d)\n", __FUNCTION__, rc); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return WRONG_BUS_FREQUENCY; + } + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + } + break; + case PCI_SPEED_33MHz: + if (bus_speed > 0x0) { + err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed); + return WRONG_BUS_FREQUENCY; + } + break; + default: + err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed); + return WRONG_BUS_FREQUENCY; + } + } else { + /* if adpater_speed == bus_speed, nothing to do here */ + if (adapter_speed != bus_speed) { + for ( slot = 0; slot < ctrl->num_slots; slot++) { + if (slot != hp_slot) { + pslot = shpchp_find_slot(ctrl, slot + ctrl->slot_device_offset); + t_func = shpchp_slot_find(pslot->bus, pslot->device, 0); + slots_not_empty |= t_func->is_a_board; + } + } + + if (slots_not_empty != 0) { /* Other slots on the same bus are occupied */ + if ( adapter_speed < bus_speed ) { + err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed); + return WRONG_BUS_FREQUENCY; + } + /* Do nothing if adapter_speed >= bus_speed */ + } + } + + if ((adapter_speed != bus_speed) && (slots_not_empty == 0)) { + /* Other slots on the same bus are empty */ + + rc = p_slot->hpc_ops->get_max_bus_speed(p_slot, &max_bus_speed); + if (rc || max_bus_speed == PCI_SPEED_UNKNOWN) { + err("%s: Can't get max bus operation speed\n", __FUNCTION__); + max_bus_speed = bus_speed; + } + + if (max_bus_speed == bus_speed) { + /* if adapter_speed >= bus_speed, do nothing */ + if (adapter_speed < bus_speed) { + /* + * Try to lower bus speed to accommodate the adapter if other slots + * on the same controller are empty + */ + + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, adapter_speed); + if (rc) { + err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); + return WRONG_BUS_FREQUENCY; + } + + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); + + rc = p_slot->hpc_ops->check_cmd_status(ctrl); + if (rc) { + err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n", + __FUNCTION__); + err("%s: Error code (%d)\n", __FUNCTION__, rc); + return WRONG_BUS_FREQUENCY; + } + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + + } + } else { + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + /* max_bus_speed != bus_speed. Note: max_bus_speed should be > than bus_speed */ + if (adapter_speed < max_bus_speed) + rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, adapter_speed); + else + rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, max_bus_speed); + + if (rc) { + err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return WRONG_BUS_FREQUENCY; + } + + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); + + rc = p_slot->hpc_ops->check_cmd_status(ctrl); + if (rc) { + err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n", + __FUNCTION__); + err("%s: Error code (%d)\n", __FUNCTION__, rc); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return WRONG_BUS_FREQUENCY; + } + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + + } + } + } + + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + /* Turn on board, blink green LED, turn off Amber LED */ + rc = p_slot->hpc_ops->slot_enable(p_slot); + + if (rc) { + err("%s: Issue of Slot Enable command failed\n", __FUNCTION__); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return rc; + } + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); + + rc = p_slot->hpc_ops->check_cmd_status(ctrl); + if (rc) { + err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return rc; + } + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + + /* Wait for ~1 second */ + dbg("%s: before long_delay\n", __FUNCTION__); + wait_for_ctrl_irq (ctrl); + dbg("%s: afterlong_delay\n", __FUNCTION__); + + dbg("%s: func status = %x\n", __FUNCTION__, func->status); + /* Check for a power fault */ + if (func->status == 0xFF) { + /* power fault occurred, but it was benign */ + temp_register = 0xFFFFFFFF; + dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register); + rc = POWER_FAILURE; + func->status = 0; + } else { + /* Get vendor/device ID u32 */ + rc = pci_bus_read_config_dword (ctrl->pci_dev->subordinate, PCI_DEVFN(func->device, func->function), PCI_VENDOR_ID, &temp_register); + dbg("%s: pci_bus_read_config_dword returns %d\n", __FUNCTION__, rc); + dbg("%s: temp_register is %x\n", __FUNCTION__, temp_register); + + if (rc != 0) { + /* Something's wrong here */ + temp_register = 0xFFFFFFFF; + dbg("%s: temp register set to %x by error\n", __FUNCTION__, temp_register); + } + /* Preset return code. It will be changed later if things go okay. */ + rc = NO_ADAPTER_PRESENT; + } + + /* All F's is an empty slot or an invalid board */ + if (temp_register != 0xFFFFFFFF) { /* Check for a board in the slot */ + res_lists.io_head = ctrl->io_head; + res_lists.mem_head = ctrl->mem_head; + res_lists.p_mem_head = ctrl->p_mem_head; + res_lists.bus_head = ctrl->bus_head; + res_lists.irqs = NULL; + + rc = configure_new_device(ctrl, func, 0, &res_lists, 0, 0); + dbg("%s: back from configure_new_device\n", __FUNCTION__); + + ctrl->io_head = res_lists.io_head; + ctrl->mem_head = res_lists.mem_head; + ctrl->p_mem_head = res_lists.p_mem_head; + ctrl->bus_head = res_lists.bus_head; + + shpchp_resource_sort_and_combine(&(ctrl->mem_head)); + shpchp_resource_sort_and_combine(&(ctrl->p_mem_head)); + shpchp_resource_sort_and_combine(&(ctrl->io_head)); + shpchp_resource_sort_and_combine(&(ctrl->bus_head)); + + if (rc) { + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + /* turn off slot, turn on Amber LED, turn off Green LED */ + retval = p_slot->hpc_ops->slot_disable(p_slot); + if (retval) { + err("%s: Issue of Slot Enable command failed\n", __FUNCTION__); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return retval; + } + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + retval = p_slot->hpc_ops->check_cmd_status(ctrl); + if (retval) { + err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return retval; + } + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + + return(rc); + } + shpchp_save_slot_config(ctrl, func); + + func->status = 0; + func->switch_save = 0x10; + func->is_a_board = 0x01; + + /* Next, we will instantiate the linux pci_dev structures + * (with appropriate driver notification, if already present) + */ + index = 0; + do { + new_func = shpchp_slot_find(ctrl->slot_bus, func->device, index++); + if (new_func && !new_func->pci_dev) { + dbg("%s:call pci_hp_configure_dev\n", __FUNCTION__); + shpchp_configure_device(ctrl, new_func); + } + } while (new_func); + + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + p_slot->hpc_ops->green_led_on(p_slot); + + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + + } else { + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + /* turn off slot, turn on Amber LED, turn off Green LED */ + rc = p_slot->hpc_ops->slot_disable(p_slot); + if (rc) { + err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return rc; + } + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + rc = p_slot->hpc_ops->check_cmd_status(ctrl); + if (rc) { + err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return rc; + } + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + + return(rc); + } + return 0; +} + + +/** + * remove_board - Turns off slot and LED's + * + */ +static u32 remove_board(struct pci_func *func, struct controller *ctrl) +{ + int index; + u8 skip = 0; + u8 device; + u8 hp_slot; + u32 rc; + struct resource_lists res_lists; + struct pci_func *temp_func; + struct slot *p_slot; + + if (func == NULL) + return(1); + + if (shpchp_unconfigure_device(func)) + return(1); + + device = func->device; + + hp_slot = func->device - ctrl->slot_device_offset; + p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + + dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); + + if ((ctrl->add_support) && + !(func->bus_head || func->mem_head || func->p_mem_head || func->io_head)) { + /* Here we check to see if we've saved any of the board's + * resources already. If so, we'll skip the attempt to + * determine what's being used. + */ + index = 0; + + temp_func = func; + + while ((temp_func = shpchp_slot_find(temp_func->bus, temp_func->device, index++))) { + if (temp_func->bus_head || temp_func->mem_head + || temp_func->p_mem_head || temp_func->io_head) { + skip = 1; + break; + } + } + + if (!skip) + rc = shpchp_save_used_resources(ctrl, func, DISABLE_CARD); + } + /* Change status to shutdown */ + if (func->is_a_board) + func->status = 0x01; + func->configured = 0; + + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + /* Turn off slot, turn on Amber LED, turn off Green LED */ + rc = p_slot->hpc_ops->slot_disable(p_slot); + if (rc) { + err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return rc; + } + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + rc = p_slot->hpc_ops->check_cmd_status(ctrl); + if (rc) { + err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return rc; + } + + rc = p_slot->hpc_ops->set_attention_status(p_slot, 0); + if (rc) { + err("%s: Issue of Set Attention command failed\n", __FUNCTION__); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + return rc; + } + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + + if (ctrl->add_support) { + while (func) { + res_lists.io_head = ctrl->io_head; + res_lists.mem_head = ctrl->mem_head; + res_lists.p_mem_head = ctrl->p_mem_head; + res_lists.bus_head = ctrl->bus_head; + + dbg("Returning resources to ctlr lists for (B/D/F) = (%#x/%#x/%#x)\n", + func->bus, func->device, func->function); + + shpchp_return_board_resources(func, &res_lists); + + ctrl->io_head = res_lists.io_head; + ctrl->mem_head = res_lists.mem_head; + ctrl->p_mem_head = res_lists.p_mem_head; + ctrl->bus_head = res_lists.bus_head; + + shpchp_resource_sort_and_combine(&(ctrl->mem_head)); + shpchp_resource_sort_and_combine(&(ctrl->p_mem_head)); + shpchp_resource_sort_and_combine(&(ctrl->io_head)); + shpchp_resource_sort_and_combine(&(ctrl->bus_head)); + + if (is_bridge(func)) { + dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", + ctrl->seg, func->bus, func->device, func->function); + bridge_slot_remove(func); + } else { + dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", + ctrl->seg, func->bus, func->device, func->function); + slot_remove(func); + } + + func = shpchp_slot_find(ctrl->slot_bus, device, 0); + } + + /* Setup slot structure with entry for empty slot */ + func = shpchp_slot_create(ctrl->slot_bus); + + if (func == NULL) { + return(1); + } + + func->bus = ctrl->slot_bus; + func->device = device; + func->function = 0; + func->configured = 0; + func->switch_save = 0x10; + func->is_a_board = 0; + } + + return 0; +} + + +static void pushbutton_helper_thread (unsigned long data) +{ + pushbutton_pending = data; + + up(&event_semaphore); +} + + +/* This is the main worker thread */ +static int event_thread(void* data) +{ + struct controller *ctrl; + lock_kernel(); + daemonize(); + + /* New name */ + strcpy(current->comm, "shpchpd_event"); + + unlock_kernel(); + + while (1) { + dbg("!!!!event_thread sleeping\n"); + down_interruptible (&event_semaphore); + dbg("event_thread woken finished = %d\n", event_finished); + if (event_finished || signal_pending(current)) + break; + /* Do stuff here */ + if (pushbutton_pending) + shpchp_pushbutton_thread(pushbutton_pending); + else + for (ctrl = shpchp_ctrl_list; ctrl; ctrl=ctrl->next) + interrupt_event_handler(ctrl); + } + dbg("event_thread signals exit\n"); + up(&event_exit); + return 0; +} + +int shpchp_event_start_thread (void) +{ + int pid; + + /* Initialize our semaphores */ + init_MUTEX_LOCKED(&event_exit); + event_finished=0; + + init_MUTEX_LOCKED(&event_semaphore); + pid = kernel_thread(event_thread, 0, 0); + + if (pid < 0) { + err ("Can't start up our event thread\n"); + return -1; + } + dbg("Our event thread pid = %d\n", pid); + return 0; +} + + +void shpchp_event_stop_thread (void) +{ + event_finished = 1; + dbg("event_thread finish command given\n"); + up(&event_semaphore); + dbg("wait for event_thread to exit\n"); + down(&event_exit); +} + + +static int update_slot_info (struct slot *slot) +{ + struct hotplug_slot_info *info; + char buffer[SLOT_NAME_SIZE]; + int result; + + info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + make_slot_name (&buffer[0], SLOT_NAME_SIZE, slot); + + slot->hpc_ops->get_power_status(slot, &(info->power_status)); + slot->hpc_ops->get_attention_status(slot, &(info->attention_status)); + slot->hpc_ops->get_latch_status(slot, &(info->latch_status)); + slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status)); + + result = pci_hp_change_slot_info(buffer, info); + kfree (info); + return result; +} + +static void interrupt_event_handler(struct controller *ctrl) +{ + int loop = 0; + int change = 1; + struct pci_func *func; + u8 hp_slot; + u8 getstatus; + struct slot *p_slot; + + dbg("%s:\n", __FUNCTION__); + while (change) { + change = 0; + + for (loop = 0; loop < 10; loop++) { + if (ctrl->event_queue[loop].event_type != 0) { + dbg("%s:loop %x event_type %x\n", __FUNCTION__, loop, + ctrl->event_queue[loop].event_type); + hp_slot = ctrl->event_queue[loop].hp_slot; + + func = shpchp_slot_find(ctrl->slot_bus, (hp_slot + ctrl->slot_device_offset), 0); + + p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + + dbg("%s:hp_slot %d, func %p, p_slot %p\n", __FUNCTION__,hp_slot, func, p_slot); + + if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) { + dbg("%s: button cancel\n", __FUNCTION__); + del_timer(&p_slot->task_event); + + switch (p_slot->state) { + case BLINKINGOFF_STATE: + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + p_slot->hpc_ops->green_led_on(p_slot); + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + p_slot->hpc_ops->set_attention_status(p_slot, 0); + + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + break; + case BLINKINGON_STATE: + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + p_slot->hpc_ops->green_led_off(p_slot); + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + p_slot->hpc_ops->set_attention_status(p_slot, 0); + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + + break; + default: + warn("Not a valid state\n"); + return; + } + info(msg_button_cancel, p_slot->number); + p_slot->state = STATIC_STATE; + } + /* Button Pressed (No action on 1st press...) */ + else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) { + dbg("%s: Button pressed\n", __FUNCTION__); + + p_slot->hpc_ops->get_power_status(p_slot, &getstatus); + if (getstatus) { + /* slot is on */ + dbg("%s: slot is on\n", __FUNCTION__); + p_slot->state = BLINKINGOFF_STATE; + info(msg_button_off, p_slot->number); + } else { + /* slot is off */ + dbg("%s: slot is off\n", __FUNCTION__); + p_slot->state = BLINKINGON_STATE; + info(msg_button_on, p_slot->number); + } + + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + /* blink green LED and turn off amber */ + p_slot->hpc_ops->green_led_blink(p_slot); + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + p_slot->hpc_ops->set_attention_status(p_slot, 0); + + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + + init_timer(&p_slot->task_event); + p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */ + p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread; + p_slot->task_event.data = (unsigned long) p_slot; + + dbg("%s: add_timer p_slot = %p\n", __FUNCTION__, (void *) p_slot); + add_timer(&p_slot->task_event); + } + /***********POWER FAULT********************/ + else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) { + dbg("%s: power fault\n", __FUNCTION__); + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + p_slot->hpc_ops->set_attention_status(p_slot, 1); + + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + p_slot->hpc_ops->green_led_off(p_slot); + + /* Wait for the command to complete */ + wait_for_ctrl_irq(ctrl); + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + } else { + /* refresh notification */ + if (p_slot) + update_slot_info(p_slot); + } + + ctrl->event_queue[loop].event_type = 0; + + change = 1; + } + } /* End of FOR loop */ + } + + return; +} + + +/** + * shpchp_pushbutton_thread + * + * Scheduled procedure to handle blocking stuff for the pushbuttons + * Handles all pending events and exits. + * + */ +void shpchp_pushbutton_thread (unsigned long slot) +{ + struct slot *p_slot = (struct slot *) slot; + u8 getstatus; + int rc; + + pushbutton_pending = 0; + + if (!p_slot) { + dbg("%s: Error! slot NULL\n", __FUNCTION__); + return; + } + + p_slot->hpc_ops->get_power_status(p_slot, &getstatus); + if (getstatus) { + p_slot->state = POWEROFF_STATE; + dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device); + + if (shpchp_disable_slot(p_slot)) { + /* Wait for exclusive access to hardware */ + down(&p_slot->ctrl->crit_sect); + + /* Turn on the Attention LED */ + rc = p_slot->hpc_ops->set_attention_status(p_slot, 1); + if (rc) { + err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__); + return; + } + + /* Wait for the command to complete */ + wait_for_ctrl_irq(p_slot->ctrl); + + /* Done with exclusive hardware access */ + up(&p_slot->ctrl->crit_sect); + } + p_slot->state = STATIC_STATE; + } else { + p_slot->state = POWERON_STATE; + dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device); + + if (shpchp_enable_slot(p_slot)) { + /* Wait for exclusive access to hardware */ + down(&p_slot->ctrl->crit_sect); + + /* Turn off the green LED */ + rc = p_slot->hpc_ops->set_attention_status(p_slot, 1); + if (rc) { + err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__); + return; + } + /* Wait for the command to complete */ + wait_for_ctrl_irq(p_slot->ctrl); + + p_slot->hpc_ops->green_led_off(p_slot); + + /* Wait for the command to complete */ + wait_for_ctrl_irq(p_slot->ctrl); + + /* Done with exclusive hardware access */ + up(&p_slot->ctrl->crit_sect); + } + p_slot->state = STATIC_STATE; + } + + return; +} + + +int shpchp_enable_slot (struct slot *p_slot) +{ + u8 getstatus = 0; + int rc; + struct pci_func *func; + + func = shpchp_slot_find(p_slot->bus, p_slot->device, 0); + if (!func) { + dbg("%s: Error! slot NULL\n", __FUNCTION__); + return (1); + } + + /* Check to see if (latch closed, card present, power off) */ + down(&p_slot->ctrl->crit_sect); + rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); + if (rc || !getstatus) { + info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); + up(&p_slot->ctrl->crit_sect); + return (0); + } + rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); + if (rc || getstatus) { + info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); + up(&p_slot->ctrl->crit_sect); + return (0); + } + rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); + if (rc || getstatus) { + info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number); + up(&p_slot->ctrl->crit_sect); + return (0); + } + up(&p_slot->ctrl->crit_sect); + + slot_remove(func); + + func = shpchp_slot_create(p_slot->bus); + if (func == NULL) + return (1); + + func->bus = p_slot->bus; + func->device = p_slot->device; + func->function = 0; + func->configured = 0; + func->is_a_board = 1; + + /* We have to save the presence info for these slots */ + p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); + p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); + func->switch_save = !getstatus? 0x10:0; + + rc = board_added(func, p_slot->ctrl); + if (rc) { + if (is_bridge(func)) + bridge_slot_remove(func); + else + slot_remove(func); + + /* Setup slot structure with entry for empty slot */ + func = shpchp_slot_create(p_slot->bus); + if (func == NULL) + return (1); /* Out of memory */ + + func->bus = p_slot->bus; + func->device = p_slot->device; + func->function = 0; + func->configured = 0; + func->is_a_board = 1; + + /* We have to save the presence info for these slots */ + p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save)); + p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); + func->switch_save = !getstatus? 0x10:0; + } + + if (p_slot) + update_slot_info(p_slot); + + return rc; +} + + +int shpchp_disable_slot (struct slot *p_slot) +{ + u8 class_code, header_type, BCR; + u8 index = 0; + u8 getstatus = 0; + u32 rc = 0; + int ret = 0; + unsigned int devfn; + struct pci_bus *pci_bus = p_slot->ctrl->pci_dev->subordinate; + struct pci_func *func; + + if (!p_slot->ctrl) + return (1); + + /* Check to see if (latch closed, card present, power on) */ + down(&p_slot->ctrl->crit_sect); + + ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); + if (ret || !getstatus) { + info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); + up(&p_slot->ctrl->crit_sect); + return (0); + } + ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); + if (ret || getstatus) { + info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); + up(&p_slot->ctrl->crit_sect); + return (0); + } + ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); + if (ret || !getstatus) { + info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); + up(&p_slot->ctrl->crit_sect); + return (0); + } + up(&p_slot->ctrl->crit_sect); + + func = shpchp_slot_find(p_slot->bus, p_slot->device, index++); + + /* Make sure there are no video controllers here + * for all func of p_slot + */ + while (func && !rc) { + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + /* Check the Class Code */ + rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); + if (rc) + return rc; + + if (class_code == PCI_BASE_CLASS_DISPLAY) { + /* Display/Video adapter (not supported) */ + rc = REMOVE_NOT_SUPPORTED; + } else { + /* See if it's a bridge */ + rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; + + /* If it's a bridge, check the VGA Enable bit */ + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR); + if (rc) + return rc; + + /* If the VGA Enable bit is set, remove isn't supported */ + if (BCR & PCI_BRIDGE_CTL_VGA) { + rc = REMOVE_NOT_SUPPORTED; + } + } + } + + func = shpchp_slot_find(p_slot->bus, p_slot->device, index++); + } + + func = shpchp_slot_find(p_slot->bus, p_slot->device, 0); + if ((func != NULL) && !rc) { + rc = remove_board(func, p_slot->ctrl); + } else if (!rc) + rc = 1; + + if (p_slot) + update_slot_info(p_slot); + + return(rc); +} + + +/** + * configure_new_device - Configures the PCI header information of one board. + * + * @ctrl: pointer to controller structure + * @func: pointer to function structure + * @behind_bridge: 1 if this is a recursive call, 0 if not + * @resources: pointer to set of resource lists + * + * Returns 0 if success + * + */ +static u32 configure_new_device (struct controller * ctrl, struct pci_func * func, + u8 behind_bridge, struct resource_lists * resources, u8 bridge_bus, u8 bridge_dev) +{ + u8 temp_byte, function, max_functions, stop_it; + int rc; + u32 ID; + struct pci_func *new_slot; + struct pci_bus lpci_bus, *pci_bus; + int index; + + new_slot = func; + + dbg("%s\n", __FUNCTION__); + memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); + pci_bus = &lpci_bus; + pci_bus->number = func->bus; + + /* Check for Multi-function device */ + rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(func->device, func->function), 0x0E, &temp_byte); + if (rc) { + dbg("%s: rc = %d\n", __FUNCTION__, rc); + return rc; + } + + if (temp_byte & 0x80) /* Multi-function device */ + max_functions = 8; + else + max_functions = 1; + + function = 0; + + do { + rc = configure_new_function(ctrl, new_slot, behind_bridge, resources, bridge_bus, bridge_dev); + + if (rc) { + dbg("configure_new_function failed %d\n",rc); + index = 0; + + while (new_slot) { + new_slot = shpchp_slot_find(new_slot->bus, new_slot->device, index++); + + if (new_slot) + shpchp_return_board_resources(new_slot, resources); + } + + return(rc); + } + + function++; + + stop_it = 0; + + /* The following loop skips to the next present function + * and creates a board structure + */ + + while ((function < max_functions) && (!stop_it)) { + pci_bus_read_config_dword(pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID); + + if (ID == 0xFFFFFFFF) { /* There's nothing there. */ + function++; + } else { /* There's something there */ + /* Setup slot structure. */ + new_slot = shpchp_slot_create(func->bus); + + if (new_slot == NULL) { + /* Out of memory */ + return(1); + } + + new_slot->bus = func->bus; + new_slot->device = func->device; + new_slot->function = function; + new_slot->is_a_board = 1; + new_slot->status = 0; + + stop_it++; + } + } + + } while (function < max_functions); + dbg("returning from configure_new_device\n"); + + return 0; +} + + +/* + * Configuration logic that involves the hotplug data structures and + * their bookkeeping + */ + + +/** + * configure_new_function - Configures the PCI header information of one device + * + * @ctrl: pointer to controller structure + * @func: pointer to function structure + * @behind_bridge: 1 if this is a recursive call, 0 if not + * @resources: pointer to set of resource lists + * + * Calls itself recursively for bridged devices. + * Returns 0 if success + * + */ +static int configure_new_function (struct controller * ctrl, struct pci_func * func, + u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev) +{ + int cloop; + u8 temp_byte; + u8 device; + u8 class_code; + u16 temp_word; + u32 rc; + u32 temp_register; + u32 base; + u32 ID; + unsigned int devfn; + struct pci_resource *mem_node; + struct pci_resource *p_mem_node; + struct pci_resource *io_node; + struct pci_resource *bus_node; + struct pci_resource *hold_mem_node; + struct pci_resource *hold_p_mem_node; + struct pci_resource *hold_IO_node; + struct pci_resource *hold_bus_node; + struct irq_mapping irqs; + struct pci_func *new_slot; + struct pci_bus lpci_bus, *pci_bus; + struct resource_lists temp_resources; +#if defined(CONFIG_X86_64) + u8 IRQ = 0; +#endif + + memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); + pci_bus = &lpci_bus; + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + /* Check for Bridge */ + rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &temp_byte); + if (rc) + return rc; + + if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */ + /* set Primary bus */ + dbg("set Primary bus = 0x%x\n", func->bus); + rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func->bus); + if (rc) + return rc; + + /* find range of busses to use */ + bus_node = get_max_resource(&resources->bus_head, 1L); + + /* If we don't have any busses to allocate, we can't continue */ + if (!bus_node) { + err("Got NO bus resource to use\n"); + return -ENOMEM; + } + dbg("Got ranges of buses to use: base:len=0x%x:%x\n", bus_node->base, bus_node->length); + + /* set Secondary bus */ + temp_byte = (u8)bus_node->base; + dbg("set Secondary bus = 0x%x\n", temp_byte); + rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, temp_byte); + if (rc) + return rc; + + /* set subordinate bus */ + temp_byte = (u8)(bus_node->base + bus_node->length - 1); + dbg("set subordinate bus = 0x%x\n", temp_byte); + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte); + if (rc) + return rc; + + /* Set HP parameters (Cache Line Size, Latency Timer) */ + rc = shpchprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_BRIDGE); + if (rc) + return rc; + + /* Setup the IO, memory, and prefetchable windows */ + + io_node = get_max_resource(&(resources->io_head), 0x1000L); + if (io_node) { + dbg("io_node(base, len, next) (%x, %x, %p)\n", io_node->base, io_node->length, io_node->next); + } + + mem_node = get_max_resource(&(resources->mem_head), 0x100000L); + if (mem_node) { + dbg("mem_node(base, len, next) (%x, %x, %p)\n", mem_node->base, mem_node->length, mem_node->next); + } + + if (resources->p_mem_head) + p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000L); + else { + /* + * In some platform implementation, MEM and PMEM are not + * distinguished, and hence ACPI _CRS has only MEM entries + * for both MEM and PMEM. + */ + dbg("using MEM for PMEM\n"); + p_mem_node = get_max_resource(&(resources->mem_head), 0x100000L); + } + if (p_mem_node) { + dbg("p_mem_node(base, len, next) (%x, %x, %p)\n", p_mem_node->base, p_mem_node->length, p_mem_node->next); + } + + /* Set up the IRQ info */ + if (!resources->irqs) { + irqs.barber_pole = 0; + irqs.interrupt[0] = 0; + irqs.interrupt[1] = 0; + irqs.interrupt[2] = 0; + irqs.interrupt[3] = 0; + irqs.valid_INT = 0; + } else { + irqs.barber_pole = resources->irqs->barber_pole; + irqs.interrupt[0] = resources->irqs->interrupt[0]; + irqs.interrupt[1] = resources->irqs->interrupt[1]; + irqs.interrupt[2] = resources->irqs->interrupt[2]; + irqs.interrupt[3] = resources->irqs->interrupt[3]; + irqs.valid_INT = resources->irqs->valid_INT; + } + + /* Set up resource lists that are now aligned on top and bottom + * for anything behind the bridge. + */ + temp_resources.bus_head = bus_node; + temp_resources.io_head = io_node; + temp_resources.mem_head = mem_node; + temp_resources.p_mem_head = p_mem_node; + temp_resources.irqs = &irqs; + + /* Make copies of the nodes we are going to pass down so that + * if there is a problem,we can just use these to free resources + */ + hold_bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + hold_IO_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + hold_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + hold_p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) { + if (hold_bus_node) + kfree(hold_bus_node); + if (hold_IO_node) + kfree(hold_IO_node); + if (hold_mem_node) + kfree(hold_mem_node); + if (hold_p_mem_node) + kfree(hold_p_mem_node); + + return(1); + } + + memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource)); + + bus_node->base += 1; + bus_node->length -= 1; + bus_node->next = NULL; + + /* If we have IO resources copy them and fill in the bridge's + * IO range registers + */ + if (io_node) { + memcpy(hold_IO_node, io_node, sizeof(struct pci_resource)); + io_node->next = NULL; + + /* Set IO base and Limit registers */ + RES_CHECK(io_node->base, 8); + temp_byte = (u8)(io_node->base >> 8); + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte); + + RES_CHECK(io_node->base + io_node->length - 1, 8); + temp_byte = (u8)((io_node->base + io_node->length - 1) >> 8); + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte); + } else { + kfree(hold_IO_node); + hold_IO_node = NULL; + } + + /* If we have memory resources copy them and fill in the bridge's + * memory range registers. Otherwise, fill in the range + * registers with values that disable them. + */ + if (mem_node) { + memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource)); + mem_node->next = NULL; + + /* Set Mem base and Limit registers */ + RES_CHECK(mem_node->base, 16); + temp_word = (u32)(mem_node->base >> 16); + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); + + RES_CHECK(mem_node->base + mem_node->length - 1, 16); + temp_word = (u32)((mem_node->base + mem_node->length - 1) >> 16); + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); + } else { + temp_word = 0xFFFF; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); + + temp_word = 0x0000; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); + + kfree(hold_mem_node); + hold_mem_node = NULL; + } + + /* If we have prefetchable memory resources copy them and + * fill in the bridge's memory range registers. Otherwise, + * fill in the range registers with values that disable them. + */ + if (p_mem_node) { + memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource)); + p_mem_node->next = NULL; + + /* Set Pre Mem base and Limit registers */ + RES_CHECK(p_mem_node->base, 16); + temp_word = (u32)(p_mem_node->base >> 16); + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); + + RES_CHECK(p_mem_node->base + p_mem_node->length - 1, 16); + temp_word = (u32)((p_mem_node->base + p_mem_node->length - 1) >> 16); + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); + } else { + temp_word = 0xFFFF; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); + + temp_word = 0x0000; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); + + kfree(hold_p_mem_node); + hold_p_mem_node = NULL; + } + + /* Adjust this to compensate for extra adjustment in first loop */ + irqs.barber_pole--; + + rc = 0; + + /* Here we actually find the devices and configure them */ + for (device = 0; (device <= 0x1F) && !rc; device++) { + irqs.barber_pole = (irqs.barber_pole + 1) & 0x03; + + ID = 0xFFFFFFFF; + pci_bus->number = hold_bus_node->base; + pci_bus_read_config_dword (pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID); + pci_bus->number = func->bus; + + if (ID != 0xFFFFFFFF) { /* device Present */ + /* Setup slot structure. */ + new_slot = shpchp_slot_create(hold_bus_node->base); + + if (new_slot == NULL) { + /* Out of memory */ + rc = -ENOMEM; + continue; + } + + new_slot->bus = hold_bus_node->base; + new_slot->device = device; + new_slot->function = 0; + new_slot->is_a_board = 1; + new_slot->status = 0; + + rc = configure_new_device(ctrl, new_slot, 1, &temp_resources, func->bus, func->device); + dbg("configure_new_device rc=0x%x\n",rc); + } /* End of IF (device in slot?) */ + } /* End of FOR loop */ + + if (rc) { + shpchp_destroy_resource_list(&temp_resources); + + return_resource(&(resources->bus_head), hold_bus_node); + return_resource(&(resources->io_head), hold_IO_node); + return_resource(&(resources->mem_head), hold_mem_node); + return_resource(&(resources->p_mem_head), hold_p_mem_node); + return(rc); + } + + /* save the interrupt routing information */ + if (resources->irqs) { + resources->irqs->interrupt[0] = irqs.interrupt[0]; + resources->irqs->interrupt[1] = irqs.interrupt[1]; + resources->irqs->interrupt[2] = irqs.interrupt[2]; + resources->irqs->interrupt[3] = irqs.interrupt[3]; + resources->irqs->valid_INT = irqs.valid_INT; + } else if (!behind_bridge) { + /* We need to hook up the interrupts here */ + for (cloop = 0; cloop < 4; cloop++) { + if (irqs.valid_INT & (0x01 << cloop)) { + rc = shpchp_set_irq(func->bus, func->device, + 0x0A + cloop, irqs.interrupt[cloop]); + if (rc) { + shpchp_destroy_resource_list (&temp_resources); + return_resource(&(resources->bus_head), hold_bus_node); + return_resource(&(resources->io_head), hold_IO_node); + return_resource(&(resources->mem_head), hold_mem_node); + return_resource(&(resources->p_mem_head), hold_p_mem_node); + return rc; + } + } + } /* end of for loop */ + } + + /* Return unused bus resources + * First use the temporary node to store information for the board + */ + if (hold_bus_node && bus_node && temp_resources.bus_head) { + hold_bus_node->length = bus_node->base - hold_bus_node->base; + + hold_bus_node->next = func->bus_head; + func->bus_head = hold_bus_node; + + temp_byte = (u8)(temp_resources.bus_head->base - 1); + + /* set subordinate bus */ + dbg("re-set subordinate bus = 0x%x\n", temp_byte); + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte); + + if (temp_resources.bus_head->length == 0) { + kfree(temp_resources.bus_head); + temp_resources.bus_head = NULL; + } else { + dbg("return bus res of b:d(0x%x:%x) base:len(0x%x:%x)\n", + func->bus, func->device, temp_resources.bus_head->base, temp_resources.bus_head->length); + return_resource(&(resources->bus_head), temp_resources.bus_head); + } + } + + /* If we have IO space available and there is some left, + * return the unused portion + */ + if (hold_IO_node && temp_resources.io_head) { + io_node = do_pre_bridge_resource_split(&(temp_resources.io_head), + &hold_IO_node, 0x1000); + + /* Check if we were able to split something off */ + if (io_node) { + hold_IO_node->base = io_node->base + io_node->length; + + RES_CHECK(hold_IO_node->base, 8); + temp_byte = (u8)((hold_IO_node->base) >> 8); + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte); + + return_resource(&(resources->io_head), io_node); + } + + io_node = do_bridge_resource_split(&(temp_resources.io_head), 0x1000); + + /* Check if we were able to split something off */ + if (io_node) { + /* First use the temporary node to store information for the board */ + hold_IO_node->length = io_node->base - hold_IO_node->base; + + /* If we used any, add it to the board's list */ + if (hold_IO_node->length) { + hold_IO_node->next = func->io_head; + func->io_head = hold_IO_node; + + RES_CHECK(io_node->base - 1, 8); + temp_byte = (u8)((io_node->base - 1) >> 8); + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte); + + return_resource(&(resources->io_head), io_node); + } else { + /* it doesn't need any IO */ + temp_byte = 0x00; + rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte); + + return_resource(&(resources->io_head), io_node); + kfree(hold_IO_node); + } + } else { + /* It used most of the range */ + hold_IO_node->next = func->io_head; + func->io_head = hold_IO_node; + } + } else if (hold_IO_node) { + /* it used the whole range */ + hold_IO_node->next = func->io_head; + func->io_head = hold_IO_node; + } + + /* If we have memory space available and there is some left, + * return the unused portion + */ + if (hold_mem_node && temp_resources.mem_head) { + mem_node = do_pre_bridge_resource_split(&(temp_resources.mem_head), &hold_mem_node, 0x100000L); + + /* Check if we were able to split something off */ + if (mem_node) { + hold_mem_node->base = mem_node->base + mem_node->length; + + RES_CHECK(hold_mem_node->base, 16); + temp_word = (u32)((hold_mem_node->base) >> 16); + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); + + return_resource(&(resources->mem_head), mem_node); + } + + mem_node = do_bridge_resource_split(&(temp_resources.mem_head), 0x100000L); + + /* Check if we were able to split something off */ + if (mem_node) { + /* First use the temporary node to store information for the board */ + hold_mem_node->length = mem_node->base - hold_mem_node->base; + + if (hold_mem_node->length) { + hold_mem_node->next = func->mem_head; + func->mem_head = hold_mem_node; + + /* configure end address */ + RES_CHECK(mem_node->base - 1, 16); + temp_word = (u32)((mem_node->base - 1) >> 16); + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); + + /* Return unused resources to the pool */ + return_resource(&(resources->mem_head), mem_node); + } else { + /* it doesn't need any Mem */ + temp_word = 0x0000; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); + + return_resource(&(resources->mem_head), mem_node); + kfree(hold_mem_node); + } + } else { + /* It used most of the range */ + hold_mem_node->next = func->mem_head; + func->mem_head = hold_mem_node; + } + } else if (hold_mem_node) { + /* It used the whole range */ + hold_mem_node->next = func->mem_head; + func->mem_head = hold_mem_node; + } + + /* If we have prefetchable memory space available and there is some + * left at the end, return the unused portion + */ + if (hold_p_mem_node && temp_resources.p_mem_head) { + p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head), + &hold_p_mem_node, 0x100000L); + + /* Check if we were able to split something off */ + if (p_mem_node) { + hold_p_mem_node->base = p_mem_node->base + p_mem_node->length; + + RES_CHECK(hold_p_mem_node->base, 16); + temp_word = (u32)((hold_p_mem_node->base) >> 16); + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); + + return_resource(&(resources->p_mem_head), p_mem_node); + } + + p_mem_node = do_bridge_resource_split(&(temp_resources.p_mem_head), 0x100000L); + + /* Check if we were able to split something off */ + if (p_mem_node) { + /* First use the temporary node to store information for the board */ + hold_p_mem_node->length = p_mem_node->base - hold_p_mem_node->base; + + /* If we used any, add it to the board's list */ + if (hold_p_mem_node->length) { + hold_p_mem_node->next = func->p_mem_head; + func->p_mem_head = hold_p_mem_node; + + RES_CHECK(p_mem_node->base - 1, 16); + temp_word = (u32)((p_mem_node->base - 1) >> 16); + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); + + return_resource(&(resources->p_mem_head), p_mem_node); + } else { + /* It doesn't need any PMem */ + temp_word = 0x0000; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); + + return_resource(&(resources->p_mem_head), p_mem_node); + kfree(hold_p_mem_node); + } + } else { + /* It used the most of the range */ + hold_p_mem_node->next = func->p_mem_head; + func->p_mem_head = hold_p_mem_node; + } + } else if (hold_p_mem_node) { + /* It used the whole range */ + hold_p_mem_node->next = func->p_mem_head; + func->p_mem_head = hold_p_mem_node; + } + + /* We should be configuring an IRQ and the bridge's base address + * registers if it needs them. Although we have never seen such + * a device + */ + + shpchprm_enable_card(ctrl, func, PCI_HEADER_TYPE_BRIDGE); + + dbg("PCI Bridge Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, + func->bus, func->device, func->function); + } else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) { + /* Standard device */ + u64 base64; + rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); + + if (class_code == PCI_BASE_CLASS_DISPLAY) + return (DEVICE_TYPE_NOT_SUPPORTED); + + /* Figure out IO and memory needs */ + for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) { + temp_register = 0xFFFFFFFF; + + rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); + rc = pci_bus_read_config_dword(pci_bus, devfn, cloop, &temp_register); + dbg("Bar[%x]=0x%x on bus:dev:func(0x%x:%x:%x)\n", cloop, temp_register, + func->bus, func->device, func->function); + + if (!temp_register) + continue; + + base64 = 0L; + if (temp_register & PCI_BASE_ADDRESS_SPACE_IO) { + /* Map IO */ + + /* Set base = amount of IO space */ + base = temp_register & 0xFFFFFFFC; + base = ~base + 1; + + dbg("NEED IO length(0x%x)\n", base); + io_node = get_io_resource(&(resources->io_head),(ulong)base); + + /* Allocate the resource to the board */ + if (io_node) { + dbg("Got IO base=0x%x(length=0x%x)\n", io_node->base, io_node->length); + base = (u32)io_node->base; + io_node->next = func->io_head; + func->io_head = io_node; + } else { + err("Got NO IO resource(length=0x%x)\n", base); + return -ENOMEM; + } + } else { /* Map MEM */ + int prefetchable = 1; + struct pci_resource **res_node = &func->p_mem_head; + char *res_type_str = "PMEM"; + u32 temp_register2; + + if (!(temp_register & PCI_BASE_ADDRESS_MEM_PREFETCH)) { + prefetchable = 0; + res_node = &func->mem_head; + res_type_str++; + } + + base = temp_register & 0xFFFFFFF0; + base = ~base + 1; + + switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) { + case PCI_BASE_ADDRESS_MEM_TYPE_32: + dbg("NEED 32 %s bar=0x%x(length=0x%x)\n", res_type_str, temp_register, base); + + if (prefetchable && resources->p_mem_head) + mem_node=get_resource(&(resources->p_mem_head), (ulong)base); + else { + if (prefetchable) + dbg("using MEM for PMEM\n"); + mem_node=get_resource(&(resources->mem_head), (ulong)base); + } + + /* Allocate the resource to the board */ + if (mem_node) { + base = (u32)mem_node->base; + mem_node->next = *res_node; + *res_node = mem_node; + dbg("Got 32 %s base=0x%x(length=0x%x)\n", res_type_str, mem_node->base, mem_node->length); + } else { + err("Got NO 32 %s resource(length=0x%x)\n", res_type_str, base); + return -ENOMEM; + } + break; + case PCI_BASE_ADDRESS_MEM_TYPE_64: + rc = pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2); + dbg("NEED 64 %s bar=0x%x:%x(length=0x%x)\n", res_type_str, temp_register2, temp_register, base); + + if (prefetchable && resources->p_mem_head) + mem_node = get_resource(&(resources->p_mem_head), (ulong)base); + else { + if (prefetchable) + dbg("using MEM for PMEM\n"); + mem_node = get_resource(&(resources->mem_head), (ulong)base); + } + + /* Allocate the resource to the board */ + if (mem_node) { + base64 = mem_node->base; + mem_node->next = *res_node; + *res_node = mem_node; + dbg("Got 64 %s base=0x%x:%x(length=%x)\n", res_type_str, (u32)(base64 >> 32), (u32)base64, mem_node->length); + } else { + err("Got NO 64 %s resource(length=0x%x)\n", res_type_str, base); + return -ENOMEM; + } + break; + default: + dbg("reserved BAR type=0x%x\n", temp_register); + break; + } + + } + + if (base64) { + rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64); + cloop += 4; + base64 >>= 32; + + if (base64) { + dbg("%s: high dword of base64(0x%x) set to 0\n", __FUNCTION__, (u32)base64); + base64 = 0x0L; + } + + rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64); + } else { + rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, base); + } + } /* End of base register loop */ + +#if defined(CONFIG_X86_64) + /* Figure out which interrupt pin this function uses */ + rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_INTERRUPT_PIN, &temp_byte); + + /* If this function needs an interrupt and we are behind a bridge + and the pin is tied to something that's alread mapped, + set this one the same + */ + if (temp_byte && resources->irqs && + (resources->irqs->valid_INT & + (0x01 << ((temp_byte + resources->irqs->barber_pole - 1) & 0x03)))) { + /* We have to share with something already set up */ + IRQ = resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03]; + } else { + /* Program IRQ based on card type */ + rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); + + if (class_code == PCI_BASE_CLASS_STORAGE) { + IRQ = shpchp_disk_irq; + } else { + IRQ = shpchp_nic_irq; + } + } + + /* IRQ Line */ + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_INTERRUPT_LINE, IRQ); + + if (!behind_bridge) { + rc = shpchp_set_irq(func->bus, func->device, temp_byte + 0x09, IRQ); + if (rc) + return(1); + } else { + /* TBD - this code may also belong in the other clause of this If statement */ + resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03] = IRQ; + resources->irqs->valid_INT |= 0x01 << (temp_byte + resources->irqs->barber_pole - 1) & 0x03; + } +#endif + /* Disable ROM base Address */ + temp_word = 0x00L; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_ROM_ADDRESS, temp_word); + + /* Set HP parameters (Cache Line Size, Latency Timer) */ + rc = shpchprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_NORMAL); + if (rc) + return rc; + + shpchprm_enable_card(ctrl, func, PCI_HEADER_TYPE_NORMAL); + + dbg("PCI function Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl->seg, func->bus, func->device, func->function); + } /* End of Not-A-Bridge else */ + else { + /* It's some strange type of PCI adapter (Cardbus?) */ + return(DEVICE_TYPE_NOT_SUPPORTED); + } + + func->configured = 1; + + return 0; +} + diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/shpchp_hpc.c linux-2.4.27-pre5/drivers/hotplug/shpchp_hpc.c --- linux-2.4.26/drivers/hotplug/shpchp_hpc.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/shpchp_hpc.c 2004-06-03 01:34:02.000000000 +0000 @@ -0,0 +1,1615 @@ +/* + * Standard PCI Hot Plug 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 "shpchp.h" + +#ifdef DEBUG +#define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */ +#define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */ +#define DBG_K_INFO ((unsigned int)0x00000004) /* Info messages */ +#define DBG_K_ERROR ((unsigned int)0x00000008) /* Error messages */ +#define DBG_K_TRACE (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT) +#define DBG_K_STANDARD (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE) +/* Redefine this flagword to set debug level */ +#define DEBUG_LEVEL DBG_K_STANDARD + +#define DEFINE_DBG_BUFFER char __dbg_str_buf[256]; + +#define DBG_PRINT( dbg_flags, args... ) \ + do { \ + if ( DEBUG_LEVEL & ( dbg_flags ) ) \ + { \ + int len; \ + len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \ + __FILE__, __LINE__, __FUNCTION__ ); \ + sprintf( __dbg_str_buf + len, args ); \ + printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \ + } \ + } while (0) + +#define DBG_ENTER_ROUTINE DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]"); +#define DBG_LEAVE_ROUTINE DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]"); +#else +#define DEFINE_DBG_BUFFER +#define DBG_ENTER_ROUTINE +#define DBG_LEAVE_ROUTINE +#endif /* DEBUG */ + +/* Slot Available Register I field definition */ +#define SLOT_33MHZ 0x0000001f +#define SLOT_66MHZ_PCIX 0x00001f00 +#define SLOT_100MHZ_PCIX 0x001f0000 +#define SLOT_133MHZ_PCIX 0x1f000000 + +/* Slot Available Register II field definition */ +#define SLOT_66MHZ 0x0000001f +#define SLOT_66MHZ_PCIX_266 0x00000f00 +#define SLOT_100MHZ_PCIX_266 0x0000f000 +#define SLOT_133MHZ_PCIX_266 0x000f0000 +#define SLOT_66MHZ_PCIX_533 0x00f00000 +#define SLOT_100MHZ_PCIX_533 0x0f000000 +#define SLOT_133MHZ_PCIX_533 0xf0000000 + +/* Secondary Bus Configuration Register */ +/* For PI = 1, Bits 0 to 2 have been encoded as follows to show current bus speed/mode */ +#define PCI_33MHZ 0x0 +#define PCI_66MHZ 0x1 +#define PCIX_66MHZ 0x2 +#define PCIX_100MHZ 0x3 +#define PCIX_133MHZ 0x4 + +/* For PI = 2, Bits 0 to 3 have been encoded as follows to show current bus speed/mode */ +#define PCI_33MHZ 0x0 +#define PCI_66MHZ 0x1 +#define PCIX_66MHZ 0x2 +#define PCIX_100MHZ 0x3 +#define PCIX_133MHZ 0x4 +#define PCIX_66MHZ_ECC 0x5 +#define PCIX_100MHZ_ECC 0x6 +#define PCIX_133MHZ_ECC 0x7 +#define PCIX_66MHZ_266 0x9 +#define PCIX_100MHZ_266 0x0a +#define PCIX_133MHZ_266 0x0b +#define PCIX_66MHZ_533 0x11 +#define PCIX_100MHZ_533 0x12 +#define PCIX_133MHZ_533 0x13 + +/* Slot Configuration */ +#define SLOT_NUM 0x0000001F +#define FIRST_DEV_NUM 0x00001F00 +#define PSN 0x07FF0000 +#define UPDOWN 0x20000000 +#define MRLSENSOR 0x40000000 +#define ATTN_BUTTON 0x80000000 + +/* Slot Status Field Definitions */ +/* Slot State */ +#define PWR_ONLY 0x0001 +#define ENABLED 0x0002 +#define DISABLED 0x0003 + +/* Power Indicator State */ +#define PWR_LED_ON 0x0004 +#define PWR_LED_BLINK 0x0008 +#define PWR_LED_OFF 0x000c + +/* Attention Indicator State */ +#define ATTEN_LED_ON 0x0010 +#define ATTEN_LED_BLINK 0x0020 +#define ATTEN_LED_OFF 0x0030 + +/* Power Fault */ +#define pwr_fault 0x0040 + +/* Attention Button */ +#define ATTEN_BUTTON 0x0080 + +/* MRL Sensor */ +#define MRL_SENSOR 0x0100 + +/* 66 MHz Capable */ +#define IS_66MHZ_CAP 0x0200 + +/* PRSNT1#/PRSNT2# */ +#define SLOT_EMP 0x0c00 + +/* PCI-X Capability */ +#define NON_PCIX 0x0000 +#define PCIX_66 0x1000 +#define PCIX_133 0x3000 +#define PCIX_266 0x4000 /* For PI = 2 only */ +#define PCIX_533 0x5000 /* For PI = 2 only */ + +/* SHPC 'write' operations/commands */ + +/* Slot operation - 0x00h to 0x3Fh */ + +#define NO_CHANGE 0x00 + +/* Slot state - Bits 0 & 1 of controller command register */ +#define SET_SLOT_PWR 0x01 +#define SET_SLOT_ENABLE 0x02 +#define SET_SLOT_DISABLE 0x03 + +/* Power indicator state - Bits 2 & 3 of controller command register*/ +#define SET_PWR_ON 0x04 +#define SET_PWR_BLINK 0x08 +#define SET_PWR_OFF 0x0C + +/* Attention indicator state - Bits 4 & 5 of controller command register*/ +#define SET_ATTN_ON 0x010 +#define SET_ATTN_BLINK 0x020 +#define SET_ATTN_OFF 0x030 + +/* Set bus speed/mode A - 0x40h to 0x47h */ +#define SETA_PCI_33MHZ 0x40 +#define SETA_PCI_66MHZ 0x41 +#define SETA_PCIX_66MHZ 0x42 +#define SETA_PCIX_100MHZ 0x43 +#define SETA_PCIX_133MHZ 0x44 +#define RESERV_1 0x45 +#define RESERV_2 0x46 +#define RESERV_3 0x47 + +/* Set bus speed/mode B - 0x50h to 0x5fh */ +#define SETB_PCI_33MHZ 0x50 +#define SETB_PCI_66MHZ 0x51 +#define SETB_PCIX_66MHZ_PM 0x52 +#define SETB_PCIX_100MHZ_PM 0x53 +#define SETB_PCIX_133MHZ_PM 0x54 +#define SETB_PCIX_66MHZ_EM 0x55 +#define SETB_PCIX_100MHZ_EM 0x56 +#define SETB_PCIX_133MHZ_EM 0x57 +#define SETB_PCIX_66MHZ_266 0x58 +#define SETB_PCIX_100MHZ_266 0x59 +#define SETB_PCIX_133MHZ_266 0x5a +#define SETB_PCIX_66MHZ_533 0x5b +#define SETB_PCIX_100MHZ_533 0x5c +#define SETB_PCIX_133MHZ_533 0x5d + +/* Power-on all slots - 0x48h */ +#define SET_PWR_ON_ALL 0x48 + +/* Enable all slots - 0x49h */ +#define SET_ENABLE_ALL 0x49 + +/* SHPC controller command error code */ +#define SWITCH_OPEN 0x1 +#define INVALID_CMD 0x2 +#define INVALID_SPEED_MODE 0x4 + +/* For accessing SHPC Working Register Set */ +#define DWORD_SELECT 0x2 +#define DWORD_DATA 0x4 +#define BASE_OFFSET 0x0 + +/* Field Offset in Logical Slot Register - byte boundary */ +#define SLOT_EVENT_LATCH 0x2 +#define SLOT_SERR_INT_MASK 0x3 + +static spinlock_t hpc_event_lock; + +DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ +static struct php_ctlr_state_s *php_ctlr_list_head = 0; /* HPC state linked list */ +static int ctlr_seq_num = 0; /* Controller sequenc # */ + +static spinlock_t list_lock; + +static void shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs); + +static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds); + +/* This is the interrupt polling timeout function. */ +static void int_poll_timeout(unsigned long lphp_ctlr) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr; + + DBG_ENTER_ROUTINE + + if ( !php_ctlr ) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return; + } + + /* Poll for interrupt events. regs == NULL => polling */ + shpc_isr( 0, (void *)php_ctlr, NULL ); + + init_timer(&php_ctlr->int_poll_timer); + if (!shpchp_poll_time) + shpchp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/ + + start_int_poll_timer(php_ctlr, shpchp_poll_time); + + return; +} + +/* This function starts the interrupt polling timer. */ +static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds) +{ + if (!php_ctlr) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return; + } + + if ( ( seconds <= 0 ) || ( seconds > 60 ) ) + seconds = 2; /* Clamp to sane value */ + + php_ctlr->int_poll_timer.function = &int_poll_timeout; + php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr; /* Instance data */ + php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ; + add_timer(&php_ctlr->int_poll_timer); + + return; +} + +static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u16 cmd_status; + int retval = 0; + u16 temp_word; + int i; + + DBG_ENTER_ROUTINE + + if (!php_ctlr) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + for (i = 0; i < 10; i++) { + cmd_status = readw(php_ctlr->creg + CMD_STATUS); + + if (!(cmd_status & 0x1)) + break; + /* Check every 0.1 sec for a total of 1 sec*/ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ/10); + } + + cmd_status = readw(php_ctlr->creg + CMD_STATUS); + + if (cmd_status & 0x1) { + /* After 1 sec and and the controller is still busy */ + err("%s : Controller is still busy after 1 sec.\n", __FUNCTION__); + return -1; + } + + ++t_slot; + temp_word = (t_slot << 8) | (cmd & 0xFF); + dbg("%s : t_slot %x cmd %x\n", __FUNCTION__, t_slot, cmd); + + /* To make sure the Controller Busy bit is 0 before we send out the + * command. + */ + writew(temp_word, php_ctlr->creg + CMD); + dbg("%s : temp_word written %x\n", __FUNCTION__, temp_word); + + DBG_LEAVE_ROUTINE + return retval; +} + +static int hpc_check_cmd_status(struct controller *ctrl) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle; + u16 cmd_status; + int retval = 0; + + DBG_ENTER_ROUTINE + + if (!ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + cmd_status = readw(php_ctlr->creg + CMD_STATUS) & 0x000F; + + switch (cmd_status >> 1) { + case 0: + retval = 0; + break; + case 1: + retval = SWITCH_OPEN; + err("%s: Switch opened!\n", __FUNCTION__); + break; + case 2: + retval = INVALID_CMD; + err("%s: Invalid HPC command!\n", __FUNCTION__); + break; + case 4: + retval = INVALID_SPEED_MODE; + err("%s: Invalid bus speed/mode!\n", __FUNCTION__); + break; + default: + retval = cmd_status; + } + + DBG_LEAVE_ROUTINE + return retval; +} + + +static int hpc_get_attention_status(struct slot *slot, u8 *status) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u32 slot_reg; + u16 slot_status; + u8 atten_led_state; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); + slot_status = (u16) slot_reg; + atten_led_state = (slot_status & 0x0030) >> 4; + + switch (atten_led_state) { + case 0: + *status = 0xFF; /* Reserved */ + break; + case 1: + *status = 1; /* On */ + break; + case 2: + *status = 2; /* Blink */ + break; + case 3: + *status = 0; /* Off */ + break; + default: + *status = 0xFF; + break; + } + + DBG_LEAVE_ROUTINE + return 0; +} + +static int hpc_get_power_status(struct slot * slot, u8 *status) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u32 slot_reg; + u16 slot_status; + u8 slot_state; + int retval = 0; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); + slot_status = (u16) slot_reg; + slot_state = (slot_status & 0x0003); + + switch (slot_state) { + case 0: + *status = 0xFF; + break; + case 1: + *status = 2; /* Powered only */ + break; + case 2: + *status = 1; /* Enabled */ + break; + case 3: + *status = 0; /* Disabled */ + break; + default: + *status = 0xFF; + break; + } + + DBG_LEAVE_ROUTINE + return retval; +} + + +static int hpc_get_latch_status(struct slot *slot, u8 *status) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u32 slot_reg; + u16 slot_status; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); + slot_status = (u16)slot_reg; + + *status = ((slot_status & 0x0100) == 0) ? 0 : 1; /* 0 -> close; 1 -> open */ + + DBG_LEAVE_ROUTINE + return 0; +} + +static int hpc_get_adapter_status(struct slot *slot, u8 *status) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u32 slot_reg; + u16 slot_status; + u8 card_state; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); + slot_status = (u16)slot_reg; + card_state = (u8)((slot_status & 0x0C00) >> 10); + *status = (card_state != 0x3) ? 1 : 0; + + DBG_LEAVE_ROUTINE + return 0; +} + +static int hpc_get_prog_int(struct slot *slot, u8 *prog_int) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + *prog_int = readb(php_ctlr->creg + PROG_INTERFACE); + + DBG_LEAVE_ROUTINE + return 0; +} + +static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u32 slot_reg; + u16 slot_status, sec_bus_status; + u8 m66_cap, pcix_cap, pi; + int retval = 0; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + if (slot->hp_slot >= php_ctlr->num_slots) { + err("%s: Invalid HPC slot number!\n", __FUNCTION__); + return -1; + } + + pi = readb(php_ctlr->creg + PROG_INTERFACE); + slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); + dbg("%s: pi = %d, slot_reg = %x\n", __FUNCTION__, pi, slot_reg); + slot_status = (u16) slot_reg; + dbg("%s: slot_status = %x\n", __FUNCTION__, slot_status); + sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG); + + pcix_cap = (u8) ((slot_status & 0x3000) >> 12); + dbg("%s: pcix_cap = %x\n", __FUNCTION__, pcix_cap); + m66_cap = (u8) ((slot_status & 0x0200) >> 9); + dbg("%s: m66_cap = %x\n", __FUNCTION__, m66_cap); + + if (pi == 2) { + switch (pcix_cap) { + case 0: + *value = m66_cap ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; + break; + case 1: + *value = PCI_SPEED_66MHz_PCIX; + break; + case 3: + *value = PCI_SPEED_133MHz_PCIX; + break; + case 4: + *value = PCI_SPEED_133MHz_PCIX_266; + break; + case 5: + *value = PCI_SPEED_133MHz_PCIX_533; + break; + case 2: /* Reserved */ + default: + *value = PCI_SPEED_UNKNOWN; + retval = -ENODEV; + break; + } + } else { + switch (pcix_cap) { + case 0: + *value = m66_cap ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; + break; + case 1: + *value = PCI_SPEED_66MHz_PCIX; + break; + case 3: + *value = PCI_SPEED_133MHz_PCIX; + break; + case 2: /* Reserved */ + default: + *value = PCI_SPEED_UNKNOWN; + retval = -ENODEV; + break; + } + } + + dbg("Adapter speed = %d\n", *value); + + DBG_LEAVE_ROUTINE + return retval; +} + +static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u16 sec_bus_status; + u8 pi; + int retval = 0; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + pi = readb(php_ctlr->creg + PROG_INTERFACE); + sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG); + + if (pi == 2) { + *mode = (sec_bus_status & 0x0100) >> 7; + } else { + retval = -1; + } + + dbg("Mode 1 ECC cap = %d\n", *mode); + + DBG_LEAVE_ROUTINE + return retval; +} + +static int hpc_query_power_fault(struct slot * slot) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u32 slot_reg; + u16 slot_status; + u8 pwr_fault_state, status; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot)); + slot_status = (u16) slot_reg; + pwr_fault_state = (slot_status & 0x0040) >> 7; + status = (pwr_fault_state == 1) ? 0 : 1; + + DBG_LEAVE_ROUTINE + /* Note: Logic 0 => fault */ + return status; +} + +static int hpc_set_attention_status(struct slot *slot, u8 value) +{ + struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u8 slot_cmd = 0; + int rc = 0; + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + if (slot->hp_slot >= php_ctlr->num_slots) { + err("%s: Invalid HPC slot number!\n", __FUNCTION__); + return -1; + } + + switch (value) { + case 0 : + slot_cmd = 0x30; /* OFF */ + break; + case 1: + slot_cmd = 0x10; /* ON */ + break; + case 2: + slot_cmd = 0x20; /* BLINK */ + break; + default: + return -1; + } + + shpc_write_cmd(slot, slot->hp_slot, slot_cmd); + + return rc; +} + + +static void hpc_set_green_led_on(struct slot *slot) +{ + struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u8 slot_cmd; + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return ; + } + + if (slot->hp_slot >= php_ctlr->num_slots) { + err("%s: Invalid HPC slot number!\n", __FUNCTION__); + return ; + } + + slot_cmd = 0x04; + + shpc_write_cmd(slot, slot->hp_slot, slot_cmd); + + return; +} + +static void hpc_set_green_led_off(struct slot *slot) +{ + struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u8 slot_cmd; + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return ; + } + + if (slot->hp_slot >= php_ctlr->num_slots) { + err("%s: Invalid HPC slot number!\n", __FUNCTION__); + return ; + } + + slot_cmd = 0x0C; + + shpc_write_cmd(slot, slot->hp_slot, slot_cmd); + + return; +} + +static void hpc_set_green_led_blink(struct slot *slot) +{ + struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u8 slot_cmd; + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return ; + } + + if (slot->hp_slot >= php_ctlr->num_slots) { + err("%s: Invalid HPC slot number!\n", __FUNCTION__); + return ; + } + + slot_cmd = 0x08; + + shpc_write_cmd(slot, slot->hp_slot, slot_cmd); + + return; +} + +int shpc_get_ctlr_slot_config(struct controller *ctrl, + int *num_ctlr_slots, /* number of slots in this HPC */ + int *first_device_num, /* PCI dev num of the first slot in this SHPC */ + int *physical_slot_num, /* phy slot num of the first slot in this SHPC */ + int *updown, /* physical_slot_num increament: 1 or -1 */ + int *flags) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle; + + DBG_ENTER_ROUTINE + + if (!ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + *first_device_num = php_ctlr->slot_device_offset; /* Obtained in shpc_init() */ + *num_ctlr_slots = php_ctlr->num_slots; /* Obtained in shpc_init() */ + + *physical_slot_num = (readl(php_ctlr->creg + SLOT_CONFIG) & PSN) >> 16; + dbg("%s: physical_slot_num = %x\n", __FUNCTION__, *physical_slot_num); + *updown = ((readl(php_ctlr->creg + SLOT_CONFIG) & UPDOWN ) >> 29) ? 1 : -1; + + DBG_LEAVE_ROUTINE + return 0; +} + +static void hpc_release_ctlr(struct controller *ctrl) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl->hpc_ctlr_handle; + struct php_ctlr_state_s *p, *p_prev; + + DBG_ENTER_ROUTINE + + if (!ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return ; + } + + if (shpchp_poll_mode) { + del_timer(&php_ctlr->int_poll_timer); + } else { + if (php_ctlr->irq) { + free_irq(php_ctlr->irq, ctrl); + php_ctlr->irq = 0; + } + } + if (php_ctlr->pci_dev) { + dbg("%s: before calling iounmap & release_mem_region\n", __FUNCTION__); + iounmap(php_ctlr->creg); + release_mem_region(pci_resource_start(php_ctlr->pci_dev, 0), pci_resource_len(php_ctlr->pci_dev, 0)); + dbg("%s: before calling iounmap & release_mem_region\n", __FUNCTION__); + php_ctlr->pci_dev = 0; + } + + spin_lock(&list_lock); + p = php_ctlr_list_head; + p_prev = NULL; + while (p) { + if (p == php_ctlr) { + if (p_prev) + p_prev->pnext = p->pnext; + else + php_ctlr_list_head = p->pnext; + break; + } else { + p_prev = p; + p = p->pnext; + } + } + spin_unlock(&list_lock); + + kfree(php_ctlr); + + DBG_LEAVE_ROUTINE + +} + +static int hpc_power_on_slot(struct slot * slot) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u8 slot_cmd; + int retval = 0; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + if (slot->hp_slot >= php_ctlr->num_slots) { + err("%s: Invalid HPC slot number!\n", __FUNCTION__); + return -1; + } + slot_cmd = 0x01; + + retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd); + + if (retval) { + err("%s: Write command failed!\n", __FUNCTION__); + return -1; + } + + DBG_LEAVE_ROUTINE + + return retval; +} + +static int hpc_slot_enable(struct slot * slot) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u8 slot_cmd; + int retval = 0; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + if (slot->hp_slot >= php_ctlr->num_slots) { + err("%s: Invalid HPC slot number!\n", __FUNCTION__); + return -1; + } + /* 3A => Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */ + slot_cmd = 0x3A; + + retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd); + + if (retval) { + err("%s: Write command failed!\n", __FUNCTION__); + return -1; + } + + DBG_LEAVE_ROUTINE + return retval; +} + +static int hpc_slot_disable(struct slot * slot) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + u8 slot_cmd; + int retval = 0; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + if (slot->hp_slot >= php_ctlr->num_slots) { + err("%s: Invalid HPC slot number!\n", __FUNCTION__); + return -1; + } + + /* 1F => Slot - Disable, Power Indicator - Off, Attention Indicator - On */ + slot_cmd = 0x1F; + + retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd); + + if (retval) { + err("%s: Write command failed!\n", __FUNCTION__); + return -1; + } + + DBG_LEAVE_ROUTINE + return retval; +} + +static int hpc_enable_all_slots( struct slot *slot ) +{ + int retval = 0; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + retval = shpc_write_cmd(slot, 0, SET_ENABLE_ALL); + if (retval) { + err("%s: Write command failed!\n", __FUNCTION__); + return -1; + } + + DBG_LEAVE_ROUTINE + + return retval; +} + +static int hpc_pwr_on_all_slots(struct slot *slot) +{ + int retval = 0; + + DBG_ENTER_ROUTINE + + retval = shpc_write_cmd(slot, 0, SET_PWR_ON_ALL); + + if (retval) { + err("%s: Write command failed!\n", __FUNCTION__); + return -1; + } + + DBG_LEAVE_ROUTINE + return retval; +} + +static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) +{ + u8 slot_cmd; + u8 pi; + int retval = 0; + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + pi = readb(php_ctlr->creg + PROG_INTERFACE); + + if (pi == 1) { + switch (value) { + case 0: + slot_cmd = SETA_PCI_33MHZ; + break; + case 1: + slot_cmd = SETA_PCI_66MHZ; + break; + case 2: + slot_cmd = SETA_PCIX_66MHZ; + break; + case 3: + slot_cmd = SETA_PCIX_100MHZ; + break; + case 4: + slot_cmd = SETA_PCIX_133MHZ; + break; + default: + slot_cmd = PCI_SPEED_UNKNOWN; + retval = -ENODEV; + return retval; + } + } else { + switch (value) { + case 0: + slot_cmd = SETB_PCI_33MHZ; + break; + case 1: + slot_cmd = SETB_PCI_66MHZ; + break; + case 2: + slot_cmd = SETB_PCIX_66MHZ_PM; + break; + case 3: + slot_cmd = SETB_PCIX_100MHZ_PM; + break; + case 4: + slot_cmd = SETB_PCIX_133MHZ_PM; + break; + case 5: + slot_cmd = SETB_PCIX_66MHZ_EM; + break; + case 6: + slot_cmd = SETB_PCIX_100MHZ_EM; + break; + case 7: + slot_cmd = SETB_PCIX_133MHZ_EM; + break; + case 8: + slot_cmd = SETB_PCIX_66MHZ_266; + break; + case 9: + slot_cmd = SETB_PCIX_100MHZ_266; + break; + case 0xa: + slot_cmd = SETB_PCIX_133MHZ_266; + break; + case 0xb: + slot_cmd = SETB_PCIX_66MHZ_533; + break; + case 0xc: + slot_cmd = SETB_PCIX_100MHZ_533; + break; + case 0xd: + slot_cmd = SETB_PCIX_133MHZ_533; + break; + default: + slot_cmd = PCI_SPEED_UNKNOWN; + retval = -ENODEV; + return retval; + } + + } + retval = shpc_write_cmd(slot, 0, slot_cmd); + if (retval) { + err("%s: Write command failed!\n", __FUNCTION__); + return -1; + } + + DBG_LEAVE_ROUTINE + return retval; +} + +static void shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) +{ + struct controller *ctrl = NULL; + struct php_ctlr_state_s *php_ctlr; + u8 schedule_flag = 0; + u8 temp_byte; + u32 temp_dword, intr_loc, intr_loc2; + int hp_slot; + + if (!dev_id) + return; + + if (!shpchp_poll_mode) { + ctrl = (struct controller *)dev_id; + php_ctlr = ctrl->hpc_ctlr_handle; + } else { + php_ctlr = (struct php_ctlr_state_s *) dev_id; + ctrl = (struct controller *)php_ctlr->callback_instance_id; + } + + if (!ctrl) + return; + + if (!php_ctlr || !php_ctlr->creg) + return; + + /* Check to see if it was our interrupt */ + intr_loc = readl(php_ctlr->creg + INTR_LOC); + + if (!intr_loc) + return; + + dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc); + + if (!shpchp_poll_mode) { + /* Mask Global Interrupt Mask - see implementation note on p. 139 */ + /* of SHPC spec rev 1.0*/ + temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); + dbg("%s: Before masking global interrupt, temp_dword = %x\n", + __FUNCTION__, temp_dword); + temp_dword |= 0x00000001; + dbg("%s: After masking global interrupt, temp_dword = %x\n", + __FUNCTION__, temp_dword); + writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); + + intr_loc2 = readl(php_ctlr->creg + INTR_LOC); + dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); + } + + if (intr_loc & 0x0001) { + /* + * Command Complete Interrupt Pending + * RO only - clear by writing 0 to the Command Completion + * Detect bit in Controller SERR-INT register + */ + temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); + dbg("%s: Before clearing CCIP, temp_dword = %x\n", + __FUNCTION__, temp_dword); + temp_dword &= 0xfffeffff; + dbg("%s: After clearing CCIP, temp_dword = %x\n", + __FUNCTION__, temp_dword); + writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); + + wake_up_interruptible(&ctrl->queue); + } + + if ((intr_loc = (intr_loc >> 1)) == 0) { + /* Unmask Global Interrupt Mask */ + temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); + dbg("%s: 1-Before unmasking global interrupt, temp_dword = %x\n", + __FUNCTION__, temp_dword); + temp_dword &= 0xfffffffe; + dbg("%s: 1-After unmasking global interrupt, temp_dword = %x\n", + __FUNCTION__, temp_dword); + writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); + return; + } + + for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { + /* To find out which slot has interrupt pending */ + if ((intr_loc >> hp_slot) & 0x01) { + temp_dword = readl(php_ctlr->creg + SLOT1 + (4*hp_slot)); + dbg("%s: Slot %x with intr, temp_dword = %x\n", + __FUNCTION__, hp_slot, temp_dword); + temp_byte = (temp_dword >> 16) & 0xFF; + dbg("%s: Slot with intr, temp_byte = %x\n", + __FUNCTION__, temp_byte); + if ((php_ctlr->switch_change_callback) && (temp_byte & 0x08)) + schedule_flag += php_ctlr->switch_change_callback( + hp_slot, php_ctlr->callback_instance_id); + if ((php_ctlr->attention_button_callback) && (temp_byte & 0x04)) + schedule_flag += php_ctlr->attention_button_callback( + hp_slot, php_ctlr->callback_instance_id); + if ((php_ctlr->presence_change_callback) && (temp_byte & 0x01)) + schedule_flag += php_ctlr->presence_change_callback( + hp_slot , php_ctlr->callback_instance_id); + if ((php_ctlr->power_fault_callback) && (temp_byte & 0x12)) + schedule_flag += php_ctlr->power_fault_callback( + hp_slot, php_ctlr->callback_instance_id); + + /* Clear all slot events */ + temp_dword = 0xe01fffff; + dbg("%s: Clearing slot events, temp_dword = %x\n", + __FUNCTION__, temp_dword); + writel(temp_dword, php_ctlr->creg + SLOT1 + (4*hp_slot)); + + intr_loc2 = readl(php_ctlr->creg + INTR_LOC); + dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); + } + } + + if (!shpchp_poll_mode) { + /* Unmask Global Interrupt Mask */ + temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); + dbg("%s: 2-Before unmasking global interrupt, temp_dword = %x\n", + __FUNCTION__, temp_dword); + temp_dword &= 0xfffffffe; + dbg("%s: 2-After unmasking global interrupt, temp_dword = %x\n", + __FUNCTION__, temp_dword); + writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); + } + + return; +} + +static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; + int retval = 0; + u8 pi; + u32 slot_avail1, slot_avail2; + int slot_num; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + if (slot->hp_slot >= php_ctlr->num_slots) { + err("%s: Invalid HPC slot number!\n", __FUNCTION__); + return -1; + } + + pi = readb(php_ctlr->creg + PROG_INTERFACE); + slot_avail1 = readl(php_ctlr->creg + SLOT_AVAIL1); + slot_avail2 = readl(php_ctlr->creg + SLOT_AVAIL2); + + if (pi == 2) { + if ((slot_num = ((slot_avail2 & SLOT_133MHZ_PCIX_533) >> 27) ) != 0 ) + bus_speed = PCIX_133MHZ_533; + else if ((slot_num = ((slot_avail2 & SLOT_100MHZ_PCIX_533) >> 23) ) != 0 ) + bus_speed = PCIX_100MHZ_533; + else if ((slot_num = ((slot_avail2 & SLOT_66MHZ_PCIX_533) >> 19) ) != 0 ) + bus_speed = PCIX_66MHZ_533; + else if ((slot_num = ((slot_avail2 & SLOT_133MHZ_PCIX_266) >> 15) ) != 0 ) + bus_speed = PCIX_133MHZ_266; + else if ((slot_num = ((slot_avail2 & SLOT_100MHZ_PCIX_266) >> 11) ) != 0 ) + bus_speed = PCIX_100MHZ_266; + else if ((slot_num = ((slot_avail2 & SLOT_66MHZ_PCIX_266) >> 7) ) != 0 ) + bus_speed = PCIX_66MHZ_266; + else if ((slot_num = ((slot_avail1 & SLOT_133MHZ_PCIX) >> 23) ) != 0 ) + bus_speed = PCIX_133MHZ; + else if ((slot_num = ((slot_avail1 & SLOT_100MHZ_PCIX) >> 15) ) != 0 ) + bus_speed = PCIX_100MHZ; + else if ((slot_num = ((slot_avail1 & SLOT_66MHZ_PCIX) >> 7) ) != 0 ) + bus_speed = PCIX_66MHZ; + else if ((slot_num = (slot_avail2 & SLOT_66MHZ)) != 0 ) + bus_speed = PCI_66MHZ; + else if ((slot_num = (slot_avail1 & SLOT_33MHZ)) != 0 ) + bus_speed = PCI_33MHZ; + else bus_speed = PCI_SPEED_UNKNOWN; + } else { + if ((slot_num = ((slot_avail1 & SLOT_133MHZ_PCIX) >> 23) ) != 0 ) + bus_speed = PCIX_133MHZ; + else if ((slot_num = ((slot_avail1 & SLOT_100MHZ_PCIX) >> 15) ) != 0 ) + bus_speed = PCIX_100MHZ; + else if ((slot_num = ((slot_avail1 & SLOT_66MHZ_PCIX) >> 7) ) != 0 ) + bus_speed = PCIX_66MHZ; + else if ((slot_num = (slot_avail2 & SLOT_66MHZ)) != 0 ) + bus_speed = PCI_66MHZ; + else if ((slot_num = (slot_avail1 & SLOT_33MHZ)) != 0 ) + bus_speed = PCI_33MHZ; + else bus_speed = PCI_SPEED_UNKNOWN; + } + + *value = bus_speed; + dbg("Max bus speed = %d\n", bus_speed); + DBG_LEAVE_ROUTINE + return retval; +} + +static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value) +{ + struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot->ctrl->hpc_ctlr_handle; + enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; + u16 sec_bus_status; + int retval = 0; + u8 pi; + + DBG_ENTER_ROUTINE + + if (!slot->ctrl->hpc_ctlr_handle) { + err("%s: Invalid HPC controller handle!\n", __FUNCTION__); + return -1; + } + + if (slot->hp_slot >= php_ctlr->num_slots) { + err("%s: Invalid HPC slot number!\n", __FUNCTION__); + return -1; + } + + pi = readb(php_ctlr->creg + PROG_INTERFACE); + sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG); + + if (pi == 2) { + switch (sec_bus_status & 0x000f) { + case 0: + bus_speed = PCI_SPEED_33MHz; + break; + case 1: + bus_speed = PCI_SPEED_66MHz; + break; + case 2: + bus_speed = PCI_SPEED_66MHz_PCIX; + break; + case 3: + bus_speed = PCI_SPEED_100MHz_PCIX; + break; + case 4: + bus_speed = PCI_SPEED_133MHz_PCIX; + break; + case 5: + bus_speed = PCI_SPEED_66MHz_PCIX_ECC; + break; + case 6: + bus_speed = PCI_SPEED_100MHz_PCIX_ECC; + break; + case 7: + bus_speed = PCI_SPEED_133MHz_PCIX_ECC; + break; + case 8: + bus_speed = PCI_SPEED_66MHz_PCIX_266; + break; + case 9: + bus_speed = PCI_SPEED_100MHz_PCIX_266; + break; + case 0xa: + bus_speed = PCI_SPEED_133MHz_PCIX_266; + break; + case 0xb: + bus_speed = PCI_SPEED_66MHz_PCIX_533; + break; + case 0xc: + bus_speed = PCI_SPEED_100MHz_PCIX_533; + break; + case 0xd: + bus_speed = PCI_SPEED_133MHz_PCIX_533; + break; + case 0xe: + case 0xf: + default: + bus_speed = PCI_SPEED_UNKNOWN; + break; + } + } else { + /* In the case where pi is undefined, default it to 1 */ + switch (sec_bus_status & 0x0007) { + case 0: + bus_speed = PCI_SPEED_33MHz; + break; + case 1: + bus_speed = PCI_SPEED_66MHz; + break; + case 2: + bus_speed = PCI_SPEED_66MHz_PCIX; + break; + case 3: + bus_speed = PCI_SPEED_100MHz_PCIX; + break; + case 4: + bus_speed = PCI_SPEED_133MHz_PCIX; + break; + case 5: + bus_speed = PCI_SPEED_UNKNOWN; /* Reserved */ + break; + case 6: + bus_speed = PCI_SPEED_UNKNOWN; /* Reserved */ + break; + case 7: + bus_speed = PCI_SPEED_UNKNOWN; /* Reserved */ + break; + default: + bus_speed = PCI_SPEED_UNKNOWN; + break; + } + } + *value = bus_speed; + dbg("Current bus speed = %d\n", bus_speed); + DBG_LEAVE_ROUTINE + return retval; + +} + +static struct hpc_ops shpchp_hpc_ops = { + .power_on_slot = hpc_power_on_slot, + .slot_enable = hpc_slot_enable, + .slot_disable = hpc_slot_disable, + .enable_all_slots = hpc_enable_all_slots, + .pwr_on_all_slots = hpc_pwr_on_all_slots, + .set_bus_speed_mode = hpc_set_bus_speed_mode, + .set_attention_status = hpc_set_attention_status, + .get_power_status = hpc_get_power_status, + .get_attention_status = hpc_get_attention_status, + .get_latch_status = hpc_get_latch_status, + .get_adapter_status = hpc_get_adapter_status, + + .get_max_bus_speed = hpc_get_max_bus_speed, + .get_cur_bus_speed = hpc_get_cur_bus_speed, + .get_adapter_speed = hpc_get_adapter_speed, + .get_mode1_ECC_cap = hpc_get_mode1_ECC_cap, + .get_prog_int = hpc_get_prog_int, + + .query_power_fault = hpc_query_power_fault, + .green_led_on = hpc_set_green_led_on, + .green_led_off = hpc_set_green_led_off, + .green_led_blink = hpc_set_green_led_blink, + + .release_ctlr = hpc_release_ctlr, + .check_cmd_status = hpc_check_cmd_status, +}; + +int shpc_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) +{ + struct php_ctlr_state_s *php_ctlr, *p; + void *instance_id = ctrl; + int rc; + u8 hp_slot; + static int first = 1; + u32 shpc_cap_offset, shpc_base_offset; + u32 tempdword, slot_reg; + u16 vendor_id, device_id; + u8 i; + + DBG_ENTER_ROUTINE + + spin_lock_init(&list_lock); + php_ctlr = (struct php_ctlr_state_s *) kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL); + + if (!php_ctlr) { /* allocate controller state data */ + err("%s: HPC controller memory allocation error!\n", __FUNCTION__); + goto abort; + } + + memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s)); + + php_ctlr->pci_dev = pdev; /* save pci_dev in context */ + + rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id); + dbg("%s: Vendor ID: %x\n",__FUNCTION__, vendor_id); + if (rc) { + err("%s: Unable to read PCI COnfiguration data\n", __FUNCTION__); + goto abort_free_ctlr; + } + + rc = pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); + dbg("%s: Device ID: %x\n",__FUNCTION__, device_id); + if (rc) { + err("%s: Unable to read PCI COnfiguration data\n", __FUNCTION__); + goto abort_free_ctlr; + } + + if ((vendor_id == PCI_VENDOR_ID_AMD) || (device_id == PCI_DEVICE_ID_AMD_GOLAM_7450)) { + shpc_base_offset = 0; /* amd shpc driver doesn't use this; assume 0 */ + } else { + if ((shpc_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC)) == 0) { + err("%s : shpc_cap_offset == 0\n", __FUNCTION__); + goto abort_free_ctlr; + } + dbg("%s: shpc_cap_offset = %x\n", __FUNCTION__, shpc_cap_offset); + + rc = pci_write_config_byte(pdev, (u8)shpc_cap_offset + DWORD_SELECT , BASE_OFFSET); + if (rc) { + err("%s : pci_word_config_byte failed\n", __FUNCTION__); + goto abort_free_ctlr; + } + + rc = pci_read_config_dword(pdev, (u8)shpc_cap_offset + DWORD_DATA, &shpc_base_offset); + if (rc) { + err("%s : pci_read_config_dword failed\n", __FUNCTION__); + goto abort_free_ctlr; + } + + for (i = 0; i <= 14; i++) { + rc = pci_write_config_byte(pdev, (u8)shpc_cap_offset + DWORD_SELECT , i); + if (rc) { + err("%s : pci_word_config_byte failed\n", __FUNCTION__); + goto abort_free_ctlr; + } + + rc = pci_read_config_dword(pdev, (u8)shpc_cap_offset + DWORD_DATA, &tempdword); + if (rc) { + err("%s : pci_read_config_dword failed\n", __FUNCTION__); + goto abort_free_ctlr; + } + dbg("%s: offset %d: tempdword %x\n", __FUNCTION__,i, tempdword); + } + } + + if (first) { + spin_lock_init(&hpc_event_lock); + first = 0; + } + + dbg("pdev = %p: b:d:f:irq=0x%x:%x:%x:%x\n", pdev, pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), pdev->irq); + for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) + if (pci_resource_len(pdev, rc) > 0) + dbg("pci resource[%d] start=0x%lx(len=0x%lx), shpc_base_offset %x\n", rc, + pci_resource_start(pdev, rc), pci_resource_len(pdev, rc), shpc_base_offset); + + info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, + pdev->subsystem_vendor, pdev->subsystem_device); + + if (!request_mem_region(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0), MY_NAME)) { + err("%s: cannot reserve MMIO region\n", __FUNCTION__); + goto abort_free_ctlr; + } + + php_ctlr->creg = (struct ctrl_reg *) + ioremap(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0)); + if (!php_ctlr->creg) { + err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__, pci_resource_len(pdev, 0), + pci_resource_start(pdev, 0) + shpc_base_offset); + release_mem_region(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0)); + goto abort_free_ctlr; + } + dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg); + dbg("%s: physical addr %p\n", __FUNCTION__, (void*)pci_resource_start(pdev, 0)); + + init_MUTEX(&ctrl->crit_sect); + /* Ssetup wait queue */ + init_waitqueue_head(&ctrl->queue); + + /* Find the IRQ */ + php_ctlr->irq = pdev->irq; + dbg("HPC interrupt = %d\n", php_ctlr->irq); + + /* Save interrupt callback info */ + php_ctlr->attention_button_callback = attention_button_callback; + php_ctlr->switch_change_callback = switch_change_callback; + php_ctlr->presence_change_callback = presence_change_callback; + php_ctlr->power_fault_callback = power_fault_callback; + php_ctlr->callback_instance_id = instance_id; + + /* Return PCI Controller Info */ + php_ctlr->slot_device_offset = (readl(php_ctlr->creg + SLOT_CONFIG) & FIRST_DEV_NUM ) >> 8; + php_ctlr->num_slots = readl(php_ctlr->creg + SLOT_CONFIG) & SLOT_NUM; + dbg("%s: slot_device_offset %x\n", __FUNCTION__, php_ctlr->slot_device_offset); + dbg("%s: num_slots %x\n", __FUNCTION__, php_ctlr->num_slots); + + /* Mask Global Interrupt Mask & Command Complete Interrupt Mask */ + tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE); + dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); + tempdword = 0x0003000f; + writel(tempdword, php_ctlr->creg + SERR_INTR_ENABLE); + tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE); + dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); + + /* Mask the MRL sensor SERR Mask of individual slot in + * Slot SERR-INT Mask & clear all the existing event if any + */ + for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { + slot_reg = readl(php_ctlr->creg + SLOT1 + 4*hp_slot ); + dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, + hp_slot, slot_reg); + tempdword = 0xffffffff; + writel(tempdword, php_ctlr->creg + SLOT1 + (4*hp_slot)); + } + + if (shpchp_poll_mode) {/* Install interrupt polling code */ + /* Install and start the interrupt polling timer */ + init_timer(&php_ctlr->int_poll_timer); + start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */ + } else { + /* Installs the interrupt handler */ +#ifdef CONFIG_PCI_USE_VECTOR + rc = pci_enable_msi(pdev); + if (rc) { + info("Can't get msi for the hotplug controller\n"); + info("Use INTx for the hotplug controller\n"); + dbg("%s: rc = %x\n", __FUNCTION__, rc); + } else + php_ctlr->irq = pdev->irq; +#endif + rc = request_irq(php_ctlr->irq, shpc_isr, SA_SHIRQ, MY_NAME, (void *) ctrl); + dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, + ctlr_seq_num, rc); + if (rc) { + err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq); + goto abort_free_ctlr; + } + /* Execute OSHP method here */ + } + dbg("%s: Before adding HPC to HPC list\n", __FUNCTION__); + + /* Add this HPC instance into the HPC list */ + spin_lock(&list_lock); + if (php_ctlr_list_head == 0) { + php_ctlr_list_head = php_ctlr; + p = php_ctlr_list_head; + p->pnext = 0; + } else { + p = php_ctlr_list_head; + + while (p->pnext) + p = p->pnext; + + p->pnext = php_ctlr; + } + spin_unlock(&list_lock); + + ctlr_seq_num++; + ctrl->hpc_ctlr_handle = php_ctlr; + ctrl->hpc_ops = &shpchp_hpc_ops; + for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) { + slot_reg = readl(php_ctlr->creg + SLOT1 + 4*hp_slot ); + dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, + hp_slot, slot_reg); + tempdword = 0xe01fffff; + writel(tempdword, php_ctlr->creg + SLOT1 + (4*hp_slot)); + } + if (!shpchp_poll_mode) { + /* Unmask all general input interrupts and SERR */ + tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE); + tempdword = 0x0000000a; + writel(tempdword, php_ctlr->creg + SERR_INTR_ENABLE); + tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE); + dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); + } + + dbg("%s: Leaving shpc_init\n", __FUNCTION__); + DBG_LEAVE_ROUTINE + return 0; + + /* We end up here for the many possible ways to fail this API. */ +abort_free_ctlr: + kfree(php_ctlr); +abort: + DBG_LEAVE_ROUTINE + return -1; +} diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/shpchp_pci.c linux-2.4.27-pre5/drivers/hotplug/shpchp_pci.c --- linux-2.4.26/drivers/hotplug/shpchp_pci.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/shpchp_pci.c 2004-06-03 01:33:00.000000000 +0000 @@ -0,0 +1,1043 @@ +/* + * Standard 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 "shpchp.h" +#ifndef CONFIG_IA64 +#include "../../arch/i386/kernel/pci-i386.h" /* horrible hack showing how processor dependant we are... */ +#endif + +static int is_pci_dev_in_use(struct pci_dev* dev) +{ + /* + * dev->driver will be set if the device is in use by a new-style + * driver -- otherwise, check the device's regions to see if any + * driver has claimed them + */ + + int i, inuse=0; + + if (dev->driver) return 1; /* Assume driver feels responsible */ + + for (i = 0; !dev->driver && !inuse && (i < 6); i++) { + if (!pci_resource_start(dev, i)) + continue; + + if (pci_resource_flags(dev, i) & IORESOURCE_IO) + inuse = check_region(pci_resource_start(dev, i), + pci_resource_len(dev, i)); + else if (pci_resource_flags(dev, i) & IORESOURCE_MEM) + inuse = check_mem_region(pci_resource_start(dev, i), + pci_resource_len(dev, i)); + } + + return inuse; + +} + + +static int pci_hp_remove_device(struct pci_dev *dev) +{ + if (is_pci_dev_in_use(dev)) { + err("***Cannot safely power down device -- " + "it appears to be in use***\n"); + return -EBUSY; + } + pci_remove_device(dev); + return 0; +} + + +static int configure_visit_pci_dev (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) +{ + struct pci_bus* bus = wrapped_bus->bus; + struct pci_dev* dev = wrapped_dev->dev; + struct pci_func *temp_func; + int i=0; + + dbg("%s: Enter\n", __FUNCTION__); + /* We need to fix up the hotplug function representation with the linux representation */ + do { + temp_func = shpchp_slot_find(dev->bus->number, dev->devfn >> 3, i++); + dbg("%s: i %d temp_func %p, bus %x dev %x\n", __FUNCTION__, i, temp_func, + dev->bus->number, dev->devfn >>3); + } while (temp_func && (temp_func->function != (dev->devfn & 0x07))); + + if (temp_func) { + temp_func->pci_dev = dev; + dbg("%s: dev %p dev->irq %x\n", __FUNCTION__, dev, dev->irq); + } else { + /* We did not even find a hotplug rep of the function, create it + * This code might be taken out if we can guarantee the creation of functions + * in parallel (hotplug and Linux at the same time). + */ + dbg("@@@@@@@@@@@ shpchp_slot_create in %s\n", __FUNCTION__); + temp_func = shpchp_slot_create(bus->number); + if (temp_func == NULL) + return -ENOMEM; + temp_func->pci_dev = dev; + } + + /* Create /proc/bus/pci proc entry for this device and bus device is on */ + /* Notify the drivers of the change */ + if (temp_func->pci_dev) { + dbg("%s: PCI_ID=%04X:%04X\n", __FUNCTION__, temp_func->pci_dev->vendor, + temp_func->pci_dev->device); + dbg("%s: PCI BUS %x DEVFN %x\n", __FUNCTION__, temp_func->pci_dev->bus->number, + temp_func->pci_dev->devfn); + dbg("%s: PCI_SLOT_NAME %s\n", __FUNCTION__, + temp_func->pci_dev->slot_name); + pci_enable_device(temp_func->pci_dev); + pci_proc_attach_device(temp_func->pci_dev); + pci_announce_device_to_drivers(temp_func->pci_dev); + } + + return 0; +} + + +static int unconfigure_visit_pci_dev_phase2 (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) +{ + struct pci_dev* dev = wrapped_dev->dev; + + struct pci_func *temp_func; + int i=0; + + /* We need to remove the hotplug function representation with the linux representation */ + do { + temp_func = shpchp_slot_find(dev->bus->number, dev->devfn >> 3, i++); + if (temp_func) { + dbg("temp_func->function = %d\n", temp_func->function); + } + } while (temp_func && (temp_func->function != (dev->devfn & 0x07))); + + /* Now, remove the Linux Representation */ + if (dev) { + if (pci_hp_remove_device(dev) == 0) { + kfree(dev); /* Now, remove */ + } else { + return -1; /* problems while freeing, abort visitation */ + } + } + + if (temp_func) { + temp_func->pci_dev = NULL; + } else { + dbg("No pci_func representation for bus, devfn = %d, %x\n", dev->bus->number, dev->devfn); + } + + return 0; +} + + +static int unconfigure_visit_pci_bus_phase2 (struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_dev) +{ + struct pci_bus* bus = wrapped_bus->bus; + + /* The cleanup code for proc entries regarding buses should be in the kernel...*/ + if (bus->procdir) + dbg("detach_pci_bus %s\n", bus->procdir->name); + pci_proc_detach_bus(bus); + /* The cleanup code should live in the kernel... */ + bus->self->subordinate = NULL; + /* Unlink from parent bus */ + list_del(&bus->node); + + /* Now, remove */ + if (bus) + kfree(bus); + + return 0; +} + + +static int unconfigure_visit_pci_dev_phase1 (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) +{ + struct pci_dev* dev = wrapped_dev->dev; + int rc; + + dbg("attempting removal of driver for device (%x, %x, %x)\n", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + /* Now, remove the Linux Driver Representation */ + if (dev->driver) { + if (dev->driver->remove) { + dev->driver->remove(dev); + dbg("driver was properly removed\n"); + } + dev->driver = NULL; + } + + rc = is_pci_dev_in_use(dev); + if (rc) + info("%s: device still in use\n", __FUNCTION__); + return rc; +} + + +static struct pci_visit configure_functions = { + .visit_pci_dev = configure_visit_pci_dev, +}; + + +static struct pci_visit unconfigure_functions_phase1 = { + .post_visit_pci_dev = unconfigure_visit_pci_dev_phase1 +}; + +static struct pci_visit unconfigure_functions_phase2 = { + .post_visit_pci_bus = unconfigure_visit_pci_bus_phase2, + .post_visit_pci_dev = unconfigure_visit_pci_dev_phase2 +}; + + +int shpchp_configure_device (struct controller* ctrl, struct pci_func* func) +{ + unsigned char bus; + struct pci_dev dev0; + struct pci_bus *child; + struct pci_dev* temp; + int rc = 0; + + struct pci_dev_wrapped wrapped_dev; + struct pci_bus_wrapped wrapped_bus; + + dbg("%s: Enter\n", __FUNCTION__); + memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped)); + memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped)); + + memset(&dev0, 0, sizeof(struct pci_dev)); + + dbg("%s: func->pci_dev %p\n", __FUNCTION__, func->pci_dev); + if (func->pci_dev != NULL) + dbg("%s: func->pci_dev->irq %x\n", __FUNCTION__, func->pci_dev->irq); + if (func->pci_dev == NULL) + func->pci_dev = pci_find_slot(func->bus, (func->device << 3) | (func->function & 0x7)); + dbg("%s: after pci_find_slot, func->pci_dev %p\n", __FUNCTION__, func->pci_dev); + if (func->pci_dev != NULL) + dbg("%s: after pci_find_slot, func->pci_dev->irq %x\n", __FUNCTION__, func->pci_dev->irq); + + /* Still NULL ? Well then scan for it ! */ + if (func->pci_dev == NULL) { + dbg("%s: pci_dev still null. do pci_scan_slot\n", __FUNCTION__); + dev0.bus = ctrl->pci_dev->subordinate; + dbg("%s: dev0.bus %p\n", __FUNCTION__, dev0.bus); + dev0.bus->number = func->bus; + dbg("%s: dev0.bus->number %x\n", __FUNCTION__, func->bus); + dev0.devfn = PCI_DEVFN(func->device, func->function); + dev0.sysdata = ctrl->pci_dev->sysdata; + + /* this will generate pci_dev structures for all functions, + * but we will only call this case when lookup fails + */ + dbg("%s: dev0.irq %x\n", __FUNCTION__, dev0.irq); + func->pci_dev = pci_scan_slot(&dev0); + dbg("%s: func->pci_dev->irq %x\n", __FUNCTION__, + func->pci_dev->irq); + if (func->pci_dev == NULL) { + dbg("ERROR: pci_dev still null\n"); + return 0; + } + } + + if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus); + child = (struct pci_bus*) pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus); + dbg("%s: calling pci_do_scan_bus\n", __FUNCTION__); + pci_do_scan_bus(child); + + } + + temp = func->pci_dev; + dbg("%s: func->pci_dev->irq %x\n", __FUNCTION__, func->pci_dev->irq); + + if (temp) { + wrapped_dev.dev = temp; + wrapped_bus.bus = temp->bus; + rc = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus); + } + + dbg("%s: Exit\n", __FUNCTION__); + return rc; +} + + +int shpchp_unconfigure_device(struct pci_func* func) +{ + int rc = 0; + int j; + struct pci_dev_wrapped wrapped_dev; + struct pci_bus_wrapped wrapped_bus; + + memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped)); + memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped)); + + dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus, func->device, func->function); + + for (j=0; j<8 ; j++) { + struct pci_dev* temp = pci_find_slot(func->bus, (func->device << 3) | j); + if (temp) { + wrapped_dev.dev = temp; + wrapped_bus.bus = temp->bus; + rc = pci_visit_dev(&unconfigure_functions_phase1, &wrapped_dev, &wrapped_bus); + if (rc) + break; + + rc = pci_visit_dev(&unconfigure_functions_phase2, &wrapped_dev, &wrapped_bus); + if (rc) + break; + } + } + return rc; +} + +/* + * shpchp_set_irq + * + * @bus_num: bus number of PCI device + * @dev_num: device number of PCI device + * @slot: pointer to u8 where slot number will be returned + */ +int shpchp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) +{ +#if defined(CONFIG_X86) && !defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64) + int rc; + u16 temp_word; + struct pci_dev fakedev; + struct pci_bus fakebus; + + fakedev.devfn = dev_num << 3; + fakedev.bus = &fakebus; + fakebus.number = bus_num; + dbg("%s: dev %d, bus %d, pin %d, num %d\n", + __FUNCTION__, dev_num, bus_num, int_pin, irq_num); + rc = pcibios_set_irq_routing(&fakedev, int_pin - 0x0a, irq_num); + dbg("%s: rc %d\n", __FUNCTION__, rc); + if (!rc) + return !rc; + + /* set the Edge Level Control Register (ELCR) */ + temp_word = inb(0x4d0); + temp_word |= inb(0x4d1) << 8; + + temp_word |= 0x01 << irq_num; + + /* This should only be for x86 as it sets the Edge Level Control Register */ + outb((u8) (temp_word & 0xFF), 0x4d0); + outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1); +#endif + return 0; +} + +/* More PCI configuration routines; this time centered around hotplug controller */ + + +/* + * shpchp_save_config + * + * Reads configuration for all slots in a PCI bus and saves info. + * + * Note: For non-hot plug busses, the slot # saved is the device # + * + * returns 0 if success + */ +int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num) +{ + int rc; + u8 class_code; + u8 header_type; + u32 ID; + u8 secondary_bus; + struct pci_func *new_slot; + int sub_bus; + int FirstSupported; + int LastSupported; + int max_functions; + int function; + u8 DevError; + int device = 0; + int cloop = 0; + int stop_it; + int index; + int is_hot_plug = num_ctlr_slots || first_device_num; + struct pci_bus lpci_bus, *pci_bus; + + dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__, num_ctlr_slots, first_device_num); + + memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); + pci_bus = &lpci_bus; + + dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__, num_ctlr_slots, first_device_num); + + /* Decide which slots are supported */ + if (is_hot_plug) { + /********************************* + * is_hot_plug is the slot mask + *********************************/ + FirstSupported = first_device_num; + LastSupported = FirstSupported + num_ctlr_slots - 1; + } else { + FirstSupported = 0; + LastSupported = 0x1F; + } + + dbg("FirstSupported = %d, LastSupported = %d\n", FirstSupported, LastSupported); + + /* Save PCI configuration space for all devices in supported slots */ + pci_bus->number = busnumber; + for (device = FirstSupported; device <= LastSupported; device++) { + ID = 0xFFFFFFFF; + rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID); + + if (ID != 0xFFFFFFFF) { /* device in slot */ + rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code); + if (rc) + return rc; + + rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; + + dbg("class_code = %x, header_type = %x\n", class_code, header_type); + + /* If multi-function device, set max_functions to 8 */ + if (header_type & 0x80) + max_functions = 8; + else + max_functions = 1; + + function = 0; + + do { + DevError = 0; + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* P-P Bridge */ + /* Recurse the subordinate bus + * get the subordinate bus number + */ + rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus); + if (rc) { + return rc; + } else { + sub_bus = (int) secondary_bus; + + /* Save secondary bus cfg spc with this recursive call. */ + rc = shpchp_save_config(ctrl, sub_bus, 0, 0); + if (rc) + return rc; + } + } + + index = 0; + new_slot = shpchp_slot_find(busnumber, device, index++); + + dbg("new_slot = %p\n", new_slot); + + while (new_slot && (new_slot->function != (u8) function)) { + new_slot = shpchp_slot_find(busnumber, device, index++); + dbg("new_slot = %p\n", new_slot); + } + if (!new_slot) { + /* Setup slot structure. */ + new_slot = shpchp_slot_create(busnumber); + dbg("new_slot = %p\n", new_slot); + + if (new_slot == NULL) + return(1); + } + + new_slot->bus = (u8) busnumber; + new_slot->device = (u8) device; + new_slot->function = (u8) function; + new_slot->is_a_board = 1; + new_slot->switch_save = 0x10; + /* In case of unsupported board */ + new_slot->status = DevError; + new_slot->pci_dev = pci_find_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function); + dbg("new_slot->pci_dev = %p\n", new_slot->pci_dev); + + for (cloop = 0; cloop < 0x20; cloop++) { + rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot->config_space [cloop])); + dbg("%s: new_slot->config_space[%x] = %x\n", __FUNCTION__, cloop, new_slot->config_space[cloop]); + if (rc) + return rc; + } + + function++; + + stop_it = 0; + + /* This loop skips to the next present function + * reading in Class Code and Header type. + */ + + while ((function < max_functions)&&(!stop_it)) { + rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID); + + if (ID == 0xFFFFFFFF) { /* nothing there. */ + function++; + dbg("Nothing there\n"); + } else { /* Something there */ + rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code); + if (rc) + return rc; + + rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; + + dbg("class_code = %x, header_type = %x\n", class_code, header_type); + stop_it++; + } + } + + } while (function < max_functions); + } /* End of IF (device in slot?) */ + else if (is_hot_plug) { + /* Setup slot structure with entry for empty slot */ + new_slot = shpchp_slot_create(busnumber); + + if (new_slot == NULL) { + return(1); + } + dbg("new_slot = %p\n", new_slot); + + new_slot->bus = (u8) busnumber; + new_slot->device = (u8) device; + new_slot->function = 0; + new_slot->is_a_board = 0; + new_slot->presence_save = 0; + new_slot->switch_save = 0; + } + } /* End of FOR loop */ + + return(0); +} + + +/* + * shpchp_save_slot_config + * + * Saves configuration info for all PCI devices in a given slot + * including subordinate busses. + * + * returns 0 if success + */ +int shpchp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) +{ + int rc; + u8 class_code; + u8 header_type; + u32 ID; + u8 secondary_bus; + int sub_bus; + int max_functions; + int function; + int cloop = 0; + int stop_it; + struct pci_bus lpci_bus, *pci_bus; + + memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); + pci_bus = &lpci_bus; + pci_bus->number = new_slot->bus; + + ID = 0xFFFFFFFF; + + pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_VENDOR_ID, &ID); + + if (ID != 0xFFFFFFFF) { /* device in slot */ + pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code); + + pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type); + + if (header_type & 0x80) /* Multi-function device */ + max_functions = 8; + else + max_functions = 1; + + function = 0; + + do { + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */ + /* Recurse the subordinate bus */ + pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus); + + sub_bus = (int) secondary_bus; + + /* Save the config headers for the secondary bus. */ + rc = shpchp_save_config(ctrl, sub_bus, 0, 0); + + if (rc) + return(rc); + + } /* End of IF */ + + new_slot->status = 0; + + for (cloop = 0; cloop < 0x20; cloop++) { + pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot->config_space [cloop])); + dbg("%s: new_slot->config_space[%x] = %x\n", __FUNCTION__,cloop, new_slot->config_space[cloop]); + } + + function++; + + stop_it = 0; + + /* this loop skips to the next present function + * reading in the Class Code and the Header type. + */ + + while ((function < max_functions) && (!stop_it)) { + pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID); + + if (ID == 0xFFFFFFFF) { /* nothing there. */ + function++; + } else { /* Something there */ + pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code); + + pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type); + + stop_it++; + } + } + + } while (function < max_functions); + } /* End of IF (device in slot?) */ + else { + return(2); + } + + return(0); +} + + +/* + * shpchp_save_used_resources + * + * Stores used resource information for existing boards. this is + * for boards that were in the system when this driver was loaded. + * this function is for hot plug ADD + * + * returns 0 if success + * if disable == 1(DISABLE_CARD), + * it loops for all functions of the slot and disables them. + * else, it just get resources of the function and return. + */ +int shpchp_save_used_resources (struct controller *ctrl, struct pci_func *func, int disable) +{ + u8 cloop; + u8 header_type; + u8 secondary_bus; + u8 temp_byte; + u16 command; + u16 save_command; + u16 w_base, w_length; + u32 temp_register; + u32 save_base; + u32 base, length; + u64 base64 = 0; + int index = 0; + unsigned int devfn; + struct pci_resource *mem_node = NULL; + struct pci_resource *p_mem_node = NULL; + struct pci_resource *t_mem_node; + struct pci_resource *io_node; + struct pci_resource *bus_node; + struct pci_bus lpci_bus, *pci_bus; + + memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus)); + pci_bus = &lpci_bus; + + if (disable) + func = shpchp_slot_find(func->bus, func->device, index++); + + while ((func != NULL) && func->is_a_board) { + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + /* Save the command register */ + pci_bus_read_config_word (pci_bus, devfn, PCI_COMMAND, &save_command); + + if (disable) { + /* disable card */ + command = 0x00; + pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); + } + + /* Check for Bridge */ + pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */ + dbg("Save_used_res of PCI bridge b:d=0x%x:%x, sc=0x%x\n", func->bus, func->device, save_command); + if (disable) { + /* Clear Bridge Control Register */ + command = 0x00; + pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command); + } + + pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); + pci_bus_read_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte); + + bus_node =(struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!bus_node) + return -ENOMEM; + + bus_node->base = (ulong)secondary_bus; + bus_node->length = (ulong)(temp_byte - secondary_bus + 1); + + bus_node->next = func->bus_head; + func->bus_head = bus_node; + + /* Save IO base and Limit registers */ + pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_BASE, &temp_byte); + base = temp_byte; + pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_LIMIT, &temp_byte); + length = temp_byte; + + if ((base <= length) && (!disable || (save_command & PCI_COMMAND_IO))) { + io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!io_node) + return -ENOMEM; + + io_node->base = (ulong)(base & PCI_IO_RANGE_MASK) << 8; + io_node->length = (ulong)(length - base + 0x10) << 8; + + io_node->next = func->io_head; + func->io_head = io_node; + } + + /* Save memory base and Limit registers */ + pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_BASE, &w_base); + pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length); + + if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) { + mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!mem_node) + return -ENOMEM; + + mem_node->base = (ulong)w_base << 16; + mem_node->length = (ulong)(w_length - w_base + 0x10) << 16; + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } + /* Save prefetchable memory base and Limit registers */ + pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base); + pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length); + + if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) { + p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!p_mem_node) + return -ENOMEM; + + p_mem_node->base = (ulong)w_base << 16; + p_mem_node->length = (ulong)(w_length - w_base + 0x10) << 16; + + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } + } else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) { + dbg("Save_used_res of PCI adapter b:d=0x%x:%x, sc=0x%x\n", func->bus, func->device, save_command); + + /* Figure out IO and memory base lengths */ + for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) { + pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base); + + temp_register = 0xFFFFFFFF; + pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); + pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp_register); + + if (!disable) { + pci_bus_write_config_dword (pci_bus, devfn, cloop, save_base); + } + + if (!temp_register) + continue; + + base = temp_register; + + if ((base & PCI_BASE_ADDRESS_SPACE_IO) && (!disable || (save_command & PCI_COMMAND_IO))) { + /* IO base */ + /* set temp_register = amount of IO space requested */ + base = base & 0xFFFFFFFCL; + base = (~base) + 1; + + io_node = (struct pci_resource *) kmalloc(sizeof (struct pci_resource), GFP_KERNEL); + if (!io_node) + return -ENOMEM; + + io_node->base = (ulong)save_base & PCI_BASE_ADDRESS_IO_MASK; + io_node->length = (ulong)base; + dbg("sur adapter: IO bar=0x%x(length=0x%x)\n", io_node->base, io_node->length); + + io_node->next = func->io_head; + func->io_head = io_node; + } else { /* map Memory */ + int prefetchable = 1; + /* struct pci_resources **res_node; */ + char *res_type_str = "PMEM"; + u32 temp_register2; + + t_mem_node = (struct pci_resource *) kmalloc(sizeof (struct pci_resource), GFP_KERNEL); + if (!t_mem_node) + return -ENOMEM; + + if (!(base & PCI_BASE_ADDRESS_MEM_PREFETCH) && (!disable || (save_command & PCI_COMMAND_MEMORY))) { + prefetchable = 0; + mem_node = t_mem_node; + res_type_str++; + } else + p_mem_node = t_mem_node; + + base = base & 0xFFFFFFF0L; + base = (~base) + 1; + + switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) { + case PCI_BASE_ADDRESS_MEM_TYPE_32: + if (prefetchable) { + p_mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK; + p_mem_node->length = (ulong)base; + dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n", res_type_str, p_mem_node->base, p_mem_node->length); + + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } else { + mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK; + mem_node->length = (ulong)base; + dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n", res_type_str, mem_node->base, mem_node->length); + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } + break; + case PCI_BASE_ADDRESS_MEM_TYPE_64: + pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2); + base64 = temp_register2; + base64 = (base64 << 32) | save_base; + + if (temp_register2) { + dbg("sur adapter: 64 %s high dword of base64(0x%x:%x) masked to 0\n", res_type_str, temp_register2, (u32)base64); + base64 &= 0x00000000FFFFFFFFL; + } + + if (prefetchable) { + p_mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK; + p_mem_node->length = base; + dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n", res_type_str, p_mem_node->base, p_mem_node->length); + + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } else { + mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK; + mem_node->length = base; + dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n", res_type_str, mem_node->base, mem_node->length); + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } + cloop += 4; + break; + default: + dbg("asur: reserved BAR type=0x%x\n", temp_register); + break; + } + } + } /* End of base register loop */ + } else { /* Some other unknown header type */ + dbg("Save_used_res of PCI unknown type b:d=0x%x:%x. skip.\n", func->bus, func->device); + } + + /* find the next device in this slot */ + if (!disable) + break; + func = shpchp_slot_find(func->bus, func->device, index++); + } + + return(0); +} + + +/* + * shpchp_return_board_resources + * + * this routine returns all resources allocated to a board to + * the available pool. + * + * returns 0 if success + */ +int shpchp_return_board_resources(struct pci_func * func, struct resource_lists * resources) +{ + int rc = 0; + struct pci_resource *node; + struct pci_resource *t_node; + dbg("%s\n", __FUNCTION__); + + if (!func) + return(1); + + node = func->io_head; + func->io_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->io_head), node); + node = t_node; + } + + node = func->mem_head; + func->mem_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->mem_head), node); + node = t_node; + } + + node = func->p_mem_head; + func->p_mem_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->p_mem_head), node); + node = t_node; + } + + node = func->bus_head; + func->bus_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->bus_head), node); + node = t_node; + } + + rc |= shpchp_resource_sort_and_combine(&(resources->mem_head)); + rc |= shpchp_resource_sort_and_combine(&(resources->p_mem_head)); + rc |= shpchp_resource_sort_and_combine(&(resources->io_head)); + rc |= shpchp_resource_sort_and_combine(&(resources->bus_head)); + + return(rc); +} + + +/* + * shpchp_destroy_resource_list + * + * Puts node back in the resource list pointed to by head + */ +void shpchp_destroy_resource_list (struct resource_lists * resources) +{ + struct pci_resource *res, *tres; + + res = resources->io_head; + resources->io_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = resources->mem_head; + resources->mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = resources->p_mem_head; + resources->p_mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = resources->bus_head; + resources->bus_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } +} + + +/* + * shpchp_destroy_board_resources + * + * Puts node back in the resource list pointed to by head + */ +void shpchp_destroy_board_resources (struct pci_func * func) +{ + struct pci_resource *res, *tres; + + dbg("%s: \n", __FUNCTION__); + + res = func->io_head; + func->io_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = func->mem_head; + func->mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = func->p_mem_head; + func->p_mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = func->bus_head; + func->bus_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } +} + diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/shpchprm.h linux-2.4.27-pre5/drivers/hotplug/shpchprm.h --- linux-2.4.26/drivers/hotplug/shpchprm.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/shpchprm.h 2004-06-03 01:32:46.000000000 +0000 @@ -0,0 +1,57 @@ +/* + * SHPCHPRM : SHPCHP Resource Manager for ACPI/non-ACPI platform + * + * 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 _SHPCHPRM_H_ +#define _SHPCHPRM_H_ + +#ifdef CONFIG_HOTPLUG_PCI_SHPC_PHPRM_LEGACY +#include "shpchprm_legacy.h" +#else +#include "shpchprm_nonacpi.h" +#endif + +int shpchprm_init(enum php_ctlr_type ct); +void shpchprm_cleanup(void); +int shpchprm_print_pirt(void); +void *shpchprm_get_slot(struct slot *slot); +int shpchprm_find_available_resources(struct controller *ctrl); +int shpchprm_set_hpp(struct controller *ctrl, struct pci_func *func, u8 card_type); +void shpchprm_enable_card(struct controller *ctrl, struct pci_func *func, u8 card_type); +int shpchprm_get_interrupt(int seg, int bus, int device, int pin, int *irq); +int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum); + +#ifdef DEBUG +#define RES_CHECK(this, bits) \ + { if (((this) & (bits - 1))) \ + printk("%s:%d ERR: potential res loss!\n", __FUNCTION__, __LINE__); } +#else +#define RES_CHECK(this, bits) +#endif + +#endif /* _SHPCHPRM_H_ */ diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/shpchprm_acpi.c linux-2.4.27-pre5/drivers/hotplug/shpchprm_acpi.c --- linux-2.4.26/drivers/hotplug/shpchprm_acpi.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/shpchprm_acpi.c 2004-06-03 01:36:28.000000000 +0000 @@ -0,0 +1,1696 @@ +/* + * SHPCHPRM ACPI: PHP Resource Manager for ACPI platform + * + * 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 +#ifdef CONFIG_IA64 +#include +#endif +#include +#include +#include +#include "shpchp.h" +#include "shpchprm.h" + +#define PCI_MAX_BUS 0x100 +#define ACPI_STA_DEVICE_PRESENT 0x01 + +#define METHOD_NAME__SUN "_SUN" +#define METHOD_NAME__HPP "_HPP" +#define METHOD_NAME_OSHP "OSHP" + +#define PHP_RES_BUS 0xA0 +#define PHP_RES_IO 0xA1 +#define PHP_RES_MEM 0xA2 +#define PHP_RES_PMEM 0xA3 + +#define BRIDGE_TYPE_P2P 0x00 +#define BRIDGE_TYPE_HOST 0x01 + +/* This should go to drivers/acpi/include/ */ +struct acpi__hpp { + u8 cache_line_size; + u8 latency_timer; + u8 enable_serr; + u8 enable_perr; +}; + +struct acpi_php_slot { + struct acpi_php_slot *next; + struct acpi_bridge *bridge; + acpi_handle handle; + int seg; + int bus; + int dev; + int fun; + u32 sun; + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; + void *slot_ops; /* _STA, _EJx, etc */ + struct slot *slot; +}; /* per func */ + +struct acpi_bridge { + struct acpi_bridge *parent; + struct acpi_bridge *next; + struct acpi_bridge *child; + acpi_handle handle; + int seg; + int pbus; /* pdev->bus->number */ + int pdevice; /* PCI_SLOT(pdev->devfn) */ + int pfunction; /* PCI_DEVFN(pdev->devfn) */ + int bus; /* pdev->subordinate->number */ + struct acpi__hpp *_hpp; + struct acpi_php_slot *slots; + struct pci_resource *tmem_head; /* total from crs */ + struct pci_resource *tp_mem_head; /* total from crs */ + struct pci_resource *tio_head; /* total from crs */ + struct pci_resource *tbus_head; /* total from crs */ + struct pci_resource *mem_head; /* available */ + struct pci_resource *p_mem_head; /* available */ + struct pci_resource *io_head; /* available */ + struct pci_resource *bus_head; /* available */ + int scanned; + int type; +}; + +static struct acpi_bridge *acpi_bridges_head; + +static u8 * acpi_path_name( acpi_handle handle) +{ + acpi_status status; + static u8 path_name[ACPI_PATHNAME_MAX]; + struct acpi_buffer ret_buf = { ACPI_PATHNAME_MAX, path_name }; + + memset(path_name, 0, sizeof (path_name)); + status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &ret_buf); + + if (ACPI_FAILURE(status)) + return NULL; + else + return path_name; +} + +static void acpi_get__hpp ( struct acpi_bridge *ab); +static void acpi_run_oshp ( struct acpi_bridge *ab); + +static int acpi_add_slot_to_php_slots( + struct acpi_bridge *ab, + int bus_num, + acpi_handle handle, + u32 adr, + u32 sun + ) +{ + struct acpi_php_slot *aps; + static long samesun = -1; + + aps = (struct acpi_php_slot *) kmalloc (sizeof(struct acpi_php_slot), GFP_KERNEL); + if (!aps) { + err ("acpi_shpchprm: alloc for aps fail\n"); + return -1; + } + memset(aps, 0, sizeof(struct acpi_php_slot)); + + aps->handle = handle; + aps->bus = bus_num; + aps->dev = (adr >> 16) & 0xffff; + aps->fun = adr & 0xffff; + aps->sun = sun; + + aps->next = ab->slots; /* cling to the bridge */ + aps->bridge = ab; + ab->slots = aps; + + ab->scanned += 1; + if (!ab->_hpp) + acpi_get__hpp(ab); + + acpi_run_oshp(ab); + if (sun != samesun) { + info("acpi_shpchprm: Slot sun(%x) at s:b:d:f=0x%02x:%02x:%02x:%02x\n", + aps->sun, ab->seg, aps->bus, aps->dev, aps->fun); + samesun = sun; + } + return 0; +} + +static void acpi_get__hpp ( struct acpi_bridge *ab) +{ + acpi_status status; + u8 nui[4]; + struct acpi_buffer ret_buf = { 0, NULL}; + union acpi_object *ext_obj, *package; + u8 *path_name = acpi_path_name(ab->handle); + int i, len = 0; + + /* get _hpp */ + status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf); + switch (status) { + case AE_BUFFER_OVERFLOW: + ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL); + if (!ret_buf.pointer) { + err ("acpi_shpchprm:%s alloc for _HPP fail\n", path_name); + return; + } + status = acpi_evaluate_object(ab->handle, METHOD_NAME__HPP, NULL, &ret_buf); + if (ACPI_SUCCESS(status)) + break; + default: + if (ACPI_FAILURE(status)) { + err("acpi_shpchprm:%s _HPP fail=0x%x\n", path_name, status); + return; + } + } + + ext_obj = (union acpi_object *) ret_buf.pointer; + if (ext_obj->type != ACPI_TYPE_PACKAGE) { + err ("acpi_shpchprm:%s _HPP obj not a package\n", path_name); + goto free_and_return; + } + + len = ext_obj->package.count; + package = (union acpi_object *) ret_buf.pointer; + for ( i = 0; (i < len) || (i < 4); i++) { + ext_obj = (union acpi_object *) &package->package.elements[i]; + switch (ext_obj->type) { + case ACPI_TYPE_INTEGER: + nui[i] = (u8)ext_obj->integer.value; + break; + default: + err ("acpi_shpchprm:%s _HPP obj type incorrect\n", path_name); + goto free_and_return; + } + } + + ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL); + memset(ab->_hpp, 0, sizeof(struct acpi__hpp)); + + ab->_hpp->cache_line_size = nui[0]; + ab->_hpp->latency_timer = nui[1]; + ab->_hpp->enable_serr = nui[2]; + ab->_hpp->enable_perr = nui[3]; + + dbg(" _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size); + dbg(" _HPP: latency timer =0x%x\n", ab->_hpp->latency_timer); + dbg(" _HPP: enable SERR =0x%x\n", ab->_hpp->enable_serr); + dbg(" _HPP: enable PERR =0x%x\n", ab->_hpp->enable_perr); + +free_and_return: + kfree(ret_buf.pointer); +} + +static void acpi_run_oshp ( struct acpi_bridge *ab) +{ + acpi_status status; + u8 *path_name = acpi_path_name(ab->handle); + struct acpi_buffer ret_buf = { 0, NULL}; + + /* run OSHP */ + status = acpi_evaluate_object(ab->handle, METHOD_NAME_OSHP, NULL, &ret_buf); + if (ACPI_FAILURE(status)) { + err("acpi_pciehprm:%s OSHP fails=0x%x\n", path_name, status); + } else + dbg("acpi_pciehprm:%s OSHP passes =0x%x\n", path_name, status); + return; +} + +static acpi_status acpi_evaluate_crs( + acpi_handle handle, + struct acpi_resource **retbuf + ) +{ + acpi_status status; + struct acpi_buffer crsbuf; + u8 *path_name = acpi_path_name(handle); + + crsbuf.length = 0; + crsbuf.pointer = NULL; + + status = acpi_get_current_resources (handle, &crsbuf); + + switch (status) { + case AE_BUFFER_OVERFLOW: + break; /* found */ + case AE_NOT_FOUND: + dbg("acpi_shpchprm:%s _CRS not found\n", path_name); + return status; + default: + err ("acpi_shpchprm:%s _CRS fail=0x%x\n", path_name, status); + return status; + } + + crsbuf.pointer = kmalloc (crsbuf.length, GFP_KERNEL); + if (!crsbuf.pointer) { + err ("acpi_shpchprm: alloc %ld bytes for %s _CRS fail\n", (ulong)crsbuf.length, path_name); + return AE_NO_MEMORY; + } + + status = acpi_get_current_resources (handle, &crsbuf); + if (ACPI_FAILURE(status)) { + err("acpi_shpchprm: %s _CRS fail=0x%x.\n", path_name, status); + kfree(crsbuf.pointer); + return status; + } + + *retbuf = crsbuf.pointer; + + return status; +} + +static void free_pci_resource ( struct pci_resource *aprh) +{ + struct pci_resource *res, *next; + + for (res = aprh; res; res = next) { + next = res->next; + kfree(res); + } +} + +static void print_pci_resource ( struct pci_resource *aprh) +{ + struct pci_resource *res; + + for (res = aprh; res; res = res->next) + dbg(" base= 0x%x length= 0x%x\n", res->base, res->length); +} + +static void print_slot_resources( struct acpi_php_slot *aps) +{ + if (aps->bus_head) { + dbg(" BUS Resources:\n"); + print_pci_resource (aps->bus_head); + } + + if (aps->io_head) { + dbg(" IO Resources:\n"); + print_pci_resource (aps->io_head); + } + + if (aps->mem_head) { + dbg(" MEM Resources:\n"); + print_pci_resource (aps->mem_head); + } + + if (aps->p_mem_head) { + dbg(" PMEM Resources:\n"); + print_pci_resource (aps->p_mem_head); + } +} + +static void print_pci_resources( struct acpi_bridge *ab) +{ + if (ab->tbus_head) { + dbg(" Total BUS Resources:\n"); + print_pci_resource (ab->tbus_head); + } + if (ab->bus_head) { + dbg(" BUS Resources:\n"); + print_pci_resource (ab->bus_head); + } + + if (ab->tio_head) { + dbg(" Total IO Resources:\n"); + print_pci_resource (ab->tio_head); + } + if (ab->io_head) { + dbg(" IO Resources:\n"); + print_pci_resource (ab->io_head); + } + + if (ab->tmem_head) { + dbg(" Total MEM Resources:\n"); + print_pci_resource (ab->tmem_head); + } + if (ab->mem_head) { + dbg(" MEM Resources:\n"); + print_pci_resource (ab->mem_head); + } + + if (ab->tp_mem_head) { + dbg(" Total PMEM Resources:\n"); + print_pci_resource (ab->tp_mem_head); + } + if (ab->p_mem_head) { + dbg(" PMEM Resources:\n"); + print_pci_resource (ab->p_mem_head); + } + if (ab->_hpp) { + dbg(" _HPP: cache_line_size=0x%x\n", ab->_hpp->cache_line_size); + dbg(" _HPP: latency timer =0x%x\n", ab->_hpp->latency_timer); + dbg(" _HPP: enable SERR =0x%x\n", ab->_hpp->enable_serr); + dbg(" _HPP: enable PERR =0x%x\n", ab->_hpp->enable_perr); + } +} + +static int shpchprm_delete_resource( + struct pci_resource **aprh, + ulong base, + ulong size) +{ + struct pci_resource *res; + struct pci_resource *prevnode; + struct pci_resource *split_node; + ulong tbase; + + shpchp_resource_sort_and_combine(aprh); + + for (res = *aprh; res; res = res->next) { + if (res->base > base) + continue; + + if ((res->base + res->length) < (base + size)) + continue; + + if (res->base < base) { + tbase = base; + + if ((res->length - (tbase - res->base)) < size) + continue; + + split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!split_node) + return -ENOMEM; + + split_node->base = res->base; + split_node->length = tbase - res->base; + res->base = tbase; + res->length -= split_node->length; + + split_node->next = res->next; + res->next = split_node; + } + + if (res->length >= size) { + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!split_node) + return -ENOMEM; + + split_node->base = res->base + size; + split_node->length = res->length - size; + res->length = size; + + split_node->next = res->next; + res->next = split_node; + } + + if (*aprh == res) { + *aprh = res->next; + } else { + prevnode = *aprh; + while (prevnode->next != res) + prevnode = prevnode->next; + + prevnode->next = res->next; + } + res->next = NULL; + kfree(res); + break; + } + + return 0; +} + +static int shpchprm_delete_resources( + struct pci_resource **aprh, + struct pci_resource *this + ) +{ + struct pci_resource *res; + + for (res = this; res; res = res->next) + shpchprm_delete_resource(aprh, res->base, res->length); + + return 0; +} + +static int shpchprm_add_resource( + struct pci_resource **aprh, + ulong base, + ulong size) +{ + struct pci_resource *res; + + for (res = *aprh; res; res = res->next) { + if ((res->base + res->length) == base) { + res->length += size; + size = 0L; + break; + } + if (res->next == *aprh) + break; + } + + if (size) { + res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!res) { + err ("acpi_shpchprm: alloc for res fail\n"); + return -ENOMEM; + } + memset(res, 0, sizeof (struct pci_resource)); + + res->base = base; + res->length = size; + res->next = *aprh; + *aprh = res; + } + + return 0; +} + +static int shpchprm_add_resources( + struct pci_resource **aprh, + struct pci_resource *this + ) +{ + struct pci_resource *res; + int rc = 0; + + for (res = this; res && !rc; res = res->next) + rc = shpchprm_add_resource(aprh, res->base, res->length); + + return rc; +} + +static void acpi_parse_io ( + struct acpi_bridge *ab, + union acpi_resource_data *data + ) +{ + struct acpi_resource_io *dataio; + dataio = (struct acpi_resource_io *) data; + + dbg("Io Resource\n"); + dbg(" %d bit decode\n", ACPI_DECODE_16 == dataio->io_decode ? 16:10); + dbg(" Range minimum base: %08X\n", dataio->min_base_address); + dbg(" Range maximum base: %08X\n", dataio->max_base_address); + dbg(" Alignment: %08X\n", dataio->alignment); + dbg(" Range Length: %08X\n", dataio->range_length); +} + +static void acpi_parse_fixed_io ( + struct acpi_bridge *ab, + union acpi_resource_data *data + ) +{ + struct acpi_resource_fixed_io *datafio; + datafio = (struct acpi_resource_fixed_io *) data; + + dbg("Fixed Io Resource\n"); + dbg(" Range base address: %08X", datafio->base_address); + dbg(" Range length: %08X", datafio->range_length); +} + +static void acpi_parse_address16_32 ( + struct acpi_bridge *ab, + union acpi_resource_data *data, + acpi_resource_type id + ) +{ + /* + * acpi_resource_address16 == acpi_resource_address32 + * acpi_resource_address16 *data16 = (acpi_resource_address16 *) data; + */ + struct acpi_resource_address32 *data32 = (struct acpi_resource_address32 *) data; + struct pci_resource **aprh, **tprh; + + if (id == ACPI_RSTYPE_ADDRESS16) + dbg("acpi_shpchprm:16-Bit Address Space Resource\n"); + else + dbg("acpi_shpchprm:32-Bit Address Space Resource\n"); + + switch (data32->resource_type) { + case ACPI_MEMORY_RANGE: + dbg(" Resource Type: Memory Range\n"); + aprh = &ab->mem_head; + tprh = &ab->tmem_head; + + switch (data32->attribute.memory.cache_attribute) { + case ACPI_NON_CACHEABLE_MEMORY: + dbg(" Type Specific: Noncacheable memory\n"); + break; + case ACPI_CACHABLE_MEMORY: + dbg(" Type Specific: Cacheable memory\n"); + break; + case ACPI_WRITE_COMBINING_MEMORY: + dbg(" Type Specific: Write-combining memory\n"); + break; + case ACPI_PREFETCHABLE_MEMORY: + aprh = &ab->p_mem_head; + dbg(" Type Specific: Prefetchable memory\n"); + break; + default: + dbg(" Type Specific: Invalid cache attribute\n"); + break; + } + + dbg(" Type Specific: Read%s\n", ACPI_READ_WRITE_MEMORY == data32->attribute.memory.read_write_attribute ? "/Write":" Only"); + break; + + case ACPI_IO_RANGE: + dbg(" Resource Type: I/O Range\n"); + aprh = &ab->io_head; + tprh = &ab->tio_head; + + switch (data32->attribute.io.range_attribute) { + case ACPI_NON_ISA_ONLY_RANGES: + dbg(" Type Specific: Non-ISA Io Addresses\n"); + break; + case ACPI_ISA_ONLY_RANGES: + dbg(" Type Specific: ISA Io Addresses\n"); + break; + case ACPI_ENTIRE_RANGE: + dbg(" Type Specific: ISA and non-ISA Io Addresses\n"); + break; + default: + dbg(" Type Specific: Invalid range attribute\n"); + break; + } + break; + + case ACPI_BUS_NUMBER_RANGE: + dbg(" Resource Type: Bus Number Range(fixed)\n"); + /* Fixup to be compatible with the rest of php driver */ + data32->min_address_range++; + data32->address_length--; + aprh = &ab->bus_head; + tprh = &ab->tbus_head; + break; + default: + dbg(" Resource Type: Invalid resource type. Exiting.\n"); + return; + } + + dbg(" Resource %s\n", ACPI_CONSUMER == data32->producer_consumer ? "Consumer":"Producer"); + dbg(" %s decode\n", ACPI_SUB_DECODE == data32->decode ? "Subtractive":"Positive"); + dbg(" Min address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->min_address_fixed ? "":"not"); + dbg(" Max address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->max_address_fixed ? "":"not"); + dbg(" Granularity: %08X\n", data32->granularity); + dbg(" Address range min: %08X\n", data32->min_address_range); + dbg(" Address range max: %08X\n", data32->max_address_range); + dbg(" Address translation offset: %08X\n", data32->address_translation_offset); + dbg(" Address Length: %08X\n", data32->address_length); + + if (0xFF != data32->resource_source.index) { + dbg(" Resource Source Index: %X\n", data32->resource_source.index); + /* dbg(" Resource Source: %s\n", data32->resource_source.string_ptr); */ + } + + shpchprm_add_resource(aprh, data32->min_address_range, data32->address_length); +} + +static acpi_status acpi_parse_crs( + struct acpi_bridge *ab, + struct acpi_resource *crsbuf + ) +{ + acpi_status status = AE_OK; + struct acpi_resource *resource = crsbuf; + u8 count = 0; + u8 done = 0; + + while (!done) { + dbg("acpi_shpchprm: PCI bus 0x%x Resource structure %x.\n", ab->bus, count++); + switch (resource->id) { + case ACPI_RSTYPE_IRQ: + dbg("Irq -------- Resource\n"); + break; + case ACPI_RSTYPE_DMA: + dbg("DMA -------- Resource\n"); + break; + case ACPI_RSTYPE_START_DPF: + dbg("Start DPF -------- Resource\n"); + break; + case ACPI_RSTYPE_END_DPF: + dbg("End DPF -------- Resource\n"); + break; + case ACPI_RSTYPE_IO: + acpi_parse_io (ab, &resource->data); + break; + case ACPI_RSTYPE_FIXED_IO: + acpi_parse_fixed_io (ab, &resource->data); + break; + case ACPI_RSTYPE_VENDOR: + dbg("Vendor -------- Resource\n"); + break; + case ACPI_RSTYPE_END_TAG: + dbg("End_tag -------- Resource\n"); + done = 1; + break; + case ACPI_RSTYPE_MEM24: + dbg("Mem24 -------- Resource\n"); + break; + case ACPI_RSTYPE_MEM32: + dbg("Mem32 -------- Resource\n"); + break; + case ACPI_RSTYPE_FIXED_MEM32: + dbg("Fixed Mem32 -------- Resource\n"); + break; + case ACPI_RSTYPE_ADDRESS16: + acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS16); + break; + case ACPI_RSTYPE_ADDRESS32: + acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS32); + break; + case ACPI_RSTYPE_ADDRESS64: + info("Address64 -------- Resource unparsed\n"); + break; + case ACPI_RSTYPE_EXT_IRQ: + dbg("Ext Irq -------- Resource\n"); + break; + default: + dbg("Invalid -------- resource type 0x%x\n", resource->id); + break; + } + + resource = (struct acpi_resource *) ((char *)resource + resource->length); + } + + return status; +} + +static acpi_status acpi_get_crs( struct acpi_bridge *ab) +{ + acpi_status status; + struct acpi_resource *crsbuf; + + status = acpi_evaluate_crs(ab->handle, &crsbuf); + if (ACPI_SUCCESS(status)) { + status = acpi_parse_crs(ab, crsbuf); + kfree(crsbuf); + + shpchp_resource_sort_and_combine(&ab->bus_head); + shpchp_resource_sort_and_combine(&ab->io_head); + shpchp_resource_sort_and_combine(&ab->mem_head); + shpchp_resource_sort_and_combine(&ab->p_mem_head); + + shpchprm_add_resources (&ab->tbus_head, ab->bus_head); + shpchprm_add_resources (&ab->tio_head, ab->io_head); + shpchprm_add_resources (&ab->tmem_head, ab->mem_head); + shpchprm_add_resources (&ab->tp_mem_head, ab->p_mem_head); + } + + return status; +} + +/* Find acpi_bridge downword from ab. */ +static struct acpi_bridge * +find_acpi_bridge_by_bus( + struct acpi_bridge *ab, + int seg, + int bus /* pdev->subordinate->number */ + ) +{ + struct acpi_bridge *lab = NULL; + + if (!ab) + return NULL; + + if ((ab->bus == bus) && (ab->seg == seg)) + return ab; + + if (ab->child) + lab = find_acpi_bridge_by_bus(ab->child, seg, bus); + + if (!lab) + if (ab->next) + lab = find_acpi_bridge_by_bus(ab->next, seg, bus); + + return lab; +} + +/* + * Build a device tree of ACPI PCI Bridges + */ +static void shpchprm_acpi_register_a_bridge ( + struct acpi_bridge **head, + struct acpi_bridge *pab, /* parent bridge to which child bridge is added */ + struct acpi_bridge *cab /* child bridge to add */ + ) +{ + struct acpi_bridge *lpab; + struct acpi_bridge *lcab; + + lpab = find_acpi_bridge_by_bus(*head, pab->seg, pab->bus); + if (!lpab) { + if (!(pab->type & BRIDGE_TYPE_HOST)) + warn("PCI parent bridge s:b(%x:%x) not in list.\n", pab->seg, pab->bus); + pab->next = *head; + *head = pab; + lpab = pab; + } + + if ((cab->type & BRIDGE_TYPE_HOST) && (pab == cab)) + return; + + lcab = find_acpi_bridge_by_bus(*head, cab->seg, cab->bus); + if (lcab) { + if ((pab->bus != lcab->parent->bus) || (lcab->bus != cab->bus)) + err("PCI child bridge s:b(%x:%x) in list with diff parent.\n", cab->seg, cab->bus); + return; + } else + lcab = cab; + + lcab->parent = lpab; + lcab->next = lpab->child; + lpab->child = lcab; +} + +static acpi_status shpchprm_acpi_build_php_slots_callback( + acpi_handle handle, + u32 Level, + void *context, + void **retval + ) +{ + ulong bus_num; + ulong seg_num; + ulong sun, adr; + ulong padr = 0; + acpi_handle phandle = NULL; + struct acpi_bridge *pab = (struct acpi_bridge *)context; + struct acpi_bridge *lab; + acpi_status status; + u8 *path_name = acpi_path_name(handle); + + /* Get _SUN */ + status = acpi_evaluate_integer(handle, METHOD_NAME__SUN, NULL, &sun); + switch(status) { + case AE_NOT_FOUND: + return AE_OK; + default: + if (ACPI_FAILURE(status)) { + err("acpi_shpchprm:%s _SUN fail=0x%x\n", path_name, status); + return status; + } + } + + /* Get _ADR. _ADR must exist if _SUN exists */ + status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); + if (ACPI_FAILURE(status)) { + err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status); + return status; + } + + dbg("acpi_shpchprm:%s sun=0x%08x adr=0x%08x\n", path_name, (u32)sun, (u32)adr); + + status = acpi_get_parent(handle, &phandle); + if (ACPI_FAILURE(status)) { + err("acpi_shpchprm:%s get_parent fail=0x%x\n", path_name, status); + return (status); + } + + bus_num = pab->bus; + seg_num = pab->seg; + + if (pab->bus == bus_num) { + lab = pab; + } else { + dbg("WARN: pab is not parent\n"); + lab = find_acpi_bridge_by_bus(pab, seg_num, bus_num); + if (!lab) { + dbg("acpi_shpchprm: alloc new P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun); + lab = (struct acpi_bridge *)kmalloc(sizeof(struct acpi_bridge), GFP_KERNEL); + if (!lab) { + err("acpi_shpchprm: alloc for ab fail\n"); + return AE_NO_MEMORY; + } + memset(lab, 0, sizeof(struct acpi_bridge)); + + lab->handle = phandle; + lab->pbus = pab->bus; + lab->pdevice = (int)(padr >> 16) & 0xffff; + lab->pfunction = (int)(padr & 0xffff); + lab->bus = (int)bus_num; + lab->scanned = 0; + lab->type = BRIDGE_TYPE_P2P; + + shpchprm_acpi_register_a_bridge (&acpi_bridges_head, pab, lab); + } else + dbg("acpi_shpchprm: found P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun); + } + + acpi_add_slot_to_php_slots(lab, (int)bus_num, handle, (u32)adr, (u32)sun); + return (status); +} + +static int shpchprm_acpi_build_php_slots( + struct acpi_bridge *ab, + u32 depth + ) +{ + acpi_status status; + u8 *path_name = acpi_path_name(ab->handle); + + /* Walk down this pci bridge to get _SUNs if any behind P2P */ + status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, + ab->handle, + depth, + shpchprm_acpi_build_php_slots_callback, + ab, + NULL ); + if (ACPI_FAILURE(status)) { + dbg("acpi_shpchprm:%s walk for _SUN on pci bridge seg:bus(%x:%x) fail=0x%x\n", path_name, ab->seg, ab->bus, status); + return -1; + } + + return 0; +} + +static void build_a_bridge( + struct acpi_bridge *pab, + struct acpi_bridge *ab + ) +{ + u8 *path_name = acpi_path_name(ab->handle); + + shpchprm_acpi_register_a_bridge (&acpi_bridges_head, pab, ab); + + switch (ab->type) { + case BRIDGE_TYPE_HOST: + dbg("acpi_shpchprm: Registered PCI HOST Bridge(%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n", + ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name); + break; + case BRIDGE_TYPE_P2P: + dbg("acpi_shpchprm: Registered PCI P2P Bridge(%02x-%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n", + ab->pbus, ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name); + break; + }; + + /* any immediate PHP slots under this pci bridge */ + shpchprm_acpi_build_php_slots(ab, 1); +} + +static struct acpi_bridge * add_p2p_bridge( + acpi_handle handle, + struct acpi_bridge *pab, /* parent */ + ulong adr + ) +{ + struct acpi_bridge *ab; + struct pci_dev *pdev; + ulong devnum, funcnum; + u8 *path_name = acpi_path_name(handle); + + ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL); + if (!ab) { + err("acpi_shpchprm: alloc for ab fail\n"); + return NULL; + } + memset(ab, 0, sizeof(struct acpi_bridge)); + + devnum = (adr >> 16) & 0xffff; + funcnum = adr & 0xffff; + + pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum)); + if (!pdev || !pdev->subordinate) { + err("acpi_shpchprm:%s is not a P2P Bridge\n", path_name); + kfree(ab); + return NULL; + } + + ab->handle = handle; + ab->seg = pab->seg; + ab->pbus = pab->bus; /* or pdev->bus->number */ + ab->pdevice = devnum; /* or PCI_SLOT(pdev->devfn) */ + ab->pfunction = funcnum; /* or PCI_FUNC(pdev->devfn) */ + ab->bus = pdev->subordinate->number; + ab->scanned = 0; + ab->type = BRIDGE_TYPE_P2P; + + dbg("acpi_shpchprm: P2P(%x-%x) on pci=b:d:f(%x:%x:%x) acpi=b:d:f(%x:%x:%x) [%s]\n", + pab->bus, ab->bus, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), + pab->bus, (u32)devnum, (u32)funcnum, path_name); + + build_a_bridge(pab, ab); + + return ab; +} + +static acpi_status scan_p2p_bridge( + acpi_handle handle, + u32 Level, + void *context, + void **retval + ) +{ + struct acpi_bridge *pab = (struct acpi_bridge *)context; + struct acpi_bridge *ab; + acpi_status status; + ulong adr = 0; + u8 *path_name = acpi_path_name(handle); + ulong devnum, funcnum; + struct pci_dev *pdev; + + /* Get device, function */ + status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); + if (ACPI_FAILURE(status)) { + if (status != AE_NOT_FOUND) + err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status); + return AE_OK; + } + + devnum = (adr >> 16) & 0xffff; + funcnum = adr & 0xffff; + + pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum)); + if (!pdev) + return AE_OK; + if (!pdev->subordinate) + return AE_OK; + + ab = add_p2p_bridge(handle, pab, adr); + if (ab) { + status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, + handle, + (u32)1, + scan_p2p_bridge, + ab, + NULL); + if (ACPI_FAILURE(status)) + dbg("acpi_shpchprm:%s find_p2p fail=0x%x\n", path_name, status); + } + + return AE_OK; +} + +static struct acpi_bridge * add_host_bridge( + acpi_handle handle, + ulong segnum, + ulong busnum + ) +{ + ulong adr = 0; + acpi_status status; + struct acpi_bridge *ab; + u8 *path_name = acpi_path_name(handle); + + /* Get device, function: host br adr is always 0000 though. */ + status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); + if (ACPI_FAILURE(status)) { + err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status); + return NULL; + } + dbg("acpi_shpchprm: ROOT PCI seg(0x%x)bus(0x%x)dev(0x%x)func(0x%x) [%s]\n", (u32)segnum, (u32)busnum, (u32)(adr >> 16) & 0xffff, (u32)adr & 0xffff, path_name); + + ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL); + if (!ab) { + err("acpi_shpchprm: alloc for ab fail\n"); + return NULL; + } + memset(ab, 0, sizeof(struct acpi_bridge)); + + ab->handle = handle; + ab->seg = (int)segnum; + ab->bus = ab->pbus = (int)busnum; + ab->pdevice = (int)(adr >> 16) & 0xffff; + ab->pfunction = (int)(adr & 0xffff); + ab->scanned = 0; + ab->type = BRIDGE_TYPE_HOST; + + /* Get root pci bridge's current resources */ + status = acpi_get_crs(ab); + if (ACPI_FAILURE(status)) { + err("acpi_shpchprm:%s evaluate _CRS fail=0x%x\n", path_name, status); + kfree(ab); + return NULL; + } + build_a_bridge(ab, ab); + + return ab; +} + +static acpi_status acpi_scan_from_root_pci_callback ( + acpi_handle handle, + u32 Level, + void *context, + void **retval + ) +{ + ulong segnum = 0; + ulong busnum = 0; + acpi_status status; + struct acpi_bridge *ab; + u8 *path_name = acpi_path_name(handle); + + /* Get bus number of this pci root bridge */ + status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &segnum); + if (ACPI_FAILURE(status)) { + if (status != AE_NOT_FOUND) { + err("acpi_shpchprm:%s evaluate _SEG fail=0x%x\n", path_name, status); + return status; + } + segnum = 0; + } + + /* Get bus number of this pci root bridge */ + status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, &busnum); + if (ACPI_FAILURE(status)) { + err("acpi_shpchprm:%s evaluate _BBN fail=0x%x\n", path_name, status); + return (status); + } + + ab = add_host_bridge(handle, segnum, busnum); + if (ab) { + status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, + handle, + 1, + scan_p2p_bridge, + ab, + NULL); + if (ACPI_FAILURE(status)) + dbg("acpi_shpchprm:%s find_p2p fail=0x%x\n", path_name, status); + } + + return AE_OK; +} + +static int shpchprm_acpi_scan_pci (void) +{ + acpi_status status; + + /* + * TBD: traverse LDM device tree with the help of + * unified ACPI augmented for php device population. + */ + status = acpi_get_devices ( PCI_ROOT_HID_STRING, + acpi_scan_from_root_pci_callback, + NULL, + NULL ); + if (ACPI_FAILURE(status)) { + err("acpi_shpchprm:get_device PCI ROOT HID fail=0x%x\n", status); + return -1; + } + + return 0; +} + +int shpchprm_init(enum php_ctlr_type ctlr_type) +{ + int rc; + + if (ctlr_type != PCI) + return -ENODEV; + + dbg("shpchprm ACPI init \n"); + acpi_bridges_head = NULL; + + /* construct PCI bus:device tree of acpi_handles */ + rc = shpchprm_acpi_scan_pci(); + if (rc) + return rc; + + dbg("shpchprm ACPI init %s\n", (rc)?"fail":"success"); + return rc; +} + +static void free_a_slot(struct acpi_php_slot *aps) +{ + dbg(" free a php func of slot(0x%02x) on PCI b:d:f=0x%02x:%02x:%02x\n", aps->sun, aps->bus, aps->dev, aps->fun); + + free_pci_resource (aps->io_head); + free_pci_resource (aps->bus_head); + free_pci_resource (aps->mem_head); + free_pci_resource (aps->p_mem_head); + + kfree(aps); +} + +static void free_a_bridge( struct acpi_bridge *ab) +{ + struct acpi_php_slot *aps, *next; + + switch (ab->type) { + case BRIDGE_TYPE_HOST: + dbg("Free ACPI PCI HOST Bridge(%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n", + ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction); + break; + case BRIDGE_TYPE_P2P: + dbg("Free ACPI PCI P2P Bridge(%x-%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n", + ab->pbus, ab->bus, acpi_path_name(ab->handle), ab->seg, ab->pbus, ab->pdevice, ab->pfunction); + break; + }; + + /* free slots first */ + for (aps = ab->slots; aps; aps = next) { + next = aps->next; + free_a_slot(aps); + } + + free_pci_resource (ab->io_head); + free_pci_resource (ab->tio_head); + free_pci_resource (ab->bus_head); + free_pci_resource (ab->tbus_head); + free_pci_resource (ab->mem_head); + free_pci_resource (ab->tmem_head); + free_pci_resource (ab->p_mem_head); + free_pci_resource (ab->tp_mem_head); + + kfree(ab); +} + +static void shpchprm_free_bridges ( struct acpi_bridge *ab) +{ + if (!ab) + return; + + if (ab->child) + shpchprm_free_bridges (ab->child); + + if (ab->next) + shpchprm_free_bridges (ab->next); + + free_a_bridge(ab); +} + +void shpchprm_cleanup(void) +{ + shpchprm_free_bridges (acpi_bridges_head); +} + +static int get_number_of_slots ( + struct acpi_bridge *ab, + int selfonly + ) +{ + struct acpi_php_slot *aps; + int prev_slot = -1; + int slot_num = 0; + + for ( aps = ab->slots; aps; aps = aps->next) + if (aps->dev != prev_slot) { + prev_slot = aps->dev; + slot_num++; + } + + if (ab->child) + slot_num += get_number_of_slots (ab->child, 0); + + if (selfonly) + return slot_num; + + if (ab->next) + slot_num += get_number_of_slots (ab->next, 0); + + return slot_num; +} + +static int print_acpi_resources (struct acpi_bridge *ab) +{ + struct acpi_php_slot *aps; + int i; + + switch (ab->type) { + case BRIDGE_TYPE_HOST: + dbg("PCI HOST Bridge (%x) [%s]\n", ab->bus, acpi_path_name(ab->handle)); + break; + case BRIDGE_TYPE_P2P: + dbg("PCI P2P Bridge (%x-%x) [%s]\n", ab->pbus, ab->bus, acpi_path_name(ab->handle)); + break; + }; + + print_pci_resources (ab); + + for ( i = -1, aps = ab->slots; aps; aps = aps->next) { + if (aps->dev == i) + continue; + dbg(" Slot sun(%x) s:b:d:f(%02x:%02x:%02x:%02x)\n", aps->sun, aps->seg, aps->bus, aps->dev, aps->fun); + print_slot_resources(aps); + i = aps->dev; + } + + if (ab->child) + print_acpi_resources (ab->child); + + if (ab->next) + print_acpi_resources (ab->next); + + return 0; +} + +int shpchprm_print_pirt(void) +{ + dbg("SHPCHPRM ACPI Slots\n"); + if (acpi_bridges_head) + print_acpi_resources (acpi_bridges_head); + return 0; +} + +static struct acpi_php_slot * get_acpi_slot ( + struct acpi_bridge *ab, + u32 sun + ) +{ + struct acpi_php_slot *aps = NULL; + + for ( aps = ab->slots; aps; aps = aps->next) + if (aps->sun == sun) + return aps; + + if (!aps && ab->child) { + aps = (struct acpi_php_slot *)get_acpi_slot (ab->child, sun); + if (aps) + return aps; + } + + if (!aps && ab->next) { + aps = (struct acpi_php_slot *)get_acpi_slot (ab->next, sun); + if (aps) + return aps; + } + + return aps; + +} + +void * shpchprm_get_slot(struct slot *slot) +{ + struct acpi_bridge *ab = acpi_bridges_head; + struct acpi_php_slot *aps = get_acpi_slot (ab, slot->number); + + aps->slot = slot; + + dbg("Got acpi slot sun(%x): s:b:d:f(%x:%x:%x:%x)\n", aps->sun, aps->seg, aps->bus, aps->dev, aps->fun); + + return (void *)aps; +} + +static void shpchprm_dump_func_res( struct pci_func *fun) +{ + struct pci_func *func = fun; + + if (func->bus_head) { + dbg(": BUS Resources:\n"); + print_pci_resource (func->bus_head); + } + if (func->io_head) { + dbg(": IO Resources:\n"); + print_pci_resource (func->io_head); + } + if (func->mem_head) { + dbg(": MEM Resources:\n"); + print_pci_resource (func->mem_head); + } + if (func->p_mem_head) { + dbg(": PMEM Resources:\n"); + print_pci_resource (func->p_mem_head); + } +} + +static void shpchprm_dump_ctrl_res( struct controller *ctlr) +{ + struct controller *ctrl = ctlr; + + if (ctrl->bus_head) { + dbg(": BUS Resources:\n"); + print_pci_resource (ctrl->bus_head); + } + if (ctrl->io_head) { + dbg(": IO Resources:\n"); + print_pci_resource (ctrl->io_head); + } + if (ctrl->mem_head) { + dbg(": MEM Resources:\n"); + print_pci_resource (ctrl->mem_head); + } + if (ctrl->p_mem_head) { + dbg(": PMEM Resources:\n"); + print_pci_resource (ctrl->p_mem_head); + } +} + +static int shpchprm_get_used_resources ( + struct controller *ctrl, + struct pci_func *func + ) +{ + return shpchp_save_used_resources (ctrl, func, !DISABLE_CARD); +} + +static int configure_existing_function( + struct controller *ctrl, + struct pci_func *func + ) +{ + int rc; + + /* see how much resources the func has used. */ + rc = shpchprm_get_used_resources (ctrl, func); + + if (!rc) { + /* subtract the resources used by the func from ctrl resources */ + rc = shpchprm_delete_resources (&ctrl->bus_head, func->bus_head); + rc |= shpchprm_delete_resources (&ctrl->io_head, func->io_head); + rc |= shpchprm_delete_resources (&ctrl->mem_head, func->mem_head); + rc |= shpchprm_delete_resources (&ctrl->p_mem_head, func->p_mem_head); + if (rc) + warn("aCEF: cannot del used resources\n"); + } else + err("aCEF: cannot get used resources\n"); + + return rc; +} + +static int bind_pci_resources_to_slots ( struct controller *ctrl) +{ + struct pci_func *func; + int busn = ctrl->bus; + int devn, funn; + u32 vid; + + for (devn = 0; devn < 32; devn++) { + for (funn = 0; funn < 8; funn++) { + if (devn == ctrl->device && funn == ctrl->function) + continue; + /* find out if this entry is for an occupied slot */ + vid = 0xFFFFFFFF; + pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &vid); + + if (vid != 0xFFFFFFFF) { + func = shpchp_slot_find(busn, devn, funn); + if (!func) + continue; + configure_existing_function(ctrl, func); + dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus); + shpchprm_dump_func_res(func); + } + } + } + + return 0; +} + +static int bind_pci_resources( + struct controller *ctrl, + struct acpi_bridge *ab + ) +{ + int status = 0; + + if (ab->bus_head) { + dbg("bapr: BUS Resources add on PCI 0x%x\n", ab->bus); + status = shpchprm_add_resources (&ctrl->bus_head, ab->bus_head); + if (shpchprm_delete_resources (&ab->bus_head, ctrl->bus_head)) + warn("bapr: cannot sub BUS Resource on PCI 0x%x\n", ab->bus); + if (status) { + err("bapr: BUS Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); + return status; + } + } else + info("bapr: No BUS Resource on PCI 0x%x.\n", ab->bus); + + if (ab->io_head) { + dbg("bapr: IO Resources add on PCI 0x%x\n", ab->bus); + status = shpchprm_add_resources (&ctrl->io_head, ab->io_head); + if (shpchprm_delete_resources (&ab->io_head, ctrl->io_head)) + warn("bapr: cannot sub IO Resource on PCI 0x%x\n", ab->bus); + if (status) { + err("bapr: IO Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); + return status; + } + } else + info("bapr: No IO Resource on PCI 0x%x.\n", ab->bus); + + if (ab->mem_head) { + dbg("bapr: MEM Resources add on PCI 0x%x\n", ab->bus); + status = shpchprm_add_resources (&ctrl->mem_head, ab->mem_head); + if (shpchprm_delete_resources (&ab->mem_head, ctrl->mem_head)) + warn("bapr: cannot sub MEM Resource on PCI 0x%x\n", ab->bus); + if (status) { + err("bapr: MEM Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); + return status; + } + } else + info("bapr: No MEM Resource on PCI 0x%x.\n", ab->bus); + + if (ab->p_mem_head) { + dbg("bapr: PMEM Resources add on PCI 0x%x\n", ab->bus); + status = shpchprm_add_resources (&ctrl->p_mem_head, ab->p_mem_head); + if (shpchprm_delete_resources (&ab->p_mem_head, ctrl->p_mem_head)) + warn("bapr: cannot sub PMEM Resource on PCI 0x%x\n", ab->bus); + if (status) { + err("bapr: PMEM Resource add on PCI 0x%x: fail=0x%x\n", ab->bus, status); + return status; + } + } else + info("bapr: No PMEM Resource on PCI 0x%x.\n", ab->bus); + + return status; +} + +static int no_pci_resources( struct acpi_bridge *ab) +{ + return !(ab->p_mem_head || ab->mem_head || ab->io_head || ab->bus_head); +} + +static int find_pci_bridge_resources ( + struct controller *ctrl, + struct acpi_bridge *ab + ) +{ + int rc = 0; + struct pci_func func; + + memset(&func, 0, sizeof(struct pci_func)); + + func.bus = ab->pbus; + func.device = ab->pdevice; + func.function = ab->pfunction; + func.is_a_board = 1; + + /* Get used resources for this PCI bridge */ + rc = shpchp_save_used_resources (ctrl, &func, !DISABLE_CARD); + + ab->io_head = func.io_head; + ab->mem_head = func.mem_head; + ab->p_mem_head = func.p_mem_head; + ab->bus_head = func.bus_head; + if (ab->bus_head) + shpchprm_delete_resource(&ab->bus_head, ctrl->bus, 1); + + return rc; +} + +static int get_pci_resources_from_bridge( + struct controller *ctrl, + struct acpi_bridge *ab + ) +{ + int rc = 0; + + dbg("grfb: Get Resources for PCI 0x%x from actual PCI bridge 0x%x.\n", ctrl->bus, ab->bus); + + rc = find_pci_bridge_resources (ctrl, ab); + + shpchp_resource_sort_and_combine(&ab->bus_head); + shpchp_resource_sort_and_combine(&ab->io_head); + shpchp_resource_sort_and_combine(&ab->mem_head); + shpchp_resource_sort_and_combine(&ab->p_mem_head); + + shpchprm_add_resources (&ab->tbus_head, ab->bus_head); + shpchprm_add_resources (&ab->tio_head, ab->io_head); + shpchprm_add_resources (&ab->tmem_head, ab->mem_head); + shpchprm_add_resources (&ab->tp_mem_head, ab->p_mem_head); + + return rc; +} + +static int get_pci_resources( + struct controller *ctrl, + struct acpi_bridge *ab + ) +{ + int rc = 0; + + if (no_pci_resources(ab)) { + dbg("spbr:PCI 0x%x has no resources. Get parent resources.\n", ab->bus); + rc = get_pci_resources_from_bridge(ctrl, ab); + } + + return rc; +} + +int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) +{ + int offset = devnum - ctrl->slot_device_offset; + + dbg("%s: ctrl->slot_num_inc %d, offset %d\n", __FUNCTION__, ctrl->slot_num_inc, offset); + *sun = (u8) (ctrl->first_slot + ctrl->slot_num_inc *offset); + return 0; +} + +/* + * Get resources for this ctrl. + * 1. get total resources from ACPI _CRS or bridge (this ctrl) + * 2. find used resources of existing adapters + * 3. subtract used resources from total resources + */ +int shpchprm_find_available_resources( struct controller *ctrl) +{ + int rc = 0; + struct acpi_bridge *ab; + + ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->pci_dev->subordinate->number); + if (!ab) { + err("pfar:cannot locate acpi bridge of PCI 0x%x.\n", ctrl->pci_dev->subordinate->number); + return -1; + } + if (no_pci_resources(ab)) { + rc = get_pci_resources(ctrl, ab); + if (rc) { + err("pfar:cannot get pci resources of PCI 0x%x.\n", ctrl->pci_dev->subordinate->number); + return -1; + } + } + + rc = bind_pci_resources(ctrl, ab); + dbg("pfar:pre-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl->pci_dev->subordinate->number); + shpchprm_dump_ctrl_res(ctrl); + + bind_pci_resources_to_slots (ctrl); + + dbg("pfar:post-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl->pci_dev->subordinate->number); + shpchprm_dump_ctrl_res(ctrl); + + return rc; +} + +int shpchprm_set_hpp( + struct controller *ctrl, + struct pci_func *func, + u8 card_type + ) +{ + struct acpi_bridge *ab; + struct pci_bus lpci_bus, *pci_bus; + int rc = 0; + unsigned int devfn; + u8 cls= 0x08; /* default cache line size */ + u8 lt = 0x40; /* default latency timer */ + u8 ep = 0; + u8 es = 0; + + memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); + pci_bus = &lpci_bus; + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus); + + if (ab) { + if (ab->_hpp) { + lt = (u8)ab->_hpp->latency_timer; + cls = (u8)ab->_hpp->cache_line_size; + ep = (u8)ab->_hpp->enable_perr; + es = (u8)ab->_hpp->enable_serr; + } else + dbg("_hpp: no _hpp for B/D/F=%#x/%#x/%#x. use default value\n", func->bus, func->device, func->function); + } else + dbg("_hpp: no acpi bridge for B/D/F = %#x/%#x/%#x. use default value\n", func->bus, func->device, func->function); + + + if (card_type == PCI_HEADER_TYPE_BRIDGE) { + /* Set subordinate Latency Timer */ + rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, lt); + } + + /* set base Latency Timer */ + rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, lt); + dbg(" set latency timer =0x%02x: %x\n", lt, rc); + + rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, cls); + dbg(" set cache_line_size=0x%02x: %x\n", cls, rc); + + return rc; +} + +void shpchprm_enable_card( + struct controller *ctrl, + struct pci_func *func, + u8 card_type) +{ + u16 command, cmd, bcommand, bcmd; + struct pci_bus lpci_bus, *pci_bus; + struct acpi_bridge *ab; + unsigned int devfn; + int rc; + + memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); + pci_bus = &lpci_bus; + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command); + + if (card_type == PCI_HEADER_TYPE_BRIDGE) { + rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand); + } + + cmd = command = command | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE + | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; + bcmd = bcommand = bcommand | PCI_BRIDGE_CTL_NO_ISA; + + ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus); + if (ab) { + if (ab->_hpp) { + if (ab->_hpp->enable_perr) { + command |= PCI_COMMAND_PARITY; + bcommand |= PCI_BRIDGE_CTL_PARITY; + } else { + command &= ~PCI_COMMAND_PARITY; + bcommand &= ~PCI_BRIDGE_CTL_PARITY; + } + if (ab->_hpp->enable_serr) { + command |= PCI_COMMAND_SERR; + bcommand |= PCI_BRIDGE_CTL_SERR; + } else { + command &= ~PCI_COMMAND_SERR; + bcommand &= ~PCI_BRIDGE_CTL_SERR; + } + } else + dbg("no _hpp for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function); + } else + dbg("no acpi bridge for B/D/F = %#x/%#x/%#x.\n", func->bus, func->device, func->function); + + if (command != cmd) { + rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); + } + if ((card_type == PCI_HEADER_TYPE_BRIDGE) && (bcommand != bcmd)) { + rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand); + } +} + diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/shpchprm_legacy.c linux-2.4.27-pre5/drivers/hotplug/shpchprm_legacy.c --- linux-2.4.26/drivers/hotplug/shpchprm_legacy.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/shpchprm_legacy.c 2004-06-03 01:35:16.000000000 +0000 @@ -0,0 +1,444 @@ +/* + * SHPCHPRM Legacy: PHP Resource Manager for Non-ACPI/Legacy platform + * + * 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 +#ifdef CONFIG_IA64 +#include +#endif +#include "shpchp.h" +#include "shpchprm.h" +#include "shpchprm_legacy.h" + +static void *shpchp_rom_start; +static u16 unused_IRQ; + +void shpchprm_cleanup() +{ + if (shpchp_rom_start) + iounmap(shpchp_rom_start); +} + + +int shpchprm_print_pirt() +{ + return 0; +} + +void * shpchprm_get_slot(struct slot *slot) +{ + return NULL; +} + +int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) +{ + int offset = devnum - ctrl->slot_device_offset; + + *sun = (u8) (ctrl->first_slot + ctrl->slot_num_inc * offset); + return 0; +} + +/* find the Hot Plug Resource Table in the specified region of memory */ +static void *detect_HRT_floating_pointer(void *begin, void *end) +{ + void *fp; + void *endp; + u8 temp1, temp2, temp3, temp4; + int status = 0; + + endp = (end - sizeof(struct hrt) + 1); + + for (fp = begin; fp <= endp; fp += 16) { + temp1 = readb(fp + SIG0); + temp2 = readb(fp + SIG1); + temp3 = readb(fp + SIG2); + temp4 = readb(fp + SIG3); + if (temp1 == '$' && temp2 == 'H' && temp3 == 'R' && temp4 == 'T') { + status = 1; + break; + } + } + + if (!status) + fp = NULL; + + dbg("Discovered Hotplug Resource Table at %p\n", fp); + return fp; +} + +/* + * shpchprm_find_available_resources + * + * Finds available memory, IO, and IRQ resources for programming + * devices which may be added to the system + * this function is for hot plug ADD! + * + * returns 0 if success + */ +int shpchprm_find_available_resources(struct controller *ctrl) +{ + u8 populated_slot; + u8 bridged_slot; + void *one_slot; + struct pci_func *func = NULL; + int i = 10, index = 0; + u32 temp_dword, rc; + ulong temp_ulong; + struct pci_resource *mem_node; + struct pci_resource *p_mem_node; + struct pci_resource *io_node; + struct pci_resource *bus_node; + void *rom_resource_table; + struct pci_bus lpci_bus, *pci_bus; + u8 cfgspc_irq, temp; + + memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); + pci_bus = &lpci_bus; + rom_resource_table = detect_HRT_floating_pointer(shpchp_rom_start, shpchp_rom_start + 0xffff); + dbg("rom_resource_table = %p\n", rom_resource_table); + if (rom_resource_table == NULL) + return -ENODEV; + + /* Sum all resources and setup resource maps */ + unused_IRQ = readl(rom_resource_table + UNUSED_IRQ); + dbg("unused_IRQ = %x\n", unused_IRQ); + + temp = 0; + while (unused_IRQ) { + if (unused_IRQ & 1) { + shpchp_disk_irq = temp; + break; + } + unused_IRQ = unused_IRQ >> 1; + temp++; + } + + dbg("shpchp_disk_irq= %d\n", shpchp_disk_irq); + unused_IRQ = unused_IRQ >> 1; + temp++; + + while (unused_IRQ) { + if (unused_IRQ & 1) { + shpchp_nic_irq = temp; + break; + } + unused_IRQ = unused_IRQ >> 1; + temp++; + } + + dbg("shpchp_nic_irq= %d\n", shpchp_nic_irq); + unused_IRQ = readl(rom_resource_table + PCIIRQ); + + temp = 0; + + pci_read_config_byte(ctrl->pci_dev, PCI_INTERRUPT_LINE, &cfgspc_irq); + + if (!shpchp_nic_irq) { + shpchp_nic_irq = cfgspc_irq; + } + + if (!shpchp_disk_irq) { + shpchp_disk_irq = cfgspc_irq; + } + + dbg("shpchp_disk_irq, shpchp_nic_irq= %d, %d\n", shpchp_disk_irq, shpchp_nic_irq); + + one_slot = rom_resource_table + sizeof(struct hrt); + + i = readb(rom_resource_table + NUMBER_OF_ENTRIES); + dbg("number_of_entries = %d\n", i); + + if (!readb(one_slot + SECONDARY_BUS)) + return (1); + + dbg("dev|IO base|length|MEMbase|length|PM base|length|PB SB MB\n"); + + while (i && readb(one_slot + SECONDARY_BUS)) { + u8 dev_func = readb(one_slot + DEV_FUNC); + u8 primary_bus = readb(one_slot + PRIMARY_BUS); + u8 secondary_bus = readb(one_slot + SECONDARY_BUS); + u8 max_bus = readb(one_slot + MAX_BUS); + u16 io_base = readw(one_slot + IO_BASE); + u16 io_length = readw(one_slot + IO_LENGTH); + u16 mem_base = readw(one_slot + MEM_BASE); + u16 mem_length = readw(one_slot + MEM_LENGTH); + u16 pre_mem_base = readw(one_slot + PRE_MEM_BASE); + u16 pre_mem_length = readw(one_slot + PRE_MEM_LENGTH); + + dbg("%2.2x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x |%2.2x %2.2x %2.2x\n", + dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length, + primary_bus, secondary_bus, max_bus); + + /* If this entry isn't for our controller's bus, ignore it */ + if (primary_bus != ctrl->slot_bus) { + i--; + one_slot += sizeof(struct slot_rt); + continue; + } + /* Find out if this entry is for an occupied slot */ + temp_dword = 0xFFFFFFFF; + pci_bus->number = primary_bus; + pci_bus_read_config_dword(pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword); + + dbg("temp_D_word = %x\n", temp_dword); + + if (temp_dword != 0xFFFFFFFF) { + index = 0; + func = shpchp_slot_find(primary_bus, dev_func >> 3, 0); + + while (func && (func->function != (dev_func & 0x07))) { + dbg("func = %p b:d:f(%x:%x:%x)\n", func, primary_bus, dev_func >> 3, index); + func = shpchp_slot_find(primary_bus, dev_func >> 3, index++); + } + + /* If we can't find a match, skip this table entry */ + if (!func) { + i--; + one_slot += sizeof(struct slot_rt); + continue; + } + /* This may not work and shouldn't be used */ + if (secondary_bus != primary_bus) + bridged_slot = 1; + else + bridged_slot = 0; + + populated_slot = 1; + } else { + populated_slot = 0; + bridged_slot = 0; + } + dbg("slot populated =%s \n", populated_slot?"yes":"no"); + + /* If we've got a valid IO base, use it */ + + temp_ulong = io_base + io_length; + + if ((io_base) && (temp_ulong <= 0x10000)) { + io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!io_node) + return -ENOMEM; + + io_node->base = (ulong)io_base; + io_node->length = (ulong)io_length; + dbg("found io_node(base, length) = %x, %x\n", io_node->base, io_node->length); + + if (!populated_slot) { + io_node->next = ctrl->io_head; + ctrl->io_head = io_node; + } else { + io_node->next = func->io_head; + func->io_head = io_node; + } + } + + /* If we've got a valid memory base, use it */ + temp_ulong = mem_base + mem_length; + if ((mem_base) && (temp_ulong <= 0x10000)) { + mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!mem_node) + return -ENOMEM; + + mem_node->base = (ulong)mem_base << 16; + mem_node->length = (ulong)(mem_length << 16); + dbg("found mem_node(base, length) = %x, %x\n", mem_node->base, mem_node->length); + + if (!populated_slot) { + mem_node->next = ctrl->mem_head; + ctrl->mem_head = mem_node; + } else { + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } + } + + /* + * If we've got a valid prefetchable memory base, and + * the base + length isn't greater than 0xFFFF + */ + temp_ulong = pre_mem_base + pre_mem_length; + if ((pre_mem_base) && (temp_ulong <= 0x10000)) { + p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!p_mem_node) + return -ENOMEM; + + p_mem_node->base = (ulong)pre_mem_base << 16; + p_mem_node->length = (ulong)pre_mem_length << 16; + dbg("found p_mem_node(base, length) = %x, %x\n", p_mem_node->base, p_mem_node->length); + + if (!populated_slot) { + p_mem_node->next = ctrl->p_mem_head; + ctrl->p_mem_head = p_mem_node; + } else { + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } + } + + /* + * If we've got a valid bus number, use it + * The second condition is to ignore bus numbers on + * populated slots that don't have PCI-PCI bridges + */ + if (secondary_bus && (secondary_bus != primary_bus)) { + bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!bus_node) + return -ENOMEM; + + bus_node->base = (ulong)secondary_bus; + bus_node->length = (ulong)(max_bus - secondary_bus + 1); + dbg("found bus_node(base, length) = %x, %x\n", bus_node->base, bus_node->length); + + if (!populated_slot) { + bus_node->next = ctrl->bus_head; + ctrl->bus_head = bus_node; + } else { + bus_node->next = func->bus_head; + func->bus_head = bus_node; + } + } + + i--; + one_slot += sizeof(struct slot_rt); + } + + /* If all of the following fail, we don't have any resources for hot plug add */ + rc = 1; + rc &= shpchp_resource_sort_and_combine(&(ctrl->mem_head)); + rc &= shpchp_resource_sort_and_combine(&(ctrl->p_mem_head)); + rc &= shpchp_resource_sort_and_combine(&(ctrl->io_head)); + rc &= shpchp_resource_sort_and_combine(&(ctrl->bus_head)); + + return (rc); +} + +int shpchprm_set_hpp( + struct controller *ctrl, + struct pci_func *func, + u8 card_type) +{ + u32 rc; + u8 temp_byte; + struct pci_bus lpci_bus, *pci_bus; + unsigned int devfn; + memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); + pci_bus = &lpci_bus; + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + temp_byte = 0x40; /* Hard coded value for LT */ + if (card_type == PCI_HEADER_TYPE_BRIDGE) { + /* Set subordinate Latency Timer */ + rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte); + if (rc) { + dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); + return rc; + } + } + + /* Set base Latency Timer */ + rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte); + if (rc) { + dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); + return rc; + } + + /* Set Cache Line size */ + temp_byte = 0x08; /* hard coded value for CLS */ + rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte); + if (rc) { + dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); + } + + /* Set enable_perr */ + /* Set enable_serr */ + + return rc; +} + +void shpchprm_enable_card( + struct controller *ctrl, + struct pci_func *func, + u8 card_type) +{ + u16 command, bcommand; + struct pci_bus lpci_bus, *pci_bus; + unsigned int devfn; + int rc; + + memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); + pci_bus = &lpci_bus; + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command); + command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR + | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE + | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; + rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); + + if (card_type == PCI_HEADER_TYPE_BRIDGE) { + rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand); + bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR + | PCI_BRIDGE_CTL_NO_ISA; + rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand); + } +} + +static int legacy_shpchprm_init_pci(void) +{ + shpchp_rom_start = (u8 *) ioremap(ROM_PHY_ADDR, ROM_PHY_LEN); + if (!shpchp_rom_start) { + err("Could not ioremap memory region for ROM\n"); + return -EIO; + } + + return 0; +} + +int shpchprm_init(enum php_ctlr_type ctrl_type) +{ + int retval; + + switch (ctrl_type) { + case PCI: + retval = legacy_shpchprm_init_pci(); + break; + default: + retval = -ENODEV; + break; + } + + return retval; +} diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/shpchprm_legacy.h linux-2.4.27-pre5/drivers/hotplug/shpchprm_legacy.h --- linux-2.4.26/drivers/hotplug/shpchprm_legacy.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/shpchprm_legacy.h 2004-06-03 01:32:59.000000000 +0000 @@ -0,0 +1,113 @@ +/* + * SHPCHPRM Legacy: PHP Resource Manager for Non-ACPI/Legacy platform using HRT + * + * 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 _SHPCHPRM_LEGACY_H_ +#define _SHPCHPRM_LEGACY_H_ + +#define ROM_PHY_ADDR 0x0F0000 +#define ROM_PHY_LEN 0x00FFFF + +struct slot_rt { + u8 dev_func; + u8 primary_bus; + u8 secondary_bus; + u8 max_bus; + u16 io_base; + u16 io_length; + u16 mem_base; + u16 mem_length; + u16 pre_mem_base; + u16 pre_mem_length; +} __attribute__ ((packed)); + +/* offsets to the hotplug slot resource table registers based on the above structure layout */ +enum slot_rt_offsets { + DEV_FUNC = offsetof(struct slot_rt, dev_func), + PRIMARY_BUS = offsetof(struct slot_rt, primary_bus), + SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus), + MAX_BUS = offsetof(struct slot_rt, max_bus), + IO_BASE = offsetof(struct slot_rt, io_base), + IO_LENGTH = offsetof(struct slot_rt, io_length), + MEM_BASE = offsetof(struct slot_rt, mem_base), + MEM_LENGTH = offsetof(struct slot_rt, mem_length), + PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base), + PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length), +}; + +struct hrt { + char sig0; + char sig1; + char sig2; + char sig3; + u16 unused_IRQ; + u16 PCIIRQ; + u8 number_of_entries; + u8 revision; + u16 reserved1; + u32 reserved2; +} __attribute__ ((packed)); + +/* offsets to the hotplug resource table registers based on the above structure layout */ +enum hrt_offsets { + SIG0 = offsetof(struct hrt, sig0), + SIG1 = offsetof(struct hrt, sig1), + SIG2 = offsetof(struct hrt, sig2), + SIG3 = offsetof(struct hrt, sig3), + UNUSED_IRQ = offsetof(struct hrt, unused_IRQ), + PCIIRQ = offsetof(struct hrt, PCIIRQ), + NUMBER_OF_ENTRIES = offsetof(struct hrt, number_of_entries), + REVISION = offsetof(struct hrt, revision), + HRT_RESERVED1 = offsetof(struct hrt, reserved1), + HRT_RESERVED2 = offsetof(struct hrt, reserved2), +}; + +struct irq_info { + u8 bus, devfn; /* bus, device and function */ + struct { + u8 link; /* IRQ line ID, chipset dependent, 0=not routed */ + u16 bitmap; /* Available IRQs */ + } __attribute__ ((packed)) irq[4]; + u8 slot; /* slot number, 0=onboard */ + u8 rfu; +} __attribute__ ((packed)); + +struct irq_routing_table { + u32 signature; /* PIRQ_SIGNATURE should be here */ + u16 version; /* PIRQ_VERSION */ + u16 size; /* Table size in bytes */ + u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */ + u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */ + u16 rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */ + u32 miniport_data; /* Crap */ + u8 rfu[11]; + u8 checksum; /* Modulo 256 checksum must give zero */ + struct irq_info slots[0]; +} __attribute__ ((packed)); + +#endif /* _SHPCHPRM_LEGACY_H_ */ diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/shpchprm_nonacpi.c linux-2.4.27-pre5/drivers/hotplug/shpchprm_nonacpi.c --- linux-2.4.26/drivers/hotplug/shpchprm_nonacpi.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/shpchprm_nonacpi.c 2004-06-03 01:34:18.000000000 +0000 @@ -0,0 +1,430 @@ +/* + * SHPCHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform + * + * 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 +#ifdef CONFIG_IA64 +#include +#endif +#include "shpchp.h" +#include "shpchprm.h" +#include "shpchprm_nonacpi.h" + +void shpchprm_cleanup(void) +{ + return; +} + +int shpchprm_print_pirt(void) +{ + return 0; +} + +void * shpchprm_get_slot(struct slot *slot) +{ + return NULL; +} + +int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum) +{ + int offset = devnum - ctrl->slot_device_offset; + + dbg("%s: ctrl->slot_num_inc %d, offset %d\n", __FUNCTION__, ctrl->slot_num_inc, offset); + *sun = (u8) (ctrl->first_slot + ctrl->slot_num_inc * offset); + return 0; +} + +static void print_pci_resource ( struct pci_resource *aprh) +{ + struct pci_resource *res; + + for (res = aprh; res; res = res->next) + dbg(" base= 0x%x length= 0x%x\n", res->base, res->length); +} + + +static void phprm_dump_func_res( struct pci_func *fun) +{ + struct pci_func *func = fun; + + if (func->bus_head) { + dbg(": BUS Resources:\n"); + print_pci_resource (func->bus_head); + } + if (func->io_head) { + dbg(": IO Resources:\n"); + print_pci_resource (func->io_head); + } + if (func->mem_head) { + dbg(": MEM Resources:\n"); + print_pci_resource (func->mem_head); + } + if (func->p_mem_head) { + dbg(": PMEM Resources:\n"); + print_pci_resource (func->p_mem_head); + } +} + +static int phprm_get_used_resources ( + struct controller *ctrl, + struct pci_func *func + ) +{ + return shpchp_save_used_resources (ctrl, func, !DISABLE_CARD); +} + +static int phprm_delete_resource( + struct pci_resource **aprh, + ulong base, + ulong size) +{ + struct pci_resource *res; + struct pci_resource *prevnode; + struct pci_resource *split_node; + ulong tbase; + + shpchp_resource_sort_and_combine(aprh); + + for (res = *aprh; res; res = res->next) { + if (res->base > base) + continue; + + if ((res->base + res->length) < (base + size)) + continue; + + if (res->base < base) { + tbase = base; + + if ((res->length - (tbase - res->base)) < size) + continue; + + split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!split_node) + return -ENOMEM; + + split_node->base = res->base; + split_node->length = tbase - res->base; + res->base = tbase; + res->length -= split_node->length; + + split_node->next = res->next; + res->next = split_node; + } + + if (res->length >= size) { + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!split_node) + return -ENOMEM; + + split_node->base = res->base + size; + split_node->length = res->length - size; + res->length = size; + + split_node->next = res->next; + res->next = split_node; + } + + if (*aprh == res) { + *aprh = res->next; + } else { + prevnode = *aprh; + while (prevnode->next != res) + prevnode = prevnode->next; + + prevnode->next = res->next; + } + res->next = NULL; + kfree(res); + break; + } + + return 0; +} + + +static int phprm_delete_resources( + struct pci_resource **aprh, + struct pci_resource *this + ) +{ + struct pci_resource *res; + + for (res = this; res; res = res->next) + phprm_delete_resource(aprh, res->base, res->length); + + return 0; +} + + +static int configure_existing_function( + struct controller *ctrl, + struct pci_func *func + ) +{ + int rc; + + /* see how much resources the func has used. */ + rc = phprm_get_used_resources (ctrl, func); + + if (!rc) { + /* subtract the resources used by the func from ctrl resources */ + rc = phprm_delete_resources (&ctrl->bus_head, func->bus_head); + rc |= phprm_delete_resources (&ctrl->io_head, func->io_head); + rc |= phprm_delete_resources (&ctrl->mem_head, func->mem_head); + rc |= phprm_delete_resources (&ctrl->p_mem_head, func->p_mem_head); + if (rc) + warn("aCEF: cannot del used resources\n"); + } else + err("aCEF: cannot get used resources\n"); + + return rc; +} + +static int bind_pci_resources_to_slots ( struct controller *ctrl) +{ + struct pci_func *func; + int busn = ctrl->slot_bus; + int devn, funn; + u32 vid; + + for (devn = 0; devn < 32; devn++) { + for (funn = 0; funn < 8; funn++) { + /* if (devn == ctrl->device && funn == ctrl->function) + continue; + */ + /* find out if this entry is for an occupied slot */ + vid = 0xFFFFFFFF; + + pci_bus_read_config_dword(ctrl->pci_dev->subordinate, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &vid); + + if (vid != 0xFFFFFFFF) { + func = shpchp_slot_find(busn, devn, funn); + if (!func) + continue; + configure_existing_function(ctrl, func); + dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus); + phprm_dump_func_res(func); + } + } + } + + return 0; +} + +static void phprm_dump_ctrl_res( struct controller *ctlr) +{ + struct controller *ctrl = ctlr; + + if (ctrl->bus_head) { + dbg(": BUS Resources:\n"); + print_pci_resource (ctrl->bus_head); + } + if (ctrl->io_head) { + dbg(": IO Resources:\n"); + print_pci_resource (ctrl->io_head); + } + if (ctrl->mem_head) { + dbg(": MEM Resources:\n"); + print_pci_resource (ctrl->mem_head); + } + if (ctrl->p_mem_head) { + dbg(": PMEM Resources:\n"); + print_pci_resource (ctrl->p_mem_head); + } +} + +/* + * phprm_find_available_resources + * + * Finds available memory, IO, and IRQ resources for programming + * devices which may be added to the system + * this function is for hot plug ADD! + * + * returns 0 if success + */ +int shpchprm_find_available_resources(struct controller *ctrl) +{ + struct pci_func func; + u32 rc; + + memset(&func, 0, sizeof(struct pci_func)); + + func.bus = ctrl->bus; + func.device = ctrl->device; + func.function = ctrl->function; + func.is_a_board = 1; + + /* Get resources for this PCI bridge */ + rc = shpchp_save_used_resources (ctrl, &func, !DISABLE_CARD); + dbg("%s: shpchp_save_used_resources rc = %d\n", __FUNCTION__, rc); + + if (func.mem_head) + func.mem_head->next = ctrl->mem_head; + ctrl->mem_head = func.mem_head; + + if (func.p_mem_head) + func.p_mem_head->next = ctrl->p_mem_head; + ctrl->p_mem_head = func.p_mem_head; + + if (func.io_head) + func.io_head->next = ctrl->io_head; + ctrl->io_head = func.io_head; + + if(func.bus_head) + func.bus_head->next = ctrl->bus_head; + ctrl->bus_head = func.bus_head; + if (ctrl->bus_head) + phprm_delete_resource(&ctrl->bus_head, ctrl->pci_dev->subordinate->number, 1); + + dbg("%s:pre-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl->bus); + phprm_dump_ctrl_res(ctrl); + + bind_pci_resources_to_slots (ctrl); + + dbg("%s:post-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl->bus); + phprm_dump_ctrl_res(ctrl); + + + /* If all of the following fail, we don't have any resources for hot plug add */ + rc = 1; + rc &= shpchp_resource_sort_and_combine(&(ctrl->mem_head)); + rc &= shpchp_resource_sort_and_combine(&(ctrl->p_mem_head)); + rc &= shpchp_resource_sort_and_combine(&(ctrl->io_head)); + rc &= shpchp_resource_sort_and_combine(&(ctrl->bus_head)); + + return (rc); +} + +int shpchprm_set_hpp( + struct controller *ctrl, + struct pci_func *func, + u8 card_type) +{ + u32 rc; + u8 temp_byte; + struct pci_bus lpci_bus, *pci_bus; + unsigned int devfn; + memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); + pci_bus = &lpci_bus; + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + temp_byte = 0x40; /* hard coded value for LT */ + if (card_type == PCI_HEADER_TYPE_BRIDGE) { + /* set subordinate Latency Timer */ + rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte); + + if (rc) { + dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); + return rc; + } + } + + /* set base Latency Timer */ + rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte); + + if (rc) { + dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); + return rc; + } + + /* set Cache Line size */ + temp_byte = 0x08; /* hard coded value for CLS */ + + rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte); + + if (rc) { + dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func->bus, func->device, func->function); + } + + /* set enable_perr */ + /* set enable_serr */ + + return rc; +} + +void shpchprm_enable_card( + struct controller *ctrl, + struct pci_func *func, + u8 card_type) +{ + u16 command, bcommand; + struct pci_bus lpci_bus, *pci_bus; + unsigned int devfn; + int rc; + + memcpy(&lpci_bus, ctrl->pci_bus, sizeof(lpci_bus)); + pci_bus = &lpci_bus; + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &command); + + command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR + | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE + | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; + + rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); + + if (card_type == PCI_HEADER_TYPE_BRIDGE) { + + rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &bcommand); + + bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR + | PCI_BRIDGE_CTL_NO_ISA; + + rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand); + } +} + +static int legacy_shpchprm_init_pci(void) +{ + return 0; +} + +int shpchprm_init(enum php_ctlr_type ctrl_type) +{ + int retval; + + switch (ctrl_type) { + case PCI: + retval = legacy_shpchprm_init_pci(); + break; + default: + retval = -ENODEV; + break; + } + + return retval; +} diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/hotplug/shpchprm_nonacpi.h linux-2.4.27-pre5/drivers/hotplug/shpchprm_nonacpi.h --- linux-2.4.26/drivers/hotplug/shpchprm_nonacpi.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/hotplug/shpchprm_nonacpi.h 2004-06-03 01:36:15.000000000 +0000 @@ -0,0 +1,56 @@ +/* + * SHPCHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform + * + * 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 _SHPCHPRM_NONACPI_H_ +#define _SHPCHPRM_NONACPI_H_ + +struct irq_info { + u8 bus, devfn; /* bus, device and function */ + struct { + u8 link; /* IRQ line ID, chipset dependent, 0=not routed */ + u16 bitmap; /* Available IRQs */ + } __attribute__ ((packed)) irq[4]; + u8 slot; /* slot number, 0=onboard */ + u8 rfu; +} __attribute__ ((packed)); + +struct irq_routing_table { + u32 signature; /* PIRQ_SIGNATURE should be here */ + u16 version; /* PIRQ_VERSION */ + u16 size; /* Table size in bytes */ + u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */ + u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */ + u16 rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */ + u32 miniport_data; /* Crap */ + u8 rfu[11]; + u8 checksum; /* Modulo 256 checksum must give zero */ + struct irq_info slots[0]; +} __attribute__ ((packed)); + +#endif /* _SHPCHPRM_NONACPI_H_ */ diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/ide-disk.c linux-2.4.27-pre5/drivers/ide/ide-disk.c --- linux-2.4.26/drivers/ide/ide-disk.c 2003-11-28 18:26:20.000000000 +0000 +++ linux-2.4.27-pre5/drivers/ide/ide-disk.c 2004-06-03 01:32:24.000000000 +0000 @@ -1161,15 +1161,15 @@ static void init_idedisk_capacity (ide_d { struct hd_driveid *id = drive->id; unsigned long capacity = drive->cyl * drive->head * drive->sect; - unsigned long set_max = idedisk_read_native_max_address(drive); + int have_setmax = idedisk_supports_host_protected_area(drive); + unsigned long set_max = + (have_setmax ? idedisk_read_native_max_address(drive) : 0); unsigned long long capacity_2 = capacity; unsigned long long set_max_ext; drive->capacity48 = 0; drive->select.b.lba = 0; - (void) idedisk_supports_host_protected_area(drive); - if (id->cfs_enable_2 & 0x0400) { capacity_2 = id->lba_capacity_2; drive->head = drive->bios_head = 255; diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/aec62xx.c linux-2.4.27-pre5/drivers/ide/pci/aec62xx.c --- linux-2.4.26/drivers/ide/pci/aec62xx.c 2003-06-13 14:51:33.000000000 +0000 +++ linux-2.4.27-pre5/drivers/ide/pci/aec62xx.c 2004-06-03 01:35:49.000000000 +0000 @@ -356,13 +356,15 @@ try_dma_modes: } else { goto fast_ata_pio; } + return hwif->ide_dma_on(drive); } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: no_dma_set: aec62xx_tune_drive(drive, 5); return hwif->ide_dma_off_quietly(drive); } - return hwif->ide_dma_on(drive); + /* IORDY not supported */ + return 0; } static int aec62xx_irq_timeout (ide_drive_t *drive) diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/cmd64x.c linux-2.4.27-pre5/drivers/ide/pci/cmd64x.c --- linux-2.4.26/drivers/ide/pci/cmd64x.c 2003-06-13 14:51:33.000000000 +0000 +++ linux-2.4.27-pre5/drivers/ide/pci/cmd64x.c 2004-06-03 01:35:51.000000000 +0000 @@ -485,13 +485,15 @@ try_dma_modes: } else { goto fast_ata_pio; } + return hwif->ide_dma_on(drive); } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: no_dma_set: config_chipset_for_pio(drive, 1); return hwif->ide_dma_off_quietly(drive); } - return hwif->ide_dma_on(drive); + /* IORDY not supported */ + return 0; } static int cmd64x_alt_dma_status (struct pci_dev *dev) diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/generic.c linux-2.4.27-pre5/drivers/ide/pci/generic.c --- linux-2.4.26/drivers/ide/pci/generic.c 2003-08-25 11:44:41.000000000 +0000 +++ linux-2.4.27-pre5/drivers/ide/pci/generic.c 2004-06-03 01:35:26.000000000 +0000 @@ -141,6 +141,8 @@ static struct pci_device_id generic_pci_ { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7}, { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8}, { PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9}, + { PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10}, + { PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11}, { 0, }, }; diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/generic.h linux-2.4.27-pre5/drivers/ide/pci/generic.h --- linux-2.4.26/drivers/ide/pci/generic.h 2004-04-14 13:05:29.000000000 +0000 +++ linux-2.4.27-pre5/drivers/ide/pci/generic.h 2004-06-03 01:32:51.000000000 +0000 @@ -130,16 +130,33 @@ static ide_pci_device_t generic_chipsets },{ /* 9 */ .vendor = PCI_VENDOR_ID_TOSHIBA, .device = PCI_DEVICE_ID_TOSHIBA_PICCOLO, - .name = "Piccolo", + .name = "Piccolo0102", + .init_chipset = init_chipset_generic, + .init_hwif = init_hwif_generic, + .init_dma = init_dma_generic, + .channels = 2, + .autodma = NOAUTODMA, + .bootable = ON_BOARD, + },{ /* 10 */ + .vendor = PCI_VENDOR_ID_TOSHIBA, + .device = PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, + .name = "Piccolo0103", + .init_chipset = init_chipset_generic, + .init_hwif = init_hwif_generic, + .init_dma = init_dma_generic, + .channels = 2, + .autodma = NOAUTODMA, + .bootable = ON_BOARD, + },{ /* 11 */ + .vendor = PCI_VENDOR_ID_TOSHIBA, + .device = PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, + .name = "Piccolo0105", .init_chipset = init_chipset_generic, - .init_iops = NULL, .init_hwif = init_hwif_generic, .init_dma = init_dma_generic, .channels = 2, .autodma = NOAUTODMA, - .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, .bootable = ON_BOARD, - .extra = 0, },{ .vendor = 0, .device = 0, diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/hpt34x.c linux-2.4.27-pre5/drivers/ide/pci/hpt34x.c --- linux-2.4.26/drivers/ide/pci/hpt34x.c 2003-06-13 14:51:33.000000000 +0000 +++ linux-2.4.27-pre5/drivers/ide/pci/hpt34x.c 2004-06-03 01:32:40.000000000 +0000 @@ -216,17 +216,19 @@ try_dma_modes: } else { goto fast_ata_pio; } +#ifndef CONFIG_HPT34X_AUTODMA + return hwif->ide_dma_off_quietly(drive); +#else + return hwif->ide_dma_on(drive); +#endif } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: no_dma_set: hpt34x_tune_drive(drive, 255); return hwif->ide_dma_off_quietly(drive); } - -#ifndef CONFIG_HPT34X_AUTODMA - return hwif->ide_dma_off_quietly(drive); -#endif /* CONFIG_HPT34X_AUTODMA */ - return hwif->ide_dma_on(drive); + /* IORDY not supported */ + return 0; } /* diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/hpt366.c linux-2.4.27-pre5/drivers/ide/pci/hpt366.c --- linux-2.4.26/drivers/ide/pci/hpt366.c 2004-04-14 13:05:30.000000000 +0000 +++ linux-2.4.27-pre5/drivers/ide/pci/hpt366.c 2004-06-03 01:32:46.000000000 +0000 @@ -567,13 +567,15 @@ try_dma_modes: } else { goto fast_ata_pio; } + return hwif->ide_dma_on(drive); } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: no_dma_set: hpt3xx_tune_drive(drive, 5); return hwif->ide_dma_off_quietly(drive); } - return hwif->ide_dma_on(drive); + /* IORDY not supported */ + return 0; } /* diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/it8172.c linux-2.4.27-pre5/drivers/ide/pci/it8172.c --- linux-2.4.26/drivers/ide/pci/it8172.c 2003-06-13 14:51:33.000000000 +0000 +++ linux-2.4.27-pre5/drivers/ide/pci/it8172.c 2004-06-03 01:34:37.000000000 +0000 @@ -228,13 +228,15 @@ try_dma_modes: } else { goto fast_ata_pio; } + return hwif->ide_dma_on(drive); } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: no_dma_set: it8172_tune_drive(drive, 5); return hwif->ide_dma_off_quietly(drive); } - return hwif->ide_dma_on(drive); + /* IORDY not supported */ + return 0; } static unsigned int __init init_chipset_it8172 (struct pci_dev *dev, const char *name) diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/pdc202xx_new.c linux-2.4.27-pre5/drivers/ide/pci/pdc202xx_new.c --- linux-2.4.26/drivers/ide/pci/pdc202xx_new.c 2003-06-13 14:51:33.000000000 +0000 +++ linux-2.4.27-pre5/drivers/ide/pci/pdc202xx_new.c 2004-06-03 01:32:40.000000000 +0000 @@ -415,13 +415,15 @@ try_dma_modes: } else { goto fast_ata_pio; } + return hwif->ide_dma_on(drive); } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: no_dma_set: hwif->tuneproc(drive, 5); return hwif->ide_dma_off_quietly(drive); } - return hwif->ide_dma_on(drive); + /* IORDY not supported */ + return 0; } static int pdcnew_quirkproc (ide_drive_t *drive) diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/pdc202xx_old.c linux-2.4.27-pre5/drivers/ide/pci/pdc202xx_old.c --- linux-2.4.26/drivers/ide/pci/pdc202xx_old.c 2003-11-28 18:26:20.000000000 +0000 +++ linux-2.4.27-pre5/drivers/ide/pci/pdc202xx_old.c 2004-06-03 01:34:18.000000000 +0000 @@ -516,13 +516,15 @@ try_dma_modes: } else { goto fast_ata_pio; } + return hwif->ide_dma_on(drive); } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: no_dma_set: hwif->tuneproc(drive, 5); return hwif->ide_dma_off_quietly(drive); } - return hwif->ide_dma_on(drive); + /* IORDY not supported */ + return 0; } static int pdc202xx_quirkproc (ide_drive_t *drive) diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/piix.c linux-2.4.27-pre5/drivers/ide/pci/piix.c --- linux-2.4.26/drivers/ide/pci/piix.c 2004-04-14 13:05:30.000000000 +0000 +++ linux-2.4.27-pre5/drivers/ide/pci/piix.c 2004-06-03 01:35:56.000000000 +0000 @@ -593,13 +593,15 @@ try_dma_modes: } else { goto fast_ata_pio; } + return hwif->ide_dma_on(drive); } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: no_dma_set: hwif->tuneproc(drive, 255); return hwif->ide_dma_off_quietly(drive); } - return hwif->ide_dma_on(drive); + /* IORDY not supported */ + return 0; } /** diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/serverworks.c linux-2.4.27-pre5/drivers/ide/pci/serverworks.c --- linux-2.4.26/drivers/ide/pci/serverworks.c 2003-11-28 18:26:20.000000000 +0000 +++ linux-2.4.27-pre5/drivers/ide/pci/serverworks.c 2004-06-03 01:34:24.000000000 +0000 @@ -473,7 +473,9 @@ static int svwks_config_drive_xfer_rate int dma = config_chipset_for_dma(drive); if ((id->field_valid & 2) && !dma) goto try_dma_modes; - } + } else + /* UDMA disabled by mask, try other DMA modes */ + goto try_dma_modes; } else if (id->field_valid & 2) { try_dma_modes: if ((id->dma_mword & hwif->mwdma_mask) || @@ -490,6 +492,7 @@ try_dma_modes: } else { goto no_dma_set; } + return hwif->ide_dma_on(drive); } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: no_dma_set: @@ -497,7 +500,8 @@ no_dma_set: // hwif->tuneproc(drive, 5); return hwif->ide_dma_off_quietly(drive); } - return hwif->ide_dma_on(drive); + /* IORDY not supported */ + return 0; } /* This can go soon */ diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/siimage.c linux-2.4.27-pre5/drivers/ide/pci/siimage.c --- linux-2.4.26/drivers/ide/pci/siimage.c 2004-04-14 13:05:30.000000000 +0000 +++ linux-2.4.27-pre5/drivers/ide/pci/siimage.c 2004-06-03 01:35:16.000000000 +0000 @@ -516,13 +516,15 @@ try_dma_modes: } else { goto fast_ata_pio; } + return hwif->ide_dma_on(drive); } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: no_dma_set: config_chipset_for_pio(drive, 1); return hwif->ide_dma_off_quietly(drive); } - return hwif->ide_dma_on(drive); + /* IORDY not supported */ + return 0; } /* returns 1 if dma irq issued, 0 otherwise */ diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/sis5513.c linux-2.4.27-pre5/drivers/ide/pci/sis5513.c --- linux-2.4.26/drivers/ide/pci/sis5513.c 2003-08-25 11:44:41.000000000 +0000 +++ linux-2.4.27-pre5/drivers/ide/pci/sis5513.c 2004-06-03 01:33:44.000000000 +0000 @@ -697,13 +697,15 @@ try_dma_modes: } else { goto fast_ata_pio; } + return hwif->ide_dma_on(drive); } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: no_dma_set: sis5513_tune_drive(drive, 5); return hwif->ide_dma_off_quietly(drive); } - return hwif->ide_dma_on(drive); + /* IORDY not supported */ + return 0; } /* initiates/aborts (U)DMA read/write operations on a drive. */ diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/ide/pci/slc90e66.c linux-2.4.27-pre5/drivers/ide/pci/slc90e66.c --- linux-2.4.26/drivers/ide/pci/slc90e66.c 2003-06-13 14:51:33.000000000 +0000 +++ linux-2.4.27-pre5/drivers/ide/pci/slc90e66.c 2004-06-03 01:32:31.000000000 +0000 @@ -302,13 +302,15 @@ try_dma_modes: } else { goto fast_ata_pio; } + return hwif->ide_dma_on(drive); } else if ((id->capability & 8) || (id->field_valid & 2)) { fast_ata_pio: no_dma_set: hwif->tuneproc(drive, 5); return hwif->ide_dma_off_quietly(drive); } - return hwif->ide_dma_on(drive); + /* IORDY not supported */ + return 0; } #endif /* CONFIG_BLK_DEV_IDEDMA */ diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/isdn/sc/command.c linux-2.4.27-pre5/drivers/isdn/sc/command.c --- linux-2.4.26/drivers/isdn/sc/command.c 2001-12-21 17:41:54.000000000 +0000 +++ linux-2.4.27-pre5/drivers/isdn/sc/command.c 2004-06-03 01:33:26.000000000 +0000 @@ -95,7 +95,7 @@ int get_card_from_id(int driver) if(adapter[i]->driverId == driver) return i; } - return -NODEV; + return -ENODEV; } /* diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/media/video/cpia.c linux-2.4.27-pre5/drivers/media/video/cpia.c --- linux-2.4.26/drivers/media/video/cpia.c 2003-11-28 18:26:20.000000000 +0000 +++ linux-2.4.27-pre5/drivers/media/video/cpia.c 2004-06-03 01:34:55.000000000 +0000 @@ -2443,7 +2443,7 @@ static int reset_camera(struct cam_data goto_high_power(cam); do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0); if (goto_low_power(cam)) - return -NODEV; + return -ENODEV; } /* procedure described in developer's guide p3-28 */ diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/media/video/videodev.c linux-2.4.27-pre5/drivers/media/video/videodev.c --- linux-2.4.26/drivers/media/video/videodev.c 2003-11-28 18:26:20.000000000 +0000 +++ linux-2.4.27-pre5/drivers/media/video/videodev.c 2004-06-03 01:32:44.000000000 +0000 @@ -553,7 +553,14 @@ int video_register_device(struct video_d /* pick a minor number */ down(&videodev_lock); - if (-1 == nr) { + if (nr >= 0 && nr < end-base) { + /* use the one the driver asked for */ + i = base+nr; + if (NULL != video_device[i]) { + up(&videodev_lock); + return -ENFILE; + } + } else { /* use first free */ for(i=base;iminor=i; diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/message/fusion/isense.c linux-2.4.27-pre5/drivers/message/fusion/isense.c --- linux-2.4.26/drivers/message/fusion/isense.c 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/message/fusion/isense.c 2004-06-03 01:34:13.000000000 +0000 @@ -66,7 +66,7 @@ #endif #define MODULEAUTHOR "Steven J. Ralston" -#define COPYRIGHT "Copyright (c) 2001-2002 " MODULEAUTHOR +#define COPYRIGHT "Copyright (c) 2001-2004 " MODULEAUTHOR #include "mptbase.h" #include "isense.h" diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/message/fusion/lsi/mpi.h linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi.h --- linux-2.4.26/drivers/message/fusion/lsi/mpi.h 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi.h 2004-06-03 01:32:44.000000000 +0000 @@ -2,11 +2,11 @@ * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI.H + * Name: mpi.h * Title: MPI Message independent structures and definitions * Creation Date: July 27, 2000 * - * MPI.H Version: 01.02.10 + * mpi.h Version: 01.05.xx * * Version History * --------------- @@ -66,7 +66,7 @@ *****************************************************************************/ #define MPI_VERSION_MAJOR (0x01) -#define MPI_VERSION_MINOR (0x02) +#define MPI_VERSION_MINOR (0x05) #define MPI_VERSION_MAJOR_MASK (0xFF00) #define MPI_VERSION_MAJOR_SHIFT (8) #define MPI_VERSION_MINOR_MASK (0x00FF) @@ -77,10 +77,12 @@ #define MPI_VERSION_01_00 (0x0100) #define MPI_VERSION_01_01 (0x0101) #define MPI_VERSION_01_02 (0x0102) +#define MPI_VERSION_01_03 (0x0103) +#define MPI_VERSION_01_05 (0x0105) /* Note: The major versions of 0xe0 through 0xff are reserved */ /* versioning for this MPI header set */ -#define MPI_HEADER_VERSION_UNIT (0x0C) +#define MPI_HEADER_VERSION_UNIT (0x00) #define MPI_HEADER_VERSION_DEV (0x00) #define MPI_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI_HEADER_VERSION_UNIT_SHIFT (8) @@ -175,6 +177,8 @@ #define MPI_REPLY_POST_FIFO_OFFSET (0x00000044) #define MPI_REPLY_FREE_FIFO_OFFSET (0x00000044) +#define MPI_HI_PRI_REQUEST_QUEUE_OFFSET (0x00000048) + /***************************************************************************** @@ -234,10 +238,6 @@ #define MPI_FUNCTION_TARGET_ASSIST (0x0B) #define MPI_FUNCTION_TARGET_STATUS_SEND (0x0C) #define MPI_FUNCTION_TARGET_MODE_ABORT (0x0D) -#define MPI_FUNCTION_TARGET_FC_BUF_POST_LINK_SRVC (0x0E) /* obsolete name */ -#define MPI_FUNCTION_TARGET_FC_RSP_LINK_SRVC (0x0F) /* obsolete name */ -#define MPI_FUNCTION_TARGET_FC_EX_SEND_LINK_SRVC (0x10) /* obsolete name */ -#define MPI_FUNCTION_TARGET_FC_ABORT (0x11) /* obsolete name */ #define MPI_FUNCTION_FC_LINK_SRVC_BUF_POST (0x0E) #define MPI_FUNCTION_FC_LINK_SRVC_RSP (0x0F) #define MPI_FUNCTION_FC_EX_LINK_SRVC_SEND (0x10) @@ -255,16 +255,46 @@ #define MPI_FUNCTION_MAILBOX (0x19) +#define MPI_FUNCTION_SMP_PASSTHROUGH (0x1A) +#define MPI_FUNCTION_SAS_IO_UNIT_CONTROL (0x1B) + +#define MPI_DIAG_BUFFER_POST (0x1D) +#define MPI_DIAG_RELEASE (0x1E) + +#define MPI_FUNCTION_SCSI_IO_32 (0x1F) + #define MPI_FUNCTION_LAN_SEND (0x20) #define MPI_FUNCTION_LAN_RECEIVE (0x21) #define MPI_FUNCTION_LAN_RESET (0x22) +#define MPI_FUNCTION_INBAND_BUFFER_POST (0x28) +#define MPI_FUNCTION_INBAND_SEND (0x29) +#define MPI_FUNCTION_INBAND_RSP (0x2A) +#define MPI_FUNCTION_INBAND_ABORT (0x2B) + #define MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40) #define MPI_FUNCTION_IO_UNIT_RESET (0x41) #define MPI_FUNCTION_HANDSHAKE (0x42) #define MPI_FUNCTION_REPLY_FRAME_REMOVAL (0x43) +/* standard version format */ +typedef struct _MPI_VERSION_STRUCT +{ + U8 Dev; /* 00h */ + U8 Unit; /* 01h */ + U8 Minor; /* 02h */ + U8 Major; /* 03h */ +} MPI_VERSION_STRUCT, MPI_POINTER PTR_MPI_VERSION_STRUCT, + MpiVersionStruct_t, MPI_POINTER pMpiVersionStruct; + +typedef union _MPI_VERSION_FORMAT +{ + MPI_VERSION_STRUCT Struct; + U32 Word; +} MPI_VERSION_FORMAT, MPI_POINTER PTR_MPI_VERSION_FORMAT, + MpiVersionFormat_t, MPI_POINTER pMpiVersionFormat_t; + /***************************************************************************** * @@ -577,44 +607,54 @@ typedef struct _MSG_DEFAULT_REPLY /* Common IOCStatus values for all replies */ /****************************************************************************/ -#define MPI_IOCSTATUS_SUCCESS (0x0000) -#define MPI_IOCSTATUS_INVALID_FUNCTION (0x0001) -#define MPI_IOCSTATUS_BUSY (0x0002) -#define MPI_IOCSTATUS_INVALID_SGL (0x0003) -#define MPI_IOCSTATUS_INTERNAL_ERROR (0x0004) -#define MPI_IOCSTATUS_RESERVED (0x0005) -#define MPI_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006) -#define MPI_IOCSTATUS_INVALID_FIELD (0x0007) -#define MPI_IOCSTATUS_INVALID_STATE (0x0008) +#define MPI_IOCSTATUS_SUCCESS (0x0000) +#define MPI_IOCSTATUS_INVALID_FUNCTION (0x0001) +#define MPI_IOCSTATUS_BUSY (0x0002) +#define MPI_IOCSTATUS_INVALID_SGL (0x0003) +#define MPI_IOCSTATUS_INTERNAL_ERROR (0x0004) +#define MPI_IOCSTATUS_RESERVED (0x0005) +#define MPI_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006) +#define MPI_IOCSTATUS_INVALID_FIELD (0x0007) +#define MPI_IOCSTATUS_INVALID_STATE (0x0008) +#define MPI_IOCSTATUS_OP_STATE_NOT_SUPPORTED (0x0009) /****************************************************************************/ /* Config IOCStatus values */ /****************************************************************************/ -#define MPI_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020) -#define MPI_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021) -#define MPI_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022) -#define MPI_IOCSTATUS_CONFIG_INVALID_DATA (0x0023) -#define MPI_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024) -#define MPI_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025) +#define MPI_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020) +#define MPI_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021) +#define MPI_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022) +#define MPI_IOCSTATUS_CONFIG_INVALID_DATA (0x0023) +#define MPI_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024) +#define MPI_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025) /****************************************************************************/ /* SCSIIO Reply (SPI & FCP) initiator values */ /****************************************************************************/ -#define MPI_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040) -#define MPI_IOCSTATUS_SCSI_INVALID_BUS (0x0041) -#define MPI_IOCSTATUS_SCSI_INVALID_TARGETID (0x0042) -#define MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043) -#define MPI_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044) -#define MPI_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045) -#define MPI_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046) -#define MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047) -#define MPI_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048) -#define MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049) -#define MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004A) -#define MPI_IOCSTATUS_SCSI_IOC_TERMINATED (0x004B) -#define MPI_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C) +#define MPI_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040) +#define MPI_IOCSTATUS_SCSI_INVALID_BUS (0x0041) +#define MPI_IOCSTATUS_SCSI_INVALID_TARGETID (0x0042) +#define MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043) +#define MPI_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044) +#define MPI_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045) +#define MPI_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046) +#define MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047) +#define MPI_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048) +#define MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049) +#define MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004A) +#define MPI_IOCSTATUS_SCSI_IOC_TERMINATED (0x004B) +#define MPI_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C) + +/****************************************************************************/ +/* For use by SCSI Initiator and SCSI Target end-to-end data protection */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_EEDP_CRC_ERROR (0x004D) +#define MPI_IOCSTATUS_EEDP_LBA_TAG_ERROR (0x004E) +#define MPI_IOCSTATUS_EEDP_APP_TAG_ERROR (0x004F) + /****************************************************************************/ /* SCSI (SPI & FCP) target values */ @@ -631,7 +671,7 @@ typedef struct _MSG_DEFAULT_REPLY #define MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT (0x006B) /****************************************************************************/ -/* Additional FCP target values */ +/* Additional FCP target values (obsolete) */ /****************************************************************************/ #define MPI_IOCSTATUS_TARGET_FC_ABORTED (0x0066) /* obsolete */ @@ -662,6 +702,25 @@ typedef struct _MSG_DEFAULT_REPLY #define MPI_IOCSTATUS_LAN_PARTIAL_PACKET (0x0086) #define MPI_IOCSTATUS_LAN_CANCELED (0x0087) +/****************************************************************************/ +/* Serial Attached SCSI values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED (0x0090) + +/****************************************************************************/ +/* Inband values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_INBAND_ABORTED (0x0098) +#define MPI_IOCSTATUS_INBAND_NO_CONNECTION (0x0099) + +/****************************************************************************/ +/* Diagnostic Tools values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_DIAGNOSTIC_RELEASED (0x00A0) + /****************************************************************************/ /* IOCStatus flag to indicate that log info is available */ @@ -675,9 +734,12 @@ typedef struct _MSG_DEFAULT_REPLY /****************************************************************************/ #define MPI_IOCLOGINFO_TYPE_MASK (0xF0000000) +#define MPI_IOCLOGINFO_TYPE_SHIFT (28) #define MPI_IOCLOGINFO_TYPE_NONE (0x0) #define MPI_IOCLOGINFO_TYPE_SCSI (0x1) #define MPI_IOCLOGINFO_TYPE_FC (0x2) +#define MPI_IOCLOGINFO_TYPE_SAS (0x3) +#define MPI_IOCLOGINFO_TYPE_ISCSI (0x4) #define MPI_IOCLOGINFO_LOG_DATA_MASK (0x0FFFFFFF) diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/message/fusion/lsi/mpi_cnfg.h linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi_cnfg.h --- linux-2.4.26/drivers/message/fusion/lsi/mpi_cnfg.h 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi_cnfg.h 2004-06-03 01:34:22.000000000 +0000 @@ -2,11 +2,11 @@ * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI_CNFG.H + * Name: mpi_cnfg.h * Title: MPI Config message, structures, and Pages * Creation Date: July 27, 2000 * - * MPI_CNFG.H Version: 01.02.12 + * mpi_cnfg.h Version: 01.05.xx * * Version History * --------------- @@ -176,6 +176,19 @@ typedef union _CONFIG_PAGE_HEADER_UNION } ConfigPageHeaderUnion, MPI_POINTER pConfigPageHeaderUnion, fCONFIG_PAGE_HEADER_UNION, MPI_POINTER PTR_CONFIG_PAGE_HEADER_UNION; +typedef struct _CONFIG_EXTENDED_PAGE_HEADER +{ + U8 PageVersion; /* 00h */ + U8 Reserved1; /* 01h */ + U8 PageNumber; /* 02h */ + U8 PageType; /* 03h */ + U16 ExtPageLength; /* 04h */ + U8 ExtPageType; /* 06h */ + U8 Reserved2; /* 07h */ +} fCONFIG_EXTENDED_PAGE_HEADER, MPI_POINTER PTR_CONFIG_EXTENDED_PAGE_HEADER, + ConfigExtendedPageHeader_t, MPI_POINTER pConfigExtendedPageHeader_t; + + /**************************************************************************** * PageType field values @@ -197,12 +210,23 @@ typedef union _CONFIG_PAGE_HEADER_UNION #define MPI_CONFIG_PAGETYPE_RAID_VOLUME (0x08) #define MPI_CONFIG_PAGETYPE_MANUFACTURING (0x09) #define MPI_CONFIG_PAGETYPE_RAID_PHYSDISK (0x0A) +#define MPI_CONFIG_PAGETYPE_INBAND (0x0B) +#define MPI_CONFIG_PAGETYPE_EXTENDED (0x0F) #define MPI_CONFIG_PAGETYPE_MASK (0x0F) #define MPI_CONFIG_TYPENUM_MASK (0x0FFF) /**************************************************************************** +* ExtPageType field values +****************************************************************************/ +#define MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT (0x10) +#define MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER (0x11) +#define MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE (0x12) +#define MPI_CONFIG_EXTPAGETYPE_SAS_PHY (0x13) + + +/**************************************************************************** * PageAddress field values ****************************************************************************/ #define MPI_SCSI_PORT_PGAD_PORT_MASK (0x000000FF) @@ -236,6 +260,24 @@ typedef union _CONFIG_PAGE_HEADER_UNION #define MPI_PHYSDISK_PGAD_PHYSDISKNUM_MASK (0x000000FF) #define MPI_PHYSDISK_PGAD_PHYSDISKNUM_SHIFT (0) +#define MPI_SAS_DEVICE_PGAD_FORM_MASK (0xF0000000) +#define MPI_SAS_DEVICE_PGAD_FORM_SHIFT (28) +#define MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) +#define MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID (0x00000001) +#define MPI_SAS_DEVICE_PGAD_FORM_HANDLE (0x00000002) +#define MPI_SAS_DEVICE_PGAD_GNH_HANDLE_MASK (0x0000FFFF) +#define MPI_SAS_DEVICE_PGAD_GNH_HANDLE_SHIFT (0) +#define MPI_SAS_DEVICE_PGAD_BT_BUS_MASK (0x0000FF00) +#define MPI_SAS_DEVICE_PGAD_BT_BUS_SHIFT (8) +#define MPI_SAS_DEVICE_PGAD_BT_TID_MASK (0x000000FF) +#define MPI_SAS_DEVICE_PGAD_BT_TID_SHIFT (0) +#define MPI_SAS_DEVICE_PGAD_H_HANDLE_MASK (0x0000FFFF) +#define MPI_SAS_DEVICE_PGAD_H_HANDLE_SHIFT (0) + +#define MPI_SAS_PHY_PGAD_PHY_NUMBER_MASK (0x00FF0000) +#define MPI_SAS_PHY_PGAD_PHY_NUMBER_SHIFT (16) +#define MPI_SAS_PHY_PGAD_DEVHANDLE_MASK (0x0000FFFF) +#define MPI_SAS_PHY_PGAD_DEVHANDLE_SHIFT (0) /**************************************************************************** @@ -247,7 +289,8 @@ typedef struct _MSG_CONFIG U8 Reserved; /* 01h */ U8 ChainOffset; /* 02h */ U8 Function; /* 03h */ - U8 Reserved1[3]; /* 04h */ + U16 ExtPageLength; /* 04h */ + U8 ExtPageType; /* 06h */ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ U8 Reserved2[8]; /* 0Ch */ @@ -277,7 +320,8 @@ typedef struct _MSG_CONFIG_REPLY U8 Reserved; /* 01h */ U8 MsgLength; /* 02h */ U8 Function; /* 03h */ - U8 Reserved1[3]; /* 04h */ + U16 ExtPageLength; /* 04h */ + U8 ExtPageType; /* 06h */ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ U8 Reserved2[2]; /* 0Ch */ @@ -299,29 +343,21 @@ typedef struct _MSG_CONFIG_REPLY * Manufacturing Config pages ****************************************************************************/ #define MPI_MANUFACTPAGE_VENDORID_LSILOGIC (0x1000) -#define MPI_MANUFACTPAGE_VENDORID_TREBIA (0x1783) - +/* Fibre Channel */ #define MPI_MANUFACTPAGE_DEVICEID_FC909 (0x0621) #define MPI_MANUFACTPAGE_DEVICEID_FC919 (0x0624) #define MPI_MANUFACTPAGE_DEVICEID_FC929 (0x0622) #define MPI_MANUFACTPAGE_DEVICEID_FC919X (0x0628) #define MPI_MANUFACTPAGE_DEVICEID_FC929X (0x0626) - +/* SCSI */ #define MPI_MANUFACTPAGE_DEVID_53C1030 (0x0030) #define MPI_MANUFACTPAGE_DEVID_53C1030ZC (0x0031) #define MPI_MANUFACTPAGE_DEVID_1030_53C1035 (0x0032) #define MPI_MANUFACTPAGE_DEVID_1030ZC_53C1035 (0x0033) #define MPI_MANUFACTPAGE_DEVID_53C1035 (0x0040) #define MPI_MANUFACTPAGE_DEVID_53C1035ZC (0x0041) - -#define MPI_MANUFACTPAGE_DEVID_SA2010 (0x0804) -#define MPI_MANUFACTPAGE_DEVID_SA2010ZC (0x0805) -#define MPI_MANUFACTPAGE_DEVID_SA2020 (0x0806) -#define MPI_MANUFACTPAGE_DEVID_SA2020ZC (0x0807) - -#define MPI_MANUFACTPAGE_DEVID_SNP1000 (0x0010) -#define MPI_MANUFACTPAGE_DEVID_SNP500 (0x0020) - +/* SAS */ +#define MPI_MANUFACTPAGE_DEVID_SAS1064 (0x0050) typedef struct _CONFIG_PAGE_MANUFACTURING_0 @@ -405,8 +441,8 @@ typedef struct _CONFIG_PAGE_MANUFACTURIN U8 InfoOffset1; /* 0Ah */ U8 InfoSize1; /* 0Bh */ U8 InquirySize; /* 0Ch */ - U8 Reserved2; /* 0Dh */ - U16 Reserved3; /* 0Eh */ + U8 Flags; /* 0Dh */ + U16 Reserved2; /* 0Eh */ U8 InquiryData[56]; /* 10h */ U32 ISVolumeSettings; /* 48h */ U32 IMEVolumeSettings; /* 4Ch */ @@ -414,7 +450,30 @@ typedef struct _CONFIG_PAGE_MANUFACTURIN } fCONFIG_PAGE_MANUFACTURING_4, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_4, ManufacturingPage4_t, MPI_POINTER pManufacturingPage4_t; -#define MPI_MANUFACTURING4_PAGEVERSION (0x00) +#define MPI_MANUFACTURING4_PAGEVERSION (0x01) + +/* defines for the Flags field */ +#define MPI_MANPAGE4_IR_NO_MIX_SAS_SATA (0x01) + + +typedef struct _CONFIG_PAGE_MANUFACTURING_5 +{ + fCONFIG_PAGE_HEADER Header; /* 00h */ + U64 BaseWWID; /* 04h */ +} fCONFIG_PAGE_MANUFACTURING_5, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_5, + ManufacturingPage5_t, MPI_POINTER pManufacturingPage5_t; + +#define MPI_MANUFACTURING5_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_MANUFACTURING_6 +{ + fCONFIG_PAGE_HEADER Header; /* 00h */ + U32 ProductSpecificInfo;/* 04h */ +} fCONFIG_PAGE_MANUFACTURING_6, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_6, + ManufacturingPage6_t, MPI_POINTER pManufacturingPage6_t; + +#define MPI_MANUFACTURING6_PAGEVERSION (0x00) /**************************************************************************** @@ -438,17 +497,18 @@ typedef struct _CONFIG_PAGE_IO_UNIT_1 } fCONFIG_PAGE_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_1, IOUnitPage1_t, MPI_POINTER pIOUnitPage1_t; -#define MPI_IOUNITPAGE1_PAGEVERSION (0x00) +#define MPI_IOUNITPAGE1_PAGEVERSION (0x01) /* IO Unit Page 1 Flags defines */ - #define MPI_IOUNITPAGE1_MULTI_FUNCTION (0x00000000) #define MPI_IOUNITPAGE1_SINGLE_FUNCTION (0x00000001) #define MPI_IOUNITPAGE1_MULTI_PATHING (0x00000002) #define MPI_IOUNITPAGE1_SINGLE_PATHING (0x00000000) #define MPI_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID (0x00000004) +#define MPI_IOUNITPAGE1_DISABLE_QUEUE_FULL_HANDLING (0x00000020) #define MPI_IOUNITPAGE1_DISABLE_IR (0x00000040) #define MPI_IOUNITPAGE1_FORCE_32 (0x00000080) +#define MPI_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE (0x00000100) typedef struct _MPI_ADAPTER_INFO @@ -478,6 +538,11 @@ typedef struct _CONFIG_PAGE_IO_UNIT_2 #define MPI_IOUNITPAGE2_FLAGS_COLOR_VIDEO_DISABLE (0x00000008) #define MPI_IOUNITPAGE2_FLAGS_DONT_HOOK_INT_40 (0x00000010) +#define MPI_IOUNITPAGE2_FLAGS_DEV_LIST_DISPLAY_MASK (0x000000E0) +#define MPI_IOUNITPAGE2_FLAGS_INSTALLED_DEV_DISPLAY (0x00000000) +#define MPI_IOUNITPAGE2_FLAGS_ADAPTER_DISPLAY (0x00000020) +#define MPI_IOUNITPAGE2_FLAGS_ADAPTER_DEV_DISPLAY (0x00000040) + /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to @@ -540,6 +605,12 @@ typedef struct _CONFIG_PAGE_IOC_1 #define MPI_IOCPAGE1_PAGEVERSION (0x01) +/* defines for the Flags field */ +#define MPI_IOCPAGE1_EEDP_HOST_SUPPORTS_DIF (0x08000000) +#define MPI_IOCPAGE1_EEDP_MODE_MASK (0x07000000) +#define MPI_IOCPAGE1_EEDP_MODE_OFF (0x00000000) +#define MPI_IOCPAGE1_EEDP_MODE_T10 (0x01000000) +#define MPI_IOCPAGE1_EEDP_MODE_LSI_1 (0x02000000) #define MPI_IOCPAGE1_REPLY_COALESCING (0x00000001) #define MPI_IOCPAGE1_PCISLOTNUM_UNKNOWN (0xFF) @@ -680,7 +751,7 @@ typedef struct _IOC_5_HOT_SPARE typedef struct _CONFIG_PAGE_IOC_5 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U32 Reserved1; /* 04h */ U8 NumHotSpares; /* 08h */ U8 Reserved2; /* 09h */ @@ -692,6 +763,57 @@ typedef struct _CONFIG_PAGE_IOC_5 #define MPI_IOCPAGE5_PAGEVERSION (0x00) +/**************************************************************************** +* BIOS Port Config Pages +****************************************************************************/ + +typedef struct _CONFIG_PAGE_BIOS_1 +{ + fCONFIG_PAGE_HEADER Header; /* 00h */ + U32 BiosOptions; /* 04h */ + U32 IOCSettings; /* 08h */ + U32 Reserved1; /* 0Ch */ + U32 DeviceSettings; /* 10h */ + U16 NumberOfDevices; /* 14h */ + U16 Reserved2; /* 16h */ + U16 IOTimeoutBlockDevicesNonRM; /* 18h */ + U16 IOTimeoutSequential; /* 1Ah */ + U16 IOTimeoutOther; /* 1Ch */ + U16 IOTimeoutBlockDevicesRM; /* 1Eh */ +} fCONFIG_PAGE_BIOS_1, MPI_POINTER PTR_CONFIG_PAGE_BIOS_1, + BIOSPage1_t, MPI_POINTER pBIOSPage1_t; + +#define MPI_BIOSPAGE1_PAGEVERSION (0x00) + +/* values for the BiosOptions field */ +#define MPI_BIOSPAGE1_OPTIONS_SPI_ENABLE (0x00000400) +#define MPI_BIOSPAGE1_OPTIONS_FC_ENABLE (0x00000200) +#define MPI_BIOSPAGE1_OPTIONS_SAS_ENABLE (0x00000100) +#define MPI_BIOSPAGE1_OPTIONS_DISABLE_BIOS (0x00000001) + +/* values for the IOCSettings field */ +#define MPI_BIOSPAGE1_IOCSET_MASK_SPINUP_DELAY (0x00000F00) +#define MPI_BIOSPAGE1_IOCSET_SHIFT_SPINUP_DELAY (8) + +#define MPI_BIOSPAGE1_IOCSET_MASK_RM_SETTING (0x000000C0) +#define MPI_BIOSPAGE1_IOCSET_NONE_RM_SETTING (0x00000000) +#define MPI_BIOSPAGE1_IOCSET_BOOT_RM_SETTING (0x00000040) +#define MPI_BIOSPAGE1_IOCSET_MEDIA_RM_SETTING (0x00000080) + +#define MPI_BIOSPAGE1_IOCSET_MASK_ADAPTER_SUPPORT (0x00000030) +#define MPI_BIOSPAGE1_IOCSET_NO_SUPPORT (0x00000000) +#define MPI_BIOSPAGE1_IOCSET_BIOS_SUPPORT (0x00000010) +#define MPI_BIOSPAGE1_IOCSET_OS_SUPPORT (0x00000020) +#define MPI_BIOSPAGE1_IOCSET_ALL_SUPPORT (0x00000030) + +#define MPI_BIOSPAGE1_IOCSET_ALTERNATE_CHS (0x00000008) + +/* values for the DeviceSettings field */ +#define MPI_BIOSPAGE1_DEVSET_DISABLE_SEQ_LUN (0x00000008) +#define MPI_BIOSPAGE1_DEVSET_DISABLE_RM_LUN (0x00000004) +#define MPI_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN (0x00000002) +#define MPI_BIOSPAGE1_DEVSET_DISABLE_OTHER_LUN (0x00000001) + /**************************************************************************** * SCSI Port Config Pages @@ -711,7 +833,27 @@ typedef struct _CONFIG_PAGE_SCSI_PORT_0 #define MPI_SCSIPORTPAGE0_CAP_DT (0x00000002) #define MPI_SCSIPORTPAGE0_CAP_QAS (0x00000004) #define MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK (0x0000FF00) +#define MPI_SCSIPORTPAGE0_SYNC_ASYNC (0x00) +#define MPI_SCSIPORTPAGE0_SYNC_5 (0x32) +#define MPI_SCSIPORTPAGE0_SYNC_10 (0x19) +#define MPI_SCSIPORTPAGE0_SYNC_20 (0x0C) +#define MPI_SCSIPORTPAGE0_SYNC_33_33 (0x0B) +#define MPI_SCSIPORTPAGE0_SYNC_40 (0x0A) +#define MPI_SCSIPORTPAGE0_SYNC_80 (0x09) +#define MPI_SCSIPORTPAGE0_SYNC_160 (0x08) +#define MPI_SCSIPORTPAGE0_SYNC_UNKNOWN (0xFF) + +#define MPI_SCSIPORTPAGE0_CAP_SHIFT_MIN_SYNC_PERIOD (8) +#define MPI_SCSIPORTPAGE0_CAP_GET_MIN_SYNC_PERIOD(Cap) \ + ( ((Cap) & MPI_SCSIPORTPAGE0_CAP_MASK_MIN_SYNC_PERIOD) \ + >> MPI_SCSIPORTPAGE0_CAP_SHIFT_MIN_SYNC_PERIOD \ + ) #define MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK (0x00FF0000) +#define MPI_SCSIPORTPAGE0_CAP_SHIFT_MAX_SYNC_OFFSET (16) +#define MPI_SCSIPORTPAGE0_CAP_GET_MAX_SYNC_OFFSET(Cap) \ + ( ((Cap) & MPI_SCSIPORTPAGE0_CAP_MASK_MAX_SYNC_OFFSET) \ + >> MPI_SCSIPORTPAGE0_CAP_SHIFT_MAX_SYNC_OFFSET \ + ) #define MPI_SCSIPORTPAGE0_CAP_WIDE (0x20000000) #define MPI_SCSIPORTPAGE0_CAP_AIP (0x80000000) @@ -736,11 +878,12 @@ typedef struct _CONFIG_PAGE_SCSI_PORT_1 } fCONFIG_PAGE_SCSI_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_1, SCSIPortPage1_t, MPI_POINTER pSCSIPortPage1_t; -#define MPI_SCSIPORTPAGE1_PAGEVERSION (0x02) +#define MPI_SCSIPORTPAGE1_PAGEVERSION (0x03) /* Configuration values */ #define MPI_SCSIPORTPAGE1_CFG_PORT_SCSI_ID_MASK (0x000000FF) #define MPI_SCSIPORTPAGE1_CFG_PORT_RESPONSE_ID_MASK (0xFFFF0000) +#define MPI_SCSIPORTPAGE1_CFG_SHIFT_PORT_RESPONSE_ID (16) /* TargetConfig values */ #define MPI_SCSIPORTPAGE1_TARGCONFIG_TARG_ONLY (0x01) @@ -777,6 +920,7 @@ typedef struct _CONFIG_PAGE_SCSI_PORT_2 #define MPI_SCSIPORTPAGE2_PORT_FLAGS_BASIC_DV_ONLY (0x00000020) #define MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV (0x00000060) + /* PortSettings values */ #define MPI_SCSIPORTPAGE2_PORT_HOST_ID_MASK (0x0000000F) #define MPI_SCSIPORTPAGE2_PORT_MASK_INIT_HBA (0x00000030) @@ -785,7 +929,11 @@ typedef struct _CONFIG_PAGE_SCSI_PORT_2 #define MPI_SCSIPORTPAGE2_PORT_OS_INIT_HBA (0x00000020) #define MPI_SCSIPORTPAGE2_PORT_BIOS_OS_INIT_HBA (0x00000030) #define MPI_SCSIPORTPAGE2_PORT_REMOVABLE_MEDIA (0x000000C0) +#define MPI_SCSIPORTPAGE2_PORT_RM_NONE (0x00000000) +#define MPI_SCSIPORTPAGE2_PORT_RM_BOOT_ONLY (0x00000040) +#define MPI_SCSIPORTPAGE2_PORT_RM_WITH_MEDIA (0x00000080) #define MPI_SCSIPORTPAGE2_PORT_SPINUP_DELAY_MASK (0x00000F00) +#define MPI_SCSIPORTPAGE2_PORT_SHIFT_SPINUP_DELAY (8) #define MPI_SCSIPORTPAGE2_PORT_MASK_NEGO_MASTER_SETTINGS (0x00003000) #define MPI_SCSIPORTPAGE2_PORT_NEGO_MASTER_SETTINGS (0x00000000) #define MPI_SCSIPORTPAGE2_PORT_NONE_MASTER_SETTINGS (0x00001000) @@ -822,7 +970,9 @@ typedef struct _CONFIG_PAGE_SCSI_DEVICE_ #define MPI_SCSIDEVPAGE0_NP_RTI (0x00000040) #define MPI_SCSIDEVPAGE0_NP_PCOMP_EN (0x00000080) #define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK (0x0000FF00) +#define MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_PERIOD (8) #define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK (0x00FF0000) +#define MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_OFFSET (16) #define MPI_SCSIDEVPAGE0_NP_WIDE (0x20000000) #define MPI_SCSIDEVPAGE0_NP_AIP (0x80000000) @@ -852,7 +1002,9 @@ typedef struct _CONFIG_PAGE_SCSI_DEVICE_ #define MPI_SCSIDEVPAGE1_RP_RTI (0x00000040) #define MPI_SCSIDEVPAGE1_RP_PCOMP_EN (0x00000080) #define MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK (0x0000FF00) +#define MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD (8) #define MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK (0x00FF0000) +#define MPI_SCSIDEVPAGE1_RP_SHIFT_MAX_SYNC_OFFSET (16) #define MPI_SCSIDEVPAGE1_RP_WIDE (0x20000000) #define MPI_SCSIDEVPAGE1_RP_AIP (0x80000000) @@ -998,13 +1150,19 @@ typedef struct _CONFIG_PAGE_FC_PORT_0 #define MPI_FCPORTPAGE0_SUPPORT_CLASS_2 (0x00000002) #define MPI_FCPORTPAGE0_SUPPORT_CLASS_3 (0x00000004) -#define MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED (0x00000001) /* (SNIA)HBA_PORTSPEED_1GBIT 1 1 GBit/sec */ -#define MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED (0x00000002) /* (SNIA)HBA_PORTSPEED_2GBIT 2 2 GBit/sec */ -#define MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED (0x00000004) /* (SNIA)HBA_PORTSPEED_10GBIT 4 10 GBit/sec */ +#define MPI_FCPORTPAGE0_SUPPORT_SPEED_UKNOWN (0x00000000) /* (SNIA)HBA_PORTSPEED_UNKNOWN 0 Unknown - transceiver incapable of reporting */ +#define MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED (0x00000001) /* (SNIA)HBA_PORTSPEED_1GBIT 1 1 GBit/sec */ +#define MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED (0x00000002) /* (SNIA)HBA_PORTSPEED_2GBIT 2 2 GBit/sec */ +#define MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED (0x00000004) /* (SNIA)HBA_PORTSPEED_10GBIT 4 10 GBit/sec */ +#define MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED (0x00000008) /* (SNIA)HBA_PORTSPEED_4GBIT 8 4 GBit/sec */ +#define MPI_FCPORTPAGE0_CURRENT_SPEED_UKNOWN MPI_FCPORTPAGE0_SUPPORT_SPEED_UKNOWN #define MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED #define MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED #define MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED +#define MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED +#define MPI_FCPORTPAGE0_CURRENT_SPEED_NOT_NEGOTIATED (0x00008000) /* (SNIA)HBA_PORTSPEED_NOT_NEGOTIATED (1<<15) Speed not established */ + typedef struct _CONFIG_PAGE_FC_PORT_1 @@ -1019,11 +1177,12 @@ typedef struct _CONFIG_PAGE_FC_PORT_1 U8 AltConnector; /* 1Bh */ U8 NumRequestedAliases; /* 1Ch */ U8 RR_TOV; /* 1Dh */ - U16 Reserved2; /* 1Eh */ + U8 InitiatorDeviceTimeout; /* 1Eh */ + U8 InitiatorIoPendTimeout; /* 1Fh */ } fCONFIG_PAGE_FC_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_1, FCPortPage1_t, MPI_POINTER pFCPortPage1_t; -#define MPI_FCPORTPAGE1_PAGEVERSION (0x05) +#define MPI_FCPORTPAGE1_PAGEVERSION (0x06) #define MPI_FCPORTPAGE1_FLAGS_EXT_FCP_STATUS_EN (0x08000000) #define MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY (0x04000000) @@ -1031,6 +1190,7 @@ typedef struct _CONFIG_PAGE_FC_PORT_1 #define MPI_FCPORTPAGE1_FLAGS_VERBOSE_RESCAN_EVENTS (0x01000000) #define MPI_FCPORTPAGE1_FLAGS_TARGET_MODE_OXID (0x00800000) #define MPI_FCPORTPAGE1_FLAGS_PORT_OFFLINE (0x00400000) +#define MPI_FCPORTPAGE1_FLAGS_SOFT_ALPA_FALLBACK (0x00200000) #define MPI_FCPORTPAGE1_FLAGS_MASK_RR_TOV_UNITS (0x00000070) #define MPI_FCPORTPAGE1_FLAGS_SUPPRESS_PROT_REG (0x00000008) #define MPI_FCPORTPAGE1_FLAGS_PLOGI_ON_LOGO (0x00000004) @@ -1066,6 +1226,8 @@ typedef struct _CONFIG_PAGE_FC_PORT_1 #define MPI_FCPORTPAGE1_ALT_CONN_UNKNOWN (0x00) +#define MPI_FCPORTPAGE1_INITIATOR_DEV_TIMEOUT_MASK (0x7F) + typedef struct _CONFIG_PAGE_FC_PORT_2 { @@ -1627,5 +1789,317 @@ typedef struct _CONFIG_PAGE_LAN_1 #define MPI_LAN_PAGE1_DEV_STATE_RESET (0x00) #define MPI_LAN_PAGE1_DEV_STATE_OPERATIONAL (0x01) + +/**************************************************************************** +* Inband Config Pages +****************************************************************************/ + +typedef struct _CONFIG_PAGE_INBAND_0 +{ + fCONFIG_PAGE_HEADER Header; /* 00h */ + MPI_VERSION_FORMAT InbandVersion; /* 04h */ + U16 MaximumBuffers; /* 08h */ + U16 Reserved1; /* 0Ah */ +} fCONFIG_PAGE_INBAND_0, MPI_POINTER PTR_CONFIG_PAGE_INBAND_0, + InbandPage0_t, MPI_POINTER pInbandPage0_t; + +#define MPI_INBAND_PAGEVERSION (0x00) + + + +/**************************************************************************** +* SAS IO Unit Config Pages +****************************************************************************/ + +typedef struct _MPI_SAS_IO_UNIT0_PHY_DATA +{ + U8 Port; /* 00h */ + U8 PortFlags; /* 01h */ + U8 PhyFlags; /* 02h */ + U8 NegotiatedLinkRate; /* 03h */ + U32 ControllerPhyDeviceInfo;/* 04h */ + U16 AttachedDeviceHandle; /* 08h */ + U16 ControllerDevHandle; /* 0Ah */ + U32 Reserved2; /* 0Ch */ +} MPI_SAS_IO_UNIT0_PHY_DATA, MPI_POINTER PTR_MPI_SAS_IO_UNIT0_PHY_DATA, + SasIOUnit0PhyData, MPI_POINTER pSasIOUnit0PhyData; + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI_SAS_IOUNIT0_PHY_MAX +#define MPI_SAS_IOUNIT0_PHY_MAX (1) +#endif + +typedef struct _CONFIG_PAGE_SAS_IO_UNIT_0 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U8 NumPhys; /* 0Ch */ + U8 Reserved2; /* 0Dh */ + U16 Reserved3; /* 0Eh */ + MPI_SAS_IO_UNIT0_PHY_DATA PhyData[MPI_SAS_IOUNIT0_PHY_MAX]; /* 10h */ +} fCONFIG_PAGE_SAS_IO_UNIT_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_0, + SasIOUnitPage0_t, MPI_POINTER pSasIOUnitPage0_t; + +#define MPI_SASIOUNITPAGE0_PAGEVERSION (0x00) + +/* values for SAS IO Unit Page 0 PortFlags */ +#define MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS (0x08) +#define MPI_SAS_IOUNIT0_PORT_FLAGS_0_TARGET_IOC_NUM (0x00) +#define MPI_SAS_IOUNIT0_PORT_FLAGS_1_TARGET_IOC_NUM (0x04) +#define MPI_SAS_IOUNIT0_PORT_FLAGS_WAIT_FOR_PORTENABLE (0x02) +#define MPI_SAS_IOUNIT0_PORT_FLAGS_AUTO_PORT_CONFIG (0x01) + +/* values for SAS IO Unit Page 0 PhyFlags */ +#define MPI_SAS_IOUNIT0_PHY_FLAGS_PHY_DISABLED (0x04) +#define MPI_SAS_IOUNIT0_PHY_FLAGS_TX_INVERT (0x02) +#define MPI_SAS_IOUNIT0_PHY_FLAGS_RX_INVERT (0x01) + +/* values for SAS IO Unit Page 0 NegotiatedLinkRate */ +#define MPI_SAS_IOUNIT0_RATE_UNKNOWN (0x00) +#define MPI_SAS_IOUNIT0_RATE_PHY_DISABLED (0x01) +#define MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION (0x02) +#define MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE (0x03) +#define MPI_SAS_IOUNIT0_RATE_1_5 (0x08) +#define MPI_SAS_IOUNIT0_RATE_3_0 (0x09) + +/* see mpi_sas.h for values for SAS IO Unit Page 0 ControllerPhyDeviceInfo values */ + + +typedef struct _MPI_SAS_IO_UNIT1_PHY_DATA +{ + U8 Port; /* 00h */ + U8 PortFlags; /* 01h */ + U8 PhyFlags; /* 02h */ + U8 MaxMinLinkRate; /* 03h */ + U32 ControllerPhyDeviceInfo;/* 04h */ + U32 Reserved1; /* 08h */ +} MPI_SAS_IO_UNIT1_PHY_DATA, MPI_POINTER PTR_MPI_SAS_IO_UNIT1_PHY_DATA, + SasIOUnit1PhyData, MPI_POINTER pSasIOUnit1PhyData; + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI_SAS_IOUNIT1_PHY_MAX +#define MPI_SAS_IOUNIT1_PHY_MAX (1) +#endif + +typedef struct _CONFIG_PAGE_SAS_IO_UNIT_1 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U8 NumPhys; /* 0Ch */ + U8 Reserved2; /* 0Dh */ + U16 Reserved3; /* 0Eh */ + MPI_SAS_IO_UNIT1_PHY_DATA PhyData[MPI_SAS_IOUNIT1_PHY_MAX]; /* 10h */ +} fCONFIG_PAGE_SAS_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_1, + SasIOUnitPage1_t, MPI_POINTER pSasIOUnitPage1_t; + +#define MPI_SASIOUNITPAGE1_PAGEVERSION (0x00) + +/* values for SAS IO Unit Page 0 PortFlags */ +#define MPI_SAS_IOUNIT1_PORT_FLAGS_0_TARGET_IOC_NUM (0x00) +#define MPI_SAS_IOUNIT1_PORT_FLAGS_1_TARGET_IOC_NUM (0x04) +#define MPI_SAS_IOUNIT1_PORT_FLAGS_WAIT_FOR_PORTENABLE (0x02) +#define MPI_SAS_IOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG (0x01) + +/* values for SAS IO Unit Page 0 PhyFlags */ +#define MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE (0x04) +#define MPI_SAS_IOUNIT1_PHY_FLAGS_TX_INVERT (0x02) +#define MPI_SAS_IOUNIT1_PHY_FLAGS_RX_INVERT (0x01) + +/* values for SAS IO Unit Page 0 MaxMinLinkRate */ +#define MPI_SAS_IOUNIT1_MAX_RATE_MASK (0xF0) +#define MPI_SAS_IOUNIT1_MAX_RATE_1_5 (0x80) +#define MPI_SAS_IOUNIT1_MAX_RATE_3_0 (0x90) +#define MPI_SAS_IOUNIT1_MIN_RATE_MASK (0x0F) +#define MPI_SAS_IOUNIT1_MIN_RATE_1_5 (0x08) +#define MPI_SAS_IOUNIT1_MIN_RATE_3_0 (0x09) + +/* see mpi_sas.h for values for SAS IO Unit Page 1 ControllerPhyDeviceInfo values */ + + +typedef struct _CONFIG_PAGE_SAS_IO_UNIT_2 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U16 MaxPersistentIDs; /* 0Ch */ + U16 NumPersistentIDsUsed; /* 0Eh */ + U8 Status; /* 10h */ + U8 Flags; /* 11h */ + U16 Reserved2; /* 12h */ +} fCONFIG_PAGE_SAS_IO_UNIT_2, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_2, + SasIOUnitPage2_t, MPI_POINTER pSasIOUnitPage2_t; + +#define MPI_SASIOUNITPAGE2_PAGEVERSION (0x00) + +/* values for SAS IO Unit Page 2 Status field */ +#define MPI_SAS_IOUNIT2_STATUS_DISABLED_PERSISTENT_MAPPINGS (0x02) +#define MPI_SAS_IOUNIT2_STATUS_FULL_PERSISTENT_MAPPINGS (0x01) + +/* values for SAS IO Unit Page 2 Flags field */ +#define MPI_SAS_IOUNIT2_FLAGS_DISABLE_PERSISTENT_MAPPINGS (0x01) + + +typedef struct _CONFIG_PAGE_SAS_IO_UNIT_3 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U32 MaxInvalidDwordCount; /* 0Ch */ + U32 InvalidDwordCountTime; /* 10h */ + U32 MaxRunningDisparityErrorCount; /* 14h */ + U32 RunningDisparityErrorTime; /* 18h */ + U32 MaxLossDwordSynchCount; /* 1Ch */ + U32 LossDwordSynchCountTime; /* 20h */ + U32 MaxPhyResetProblemCount; /* 24h */ + U32 PhyResetProblemTime; /* 28h */ +} fCONFIG_PAGE_SAS_IO_UNIT_3, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_3, + SasIOUnitPage3_t, MPI_POINTER pSasIOUnitPage3_t; + +#define MPI_SASIOUNITPAGE3_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_SAS_EXPANDER_0 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U64 SASAddress; /* 0Ch */ + U32 Reserved2; /* 14h */ + U16 DevHandle; /* 18h */ + U16 ParentDevHandle; /* 1Ah */ + U16 ExpanderChangeCount; /* 1Ch */ + U16 ExpanderRouteIndexes; /* 1Eh */ + U8 NumPhys; /* 20h */ + U8 SASLevel; /* 21h */ + U8 Flags; /* 22h */ + U8 Reserved3; /* 23h */ +} fCONFIG_PAGE_SAS_EXPANDER_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_EXPANDER_0, + SasExpanderPage0_t, MPI_POINTER pSasExpanderPage0_t; + +#define MPI_SASEXPANDER0_PAGEVERSION (0x00) + +/* values for SAS Expander Page 0 Flags field */ +#define MPI_SAS_EXPANDER0_FLAGS_ROUTE_TABLE_CONFIG (0x02) +#define MPI_SAS_EXPANDER0_FLAGS_CONFIG_IN_PROGRESS (0x01) + + +typedef struct _CONFIG_PAGE_SAS_DEVICE_0 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U64 SASAddress; /* 0Ch */ + U32 Reserved2; /* 14h */ + U16 DevHandle; /* 18h */ + U8 TargetID; /* 1Ah */ + U8 Bus; /* 1Bh */ + U32 DeviceInfo; /* 1Ch */ + U16 Flags; /* 20h */ + U8 PhysicalPort; /* 22h */ + U8 Reserved3; /* 23h */ +} fCONFIG_PAGE_SAS_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_DEVICE_0, + SasDevicePage0_t, MPI_POINTER pSasDevicePage0_t; + +#define MPI_SASDEVICE0_PAGEVERSION (0x00) + +/* values for SAS Device Page 0 Flags field */ +#define MPI_SAS_DEVICE0_FLAGS_MAPPING_PERSISTENT (0x04) +#define MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED (0x02) +#define MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x01) + +/* see mpi_sas.h for values for SAS Device Page 0 DeviceInfo values */ + + +typedef struct _CONFIG_PAGE_SAS_DEVICE_1 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U64 SASAddress; /* 0Ch */ + U32 Reserved2; /* 14h */ + U16 DevHandle; /* 18h */ + U8 TargetID; /* 1Ah */ + U8 Bus; /* 1Bh */ + U8 InitialRegDeviceFIS[20];/* 1Ch */ +} fCONFIG_PAGE_SAS_DEVICE_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_DEVICE_1, + SasDevicePage1_t, MPI_POINTER pSasDevicePage1_t; + +#define MPI_SASDEVICE1_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_SAS_PHY_0 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U64 SASAddress; /* 0Ch */ + U16 AttachedDevHandle; /* 14h */ + U8 AttachedPhyIdentifier; /* 16h */ + U8 Reserved2; /* 17h */ + U32 AttachedDeviceInfo; /* 18h */ + U8 ProgrammedLinkRate; /* 20h */ + U8 HwLinkRate; /* 21h */ + U8 ChangeCount; /* 22h */ + U8 Reserved3; /* 23h */ + U32 PhyInfo; /* 24h */ +} fCONFIG_PAGE_SAS_PHY_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_PHY_0, + SasPhyPage0_t, MPI_POINTER pSasPhyPage0_t; + +#define MPI_SASPHY0_PAGEVERSION (0x00) + +/* values for SAS PHY Page 0 ProgrammedLinkRate field */ +#define MPI_SAS_PHY0_PRATE_MAX_RATE_MASK (0xF0) +#define MPI_SAS_PHY0_PRATE_MAX_RATE_NOT_PROGRAMMABLE (0x00) +#define MPI_SAS_PHY0_PRATE_MAX_RATE_1_5 (0x80) +#define MPI_SAS_PHY0_PRATE_MAX_RATE_3_0 (0x90) +#define MPI_SAS_PHY0_PRATE_MIN_RATE_MASK (0x0F) +#define MPI_SAS_PHY0_PRATE_MIN_RATE_NOT_PROGRAMMABLE (0x00) +#define MPI_SAS_PHY0_PRATE_MIN_RATE_1_5 (0x08) +#define MPI_SAS_PHY0_PRATE_MIN_RATE_3_0 (0x09) + +/* values for SAS PHY Page 0 HwLinkRate field */ +#define MPI_SAS_PHY0_HWRATE_MAX_RATE_MASK (0xF0) +#define MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5 (0x80) +#define MPI_SAS_PHY0_HWRATE_MAX_RATE_3_0 (0x90) +#define MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK (0x0F) +#define MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5 (0x08) +#define MPI_SAS_PHY0_HWRATE_MIN_RATE_3_0 (0x09) + +/* values for SAS PHY Page 0 PhyInfo field */ +#define MPI_SAS_PHY0_PHYINFO_SATA_PORT_ACTIVE (0x00004000) +#define MPI_SAS_PHY0_PHYINFO_SATA_PORT_SELECTOR (0x00002000) +#define MPI_SAS_PHY0_PHYINFO_VIRTUAL_PHY (0x00001000) + +#define MPI_SAS_PHY0_PHYINFO_MASK_PARTIAL_PATHWAY_TIME (0x00000F00) +#define MPI_SAS_PHY0_PHYINFO_SHIFT_PARTIAL_PATHWAY_TIME (8) + +#define MPI_SAS_PHY0_PHYINFO_MASK_ROUTING_ATTRIBUTE (0x000000F0) +#define MPI_SAS_PHY0_PHYINFO_DIRECT_ROUTING (0x00000000) +#define MPI_SAS_PHY0_PHYINFO_SUBTRACTIVE_ROUTING (0x00000010) +#define MPI_SAS_PHY0_PHYINFO_TABLE_ROUTING (0x00000020) + +#define MPI_SAS_PHY0_PHYINFO_MASK_LINK_RATE (0x0000000F) +#define MPI_SAS_PHY0_PHYINFO_UNKNOWN_LINK_RATE (0x00000000) +#define MPI_SAS_PHY0_PHYINFO_PHY_DISABLED (0x00000001) +#define MPI_SAS_PHY0_PHYINFO_NEGOTIATION_FAILED (0x00000002) +#define MPI_SAS_PHY0_PHYINFO_SATA_OOB_COMPLETE (0x00000003) +#define MPI_SAS_PHY0_PHYINFO_RATE_1_5 (0x00000008) +#define MPI_SAS_PHY0_PHYINFO_RATE_3_0 (0x00000009) + + +typedef struct _CONFIG_PAGE_SAS_PHY_1 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U32 InvalidDwordCount; /* 0Ch */ + U32 RunningDisparityErrorCount; /* 10h */ + U32 LossDwordSynchCount; /* 14h */ + U32 PhyResetProblemCount; /* 18h */ +} fCONFIG_PAGE_SAS_PHY_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_PHY_1, + SasPhyPage1_t, MPI_POINTER pSasPhyPage1_t; + +#define MPI_SASPHY1_PAGEVERSION (0x00) + + #endif diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/message/fusion/lsi/mpi_fc.h linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi_fc.h --- linux-2.4.26/drivers/message/fusion/lsi/mpi_fc.h 2003-06-13 14:51:34.000000000 +0000 +++ linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi_fc.h 2004-06-03 01:32:50.000000000 +0000 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2002 LSI Logic Corporation. + * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI_FC.H + * Name: mpi_fc.h * Title: MPI Fibre Channel messages and structures * Creation Date: June 12, 2000 * - * MPI_FC.H Version: 01.02.03 + * mpi_fc.h Version: 01.05.xx * * Version History * --------------- @@ -45,7 +45,7 @@ /***************************************************************************** * -* F C T a r g e t M o d e M e s s a g e s +* F C D i r e c t A c c e s s M e s s a g e s * *****************************************************************************/ @@ -334,6 +334,7 @@ typedef struct _MSG_FC_PRIMITIVE_SEND_RE FcPrimitiveSendRequest_t, MPI_POINTER pFcPrimitiveSendRequest_t; #define MPI_FC_PRIM_SEND_FLAGS_PORT_MASK (0x01) +#define MPI_FC_PRIM_SEND_FLAGS_ML_RESET_LINK (0x02) #define MPI_FC_PRIM_SEND_FLAGS_RESET_LINK (0x04) #define MPI_FC_PRIM_SEND_FLAGS_STOP_SEND (0x08) #define MPI_FC_PRIM_SEND_FLAGS_SEND_ONCE (0x10) diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/message/fusion/lsi/mpi_inb.h linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi_inb.h --- linux-2.4.26/drivers/message/fusion/lsi/mpi_inb.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi_inb.h 2004-06-03 01:32:26.000000000 +0000 @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2003 LSI Logic Corporation. + * + * + * Name: mpi_inb.h + * Title: MPI Inband structures and definitions + * Creation Date: September 30, 2003 + * + * mpi_inb.h Version: 01.03.xx + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * ??-??-?? 01.03.01 Original release. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_INB_H +#define MPI_INB_H + +/****************************************************************************** +* +* I n b a n d M e s s a g e s +* +*******************************************************************************/ + + +/****************************************************************************/ +/* Inband Buffer Post Request */ +/****************************************************************************/ + +typedef struct _MSG_INBAND_BUFFER_POST_REQUEST +{ + U8 Reserved1; /* 00h */ + U8 BufferCount; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Reserved4; /* 0Ch */ + SGE_TRANS_SIMPLE_UNION SGL; /* 10h */ +} MSG_INBAND_BUFFER_POST_REQUEST, MPI_POINTER PTR_MSG_INBAND_BUFFER_POST_REQUEST, + MpiInbandBufferPostRequest_t , MPI_POINTER pMpiInbandBufferPostRequest_t; + + +typedef struct _WWN_FC_FORMAT +{ + U64 NodeName; /* 00h */ + U64 PortName; /* 08h */ +} WWN_FC_FORMAT, MPI_POINTER PTR_WWN_FC_FORMAT, + WwnFcFormat_t, MPI_POINTER pWwnFcFormat_t; + +typedef struct _WWN_SAS_FORMAT +{ + U64 WorldWideID; /* 00h */ + U32 Reserved1; /* 08h */ + U32 Reserved2; /* 0Ch */ +} WWN_SAS_FORMAT, MPI_POINTER PTR_WWN_SAS_FORMAT, + WwnSasFormat_t, MPI_POINTER pWwnSasFormat_t; + +typedef union _WWN_INBAND_FORMAT +{ + WWN_FC_FORMAT Fc; + WWN_SAS_FORMAT Sas; +} WWN_INBAND_FORMAT, MPI_POINTER PTR_WWN_INBAND_FORMAT, + WwnInbandFormat, MPI_POINTER pWwnInbandFormat; + + +/* Inband Buffer Post reply message */ + +typedef struct _MSG_INBAND_BUFFER_POST_REPLY +{ + U16 Reserved1; /* 00h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved4; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 TransferLength; /* 14h */ + U32 TransactionContext; /* 18h */ + WWN_INBAND_FORMAT Wwn; /* 1Ch */ + U32 IOCIdentifier[4]; /* 2Ch */ +} MSG_INBAND_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_INBAND_BUFFER_POST_REPLY, + MpiInbandBufferPostReply_t, MPI_POINTER pMpiInbandBufferPostReply_t; + + +/****************************************************************************/ +/* Inband Send Request */ +/****************************************************************************/ + +typedef struct _MSG_INBAND_SEND_REQUEST +{ + U16 Reserved1; /* 00h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Reserved4; /* 0Ch */ + WWN_INBAND_FORMAT Wwn; /* 10h */ + U32 Reserved5; /* 20h */ + SGE_IO_UNION SGL; /* 24h */ +} MSG_INBAND_SEND_REQUEST, MPI_POINTER PTR_MSG_INBAND_SEND_REQUEST, + MpiInbandSendRequest_t , MPI_POINTER pMpiInbandSendRequest_t; + + +/* Inband Send reply message */ + +typedef struct _MSG_INBAND_SEND_REPLY +{ + U16 Reserved1; /* 00h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved4; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 ResponseLength; /* 14h */ +} MSG_INBAND_SEND_REPLY, MPI_POINTER PTR_MSG_INBAND_SEND_REPLY, + MpiInbandSendReply_t, MPI_POINTER pMpiInbandSendReply_t; + + +/****************************************************************************/ +/* Inband Response Request */ +/****************************************************************************/ + +typedef struct _MSG_INBAND_RSP_REQUEST +{ + U16 Reserved1; /* 00h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Reserved4; /* 0Ch */ + WWN_INBAND_FORMAT Wwn; /* 10h */ + U32 IOCIdentifier[4]; /* 20h */ + U32 ResponseLength; /* 30h */ + SGE_IO_UNION SGL; /* 34h */ +} MSG_INBAND_RSP_REQUEST, MPI_POINTER PTR_MSG_INBAND_RSP_REQUEST, + MpiInbandRspRequest_t , MPI_POINTER pMpiInbandRspRequest_t; + + +/* Inband Response reply message */ + +typedef struct _MSG_INBAND_RSP_REPLY +{ + U16 Reserved1; /* 00h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved4; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ +} MSG_INBAND_RSP_REPLY, MPI_POINTER PTR_MSG_INBAND_RSP_REPLY, + MpiInbandRspReply_t, MPI_POINTER pMpiInbandRspReply_t; + + +/****************************************************************************/ +/* Inband Abort Request */ +/****************************************************************************/ + +typedef struct _MSG_INBAND_ABORT_REQUEST +{ + U8 Reserved1; /* 00h */ + U8 AbortType; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Reserved4; /* 0Ch */ + U32 ContextToAbort; /* 10h */ +} MSG_INBAND_ABORT_REQUEST, MPI_POINTER PTR_MSG_INBAND_ABORT_REQUEST, + MpiInbandAbortRequest_t , MPI_POINTER pMpiInbandAbortRequest_t; + +#define MPI_INBAND_ABORT_TYPE_ALL_BUFFERS (0x00) +#define MPI_INBAND_ABORT_TYPE_EXACT_BUFFER (0x01) +#define MPI_INBAND_ABORT_TYPE_SEND_REQUEST (0x02) +#define MPI_INBAND_ABORT_TYPE_RESPONSE_REQUEST (0x03) + + +/* Inband Abort reply message */ + +typedef struct _MSG_INBAND_ABORT_REPLY +{ + U8 Reserved1; /* 00h */ + U8 AbortType; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved4; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ +} MSG_INBAND_ABORT_REPLY, MPI_POINTER PTR_MSG_INBAND_ABORT_REPLY, + MpiInbandAbortReply_t, MPI_POINTER pMpiInbandAbortReply_t; + + +#endif + diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/message/fusion/lsi/mpi_init.h linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi_init.h --- linux-2.4.26/drivers/message/fusion/lsi/mpi_init.h 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi_init.h 2004-06-03 01:32:35.000000000 +0000 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2002 LSI Logic Corporation. + * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI_INIT.H + * Name: mpi_init.h * Title: MPI initiator mode messages and structures * Creation Date: June 8, 2000 * - * MPI_INIT.H Version: 01.02.07 + * mpi_init.h Version: 01.05.xx * * Version History * --------------- @@ -47,7 +47,7 @@ *****************************************************************************/ /****************************************************************************/ -/* SCSI IO messages and assocaited structures */ +/* SCSI IO messages and associated structures */ /****************************************************************************/ typedef struct _MSG_SCSI_IO_REQUEST @@ -80,6 +80,16 @@ typedef struct _MSG_SCSI_IO_REQUEST #define MPI_SCSIIO_MSGFLGS_SENSE_LOC_HOST (0x00) #define MPI_SCSIIO_MSGFLGS_SENSE_LOC_IOC (0x02) #define MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR (0x04) +#define MPI_SCSIIO_MSGFLGS_EEDP_TYPE_MASK (0xE0) +#define MPI_SCSIIO_MSGFLGS_EEDP_NONE (0x00) +#define MPI_SCSIIO_MSGFLGS_EEDP_RDPROTECT_T10 (0x20) +#define MPI_SCSIIO_MSGFLGS_EEDP_VRPROTECT_T10 (0x40) +#define MPI_SCSIIO_MSGFLGS_EEDP_WRPROTECT_T10 (0x60) +#define MPI_SCSIIO_MSGFLGS_EEDP_520_READ_MODE1 (0x20) +#define MPI_SCSIIO_MSGFLGS_EEDP_520_WRITE_MODE1 (0x40) +#define MPI_SCSIIO_MSGFLGS_EEDP_8_9_READ_MODE1 (0x60) +#define MPI_SCSIIO_MSGFLGS_EEDP_8_9_WRITE_MODE1 (0x80) + /* SCSI IO LUN fields */ @@ -182,6 +192,33 @@ typedef struct _MSG_SCSI_IO_REPLY /****************************************************************************/ +/* SCSI IO 32 Request message structure */ +/****************************************************************************/ + +typedef struct _MSG_SCSI_IO32_REQUEST +{ + U8 TargetID; /* 00h */ + U8 Bus; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U8 CDBLength; /* 04h */ + U8 SenseBufferLength; /* 05h */ + U8 Reserved; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 LUN[8]; /* 0Ch */ + U32 Control; /* 14h */ + U8 CDB[32]; /* 18h */ + U32 DataLength; /* 38h */ + U32 SenseBufferLowAddr; /* 3Ch */ + SGE_IO_UNION SGL; /* 40h */ +} MSG_SCSI_IO32_REQUEST, MPI_POINTER PTR_MSG_SCSI_IO32_REQUEST, + SCSIIO32Request_t, MPI_POINTER pSCSIIO32Request_t; + +/* SCSI IO 32 uses the same defines as above for SCSI IO */ + + +/****************************************************************************/ /* SCSI Task Management messages */ /****************************************************************************/ @@ -209,6 +246,7 @@ typedef struct _MSG_SCSI_TASK_MGMT #define MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03) #define MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS (0x04) #define MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05) +#define MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06) /* MsgFlags bits */ #define MPI_SCSITASKMGMT_MSGFLAGS_TARGET_RESET_OPTION (0x00) diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/message/fusion/lsi/mpi_ioc.h linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi_ioc.h --- linux-2.4.26/drivers/message/fusion/lsi/mpi_ioc.h 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi_ioc.h 2004-06-03 01:33:28.000000000 +0000 @@ -2,11 +2,11 @@ * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI_IOC.H + * Name: mpi_ioc.h * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: August 11, 2000 * - * MPI_IOC.H Version: 01.02.08 + * mpi_ioc.h Version: 01.05.xx * * Version History * --------------- @@ -89,19 +89,21 @@ typedef struct _MSG_IOC_INIT U8 Reserved1[2]; /* 0Eh */ U32 HostMfaHighAddr; /* 10h */ U32 SenseBufferHighAddr; /* 14h */ + U32 ReplyFifoHostSignalingAddr; /* 18h */ } MSG_IOC_INIT, MPI_POINTER PTR_MSG_IOC_INIT, IOCInit_t, MPI_POINTER pIOCInit_t; /* WhoInit values */ -#define MPI_WHOINIT_NO_ONE (0x00) -#define MPI_WHOINIT_SYSTEM_BIOS (0x01) -#define MPI_WHOINIT_ROM_BIOS (0x02) -#define MPI_WHOINIT_PCI_PEER (0x03) -#define MPI_WHOINIT_HOST_DRIVER (0x04) -#define MPI_WHOINIT_MANUFACTURER (0x05) +#define MPI_WHOINIT_NO_ONE (0x00) +#define MPI_WHOINIT_SYSTEM_BIOS (0x01) +#define MPI_WHOINIT_ROM_BIOS (0x02) +#define MPI_WHOINIT_PCI_PEER (0x03) +#define MPI_WHOINIT_HOST_DRIVER (0x04) +#define MPI_WHOINIT_MANUFACTURER (0x05) /* Flags values */ -#define MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE (0x01) +#define MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE (0x01) +#define MPI_IOCINIT_FLAGS_REPLY_FIFO_HOST_SIGNAL (0x02) typedef struct _MSG_IOC_INIT_REPLY { @@ -181,8 +183,10 @@ typedef struct _MSG_IOC_FACTS_REPLY U8 MaxDevices; /* 2Eh */ U8 MaxBuses; /* 2Fh */ U32 FWImageSize; /* 30h */ - U32 Reserved4; /* 34h */ + U32 IOCCapabilities; /* 34h */ MPI_FW_VERSION FWVersion; /* 38h */ + U16 HighPriorityQueueDepth; /* 3Ch */ + U16 Reserved2; /* 3Eh */ } MSG_IOC_FACTS_REPLY, MPI_POINTER PTR_MSG_IOC_FACTS_REPLY, IOCFactsReply_t, MPI_POINTER pIOCFactsReply_t; @@ -194,12 +198,22 @@ typedef struct _MSG_IOC_FACTS_REPLY #define MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL (0x0001) #define MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID (0x0002) +#define MPI_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL (0x0004) +#define MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL (0x0008) #define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT (0x01) #define MPI_IOCFACTS_EVENTSTATE_DISABLED (0x00) #define MPI_IOCFACTS_EVENTSTATE_ENABLED (0x01) +#define MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q (0x00000001) +#define MPI_IOCFACTS_CAPABILITY_REPLY_HOST_SIGNAL (0x00000002) +#define MPI_IOCFACTS_CAPABILITY_QUEUE_FULL_HANDLING (0x00000004) +#define MPI_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER (0x00000008) +#define MPI_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER (0x00000010) +#define MPI_IOCFACTS_CAPABILITY_EXTENDED_BUFFER (0x00000020) +#define MPI_IOCFACTS_CAPABILITY_EEDP (0x00000040) + /***************************************************************************** @@ -255,6 +269,8 @@ typedef struct _MSG_PORT_FACTS_REPLY #define MPI_PORTFACTS_PORTTYPE_INACTIVE (0x00) #define MPI_PORTFACTS_PORTTYPE_SCSI (0x01) #define MPI_PORTFACTS_PORTTYPE_FC (0x10) +#define MPI_PORTFACTS_PORTTYPE_ISCSI (0x20) +#define MPI_PORTFACTS_PORTTYPE_SAS (0x30) /* ProtocolFlags values */ @@ -388,6 +404,10 @@ typedef struct _MSG_EVENT_ACK_REPLY #define MPI_EVENT_INTEGRATED_RAID (0x0000000B) #define MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE (0x0000000C) #define MPI_EVENT_ON_BUS_TIMER_EXPIRED (0x0000000D) +#define MPI_EVENT_QUEUE_FULL (0x0000000E) +#define MPI_EVENT_SAS_DEVICE_STATUS_CHANGE (0x0000000F) +#define MPI_EVENT_SAS_SES (0x00000010) +#define MPI_EVENT_PERSISTENT_TABLE_FULL (0x00000011) /* AckRequired field values */ @@ -435,6 +455,39 @@ typedef struct _EVENT_DATA_SCSI_DEVICE_S #define MPI_EVENT_SCSI_DEV_STAT_RC_NOT_RESPONDING (0x04) #define MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA (0x05) +/* SAS Device Status Change Event data */ + +typedef struct _EVENT_DATA_SAS_DEVICE_STATUS_CHANGE +{ + U8 TargetID; /* 00h */ + U8 Bus; /* 01h */ + U8 ReasonCode; /* 02h */ + U8 Reserved; /* 03h */ + U8 ASC; /* 04h */ + U8 ASCQ; /* 05h */ + U16 DevHandle; /* 06h */ + U32 DeviceInfo; /* 08h */ +} EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, + MPI_POINTER PTR_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, + MpiEventDataSasDeviceStatusChange_t, + MPI_POINTER pMpiEventDataSasDeviceStatusChange_t; + +/* MPI SAS Device Status Change Event data ReasonCode values */ +#define MPI_EVENT_SAS_DEV_STAT_RC_ADDED (0x03) +#define MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING (0x04) +#define MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05) +#define MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED (0x06) + +/* SCSI Event data for Queue Full event */ + +typedef struct _EVENT_DATA_QUEUE_FULL +{ + U8 TargetID; /* 00h */ + U8 Bus; /* 01h */ + U16 CurrentDepth; /* 02h */ +} EVENT_DATA_QUEUE_FULL, MPI_POINTER PTR_EVENT_DATA_QUEUE_FULL, + EventDataQueueFull_t, MPI_POINTER pEventDataQueueFull_t; + /* MPI Link Status Change Event data */ typedef struct _EVENT_DATA_LINK_STATUS @@ -540,6 +593,7 @@ typedef struct _MSG_FW_DOWNLOAD #define MPI_FW_DOWNLOAD_ITYPE_FW (0x01) #define MPI_FW_DOWNLOAD_ITYPE_BIOS (0x02) #define MPI_FW_DOWNLOAD_ITYPE_NVDATA (0x03) +#define MPI_FW_DOWNLOAD_ITYPE_BOOTLOADER (0x04) typedef struct _FWDownloadTCSGE @@ -592,6 +646,7 @@ typedef struct _MSG_FW_UPLOAD #define MPI_FW_UPLOAD_ITYPE_FW_FLASH (0x01) #define MPI_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02) #define MPI_FW_UPLOAD_ITYPE_NVDATA (0x03) +#define MPI_FW_UPLOAD_ITYPE_BOOTLOADER (0x04) typedef struct _FWUploadTCSGE { @@ -655,6 +710,7 @@ typedef struct _MPI_FW_HEADER #define MPI_FW_HEADER_PID_TYPE_MASK (0xF000) #define MPI_FW_HEADER_PID_TYPE_SCSI (0x0000) #define MPI_FW_HEADER_PID_TYPE_FC (0x1000) +#define MPI_FW_HEADER_PID_TYPE_SAS (0x2000) #define MPI_FW_HEADER_SIGNATURE_0 (0x5AEAA55A) #define MPI_FW_HEADER_SIGNATURE_1 (0xA55AEAA5) @@ -669,6 +725,7 @@ typedef struct _MPI_FW_HEADER #define MPI_FW_HEADER_PID_PROD_CTX_SCSI (0x0600) #define MPI_FW_HEADER_PID_FAMILY_MASK (0x00FF) +/* SCSI */ #define MPI_FW_HEADER_PID_FAMILY_1030A0_SCSI (0x0001) #define MPI_FW_HEADER_PID_FAMILY_1030B0_SCSI (0x0002) #define MPI_FW_HEADER_PID_FAMILY_1030B1_SCSI (0x0003) @@ -681,9 +738,15 @@ typedef struct _MPI_FW_HEADER #define MPI_FW_HEADER_PID_FAMILY_1035B0_SCSI (0x000A) #define MPI_FW_HEADER_PID_FAMILY_1030TA0_SCSI (0x000B) #define MPI_FW_HEADER_PID_FAMILY_1020TA0_SCSI (0x000C) +/* Fibre Channel */ #define MPI_FW_HEADER_PID_FAMILY_909_FC (0x0000) #define MPI_FW_HEADER_PID_FAMILY_919_FC (0x0001) #define MPI_FW_HEADER_PID_FAMILY_919X_FC (0x0002) +#define MPI_FW_HEADER_PID_FAMILY_919XL_FC (0x0003) +#define MPI_FW_HEADER_PID_FAMILY_949_FC (0x0004) +#define MPI_FW_HEADER_PID_FAMILY_959_FC (0x0005) +/* SAS */ +#define MPI_FW_HEADER_PID_FAMILY_1064_SAS (0x0001) typedef struct _MPI_EXT_IMAGE_HEADER { @@ -702,5 +765,6 @@ typedef struct _MPI_EXT_IMAGE_HEADER #define MPI_EXT_IMAGE_TYPE_UNSPECIFIED (0x00) #define MPI_EXT_IMAGE_TYPE_FW (0x01) #define MPI_EXT_IMAGE_TYPE_NVDATA (0x03) +#define MPI_EXT_IMAGE_TYPE_BOOTLOADER (0x04) #endif diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/message/fusion/lsi/mpi_lan.h linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi_lan.h --- linux-2.4.26/drivers/message/fusion/lsi/mpi_lan.h 2003-06-13 14:51:34.000000000 +0000 +++ linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi_lan.h 2004-06-03 01:34:16.000000000 +0000 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2002 LSI Logic Corporation. + * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI_LAN.H + * Name: mpi_lan.h * Title: MPI LAN messages and structures * Creation Date: June 30, 2000 * - * MPI_LAN.H Version: 01.02.01 + * mpi_lan.h Version: 01.05.xx * * Version History * --------------- diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/message/fusion/lsi/mpi_raid.h linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi_raid.h --- linux-2.4.26/drivers/message/fusion/lsi/mpi_raid.h 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi_raid.h 2004-06-03 01:34:58.000000000 +0000 @@ -2,11 +2,11 @@ * Copyright (c) 2001-2003 LSI Logic Corporation. * * - * Name: MPI_RAID.H + * Name: mpi_raid.h * Title: MPI RAID message and structures * Creation Date: February 27, 2001 * - * MPI_RAID.H Version: 01.02.09 + * mpi_raid.h Version: 01.05.xx * * Version History * --------------- @@ -43,7 +43,7 @@ /****************************************************************************/ -/* RAID Volume Request */ +/* RAID Action Request */ /****************************************************************************/ typedef struct _MSG_RAID_ACTION diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/message/fusion/lsi/mpi_sas.h linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi_sas.h --- linux-2.4.26/drivers/message/fusion/lsi/mpi_sas.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi_sas.h 2004-06-03 01:34:37.000000000 +0000 @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2003 LSI Logic Corporation. + * + * + * Name: mpi_sas.h + * Title: MPI Serial Attached SCSI structures and definitions + * Creation Date: April 23, 2003 + * + * mpi_sas.h Version: 01.05.xx + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * xx-yy-zz 01.05.01 Original release. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_SAS_H +#define MPI_SAS_H + +/***************************************************************************** +* +* S e r i a l A t t a c h e d S C S I M e s s a g e s +* +*****************************************************************************/ + +/****************************************************************************/ +/* Serial Management Protocol Passthrough Request */ +/****************************************************************************/ + +typedef struct _MSG_SMP_PASSTHROUGH_REQUEST +{ + U8 PassthroughFlags; /* 00h */ + U8 PhysicalPort; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 RequestDataLength; /* 04h */ + U8 ConnectionRate; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Reserved1; /* 0Ch */ + U64 SASAddress; /* 10h */ + U32 Reserved2; /* 18h */ + U32 Reserved3; /* 1Ch */ + SGE_SIMPLE_UNION SGL; /* 20h */ +} MSG_SMP_PASSTHROUGH_REQUEST, MPI_POINTER PTR_MSG_SMP_PASSTHROUGH_REQUEST, + SmpPassthroughRequest_t, MPI_POINTER pSmpPassthroughRequest_t; + +#define MPI_SMP_PT_REQ_PT_FLAGS_IMMEDIATE (0x80) + +#define MPI_SMP_PT_REQ_CONNECT_RATE_NEGOTIATED (0x00) +#define MPI_SMP_PT_REQ_CONNECT_RATE_1_5 (0x08) +#define MPI_SMP_PT_REQ_CONNECT_RATE_3_0 (0x09) + + +/* Serial Management Protocol Passthrough Reply */ +typedef struct _MSG_SMP_PASSTHROUGH_REPLY +{ + U8 PassthroughFlags; /* 00h */ + U8 PhysicalPort; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 ResponseDataLength; /* 04h */ + U8 Reserved1; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 Reserved2; /* 0Ch */ + U8 SASStatus; /* 0Dh */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 Reserved3; /* 14h */ + U8 ResponseData[4]; /* 18h */ +} MSG_SMP_PASSTHROUGH_REPLY, MPI_POINTER PTR_MSG_SMP_PASSTHROUGH_REPLY, + SmpPassthroughReply_t, MPI_POINTER pSmpPassthroughReply_t; + +#define MPI_SMP_PT_REPLY_PT_FLAGS_IMMEDIATE (0x80) + +/* values for the SASStatus field */ +#define MPI_SASSTATUS_SUCCESS (0x00) +#define MPI_SASSTATUS_UNKNOWN_ERROR (0x01) +#define MPI_SASSTATUS_INVALID_FRAME (0x02) +#define MPI_SASSTATUS_UTC_BAD_DEST (0x03) +#define MPI_SASSTATUS_UTC_BREAK_RECEIVED (0x04) +#define MPI_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED (0x05) +#define MPI_SASSTATUS_UTC_PORT_LAYER_REQUEST (0x06) +#define MPI_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED (0x07) +#define MPI_SASSTATUS_UTC_STP_RESOURCES_BUSY (0x08) +#define MPI_SASSTATUS_UTC_WRONG_DESTINATION (0x09) +#define MPI_SASSTATUS_SHORT_INFORMATION_UNIT (0x0A) +#define MPI_SASSTATUS_LONG_INFORMATION_UNIT (0x0B) +#define MPI_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA (0x0C) +#define MPI_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR (0x0D) +#define MPI_SASSTATUS_XFER_RDY_NOT_EXPECTED (0x0E) +#define MPI_SASSTATUS_DATA_INCORRECT_DATA_LENGTH (0x0F) +#define MPI_SASSTATUS_DATA_TOO_MUCH_READ_DATA (0x10) +#define MPI_SASSTATUS_DATA_OFFSET_ERROR (0x11) +#define MPI_SASSTATUS_SDSF_NAK_RECEIVED (0x12) +#define MPI_SASSTATUS_SDSF_CONNECTION_FAILED (0x13) +#define MPI_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT (0x14) + + +/* + * Values for the SAS DeviceInfo field used in SAS Device Status Change Event + * data and SAS IO Unit Configuration pages. + */ +#define MPI_SAS_DEVICE_INFO_ATAPI_DEVICE (0x00002000) +#define MPI_SAS_DEVICE_INFO_LSI_DEVICE (0x00001000) +#define MPI_SAS_DEVICE_INFO_DIRECT_ATTACH (0x00000800) +#define MPI_SAS_DEVICE_INFO_SSP_TARGET (0x00000400) +#define MPI_SAS_DEVICE_INFO_STP_TARGET (0x00000200) +#define MPI_SAS_DEVICE_INFO_SMP_TARGET (0x00000100) +#define MPI_SAS_DEVICE_INFO_SATA_DEVICE (0x00000080) +#define MPI_SAS_DEVICE_INFO_SSP_INITIATOR (0x00000040) +#define MPI_SAS_DEVICE_INFO_STP_INITIATOR (0x00000020) +#define MPI_SAS_DEVICE_INFO_SMP_INITIATOR (0x00000010) +#define MPI_SAS_DEVICE_INFO_SATA_HOST (0x00000008) + +#define MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE (0x00000007) +#define MPI_SAS_DEVICE_INFO_NO_DEVICE (0x00000000) +#define MPI_SAS_DEVICE_INFO_END_DEVICE (0x00000001) +#define MPI_SAS_DEVICE_INFO_EDGE_EXPANDER (0x00000002) +#define MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER (0x00000003) + + +/****************************************************************************/ +/* SAS IO Unit Control Request */ +/****************************************************************************/ + +typedef struct _MSG_SAS_IOUNIT_CONTROL_REQUEST +{ + U8 Operation; /* 00h */ + U8 Reserved1; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 TargetID; /* 0Ch */ + U8 Bus; /* 0Dh */ + U8 PhyNum; /* 0Eh */ + U8 Reserved4; /* 0Fh */ + U32 Reserved5; /* 10h */ + U64 SASAddress; /* 14h */ + U32 Reserved6; /* 1Ch */ +} MSG_SAS_IOUNIT_CONTROL_REQUEST, MPI_POINTER PTR_MSG_SAS_IOUNIT_CONTROL_REQUEST, + SasIoUnitControlRequest_t, MPI_POINTER pSasIoUnitControlRequest_t; + +/* values for the ... field */ +#define MPI_SAS_OP_CLEAR_NOT_PRESENT (0x01) +#define MPI_SAS_OP_CLEAR_ALL (0x02) +#define MPI_SAS_OP_MAP (0x03) +#define MPI_SAS_OP_MOVE (0x04) +#define MPI_SAS_OP_CLEAR (0x05) +#define MPI_SAS_OP_PHY_LINK_RESET (0x06) +#define MPI_SAS_OP_PHY_HARD_RESET (0x07) +#define MPI_SAS_OP_PHY_CLEAR_ERROR_LOG (0x08) + + +/* SAS IO Unit Control Reply */ +typedef struct _MSG_SAS_IOUNIT_CONTROL_REPLY +{ + U8 Operation; /* 00h */ + U8 Reserved1; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved4; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ +} MSG_SAS_IOUNIT_CONTROL_REPLY, MPI_POINTER PTR_MSG_SAS_IOUNIT_CONTROL_REPLY, + SasIoUnitControlReply_t, MPI_POINTER pSasIoUnitControlReply_t; + +#endif + + diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/message/fusion/lsi/mpi_targ.h linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi_targ.h --- linux-2.4.26/drivers/message/fusion/lsi/mpi_targ.h 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi_targ.h 2004-06-03 01:32:49.000000000 +0000 @@ -2,11 +2,11 @@ * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI_TARG.H + * Name: mpi_targ.h * Title: MPI Target mode messages and structures * Creation Date: June 22, 2000 * - * MPI_TARG.H Version: 01.02.09 + * mpi_targ.h Version: 01.05.xx * * Version History * --------------- diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/message/fusion/lsi/mpi_tool.h linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi_tool.h --- linux-2.4.26/drivers/message/fusion/lsi/mpi_tool.h 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi_tool.h 2004-06-03 01:34:51.000000000 +0000 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2001 LSI Logic Corporation. + * Copyright (c) 2001-2003 LSI Logic Corporation. * * - * Name: MPI_TOOL.H + * Name: mpi_tool.h * Title: MPI Toolbox structures and definitions * Creation Date: July 30, 2001 * - * MPI Version: 01.02.02 + * mpi_tool.h Version: 01.05.xx * * Version History * --------------- @@ -24,6 +24,8 @@ #define MPI_TOOLBOX_CLEAN_TOOL (0x00) #define MPI_TOOLBOX_MEMORY_MOVE_TOOL (0x01) #define MPI_TOOLBOX_DIAG_DATA_UPLOAD_TOOL (0x02) +#define MPI_TOOLBOX_ISTWI_READ_WRITE_TOOL (0x03) +#define MPI_TOOLBOX_FC_MANAGEMENT_TOOL (0x04) /****************************************************************************/ @@ -68,6 +70,12 @@ typedef struct _MSG_TOOLBOX_CLEAN_REQUES #define MPI_TOOLBOX_CLEAN_NVSRAM (0x00000001) #define MPI_TOOLBOX_CLEAN_SEEPROM (0x00000002) #define MPI_TOOLBOX_CLEAN_FLASH (0x00000004) +#define MPI_TOOLBOX_CLEAN_BOOTLOADER (0x04000000) +#define MPI_TOOLBOX_CLEAN_FW_BACKUP (0x08000000) +#define MPI_TOOLBOX_CLEAN_FW_CURRENT (0x10000000) +#define MPI_TOOLBOX_CLEAN_OTHER_PERSIST_PAGES (0x20000000) +#define MPI_TOOLBOX_CLEAN_PERSIST_MANUFACT_PAGES (0x40000000) +#define MPI_TOOLBOX_CLEAN_BOOT_SERVICES (0x80000000) /****************************************************************************/ @@ -124,6 +132,174 @@ typedef struct _DIAG_DATA_UPLOAD_HEADER #define MPI_TB_DIAG_FORMAT_FC_TRACE_1 (0x04) +/****************************************************************************/ +/* Toolbox ISTWI Read Write request */ +/****************************************************************************/ + +typedef struct _MSG_TOOLBOX_ISTWI_READ_WRITE_REQUEST +{ + U8 Tool; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 Flags; /* 0Ch */ + U8 BusNum; /* 0Dh */ + U16 Reserved3; /* 0Eh */ + U8 NumAddressBytes; /* 10h */ + U8 Reserved4; /* 11h */ + U16 DataLength; /* 12h */ + U8 DeviceAddr; /* 14h */ + U8 Addr1; /* 15h */ + U8 Addr2; /* 16h */ + U8 Addr3; /* 17h */ + U32 Reserved5; /* 18h */ + SGE_SIMPLE_UNION SGL; /* 1Ch */ +} MSG_TOOLBOX_ISTWI_READ_WRITE_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_ISTWI_READ_WRITE_REQUEST, + ToolboxIstwiReadWriteRequest_t, MPI_POINTER pToolboxIstwiReadWriteRequest_t; + +#define MPI_TB_ISTWI_FLAGS_WRITE (0x00) +#define MPI_TB_ISTWI_FLAGS_READ (0x01) + + +/****************************************************************************/ +/* Toolbox FC Management request */ +/****************************************************************************/ + +/* ActionInfo for Bus and TargetId */ +typedef struct _MPI_TB_FC_MANAGE_BUS_TID_AI +{ + U16 Reserved; /* 00h */ + U8 Bus; /* 02h */ + U8 TargetId; /* 03h */ +} MPI_TB_FC_MANAGE_BUS_TID_AI, MPI_POINTER PTR_MPI_TB_FC_MANAGE_BUS_TID_AI, + MpiTbFcManageBusTidAi_t, MPI_POINTER pMpiTbFcManageBusTidAi_t; + +/* ActionInfo for port identifier */ +typedef struct _MPI_TB_FC_MANAGE_PID_AI +{ + U32 PortIdentifier; /* 00h */ +} MPI_TB_FC_MANAGE_PID_AI, MPI_POINTER PTR_MPI_TB_FC_MANAGE_PID_AI, + MpiTbFcManagePidAi_t, MPI_POINTER pMpiTbFcManagePidAi_t; + +/* union of ActionInfo */ +typedef union _MPI_TB_FC_MANAGE_AI_UNION +{ + MPI_TB_FC_MANAGE_BUS_TID_AI BusTid; + MPI_TB_FC_MANAGE_PID_AI Port; +} MPI_TB_FC_MANAGE_AI_UNION, MPI_POINTER PTR_MPI_TB_FC_MANAGE_AI_UNION, + MpiTbFcManageAiUnion_t, MPI_POINTER pMpiTbFcManageAiUnion_t; + +typedef struct _MSG_TOOLBOX_FC_MANAGE_REQUEST +{ + U8 Tool; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 Action; /* 0Ch */ + U8 Reserved3; /* 0Dh */ + U16 Reserved4; /* 0Eh */ + MPI_TB_FC_MANAGE_AI_UNION ActionInfo; /* 10h */ +} MSG_TOOLBOX_FC_MANAGE_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_FC_MANAGE_REQUEST, + ToolboxFcManageRequest_t, MPI_POINTER pToolboxFcManageRequest_t; + +/* defines for the Action field */ +#define MPI_TB_FC_MANAGE_ACTION_DISC_ALL (0x00) +#define MPI_TB_FC_MANAGE_ACTION_DISC_PID (0x01) +#define MPI_TB_FC_MANAGE_ACTION_DISC_BUS_TID (0x02) + + +/****************************************************************************/ +/* Diagnostic Buffer Post request */ +/****************************************************************************/ + +typedef struct _MSG_DIAG_BUFFER_POST_REQUEST +{ + U8 TraceLevel; /* 00h */ + U8 BufferType; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 ExtendedType; /* 0Ch */ + U32 BufferLength; /* 10h */ + U32 ProductSpecific[4]; /* 14h */ + U32 Reserved3; /* 18h */ + SGE_SIMPLE_UNION SGL; /* 28h */ +} MSG_DIAG_BUFFER_POST_REQUEST, MPI_POINTER PTR_MSG_DIAG_BUFFER_POST_REQUEST, + DiagBufferPostRequest_t, MPI_POINTER pDiagBufferPostRequest_t; + +#define MPI_DIAG_BUF_TYPE_TRACE (0x00) +#define MPI_DIAG_BUF_TYPE_SNAPSHOT (0x01) +#define MPI_DIAG_BUF_TYPE_EXTENDED (0x02) + +#define MPI_DIAG_EXTENDED_QTAG (0x00000001) + + +/* Diagnostic Buffer Post reply */ +typedef struct _MSG_DIAG_BUFFER_POST_REPLY +{ + U8 Reserved1; /* 00h */ + U8 BufferType; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved4; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 TransferLength; /* 14h */ +} MSG_DIAG_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_DIAG_BUFFER_POST_REPLY, + DiagBufferPostReply_t, MPI_POINTER pDiagBufferPostReply_t; + + +/****************************************************************************/ +/* Diagnostic Release request */ +/****************************************************************************/ + +typedef struct _MSG_DIAG_RELEASE_REQUEST +{ + U8 Reserved1; /* 00h */ + U8 BufferType; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ +} MSG_DIAG_RELEASE_REQUEST, MPI_POINTER PTR_MSG_DIAG_RELEASE_REQUEST, + DiagReleaseRequest_t, MPI_POINTER pDiagReleaseRequest_t; + + +/* Diagnostic Release reply */ +typedef struct _MSG_DIAG_RELEASE_REPLY +{ + U8 Reserved1; /* 00h */ + U8 BufferType; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved4; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ +} MSG_DIAG_RELEASE_REPLY, MPI_POINTER PTR_MSG_DIAG_RELEASE_REPLY, + DiagReleaseReply_t, MPI_POINTER pDiagReleaseReply_t; + + #endif diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/message/fusion/lsi/mpi_type.h linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi_type.h --- linux-2.4.26/drivers/message/fusion/lsi/mpi_type.h 2003-06-13 14:51:34.000000000 +0000 +++ linux-2.4.27-pre5/drivers/message/fusion/lsi/mpi_type.h 2004-06-03 01:34:38.000000000 +0000 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2002 LSI Logic Corporation. + * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI_TYPE.H + * Name: mpi_type.h * Title: MPI Basic type definitions * Creation Date: June 6, 2000 * - * MPI Version: 01.02.01 + * mpi_type.h Version: 01.05.xx * * Version History * --------------- diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/message/fusion/mptbase.c linux-2.4.27-pre5/drivers/message/fusion/mptbase.c --- linux-2.4.26/drivers/message/fusion/mptbase.c 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/message/fusion/mptbase.c 2004-06-03 01:33:06.000000000 +0000 @@ -209,7 +209,6 @@ static int GetFcPortPage0(MPT_ADAPTER *i static int GetIoUnitPage2(MPT_ADAPTER *ioc); static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum); static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum); -static int mpt_findImVolumes(MPT_ADAPTER *ioc); static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc); static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc); static void mpt_timer_expired(unsigned long data); @@ -567,7 +566,8 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRA } else if (func == MPI_FUNCTION_EVENT_ACK) { dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n", ioc->name)); - } else if (func == MPI_FUNCTION_CONFIG) { + } else if (func == MPI_FUNCTION_CONFIG || + func == MPI_FUNCTION_TOOLBOX) { CONFIGPARMS *pCfg; unsigned long flags; @@ -904,6 +904,8 @@ mpt_put_msg_frame(int handle, int iocid, mf_dma_addr = iocp->req_frames_low_dma + req_offset; CHIPREG_WRITE32(&iocp->chip->RequestFifo, mf_dma_addr); + } else { + printk (KERN_ERR "mpt_put_msg_frame: Invalid iocid=%d\n", iocid); } } @@ -1053,7 +1055,7 @@ mpt_send_handshake_request(int handle, i ((reqBytes/4)<chip->IntStatus, 0); - if ((r = WaitForDoorbellAck(iocp, 2, sleepFlag)) < 0) { + if ((r = WaitForDoorbellAck(iocp, 5, sleepFlag)) < 0) { return -2; } @@ -1080,7 +1082,7 @@ mpt_send_handshake_request(int handle, i (req_as_bytes[(ii*4) + 2] << 16) | (req_as_bytes[(ii*4) + 3] << 24)); CHIPREG_WRITE32(&iocp->chip->Doorbell, word); - if ((r = WaitForDoorbellAck(iocp, 2, sleepFlag)) < 0) { + if ((r = WaitForDoorbellAck(iocp, 5, sleepFlag)) < 0) { r = -3; break; } @@ -1279,6 +1281,8 @@ mpt_adapter_install(struct pci_dev *pdev int ii; int r = -ENODEV; u64 mask = 0xffffffffffffffffULL; + u8 revision; + u8 pcixcmd; if (pci_enable_device(pdev)) return r; @@ -1418,46 +1422,45 @@ mpt_adapter_install(struct pci_dev *pdev } else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) { ioc->chip_type = FC929X; - ioc->prod_name = "LSIFC929X"; - { + pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); + if (revision < XL_929) { + ioc->prod_name = "LSIFC929X"; /* 929X Chip Fix. Set Split transactions level - * for PCIX. Set MOST bits to zero. - */ - u8 pcixcmd; + * for PCIX. Set MOST bits to zero. + */ pci_read_config_byte(pdev, 0x6a, &pcixcmd); pcixcmd &= 0x8F; pci_write_config_byte(pdev, 0x6a, pcixcmd); + } else { + ioc->prod_name = "LSIFC929XL"; + /* 929XL Chip Fix. Set MMRBC to 0x08. + */ + pci_read_config_byte(pdev, 0x6a, &pcixcmd); + pcixcmd |= 0x08; + pci_write_config_byte(pdev, 0x6a, pcixcmd); } } else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) { ioc->chip_type = FC919X; ioc->prod_name = "LSIFC919X"; - { - /* 919X Chip Fix. Set Split transactions level - * for PCIX. Set MOST bits to zero. - */ - u8 pcixcmd; - pci_read_config_byte(pdev, 0x6a, &pcixcmd); - pcixcmd &= 0x8F; - pci_write_config_byte(pdev, 0x6a, pcixcmd); - } + /* 919X Chip Fix. Set Split transactions level + * for PCIX. Set MOST bits to zero. + */ + pci_read_config_byte(pdev, 0x6a, &pcixcmd); + pcixcmd &= 0x8F; + pci_write_config_byte(pdev, 0x6a, pcixcmd); } else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) { ioc->chip_type = C1030; ioc->prod_name = "LSI53C1030"; - { - u8 revision; - - /* 1030 Chip Fix. Disable Split transactions - * for PCIX. Set MOST bits to zero if Rev < C0( = 8). - */ - pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); - if (revision < 0x08) { - u8 pcixcmd; - pci_read_config_byte(pdev, 0x6a, &pcixcmd); - pcixcmd &= 0x8F; - pci_write_config_byte(pdev, 0x6a, pcixcmd); - } + /* 1030 Chip Fix. Disable Split transactions + * for PCIX. Set MOST bits to zero if Rev < C0( = 8). + */ + pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); + if (revision < C0_1030) { + pci_read_config_byte(pdev, 0x6a, &pcixcmd); + pcixcmd &= 0x8F; + pci_write_config_byte(pdev, 0x6a, pcixcmd); } } else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) { @@ -1610,11 +1613,17 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 ioc->alt_ioc->name, r); } + for (ii=0; ii<5; ii++) { /* Get IOC facts! Allow 1 retry */ - if ((r = GetIocFacts(ioc, sleepFlag, reason)) != 0) - r = GetIocFacts(ioc, sleepFlag, reason); + if ((r = GetIocFacts(ioc, sleepFlag, reason)) != 0) { + dinitprintk((MYIOC_s_INFO_FMT "ii=%d IocFacts failed r=%x\n", ioc->name, ii, r)); + } else + break; + } + if (r) { + dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed r=%x\n", ioc->name, r)); ret = -2; } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { MptDisplayIocCapabilities(ioc); @@ -1622,11 +1631,13 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u3 if (alt_ioc_ready) { if ((r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) { + dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed r=%x\n", ioc->name, r)); /* Retry - alt IOC was initialized once */ r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason); } if (r) { + dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed r=%x\n", ioc->name, r)); alt_ioc_ready = 0; reset_alt_ioc_active = 0; } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { @@ -1862,15 +1873,8 @@ mpt_adapter_disable(MPT_ADAPTER *this, i u32 state; int ret; - /* Disable the FW */ - state = mpt_GetIocState(this, 1); - if (state == MPI_IOC_STATE_OPERATIONAL) { - SendIocReset(this, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, NO_SLEEP); - } - if (this->cached_fw != NULL) { ddlprintk((KERN_INFO MYNAM ": Pushing FW onto adapter\n")); - if ((ret = mpt_downloadboot(this, NO_SLEEP)) < 0) { printk(KERN_WARNING MYNAM ": firmware downloadboot failure (%d)!\n", ret); @@ -1921,25 +1925,11 @@ mpt_adapter_disable(MPT_ADAPTER *this, i } if (freeup && this->cached_fw != NULL) { - int ii = 0; - - while ((ii < this->num_fw_frags) && (this->cached_fw[ii]!= NULL)) { - sz = this->cached_fw[ii]->size; - pci_free_consistent(this->pcidev, sz, - this->cached_fw[ii]->fw, this->cached_fw[ii]->fw_dma); - this->cached_fw[ii]->fw = NULL; - this->alloc_total -= sz; - - kfree(this->cached_fw[ii]); - this->cached_fw[ii] = NULL; - this->alloc_total -= sizeof(fw_image_t); - - ii++; - } - kfree(this->cached_fw); + sz = this->facts.FWImageSize; + pci_free_consistent(this->pcidev, sz, + this->cached_fw, this->cached_fw_dma); this->cached_fw = NULL; - sz = this->num_fw_frags * sizeof(void *); this->alloc_total -= sz; } @@ -1981,11 +1971,6 @@ mpt_adapter_dispose(MPT_ADAPTER *this) sz_first = this->alloc_total; - if (this->alt_ioc != NULL) { - this->alt_ioc->alt_ioc = NULL; - this->alt_ioc = NULL; - } - mpt_adapter_disable(this, 1); if (this->pci_irq != -1) { @@ -2101,13 +2086,14 @@ MakeIocReady(MPT_ADAPTER *ioc, int force if ((int)ioc->chip_type <= (int)FC929) return 0; else { + return 0; /* Workaround from broken 1030 FW. * Force a diagnostic reset if fails. */ - if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0) +/* if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0) return 0; else - statefault = 4; + statefault = 4; */ } } @@ -2126,7 +2112,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force * Hmmm... Did it get left operational? */ if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) { - dprintk((MYIOC_s_WARN_FMT "IOC operational unexpected\n", + dinitprintk((MYIOC_s_WARN_FMT "IOC operational unexpected\n", ioc->name)); /* Check WhoInit. @@ -2270,13 +2256,13 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF get_facts.Function = MPI_FUNCTION_IOC_FACTS; /* Assert: All other get_facts fields are zero! */ - dprintk((MYIOC_s_INFO_FMT "Sending get IocFacts request\n", ioc->name)); + dinitprintk((MYIOC_s_INFO_FMT "Sending get IocFacts request\n", ioc->name)); /* No non-zero fields in the get_facts request are greater than * 1 byte in size, so we can just fire it off as is. */ r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts, - reply_sz, (u16*)facts, 3 /*seconds*/, sleepFlag); + reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag); if (r != 0) return r; @@ -2370,8 +2356,8 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepF return r; } } else { - printk(MYIOC_s_ERR_FMT "Invalid IOC facts reply!\n", - ioc->name); + printk(MYIOC_s_ERR_FMT "Invalid IOC facts reply, msgLength=%d offsetof=%d!\n", + ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32))); return -66; } @@ -2425,7 +2411,7 @@ GetPortFacts(MPT_ADAPTER *ioc, int portn * 1 byte in size, so we can just fire it off as is. */ ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts, - reply_sz, (u16*)pfacts, 3 /*seconds*/, sleepFlag); + reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag); if (ii != 0) return ii; @@ -2511,7 +2497,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepF ioc_init.SenseBufferHighAddr = cpu_to_le32(0); } - dprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n", + dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n", ioc->name, &ioc_init)); r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init, @@ -2523,6 +2509,9 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepF * since we don't even look at it's contents. */ + dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n", + ioc->name, &ioc_init)); + if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) return r; @@ -2589,7 +2578,7 @@ SendPortEnable(MPT_ADAPTER *ioc, int por /* port_enable.MsgFlags = 0; */ /* port_enable.MsgContext = 0; */ - dprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n", + dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n", ioc->name, portnum, &port_enable)); /* RAID FW may take a long time to enable @@ -2617,86 +2606,14 @@ SendPortEnable(MPT_ADAPTER *ioc, int por * Outputs: frags - number of fragments needed * Return NULL if failed. */ -void * -mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz) +void +mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size) { - fw_image_t **cached_fw; - u8 *mem; - dma_addr_t fw_dma; - int alloc_total = 0; - int bytes_left, bytes, num_frags; - int sz, ii; - /* cached_fw */ - sz = ioc->num_fw_frags * sizeof(void *); - mem = kmalloc(sz, GFP_ATOMIC); - if (mem == NULL) - return NULL; - - memset(mem, 0, sz); - cached_fw = (fw_image_t **)mem; - alloc_total += sz; - - /* malloc fragment memory - * fw_image_t struct and dma for fw data - */ - bytes_left = size; - ii = 0; - num_frags = 0; - bytes = bytes_left; - while((bytes_left) && (num_frags < ioc->num_fw_frags)) { - if (cached_fw[ii] == NULL) { - mem = kmalloc(sizeof(fw_image_t), GFP_ATOMIC); - if (mem == NULL) - break; - - memset(mem, 0, sizeof(fw_image_t)); - cached_fw[ii] = (fw_image_t *)mem; - alloc_total += sizeof(fw_image_t); - } - - mem = pci_alloc_consistent(ioc->pcidev, bytes, &fw_dma); - if (mem == NULL) { - if (bytes > 0x10000) - bytes = 0x10000; - else if (bytes > 0x8000) - bytes = 0x8000; - else if (bytes > 0x4000) - bytes = 0x4000; - else if (bytes > 0x2000) - bytes = 0x2000; - else if (bytes > 0x1000) - bytes = 0x1000; - else - break; - - continue; - } - - cached_fw[ii]->fw = mem; - cached_fw[ii]->fw_dma = fw_dma; - cached_fw[ii]->size = bytes; - memset(mem, 0, bytes); - alloc_total += bytes; - - bytes_left -= bytes; - - num_frags++; - ii++; - } - - if (bytes_left ) { - /* Major Failure. - */ - mpt_free_fw_memory(ioc, cached_fw); - return NULL; - } - - *frags = num_frags; - *alloc_sz = alloc_total; - return (void *) cached_fw; + if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) ) + ioc->alloc_total += size; } /* @@ -2704,45 +2621,14 @@ mpt_alloc_fw_memory(MPT_ADAPTER *ioc, in * Else, delete a secondary image in same format. */ void -mpt_free_fw_memory(MPT_ADAPTER *ioc, fw_image_t **alt_img) +mpt_free_fw_memory(MPT_ADAPTER *ioc) { - fw_image_t **cached_fw; - int ii; int sz; - int alloc_freed = 0; - - if (alt_img != NULL) - cached_fw = alt_img; - else - cached_fw = ioc->cached_fw; - - if (cached_fw == NULL) - return; - ii = 0; - while ((ii < ioc->num_fw_frags) && (cached_fw[ii]!= NULL)) { - sz = cached_fw[ii]->size; - if (sz > 0) { - pci_free_consistent(ioc->pcidev, sz, - cached_fw[ii]->fw, cached_fw[ii]->fw_dma); - } - cached_fw[ii]->fw = NULL; - alloc_freed += sz; - - kfree(cached_fw[ii]); - cached_fw[ii] = NULL; - alloc_freed += sizeof(fw_image_t); - - ii++; - } - - kfree(cached_fw); - cached_fw = NULL; - sz = ioc->num_fw_frags * sizeof(void *); - alloc_freed += sz; - - if (alt_img == NULL) - ioc->alloc_total -= alloc_freed; + sz = ioc->facts.FWImageSize; + pci_free_consistent(ioc->pcidev, sz, + ioc->cached_fw, ioc->cached_fw_dma); + ioc->cached_fw = NULL; return; } @@ -2771,9 +2657,9 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee FWUploadReply_t *preply; FWUploadTCSGE_t *ptcsge; int sgeoffset; + u32 flagsLength; int ii, sz, reply_sz; int cmdStatus, freeMem = 0; - int num_frags, alloc_sz; /* If the image size is 0 or if the pointer is * not NULL (error), we are done. @@ -2781,24 +2667,21 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee if (((sz = ioc->facts.FWImageSize) == 0) || ioc->cached_fw) return 0; - ioc->num_fw_frags = ioc->req_sz - sizeof(FWUpload_t) + sizeof(dma_addr_t) + sizeof(u32) -1; - ioc->num_fw_frags /= sizeof(dma_addr_t) + sizeof(u32); + if ( sz & 0x01 ) + sz += 1; + if ( sz & 0x02 ) + sz += 2; - ioc->cached_fw = (fw_image_t **) mpt_alloc_fw_memory(ioc, - ioc->facts.FWImageSize, &num_frags, &alloc_sz); + mpt_alloc_fw_memory(ioc, sz); if (ioc->cached_fw == NULL) { /* Major Failure. */ - mpt_free_fw_memory(ioc, NULL); - ioc->cached_fw = NULL; - return -ENOMEM; } - ioc->alloc_total += alloc_sz; - ddlprintk((KERN_INFO MYNAM ": FW Image @ %p, sz=%d bytes\n", - (void *)(ulong)ioc->cached_fw, ioc->facts.FWImageSize)); + dinitprintk((KERN_WARNING MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n", + ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); prequest = (FWUpload_t *)&request; preply = (FWUploadReply_t *)&reply; @@ -2811,39 +2694,27 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee prequest->ImageType = MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM; prequest->Function = MPI_FUNCTION_FW_UPLOAD; - prequest->MsgContext = 0; /* anything */ ptcsge = (FWUploadTCSGE_t *) &prequest->SGL; - ptcsge->Reserved = 0; - ptcsge->ContextSize = 0; ptcsge->DetailsLength = 12; ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT; - ptcsge->Reserved1 = 0; - ptcsge->ImageOffset = 0; ptcsge->ImageSize = cpu_to_le32(sz); sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t); - for (ii = 0; ii < (num_frags-1); ii++) { - mpt_add_sge(&request[sgeoffset], MPT_SGE_FLAGS_SIMPLE_ELEMENT | - MPT_SGE_FLAGS_ADDRESSING | MPT_TRANSFER_IOC_TO_HOST | - (u32) ioc->cached_fw[ii]->size, ioc->cached_fw[ii]->fw_dma); - - sgeoffset += sizeof(u32) + sizeof(dma_addr_t); - } - - mpt_add_sge(&request[sgeoffset], - MPT_SGE_FLAGS_SSIMPLE_READ |(u32) ioc->cached_fw[ii]->size, - ioc->cached_fw[ii]->fw_dma); + flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz; + mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma); sgeoffset += sizeof(u32) + sizeof(dma_addr_t); - - dprintk((MYIOC_s_INFO_FMT "Sending FW Upload (req @ %p) size %d \n", - ioc->name, prequest, sgeoffset)); + dinitprintk((KERN_WARNING MYNAM "Sending FW Upload (req @ %p) sgeoffset=%d \n", + prequest, sgeoffset)); + DBG_DUMP_FW_REQUEST_FRAME(prequest) ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest, reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag); + dinitprintk((KERN_WARNING MYNAM "FW Upload completed rc=%x \n", ii)); + cmdStatus = -EFAULT; if (ii == 0) { /* Handshake transfer was complete and successful. @@ -2857,7 +2728,7 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee cmdStatus = 0; } } - ddlprintk((MYIOC_s_INFO_FMT ": do_upload status %d \n", + dinitprintk((MYIOC_s_INFO_FMT ": do_upload status %d \n", ioc->name, cmdStatus)); /* Check to see if we have a copy of this image in @@ -2877,8 +2748,7 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee ddlprintk((MYIOC_s_INFO_FMT ": do_upload freeing %s image \n", ioc->name, cmdStatus ? "incomplete" : "duplicate")); - mpt_free_fw_memory(ioc, NULL); - ioc->cached_fw = NULL; + mpt_free_fw_memory(ioc); } return cmdStatus; @@ -2901,241 +2771,141 @@ mpt_do_upload(MPT_ADAPTER *ioc, int slee static int mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag) { - MpiFwHeader_t *FwHdr; - MpiExtImageHeader_t *ExtHdr; - fw_image_t **pCached; - int fw_sz; + MpiFwHeader_t *pFwHeader; + MpiExtImageHeader_t *pExtImage; + u32 fwSize; u32 diag0val; #ifdef MPT_DEBUG u32 diag1val = 0; #endif int count = 0; - u32 *ptru32; + u32 *ptrFw; u32 diagRwData; u32 nextImage; u32 ext_offset; u32 load_addr; - int max_idx, fw_idx, ext_idx; - int left_u32s; - - ddlprintk((MYIOC_s_INFO_FMT "DbGb0: downloadboot entered.\n", - ioc->name)); -#ifdef MPT_DEBUG - diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); - if (ioc->alt_ioc) - diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); - ddlprintk((MYIOC_s_INFO_FMT "DbGb1: diag0=%08x, diag1=%08x\n", - ioc->name, diag0val, diag1val)); -#endif + u32 ioc_state; + int fw_idx; + int r; - ddlprintk((MYIOC_s_INFO_FMT "fw size 0x%x, ioc FW Ptr %p\n", + ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x, ioc FW Ptr %p\n", ioc->name, ioc->facts.FWImageSize, ioc->cached_fw)); - if (ioc->alt_ioc) - ddlprintk((MYIOC_s_INFO_FMT "alt ioc FW Ptr %p\n", - ioc->name, ioc->alt_ioc->cached_fw)); /* Get dma_addr and data transfer size. */ - if ((fw_sz = ioc->facts.FWImageSize) == 0) + if ( ioc->facts.FWImageSize == 0 ) return -1; /* Get the DMA from ioc or ioc->alt_ioc */ - if (ioc->cached_fw != NULL) - pCached = (fw_image_t **)ioc->cached_fw; - else if (ioc->alt_ioc && (ioc->alt_ioc->cached_fw != NULL)) - pCached = (fw_image_t **)ioc->alt_ioc->cached_fw; - - ddlprintk((MYIOC_s_INFO_FMT "DbGb2: FW Image @ %p\n", - ioc->name, pCached)); - if (!pCached) + if (ioc->cached_fw == NULL) return -2; - /* Write magic sequence to WriteSequence register - * until enter diagnostic mode - */ + CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); - while ((diag0val & MPI_DIAG_DRWE) == 0) { - CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); - CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); - CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); - CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); - CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); - CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); + diag0val |= (MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM); + CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); - /* wait 100 msec */ + /* wait 100 msec */ + if (sleepFlag == CAN_SLEEP) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(100 * HZ / 1000); + } else { + mdelay (100); + } + + CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER); + + for (count = 0; count < 30; count ++) { + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); + if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) { + ddlprintk((MYIOC_s_INFO_FMT "RESET_ADAPTER cleared, count=%d\n", + ioc->name, count)); + break; + } + /* wait 1 sec */ if (sleepFlag == CAN_SLEEP) { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(100 * HZ / 1000); + schedule_timeout(HZ); } else { - mdelay (100); - } - - count++; - if (count > 20) { - printk(MYIOC_s_ERR_FMT "Enable Diagnostic mode FAILED! (%02xh)\n", - ioc->name, diag0val); - return -EFAULT; - + mdelay (1000); } - - diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); -#ifdef MPT_DEBUG - if (ioc->alt_ioc) - diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); - ddlprintk((MYIOC_s_INFO_FMT "DbGb3: diag0=%08x, diag1=%08x\n", - ioc->name, diag0val, diag1val)); -#endif - ddlprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n", - ioc->name, diag0val)); } - /* Set the DiagRwEn and Disable ARM bits */ - diag0val |= (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM); - CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); + if ( count == 30 ) { + ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! Unable to RESET_ADAPTER diag0val=%x\n", + ioc->name, diag0val)); + return -3; + } -#ifdef MPT_DEBUG - if (ioc->alt_ioc) - diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_4TH_KEY_VALUE); + CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_5TH_KEY_VALUE); - ddlprintk((MYIOC_s_INFO_FMT "DbGb3: diag0=%08x, diag1=%08x\n", - ioc->name, diag0val, diag1val)); -#endif + /* Set the DiagRwEn and Disable ARM bits */ + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); + CHIPREG_WRITE32(&ioc->chip->Diagnostic, (diag0val | MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM)); - /* max_idx = 1 + maximum valid buffer index - */ - max_idx = 0; - while (pCached[max_idx]) - max_idx++; - - fw_idx = 0; - FwHdr = (MpiFwHeader_t *) pCached[fw_idx]->fw; - ptru32 = (u32 *) FwHdr; - count = (FwHdr->ImageSize + 3)/4; - nextImage = FwHdr->NextImageHeaderOffset; + pFwHeader = (MpiFwHeader_t *) ioc->cached_fw; + fwSize = (pFwHeader->ImageSize + 3)/4; + ptrFw = (u32 *) pFwHeader; /* Write the LoadStartAddress to the DiagRw Address Register * using Programmed IO */ - CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, FwHdr->LoadStartAddress); + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress); ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n", - ioc->name, FwHdr->LoadStartAddress)); + ioc->name, pFwHeader->LoadStartAddress)); - ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x u32's @ %p\n", - ioc->name, count, ptru32)); - left_u32s = pCached[fw_idx]->size/4; - while (count--) { - if (left_u32s == 0) { - fw_idx++; - if (fw_idx >= max_idx) { - /* FIXME - ERROR CASE - */ - ; - } - ptru32 = (u32 *) pCached[fw_idx]->fw; - left_u32s = pCached[fw_idx]->size / 4; - } - left_u32s--; - CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptru32); - ptru32++; + ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x bytes @ %p\n", + ioc->name, fwSize*4, ptrFw)); + while (fwSize--) { + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++); } - /* left_u32s, fw_idx and ptru32 are all valid - */ + nextImage = pFwHeader->NextImageHeaderOffset; while (nextImage) { - ext_idx = 0; - ext_offset = nextImage; - while (ext_offset > pCached[ext_idx]->size) { - ext_idx++; - if (ext_idx >= max_idx) { - /* FIXME - ERROR CASE - */ - ; - } - ext_offset -= pCached[ext_idx]->size; - } - ptru32 = (u32 *) ((char *)pCached[ext_idx]->fw + ext_offset); - left_u32s = pCached[ext_idx]->size - ext_offset; - - if ((left_u32s * 4) >= sizeof(MpiExtImageHeader_t)) { - ExtHdr = (MpiExtImageHeader_t *) ptru32; - count = (ExtHdr->ImageSize + 3 )/4; - nextImage = ExtHdr->NextImageHeaderOffset; - load_addr = ExtHdr->LoadStartAddress; - } else { - u32 * ptmp = (u32 *)pCached[ext_idx+1]->fw; - - switch (left_u32s) { - case 5: - count = *(ptru32 + 2); - nextImage = *(ptru32 + 3); - load_addr = *(ptru32 + 4); - break; - case 4: - count = *(ptru32 + 2); - nextImage = *(ptru32 + 3); - load_addr = *ptmp; - break; - case 3: - count = *(ptru32 + 2); - nextImage = *ptmp; - load_addr = *(ptmp + 1); - break; - case 2: - count = *ptmp; - nextImage = *(ptmp + 1); - load_addr = *(ptmp + 2); - break; - - case 1: - count = *(ptmp + 1); - nextImage = *(ptmp + 2); - load_addr = *(ptmp + 3); - break; + pExtImage = (MpiExtImageHeader_t *) ((char *)pFwHeader + nextImage); - default: - count = 0; - nextImage = 0; - load_addr = 0; - /* FIXME - ERROR CASE - */ - ; + load_addr = pExtImage->LoadStartAddress; - } - count = (count +3)/4; - } + fwSize = (pExtImage->ImageSize + 3) >> 2; + ptrFw = (u32 *)pExtImage; - ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x u32's @ %p\n", - ioc->name, count, ptru32)); + ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x bytes @ %p load_addr=%x\n", + ioc->name, fwSize*4, ptrFw, load_addr)); CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr); - while (count--) { - if (left_u32s == 0) { - fw_idx++; - if (fw_idx >= max_idx) { - /* FIXME - ERROR CASE - */ - ; - } - ptru32 = (u32 *) pCached[fw_idx]->fw; - left_u32s = pCached[fw_idx]->size / 4; - } - left_u32s--; - CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptru32); - ptru32++; + while (fwSize--) { + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++); } + nextImage = pExtImage->NextImageHeaderOffset; } /* Write the IopResetVectorRegAddr */ - ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr! \n", ioc->name)); - CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, FwHdr->IopResetRegAddr); + ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr=%x! \n", ioc->name, pFwHeader->IopResetRegAddr)); + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr); /* Write the IopResetVectorValue */ - ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value! \n", ioc->name)); - CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, FwHdr->IopResetVectorValue); + ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue)); + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue); + + /* clear the PREVENT_IOC_BOOT bit */ + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); + ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, turning off PREVENT_IOC_BOOT\n", + ioc->name, diag0val)); + diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT); + ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n", + ioc->name, diag0val)); + CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); /* Clear the internal flash bad bit - autoincrementing register, * so must do two writes. @@ -3146,15 +2916,63 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int s CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000); CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData); - /* clear the RW enable and DISARM bits */ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); - diag0val &= ~(MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE | MPI_DIAG_FLASH_BAD_SIG); + ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, turning off DISABLE_ARM, RW_ENABLE, RESET_HISTORY\n", + ioc->name, diag0val)); + diag0val &= ~(MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE | MPI_DIAG_RESET_HISTORY); + ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n", + ioc->name, diag0val)); CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); + /* wait 100 msec */ + if (sleepFlag == CAN_SLEEP) { + ddlprintk((MYIOC_s_INFO_FMT "CAN_SLEEP 100 msec before reset the sequencer\n", ioc->name)); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(100 * HZ / 1000); + } else { + ddlprintk((MYIOC_s_INFO_FMT "mdelay 100 msec before reset the sequencer\n", ioc->name)); + mdelay (100); + } + + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); + if ( diag0val & (MPI_DIAG_FLASH_BAD_SIG | MPI_DIAG_DISABLE_ARM) ) { + ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed, diag0val=%x FLASH_BAD_SIG | DISABLE_ARM on\n ", + ioc->name, diag0val)); + } /* Write 0xFF to reset the sequencer */ CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); - return 0; + for (count=0; countname, count, ioc_state)); +/* if ((r = GetIocFacts(ioc, sleepFlag, MPT_HOSTEVENT_IOC_BRINGUP)) != 0) { + if ((r = GetIocFacts(ioc, sleepFlag, MPT_HOSTEVENT_IOC_BRINGUP)) != 0) { + ddlprintk((MYIOC_s_INFO_FMT "GetIocFacts failed\n", + ioc->name)); + return -EFAULT; + } + } */ + /* wait 2 sec */ +/* if (sleepFlag == CAN_SLEEP) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(5000 * HZ / 1000); + } else { + mdelay (5000); + } */ + + return 0; + } + if (sleepFlag == CAN_SLEEP) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + } else { + mdelay (10); + } + } + ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! IocState=%x\n", + ioc->name, ioc_state)); + return -EFAULT; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -3190,7 +3008,7 @@ KickStart(MPT_ADAPTER *ioc, int force, i u32 ioc_state; int cnt = 0; - dprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name)); + dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name)); if ((int)ioc->chip_type > (int)FC929) { /* Always issue a Msg Unit Reset first. This will clear some * SCSI bus hang conditions. @@ -3437,6 +3255,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ign /* Write magic sequence to WriteSequence register * Loop until in diagnostic mode */ + CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); @@ -3516,10 +3335,10 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_ u32 state; int cntdn, count; - dprintk((KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n", + drsprintk((KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n", ioc->name, reset_type)); CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<chip->IntStatus, 0); - if (!failcnt && (t = WaitForDoorbellAck(ioc, 4, sleepFlag)) < 0) + if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) failcnt++; if (!failcnt) { @@ -3819,7 +3638,7 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER (req_as_bytes[(ii*4) + 3] << 24)); CHIPREG_WRITE32(&ioc->chip->Doorbell, word); - if ((t = WaitForDoorbellAck(ioc, 4, sleepFlag)) < 0) + if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) failcnt++; } @@ -3835,6 +3654,9 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0) failcnt++; + dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n", + ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : "")); + /* * Copy out the cached reply... */ @@ -3865,7 +3687,7 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int { int cntdn; int count = 0; - u32 intstat; + u32 intstat=0; cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * howlong; @@ -3889,13 +3711,13 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int } if (cntdn) { - dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (cnt=%d)\n", + dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n", ioc->name, count)); return count; } - printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout(%d)!\n", - ioc->name, (count+5)/HZ); + printk(MYIOC_s_ERR_FMT "Doorbell ACK timeout (count=%d), IntStatus=%x!\n", + ioc->name, count, intstat); return -1; } @@ -3916,7 +3738,7 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int { int cntdn; int count = 0; - u32 intstat; + u32 intstat=0; cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * howlong; if (sleepFlag == CAN_SLEEP) { @@ -3939,13 +3761,13 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int } if (cntdn) { - dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d)\n", - ioc->name, count)); + dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n", + ioc->name, count, howlong)); return count; } - printk(MYIOC_s_ERR_FMT "Doorbell INT timeout(%d)!\n", - ioc->name, (count+5)/HZ); + printk(MYIOC_s_ERR_FMT "Doorbell INT timeout (count=%d), IntStatus=%x!\n", + ioc->name, count, intstat); return -1; } @@ -3983,7 +3805,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, i } else { hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); - if ((t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0) + if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) failcnt++; else { hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); @@ -3991,8 +3813,8 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, i } } - dhsprintk((MYIOC_s_INFO_FMT "First handshake reply word=%08x%s\n", - ioc->name, le32_to_cpu(*(u32 *)hs_reply), + dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n", + ioc->name, t, le32_to_cpu(*(u32 *)hs_reply), failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); /* @@ -4000,7 +3822,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, i * reply 16 bits at a time. */ for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) { - if ((t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0) + if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) failcnt++; hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); /* don't overflow our IOC hs_reply[] buffer! */ @@ -4009,7 +3831,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, i CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); } - if (!failcnt && (t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0) + if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) failcnt++; CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); @@ -4030,8 +3852,8 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, i dmfprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name)); DBG_DUMP_REPLY_FRAME(mptReply) - dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY (sz=%d)\n", - ioc->name, u16cnt/2)); + dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n", + ioc->name, t, u16cnt/2)); return u16cnt/2; } @@ -4374,6 +4196,8 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities); pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface); + if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) + ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS; ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0; data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK; if (data) { @@ -4517,10 +4341,11 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTE * -EFAULT if read of config page header fails or data pointer not NULL * -ENOMEM if pci_alloc failed */ -static int +int mpt_findImVolumes(MPT_ADAPTER *ioc) { IOCPage2_t *pIoc2; + u8 *mem; ConfigPageIoc2RaidVol_t *pIocRv; dma_addr_t ioc2_dma; CONFIGPARMS cfg; @@ -4531,9 +4356,6 @@ mpt_findImVolumes(MPT_ADAPTER *ioc) u8 nVols, nPhys; u8 vid, vbus, vioc; - if (ioc->spi_data.pIocPg3) - return -EFAULT; - /* Read IOCP2 header then the page. */ header.PageVersion = 0; @@ -4562,11 +4384,22 @@ mpt_findImVolumes(MPT_ADAPTER *ioc) if (mpt_config(ioc, &cfg) != 0) goto done_and_free; + if ( (mem = (u8 *)ioc->spi_data.pIocPg2) == NULL ) { + mem = kmalloc(iocpage2sz, GFP_ATOMIC); + if (mem) { + ioc->spi_data.pIocPg2 = (IOCPage2_t *) mem; + } else { + goto done_and_free; + } + } + memcpy(mem, (u8 *)pIoc2, iocpage2sz); + /* Identify RAID Volume Id's */ nVols = pIoc2->NumActiveVolumes; if ( nVols == 0) { - /* No RAID Volumes. Done. + /* No RAID Volume. */ + goto done_and_free; } else { /* At least 1 RAID Volume */ @@ -4591,7 +4424,7 @@ mpt_findImVolumes(MPT_ADAPTER *ioc) /* Identify Hidden Physical Disk Id's */ nPhys = pIoc2->NumActivePhysDisks; if (nPhys == 0) { - /* No physical disks. Done. + /* No physical disks. */ } else { mpt_read_ioc_pg_3(ioc); @@ -4883,7 +4716,7 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS MPT_FRAME_HDR *mf; unsigned long flags; int ii, rc; - int flagsLength; + u32 flagsLength; int in_isr; /* (Bugzilla:fibrebugs, #513) @@ -4910,9 +4743,8 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS pReq->Reserved = 0; pReq->ChainOffset = 0; pReq->Function = MPI_FUNCTION_CONFIG; - pReq->Reserved1[0] = 0; - pReq->Reserved1[1] = 0; - pReq->Reserved1[2] = 0; + pReq->ExtPageLength = 0; + pReq->ExtPageType = 0; pReq->MsgFlags = 0; for (ii=0; ii < 8; ii++) pReq->Reserved2[ii] = 0; @@ -4971,6 +4803,114 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_toolbox - Generic function to issue toolbox message + * @ioc - Pointer to an adapter structure + * @cfg - Pointer to a toolbox structure. Struct contains + * action, page address, direction, physical address + * and pointer to a configuration page header + * Page header is updated. + * + * Returns 0 for success + * -EPERM if not allowed due to ISR context + * -EAGAIN if no msg frames currently available + * -EFAULT for non-successful reply or no reply (timeout) + */ +int +mpt_toolbox(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) +{ + ToolboxIstwiReadWriteRequest_t *pReq; + u32 *toolbox_alloc; + dma_addr_t toolbox_dma; + MPT_FRAME_HDR *mf; + unsigned long flags; + int ii, rc; + u32 flagsLength; + int in_isr; + + /* (Bugzilla:fibrebugs, #513) + * Bug fix (part 1)! 20010905 -sralston + * Prevent calling wait_event() (below), if caller happens + * to be in ISR context, because that is fatal! + */ + in_isr = in_interrupt(); + if (in_isr) { + dcprintk((MYIOC_s_WARN_FMT "toobox request not allowed in ISR context!\n", + ioc->name)); + return -EPERM; + } + + /* Get and Populate a free Frame + */ + if ((mf = mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) { + dcprintk((MYIOC_s_WARN_FMT "mpt_toolbox: no msg frames!\n", + ioc->name)); + return -EAGAIN; + } + pReq = (ToolboxIstwiReadWriteRequest_t *)mf; + pReq->Tool = pCfg->action; + pReq->Reserved = 0; + pReq->ChainOffset = 0; + pReq->Function = MPI_FUNCTION_TOOLBOX; + pReq->Reserved1 = 0; + pReq->Reserved2 = 0; + pReq->MsgFlags = 0; + pReq->Flags = pCfg->dir; + pReq->BusNum = 0; + pReq->Reserved3 = 0; + pReq->NumAddressBytes = 0x01; + pReq->Reserved4 = 0; + pReq->DataLength = 0x04; + pReq->DeviceAddr = 0xB0; + pReq->Addr1 = 0; + pReq->Addr2 = 0; + pReq->Addr3 = 0; + pReq->Reserved5 = 0; + + /* Add a SGE to the config request. + */ + + flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | 4; + + mpt_add_sge((char *)&pReq->SGL, flagsLength, pCfg->physAddr); + + dcprintk((MYIOC_s_INFO_FMT "Sending Toolbox request, Tool=%x\n", + ioc->name, pReq->Tool)); + + /* Append pCfg pointer to end of mf + */ + *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg; + + /* Initalize the timer + */ + init_timer(&pCfg->timer); + pCfg->timer.data = (unsigned long) ioc; + pCfg->timer.function = mpt_timer_expired; + pCfg->wait_done = 0; + + /* Set the timer; ensure 10 second minimum */ + if (pCfg->timeout < 10) + pCfg->timer.expires = jiffies + HZ*10; + else + pCfg->timer.expires = jiffies + HZ*pCfg->timeout; + + /* Add to end of Q, set timer and then issue this command */ + spin_lock_irqsave(&ioc->FreeQlock, flags); + Q_ADD_TAIL(&ioc->configQ.head, &pCfg->linkage, Q_ITEM); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + + add_timer(&pCfg->timer); + mpt_put_msg_frame(mpt_base_index, ioc->id, mf); + wait_event(mpt_waitq, pCfg->wait_done); + + /* mf has been freed - do not access */ + + rc = pCfg->status; + + return rc; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * mpt_timer_expired - Call back for timer process. * Used only internal config functionality. @@ -5753,109 +5693,11 @@ mpt_fc_log_info(MPT_ADAPTER *ioc, u32 lo "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer", "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info" }; - char *desc = "unknown"; u8 subcl = (log_info >> 24) & 0x7; u32 SubCl = log_info & 0x27000000; - switch(log_info) { -/* FCP Initiator */ - case MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME: - desc = "Received an out of order frame - unsupported"; - break; - case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME: - desc = "Bad start of frame primative"; - break; - case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME: - desc = "Bad end of frame primative"; - break; - case MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN: - desc = "Receiver hardware detected overrun"; - break; - case MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER: - desc = "Other errors caught by IOC which require retries"; - break; - case MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD: - desc = "Main processor could not initialize sub-processor"; - break; -/* FC Target */ - case MPI_IOCLOGINFO_FC_TARGET_NO_PDISC: - desc = "Not sent because we are waiting for a PDISC from the initiator"; - break; - case MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN: - desc = "Not sent because we are not logged in to the remote node"; - break; - case MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP: - desc = "Data Out, Auto Response, not sent due to a LIP"; - break; - case MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP: - desc = "Data In, Auto Response, not sent due to a LIP"; - break; - case MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA: - desc = "Data In, Auto Response, missing data frames"; - break; - case MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP: - desc = "Data Out, No Response, not sent due to a LIP"; - break; - case MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP: - desc = "Auto-response after a write not sent due to a LIP"; - break; - case MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP: - desc = "Data In, No Response, not completed due to a LIP"; - break; - case MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA: - desc = "Data In, No Response, missing data frames"; - break; - case MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP: - desc = "Manual Response not sent due to a LIP"; - break; - case MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3: - desc = "Not sent because remote node does not support Class 3"; - break; - case MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID: - desc = "Not sent because login to remote node not validated"; - break; - case MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND: - desc = "Cleared from the outbound queue after a logout"; - break; - case MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN: - desc = "Cleared waiting for data after a logout"; - break; -/* LAN */ - case MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING: - desc = "Transaction Context Sgl Missing"; - break; - case MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE: - desc = "Transaction Context found before an EOB"; - break; - case MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET: - desc = "Transaction Context value has reserved bits set"; - break; - case MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG: - desc = "Invalid SGL Flags"; - break; -/* FC Link */ - case MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT: - desc = "Loop initialization timed out"; - break; - case MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED: - desc = "Another system controller already initialized the loop"; - break; - case MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED: - desc = "Not synchronized to signal or still negotiating (possible cable problem)"; - break; - case MPI_IOCLOGINFO_FC_LINK_CRC_ERROR: - desc = "CRC check detected error on received frame"; - break; - } - printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}", ioc->name, log_info, subcl_str[subcl]); - if (SubCl == MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET) - printk(", byte_offset=%d\n", log_info & MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET); - else if (SubCl == MPI_IOCLOGINFO_FC_STATE_CHANGE) - printk("\n"); /* StateChg in LogInfo & 0x00FFFFFF, above */ - else - printk("\n" KERN_INFO " %s\n", desc); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -5984,6 +5826,8 @@ EXPORT_SYMBOL(mpt_lan_index); EXPORT_SYMBOL(mpt_stm_index); EXPORT_SYMBOL(mpt_HardResetHandler); EXPORT_SYMBOL(mpt_config); +EXPORT_SYMBOL(mpt_toolbox); +EXPORT_SYMBOL(mpt_findImVolumes); EXPORT_SYMBOL(mpt_read_ioc_pg_3); EXPORT_SYMBOL(mpt_alloc_fw_memory); EXPORT_SYMBOL(mpt_free_fw_memory); @@ -6055,8 +5899,9 @@ fusion_exit(void) { MPT_ADAPTER *this; struct pci_dev *pdev; + int ii; - dprintk((KERN_INFO MYNAM ": fusion_exit() called!\n")); + dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n")); /* Whups? 20010120 -sralston * Moved this *above* removal of all MptAdapters! @@ -6064,23 +5909,40 @@ fusion_exit(void) #ifdef CONFIG_PROC_FS (void) procmpt_destroy(); #endif + /* Find onboard HBAs */ + for (ii=0; ii < MPT_MAX_ADAPTERS; ii++) { + if ( (this = mpt_adapters[ii]) ) { + if (this->cached_fw != NULL) { + if (this->alt_ioc) { + pdev = (struct pci_dev *)this->alt_ioc->pcidev; + mpt_sync_irq(pdev->irq); + + dexitprintk((MYIOC_s_INFO_FMT "Calling mpt_adapter_dispose for alt_ioc %d\n", this->name, this->alt_ioc->id)); + + Q_DEL_ITEM(this->alt_ioc); + mpt_adapter_dispose(this->alt_ioc); + } + pdev = (struct pci_dev *)this->pcidev; + mpt_sync_irq(pdev->irq); + + dexitprintk((MYIOC_s_INFO_FMT "Calling mpt_adapter_dispose for on-board ioc %d\n", this->name, ii)); + + Q_DEL_ITEM(this); + mpt_adapter_dispose(this); + } + } + } + while (! Q_IS_EMPTY(&MptAdapters)) { this = MptAdapters.head; - /* Disable interrupts! */ - CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF); - this->active = 0; pdev = (struct pci_dev *)this->pcidev; mpt_sync_irq(pdev->irq); - /* Clear any lingering interrupt */ - CHIPREG_WRITE32(&this->chip->IntStatus, 0); - - CHIPREG_READ32(&this->chip->IntStatus); - + dexitprintk((MYIOC_s_INFO_FMT "Calling mpt_adapter_dispose for ioc %d\n", this->name,this->id)); Q_DEL_ITEM(this); mpt_adapter_dispose(this); } diff -Naur -p -X /home/marcelo/lib/dontdiff linux-2.4.26/drivers/message/fusion/mptbase.h linux-2.4.27-pre5/drivers/message/fusion/mptbase.h --- linux-2.4.26/drivers/message/fusion/mptbase.h 2004-02-18 13:36:31.000000000 +0000 +++ linux-2.4.27-pre5/drivers/message/fusion/mptbase.h 2004-06-03 01:32:51.000000000 +0000 @@ -8,7 +8,7 @@ * Credits: * (see mptbase.c) * - * Copyright (c) 1999-2002 LSI Logic Corporation + * Copyright (c) 1999-2004 LSI Logic Corporation * Originally By: Steven J. Ralston * (mailto:sjralston1@netscape.net) * (mailto:mpt_linux_developer@lsil.com) @@ -68,6 +68,7 @@ #include "lsi/mpi_fc.h" /* Fibre Channel (lowlevel) support */ #include "lsi/mpi_targ.h" /* SCSI/FCP Target protcol support */ +#include "lsi/mpi_tool.h" /* Tools support */ #include "lsi/fc_log.h" /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -77,11 +78,11 @@ #endif #ifndef COPYRIGHT -#define COPYRIGHT "Copyright (c) 1999-2003 " MODULEAUTHOR +#define COPYRIGHT "Copyright (c) 1999-2004 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "2.05.11.03" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-2.05.11.03" +#define MPT_LINUX_VERSION_COMMON "2.05.16" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-2.05.16" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -152,6 +153,9 @@ #define MPT_NARROW 0 #define MPT_WIDE 1 +#define C0_1030 0x08 +#define XL_929 0x01 + #ifdef __KERNEL__ /* { */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -527,6 +531,7 @@ typedef struct _mpt_ioctl_events { typedef struct _ScsiCfgData { u32 PortFlags; int *nvram; /* table of device NVRAM values */ + IOCPage2_t *pIocPg2; /* table of Raid Volumes */ IOCPage3_t *pIocPg3; /* table of physical disks */ IOCPage4_t *pIocPg4; /* SEP devices addressing */ dma_addr_t IocPg4_dma; /* Phys Addr of IOCPage4 data */ @@ -548,13 +553,6 @@ typedef struct _ScsiCfgData { u8 rsvd[1]; } ScsiCfgData; -typedef struct _fw_image { - char *fw; - dma_addr_t fw_dma; - u32 size; - u32 rsvd; -} fw_image_t; - /* * Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS */ @@ -620,9 +618,9 @@ typedef struct _MPT_ADAPTER int timeout_maxcnt; #endif struct _mpt_ioctl_events *events; /* pointer to event log */ - fw_image_t **cached_fw; /* Pointer to FW SG List */ + u8 *cached_fw; /* Pointer to FW */ + dma_addr_t cached_fw_dma; Q_TRACKER configQ; /* linked list of config. requests */ - int num_fw_frags; /* Number of SGE in FW SG List */ int hs_reply_idx; #ifndef MFCNT u32 pad0; @@ -700,6 +698,33 @@ typedef struct _mpt_sge { #define dprintk(x) #endif +#ifdef MPT_DEBUG_INIT +#define dinitprintk(x) printk x +#define DBG_DUMP_FW_REQUEST_FRAME(mfp) \ + { int i, n = 10; \ + u32 *m = (u32 *)(mfp); \ + printk(KERN_INFO " "); \ + for (i=0; iid])) + rc = -ERESTARTSYS; + } else { + rc = -EPERM; + } +#else if (nonblock) { if (down_trylock(&mptctl_syscall_sem_ioc[ioc->id])) rc = -EAGAIN; @@ -216,6 +224,7 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, in if (down_interruptible(&mptctl_syscall_sem_ioc[ioc->id])) rc = -ERESTARTSYS; } +#endif dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down return %d\n", rc)); return rc; } @@ -1357,16 +1366,19 @@ mptctl_gettargetinfo (unsigned long arg) MPT_ADAPTER *ioc; struct Scsi_Host *sh; MPT_SCSI_HOST *hd; + VirtDevice *vdev; char *pmem; int *pdata; + IOCPage2_t *pIoc2; + IOCPage3_t *pIoc3; int iocnum; int numDevices = 0; unsigned int max_id; - int ii, jj, indexed_lun, lun_index; + int id, jj, indexed_lun, lun_index; u32 lun; int maxWordsLeft; int numBytes; - u8 port; + u8 port, devType, bus_id; dctlprintk(("mptctl_gettargetinfo called.\n")); if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) { @@ -1433,29 +1445,63 @@ mptctl_gettargetinfo (unsigned long arg) * sh->max_id = maximum target ID + 1 */ if (hd && hd->Targets) { - ii = 0; - while (ii <= max_id) { - if (hd->Targets[ii]) { + mpt_findImVolumes(ioc); + pIoc2 = ioc->spi_data.pIocPg2; + for ( id = 0; id <= max_id; ) { + if ( pIoc2 && pIoc2->NumActiveVolumes ) { + if ( id == pIoc2->RaidVolume[0].VolumeID ) { + if (maxWordsLeft <= 0) { + printk(KERN_ERR "mptctl_gettargetinfo - " + "buffer is full but volume is available on ioc %d\n, numDevices=%d", iocnum, numDevices); + goto data_space_full; + } + if ( ( pIoc2->RaidVolume[0].Flags & MPI_IOCPAGE2_FLAG_VOLUME_INACTIVE ) == 0 ) + devType = 0x80; + else + devType = 0xC0; + bus_id = pIoc2->RaidVolume[0].VolumeBus; + numDevices++; + *pdata = ( (devType << 24) | (bus_id << 8) | id ); + dctlprintk((KERN_ERR "mptctl_gettargetinfo - " + "volume ioc=%d target=%x numDevices=%d pdata=%p\n", iocnum, *pdata, numDevices, pdata)); + pdata++; + --maxWordsLeft; + goto next_id; + } else { + pIoc3 = ioc->spi_data.pIocPg3; + for ( jj = 0; jj < pIoc3->NumPhysDisks; jj++ ) { + if ( pIoc3->PhysDisk[jj].PhysDiskID == id ) + goto next_id; + } + } + } + if ( (vdev = hd->Targets[id]) ) { for (jj = 0; jj <= MPT_LAST_LUN; jj++) { lun_index = (jj >> 5); indexed_lun = (jj % 32); lun = (1 << indexed_lun); - if (hd->Targets[ii]->luns[lun_index] & lun) { + if (vdev->luns[lun_index] & lun) { + if (maxWordsLeft <= 0) { + printk(KERN_ERR "mptctl_gettargetinfo - " + "buffer is full but more targets are available on ioc %d numDevices=%d\n", iocnum, numDevices); + goto data_space_full; + } + bus_id = vdev->bus_id; numDevices++; - *pdata = (jj << 16) | ii; - --maxWordsLeft; - + *pdata = ( (jj << 16) | (bus_id << 8) | id ); + dctlprintk((KERN_ERR "mptctl_gettargetinfo - " + "target ioc=%d target=%x numDevices=%d pdata=%p\n", iocnum, *pdata, numDevices, pdata)); pdata++; - - if (maxWordsLeft <= 0) - break; + --maxWordsLeft; } } } - ii++; +next_id: + id++; } } } +data_space_full: karg.numDevices = numDevices; /* Copy part of the data from kernel memory to user memory @@ -1693,12 +1739,11 @@ mptctl_replace_fw (unsigned long arg) struct mpt_ioctl_replace_fw *uarg = (struct mpt_ioctl_replace_fw *) arg; struct mpt_ioctl_replace_fw karg; MPT_ADAPTER *ioc; - fw_image_t **fwmem = NULL; + u8 *fwmem = NULL; int iocnum; int newFwSize; - int num_frags, alloc_sz; + int alloc_sz; int ii; - u32 offset; dctlprintk(("mptctl_replace_fw called.\n")); if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_replace_