diff --git a/CREDITS b/CREDITS index 5b1edf3a38a22bc9f7a7d668d4290434342d1bf1..7fb4c73e02288494856ae67eb9a37e461035f2b5 100644 --- a/CREDITS +++ b/CREDITS @@ -3642,11 +3642,9 @@ S: Beaverton, OR 97005 S: USA N: Michal Wronski -E: wrona@mat.uni.torun.pl -W: http://www.mat.uni.torun.pl/~wrona +E: Michal.Wronski@motorola.com D: POSIX message queues fs (with K. Benedyczak) -S: ul. Teczowa 23/12 -S: 80-680 Gdansk-Sobieszewo +S: Krakow S: Poland N: Frank Xia diff --git a/Documentation/Changes b/Documentation/Changes index 783ddc3ce4e821a8b8c2a04881e494ab4f503c2c..86b86399d61d7237aab919f87867bd984dddaa25 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -139,9 +139,14 @@ You'll probably want to upgrade. Ksymoops -------- -If the unthinkable happens and your kernel oopses, you'll need a 2.4 -version of ksymoops to decode the report; see REPORTING-BUGS in the -root of the Linux source for more information. +If the unthinkable happens and your kernel oopses, you may need the +ksymoops tool to decode it, but in most cases you don't. +In the 2.6 kernel it is generally preferred to build the kernel with +CONFIG_KALLSYMS so that it produces readable dumps that can be used as-is +(this also produces better output than ksymoops). +If for some reason your kernel is not build with CONFIG_KALLSYMS and +you have no way to rebuild and reproduce the Oops with that option, then +you can still decode that Oops with ksymoops. Module-Init-Tools ----------------- diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index fa3e29ad8a463855c48241fb49ebfd3fd8ba86bb..7018f5c6a447b392a8ccd316d49380ce5307e936 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -10,7 +10,7 @@ DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \ kernel-hacking.xml kernel-locking.xml deviceiobook.xml \ procfs-guide.xml writing_usb_driver.xml \ sis900.xml kernel-api.xml journal-api.xml lsm.xml usb.xml \ - gadget.xml libata.xml mtdnand.xml librs.xml + gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml ### # The build process is as follows (targets): diff --git a/Documentation/DocBook/journal-api.tmpl b/Documentation/DocBook/journal-api.tmpl index 341aaa4ce481a5a9af1f85d17be35e83e2b8b075..2077f9a28c191bdba263271e649f015485052926 100644 --- a/Documentation/DocBook/journal-api.tmpl +++ b/Documentation/DocBook/journal-api.tmpl @@ -306,7 +306,7 @@ an example. Journal Level !Efs/jbd/journal.c -!Efs/jbd/recovery.c +!Ifs/jbd/recovery.c Transasction Level !Efs/jbd/transaction.c diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index ec474e5a25ed39db151790e83bfe6e882fc34ffa..a8316b1a3e3d45e3368a1a4b3dddb732bab65b32 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -118,7 +118,7 @@ X!Ilib/string.c User Space Memory Access !Iinclude/asm-i386/uaccess.h -!Iarch/i386/lib/usercopy.c +!Earch/i386/lib/usercopy.c More Memory Management Functions !Iinclude/linux/rmap.h @@ -174,7 +174,6 @@ X!Ilib/string.c The Linux VFS The Filesystem types !Iinclude/linux/fs.h -!Einclude/linux/fs.h The Directory Cache !Efs/dcache.c @@ -266,7 +265,7 @@ X!Ekernel/module.c Hardware Interfaces Interrupt Handling -!Ikernel/irq/manage.c +!Ekernel/irq/manage.c Resources Management @@ -501,7 +500,7 @@ KAO --> !Edrivers/video/modedb.c Frame Buffer Macintosh Video Mode Database -!Idrivers/video/macmodes.c +!Edrivers/video/macmodes.c Frame Buffer Fonts diff --git a/Documentation/DocBook/rapidio.tmpl b/Documentation/DocBook/rapidio.tmpl new file mode 100644 index 0000000000000000000000000000000000000000..1becf27ba27ea60e9b1dc75dac3be7caccdc5e66 --- /dev/null +++ b/Documentation/DocBook/rapidio.tmpl @@ -0,0 +1,160 @@ + + + ]> + + + + RapidIO Subsystem Guide + + + + Matt + Porter + +
+ mporter@kernel.crashing.org + mporter@mvista.com +
+
+
+
+ + + 2005 + MontaVista Software, Inc. + + + + + This documentation is free software; you can redistribute + it and/or modify it under the terms of the GNU General Public + License version 2 as published by the Free Software Foundation. + + + + This program is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, + MA 02111-1307 USA + + + + For more details see the file COPYING in the source + distribution of Linux. + + +
+ + + + + Introduction + + RapidIO is a high speed switched fabric interconnect with + features aimed at the embedded market. RapidIO provides + support for memory-mapped I/O as well as message-based + transactions over the switched fabric network. RapidIO has + a standardized discovery mechanism not unlike the PCI bus + standard that allows simple detection of devices in a + network. + + + This documentation is provided for developers intending + to support RapidIO on new architectures, write new drivers, + or to understand the subsystem internals. + + + + + Known Bugs and Limitations + + + Bugs + None. ;) + + + Limitations + + + Access/management of RapidIO memory regions is not supported + Multiple host enumeration is not supported + + + + + + + RapidIO driver interface + + Drivers are provided a set of calls in order + to interface with the subsystem to gather info + on devices, request/map memory region resources, + and manage mailboxes/doorbells. + + + Functions +!Iinclude/linux/rio_drv.h +!Edrivers/rapidio/rio-driver.c +!Edrivers/rapidio/rio.c + + + + + Internals + + + This chapter contains the autogenerated documentation of the RapidIO + subsystem. + + + Structures +!Iinclude/linux/rio.h + + Enumeration and Discovery +!Idrivers/rapidio/rio-scan.c + + Driver functionality +!Idrivers/rapidio/rio.c +!Idrivers/rapidio/rio-access.c + + Device model support +!Idrivers/rapidio/rio-driver.c + + Sysfs support +!Idrivers/rapidio/rio-sysfs.c + + PPC32 support +!Iarch/ppc/kernel/rio.c +!Earch/ppc/syslib/ppc85xx_rio.c +!Iarch/ppc/syslib/ppc85xx_rio.c + + + + + Credits + + The following people have contributed to the RapidIO + subsystem directly or indirectly: + + Matt Portermporter@kernel.crashing.org + Randy Vinsonrvinson@mvista.com + Dan Malekdan@embeddedalley.com + + + + The following people have contributed to this document: + + Matt Portermporter@kernel.crashing.org + + + +
diff --git a/Documentation/MSI-HOWTO.txt b/Documentation/MSI-HOWTO.txt index 63edc5f847c45a4b1771c4e35872317ca2bbcbc7..3ec6c720b0166b4a76c576391414c795898d47b5 100644 --- a/Documentation/MSI-HOWTO.txt +++ b/Documentation/MSI-HOWTO.txt @@ -10,14 +10,22 @@ This guide describes the basics of Message Signaled Interrupts (MSI), the advantages of using MSI over traditional interrupt mechanisms, and how to enable your driver to use MSI or MSI-X. Also included is -a Frequently Asked Questions. +a Frequently Asked Questions (FAQ) section. + +1.1 Terminology + +PCI devices can be single-function or multi-function. In either case, +when this text talks about enabling or disabling MSI on a "device +function," it is referring to one specific PCI device and function and +not to all functions on a PCI device (unless the PCI device has only +one function). 2. Copyright 2003 Intel Corporation 3. What is MSI/MSI-X? Message Signaled Interrupt (MSI), as described in the PCI Local Bus -Specification Revision 2.3 or latest, is an optional feature, and a +Specification Revision 2.3 or later, is an optional feature, and a required feature for PCI Express devices. MSI enables a device function to request service by sending an Inbound Memory Write on its PCI bus to the FSB as a Message Signal Interrupt transaction. Because MSI is @@ -27,7 +35,7 @@ supported. A PCI device that supports MSI must also support pin IRQ assertion interrupt mechanism to provide backward compatibility for systems that -do not support MSI. In Systems, which support MSI, the bus driver is +do not support MSI. In systems which support MSI, the bus driver is responsible for initializing the message address and message data of the device function's MSI/MSI-X capability structure during device initial configuration. @@ -61,17 +69,17 @@ over the MSI capability structure as described below. - MSI and MSI-X both support per-vector masking. Per-vector masking is an optional extension of MSI but a required - feature for MSI-X. Per-vector masking provides the kernel - the ability to mask/unmask MSI when servicing its software - interrupt service routing handler. If per-vector masking is + feature for MSI-X. Per-vector masking provides the kernel the + ability to mask/unmask a single MSI while running its + interrupt service routine. If per-vector masking is not supported, then the device driver should provide the hardware/software synchronization to ensure that the device generates MSI when the driver wants it to do so. 4. Why use MSI? -As a benefit the simplification of board design, MSI allows board -designers to remove out of band interrupt routing. MSI is another +As a benefit to the simplification of board design, MSI allows board +designers to remove out-of-band interrupt routing. MSI is another step towards a legacy-free environment. Due to increasing pressure on chipset and processor packages to @@ -87,7 +95,7 @@ support. As a result, the PCI Express technology requires MSI support for better interrupt performance. Using MSI enables the device functions to support two or more -vectors, which can be configured to target different CPU's to +vectors, which can be configured to target different CPUs to increase scalability. 5. Configuring a driver to use MSI/MSI-X @@ -119,13 +127,13 @@ pci_enable_msi() explicitly. int pci_enable_msi(struct pci_dev *dev) -With this new API, any existing device driver, which like to have -MSI enabled on its device function, must call this API to enable MSI +With this new API, a device driver that wants to have MSI +enabled on its device function must call this API to enable MSI. A successful call will initialize the MSI capability structure with ONE vector, regardless of whether a device function is capable of supporting multiple messages. This vector replaces the -pre-assigned dev->irq with a new MSI vector. To avoid the conflict -of new assigned vector with existing pre-assigned vector requires +pre-assigned dev->irq with a new MSI vector. To avoid a conflict +of the new assigned vector with existing pre-assigned vector requires a device driver to call this API before calling request_irq(). 5.2.2 API pci_disable_msi @@ -137,14 +145,14 @@ when a device driver is unloading. This API restores dev->irq with the pre-assigned IOAPIC vector and switches a device's interrupt mode to PCI pin-irq assertion/INTx emulation mode. -Note that a device driver should always call free_irq() on MSI vector -it has done request_irq() on before calling this API. Failure to do -so results a BUG_ON() and a device will be left with MSI enabled and +Note that a device driver should always call free_irq() on the MSI vector +that it has done request_irq() on before calling this API. Failure to do +so results in a BUG_ON() and a device will be left with MSI enabled and leaks its vector. 5.2.3 MSI mode vs. legacy mode diagram -The below diagram shows the events, which switches the interrupt +The below diagram shows the events which switch the interrupt mode on the MSI-capable device function between MSI mode and PIN-IRQ assertion mode. @@ -155,9 +163,9 @@ PIN-IRQ assertion mode. ------------ pci_disable_msi ------------------------ -Figure 1.0 MSI Mode vs. Legacy Mode +Figure 1. MSI Mode vs. Legacy Mode -In Figure 1.0, a device operates by default in legacy mode. Legacy +In Figure 1, a device operates by default in legacy mode. Legacy in this context means PCI pin-irq assertion or PCI-Express INTx emulation. A successful MSI request (using pci_enable_msi()) switches a device's interrupt mode to MSI mode. A pre-assigned IOAPIC vector @@ -166,11 +174,11 @@ assigned MSI vector will replace dev->irq. To return back to its default mode, a device driver should always call pci_disable_msi() to undo the effect of pci_enable_msi(). Note that a -device driver should always call free_irq() on MSI vector it has done -request_irq() on before calling pci_disable_msi(). Failure to do so -results a BUG_ON() and a device will be left with MSI enabled and +device driver should always call free_irq() on the MSI vector it has +done request_irq() on before calling pci_disable_msi(). Failure to do +so results in a BUG_ON() and a device will be left with MSI enabled and leaks its vector. Otherwise, the PCI subsystem restores a device's -dev->irq with a pre-assigned IOAPIC vector and marks released +dev->irq with a pre-assigned IOAPIC vector and marks the released MSI vector as unused. Once being marked as unused, there is no guarantee that the PCI @@ -178,8 +186,8 @@ subsystem will reserve this MSI vector for a device. Depending on the availability of current PCI vector resources and the number of MSI/MSI-X requests from other drivers, this MSI may be re-assigned. -For the case where the PCI subsystem re-assigned this MSI vector -another driver, a request to switching back to MSI mode may result +For the case where the PCI subsystem re-assigns this MSI vector to +another driver, a request to switch back to MSI mode may result in being assigned a different MSI vector or a failure if no more vectors are available. @@ -208,12 +216,12 @@ Unlike the function pci_enable_msi(), the function pci_enable_msix() does not replace the pre-assigned IOAPIC dev->irq with a new MSI vector because the PCI subsystem writes the 1:1 vector-to-entry mapping into the field vector of each element contained in a second argument. -Note that the pre-assigned IO-APIC dev->irq is valid only if the device -operates in PIN-IRQ assertion mode. In MSI-X mode, any attempt of +Note that the pre-assigned IOAPIC dev->irq is valid only if the device +operates in PIN-IRQ assertion mode. In MSI-X mode, any attempt at using dev->irq by the device driver to request for interrupt service may result unpredictabe behavior. -For each MSI-X vector granted, a device driver is responsible to call +For each MSI-X vector granted, a device driver is responsible for calling other functions like request_irq(), enable_irq(), etc. to enable this vector with its corresponding interrupt service handler. It is a device driver's choice to assign all vectors with the same @@ -224,13 +232,13 @@ service handler. The PCI 3.0 specification has implementation notes that MMIO address space for a device's MSI-X structure should be isolated so that the -software system can set different page for controlling accesses to -the MSI-X structure. The implementation of MSI patch requires the PCI +software system can set different pages for controlling accesses to the +MSI-X structure. The implementation of MSI support requires the PCI subsystem, not a device driver, to maintain full control of the MSI-X -table/MSI-X PBA and MMIO address space of the MSI-X table/MSI-X PBA. -A device driver is prohibited from requesting the MMIO address space -of the MSI-X table/MSI-X PBA. Otherwise, the PCI subsystem will fail -enabling MSI-X on its hardware device when it calls the function +table/MSI-X PBA (Pending Bit Array) and MMIO address space of the MSI-X +table/MSI-X PBA. A device driver is prohibited from requesting the MMIO +address space of the MSI-X table/MSI-X PBA. Otherwise, the PCI subsystem +will fail enabling MSI-X on its hardware device when it calls the function pci_enable_msix(). 5.3.2 Handling MSI-X allocation @@ -274,9 +282,9 @@ For the case where fewer MSI-X vectors are allocated to a function than requested, the function pci_enable_msix() will return the maximum number of MSI-X vectors available to the caller. A device driver may re-send its request with fewer or equal vectors indicated -in a return. For example, if a device driver requests 5 vectors, but -the number of available vectors is 3 vectors, a value of 3 will be a -return as a result of pci_enable_msix() call. A function could be +in the return. For example, if a device driver requests 5 vectors, but +the number of available vectors is 3 vectors, a value of 3 will be +returned as a result of pci_enable_msix() call. A function could be designed for its driver to use only 3 MSI-X table entries as different combinations as ABC--, A-B-C, A--CB, etc. Note that this patch does not support multiple entries with the same vector. Such @@ -285,49 +293,46 @@ as ABBCC, AABCC, BCCBA, etc will result as a failure by the function pci_enable_msix(). Below are the reasons why supporting multiple entries with the same vector is an undesirable solution. - - The PCI subsystem can not determine which entry, which - generated the message, to mask/unmask MSI while handling + - The PCI subsystem cannot determine the entry that + generated the message to mask/unmask MSI while handling software driver ISR. Attempting to walk through all MSI-X table entries (2048 max) to mask/unmask any match vector is an undesirable solution. - - Walk through all MSI-X table entries (2048 max) to handle + - Walking through all MSI-X table entries (2048 max) to handle SMP affinity of any match vector is an undesirable solution. 5.3.4 API pci_enable_msix -int pci_enable_msix(struct pci_dev *dev, u32 *entries, int nvec) +int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec) This API enables a device driver to request the PCI subsystem -for enabling MSI-X messages on its hardware device. Depending on +to enable MSI-X messages on its hardware device. Depending on the availability of PCI vectors resources, the PCI subsystem enables -either all or nothing. +either all or none of the requested vectors. -Argument dev points to the device (pci_dev) structure. +Argument 'dev' points to the device (pci_dev) structure. -Argument entries is a pointer of unsigned integer type. The number of -elements is indicated in argument nvec. The content of each element -will be mapped to the following struct defined in /driver/pci/msi.h. +Argument 'entries' is a pointer to an array of msix_entry structs. +The number of entries is indicated in argument 'nvec'. +struct msix_entry is defined in /driver/pci/msi.h: struct msix_entry { u16 vector; /* kernel uses to write alloc vector */ u16 entry; /* driver uses to specify entry */ }; -A device driver is responsible for initializing the field entry of -each element with unique entry supported by MSI-X table. Otherwise, +A device driver is responsible for initializing the field 'entry' of +each element with a unique entry supported by MSI-X table. Otherwise, -EINVAL will be returned as a result. A successful return of zero -indicates the PCI subsystem completes initializing each of requested +indicates the PCI subsystem completed initializing each of the requested entries of the MSI-X table with message address and message data. Last but not least, the PCI subsystem will write the 1:1 -vector-to-entry mapping into the field vector of each element. A -device driver is responsible of keeping track of allocated MSI-X +vector-to-entry mapping into the field 'vector' of each element. A +device driver is responsible for keeping track of allocated MSI-X vectors in its internal data structure. -Argument nvec is an integer indicating the number of messages -requested. - -A return of zero indicates that the number of MSI-X vectors is +A return of zero indicates that the number of MSI-X vectors was successfully allocated. A return of greater than zero indicates MSI-X vector shortage. Or a return of less than zero indicates a failure. This failure may be a result of duplicate entries @@ -341,12 +346,12 @@ void pci_disable_msix(struct pci_dev *dev) This API should always be used to undo the effect of pci_enable_msix() when a device driver is unloading. Note that a device driver should always call free_irq() on all MSI-X vectors it has done request_irq() -on before calling this API. Failure to do so results a BUG_ON() and +on before calling this API. Failure to do so results in a BUG_ON() and a device will be left with MSI-X enabled and leaks its vectors. 5.3.6 MSI-X mode vs. legacy mode diagram -The below diagram shows the events, which switches the interrupt +The below diagram shows the events which switch the interrupt mode on the MSI-X capable device function between MSI-X mode and PIN-IRQ assertion mode (legacy). @@ -356,22 +361,22 @@ PIN-IRQ assertion mode (legacy). | | ===============> | | ------------ pci_disable_msix ------------------------ -Figure 2.0 MSI-X Mode vs. Legacy Mode +Figure 2. MSI-X Mode vs. Legacy Mode -In Figure 2.0, a device operates by default in legacy mode. A +In Figure 2, a device operates by default in legacy mode. A successful MSI-X request (using pci_enable_msix()) switches a device's interrupt mode to MSI-X mode. A pre-assigned IOAPIC vector stored in dev->irq will be saved by the PCI subsystem; however, unlike MSI mode, the PCI subsystem will not replace dev->irq with assigned MSI-X vector because the PCI subsystem already writes the 1:1 -vector-to-entry mapping into the field vector of each element +vector-to-entry mapping into the field 'vector' of each element specified in second argument. To return back to its default mode, a device driver should always call pci_disable_msix() to undo the effect of pci_enable_msix(). Note that a device driver should always call free_irq() on all MSI-X vectors it has done request_irq() on before calling pci_disable_msix(). Failure -to do so results a BUG_ON() and a device will be left with MSI-X +to do so results in a BUG_ON() and a device will be left with MSI-X enabled and leaks its vectors. Otherwise, the PCI subsystem switches a device function's interrupt mode from MSI-X mode to legacy mode and marks all allocated MSI-X vectors as unused. @@ -383,53 +388,56 @@ MSI/MSI-X requests from other drivers, these MSI-X vectors may be re-assigned. For the case where the PCI subsystem re-assigned these MSI-X vectors -to other driver, a request to switching back to MSI-X mode may result +to other drivers, a request to switch back to MSI-X mode may result being assigned with another set of MSI-X vectors or a failure if no more vectors are available. -5.4 Handling function implementng both MSI and MSI-X capabilities +5.4 Handling function implementing both MSI and MSI-X capabilities For the case where a function implements both MSI and MSI-X capabilities, the PCI subsystem enables a device to run either in MSI mode or MSI-X mode but not both. A device driver determines whether it wants MSI or MSI-X enabled on its hardware device. Once a device -driver requests for MSI, for example, it is prohibited to request for +driver requests for MSI, for example, it is prohibited from requesting MSI-X; in other words, a device driver is not permitted to ping-pong between MSI mod MSI-X mode during a run-time. 5.5 Hardware requirements for MSI/MSI-X support + MSI/MSI-X support requires support from both system hardware and individual hardware device functions. 5.5.1 System hardware support + Since the target of MSI address is the local APIC CPU, enabling -MSI/MSI-X support in Linux kernel is dependent on whether existing -system hardware supports local APIC. Users should verify their -system whether it runs when CONFIG_X86_LOCAL_APIC=y. +MSI/MSI-X support in the Linux kernel is dependent on whether existing +system hardware supports local APIC. Users should verify that their +system supports local APIC operation by testing that it runs when +CONFIG_X86_LOCAL_APIC=y. In SMP environment, CONFIG_X86_LOCAL_APIC is automatically set; however, in UP environment, users must manually set CONFIG_X86_LOCAL_APIC. Once CONFIG_X86_LOCAL_APIC=y, setting -CONFIG_PCI_MSI enables the VECTOR based scheme and -the option for MSI-capable device drivers to selectively enable -MSI/MSI-X. +CONFIG_PCI_MSI enables the VECTOR based scheme and the option for +MSI-capable device drivers to selectively enable MSI/MSI-X. Note that CONFIG_X86_IO_APIC setting is irrelevant because MSI/MSI-X vector is allocated new during runtime and MSI/MSI-X support does not depend on BIOS support. This key independency enables MSI/MSI-X -support on future IOxAPIC free platform. +support on future IOxAPIC free platforms. 5.5.2 Device hardware support + The hardware device function supports MSI by indicating the MSI/MSI-X capability structure on its PCI capability list. By default, this capability structure will not be initialized by the kernel to enable MSI during the system boot. In other words, the device function is running on its default pin assertion mode. Note that in many cases the hardware supporting MSI have bugs, -which may result in system hang. The software driver of specific -MSI-capable hardware is responsible for whether calling +which may result in system hangs. The software driver of specific +MSI-capable hardware is responsible for deciding whether to call pci_enable_msi or not. A return of zero indicates the kernel -successfully initializes the MSI/MSI-X capability structure of the +successfully initialized the MSI/MSI-X capability structure of the device function. The device function is now running on MSI/MSI-X mode. 5.6 How to tell whether MSI/MSI-X is enabled on device function @@ -439,10 +447,10 @@ pci_enable_msi()/pci_enable_msix() indicates to a device driver that its device function is initialized successfully and ready to run in MSI/MSI-X mode. -At the user level, users can use command 'cat /proc/interrupts' -to display the vector allocated for a device and its interrupt -MSI/MSI-X mode ("PCI MSI"/"PCI MSIX"). Below shows below MSI mode is -enabled on a SCSI Adaptec 39320D Ultra320. +At the user level, users can use the command 'cat /proc/interrupts' +to display the vectors allocated for devices and their interrupt +MSI/MSI-X modes ("PCI-MSI"/"PCI-MSI-X"). Below shows MSI mode is +enabled on a SCSI Adaptec 39320D Ultra320 controller. CPU0 CPU1 0: 324639 0 IO-APIC-edge timer @@ -453,8 +461,8 @@ enabled on a SCSI Adaptec 39320D Ultra320. 15: 1 0 IO-APIC-edge ide1 169: 0 0 IO-APIC-level uhci-hcd 185: 0 0 IO-APIC-level uhci-hcd -193: 138 10 PCI MSI aic79xx -201: 30 0 PCI MSI aic79xx +193: 138 10 PCI-MSI aic79xx +201: 30 0 PCI-MSI aic79xx 225: 30 0 IO-APIC-level aic7xxx 233: 30 0 IO-APIC-level aic7xxx NMI: 0 0 @@ -490,8 +498,8 @@ target address set as 0xfeexxxxx, as conformed to PCI specification 2.3 or latest, then it should work. Q4. From the driver point of view, if the MSI is lost because -of the errors occur during inbound memory write, then it may -wait for ever. Is there a mechanism for it to recover? +of errors occurring during inbound memory write, then it may +wait forever. Is there a mechanism for it to recover? A4. Since the target of the transaction is an inbound memory write, all transaction termination conditions (Retry, diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt index 354d89c783777489408967d012ff4d4f55392adf..15da16861fa3d6bfbec2e3f192ece4a22ace5b7f 100644 --- a/Documentation/RCU/whatisRCU.txt +++ b/Documentation/RCU/whatisRCU.txt @@ -772,8 +772,6 @@ RCU pointer/list traversal: list_for_each_entry_rcu list_for_each_continue_rcu (to be deprecated in favor of new list_for_each_entry_continue_rcu) - hlist_for_each_rcu (to be deprecated in favor of - hlist_for_each_entry_rcu) hlist_for_each_entry_rcu RCU pointer update: diff --git a/Documentation/connector/cn_test.c b/Documentation/connector/cn_test.c index b7de82e9c0e014aeff8fecfb3e7b271821b4598c..3e73231695b3107eb743452836e8d0b24d17af85 100644 --- a/Documentation/connector/cn_test.c +++ b/Documentation/connector/cn_test.c @@ -25,7 +25,7 @@ #include #include -#include "connector.h" +#include static struct cb_id cn_test_id = { 0x123, 0x456 }; static char cn_test_name[] = "cn_test"; @@ -104,7 +104,7 @@ static int cn_test_want_notify(void) req->first = cn_test_id.val + 20; req->range = 10; - NETLINK_CB(skb).dst_groups = ctl->group; + NETLINK_CB(skb).dst_group = ctl->group; //netlink_broadcast(nls, skb, 0, ctl->group, GFP_ATOMIC); netlink_unicast(nls, skb, 0, 0); diff --git a/Documentation/device-mapper/snapshot.txt b/Documentation/device-mapper/snapshot.txt index dca274ff40052e31cd3a0d6badd23003648a37a7..a5009c8300f3364a98e8982c9697f1dee789346f 100644 --- a/Documentation/device-mapper/snapshot.txt +++ b/Documentation/device-mapper/snapshot.txt @@ -19,7 +19,6 @@ There are two dm targets available: snapshot and snapshot-origin. *) snapshot-origin which will normally have one or more snapshots based on it. -You must create the snapshot-origin device before you can create snapshots. Reads will be mapped directly to the backing device. For each write, the original data will be saved in the of each snapshot to keep its visible content unchanged, at least until the fills up. @@ -27,7 +26,7 @@ its visible content unchanged, at least until the fills up. *) snapshot -A snapshot is created of the block device. Changed chunks of +A snapshot of the block device is created. Changed chunks of sectors will be stored on the . Writes will only go to the . Reads will come from the or from for unchanged data. will often be @@ -37,6 +36,8 @@ the amount of free space and expand the before it fills up. is P (Persistent) or N (Not persistent - will not survive after reboot). +The difference is that for transient snapshots less metadata must be +saved on disk - they can be kept in memory by the kernel. How this is used by LVM2 diff --git a/Documentation/fb/vesafb.txt b/Documentation/fb/vesafb.txt index 62db6758d1c1050db42b638ad4d42dc06809c68b..ee277dd204b0f575165b02f0dfc1fcb27c8d0bf8 100644 --- a/Documentation/fb/vesafb.txt +++ b/Documentation/fb/vesafb.txt @@ -146,10 +146,10 @@ pmipal Use the protected mode interface for palette changes. mtrr:n setup memory type range registers for the vesafb framebuffer where n: - 0 - disabled (equivalent to nomtrr) + 0 - disabled (equivalent to nomtrr) (default) 1 - uncachable 2 - write-back - 3 - write-combining (default) + 3 - write-combining 4 - write-through If you see the following in dmesg, choose the type that matches the diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index b67189a8d8d471789629ae23e4c1b6e9e2b713da..decdf9917e0ddd4d809a673ef0dc5538f741b34f 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -69,6 +69,22 @@ Who: Grant Coady --------------------------- +What: remove EXPORT_SYMBOL(panic_timeout) +When: April 2006 +Files: kernel/panic.c +Why: No modular usage in the kernel. +Who: Adrian Bunk + +--------------------------- + +What: remove EXPORT_SYMBOL(insert_resource) +When: April 2006 +Files: kernel/resource.c +Why: No modular usage in the kernel. +Who: Adrian Bunk + +--------------------------- + What: PCMCIA control ioctl (needed for pcmcia-cs [cardmgr, cardctl]) When: November 2005 Files: drivers/pcmcia/: pcmcia_ioctl.c diff --git a/Documentation/filesystems/dentry-locking.txt b/Documentation/filesystems/dentry-locking.txt new file mode 100644 index 0000000000000000000000000000000000000000..4c0c575a40120709120f1b8824d50df5a8906ab0 --- /dev/null +++ b/Documentation/filesystems/dentry-locking.txt @@ -0,0 +1,173 @@ +RCU-based dcache locking model +============================== + +On many workloads, the most common operation on dcache is to look up a +dentry, given a parent dentry and the name of the child. Typically, +for every open(), stat() etc., the dentry corresponding to the +pathname will be looked up by walking the tree starting with the first +component of the pathname and using that dentry along with the next +component to look up the next level and so on. Since it is a frequent +operation for workloads like multiuser environments and web servers, +it is important to optimize this path. + +Prior to 2.5.10, dcache_lock was acquired in d_lookup and thus in +every component during path look-up. Since 2.5.10 onwards, fast-walk +algorithm changed this by holding the dcache_lock at the beginning and +walking as many cached path component dentries as possible. This +significantly decreases the number of acquisition of +dcache_lock. However it also increases the lock hold time +significantly and affects performance in large SMP machines. Since +2.5.62 kernel, dcache has been using a new locking model that uses RCU +to make dcache look-up lock-free. + +The current dcache locking model is not very different from the +existing dcache locking model. Prior to 2.5.62 kernel, dcache_lock +protected the hash chain, d_child, d_alias, d_lru lists as well as +d_inode and several other things like mount look-up. RCU-based changes +affect only the way the hash chain is protected. For everything else +the dcache_lock must be taken for both traversing as well as +updating. The hash chain updates too take the dcache_lock. The +significant change is the way d_lookup traverses the hash chain, it +doesn't acquire the dcache_lock for this and rely on RCU to ensure +that the dentry has not been *freed*. + + +Dcache locking details +====================== + +For many multi-user workloads, open() and stat() on files are very +frequently occurring operations. Both involve walking of path names to +find the dentry corresponding to the concerned file. In 2.4 kernel, +dcache_lock was held during look-up of each path component. Contention +and cache-line bouncing of this global lock caused significant +scalability problems. With the introduction of RCU in Linux kernel, +this was worked around by making the look-up of path components during +path walking lock-free. + + +Safe lock-free look-up of dcache hash table +=========================================== + +Dcache is a complex data structure with the hash table entries also +linked together in other lists. In 2.4 kernel, dcache_lock protected +all the lists. We applied RCU only on hash chain walking. The rest of +the lists are still protected by dcache_lock. Some of the important +changes are : + +1. The deletion from hash chain is done using hlist_del_rcu() macro + which doesn't initialize next pointer of the deleted dentry and + this allows us to walk safely lock-free while a deletion is + happening. + +2. Insertion of a dentry into the hash table is done using + hlist_add_head_rcu() which take care of ordering the writes - the + writes to the dentry must be visible before the dentry is + inserted. This works in conjunction with hlist_for_each_rcu() while + walking the hash chain. The only requirement is that all + initialization to the dentry must be done before + hlist_add_head_rcu() since we don't have dcache_lock protection + while traversing the hash chain. This isn't different from the + existing code. + +3. The dentry looked up without holding dcache_lock by cannot be + returned for walking if it is unhashed. It then may have a NULL + d_inode or other bogosity since RCU doesn't protect the other + fields in the dentry. We therefore use a flag DCACHE_UNHASHED to + indicate unhashed dentries and use this in conjunction with a + per-dentry lock (d_lock). Once looked up without the dcache_lock, + we acquire the per-dentry lock (d_lock) and check if the dentry is + unhashed. If so, the look-up is failed. If not, the reference count + of the dentry is increased and the dentry is returned. + +4. Once a dentry is looked up, it must be ensured during the path walk + for that component it doesn't go away. In pre-2.5.10 code, this was + done holding a reference to the dentry. dcache_rcu does the same. + In some sense, dcache_rcu path walking looks like the pre-2.5.10 + version. + +5. All dentry hash chain updates must take the dcache_lock as well as + the per-dentry lock in that order. dput() does this to ensure that + a dentry that has just been looked up in another CPU doesn't get + deleted before dget() can be done on it. + +6. There are several ways to do reference counting of RCU protected + objects. One such example is in ipv4 route cache where deferred + freeing (using call_rcu()) is done as soon as the reference count + goes to zero. This cannot be done in the case of dentries because + tearing down of dentries require blocking (dentry_iput()) which + isn't supported from RCU callbacks. Instead, tearing down of + dentries happen synchronously in dput(), but actual freeing happens + later when RCU grace period is over. This allows safe lock-free + walking of the hash chains, but a matched dentry may have been + partially torn down. The checking of DCACHE_UNHASHED flag with + d_lock held detects such dentries and prevents them from being + returned from look-up. + + +Maintaining POSIX rename semantics +================================== + +Since look-up of dentries is lock-free, it can race against a +concurrent rename operation. For example, during rename of file A to +B, look-up of either A or B must succeed. So, if look-up of B happens +after A has been removed from the hash chain but not added to the new +hash chain, it may fail. Also, a comparison while the name is being +written concurrently by a rename may result in false positive matches +violating rename semantics. Issues related to race with rename are +handled as described below : + +1. Look-up can be done in two ways - d_lookup() which is safe from + simultaneous renames and __d_lookup() which is not. If + __d_lookup() fails, it must be followed up by a d_lookup() to + correctly determine whether a dentry is in the hash table or + not. d_lookup() protects look-ups using a sequence lock + (rename_lock). + +2. The name associated with a dentry (d_name) may be changed if a + rename is allowed to happen simultaneously. To avoid memcmp() in + __d_lookup() go out of bounds due to a rename and false positive + comparison, the name comparison is done while holding the + per-dentry lock. This prevents concurrent renames during this + operation. + +3. Hash table walking during look-up may move to a different bucket as + the current dentry is moved to a different bucket due to rename. + But we use hlists in dcache hash table and they are + null-terminated. So, even if a dentry moves to a different bucket, + hash chain walk will terminate. [with a list_head list, it may not + since termination is when the list_head in the original bucket is + reached]. Since we redo the d_parent check and compare name while + holding d_lock, lock-free look-up will not race against d_move(). + +4. There can be a theoretical race when a dentry keeps coming back to + original bucket due to double moves. Due to this look-up may + consider that it has never moved and can end up in a infinite loop. + But this is not any worse that theoretical livelocks we already + have in the kernel. + + +Important guidelines for filesystem developers related to dcache_rcu +==================================================================== + +1. Existing dcache interfaces (pre-2.5.62) exported to filesystem + don't change. Only dcache internal implementation changes. However + filesystems *must not* delete from the dentry hash chains directly + using the list macros like allowed earlier. They must use dcache + APIs like d_drop() or __d_drop() depending on the situation. + +2. d_flags is now protected by a per-dentry lock (d_lock). All access + to d_flags must be protected by it. + +3. For a hashed dentry, checking of d_count needs to be protected by + d_lock. + + +Papers and other documentation on dcache locking +================================================ + +1. Scaling dcache with RCU (http://linuxjournal.com/article.php?sid=7124). + +2. http://lse.sourceforge.net/locking/dcache/dcache.html + + + diff --git a/Documentation/filesystems/devfs/README b/Documentation/filesystems/devfs/README index 54366ecc241fee30aaf1a77ec91b15c310b766a3..aabfba24bc2edc214adfb90d5f28bda9de7ccad1 100644 --- a/Documentation/filesystems/devfs/README +++ b/Documentation/filesystems/devfs/README @@ -1812,11 +1812,6 @@ it may overflow the messages buffer, but try to get as much of it as you can -if you get an Oops, run ksymoops to decode it so that the -names of the offending functions are provided. A non-decoded Oops is -pretty useless - - send a copy of your devfsd configuration file(s) send the bug report to me first. diff --git a/Documentation/filesystems/ramfs-rootfs-initramfs.txt b/Documentation/filesystems/ramfs-rootfs-initramfs.txt new file mode 100644 index 0000000000000000000000000000000000000000..b3404a0325967de5fdce4a29e879258075ede500 --- /dev/null +++ b/Documentation/filesystems/ramfs-rootfs-initramfs.txt @@ -0,0 +1,195 @@ +ramfs, rootfs and initramfs +October 17, 2005 +Rob Landley +============================= + +What is ramfs? +-------------- + +Ramfs is a very simple filesystem that exports Linux's disk caching +mechanisms (the page cache and dentry cache) as a dynamically resizable +ram-based filesystem. + +Normally all files are cached in memory by Linux. Pages of data read from +backing store (usually the block device the filesystem is mounted on) are kept +around in case it's needed again, but marked as clean (freeable) in case the +Virtual Memory system needs the memory for something else. Similarly, data +written to files is marked clean as soon as it has been written to backing +store, but kept around for caching purposes until the VM reallocates the +memory. A similar mechanism (the dentry cache) greatly speeds up access to +directories. + +With ramfs, there is no backing store. Files written into ramfs allocate +dentries and page cache as usual, but there's nowhere to write them to. +This means the pages are never marked clean, so they can't be freed by the +VM when it's looking to recycle memory. + +The amount of code required to implement ramfs is tiny, because all the +work is done by the existing Linux caching infrastructure. Basically, +you're mounting the disk cache as a filesystem. Because of this, ramfs is not +an optional component removable via menuconfig, since there would be negligible +space savings. + +ramfs and ramdisk: +------------------ + +The older "ram disk" mechanism created a synthetic block device out of +an area of ram and used it as backing store for a filesystem. This block +device was of fixed size, so the filesystem mounted on it was of fixed +size. Using a ram disk also required unnecessarily copying memory from the +fake block device into the page cache (and copying changes back out), as well +as creating and destroying dentries. Plus it needed a filesystem driver +(such as ext2) to format and interpret this data. + +Compared to ramfs, this wastes memory (and memory bus bandwidth), creates +unnecessary work for the CPU, and pollutes the CPU caches. (There are tricks +to avoid this copying by playing with the page tables, but they're unpleasantly +complicated and turn out to be about as expensive as the copying anyway.) +More to the point, all the work ramfs is doing has to happen _anyway_, +since all file access goes through the page and dentry caches. The ram +disk is simply unnecessary, ramfs is internally much simpler. + +Another reason ramdisks are semi-obsolete is that the introduction of +loopback devices offered a more flexible and convenient way to create +synthetic block devices, now from files instead of from chunks of memory. +See losetup (8) for details. + +ramfs and tmpfs: +---------------- + +One downside of ramfs is you can keep writing data into it until you fill +up all memory, and the VM can't free it because the VM thinks that files +should get written to backing store (rather than swap space), but ramfs hasn't +got any backing store. Because of this, only root (or a trusted user) should +be allowed write access to a ramfs mount. + +A ramfs derivative called tmpfs was created to add size limits, and the ability +to write the data to swap space. Normal users can be allowed write access to +tmpfs mounts. See Documentation/filesystems/tmpfs.txt for more information. + +What is rootfs? +--------------- + +Rootfs is a special instance of ramfs, which is always present in 2.6 systems. +(It's used internally as the starting and stopping point for searches of the +kernel's doubly-linked list of mount points.) + +Most systems just mount another filesystem over it and ignore it. The +amount of space an empty instance of ramfs takes up is tiny. + +What is initramfs? +------------------ + +All 2.6 Linux kernels contain a gzipped "cpio" format archive, which is +extracted into rootfs when the kernel boots up. After extracting, the kernel +checks to see if rootfs contains a file "init", and if so it executes it as PID +1. If found, this init process is responsible for bringing the system the +rest of the way up, including locating and mounting the real root device (if +any). If rootfs does not contain an init program after the embedded cpio +archive is extracted into it, the kernel will fall through to the older code +to locate and mount a root partition, then exec some variant of /sbin/init +out of that. + +All this differs from the old initrd in several ways: + + - The old initrd was a separate file, while the initramfs archive is linked + into the linux kernel image. (The directory linux-*/usr is devoted to + generating this archive during the build.) + + - The old initrd file was a gzipped filesystem image (in some file format, + such as ext2, that had to be built into the kernel), while the new + initramfs archive is a gzipped cpio archive (like tar only simpler, + see cpio(1) and Documentation/early-userspace/buffer-format.txt). + + - The program run by the old initrd (which was called /initrd, not /init) did + some setup and then returned to the kernel, while the init program from + initramfs is not expected to return to the kernel. (If /init needs to hand + off control it can overmount / with a new root device and exec another init + program. See the switch_root utility, below.) + + - When switching another root device, initrd would pivot_root and then + umount the ramdisk. But initramfs is rootfs: you can neither pivot_root + rootfs, nor unmount it. Instead delete everything out of rootfs to + free up the space (find -xdev / -exec rm '{}' ';'), overmount rootfs + with the new root (cd /newmount; mount --move . /; chroot .), attach + stdin/stdout/stderr to the new /dev/console, and exec the new init. + + Since this is a remarkably persnickity process (and involves deleting + commands before you can run them), the klibc package introduced a helper + program (utils/run_init.c) to do all this for you. Most other packages + (such as busybox) have named this command "switch_root". + +Populating initramfs: +--------------------- + +The 2.6 kernel build process always creates a gzipped cpio format initramfs +archive and links it into the resulting kernel binary. By default, this +archive is empty (consuming 134 bytes on x86). The config option +CONFIG_INITRAMFS_SOURCE (for some reason buried under devices->block devices +in menuconfig, and living in usr/Kconfig) can be used to specify a source for +the initramfs archive, which will automatically be incorporated into the +resulting binary. This option can point to an existing gzipped cpio archive, a +directory containing files to be archived, or a text file specification such +as the following example: + + dir /dev 755 0 0 + nod /dev/console 644 0 0 c 5 1 + nod /dev/loop0 644 0 0 b 7 0 + dir /bin 755 1000 1000 + slink /bin/sh busybox 777 0 0 + file /bin/busybox initramfs/busybox 755 0 0 + dir /proc 755 0 0 + dir /sys 755 0 0 + dir /mnt 755 0 0 + file /init initramfs/init.sh 755 0 0 + +One advantage of the text file is that root access is not required to +set permissions or create device nodes in the new archive. (Note that those +two example "file" entries expect to find files named "init.sh" and "busybox" in +a directory called "initramfs", under the linux-2.6.* directory. See +Documentation/early-userspace/README for more details.) + +If you don't already understand what shared libraries, devices, and paths +you need to get a minimal root filesystem up and running, here are some +references: +http://www.tldp.org/HOWTO/Bootdisk-HOWTO/ +http://www.tldp.org/HOWTO/From-PowerUp-To-Bash-Prompt-HOWTO.html +http://www.linuxfromscratch.org/lfs/view/stable/ + +The "klibc" package (http://www.kernel.org/pub/linux/libs/klibc) is +designed to be a tiny C library to statically link early userspace +code against, along with some related utilities. It is BSD licensed. + +I use uClibc (http://www.uclibc.org) and busybox (http://www.busybox.net) +myself. These are LGPL and GPL, respectively. + +In theory you could use glibc, but that's not well suited for small embedded +uses like this. (A "hello world" program statically linked against glibc is +over 400k. With uClibc it's 7k. Also note that glibc dlopens libnss to do +name lookups, even when otherwise statically linked.) + +Future directions: +------------------ + +Today (2.6.14), initramfs is always compiled in, but not always used. The +kernel falls back to legacy boot code that is reached only if initramfs does +not contain an /init program. The fallback is legacy code, there to ensure a +smooth transition and allowing early boot functionality to gradually move to +"early userspace" (I.E. initramfs). + +The move to early userspace is necessary because finding and mounting the real +root device is complex. Root partitions can span multiple devices (raid or +separate journal). They can be out on the network (requiring dhcp, setting a +specific mac address, logging into a server, etc). They can live on removable +media, with dynamically allocated major/minor numbers and persistent naming +issues requiring a full udev implementation to sort out. They can be +compressed, encrypted, copy-on-write, loopback mounted, strangely partitioned, +and so on. + +This kind of complexity (which inevitably includes policy) is rightly handled +in userspace. Both klibc and busybox/uClibc are working on simple initramfs +packages to drop into a kernel build, and when standard solutions are ready +and widely deployed, the kernel's legacy early boot code will become obsolete +and a candidate for the feature removal schedule. + +But that's a while off yet. diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index f042c12e0ed2d24683e1b83ddfd130b561ad0e1b..ee4c0a8b8db7a663169fd97c57ce472a1a790398 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -3,7 +3,7 @@ Original author: Richard Gooch - Last updated on August 25, 2005 + Last updated on October 28, 2005 Copyright (C) 1999 Richard Gooch Copyright (C) 2005 Pekka Enberg @@ -11,62 +11,61 @@ This file is released under the GPLv2. -What is it? -=========== +Introduction +============ -The Virtual File System (otherwise known as the Virtual Filesystem -Switch) is the software layer in the kernel that provides the -filesystem interface to userspace programs. It also provides an -abstraction within the kernel which allows different filesystem -implementations to coexist. +The Virtual File System (also known as the Virtual Filesystem Switch) +is the software layer in the kernel that provides the filesystem +interface to userspace programs. It also provides an abstraction +within the kernel which allows different filesystem implementations to +coexist. +VFS system calls open(2), stat(2), read(2), write(2), chmod(2) and so +on are called from a process context. Filesystem locking is described +in the document Documentation/filesystems/Locking. -A Quick Look At How It Works -============================ -In this section I'll briefly describe how things work, before -launching into the details. I'll start with describing what happens -when user programs open and manipulate files, and then look from the -other view which is how a filesystem is supported and subsequently -mounted. - - -Opening a File --------------- - -The VFS implements the open(2), stat(2), chmod(2) and similar system -calls. The pathname argument is used by the VFS to search through the -directory entry cache (dentry cache or "dcache"). This provides a very -fast look-up mechanism to translate a pathname (filename) into a -specific dentry. - -An individual dentry usually has a pointer to an inode. Inodes are the -things that live on disc drives, and can be regular files (you know: -those things that you write data into), directories, FIFOs and other -beasts. Dentries live in RAM and are never saved to disc: they exist -only for performance. Inodes live on disc and are copied into memory -when required. Later any changes are written back to disc. The inode -that lives in RAM is a VFS inode, and it is this which the dentry -points to. A single inode can be pointed to by multiple dentries -(think about hardlinks). - -The dcache is meant to be a view into your entire filespace. Unlike -Linus, most of us losers can't fit enough dentries into RAM to cover -all of our filespace, so the dcache has bits missing. In order to -resolve your pathname into a dentry, the VFS may have to resort to -creating dentries along the way, and then loading the inode. This is -done by looking up the inode. - -To look up an inode (usually read from disc) requires that the VFS -calls the lookup() method of the parent directory inode. This method -is installed by the specific filesystem implementation that the inode -lives in. There will be more on this later. +Directory Entry Cache (dcache) +------------------------------ -Once the VFS has the required dentry (and hence the inode), we can do -all those boring things like open(2) the file, or stat(2) it to peek -at the inode data. The stat(2) operation is fairly simple: once the -VFS has the dentry, it peeks at the inode data and passes some of it -back to userspace. +The VFS implements the open(2), stat(2), chmod(2), and similar system +calls. The pathname argument that is passed to them is used by the VFS +to search through the directory entry cache (also known as the dentry +cache or dcache). This provides a very fast look-up mechanism to +translate a pathname (filename) into a specific dentry. Dentries live +in RAM and are never saved to disc: they exist only for performance. + +The dentry cache is meant to be a view into your entire filespace. As +most computers cannot fit all dentries in the RAM at the same time, +some bits of the cache are missing. In order to resolve your pathname +into a dentry, the VFS may have to resort to creating dentries along +the way, and then loading the inode. This is done by looking up the +inode. + + +The Inode Object +---------------- + +An individual dentry usually has a pointer to an inode. Inodes are +filesystem objects such as regular files, directories, FIFOs and other +beasts. They live either on the disc (for block device filesystems) +or in the memory (for pseudo filesystems). Inodes that live on the +disc are copied into the memory when required and changes to the inode +are written back to disc. A single inode can be pointed to by multiple +dentries (hard links, for example, do this). + +To look up an inode requires that the VFS calls the lookup() method of +the parent directory inode. This method is installed by the specific +filesystem implementation that the inode lives in. Once the VFS has +the required dentry (and hence the inode), we can do all those boring +things like open(2) the file, or stat(2) it to peek at the inode +data. The stat(2) operation is fairly simple: once the VFS has the +dentry, it peeks at the inode data and passes some of it back to +userspace. + + +The File Object +--------------- Opening a file requires another operation: allocation of a file structure (this is the kernel-side implementation of file @@ -74,51 +73,39 @@ descriptors). The freshly allocated file structure is initialized with a pointer to the dentry and a set of file operation member functions. These are taken from the inode data. The open() file method is then called so the specific filesystem implementation can do it's work. You -can see that this is another switch performed by the VFS. - -The file structure is placed into the file descriptor table for the -process. +can see that this is another switch performed by the VFS. The file +structure is placed into the file descriptor table for the process. Reading, writing and closing files (and other assorted VFS operations) is done by using the userspace file descriptor to grab the appropriate -file structure, and then calling the required file structure method -function to do whatever is required. - -For as long as the file is open, it keeps the dentry "open" (in use), -which in turn means that the VFS inode is still in use. - -All VFS system calls (i.e. open(2), stat(2), read(2), write(2), -chmod(2) and so on) are called from a process context. You should -assume that these calls are made without any kernel locks being -held. This means that the processes may be executing the same piece of -filesystem or driver code at the same time, on different -processors. You should ensure that access to shared resources is -protected by appropriate locks. +file structure, and then calling the required file structure method to +do whatever is required. For as long as the file is open, it keeps the +dentry in use, which in turn means that the VFS inode is still in use. Registering and Mounting a Filesystem -------------------------------------- +===================================== -If you want to support a new kind of filesystem in the kernel, all you -need to do is call register_filesystem(). You pass a structure -describing the filesystem implementation (struct file_system_type) -which is then added to an internal table of supported filesystems. You -can do: +To register and unregister a filesystem, use the following API +functions: -% cat /proc/filesystems + #include -to see what filesystems are currently available on your system. + extern int register_filesystem(struct file_system_type *); + extern int unregister_filesystem(struct file_system_type *); -When a request is made to mount a block device onto a directory in -your filespace the VFS will call the appropriate method for the -specific filesystem. The dentry for the mount point will then be -updated to point to the root inode for the new filesystem. +The passed struct file_system_type describes your filesystem. When a +request is made to mount a device onto a directory in your filespace, +the VFS will call the appropriate get_sb() method for the specific +filesystem. The dentry for the mount point will then be updated to +point to the root inode for the new filesystem. -It's now time to look at things in more detail. +You can see all filesystems that are registered to the kernel in the +file /proc/filesystems. struct file_system_type -======================= +----------------------- This describes the filesystem. As of kernel 2.6.13, the following members are defined: @@ -197,8 +184,14 @@ A fill_super() method implementation has the following arguments: int silent: whether or not to be silent on error +The Superblock Object +===================== + +A superblock object represents a mounted filesystem. + + struct super_operations -======================= +----------------------- This describes how the VFS can manipulate the superblock of your filesystem. As of kernel 2.6.13, the following members are defined: @@ -286,9 +279,9 @@ or bottom half). a superblock. The second parameter indicates whether the method should wait until the write out has been completed. Optional. - write_super_lockfs: called when VFS is locking a filesystem and forcing - it into a consistent state. This function is currently used by the - Logical Volume Manager (LVM). + write_super_lockfs: called when VFS is locking a filesystem and + forcing it into a consistent state. This method is currently + used by the Logical Volume Manager (LVM). unlockfs: called when VFS is unlocking a filesystem and making it writable again. @@ -317,8 +310,14 @@ field. This is a pointer to a "struct inode_operations" which describes the methods that can be performed on individual inodes. +The Inode Object +================ + +An inode object represents an object within the filesystem. + + struct inode_operations -======================= +----------------------- This describes how the VFS can manipulate an inode in your filesystem. As of kernel 2.6.13, the following members are defined: @@ -394,51 +393,62 @@ otherwise noted. will probably need to call d_instantiate() just as you would in the create() method + rename: called by the rename(2) system call to rename the object to + have the parent and name given by the second inode and dentry. + readlink: called by the readlink(2) system call. Only required if you want to support reading symbolic links follow_link: called by the VFS to follow a symbolic link to the inode it points to. Only required if you want to support - symbolic links. This function returns a void pointer cookie + symbolic links. This method returns a void pointer cookie that is passed to put_link(). put_link: called by the VFS to release resources allocated by - follow_link(). The cookie returned by follow_link() is passed to - to this function as the last parameter. It is used by filesystems - such as NFS where page cache is not stable (i.e. page that was - installed when the symbolic link walk started might not be in the - page cache at the end of the walk). - - truncate: called by the VFS to change the size of a file. The i_size - field of the inode is set to the desired size by the VFS before - this function is called. This function is called by the truncate(2) - system call and related functionality. + follow_link(). The cookie returned by follow_link() is passed + to to this method as the last parameter. It is used by + filesystems such as NFS where page cache is not stable + (i.e. page that was installed when the symbolic link walk + started might not be in the page cache at the end of the + walk). + + truncate: called by the VFS to change the size of a file. The + i_size field of the inode is set to the desired size by the + VFS before this method is called. This method is called by + the truncate(2) system call and related functionality. permission: called by the VFS to check for access rights on a POSIX-like filesystem. - setattr: called by the VFS to set attributes for a file. This function is - called by chmod(2) and related system calls. + setattr: called by the VFS to set attributes for a file. This method + is called by chmod(2) and related system calls. - getattr: called by the VFS to get attributes of a file. This function is - called by stat(2) and related system calls. + getattr: called by the VFS to get attributes of a file. This method + is called by stat(2) and related system calls. setxattr: called by the VFS to set an extended attribute for a file. - Extended attribute is a name:value pair associated with an inode. This - function is called by setxattr(2) system call. + Extended attribute is a name:value pair associated with an + inode. This method is called by setxattr(2) system call. + + getxattr: called by the VFS to retrieve the value of an extended + attribute name. This method is called by getxattr(2) function + call. - getxattr: called by the VFS to retrieve the value of an extended attribute - name. This function is called by getxattr(2) function call. + listxattr: called by the VFS to list all extended attributes for a + given file. This method is called by listxattr(2) system call. - listxattr: called by the VFS to list all extended attributes for a given - file. This function is called by listxattr(2) system call. + removexattr: called by the VFS to remove an extended attribute from + a file. This method is called by removexattr(2) system call. - removexattr: called by the VFS to remove an extended attribute from a file. - This function is called by removexattr(2) system call. + +The Address Space Object +======================== + +The address space object is used to identify pages in the page cache. struct address_space_operations -=============================== +------------------------------- This describes how the VFS can manipulate mapping of a file to page cache in your filesystem. As of kernel 2.6.13, the following members are defined: @@ -502,8 +512,14 @@ struct address_space_operations { it. An example implementation can be found in fs/ext2/xip.c. +The File Object +=============== + +A file object represents a file opened by a process. + + struct file_operations -====================== +---------------------- This describes how the VFS can manipulate an open file. As of kernel 2.6.13, the following members are defined: @@ -661,7 +677,7 @@ of child dentries. Child dentries are basically like files in a directory. -Directory Entry Cache APIs +Directory Entry Cache API -------------------------- There are a number of functions defined which permit a filesystem to @@ -705,178 +721,24 @@ manipulate dentries: and the dentry is returned. The caller must use d_put() to free the dentry when it finishes using it. +For further information on dentry locking, please refer to the document +Documentation/filesystems/dentry-locking.txt. -RCU-based dcache locking model ------------------------------- -On many workloads, the most common operation on dcache is -to look up a dentry, given a parent dentry and the name -of the child. Typically, for every open(), stat() etc., -the dentry corresponding to the pathname will be looked -up by walking the tree starting with the first component -of the pathname and using that dentry along with the next -component to look up the next level and so on. Since it -is a frequent operation for workloads like multiuser -environments and web servers, it is important to optimize -this path. - -Prior to 2.5.10, dcache_lock was acquired in d_lookup and thus -in every component during path look-up. Since 2.5.10 onwards, -fast-walk algorithm changed this by holding the dcache_lock -at the beginning and walking as many cached path component -dentries as possible. This significantly decreases the number -of acquisition of dcache_lock. However it also increases the -lock hold time significantly and affects performance in large -SMP machines. Since 2.5.62 kernel, dcache has been using -a new locking model that uses RCU to make dcache look-up -lock-free. - -The current dcache locking model is not very different from the existing -dcache locking model. Prior to 2.5.62 kernel, dcache_lock -protected the hash chain, d_child, d_alias, d_lru lists as well -as d_inode and several other things like mount look-up. RCU-based -changes affect only the way the hash chain is protected. For everything -else the dcache_lock must be taken for both traversing as well as -updating. The hash chain updates too take the dcache_lock. -The significant change is the way d_lookup traverses the hash chain, -it doesn't acquire the dcache_lock for this and rely on RCU to -ensure that the dentry has not been *freed*. - - -Dcache locking details ----------------------- +Resources +========= + +(Note some of these resources are not up-to-date with the latest kernel + version.) + +Creating Linux virtual filesystems. 2002 + + +The Linux Virtual File-system Layer by Neil Brown. 1999 + + +A tour of the Linux VFS by Michael K. Johnson. 1996 + -For many multi-user workloads, open() and stat() on files are -very frequently occurring operations. Both involve walking -of path names to find the dentry corresponding to the -concerned file. In 2.4 kernel, dcache_lock was held -during look-up of each path component. Contention and -cache-line bouncing of this global lock caused significant -scalability problems. With the introduction of RCU -in Linux kernel, this was worked around by making -the look-up of path components during path walking lock-free. - - -Safe lock-free look-up of dcache hash table -=========================================== - -Dcache is a complex data structure with the hash table entries -also linked together in other lists. In 2.4 kernel, dcache_lock -protected all the lists. We applied RCU only on hash chain -walking. The rest of the lists are still protected by dcache_lock. -Some of the important changes are : - -1. The deletion from hash chain is done using hlist_del_rcu() macro which - doesn't initialize next pointer of the deleted dentry and this - allows us to walk safely lock-free while a deletion is happening. - -2. Insertion of a dentry into the hash table is done using - hlist_add_head_rcu() which take care of ordering the writes - - the writes to the dentry must be visible before the dentry - is inserted. This works in conjunction with hlist_for_each_rcu() - while walking the hash chain. The only requirement is that - all initialization to the dentry must be done before hlist_add_head_rcu() - since we don't have dcache_lock protection while traversing - the hash chain. This isn't different from the existing code. - -3. The dentry looked up without holding dcache_lock by cannot be - returned for walking if it is unhashed. It then may have a NULL - d_inode or other bogosity since RCU doesn't protect the other - fields in the dentry. We therefore use a flag DCACHE_UNHASHED to - indicate unhashed dentries and use this in conjunction with a - per-dentry lock (d_lock). Once looked up without the dcache_lock, - we acquire the per-dentry lock (d_lock) and check if the - dentry is unhashed. If so, the look-up is failed. If not, the - reference count of the dentry is increased and the dentry is returned. - -4. Once a dentry is looked up, it must be ensured during the path - walk for that component it doesn't go away. In pre-2.5.10 code, - this was done holding a reference to the dentry. dcache_rcu does - the same. In some sense, dcache_rcu path walking looks like - the pre-2.5.10 version. - -5. All dentry hash chain updates must take the dcache_lock as well as - the per-dentry lock in that order. dput() does this to ensure - that a dentry that has just been looked up in another CPU - doesn't get deleted before dget() can be done on it. - -6. There are several ways to do reference counting of RCU protected - objects. One such example is in ipv4 route cache where - deferred freeing (using call_rcu()) is done as soon as - the reference count goes to zero. This cannot be done in - the case of dentries because tearing down of dentries - require blocking (dentry_iput()) which isn't supported from - RCU callbacks. Instead, tearing down of dentries happen - synchronously in dput(), but actual freeing happens later - when RCU grace period is over. This allows safe lock-free - walking of the hash chains, but a matched dentry may have - been partially torn down. The checking of DCACHE_UNHASHED - flag with d_lock held detects such dentries and prevents - them from being returned from look-up. - - -Maintaining POSIX rename semantics -================================== - -Since look-up of dentries is lock-free, it can race against -a concurrent rename operation. For example, during rename -of file A to B, look-up of either A or B must succeed. -So, if look-up of B happens after A has been removed from the -hash chain but not added to the new hash chain, it may fail. -Also, a comparison while the name is being written concurrently -by a rename may result in false positive matches violating -rename semantics. Issues related to race with rename are -handled as described below : - -1. Look-up can be done in two ways - d_lookup() which is safe - from simultaneous renames and __d_lookup() which is not. - If __d_lookup() fails, it must be followed up by a d_lookup() - to correctly determine whether a dentry is in the hash table - or not. d_lookup() protects look-ups using a sequence - lock (rename_lock). - -2. The name associated with a dentry (d_name) may be changed if - a rename is allowed to happen simultaneously. To avoid memcmp() - in __d_lookup() go out of bounds due to a rename and false - positive comparison, the name comparison is done while holding the - per-dentry lock. This prevents concurrent renames during this - operation. - -3. Hash table walking during look-up may move to a different bucket as - the current dentry is moved to a different bucket due to rename. - But we use hlists in dcache hash table and they are null-terminated. - So, even if a dentry moves to a different bucket, hash chain - walk will terminate. [with a list_head list, it may not since - termination is when the list_head in the original bucket is reached]. - Since we redo the d_parent check and compare name while holding - d_lock, lock-free look-up will not race against d_move(). - -4. There can be a theoretical race when a dentry keeps coming back - to original bucket due to double moves. Due to this look-up may - consider that it has never moved and can end up in a infinite loop. - But this is not any worse that theoretical livelocks we already - have in the kernel. - - -Important guidelines for filesystem developers related to dcache_rcu -==================================================================== - -1. Existing dcache interfaces (pre-2.5.62) exported to filesystem - don't change. Only dcache internal implementation changes. However - filesystems *must not* delete from the dentry hash chains directly - using the list macros like allowed earlier. They must use dcache - APIs like d_drop() or __d_drop() depending on the situation. - -2. d_flags is now protected by a per-dentry lock (d_lock). All - access to d_flags must be protected by it. - -3. For a hashed dentry, checking of d_count needs to be protected - by d_lock. - - -Papers and other documentation on dcache locking -================================================ - -1. Scaling dcache with RCU (http://linuxjournal.com/article.php?sid=7124). - -2. http://lse.sourceforge.net/locking/dcache/dcache.html +A small trail through the Linux kernel by Andries Brouwer. 2001 + diff --git a/Documentation/hpet.txt b/Documentation/hpet.txt index 4e7cc8d3359b9a839ed941d5dbad01598869c306..e52457581f47ef0e6274f756a9f70ab8fcb61961 100644 --- a/Documentation/hpet.txt +++ b/Documentation/hpet.txt @@ -1,18 +1,21 @@ High Precision Event Timer Driver for Linux -The High Precision Event Timer (HPET) hardware is the future replacement for the 8254 and Real -Time Clock (RTC) periodic timer functionality. Each HPET can have up two 32 timers. It is possible -to configure the first two timers as legacy replacements for 8254 and RTC periodic. A specification -done by INTEL and Microsoft can be found at http://www.intel.com/labs/platcomp/hpet/hpetspec.htm. - -The driver supports detection of HPET driver allocation and initialization of the HPET before the -driver module_init routine is called. This enables platform code which uses timer 0 or 1 as the -main timer to intercept HPET initialization. An example of this initialization can be found in +The High Precision Event Timer (HPET) hardware is the future replacement +for the 8254 and Real Time Clock (RTC) periodic timer functionality. +Each HPET can have up two 32 timers. It is possible to configure the +first two timers as legacy replacements for 8254 and RTC periodic timers. +A specification done by Intel and Microsoft can be found at +. + +The driver supports detection of HPET driver allocation and initialization +of the HPET before the driver module_init routine is called. This enables +platform code which uses timer 0 or 1 as the main timer to intercept HPET +initialization. An example of this initialization can be found in arch/i386/kernel/time_hpet.c. -The driver provides two APIs which are very similar to the API found in the rtc.c driver. -There is a user space API and a kernel space API. An example user space program is provided -below. +The driver provides two APIs which are very similar to the API found in +the rtc.c driver. There is a user space API and a kernel space API. +An example user space program is provided below. #include #include @@ -290,9 +293,8 @@ The kernel API has three interfaces exported from the driver: hpet_unregister(struct hpet_task *tp) hpet_control(struct hpet_task *tp, unsigned int cmd, unsigned long arg) -The kernel module using this interface fills in the ht_func and ht_data members of the -hpet_task structure before calling hpet_register. hpet_control simply vectors to the hpet_ioctl -routine and has the same commands and respective arguments as the user API. hpet_unregister +The kernel module using this interface fills in the ht_func and ht_data +members of the hpet_task structure before calling hpet_register. +hpet_control simply vectors to the hpet_ioctl routine and has the same +commands and respective arguments as the user API. hpet_unregister is used to terminate usage of the HPET timer reserved by hpet_register. - - diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt index 769f925c8526a9033c5e031c8aba094882cc27ea..87f4d052e39ca9adcbc35f3a0eb272dd668c1d7e 100644 --- a/Documentation/ioctl-number.txt +++ b/Documentation/ioctl-number.txt @@ -130,8 +130,6 @@ Code Seq# Include File Comments 'i' 00-3F linux/i2o.h 'j' 00-3F linux/joystick.h -'k' all asm-sparc/kbio.h - asm-sparc64/kbio.h 'l' 00-3F linux/tcfs_fs.h transparent cryptographic file system 'l' 40-7F linux/udf_fs_i.h in development: diff --git a/Documentation/magic-number.txt b/Documentation/magic-number.txt index bd8eefa175872b7aaf85df4439870b43fba2892f..af67faccf4de991f75ef5bcc387095dceaa21926 100644 --- a/Documentation/magic-number.txt +++ b/Documentation/magic-number.txt @@ -120,7 +120,7 @@ ISDN_NET_MAGIC 0x49344C02 isdn_net_local_s drivers/isdn/i4l/isdn_net_li SAVEKMSG_MAGIC2 0x4B4D5347 savekmsg arch/*/amiga/config.c STLI_BOARDMAGIC 0x4bc6c825 stlibrd include/linux/istallion.h CS_STATE_MAGIC 0x4c4f4749 cs_state sound/oss/cs46xx.c -SLAB_C_MAGIC 0x4f17a36d kmem_cache_s mm/slab.c +SLAB_C_MAGIC 0x4f17a36d kmem_cache mm/slab.c COW_MAGIC 0x4f4f4f4d cow_header_v1 arch/um/drivers/ubd_user.c I810_CARD_MAGIC 0x5072696E i810_card sound/oss/i810_audio.c TRIDENT_CARD_MAGIC 0x5072696E trident_card sound/oss/trident.c diff --git a/Documentation/networking/decnet.txt b/Documentation/networking/decnet.txt index c6bd25f5d61d4153c9590d7cb590b2b352aad006..e6c39c5831f5f4059ebfbeefb597991221185543 100644 --- a/Documentation/networking/decnet.txt +++ b/Documentation/networking/decnet.txt @@ -176,8 +176,6 @@ information (_most_ of which _is_ _essential_) includes: - Which client caused the problem ? - How much data was being transferred ? - Was the network congested ? - - If there was a kernel panic, please run the output through ksymoops - before sending it to me, otherwise its _useless_. - How can the problem be reproduced ? - Can you use tcpdump to get a trace ? (N.B. Most (all?) versions of tcpdump don't understand how to dump DECnet properly, so including diff --git a/Documentation/oops-tracing.txt b/Documentation/oops-tracing.txt index 66eaaab7773d551691181070daead961fca33df2..c563842ed8057e1ee960ff0faa75d87c6b797a56 100644 --- a/Documentation/oops-tracing.txt +++ b/Documentation/oops-tracing.txt @@ -1,6 +1,6 @@ NOTE: ksymoops is useless on 2.6. Please use the Oops in its original format (from dmesg, etc). Ignore any references in this or other docs to "decoding -the Oops" or "running it through ksymoops". If you post an Oops fron 2.6 that +the Oops" or "running it through ksymoops". If you post an Oops from 2.6 that has been run through ksymoops, people will just tell you to repost it. Quick Summary diff --git a/Documentation/power/video.txt b/Documentation/power/video.txt index 526d6dd267ea8e38f319c30de9f6accf2967327f..912bed87c758457b2f42b6decb1964326efce3de 100644 --- a/Documentation/power/video.txt +++ b/Documentation/power/video.txt @@ -11,9 +11,9 @@ boot video card. (Kernel usually does not even contain video card driver -- vesafb and vgacon are widely used). This is not problem for swsusp, because during swsusp resume, BIOS is -run normally so video card is normally initialized. S3 has absolutely -no chance of working with SMP/HT. Be sure it to turn it off before -testing (swsusp should work ok, OTOH). +run normally so video card is normally initialized. It should not be +problem for S1 standby, because hardware should retain its state over +that. There are a few types of systems where video works after S3 resume: @@ -64,7 +64,7 @@ your video card (good luck getting docs :-(). Maybe suspending from X (proper X, knowing your hardware, not XF68_FBcon) might have better chance of working. -Table of known working systems: +Table of known working notebooks: Model hack (or "how to do it") ------------------------------------------------------------------------------ @@ -73,7 +73,7 @@ Acer TM 242FX vbetool (6) Acer TM C110 video_post (8) Acer TM C300 vga=normal (only suspend on console, not in X), vbetool (6) or video_post (8) Acer TM 4052LCi s3_bios (2) -Acer TM 636Lci s3_bios vga=normal (2) +Acer TM 636Lci s3_bios,s3_mode (4) Acer TM 650 (Radeon M7) vga=normal plus boot-radeon (5) gets text console back Acer TM 660 ??? (*) Acer TM 800 vga=normal, X patches, see webpage (5) or vbetool (6) @@ -137,6 +137,13 @@ Toshiba Satellite P10-554 s3_bios,s3_mode (4)(****) Toshiba M30 (2) xor X with nvidia driver using internal AGP Uniwill 244IIO ??? (*) +Known working desktop systems +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Mainboard Graphics card hack (or "how to do it") +------------------------------------------------------------------------------ +Asus A7V8X nVidia RIVA TNT2 model 64 s3_bios,s3_mode (4) + (*) from http://www.ubuntulinux.org/wiki/HoaryPMResults, not sure which options to use. If you know, please tell me. diff --git a/Documentation/s390/driver-model.txt b/Documentation/s390/driver-model.txt index 19461958e2bd98a24260866329eb2e26b5188dbd..df09758bf3fe1619df2b57118b5bb60a12c754a8 100644 --- a/Documentation/s390/driver-model.txt +++ b/Documentation/s390/driver-model.txt @@ -8,11 +8,10 @@ All devices which can be addressed by means of ccws are called 'CCW devices' - even if they aren't actually driven by ccws. All ccw devices are accessed via a subchannel, this is reflected in the -structures under root/: +structures under devices/: -root/ - - sys - - legacy +devices/ + - system/ - css0/ - 0.0.0000/0.0.0815/ - 0.0.0001/0.0.4711/ @@ -36,7 +35,7 @@ availability: Can be 'good' or 'boxed'; 'no path' or 'no device' for online: An interface to set the device online and offline. In the special case of the device being disconnected (see the - notify function under 1.2), piping 0 to online will focibly delete + notify function under 1.2), piping 0 to online will forcibly delete the device. The device drivers can add entries to export per-device data and interfaces. @@ -222,7 +221,7 @@ and are called 'chp0.'. They have no driver and do not belong to any bus. Please note, that unlike /proc/chpids in 2.4, the channel path objects reflect only the logical state and not the physical state, since we cannot track the latter consistently due to lacking machine support (we don't need to be aware -of anyway). +of it anyway). status - Can be 'online' or 'offline'. Piping 'on' or 'off' sets the chpid logically online/offline. @@ -235,12 +234,16 @@ status - Can be 'online' or 'offline'. 3. System devices ----------------- -Note: cpus may yet be added here. - 3.1 xpram --------- -xpram shows up under sys/ as 'xpram'. +xpram shows up under devices/system/ as 'xpram'. + +3.2 cpus +-------- + +For each cpu, a directory is created under devices/system/cpu/. Each cpu has an +attribute 'online' which can be 0 or 1. 4. Other devices diff --git a/Documentation/sharedsubtree.txt b/Documentation/sharedsubtree.txt new file mode 100644 index 0000000000000000000000000000000000000000..2d8f403eb6eb98a49c78f92bbc41c9172a21646d --- /dev/null +++ b/Documentation/sharedsubtree.txt @@ -0,0 +1,1060 @@ +Shared Subtrees +--------------- + +Contents: + 1) Overview + 2) Features + 3) smount command + 4) Use-case + 5) Detailed semantics + 6) Quiz + 7) FAQ + 8) Implementation + + +1) Overview +----------- + +Consider the following situation: + +A process wants to clone its own namespace, but still wants to access the CD +that got mounted recently. Shared subtree semantics provide the necessary +mechanism to accomplish the above. + +It provides the necessary building blocks for features like per-user-namespace +and versioned filesystem. + +2) Features +----------- + +Shared subtree provides four different flavors of mounts; struct vfsmount to be +precise + + a. shared mount + b. slave mount + c. private mount + d. unbindable mount + + +2a) A shared mount can be replicated to as many mountpoints and all the +replicas continue to be exactly same. + + Here is an example: + + Lets say /mnt has a mount that is shared. + mount --make-shared /mnt + + note: mount command does not yet support the --make-shared flag. + I have included a small C program which does the same by executing + 'smount /mnt shared' + + #mount --bind /mnt /tmp + The above command replicates the mount at /mnt to the mountpoint /tmp + and the contents of both the mounts remain identical. + + #ls /mnt + a b c + + #ls /tmp + a b c + + Now lets say we mount a device at /tmp/a + #mount /dev/sd0 /tmp/a + + #ls /tmp/a + t1 t2 t2 + + #ls /mnt/a + t1 t2 t2 + + Note that the mount has propagated to the mount at /mnt as well. + + And the same is true even when /dev/sd0 is mounted on /mnt/a. The + contents will be visible under /tmp/a too. + + +2b) A slave mount is like a shared mount except that mount and umount events + only propagate towards it. + + All slave mounts have a master mount which is a shared. + + Here is an example: + + Lets say /mnt has a mount which is shared. + #mount --make-shared /mnt + + Lets bind mount /mnt to /tmp + #mount --bind /mnt /tmp + + the new mount at /tmp becomes a shared mount and it is a replica of + the mount at /mnt. + + Now lets make the mount at /tmp; a slave of /mnt + #mount --make-slave /tmp + [or smount /tmp slave] + + lets mount /dev/sd0 on /mnt/a + #mount /dev/sd0 /mnt/a + + #ls /mnt/a + t1 t2 t3 + + #ls /tmp/a + t1 t2 t3 + + Note the mount event has propagated to the mount at /tmp + + However lets see what happens if we mount something on the mount at /tmp + + #mount /dev/sd1 /tmp/b + + #ls /tmp/b + s1 s2 s3 + + #ls /mnt/b + + Note how the mount event has not propagated to the mount at + /mnt + + +2c) A private mount does not forward or receive propagation. + + This is the mount we are familiar with. Its the default type. + + +2d) A unbindable mount is a unbindable private mount + + lets say we have a mount at /mnt and we make is unbindable + + #mount --make-unbindable /mnt + [ smount /mnt unbindable ] + + Lets try to bind mount this mount somewhere else. + # mount --bind /mnt /tmp + mount: wrong fs type, bad option, bad superblock on /mnt, + or too many mounted file systems + + Binding a unbindable mount is a invalid operation. + + +3) smount command + + Currently the mount command is not aware of shared subtree features. + Work is in progress to add the support in mount ( util-linux package ). + Till then use the following program. + + ------------------------------------------------------------------------ + // + //this code was developed my Miklos Szeredi + //and modified by Ram Pai + // sample usage: + // smount /tmp shared + // + #include + #include + #include + #include + #include + + #ifndef MS_REC + #define MS_REC 0x4000 /* 16384: Recursive loopback */ + #endif + + #ifndef MS_SHARED + #define MS_SHARED 1<<20 /* Shared */ + #endif + + #ifndef MS_PRIVATE + #define MS_PRIVATE 1<<18 /* Private */ + #endif + + #ifndef MS_SLAVE + #define MS_SLAVE 1<<19 /* Slave */ + #endif + + #ifndef MS_UNBINDABLE + #define MS_UNBINDABLE 1<<17 /* Unbindable */ + #endif + + int main(int argc, char *argv[]) + { + int type; + if(argc != 3) { + fprintf(stderr, "usage: %s dir " + "\n" , argv[0]); + return 1; + } + + fprintf(stdout, "%s %s %s\n", argv[0], argv[1], argv[2]); + + if (strcmp(argv[2],"rshared")==0) + type=(MS_SHARED|MS_REC); + else if (strcmp(argv[2],"rslave")==0) + type=(MS_SLAVE|MS_REC); + else if (strcmp(argv[2],"rprivate")==0) + type=(MS_PRIVATE|MS_REC); + else if (strcmp(argv[2],"runbindable")==0) + type=(MS_UNBINDABLE|MS_REC); + else if (strcmp(argv[2],"shared")==0) + type=MS_SHARED; + else if (strcmp(argv[2],"slave")==0) + type=MS_SLAVE; + else if (strcmp(argv[2],"private")==0) + type=MS_PRIVATE; + else if (strcmp(argv[2],"unbindable")==0) + type=MS_UNBINDABLE; + else { + fprintf(stderr, "invalid operation: %s\n", argv[2]); + return 1; + } + setfsuid(getuid()); + + if(mount("", argv[1], "dontcare", type, "") == -1) { + perror("mount"); + return 1; + } + return 0; + } + ----------------------------------------------------------------------- + + Copy the above code snippet into smount.c + gcc -o smount smount.c + + + (i) To mark all the mounts under /mnt as shared execute the following + command: + + smount /mnt rshared + the corresponding syntax planned for mount command is + mount --make-rshared /mnt + + just to mark a mount /mnt as shared, execute the following + command: + smount /mnt shared + the corresponding syntax planned for mount command is + mount --make-shared /mnt + + (ii) To mark all the shared mounts under /mnt as slave execute the + following + + command: + smount /mnt rslave + the corresponding syntax planned for mount command is + mount --make-rslave /mnt + + just to mark a mount /mnt as slave, execute the following + command: + smount /mnt slave + the corresponding syntax planned for mount command is + mount --make-slave /mnt + + (iii) To mark all the mounts under /mnt as private execute the + following command: + + smount /mnt rprivate + the corresponding syntax planned for mount command is + mount --make-rprivate /mnt + + just to mark a mount /mnt as private, execute the following + command: + smount /mnt private + the corresponding syntax planned for mount command is + mount --make-private /mnt + + NOTE: by default all the mounts are created as private. But if + you want to change some shared/slave/unbindable mount as + private at a later point in time, this command can help. + + (iv) To mark all the mounts under /mnt as unbindable execute the + following + + command: + smount /mnt runbindable + the corresponding syntax planned for mount command is + mount --make-runbindable /mnt + + just to mark a mount /mnt as unbindable, execute the following + command: + smount /mnt unbindable + the corresponding syntax planned for mount command is + mount --make-unbindable /mnt + + +4) Use cases +------------ + + A) A process wants to clone its own namespace, but still wants to + access the CD that got mounted recently. + + Solution: + + The system administrator can make the mount at /cdrom shared + mount --bind /cdrom /cdrom + mount --make-shared /cdrom + + Now any process that clones off a new namespace will have a + mount at /cdrom which is a replica of the same mount in the + parent namespace. + + So when a CD is inserted and mounted at /cdrom that mount gets + propagated to the other mount at /cdrom in all the other clone + namespaces. + + B) A process wants its mounts invisible to any other process, but + still be able to see the other system mounts. + + Solution: + + To begin with, the administrator can mark the entire mount tree + as shareable. + + mount --make-rshared / + + A new process can clone off a new namespace. And mark some part + of its namespace as slave + + mount --make-rslave /myprivatetree + + Hence forth any mounts within the /myprivatetree done by the + process will not show up in any other namespace. However mounts + done in the parent namespace under /myprivatetree still shows + up in the process's namespace. + + + Apart from the above semantics this feature provides the + building blocks to solve the following problems: + + C) Per-user namespace + + The above semantics allows a way to share mounts across + namespaces. But namespaces are associated with processes. If + namespaces are made first class objects with user API to + associate/disassociate a namespace with userid, then each user + could have his/her own namespace and tailor it to his/her + requirements. Offcourse its needs support from PAM. + + D) Versioned files + + If the entire mount tree is visible at multiple locations, then + a underlying versioning file system can return different + version of the file depending on the path used to access that + file. + + An example is: + + mount --make-shared / + mount --rbind / /view/v1 + mount --rbind / /view/v2 + mount --rbind / /view/v3 + mount --rbind / /view/v4 + + and if /usr has a versioning filesystem mounted, than that + mount appears at /view/v1/usr, /view/v2/usr, /view/v3/usr and + /view/v4/usr too + + A user can request v3 version of the file /usr/fs/namespace.c + by accessing /view/v3/usr/fs/namespace.c . The underlying + versioning filesystem can then decipher that v3 version of the + filesystem is being requested and return the corresponding + inode. + +5) Detailed semantics: +------------------- + The section below explains the detailed semantics of + bind, rbind, move, mount, umount and clone-namespace operations. + + Note: the word 'vfsmount' and the noun 'mount' have been used + to mean the same thing, throughout this document. + +5a) Mount states + + A given mount can be in one of the following states + 1) shared + 2) slave + 3) shared and slave + 4) private + 5) unbindable + + A 'propagation event' is defined as event generated on a vfsmount + that leads to mount or unmount actions in other vfsmounts. + + A 'peer group' is defined as a group of vfsmounts that propagate + events to each other. + + (1) Shared mounts + + A 'shared mount' is defined as a vfsmount that belongs to a + 'peer group'. + + For example: + mount --make-shared /mnt + mount --bin /mnt /tmp + + The mount at /mnt and that at /tmp are both shared and belong + to the same peer group. Anything mounted or unmounted under + /mnt or /tmp reflect in all the other mounts of its peer + group. + + + (2) Slave mounts + + A 'slave mount' is defined as a vfsmount that receives + propagation events and does not forward propagation events. + + A slave mount as the name implies has a master mount from which + mount/unmount events are received. Events do not propagate from + the slave mount to the master. Only a shared mount can be made + a slave by executing the following command + + mount --make-slave mount + + A shared mount that is made as a slave is no more shared unless + modified to become shared. + + (3) Shared and Slave + + A vfsmount can be both shared as well as slave. This state + indicates that the mount is a slave of some vfsmount, and + has its own peer group too. This vfsmount receives propagation + events from its master vfsmount, and also forwards propagation + events to its 'peer group' and to its slave vfsmounts. + + Strictly speaking, the vfsmount is shared having its own + peer group, and this peer-group is a slave of some other + peer group. + + Only a slave vfsmount can be made as 'shared and slave' by + either executing the following command + mount --make-shared mount + or by moving the slave vfsmount under a shared vfsmount. + + (4) Private mount + + A 'private mount' is defined as vfsmount that does not + receive or forward any propagation events. + + (5) Unbindable mount + + A 'unbindable mount' is defined as vfsmount that does not + receive or forward any propagation events and cannot + be bind mounted. + + + State diagram: + The state diagram below explains the state transition of a mount, + in response to various commands. + ------------------------------------------------------------------------ + | |make-shared | make-slave | make-private |make-unbindab| + --------------|------------|--------------|--------------|-------------| + |shared |shared |*slave/private| private | unbindable | + | | | | | | + |-------------|------------|--------------|--------------|-------------| + |slave |shared | **slave | private | unbindable | + | |and slave | | | | + |-------------|------------|--------------|--------------|-------------| + |shared |shared | slave | private | unbindable | + |and slave |and slave | | | | + |-------------|------------|--------------|--------------|-------------| + |private |shared | **private | private | unbindable | + |-------------|------------|--------------|--------------|-------------| + |unbindable |shared |**unbindable | private | unbindable | + ------------------------------------------------------------------------ + + * if the shared mount is the only mount in its peer group, making it + slave, makes it private automatically. Note that there is no master to + which it can be slaved to. + + ** slaving a non-shared mount has no effect on the mount. + + Apart from the commands listed below, the 'move' operation also changes + the state of a mount depending on type of the destination mount. Its + explained in section 5d. + +5b) Bind semantics + + Consider the following command + + mount --bind A/a B/b + + where 'A' is the source mount, 'a' is the dentry in the mount 'A', 'B' + is the destination mount and 'b' is the dentry in the destination mount. + + The outcome depends on the type of mount of 'A' and 'B'. The table + below contains quick reference. + --------------------------------------------------------------------------- + | BIND MOUNT OPERATION | + |************************************************************************** + |source(A)->| shared | private | slave | unbindable | + | dest(B) | | | | | + | | | | | | | + | v | | | | | + |************************************************************************** + | shared | shared | shared | shared & slave | invalid | + | | | | | | + |non-shared| shared | private | slave | invalid | + *************************************************************************** + + Details: + + 1. 'A' is a shared mount and 'B' is a shared mount. A new mount 'C' + which is clone of 'A', is created. Its root dentry is 'a' . 'C' is + mounted on mount 'B' at dentry 'b'. Also new mount 'C1', 'C2', 'C3' ... + are created and mounted at the dentry 'b' on all mounts where 'B' + propagates to. A new propagation tree containing 'C1',..,'Cn' is + created. This propagation tree is identical to the propagation tree of + 'B'. And finally the peer-group of 'C' is merged with the peer group + of 'A'. + + 2. 'A' is a private mount and 'B' is a shared mount. A new mount 'C' + which is clone of 'A', is created. Its root dentry is 'a'. 'C' is + mounted on mount 'B' at dentry 'b'. Also new mount 'C1', 'C2', 'C3' ... + are created and mounted at the dentry 'b' on all mounts where 'B' + propagates to. A new propagation tree is set containing all new mounts + 'C', 'C1', .., 'Cn' with exactly the same configuration as the + propagation tree for 'B'. + + 3. 'A' is a slave mount of mount 'Z' and 'B' is a shared mount. A new + mount 'C' which is clone of 'A', is created. Its root dentry is 'a' . + 'C' is mounted on mount 'B' at dentry 'b'. Also new mounts 'C1', 'C2', + 'C3' ... are created and mounted at the dentry 'b' on all mounts where + 'B' propagates to. A new propagation tree containing the new mounts + 'C','C1',.. 'Cn' is created. This propagation tree is identical to the + propagation tree for 'B'. And finally the mount 'C' and its peer group + is made the slave of mount 'Z'. In other words, mount 'C' is in the + state 'slave and shared'. + + 4. 'A' is a unbindable mount and 'B' is a shared mount. This is a + invalid operation. + + 5. 'A' is a private mount and 'B' is a non-shared(private or slave or + unbindable) mount. A new mount 'C' which is clone of 'A', is created. + Its root dentry is 'a'. 'C' is mounted on mount 'B' at dentry 'b'. + + 6. 'A' is a shared mount and 'B' is a non-shared mount. A new mount 'C' + which is a clone of 'A' is created. Its root dentry is 'a'. 'C' is + mounted on mount 'B' at dentry 'b'. 'C' is made a member of the + peer-group of 'A'. + + 7. 'A' is a slave mount of mount 'Z' and 'B' is a non-shared mount. A + new mount 'C' which is a clone of 'A' is created. Its root dentry is + 'a'. 'C' is mounted on mount 'B' at dentry 'b'. Also 'C' is set as a + slave mount of 'Z'. In other words 'A' and 'C' are both slave mounts of + 'Z'. All mount/unmount events on 'Z' propagates to 'A' and 'C'. But + mount/unmount on 'A' do not propagate anywhere else. Similarly + mount/unmount on 'C' do not propagate anywhere else. + + 8. 'A' is a unbindable mount and 'B' is a non-shared mount. This is a + invalid operation. A unbindable mount cannot be bind mounted. + +5c) Rbind semantics + + rbind is same as bind. Bind replicates the specified mount. Rbind + replicates all the mounts in the tree belonging to the specified mount. + Rbind mount is bind mount applied to all the mounts in the tree. + + If the source tree that is rbind has some unbindable mounts, + then the subtree under the unbindable mount is pruned in the new + location. + + eg: lets say we have the following mount tree. + + A + / \ + B C + / \ / \ + D E F G + + Lets say all the mount except the mount C in the tree are + of a type other than unbindable. + + If this tree is rbound to say Z + + We will have the following tree at the new location. + + Z + | + A' + / + B' Note how the tree under C is pruned + / \ in the new location. + D' E' + + + +5d) Move semantics + + Consider the following command + + mount --move A B/b + + where 'A' is the source mount, 'B' is the destination mount and 'b' is + the dentry in the destination mount. + + The outcome depends on the type of the mount of 'A' and 'B'. The table + below is a quick reference. + --------------------------------------------------------------------------- + | MOVE MOUNT OPERATION | + |************************************************************************** + | source(A)->| shared | private | slave | unbindable | + | dest(B) | | | | | + | | | | | | | + | v | | | | | + |************************************************************************** + | shared | shared | shared |shared and slave| invalid | + | | | | | | + |non-shared| shared | private | slave | unbindable | + *************************************************************************** + NOTE: moving a mount residing under a shared mount is invalid. + + Details follow: + + 1. 'A' is a shared mount and 'B' is a shared mount. The mount 'A' is + mounted on mount 'B' at dentry 'b'. Also new mounts 'A1', 'A2'...'An' + are created and mounted at dentry 'b' on all mounts that receive + propagation from mount 'B'. A new propagation tree is created in the + exact same configuration as that of 'B'. This new propagation tree + contains all the new mounts 'A1', 'A2'... 'An'. And this new + propagation tree is appended to the already existing propagation tree + of 'A'. + + 2. 'A' is a private mount and 'B' is a shared mount. The mount 'A' is + mounted on mount 'B' at dentry 'b'. Also new mount 'A1', 'A2'... 'An' + are created and mounted at dentry 'b' on all mounts that receive + propagation from mount 'B'. The mount 'A' becomes a shared mount and a + propagation tree is created which is identical to that of + 'B'. This new propagation tree contains all the new mounts 'A1', + 'A2'... 'An'. + + 3. 'A' is a slave mount of mount 'Z' and 'B' is a shared mount. The + mount 'A' is mounted on mount 'B' at dentry 'b'. Also new mounts 'A1', + 'A2'... 'An' are created and mounted at dentry 'b' on all mounts that + receive propagation from mount 'B'. A new propagation tree is created + in the exact same configuration as that of 'B'. This new propagation + tree contains all the new mounts 'A1', 'A2'... 'An'. And this new + propagation tree is appended to the already existing propagation tree of + 'A'. Mount 'A' continues to be the slave mount of 'Z' but it also + becomes 'shared'. + + 4. 'A' is a unbindable mount and 'B' is a shared mount. The operation + is invalid. Because mounting anything on the shared mount 'B' can + create new mounts that get mounted on the mounts that receive + propagation from 'B'. And since the mount 'A' is unbindable, cloning + it to mount at other mountpoints is not possible. + + 5. 'A' is a private mount and 'B' is a non-shared(private or slave or + unbindable) mount. The mount 'A' is mounted on mount 'B' at dentry 'b'. + + 6. 'A' is a shared mount and 'B' is a non-shared mount. The mount 'A' + is mounted on mount 'B' at dentry 'b'. Mount 'A' continues to be a + shared mount. + + 7. 'A' is a slave mount of mount 'Z' and 'B' is a non-shared mount. + The mount 'A' is mounted on mount 'B' at dentry 'b'. Mount 'A' + continues to be a slave mount of mount 'Z'. + + 8. 'A' is a unbindable mount and 'B' is a non-shared mount. The mount + 'A' is mounted on mount 'B' at dentry 'b'. Mount 'A' continues to be a + unbindable mount. + +5e) Mount semantics + + Consider the following command + + mount device B/b + + 'B' is the destination mount and 'b' is the dentry in the destination + mount. + + The above operation is the same as bind operation with the exception + that the source mount is always a private mount. + + +5f) Unmount semantics + + Consider the following command + + umount A + + where 'A' is a mount mounted on mount 'B' at dentry 'b'. + + If mount 'B' is shared, then all most-recently-mounted mounts at dentry + 'b' on mounts that receive propagation from mount 'B' and does not have + sub-mounts within them are unmounted. + + Example: Lets say 'B1', 'B2', 'B3' are shared mounts that propagate to + each other. + + lets say 'A1', 'A2', 'A3' are first mounted at dentry 'b' on mount + 'B1', 'B2' and 'B3' respectively. + + lets say 'C1', 'C2', 'C3' are next mounted at the same dentry 'b' on + mount 'B1', 'B2' and 'B3' respectively. + + if 'C1' is unmounted, all the mounts that are most-recently-mounted on + 'B1' and on the mounts that 'B1' propagates-to are unmounted. + + 'B1' propagates to 'B2' and 'B3'. And the most recently mounted mount + on 'B2' at dentry 'b' is 'C2', and that of mount 'B3' is 'C3'. + + So all 'C1', 'C2' and 'C3' should be unmounted. + + If any of 'C2' or 'C3' has some child mounts, then that mount is not + unmounted, but all other mounts are unmounted. However if 'C1' is told + to be unmounted and 'C1' has some sub-mounts, the umount operation is + failed entirely. + +5g) Clone Namespace + + A cloned namespace contains all the mounts as that of the parent + namespace. + + Lets say 'A' and 'B' are the corresponding mounts in the parent and the + child namespace. + + If 'A' is shared, then 'B' is also shared and 'A' and 'B' propagate to + each other. + + If 'A' is a slave mount of 'Z', then 'B' is also the slave mount of + 'Z'. + + If 'A' is a private mount, then 'B' is a private mount too. + + If 'A' is unbindable mount, then 'B' is a unbindable mount too. + + +6) Quiz + + A. What is the result of the following command sequence? + + mount --bind /mnt /mnt + mount --make-shared /mnt + mount --bind /mnt /tmp + mount --move /tmp /mnt/1 + + what should be the contents of /mnt /mnt/1 /mnt/1/1 should be? + Should they all be identical? or should /mnt and /mnt/1 be + identical only? + + + B. What is the result of the following command sequence? + + mount --make-rshared / + mkdir -p /v/1 + mount --rbind / /v/1 + + what should be the content of /v/1/v/1 be? + + + C. What is the result of the following command sequence? + + mount --bind /mnt /mnt + mount --make-shared /mnt + mkdir -p /mnt/1/2/3 /mnt/1/test + mount --bind /mnt/1 /tmp + mount --make-slave /mnt + mount --make-shared /mnt + mount --bind /mnt/1/2 /tmp1 + mount --make-slave /mnt + + At this point we have the first mount at /tmp and + its root dentry is 1. Lets call this mount 'A' + And then we have a second mount at /tmp1 with root + dentry 2. Lets call this mount 'B' + Next we have a third mount at /mnt with root dentry + mnt. Lets call this mount 'C' + + 'B' is the slave of 'A' and 'C' is a slave of 'B' + A -> B -> C + + at this point if we execute the following command + + mount --bind /bin /tmp/test + + The mount is attempted on 'A' + + will the mount propagate to 'B' and 'C' ? + + what would be the contents of + /mnt/1/test be? + +7) FAQ + + Q1. Why is bind mount needed? How is it different from symbolic links? + symbolic links can get stale if the destination mount gets + unmounted or moved. Bind mounts continue to exist even if the + other mount is unmounted or moved. + + Q2. Why can't the shared subtree be implemented using exportfs? + + exportfs is a heavyweight way of accomplishing part of what + shared subtree can do. I cannot imagine a way to implement the + semantics of slave mount using exportfs? + + Q3 Why is unbindable mount needed? + + Lets say we want to replicate the mount tree at multiple + locations within the same subtree. + + if one rbind mounts a tree within the same subtree 'n' times + the number of mounts created is an exponential function of 'n'. + Having unbindable mount can help prune the unneeded bind + mounts. Here is a example. + + step 1: + lets say the root tree has just two directories with + one vfsmount. + root + / \ + tmp usr + + And we want to replicate the tree at multiple + mountpoints under /root/tmp + + step2: + mount --make-shared /root + + mkdir -p /tmp/m1 + + mount --rbind /root /tmp/m1 + + the new tree now looks like this: + + root + / \ + tmp usr + / + m1 + / \ + tmp usr + / + m1 + + it has two vfsmounts + + step3: + mkdir -p /tmp/m2 + mount --rbind /root /tmp/m2 + + the new tree now looks like this: + + root + / \ + tmp usr + / \ + m1 m2 + / \ / \ + tmp usr tmp usr + / \ / + m1 m2 m1 + / \ / \ + tmp usr tmp usr + / / \ + m1 m1 m2 + / \ + tmp usr + / \ + m1 m2 + + it has 6 vfsmounts + + step 4: + mkdir -p /tmp/m3 + mount --rbind /root /tmp/m3 + + I wont' draw the tree..but it has 24 vfsmounts + + + at step i the number of vfsmounts is V[i] = i*V[i-1]. + This is an exponential function. And this tree has way more + mounts than what we really needed in the first place. + + One could use a series of umount at each step to prune + out the unneeded mounts. But there is a better solution. + Unclonable mounts come in handy here. + + step 1: + lets say the root tree has just two directories with + one vfsmount. + root + / \ + tmp usr + + How do we set up the same tree at multiple locations under + /root/tmp + + step2: + mount --bind /root/tmp /root/tmp + + mount --make-rshared /root + mount --make-unbindable /root/tmp + + mkdir -p /tmp/m1 + + mount --rbind /root /tmp/m1 + + the new tree now looks like this: + + root + / \ + tmp usr + / + m1 + / \ + tmp usr + + step3: + mkdir -p /tmp/m2 + mount --rbind /root /tmp/m2 + + the new tree now looks like this: + + root + / \ + tmp usr + / \ + m1 m2 + / \ / \ + tmp usr tmp usr + + step4: + + mkdir -p /tmp/m3 + mount --rbind /root /tmp/m3 + + the new tree now looks like this: + + root + / \ + tmp usr + / \ \ + m1 m2 m3 + / \ / \ / \ + tmp usr tmp usr tmp usr + +8) Implementation + +8A) Datastructure + + 4 new fields are introduced to struct vfsmount + ->mnt_share + ->mnt_slave_list + ->mnt_slave + ->mnt_master + + ->mnt_share links togather all the mount to/from which this vfsmount + send/receives propagation events. + + ->mnt_slave_list links all the mounts to which this vfsmount propagates + to. + + ->mnt_slave links togather all the slaves that its master vfsmount + propagates to. + + ->mnt_master points to the master vfsmount from which this vfsmount + receives propagation. + + ->mnt_flags takes two more flags to indicate the propagation status of + the vfsmount. MNT_SHARE indicates that the vfsmount is a shared + vfsmount. MNT_UNCLONABLE indicates that the vfsmount cannot be + replicated. + + All the shared vfsmounts in a peer group form a cyclic list through + ->mnt_share. + + All vfsmounts with the same ->mnt_master form on a cyclic list anchored + in ->mnt_master->mnt_slave_list and going through ->mnt_slave. + + ->mnt_master can point to arbitrary (and possibly different) members + of master peer group. To find all immediate slaves of a peer group + you need to go through _all_ ->mnt_slave_list of its members. + Conceptually it's just a single set - distribution among the + individual lists does not affect propagation or the way propagation + tree is modified by operations. + + A example propagation tree looks as shown in the figure below. + [ NOTE: Though it looks like a forest, if we consider all the shared + mounts as a conceptual entity called 'pnode', it becomes a tree] + + + A <--> B <--> C <---> D + /|\ /| |\ + / F G J K H I + / + E<-->K + /|\ + M L N + + In the above figure A,B,C and D all are shared and propagate to each + other. 'A' has got 3 slave mounts 'E' 'F' and 'G' 'C' has got 2 slave + mounts 'J' and 'K' and 'D' has got two slave mounts 'H' and 'I'. + 'E' is also shared with 'K' and they propagate to each other. And + 'K' has 3 slaves 'M', 'L' and 'N' + + A's ->mnt_share links with the ->mnt_share of 'B' 'C' and 'D' + + A's ->mnt_slave_list links with ->mnt_slave of 'E', 'K', 'F' and 'G' + + E's ->mnt_share links with ->mnt_share of K + 'E', 'K', 'F', 'G' have their ->mnt_master point to struct + vfsmount of 'A' + 'M', 'L', 'N' have their ->mnt_master point to struct vfsmount of 'K' + K's ->mnt_slave_list links with ->mnt_slave of 'M', 'L' and 'N' + + C's ->mnt_slave_list links with ->mnt_slave of 'J' and 'K' + J and K's ->mnt_master points to struct vfsmount of C + and finally D's ->mnt_slave_list links with ->mnt_slave of 'H' and 'I' + 'H' and 'I' have their ->mnt_master pointing to struct vfsmount of 'D'. + + + NOTE: The propagation tree is orthogonal to the mount tree. + + +8B Algorithm: + + The crux of the implementation resides in rbind/move operation. + + The overall algorithm breaks the operation into 3 phases: (look at + attach_recursive_mnt() and propagate_mnt()) + + 1. prepare phase. + 2. commit phases. + 3. abort phases. + + Prepare phase: + + for each mount in the source tree: + a) Create the necessary number of mount trees to + be attached to each of the mounts that receive + propagation from the destination mount. + b) Do not attach any of the trees to its destination. + However note down its ->mnt_parent and ->mnt_mountpoint + c) Link all the new mounts to form a propagation tree that + is identical to the propagation tree of the destination + mount. + + If this phase is successful, there should be 'n' new + propagation trees; where 'n' is the number of mounts in the + source tree. Go to the commit phase + + Also there should be 'm' new mount trees, where 'm' is + the number of mounts to which the destination mount + propagates to. + + if any memory allocations fail, go to the abort phase. + + Commit phase + attach each of the mount trees to their corresponding + destination mounts. + + Abort phase + delete all the newly created trees. + + NOTE: all the propagation related functionality resides in the file + pnode.c + + +------------------------------------------------------------------------ + +version 0.1 (created the initial document, Ram Pai linuxram@us.ibm.com) +version 0.2 (Incorporated comments from Al Viro) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 13cba955cb5af313a2c2cc0866666766ef56a40a..2f27f391c7cc778e87bfc374f4bb6db9ea9b77d2 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -167,7 +167,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. spdif - Support SPDIF I/O - Default: disabled - Module supports autoprobe and multiple chips (max 8). + This module supports one chip and autoprobe. The power-management is supported. @@ -206,7 +206,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. See "AC97 Quirk Option" section below. spdif_aclink - S/PDIF transfer over AC-link (default = 1) - This module supports up to 8 cards and autoprobe. + This module supports one card and autoprobe. ATI IXP has two different methods to control SPDIF output. One is over AC-link and another is over the "direct" SPDIF output. The @@ -218,7 +218,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Module for ATI IXP 150/200/250 AC97 modem controllers. - Module supports up to 8 cards. + This module supports one card and autoprobe. Note: The default index value of this module is -2, i.e. the first slot is excluded. @@ -637,7 +637,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. model - force the model name position_fix - Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size) - Module supports up to 8 cards. + This module supports one card and autoprobe. Each codec may have a model table for different configurations. If your machine isn't listed there, the default (usually minimal) @@ -663,6 +663,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. adjusted. Appearing only when compiled with $CONFIG_SND_DEBUG=y + ALC260 + hp HP machines + fujitsu Fujitsu S7020 + CMI9880 minimal 3-jack in back min_fp 3-jack in back, 2-jack in front @@ -811,7 +815,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. semaphores (e.g. on some ASUS laptops) (default off) - Module supports autoprobe and multiple bus-master chips (max 8). + This module supports one chip and autoprobe. Note: the latest driver supports auto-detection of chip clock. if you still encounter too fast playback, specify the clock @@ -830,7 +834,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. ac97_clock - AC'97 codec clock base (0 = auto-detect) - This module supports up to 8 cards and autoprobe. + This module supports one card and autoprobe. Note: The default index value of this module is -2, i.e. the first slot is excluded. @@ -950,8 +954,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. use_cache - 0 or 1 (disabled by default) vaio_hack - alias buffer_top=0x25a800 reset_workaround - enable AC97 RESET workaround for some laptops + reset_workaround2 - enable extended AC97 RESET workaround for some + other laptops - Module supports autoprobe and multiple chips (max 8). + This module supports one chip and autoprobe. The power-management is supported. @@ -980,6 +986,11 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. workaround is enabled automatically. For other laptops with a hard freeze, you can try reset_workaround=1 option. + Note: Dell Latitude CSx laptops have another problem regarding + AC97 RESET. On these laptops, reset_workaround2 option is + turned on as default. This option is worth to try if the + previous reset_workaround option doesn't help. + Note: This driver is really crappy. It's a porting from the OSS driver, which is a result of black-magic reverse engineering. The detection of codec will fail if the driver is loaded *after* @@ -1310,7 +1321,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. ac97_quirk - AC'97 workaround for strange hardware See "AC97 Quirk Option" section below. - Module supports autoprobe and multiple bus-master chips (max 8). + This module supports one chip and autoprobe. Note: on some SMP motherboards like MSI 694D the interrupts might not be generated properly. In such a case, please try to @@ -1352,7 +1363,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. ac97_clock - AC'97 codec clock base (default 48000Hz) - Module supports up to 8 cards. + This module supports one card and autoprobe. Note: The default index value of this module is -2, i.e. the first slot is excluded. diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl index 24e85520890b902a799def758cef191f78a30490..260334c98d95133e19897b85e43179e205292352 100644 --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl @@ -18,8 +18,8 @@ - March 6, 2005 - 0.3.4 + October 6, 2005 + 0.3.5 @@ -30,7 +30,7 @@ - Copyright (c) 2002-2004 Takashi Iwai tiwai@suse.de + Copyright (c) 2002-2005 Takashi Iwai tiwai@suse.de @@ -1433,25 +1433,10 @@ res_port) { - release_resource(chip->res_port); - kfree_nocheck(chip->res_port); - } + release_and_free_resource(chip->res_port); ]]> - - As you can see, the resource pointer is also to be freed - via kfree_nocheck() after - release_resource() is called. You - cannot use kfree() here, because on ALSA, - kfree() may be a wrapper to its own - allocator with the memory debugging. Since the resource pointer - is allocated externally outside the ALSA, it must be released - via the native - kfree(). - kfree_nocheck() is used for that; it calls - the native kfree() without wrapper. @@ -2190,8 +2175,7 @@ struct _snd_pcm_runtime { unsigned int rate_den; /* -- SW params -- */ - int tstamp_timespec; /* use timeval (0) or timespec (1) */ - snd_pcm_tstamp_t tstamp_mode; /* mmap timestamp is updated */ + struct timespec tstamp_mode; /* mmap timestamp is updated */ unsigned int period_step; unsigned int sleep_min; /* min ticks to sleep */ snd_pcm_uframes_t xfer_align; /* xfer size need to be a multiple */ @@ -3709,8 +3693,7 @@ struct _snd_pcm_runtime { Here, the chip instance is retrieved via snd_kcontrol_chip() macro. This macro - converts from kcontrol->private_data to the type defined by - chip_t. The + just accesses to kcontrol->private_data. The kcontrol->private_data field is given as the argument of snd_ctl_new() (see the later subsection @@ -5998,32 +5981,23 @@ struct _snd_pcm_runtime { The first argument is the expression to evaluate, and the second argument is the action if it fails. When CONFIG_SND_DEBUG, is set, it will show an - error message such as BUG? (xxx) (called from - yyy). When no debug flag is set, this is - ignored. + error message such as BUG? (xxx) + together with stack trace. - - -
- <function>snd_runtime_check()</function> - This macro is quite similar with - snd_assert(). Unlike - snd_assert(), the expression is always - evaluated regardless of - CONFIG_SND_DEBUG. When - CONFIG_SND_DEBUG is set, the macro will - show a message like ERROR (xx) (called from - yyy). + When no debug flag is set, this macro is ignored.
<function>snd_BUG()</function> - It calls snd_assert(0,) -- that is, just - prints the error message at the point. It's useful to show that - a fatal error happens there. + It shows BUG? message and + stack trace as well as snd_assert at the point. + It's useful to show that a fatal error happens there. + + + When no debug flag is set, this macro is ignored.
diff --git a/Documentation/sparse.txt b/Documentation/sparse.txt index 1829009db771042038f3e302a8c35dbcb07c1d14..3f1c5464b1c9f1206dd497e891e1bd6e691d15fb 100644 --- a/Documentation/sparse.txt +++ b/Documentation/sparse.txt @@ -41,9 +41,9 @@ sure that bitwise types don't get mixed up (little-endian vs big-endian vs cpu-endian vs whatever), and there the constant "0" really _is_ special. -Modify top-level Makefile to say +Use -CHECK = sparse -Wbitwise + make C=[12] CF=-Wbitwise or you don't get any checking at all. diff --git a/Documentation/video4linux/bttv/README.freeze b/Documentation/video4linux/bttv/README.freeze index 51f8d4379a9475b3034e00d68f92df50974ad4bc..4259dccc8287fdd421693bf0d08879175fa64386 100644 --- a/Documentation/video4linux/bttv/README.freeze +++ b/Documentation/video4linux/bttv/README.freeze @@ -27,9 +27,9 @@ information out of a register+stack dump printed by the kernel on protection faults (so-called "kernel oops"). If you run into some kind of deadlock, you can try to dump a call trace -for each process using sysrq-t (see Documentation/sysrq.txt). ksymoops -will translate these dumps into kernel symbols too. This way it is -possible to figure where *exactly* some process in "D" state is stuck. +for each process using sysrq-t (see Documentation/sysrq.txt). +This way it is possible to figure where *exactly* some process in "D" +state is stuck. I've seen reports that bttv 0.7.x crashes whereas 0.8.x works rock solid for some people. Thus probably a small buglet left somewhere in bttv diff --git a/Documentation/vm/hugetlbpage.txt b/Documentation/vm/hugetlbpage.txt index 1b9bcd1fe98b3867d60a50241bbee7ab84099608..1ad9af1ca4d0b1f2c58b49009c139a69c6124f2d 100644 --- a/Documentation/vm/hugetlbpage.txt +++ b/Documentation/vm/hugetlbpage.txt @@ -13,12 +13,13 @@ This optimization is more critical now as bigger and bigger physical memories Users can use the huge page support in Linux kernel by either using the mmap system call or standard SYSv shared memory system calls (shmget, shmat). -First the Linux kernel needs to be built with CONFIG_HUGETLB_PAGE (present -under Processor types and feature) and CONFIG_HUGETLBFS (present under file -system option on config menu) config options. +First the Linux kernel needs to be built with the CONFIG_HUGETLBFS +(present under "File systems") and CONFIG_HUGETLB_PAGE (selected +automatically when CONFIG_HUGETLBFS is selected) configuration +options. The kernel built with hugepage support should show the number of configured -hugepages in the system by running the "cat /proc/meminfo" command. +hugepages in the system by running the "cat /proc/meminfo" command. /proc/meminfo also provides information about the total number of hugetlb pages configured in the kernel. It also displays information about the @@ -38,19 +39,19 @@ in the kernel. /proc/sys/vm/nr_hugepages indicates the current number of configured hugetlb pages in the kernel. Super user can dynamically request more (or free some -pre-configured) hugepages. -The allocation( or deallocation) of hugetlb pages is posible only if there are +pre-configured) hugepages. +The allocation (or deallocation) of hugetlb pages is possible only if there are enough physically contiguous free pages in system (freeing of hugepages is -possible only if there are enough hugetlb pages free that can be transfered +possible only if there are enough hugetlb pages free that can be transfered back to regular memory pool). Pages that are used as hugetlb pages are reserved inside the kernel and can -not be used for other purposes. +not be used for other purposes. Once the kernel with Hugetlb page support is built and running, a user can use either the mmap system call or shared memory system calls to start using the huge pages. It is required that the system administrator preallocate -enough memory for huge page purposes. +enough memory for huge page purposes. Use the following command to dynamically allocate/deallocate hugepages: @@ -80,9 +81,9 @@ memory (huge pages) allowed for that filesystem (/mnt/huge). The size is rounded down to HPAGE_SIZE. The option nr_inode sets the maximum number of inodes that /mnt/huge can use. If the size or nr_inode options are not provided on command line then no limits are set. For size and nr_inodes -options, you can use [G|g]/[M|m]/[K|k] to represent giga/mega/kilo. For -example, size=2K has the same meaning as size=2048. An example is given at -the end of this document. +options, you can use [G|g]/[M|m]/[K|k] to represent giga/mega/kilo. For +example, size=2K has the same meaning as size=2048. An example is given at +the end of this document. read and write system calls are not supported on files that reside on hugetlb file systems. diff --git a/MAINTAINERS b/MAINTAINERS index d57c491212b1bf8184272b2c172c18c51c0c09d4..995bfd8e6e7f8a830edf5cf04d9376bcf238ab3f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1077,6 +1077,26 @@ P: Jaroslav Kysela M: perex@suse.cz S: Maintained +HPET: High Precision Event Timers driver (hpet.c) +P: Clemens Ladisch +M: clemens@ladisch.de +S: Maintained + +HPET: i386 +P: Venkatesh Pallipadi (Venki) +M: venkatesh.pallipadi@intel.com +S: Maintained + +HPET: x86_64 +P: Andi Kleen and Vojtech Pavlik +M: ak@muc.de and vojtech@suse.cz +S: Maintained + +HPET: ACPI hpet.c +P: Bob Picco +M: bob.picco@hp.com +S: Maintained + HPFS FILESYSTEM P: Mikulas Patocka M: mikulas@artax.karlin.mff.cuni.cz @@ -2051,6 +2071,12 @@ P: Matt Mackall M: mpm@selenic.com S: Maintained +RAPIDIO SUBSYSTEM +P: Matt Porter +M: mporter@kernel.crashing.org +L: linux-kernel@vger.kernel.org +S: Maintained + REAL TIME CLOCK DRIVER P: Paul Gortmaker M: p_gortmaker@yahoo.com @@ -2455,10 +2481,10 @@ L: linux-kernel@vger.kernel.org S: Maintained TRIVIAL PATCHES -P: Rusty Russell -M: trivial@rustcorp.com.au +P: Adrian Bunk +M: trivial@kernel.org L: linux-kernel@vger.kernel.org -W: http://www.kernel.org/pub/linux/kernel/people/rusty/trivial/ +W: http://www.kernel.org/pub/linux/kernel/people/bunk/trivial/ S: Maintained TMS380 TOKEN-RING NETWORK DRIVER diff --git a/Makefile b/Makefile index 2dac8010c14296bf71b20da92d7256d6a5b41f22..ea96da1572d595de19daeda44b2364416e9bd3a0 100644 --- a/Makefile +++ b/Makefile @@ -583,7 +583,7 @@ export MODLIB ifeq ($(KBUILD_EXTMOD),) -core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ +core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \ $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 296bc03d1cf161a1cc6d5534e630bf7d98fdf3ba..3bfef0934c9d39162e346e73764f379aad8946f4 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -324,7 +324,7 @@ menu "Kernel Features" config SMP bool "Symmetric Multi-Processing (EXPERIMENTAL)" - depends on EXPERIMENTAL && BROKEN #&& n + depends on EXPERIMENTAL && REALVIEW_MPCORE help This enables support for systems with more than one CPU. If you have a system with only one CPU, like most personal computers, say N. If @@ -356,6 +356,16 @@ config HOTPLUG_CPU Say Y here to experiment with turning CPUs off and on. CPUs can be controlled through /sys/devices/system/cpu. +config LOCAL_TIMERS + bool "Use local timer interrupts" + depends on SMP && n + default y + help + Enable support for local timers on SMP platforms, rather then the + legacy IPI broadcast method. Local timers allows the system + accounting to be spread across the timer interval, preventing a + "thundering herd" at every timer tick. + config PREEMPT bool "Preemptible Kernel (EXPERIMENTAL)" depends on EXPERIMENTAL @@ -585,7 +595,7 @@ config FPE_NWFPE config FPE_NWFPE_XP bool "Support extended precision" - depends on FPE_NWFPE && !CPU_BIG_ENDIAN + depends on FPE_NWFPE help Say Y to include 80-bit support in the kernel floating-point emulator. Otherwise, only 32 and 64-bit support is compiled in. diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c index 50f13eec6cd70cd4c2e0a93233af141027211529..5ab94584baee6a46839e58819a9b443422c2a923 100644 --- a/arch/arm/boot/compressed/misc.c +++ b/arch/arm/boot/compressed/misc.c @@ -283,8 +283,14 @@ void flush_window(void) putstr("."); } +#ifndef arch_error +#define arch_error(x) +#endif + static void error(char *x) { + arch_error(x); + putstr("\n\n"); putstr(x); putstr("\n\n -- System halted"); diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c index bb4eff61441307458f92a104b0fa655542e118b7..c7fdf390cef9cbf20325431ea092d07c658f7f18 100644 --- a/arch/arm/common/scoop.c +++ b/arch/arm/common/scoop.c @@ -19,12 +19,6 @@ #define SCOOP_REG(d,adr) (*(volatile unsigned short*)(d +(adr))) -/* PCMCIA to Scoop linkage structures for pxa2xx_sharpsl.c - There is no easy way to link multiple scoop devices into one - single entity for the pxa2xx_pcmcia device */ -int scoop_num; -struct scoop_pcmcia_dev *scoop_devs; - struct scoop_dev { void *base; spinlock_t scoop_lock; diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index 7b17a87a3311af3ece561f3cbc19debf459e4a8c..7a3261f0bf79012e158e81eab69e7f633d56b4c6 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -9,6 +9,7 @@ */ #include #include +#include #include #include #include @@ -126,6 +127,9 @@ EXPORT_SYMBOL(__put_user_2); EXPORT_SYMBOL(__put_user_4); EXPORT_SYMBOL(__put_user_8); + /* crypto hash */ +EXPORT_SYMBOL(sha_transform); + /* gcc lib functions */ EXPORT_SYMBOL(__ashldi3); EXPORT_SYMBOL(__ashrdi3); diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index a511ec5b11a33344c945b66811b889c0a91bf084..d9fb819bf7cc3960aedb4b9836451371458a4893 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -47,6 +47,13 @@ movne r0, sp adrne lr, 1b bne do_IPI + +#ifdef CONFIG_LOCAL_TIMERS + test_for_ltirq r0, r6, r5, lr + movne r0, sp + adrne lr, 1b + bne do_local_timer +#endif #endif .endm diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 9def4404e1f27607e46931d4e093725d705d843a..d7099dbbb879ab8cd9ed6c417bdcc87d461dd747 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -264,6 +264,7 @@ int show_interrupts(struct seq_file *p, void *v) #endif #ifdef CONFIG_SMP show_ipi_list(p); + show_local_irqs(p); #endif seq_printf(p, "Err: %10lu\n", irq_err_count); } @@ -995,7 +996,7 @@ void __init init_irq_proc(void) struct proc_dir_entry *dir; int irq; - dir = proc_mkdir("irq", 0); + dir = proc_mkdir("irq", NULL); if (!dir) return; diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 9bd8609a2926d29f12913c28705f9175d6e2a420..9a340e790da52a9b801857c2da22226f89c91d66 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -648,7 +648,7 @@ static int ptrace_setwmmxregs(struct task_struct *tsk, void __user *ufp) #endif -static int do_ptrace(int request, struct task_struct *child, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, long addr, long data) { unsigned long tmp; int ret; @@ -782,53 +782,6 @@ static int do_ptrace(int request, struct task_struct *child, long addr, long dat return ret; } -asmlinkage long sys_ptrace(long request, long pid, long addr, long data) -{ - struct task_struct *child; - int ret; - - lock_kernel(); - ret = -EPERM; - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - ret = security_ptrace(current->parent, current); - if (ret) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret == 0) - ret = do_ptrace(request, child, addr, data); - -out_tsk: - put_task_struct(child); -out: - unlock_kernel(); - return ret; -} - asmlinkage void syscall_trace(int why, struct pt_regs *regs) { unsigned long ip; diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index edb5a406922f3953b02f3f5ba148d3b438585588..77e2e9ca89fab8477cdb13567d1c992c2e1c7d8b 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -142,7 +142,7 @@ int __cpuinit __cpu_up(unsigned int cpu) ret = -EIO; } - secondary_data.stack = 0; + secondary_data.stack = NULL; secondary_data.pgdir = 0; *pmd_offset(pgd, PHYS_OFFSET) = __pmd(0); @@ -184,6 +184,11 @@ int __cpuexit __cpu_disable(void) */ migrate_irqs(); + /* + * Stop the local timer for this CPU. + */ + local_timer_stop(cpu); + /* * Flush user cache and TLB mappings, and then remove this CPU * from the vm mask set of all processes. @@ -289,6 +294,11 @@ asmlinkage void __cpuinit secondary_start_kernel(void) */ cpu_set(cpu, cpu_online_map); + /* + * Setup local timer for this CPU. + */ + local_timer_setup(cpu); + /* * OK, it's off to the idle thread for us */ @@ -359,8 +369,8 @@ static void send_ipi_message(cpumask_t callmap, enum ipi_msg_type msg) * You must not call this function with disabled interrupts, from a * hardware interrupt handler, nor from a bottom half handler. */ -int smp_call_function_on_cpu(void (*func)(void *info), void *info, int retry, - int wait, cpumask_t callmap) +static int smp_call_function_on_cpu(void (*func)(void *info), void *info, + int retry, int wait, cpumask_t callmap) { struct smp_call_struct data; unsigned long timeout; @@ -454,6 +464,18 @@ void show_ipi_list(struct seq_file *p) seq_putc(p, '\n'); } +void show_local_irqs(struct seq_file *p) +{ + unsigned int cpu; + + seq_printf(p, "LOC: "); + + for_each_present_cpu(cpu) + seq_printf(p, "%10u ", irq_stat[cpu].local_timer_irqs); + + seq_putc(p, '\n'); +} + static void ipi_timer(struct pt_regs *regs) { int user = user_mode(regs); @@ -464,6 +486,18 @@ static void ipi_timer(struct pt_regs *regs) irq_exit(); } +#ifdef CONFIG_LOCAL_TIMERS +asmlinkage void do_local_timer(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + + if (local_timer_ack()) { + irq_stat[cpu].local_timer_irqs++; + ipi_timer(regs); + } +} +#endif + /* * ipi_call_function - handle IPI from smp_call_function() * @@ -515,7 +549,7 @@ static void ipi_cpu_stop(unsigned int cpu) * * Bit 0 - Inter-processor function call */ -void do_IPI(struct pt_regs *regs) +asmlinkage void do_IPI(struct pt_regs *regs) { unsigned int cpu = smp_processor_id(); struct ipi_data *ipi = &per_cpu(ipi_data, cpu); diff --git a/arch/arm/mach-aaec2000/clock.c b/arch/arm/mach-aaec2000/clock.c index 99e019169ddadbbd61c74c757909da93bcc8f351..0340ddc4824ea3e7e8f0ebb733d71c3385c9bb7b 100644 --- a/arch/arm/mach-aaec2000/clock.c +++ b/arch/arm/mach-aaec2000/clock.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-epxa10db/mm.c b/arch/arm/mach-epxa10db/mm.c index e8832d0910ee52117673bb66b3a51aefbd0515fa..cfd0d2182d44c46be13f55df034a596e2197ea29 100644 --- a/arch/arm/mach-epxa10db/mm.c +++ b/arch/arm/mach-epxa10db/mm.c @@ -25,6 +25,7 @@ #include #include #include +#include #include diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c index a1b153d1626cf182b6fa952c31daedfc6bb8528a..a4bafee77a06d0389269981a370a01192033096a 100644 --- a/arch/arm/mach-integrator/impd1.c +++ b/arch/arm/mach-integrator/impd1.c @@ -420,8 +420,7 @@ static int impd1_probe(struct lm_device *dev) free_impd1: if (impd1 && impd1->base) iounmap(impd1->base); - if (impd1) - kfree(impd1); + kfree(impd1); release_lm: release_mem_region(dev->resource.start, SZ_4K); return ret; diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c index df140962bb0fca0ae4f521f455a98bad10ce7e8c..6851abaf5524f6a4b1273339f3c4fb577f59fa2a 100644 --- a/arch/arm/mach-ixp2000/core.c +++ b/arch/arm/mach-ixp2000/core.c @@ -84,63 +84,54 @@ static struct map_desc ixp2000_io_desc[] __initdata = { .virtual = IXP2000_CAP_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_CAP_PHYS_BASE), .length = IXP2000_CAP_SIZE, - .type = MT_DEVICE + .type = MT_IXP2000_DEVICE, }, { .virtual = IXP2000_INTCTL_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_INTCTL_PHYS_BASE), .length = IXP2000_INTCTL_SIZE, - .type = MT_DEVICE + .type = MT_IXP2000_DEVICE, }, { .virtual = IXP2000_PCI_CREG_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_PCI_CREG_PHYS_BASE), .length = IXP2000_PCI_CREG_SIZE, - .type = MT_DEVICE + .type = MT_IXP2000_DEVICE, }, { .virtual = IXP2000_PCI_CSR_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_PCI_CSR_PHYS_BASE), .length = IXP2000_PCI_CSR_SIZE, - .type = MT_DEVICE + .type = MT_IXP2000_DEVICE, }, { .virtual = IXP2000_MSF_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_MSF_PHYS_BASE), .length = IXP2000_MSF_SIZE, - .type = MT_DEVICE + .type = MT_IXP2000_DEVICE, }, { .virtual = IXP2000_PCI_IO_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_PCI_IO_PHYS_BASE), .length = IXP2000_PCI_IO_SIZE, - .type = MT_DEVICE + .type = MT_IXP2000_DEVICE, }, { .virtual = IXP2000_PCI_CFG0_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_PCI_CFG0_PHYS_BASE), .length = IXP2000_PCI_CFG0_SIZE, - .type = MT_DEVICE + .type = MT_IXP2000_DEVICE, }, { .virtual = IXP2000_PCI_CFG1_VIRT_BASE, .pfn = __phys_to_pfn(IXP2000_PCI_CFG1_PHYS_BASE), .length = IXP2000_PCI_CFG1_SIZE, - .type = MT_DEVICE + .type = MT_IXP2000_DEVICE, } }; void __init ixp2000_map_io(void) { - extern unsigned int processor_id; - /* - * On IXP2400 CPUs we need to use MT_IXP2000_DEVICE for - * tweaking the PMDs so XCB=101. On IXP2800s we use the normal - * PMD flags. + * On IXP2400 CPUs we need to use MT_IXP2000_DEVICE so that + * XCB=101 (to avoid triggering erratum #66), and given that + * this mode speeds up I/O accesses and we have write buffer + * flushes in the right places anyway, it doesn't hurt to use + * XCB=101 for all IXP2000s. */ - if ((processor_id & 0xfffffff0) == 0x69054190) { - int i; - - printk(KERN_INFO "Enabling IXP2400 erratum #66 workaround\n"); - - for(i=0;i #include #include +#include #include #include #include diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index ad6a13f95a62cfcae51bc94ffc2fd1f243f17be7..eef3de26ad3704dba4604255abcf13bb3942b16a 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -65,6 +65,27 @@ struct platform_device poodle_scoop_device = { .resource = poodle_scoop_resources, }; +static void poodle_pcmcia_init(void) +{ + /* Setup default state of GPIO outputs + before we enable them as outputs. */ + GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) | + GPIO_bit(GPIO49_nPWE) | GPIO_bit(GPIO50_nPIOR) | + GPIO_bit(GPIO51_nPIOW) | GPIO_bit(GPIO52_nPCE_1) | + GPIO_bit(GPIO53_nPCE_2); + + pxa_gpio_mode(GPIO48_nPOE_MD); + pxa_gpio_mode(GPIO49_nPWE_MD); + pxa_gpio_mode(GPIO50_nPIOR_MD); + pxa_gpio_mode(GPIO51_nPIOW_MD); + pxa_gpio_mode(GPIO55_nPREG_MD); + pxa_gpio_mode(GPIO56_nPWAIT_MD); + pxa_gpio_mode(GPIO57_nIOIS16_MD); + pxa_gpio_mode(GPIO52_nPCE_1_MD); + pxa_gpio_mode(GPIO53_nPCE_2_MD); + pxa_gpio_mode(GPIO54_pSKTSEL_MD); +} + static struct scoop_pcmcia_dev poodle_pcmcia_scoop[] = { { .dev = &poodle_scoop_device.dev, @@ -74,6 +95,14 @@ static struct scoop_pcmcia_dev poodle_pcmcia_scoop[] = { }, }; +static struct scoop_pcmcia_config poodle_pcmcia_config = { + .devs = &poodle_pcmcia_scoop[0], + .num_devs = 1, + .pcmcia_init = poodle_pcmcia_init, +}; + +EXPORT_SYMBOL(poodle_scoop_device); + /* LoCoMo device */ static struct resource locomo_resources[] = { @@ -268,8 +297,7 @@ static void __init poodle_init(void) pxa_set_mci_info(&poodle_mci_platform_data); pxa_set_ficp_info(&poodle_ficp_platform_data); - scoop_num = 1; - scoop_devs = &poodle_pcmcia_scoop[0]; + platform_scoop_config = &poodle_pcmcia_config; ret = platform_add_devices(devices, ARRAY_SIZE(devices)); if (ret) { diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 6c6878cd2207db94f3b70343beef634fbb6491f2..4e9a699ee4280e61560a5672e9bd6c276c36a284 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -104,6 +104,66 @@ struct platform_device spitzscoop2_device = { .resource = spitz_scoop2_resources, }; +#define SPITZ_PWR_SD 0x01 +#define SPITZ_PWR_CF 0x02 + +/* Power control is shared with between one of the CF slots and SD */ +static void spitz_card_pwr_ctrl(int device, unsigned short new_cpr) +{ + unsigned short cpr = read_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR); + + if (new_cpr & 0x0007) { + set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER); + if (!(cpr & 0x0002) && !(cpr & 0x0004)) + mdelay(5); + if (device == SPITZ_PWR_CF) + cpr |= 0x0002; + if (device == SPITZ_PWR_SD) + cpr |= 0x0004; + write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr | new_cpr); + } else { + if (device == SPITZ_PWR_CF) + cpr &= ~0x0002; + if (device == SPITZ_PWR_SD) + cpr &= ~0x0004; + write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr | new_cpr); + if (!(cpr & 0x0002) && !(cpr & 0x0004)) { + mdelay(1); + reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER); + } + } +} + +static void spitz_pcmcia_init(void) +{ + /* Setup default state of GPIO outputs + before we enable them as outputs. */ + GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) | + GPIO_bit(GPIO49_nPWE) | GPIO_bit(GPIO50_nPIOR) | + GPIO_bit(GPIO51_nPIOW) | GPIO_bit(GPIO54_nPCE_2); + GPSR(GPIO85_nPCE_1) = GPIO_bit(GPIO85_nPCE_1); + + pxa_gpio_mode(GPIO48_nPOE_MD); + pxa_gpio_mode(GPIO49_nPWE_MD); + pxa_gpio_mode(GPIO50_nPIOR_MD); + pxa_gpio_mode(GPIO51_nPIOW_MD); + pxa_gpio_mode(GPIO55_nPREG_MD); + pxa_gpio_mode(GPIO56_nPWAIT_MD); + pxa_gpio_mode(GPIO57_nIOIS16_MD); + pxa_gpio_mode(GPIO85_nPCE_1_MD); + pxa_gpio_mode(GPIO54_nPCE_2_MD); + pxa_gpio_mode(GPIO104_pSKTSEL_MD); +} + +static void spitz_pcmcia_pwr(struct device *scoop, unsigned short cpr, int nr) +{ + /* Only need to override behaviour for slot 0 */ + if (nr == 0) + spitz_card_pwr_ctrl(SPITZ_PWR_CF, cpr); + else + write_scoop_reg(scoop, SCOOP_CPR, cpr); +} + static struct scoop_pcmcia_dev spitz_pcmcia_scoop[] = { { .dev = &spitzscoop_device.dev, @@ -117,6 +177,16 @@ static struct scoop_pcmcia_dev spitz_pcmcia_scoop[] = { }, }; +static struct scoop_pcmcia_config spitz_pcmcia_config = { + .devs = &spitz_pcmcia_scoop[0], + .num_devs = 2, + .pcmcia_init = spitz_pcmcia_init, + .power_ctrl = spitz_pcmcia_pwr, +}; + +EXPORT_SYMBOL(spitzscoop_device); +EXPORT_SYMBOL(spitzscoop2_device); + /* * Spitz SSP Device @@ -235,27 +305,14 @@ static int spitz_mci_init(struct device *dev, irqreturn_t (*spitz_detect_int)(in return 0; } -/* Power control is shared with one of the CF slots so we have a mess */ static void spitz_mci_setpower(struct device *dev, unsigned int vdd) { struct pxamci_platform_data* p_d = dev->platform_data; - unsigned short cpr = read_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR); - - if (( 1 << vdd) & p_d->ocr_mask) { - /* printk(KERN_DEBUG "%s: on\n", __FUNCTION__); */ - set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER); - mdelay(2); - write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr | 0x04); - } else { - /* printk(KERN_DEBUG "%s: off\n", __FUNCTION__); */ - write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr & ~0x04); - - if (!(cpr | 0x02)) { - mdelay(1); - reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER); - } - } + if (( 1 << vdd) & p_d->ocr_mask) + spitz_card_pwr_ctrl(SPITZ_PWR_SD, 0x0004); + else + spitz_card_pwr_ctrl(SPITZ_PWR_SD, 0x0000); } static int spitz_mci_get_ro(struct device *dev) @@ -351,8 +408,8 @@ static void __init common_init(void) static void __init spitz_init(void) { - scoop_num = 2; - scoop_devs = &spitz_pcmcia_scoop[0]; + platform_scoop_config = &spitz_pcmcia_config; + spitz_bl_machinfo.set_bl_intensity = spitz_bl_set_intensity; common_init(); diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c index 7dad3f1465e076028954b1f18169ed8b82b2502e..b9b2057349ebe9a1738fd327ab668bd11decb4e7 100644 --- a/arch/arm/mach-pxa/time.c +++ b/arch/arm/mach-pxa/time.c @@ -132,11 +132,13 @@ static void __init pxa_timer_init(void) tv.tv_sec = pxa_get_rtc_time(); do_settimeofday(&tv); - OSMR0 = 0; /* set initial match at 0 */ + OIER = 0; /* disable any timer interrupts */ + OSCR = LATCH*2; /* push OSCR out of the way */ + OSMR0 = LATCH; /* set initial match */ OSSR = 0xf; /* clear status on all timers */ setup_irq(IRQ_OST0, &pxa_timer_irq); - OIER |= OIER_E0; /* enable match on timer 0 to cause interrupts */ - OSCR = 0; /* initialize free-running timer, force first match */ + OIER = OIER_E0; /* enable match on timer 0 to cause interrupts */ + OSCR = 0; /* initialize free-running timer */ } #ifdef CONFIG_NO_IDLE_HZ diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index 400609f8b6a85e3703e5b64933bbfd0373d47a00..c312054dfb8872b3e2af9a1065fdd227488af969 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -98,6 +98,9 @@ struct platform_device tosascoop_jc_device = { .resource = tosa_scoop_jc_resources, }; +/* + * PCMCIA + */ static struct scoop_pcmcia_dev tosa_pcmcia_scoop[] = { { .dev = &tosascoop_device.dev, @@ -111,16 +114,155 @@ static struct scoop_pcmcia_dev tosa_pcmcia_scoop[] = { }, }; +static void tosa_pcmcia_init(void) +{ + /* Setup default state of GPIO outputs + before we enable them as outputs. */ + GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) | + GPIO_bit(GPIO49_nPWE) | GPIO_bit(GPIO50_nPIOR) | + GPIO_bit(GPIO51_nPIOW) | GPIO_bit(GPIO52_nPCE_1) | + GPIO_bit(GPIO53_nPCE_2); + + pxa_gpio_mode(GPIO48_nPOE_MD); + pxa_gpio_mode(GPIO49_nPWE_MD); + pxa_gpio_mode(GPIO50_nPIOR_MD); + pxa_gpio_mode(GPIO51_nPIOW_MD); + pxa_gpio_mode(GPIO55_nPREG_MD); + pxa_gpio_mode(GPIO56_nPWAIT_MD); + pxa_gpio_mode(GPIO57_nIOIS16_MD); + pxa_gpio_mode(GPIO52_nPCE_1_MD); + pxa_gpio_mode(GPIO53_nPCE_2_MD); + pxa_gpio_mode(GPIO54_pSKTSEL_MD); +} + +static struct scoop_pcmcia_config tosa_pcmcia_config = { + .devs = &tosa_pcmcia_scoop[0], + .num_devs = 2, + .pcmcia_init = tosa_pcmcia_init, +}; + +/* + * USB Device Controller + */ +static void tosa_udc_command(int cmd) +{ + switch(cmd) { + case PXA2XX_UDC_CMD_CONNECT: + set_scoop_gpio(&tosascoop_jc_device.dev,TOSA_SCOOP_JC_USB_PULLUP); + break; + case PXA2XX_UDC_CMD_DISCONNECT: + reset_scoop_gpio(&tosascoop_jc_device.dev,TOSA_SCOOP_JC_USB_PULLUP); + break; + } +} + +static int tosa_udc_is_connected(void) +{ + return ((GPLR(TOSA_GPIO_USB_IN) & GPIO_bit(TOSA_GPIO_USB_IN)) == 0); +} + + +static struct pxa2xx_udc_mach_info udc_info __initdata = { + .udc_command = tosa_udc_command, + .udc_is_connected = tosa_udc_is_connected, +}; + +/* + * MMC/SD Device + */ +static struct pxamci_platform_data tosa_mci_platform_data; + +static int tosa_mci_init(struct device *dev, irqreturn_t (*tosa_detect_int)(int, void *, struct pt_regs *), void *data) +{ + int err; + + /* setup GPIO for PXA25x MMC controller */ + pxa_gpio_mode(GPIO6_MMCCLK_MD); + pxa_gpio_mode(GPIO8_MMCCS0_MD); + pxa_gpio_mode(TOSA_GPIO_nSD_DETECT | GPIO_IN); + + tosa_mci_platform_data.detect_delay = msecs_to_jiffies(250); + + err = request_irq(TOSA_IRQ_GPIO_nSD_DETECT, tosa_detect_int, SA_INTERRUPT, + "MMC/SD card detect", data); + if (err) { + printk(KERN_ERR "tosa_mci_init: MMC/SD: can't request MMC card detect IRQ\n"); + return -1; + } + + set_irq_type(TOSA_IRQ_GPIO_nSD_DETECT, IRQT_BOTHEDGE); + + return 0; +} + +static void tosa_mci_setpower(struct device *dev, unsigned int vdd) +{ + struct pxamci_platform_data* p_d = dev->platform_data; + + if (( 1 << vdd) & p_d->ocr_mask) { + set_scoop_gpio(&tosascoop_device.dev,TOSA_SCOOP_PWR_ON); + } else { + reset_scoop_gpio(&tosascoop_device.dev,TOSA_SCOOP_PWR_ON); + } +} + +static int tosa_mci_get_ro(struct device *dev) +{ + return (read_scoop_reg(&tosascoop_device.dev, SCOOP_GPWR)&TOSA_SCOOP_SD_WP); +} + +static void tosa_mci_exit(struct device *dev, void *data) +{ + free_irq(TOSA_IRQ_GPIO_nSD_DETECT, data); +} + +static struct pxamci_platform_data tosa_mci_platform_data = { + .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, + .init = tosa_mci_init, + .get_ro = tosa_mci_get_ro, + .setpower = tosa_mci_setpower, + .exit = tosa_mci_exit, +}; + +/* + * Irda + */ +static void tosa_irda_transceiver_mode(struct device *dev, int mode) +{ + if (mode & IR_OFF) { + reset_scoop_gpio(&tosascoop_device.dev,TOSA_SCOOP_IR_POWERDWN); + pxa_gpio_mode(GPIO47_STTXD|GPIO_DFLT_LOW); + pxa_gpio_mode(GPIO47_STTXD|GPIO_OUT); + } else { + pxa_gpio_mode(GPIO47_STTXD_MD); + set_scoop_gpio(&tosascoop_device.dev,TOSA_SCOOP_IR_POWERDWN); + } +} + +static struct pxaficp_platform_data tosa_ficp_platform_data = { + .transceiver_cap = IR_SIRMODE | IR_OFF, + .transceiver_mode = tosa_irda_transceiver_mode, +}; + +/* + * Tosa Keyboard + */ +static struct platform_device tosakbd_device = { + .name = "tosa-keyboard", + .id = -1, +}; static struct platform_device *devices[] __initdata = { &tosascoop_device, &tosascoop_jc_device, + &tosakbd_device, }; static void __init tosa_init(void) { pxa_gpio_mode(TOSA_GPIO_ON_RESET | GPIO_IN); pxa_gpio_mode(TOSA_GPIO_TC6393_INT | GPIO_IN); + pxa_gpio_mode(TOSA_GPIO_USB_IN | GPIO_IN); /* setup sleep mode values */ PWER = 0x00000002; @@ -131,13 +273,15 @@ static void __init tosa_init(void) PGSR2 = 0x00014000; PCFR |= PCFR_OPDE; - // enable batt_fault + /* enable batt_fault */ PMCR = 0x01; - platform_add_devices(devices, ARRAY_SIZE(devices)); + pxa_set_mci_info(&tosa_mci_platform_data); + pxa_set_udc_info(&udc_info); + pxa_set_ficp_info(&tosa_ficp_platform_data); + platform_scoop_config = &tosa_pcmcia_config; - scoop_num = 2; - scoop_devs = &tosa_pcmcia_scoop[0]; + platform_add_devices(devices, ARRAY_SIZE(devices)); } static void __init fixup_tosa(struct machine_desc *desc, diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig index 4b63dc9eabfe74efd7aad7b6bc2a5e4fb8dd8804..129976866d479af79c6ec80b9eedc25d269e7ac7 100644 --- a/arch/arm/mach-realview/Kconfig +++ b/arch/arm/mach-realview/Kconfig @@ -8,4 +8,13 @@ config MACH_REALVIEW_EB help Include support for the ARM(R) RealView Emulation Baseboard platform. +config REALVIEW_MPCORE + bool "Support MPcore tile" + depends on MACH_REALVIEW_EB + help + Enable support for the MPCore tile on the Realview platform. + Since there are device address and interrupt differences, a + kernel built with this option enabled is not compatible with + other tiles. + endmenu diff --git a/arch/arm/mach-realview/Makefile b/arch/arm/mach-realview/Makefile index 8d37ea1605fdc8d08b67c01551c12d32a91bdd66..011a85c1062746f050cabf4cf581beb7424df3be 100644 --- a/arch/arm/mach-realview/Makefile +++ b/arch/arm/mach-realview/Makefile @@ -4,3 +4,4 @@ obj-y := core.o clock.o obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.o +obj-$(CONFIG_SMP) += platsmp.o headsmp.o diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index 482eb512ebe8a79d0b38d1989b39e68d77ac4add..4ea60d8b6e36838bdd5deb72955732297edf6cf9 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c @@ -550,6 +550,11 @@ static irqreturn_t realview_timer_interrupt(int irq, void *dev_id, struct pt_reg timer_tick(regs); +#ifdef CONFIG_SMP + smp_send_timer(); + update_process_times(user_mode(regs)); +#endif + write_sequnlock(&xtime_lock); return IRQ_HANDLED; diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h index 575599db74dbe0d120518266981a4177fe3d0d65..d83e8bad20384291b1ad8c8e99d400277546922d 100644 --- a/arch/arm/mach-realview/core.h +++ b/arch/arm/mach-realview/core.h @@ -23,6 +23,7 @@ #define __ASM_ARCH_REALVIEW_H #include +#include #include #define __io_address(n) __io(IO_ADDRESS(n)) diff --git a/arch/arm/mach-realview/headsmp.S b/arch/arm/mach-realview/headsmp.S new file mode 100644 index 0000000000000000000000000000000000000000..4075473cf68a1b061a05860ffd4f5da35e92e1e3 --- /dev/null +++ b/arch/arm/mach-realview/headsmp.S @@ -0,0 +1,39 @@ +/* + * linux/arch/arm/mach-realview/headsmp.S + * + * Copyright (c) 2003 ARM Limited + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include + + __INIT + +/* + * Realview specific entry point for secondary CPUs. This provides + * a "holding pen" into which all secondary cores are held until we're + * ready for them to initialise. + */ +ENTRY(realview_secondary_startup) + mrc p15, 0, r0, c0, c0, 5 + and r0, r0, #15 + adr r4, 1f + ldmia r4, {r5, r6} + sub r4, r4, r5 + add r6, r6, r4 +pen: ldr r7, [r6] + cmp r7, r0 + bne pen + + /* + * we've been released from the holding pen: secondary_stack + * should now contain the SVC stack for this core + */ + b secondary_startup + +1: .long . + .long pen_release diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c new file mode 100644 index 0000000000000000000000000000000000000000..09b35f62247a8863c268ec0ae4c1b3d3259c1d1d --- /dev/null +++ b/arch/arm/mach-realview/platsmp.c @@ -0,0 +1,195 @@ +/* + * linux/arch/arm/mach-realview/platsmp.c + * + * Copyright (C) 2002 ARM Ltd. + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "core.h" + +extern void realview_secondary_startup(void); + +/* + * control for which core is the next to come out of the secondary + * boot "holding pen" + */ +volatile int __cpuinitdata pen_release = -1; + +static unsigned int __init get_core_count(void) +{ + unsigned int ncores; + + ncores = __raw_readl(__io_address(REALVIEW_MPCORE_SCU_BASE) + SCU_CONFIG); + + return (ncores & 0x03) + 1; +} + +static DEFINE_SPINLOCK(boot_lock); + +void __cpuinit platform_secondary_init(unsigned int cpu) +{ + /* + * the primary core may have used a "cross call" soft interrupt + * to get this processor out of WFI in the BootMonitor - make + * sure that we are no longer being sent this soft interrupt + */ + smp_cross_call_done(cpumask_of_cpu(cpu)); + + /* + * if any interrupts are already enabled for the primary + * core (e.g. timer irq), then they will not have been enabled + * for us: do so + */ + gic_cpu_init(__io_address(REALVIEW_GIC_CPU_BASE)); + + /* + * let the primary processor know we're out of the + * pen, then head off into the C entry point + */ + pen_release = -1; + + /* + * Synchronise with the boot thread. + */ + spin_lock(&boot_lock); + spin_unlock(&boot_lock); +} + +int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + unsigned long timeout; + + /* + * set synchronisation state between this boot processor + * and the secondary one + */ + spin_lock(&boot_lock); + + /* + * The secondary processor is waiting to be released from + * the holding pen - release it, then wait for it to flag + * that it has been released by resetting pen_release. + * + * Note that "pen_release" is the hardware CPU ID, whereas + * "cpu" is Linux's internal ID. + */ + pen_release = cpu; + flush_cache_all(); + + /* + * XXX + * + * This is a later addition to the booting protocol: the + * bootMonitor now puts secondary cores into WFI, so + * poke_milo() no longer gets the cores moving; we need + * to send a soft interrupt to wake the secondary core. + * Use smp_cross_call() for this, since there's little + * point duplicating the code here + */ + smp_cross_call(cpumask_of_cpu(cpu)); + + timeout = jiffies + (1 * HZ); + while (time_before(jiffies, timeout)) { + if (pen_release == -1) + break; + + udelay(10); + } + + /* + * now the secondary core is starting up let it run its + * calibrations, then wait for it to finish + */ + spin_unlock(&boot_lock); + + return pen_release != -1 ? -ENOSYS : 0; +} + +static void __init poke_milo(void) +{ + extern void secondary_startup(void); + + /* nobody is to be released from the pen yet */ + pen_release = -1; + + /* + * write the address of secondary startup into the system-wide + * flags register, then clear the bottom two bits, which is what + * BootMonitor is waiting for + */ +#if 1 +#define REALVIEW_SYS_FLAGSS_OFFSET 0x30 + __raw_writel(virt_to_phys(realview_secondary_startup), + __io_address(REALVIEW_SYS_BASE) + + REALVIEW_SYS_FLAGSS_OFFSET); +#define REALVIEW_SYS_FLAGSC_OFFSET 0x34 + __raw_writel(3, + __io_address(REALVIEW_SYS_BASE) + + REALVIEW_SYS_FLAGSC_OFFSET); +#endif + + mb(); +} + +void __init smp_prepare_cpus(unsigned int max_cpus) +{ + unsigned int ncores = get_core_count(); + unsigned int cpu = smp_processor_id(); + int i; + + /* sanity check */ + if (ncores == 0) { + printk(KERN_ERR + "Realview: strange CM count of 0? Default to 1\n"); + + ncores = 1; + } + + if (ncores > NR_CPUS) { + printk(KERN_WARNING + "Realview: no. of cores (%d) greater than configured " + "maximum of %d - clipping\n", + ncores, NR_CPUS); + ncores = NR_CPUS; + } + + smp_store_cpu_info(cpu); + + /* + * are we trying to boot more cores than exist? + */ + if (max_cpus > ncores) + max_cpus = ncores; + + /* + * Initialise the possible/present maps. + * cpu_possible_map describes the set of CPUs which may be present + * cpu_present_map describes the set of CPUs populated + */ + for (i = 0; i < max_cpus; i++) { + cpu_set(i, cpu_possible_map); + cpu_set(i, cpu_present_map); + } + + /* + * Do we need any more CPUs? If so, then let them know where + * to start. Note that, on modern versions of MILO, the "poke" + * doesn't actually do anything until each individual core is + * sent a soft interrupt to get it out of WFI + */ + if (max_cpus > 1) + poke_milo(); +} diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c index 267bb07e39b73b57375049db5086ddf2b1b4a574..7dc32503fdf28ae68291c829866f2bbb8503624f 100644 --- a/arch/arm/mach-realview/realview_eb.c +++ b/arch/arm/mach-realview/realview_eb.c @@ -136,6 +136,11 @@ static struct amba_device *amba_devs[] __initdata = { static void __init gic_init_irq(void) { +#ifdef CONFIG_REALVIEW_MPCORE + writel(0x0000a05f, __io_address(REALVIEW_SYS_LOCK)); + writel(0x008003c0, __io_address(REALVIEW_SYS_BASE) + 0xd8); + writel(0x00000000, __io_address(REALVIEW_SYS_LOCK)); +#endif gic_dist_init(__io_address(REALVIEW_GIC_DIST_BASE)); gic_cpu_init(__io_address(REALVIEW_GIC_CPU_BASE)); } diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig index c796bcdd6158208c77cc1f97b7bfbb8a12ca6573..0b9d7ca49ec1ff9f9520cc02c845c0c8990c30b1 100644 --- a/arch/arm/mach-s3c2410/Kconfig +++ b/arch/arm/mach-s3c2410/Kconfig @@ -121,6 +121,14 @@ config S3C2410_BOOT_WATCHDOG system resets depends on the value of PCLK. The timeout on an 200MHz s3c2410 should be about 30 seconds. +config S3C2410_BOOT_ERROR_RESET + bool "S3C2410 Reboot on decompression error" + depends on ARCH_S3C2410 + help + Say y here to use the watchdog to reset the system if the + kernel decompressor detects an error during decompression. + + comment "S3C2410 Setup" config S3C2410_DMA diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c index 0b71c896bbd1ac5fe5ebb9ae55487cf01992e9d4..1be2567a7486606039f1f36902d97fad891b0aaf 100644 --- a/arch/arm/mach-s3c2410/mach-bast.c +++ b/arch/arm/mach-s3c2410/mach-bast.c @@ -89,32 +89,63 @@ /* macros to modify the physical addresses for io space */ -#define PA_CS2(item) ((item) + S3C2410_CS2) -#define PA_CS3(item) ((item) + S3C2410_CS3) -#define PA_CS4(item) ((item) + S3C2410_CS4) -#define PA_CS5(item) ((item) + S3C2410_CS5) +#define PA_CS2(item) (__phys_to_pfn((item) + S3C2410_CS2)) +#define PA_CS3(item) (__phys_to_pfn((item) + S3C2410_CS3)) +#define PA_CS4(item) (__phys_to_pfn((item) + S3C2410_CS4)) +#define PA_CS5(item) (__phys_to_pfn((item) + S3C2410_CS5)) static struct map_desc bast_iodesc[] __initdata = { /* ISA IO areas */ - - { (u32)S3C24XX_VA_ISA_BYTE, PA_CS2(BAST_PA_ISAIO), SZ_16M, MT_DEVICE }, - { (u32)S3C24XX_VA_ISA_WORD, PA_CS3(BAST_PA_ISAIO), SZ_16M, MT_DEVICE }, - - /* we could possibly compress the next set down into a set of smaller tables - * pagetables, but that would mean using an L2 section, and it still means - * we cannot actually feed the same register to an LDR due to 16K spacing - */ - + { + .virtual = (u32)S3C24XX_VA_ISA_BYTE, + .pfn = PA_CS2(BAST_PA_ISAIO), + .length = SZ_16M, + .type = MT_DEVICE, + }, { + .virtual = (u32)S3C24XX_VA_ISA_WORD, + .pfn = PA_CS3(BAST_PA_ISAIO), + .length = SZ_16M, + .type = MT_DEVICE, + }, /* bast CPLD control registers, and external interrupt controls */ - { (u32)BAST_VA_CTRL1, BAST_PA_CTRL1, SZ_1M, MT_DEVICE }, - { (u32)BAST_VA_CTRL2, BAST_PA_CTRL2, SZ_1M, MT_DEVICE }, - { (u32)BAST_VA_CTRL3, BAST_PA_CTRL3, SZ_1M, MT_DEVICE }, - { (u32)BAST_VA_CTRL4, BAST_PA_CTRL4, SZ_1M, MT_DEVICE }, - + { + .virtual = (u32)BAST_VA_CTRL1, + .pfn = __phys_to_pfn(BAST_PA_CTRL1), + .length = SZ_1M, + .type = MT_DEVICE, + }, { + .virtual = (u32)BAST_VA_CTRL2, + .pfn = __phys_to_pfn(BAST_PA_CTRL2), + .length = SZ_1M, + .type = MT_DEVICE, + }, { + .virtual = (u32)BAST_VA_CTRL3, + .pfn = __phys_to_pfn(BAST_PA_CTRL3), + .length = SZ_1M, + .type = MT_DEVICE, + }, { + .virtual = (u32)BAST_VA_CTRL4, + .pfn = __phys_to_pfn(BAST_PA_CTRL4), + .length = SZ_1M, + .type = MT_DEVICE, + }, /* PC104 IRQ mux */ - { (u32)BAST_VA_PC104_IRQREQ, BAST_PA_PC104_IRQREQ, SZ_1M, MT_DEVICE }, - { (u32)BAST_VA_PC104_IRQRAW, BAST_PA_PC104_IRQRAW, SZ_1M, MT_DEVICE }, - { (u32)BAST_VA_PC104_IRQMASK, BAST_PA_PC104_IRQMASK, SZ_1M, MT_DEVICE }, + { + .virtual = (u32)BAST_VA_PC104_IRQREQ, + .pfn = __phys_to_pfn(BAST_PA_PC104_IRQREQ), + .length = SZ_1M, + .type = MT_DEVICE, + }, { + .virtual = (u32)BAST_VA_PC104_IRQRAW, + .pfn = __phys_to_pfn(BAST_PA_PC104_IRQRAW), + .length = SZ_1M, + .type = MT_DEVICE, + }, { + .virtual = (u32)BAST_VA_PC104_IRQMASK, + .pfn = __phys_to_pfn(BAST_PA_PC104_IRQMASK), + .length = SZ_1M, + .type = MT_DEVICE, + }, /* peripheral space... one for each of fast/slow/byte/16bit */ /* note, ide is only decoded in word space, even though some registers diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c index 46b259673c18156606f6ffb190ce69790d4b5274..ae7e099bf6c80521eaf32cd9279881642dbea94d 100644 --- a/arch/arm/mach-s3c2410/mach-vr1000.c +++ b/arch/arm/mach-s3c2410/mach-vr1000.c @@ -74,27 +74,47 @@ /* macros to modify the physical addresses for io space */ -#define PA_CS2(item) ((item) + S3C2410_CS2) -#define PA_CS3(item) ((item) + S3C2410_CS3) -#define PA_CS4(item) ((item) + S3C2410_CS4) -#define PA_CS5(item) ((item) + S3C2410_CS5) +#define PA_CS2(item) (__phys_to_pfn((item) + S3C2410_CS2)) +#define PA_CS3(item) (__phys_to_pfn((item) + S3C2410_CS3)) +#define PA_CS4(item) (__phys_to_pfn((item) + S3C2410_CS4)) +#define PA_CS5(item) (__phys_to_pfn((item) + S3C2410_CS5)) static struct map_desc vr1000_iodesc[] __initdata = { /* ISA IO areas */ - - { (u32)S3C24XX_VA_ISA_BYTE, PA_CS2(BAST_PA_ISAIO), SZ_16M, MT_DEVICE }, - { (u32)S3C24XX_VA_ISA_WORD, PA_CS3(BAST_PA_ISAIO), SZ_16M, MT_DEVICE }, - - /* we could possibly compress the next set down into a set of smaller tables - * pagetables, but that would mean using an L2 section, and it still means - * we cannot actually feed the same register to an LDR due to 16K spacing - */ - - /* bast CPLD control registers, and external interrupt controls */ - { (u32)VR1000_VA_CTRL1, VR1000_PA_CTRL1, SZ_1M, MT_DEVICE }, - { (u32)VR1000_VA_CTRL2, VR1000_PA_CTRL2, SZ_1M, MT_DEVICE }, - { (u32)VR1000_VA_CTRL3, VR1000_PA_CTRL3, SZ_1M, MT_DEVICE }, - { (u32)VR1000_VA_CTRL4, VR1000_PA_CTRL4, SZ_1M, MT_DEVICE }, + { + .virtual = (u32)S3C24XX_VA_ISA_BYTE, + .pfn = PA_CS2(BAST_PA_ISAIO), + .length = SZ_16M, + .type = MT_DEVICE, + }, { + .virtual = (u32)S3C24XX_VA_ISA_WORD, + .pfn = PA_CS3(BAST_PA_ISAIO), + .length = SZ_16M, + .type = MT_DEVICE, + }, + + /* CPLD control registers, and external interrupt controls */ + { + .virtual = (u32)VR1000_VA_CTRL1, + .pfn = __phys_to_pfn(VR1000_PA_CTRL1), + .length = SZ_1M, + .type = MT_DEVICE, + }, { + .virtual = (u32)VR1000_VA_CTRL2, + .pfn = __phys_to_pfn(VR1000_PA_CTRL2), + .length = SZ_1M, + .type = MT_DEVICE, + }, { + .virtual = (u32)VR1000_VA_CTRL3, + .pfn = __phys_to_pfn(VR1000_PA_CTRL3), + .length = SZ_1M, + .type = MT_DEVICE, + }, { + .virtual = (u32)VR1000_VA_CTRL4, + .pfn = __phys_to_pfn(VR1000_PA_CTRL4), + .length = SZ_1M, + .type = MT_DEVICE, + }, /* peripheral space... one for each of fast/slow/byte/16bit */ /* note, ide is only decoded in word space, even though some registers diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c index 47e0420623fc25083a486f74887bff522260108b..e4b435e634e41a657321360a5c6d22173ad98fc6 100644 --- a/arch/arm/mach-sa1100/time.c +++ b/arch/arm/mach-sa1100/time.c @@ -124,11 +124,13 @@ static void __init sa1100_timer_init(void) tv.tv_sec = sa1100_get_rtc_time(); do_settimeofday(&tv); - OSMR0 = 0; /* set initial match at 0 */ + OIER = 0; /* disable any timer interrupts */ + OSCR = LATCH*2; /* push OSCR out of the way */ + OSMR0 = LATCH; /* set initial match */ OSSR = 0xf; /* clear status on all timers */ setup_irq(IRQ_OST0, &sa1100_timer_irq); - OIER |= OIER_E0; /* enable match on timer 0 to cause interrupts */ - OSCR = 0; /* initialize free-running timer, force first match */ + OIER = OIER_E0; /* enable match on timer 0 to cause interrupts */ + OSCR = 0; /* initialize free-running timer */ } #ifdef CONFIG_NO_IDLE_HZ diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c index fb5b40289de287fa34ab4e986e1fcbde7d18d99c..9e50127be635c7bbb52c4dc8824524ba4397f6fc 100644 --- a/arch/arm/mm/mm-armv.c +++ b/arch/arm/mm/mm-armv.c @@ -354,7 +354,7 @@ void __init build_mem_type_table(void) { struct cachepolicy *cp; unsigned int cr = get_cr(); - unsigned int user_pgprot; + unsigned int user_pgprot, kern_pgprot; int cpu_arch = cpu_architecture(); int i; @@ -381,7 +381,7 @@ void __init build_mem_type_table(void) } cp = &cache_policies[cachepolicy]; - user_pgprot = cp->pte; + kern_pgprot = user_pgprot = cp->pte; /* * ARMv6 and above have extended page tables. @@ -393,6 +393,7 @@ void __init build_mem_type_table(void) */ mem_types[MT_MEMORY].prot_sect &= ~PMD_BIT4; mem_types[MT_ROM].prot_sect &= ~PMD_BIT4; + /* * Mark cache clean areas and XIP ROM read only * from SVC mode and no access from userspace. @@ -412,32 +413,47 @@ void __init build_mem_type_table(void) * (iow, non-global) */ user_pgprot |= L_PTE_ASID; + +#ifdef CONFIG_SMP + /* + * Mark memory with the "shared" attribute for SMP systems + */ + user_pgprot |= L_PTE_SHARED; + kern_pgprot |= L_PTE_SHARED; + mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S; +#endif } + for (i = 0; i < 16; i++) { + unsigned long v = pgprot_val(protection_map[i]); + v = (v & ~(L_PTE_BUFFERABLE|L_PTE_CACHEABLE)) | user_pgprot; + protection_map[i] = __pgprot(v); + } + + mem_types[MT_LOW_VECTORS].prot_pte |= kern_pgprot; + mem_types[MT_HIGH_VECTORS].prot_pte |= kern_pgprot; + if (cpu_arch >= CPU_ARCH_ARMv5) { - mem_types[MT_LOW_VECTORS].prot_pte |= cp->pte & PTE_CACHEABLE; - mem_types[MT_HIGH_VECTORS].prot_pte |= cp->pte & PTE_CACHEABLE; +#ifndef CONFIG_SMP + /* + * Only use write-through for non-SMP systems + */ + mem_types[MT_LOW_VECTORS].prot_pte &= ~L_PTE_BUFFERABLE; + mem_types[MT_HIGH_VECTORS].prot_pte &= ~L_PTE_BUFFERABLE; +#endif } else { - mem_types[MT_LOW_VECTORS].prot_pte |= cp->pte; - mem_types[MT_HIGH_VECTORS].prot_pte |= cp->pte; mem_types[MT_MINICLEAN].prot_sect &= ~PMD_SECT_TEX(1); } + pgprot_kernel = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | + L_PTE_DIRTY | L_PTE_WRITE | + L_PTE_EXEC | kern_pgprot); + mem_types[MT_LOW_VECTORS].prot_l1 |= ecc_mask; mem_types[MT_HIGH_VECTORS].prot_l1 |= ecc_mask; mem_types[MT_MEMORY].prot_sect |= ecc_mask | cp->pmd; mem_types[MT_ROM].prot_sect |= cp->pmd; - for (i = 0; i < 16; i++) { - unsigned long v = pgprot_val(protection_map[i]); - v = (v & ~(PTE_BUFFERABLE|PTE_CACHEABLE)) | user_pgprot; - protection_map[i] = __pgprot(v); - } - - pgprot_kernel = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | - L_PTE_DIRTY | L_PTE_WRITE | - L_PTE_EXEC | cp->pte); - switch (cp->pmd) { case PMD_SECT_WT: mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_WT; diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S index 9bb5fff406fb73b094dc3c674d9c45e3b026a0f4..92f3ca31b7b90e46c03f05104f6e5d6300d2ce7b 100644 --- a/arch/arm/mm/proc-v6.S +++ b/arch/arm/mm/proc-v6.S @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -112,6 +113,9 @@ ENTRY(cpu_v6_dcache_clean_area) ENTRY(cpu_v6_switch_mm) mov r2, #0 ldr r1, [r1, #MM_CONTEXT_ID] @ get mm->context.id +#ifdef CONFIG_SMP + orr r0, r0, #2 @ set shared pgtable +#endif mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB mcr p15, 0, r2, c7, c10, 4 @ drain write buffer mcr p15, 0, r0, c2, c0, 0 @ set TTB 0 @@ -140,7 +144,7 @@ ENTRY(cpu_v6_switch_mm) ENTRY(cpu_v6_set_pte) str r1, [r0], #-2048 @ linux version - bic r2, r1, #0x000007f0 + bic r2, r1, #0x000003f0 bic r2, r2, #0x00000003 orr r2, r2, #PTE_EXT_AP0 | 2 @@ -191,6 +195,23 @@ cpu_v6_name: * - cache type register is implemented */ __v6_setup: +#ifdef CONFIG_SMP + /* Set up the SCU on core 0 only */ + mrc p15, 0, r0, c0, c0, 5 @ CPU core number + ands r0, r0, #15 + moveq r0, #0x10000000 @ SCU_BASE + orreq r0, r0, #0x00100000 + ldreq r5, [r0, #SCU_CTRL] + orreq r5, r5, #1 + streq r5, [r0, #SCU_CTRL] + +#ifndef CONFIG_CPU_DCACHE_DISABLE + mrc p15, 0, r0, c1, c0, 1 @ Enable SMP/nAMP mode + orr r0, r0, #0x20 + mcr p15, 0, r0, c1, c0, 1 +#endif +#endif + mov r0, #0 mcr p15, 0, r0, c7, c14, 0 @ clean+invalidate D cache mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache @@ -198,6 +219,9 @@ __v6_setup: mcr p15, 0, r0, c7, c10, 4 @ drain write buffer mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs mcr p15, 0, r0, c2, c0, 2 @ TTB control register +#ifdef CONFIG_SMP + orr r4, r4, #2 @ set shared pgtable +#endif mcr p15, 0, r4, c2, c0, 1 @ load TTB1 #ifdef CONFIG_VFP mrc p15, 0, r0, c1, c0, 2 diff --git a/arch/arm/nwfpe/fpa11.h b/arch/arm/nwfpe/fpa11.h index 9677ae8448e85f92ee742fe900faac31c70600a5..da4c616b6c49886c225a664a4d2b9c31eb052da5 100644 --- a/arch/arm/nwfpe/fpa11.h +++ b/arch/arm/nwfpe/fpa11.h @@ -60,7 +60,7 @@ typedef union tagFPREG { #ifdef CONFIG_FPE_NWFPE_XP floatx80 fExtended; #else - int padding[3]; + u32 padding[3]; #endif } FPREG; diff --git a/arch/arm/nwfpe/fpa11_cpdt.c b/arch/arm/nwfpe/fpa11_cpdt.c index b0db5cbcc3b190575774991ff759d1590461a7d2..32859fa8dcfcf5c5d85c200c65b588c4e73831c2 100644 --- a/arch/arm/nwfpe/fpa11_cpdt.c +++ b/arch/arm/nwfpe/fpa11_cpdt.c @@ -59,8 +59,13 @@ static inline void loadExtended(const unsigned int Fn, const unsigned int __user p = (unsigned int *) &fpa11->fpreg[Fn].fExtended; fpa11->fType[Fn] = typeExtended; get_user(p[0], &pMem[0]); /* sign & exponent */ +#ifdef __ARMEB__ + get_user(p[1], &pMem[1]); /* ms bits */ + get_user(p[2], &pMem[2]); /* ls bits */ +#else get_user(p[1], &pMem[2]); /* ls bits */ get_user(p[2], &pMem[1]); /* ms bits */ +#endif } #endif @@ -177,8 +182,13 @@ static inline void storeExtended(const unsigned int Fn, unsigned int __user *pMe } put_user(val.i[0], &pMem[0]); /* sign & exp */ +#ifdef __ARMEB__ + put_user(val.i[1], &pMem[1]); /* msw */ + put_user(val.i[2], &pMem[2]); +#else put_user(val.i[1], &pMem[2]); put_user(val.i[2], &pMem[1]); /* msw */ +#endif } #endif diff --git a/arch/arm/nwfpe/fpopcode.c b/arch/arm/nwfpe/fpopcode.c index 4c9f5703148c64d37138582cc8924b9be57add7f..67ff2ab08ea0162783dbee678e2f7885d578c84d 100644 --- a/arch/arm/nwfpe/fpopcode.c +++ b/arch/arm/nwfpe/fpopcode.c @@ -29,14 +29,14 @@ #ifdef CONFIG_FPE_NWFPE_XP const floatx80 floatx80Constant[] = { - {0x0000, 0x0000000000000000ULL}, /* extended 0.0 */ - {0x3fff, 0x8000000000000000ULL}, /* extended 1.0 */ - {0x4000, 0x8000000000000000ULL}, /* extended 2.0 */ - {0x4000, 0xc000000000000000ULL}, /* extended 3.0 */ - {0x4001, 0x8000000000000000ULL}, /* extended 4.0 */ - {0x4001, 0xa000000000000000ULL}, /* extended 5.0 */ - {0x3ffe, 0x8000000000000000ULL}, /* extended 0.5 */ - {0x4002, 0xa000000000000000ULL} /* extended 10.0 */ + { .high = 0x0000, .low = 0x0000000000000000ULL},/* extended 0.0 */ + { .high = 0x3fff, .low = 0x8000000000000000ULL},/* extended 1.0 */ + { .high = 0x4000, .low = 0x8000000000000000ULL},/* extended 2.0 */ + { .high = 0x4000, .low = 0xc000000000000000ULL},/* extended 3.0 */ + { .high = 0x4001, .low = 0x8000000000000000ULL},/* extended 4.0 */ + { .high = 0x4001, .low = 0xa000000000000000ULL},/* extended 5.0 */ + { .high = 0x3ffe, .low = 0x8000000000000000ULL},/* extended 0.5 */ + { .high = 0x4002, .low = 0xa000000000000000ULL},/* extended 10.0 */ }; #endif diff --git a/arch/arm/nwfpe/softfloat-specialize b/arch/arm/nwfpe/softfloat-specialize index acf409144763775b3d3a43377ffb9fa11bfb2feb..d4a4c8e06635c4ccd86817e1f61ab37319c7b8af 100644 --- a/arch/arm/nwfpe/softfloat-specialize +++ b/arch/arm/nwfpe/softfloat-specialize @@ -332,6 +332,7 @@ static floatx80 commonNaNToFloatx80( commonNaNT a ) z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 ); z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF; + z.__padding = 0; return z; } diff --git a/arch/arm/nwfpe/softfloat.c b/arch/arm/nwfpe/softfloat.c index f9f049132a17bffb920acb8df278f5e91b514f7a..0f9656e482ba40d6d43a49d081e4c6489797bad1 100644 --- a/arch/arm/nwfpe/softfloat.c +++ b/arch/arm/nwfpe/softfloat.c @@ -531,6 +531,7 @@ INLINE floatx80 packFloatx80( flag zSign, int32 zExp, bits64 zSig ) z.low = zSig; z.high = ( ( (bits16) zSign )<<15 ) + zExp; + z.__padding = 0; return z; } @@ -2831,6 +2832,7 @@ static floatx80 subFloatx80Sigs( struct roundingData *roundData, floatx80 a, flo roundData->exception |= float_flag_invalid; z.low = floatx80_default_nan_low; z.high = floatx80_default_nan_high; + z.__padding = 0; return z; } if ( aExp == 0 ) { @@ -2950,6 +2952,7 @@ floatx80 floatx80_mul( struct roundingData *roundData, floatx80 a, floatx80 b ) roundData->exception |= float_flag_invalid; z.low = floatx80_default_nan_low; z.high = floatx80_default_nan_high; + z.__padding = 0; return z; } return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); @@ -3015,6 +3018,7 @@ floatx80 floatx80_div( struct roundingData *roundData, floatx80 a, floatx80 b ) roundData->exception |= float_flag_invalid; z.low = floatx80_default_nan_low; z.high = floatx80_default_nan_high; + z.__padding = 0; return z; } roundData->exception |= float_flag_divbyzero; @@ -3093,6 +3097,7 @@ floatx80 floatx80_rem( struct roundingData *roundData, floatx80 a, floatx80 b ) roundData->exception |= float_flag_invalid; z.low = floatx80_default_nan_low; z.high = floatx80_default_nan_high; + z.__padding = 0; return z; } normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); @@ -3184,6 +3189,7 @@ floatx80 floatx80_sqrt( struct roundingData *roundData, floatx80 a ) roundData->exception |= float_flag_invalid; z.low = floatx80_default_nan_low; z.high = floatx80_default_nan_high; + z.__padding = 0; return z; } if ( aExp == 0 ) { diff --git a/arch/arm/nwfpe/softfloat.h b/arch/arm/nwfpe/softfloat.h index 14151700b6b2f00e3722bd7b852d7b7404f31606..978c699673c69e65ccb2957d09957597ac32942f 100644 --- a/arch/arm/nwfpe/softfloat.h +++ b/arch/arm/nwfpe/softfloat.h @@ -51,11 +51,17 @@ input or output the `floatx80' type will be defined. Software IEC/IEEE floating-point types. ------------------------------------------------------------------------------- */ -typedef unsigned long int float32; -typedef unsigned long long float64; +typedef u32 float32; +typedef u64 float64; typedef struct { - unsigned short high; - unsigned long long low; +#ifdef __ARMEB__ + u16 __padding; + u16 high; +#else + u16 high; + u16 __padding; +#endif + u64 low; } floatx80; /* diff --git a/arch/arm26/kernel/ptrace.c b/arch/arm26/kernel/ptrace.c index cf7e977d18c850eb4aba0bd3a2975cf48e85d525..4e6b7356a7221a29c20faa79299ba118bd9cfebe 100644 --- a/arch/arm26/kernel/ptrace.c +++ b/arch/arm26/kernel/ptrace.c @@ -546,7 +546,7 @@ static int ptrace_setfpregs(struct task_struct *tsk, void *ufp) sizeof(struct user_fp)) ? -EFAULT : 0; } -static int do_ptrace(int request, struct task_struct *child, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, long addr, long data) { unsigned long tmp; int ret; @@ -665,53 +665,6 @@ static int do_ptrace(int request, struct task_struct *child, long addr, long dat return ret; } -asmlinkage long sys_ptrace(long request, long pid, long addr, long data) -{ - struct task_struct *child; - int ret; - - lock_kernel(); - ret = -EPERM; - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - ret = security_ptrace(current->parent, current); - if (ret) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret == 0) - ret = do_ptrace(request, child, addr, data); - -out_tsk: - put_task_struct(child); -out: - unlock_kernel(); - return ret; -} - asmlinkage void syscall_trace(int why, struct pt_regs *regs) { unsigned long ip; diff --git a/arch/cris/arch-v10/README.mm b/arch/cris/arch-v10/README.mm index 6f08903f3139f866888cdde72d4b11aabf942aa6..517d1f027fe879efc310e49aae97732bd7c7f564 100644 --- a/arch/cris/arch-v10/README.mm +++ b/arch/cris/arch-v10/README.mm @@ -177,7 +177,7 @@ The example address is 0xd004000c; in binary this is: Given the top-level Page Directory, the offset in that directory is calculated using the upper 8 bits: -extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address) +static inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address) { return mm->pgd + (address >> PGDIR_SHIFT); } @@ -190,14 +190,14 @@ The pgd_t from our example will therefore be the 208'th (0xd0) entry in mm->pgd. Since the Middle Directory does not exist, it is a unity mapping: -extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) +static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) { return (pmd_t *) dir; } The Page Table provides the final lookup by using bits 13 to 23 as index: -extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address) +static inline pte_t * pte_offset(pmd_t * dir, unsigned long address) { return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)); diff --git a/arch/cris/arch-v10/kernel/ptrace.c b/arch/cris/arch-v10/kernel/ptrace.c index 130dd214e41d9e4d8f287afa8bb37e4d454dfa54..6cbd34a27b906cdce1805b710eedca1cd6cfa566 100644 --- a/arch/cris/arch-v10/kernel/ptrace.c +++ b/arch/cris/arch-v10/kernel/ptrace.c @@ -76,55 +76,11 @@ ptrace_disable(struct task_struct *child) * (in user space) where the result of the ptrace call is written (instead of * being returned). */ -asmlinkage int -sys_ptrace(long request, long pid, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, long addr, long data) { - struct task_struct *child; int ret; unsigned long __user *datap = (unsigned long __user *)data; - lock_kernel(); - ret = -EPERM; - - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - ret = security_ptrace(current->parent, current); - if (ret) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - - if (child) - get_task_struct(child); - - read_unlock(&tasklist_lock); - - if (!child) - goto out; - - ret = -EPERM; - - if (pid == 1) /* Leave the init process alone! */ - goto out_tsk; - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) - goto out_tsk; - switch (request) { /* Read word at location address. */ case PTRACE_PEEKTEXT: @@ -289,10 +245,7 @@ sys_ptrace(long request, long pid, long addr, long data) ret = ptrace_request(child, request, addr, data); break; } -out_tsk: - put_task_struct(child); -out: - unlock_kernel(); + return ret; } diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c index 693771961f859f788c4eec80bbea21df85ecf1e7..19bcad05716f7880506983cec1f580d88bb689cb 100644 --- a/arch/cris/arch-v10/kernel/signal.c +++ b/arch/cris/arch-v10/kernel/signal.c @@ -476,7 +476,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, * OK, we're invoking a handler */ -extern inline void +static inline void handle_signal(int canrestart, unsigned long sig, siginfo_t *info, struct k_sigaction *ka, sigset_t *oldset, struct pt_regs * regs) diff --git a/arch/cris/arch-v32/drivers/cryptocop.c b/arch/cris/arch-v32/drivers/cryptocop.c index ca72076c630a9efee555ab7894983f70633d0357..501fa52d8d3a1974285b1d8c1d0e9e73444f9f37 100644 --- a/arch/cris/arch-v32/drivers/cryptocop.c +++ b/arch/cris/arch-v32/drivers/cryptocop.c @@ -277,7 +277,7 @@ struct file_operations cryptocop_fops = { static void free_cdesc(struct cryptocop_dma_desc *cdesc) { DEBUG(printk("free_cdesc: cdesc 0x%p, from_pool=%d\n", cdesc, cdesc->from_pool)); - if (cdesc->free_buf) kfree(cdesc->free_buf); + kfree(cdesc->free_buf); if (cdesc->from_pool) { unsigned long int flags; @@ -2950,15 +2950,15 @@ static int cryptocop_ioctl_process(struct inode *inode, struct file *filp, unsig put_page(outpages[i]); } - if (digest_result) kfree(digest_result); - if (inpages) kfree(inpages); - if (outpages) kfree(outpages); + kfree(digest_result); + kfree(inpages); + kfree(outpages); if (cop){ - if (cop->tfrm_op.indata) kfree(cop->tfrm_op.indata); - if (cop->tfrm_op.outdata) kfree(cop->tfrm_op.outdata); + kfree(cop->tfrm_op.indata); + kfree(cop->tfrm_op.outdata); kfree(cop); } - if (jc) kfree(jc); + kfree(jc); DEBUG(print_lock_status()); diff --git a/arch/cris/arch-v32/kernel/ptrace.c b/arch/cris/arch-v32/kernel/ptrace.c index 208489da2a87fe0ee7ad1843ae69b28439539d4c..5528b83a622b62e666f2e4241967353724f47f7e 100644 --- a/arch/cris/arch-v32/kernel/ptrace.c +++ b/arch/cris/arch-v32/kernel/ptrace.c @@ -99,55 +99,11 @@ ptrace_disable(struct task_struct *child) } -asmlinkage int -sys_ptrace(long request, long pid, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, long addr, long data) { - struct task_struct *child; int ret; unsigned long __user *datap = (unsigned long __user *)data; - lock_kernel(); - ret = -EPERM; - - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - ret = security_ptrace(current->parent, current); - if (ret) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - - if (child) - get_task_struct(child); - - read_unlock(&tasklist_lock); - - if (!child) - goto out; - - ret = -EPERM; - - if (pid == 1) /* Leave the init process alone! */ - goto out_tsk; - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) - goto out_tsk; - switch (request) { /* Read word at location address. */ case PTRACE_PEEKTEXT: @@ -347,10 +303,7 @@ sys_ptrace(long request, long pid, long addr, long data) ret = ptrace_request(child, request, addr, data); break; } -out_tsk: - put_task_struct(child); -out: - unlock_kernel(); + return ret; } diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c index 0a3614dab88701b2827e26ce5858c94bf824852e..99e59b3eacf8fd5cd4616108873be9afbc460401 100644 --- a/arch/cris/arch-v32/kernel/signal.c +++ b/arch/cris/arch-v32/kernel/signal.c @@ -513,7 +513,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, } /* Invoke a singal handler to, well, handle the signal. */ -extern inline void +static inline void handle_signal(int canrestart, unsigned long sig, siginfo_t *info, struct k_sigaction *ka, sigset_t *oldset, struct pt_regs * regs) diff --git a/arch/cris/mm/ioremap.c b/arch/cris/mm/ioremap.c index a92ac9877582f29acea28be385ebccfc9ed01ca5..1780df3ed9e590997529aadcbd9d3a1c7f134abd 100644 --- a/arch/cris/mm/ioremap.c +++ b/arch/cris/mm/ioremap.c @@ -16,7 +16,7 @@ #include #include -extern inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, +static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, unsigned long phys_addr, pgprot_t prot) { unsigned long end; diff --git a/arch/frv/kernel/ptrace.c b/arch/frv/kernel/ptrace.c index cb335a14a315ae3d18ac319939754725f4b89b67..f953484e7d596eced5666356750f6ef72f2239f6 100644 --- a/arch/frv/kernel/ptrace.c +++ b/arch/frv/kernel/ptrace.c @@ -106,48 +106,11 @@ void ptrace_enable(struct task_struct *child) child->thread.frame0->__status |= REG__STATUS_STEP; } -asmlinkage long sys_ptrace(long request, long pid, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, long addr, long data) { - struct task_struct *child; unsigned long tmp; int ret; - lock_kernel(); - ret = -EPERM; - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - ret = security_ptrace(current->parent, current); - if (ret) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) - goto out_tsk; - switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ @@ -351,10 +314,6 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data) ret = -EIO; break; } -out_tsk: - put_task_struct(child); -out: - unlock_kernel(); return ret; } diff --git a/arch/h8300/kernel/ptrace.c b/arch/h8300/kernel/ptrace.c index a569fe4aa2842c34271174a0dfedecc232ff986e..0ff6f79b0fedcf240fc56af0e1f8c679fb9db716 100644 --- a/arch/h8300/kernel/ptrace.c +++ b/arch/h8300/kernel/ptrace.c @@ -57,43 +57,10 @@ void ptrace_disable(struct task_struct *child) h8300_disable_trace(child); } -asmlinkage long sys_ptrace(long request, long pid, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, long addr, long data) { - struct task_struct *child; int ret; - lock_kernel(); - ret = -EPERM; - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) - goto out_tsk; - switch (request) { case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { @@ -251,10 +218,6 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data) ret = -EIO; break; } -out_tsk: - put_task_struct(child); -out: - unlock_kernel(); return ret; } diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index bac0da731ee3ae98065d5771148648ad1df53940..dbf90ad6eac363a082deae5141c7fcac7a385279 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -997,8 +997,21 @@ source "drivers/Kconfig" source "fs/Kconfig" +menu "Instrumentation Support" + depends on EXPERIMENTAL + source "arch/i386/oprofile/Kconfig" +config KPROBES + bool "Kprobes (EXPERIMENTAL)" + help + Kprobes allows you to trap at almost any kernel address and + execute a callback function. register_kprobe() establishes + a probepoint and specifies the callback. Kprobes is useful + for kernel debugging, non-intrusive instrumentation and testing. + If in doubt, say "N". +endmenu + source "arch/i386/Kconfig.debug" source "security/Kconfig" diff --git a/arch/i386/Kconfig.debug b/arch/i386/Kconfig.debug index 5228c40a6fb21f6c7e34745ec537ca94c9781e7d..c48b424dd6401de05d5c8d3ecbbf661e15f0a78f 100644 --- a/arch/i386/Kconfig.debug +++ b/arch/i386/Kconfig.debug @@ -22,16 +22,6 @@ config DEBUG_STACKOVERFLOW This option will cause messages to be printed if free stack space drops below a certain limit. -config KPROBES - bool "Kprobes" - depends on DEBUG_KERNEL - help - Kprobes allows you to trap at almost any kernel address and - execute a callback function. register_kprobe() establishes - a probepoint and specifies the callback. Kprobes is useful - for kernel debugging, non-intrusive instrumentation and testing. - If in doubt, say "N". - config DEBUG_STACK_USAGE bool "Stack utilization instrumentation" depends on DEBUG_KERNEL diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index 7c724ffa08bb9617e4a1834fb20e5924565e281f..496a2c9909fe71d6c502e00683239183f08e72cc 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -559,14 +559,20 @@ void __devinit setup_local_APIC(void) * If Linux enabled the LAPIC against the BIOS default * disable it down before re-entering the BIOS on shutdown. * Otherwise the BIOS may get confused and not power-off. + * Additionally clear all LVT entries before disable_local_APIC + * for the case where Linux didn't enable the LAPIC. */ void lapic_shutdown(void) { - if (!cpu_has_apic || !enabled_via_apicbase) + if (!cpu_has_apic) return; local_irq_disable(); - disable_local_APIC(); + clear_local_APIC(); + + if (enabled_via_apicbase) + disable_local_APIC(); + local_irq_enable(); } diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index d2ef0c2aa93e462df516ec6e78c8473bed7c56b7..86e80c551478894c468b4225f72d00a4c772bcfc 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -447,8 +447,7 @@ static char * apm_event_name[] = { "system standby resume", "capabilities change" }; -#define NR_APM_EVENT_NAME \ - (sizeof(apm_event_name) / sizeof(apm_event_name[0])) +#define NR_APM_EVENT_NAME ARRAY_SIZE(apm_event_name) typedef struct lookup_t { int key; @@ -479,7 +478,7 @@ static const lookup_t error_table[] = { { APM_NO_ERROR, "BIOS did not set a return code" }, { APM_NOT_PRESENT, "No APM present" } }; -#define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t)) +#define ERROR_COUNT ARRAY_SIZE(error_table) /** * apm_error - display an APM error diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index 74145a33cb0fd9cc4b69d9e07717e65adac35f74..c145fb30002ed6894d37ffa03b33227166337243 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -30,8 +30,6 @@ static int disable_x86_serial_nr __devinitdata = 1; struct cpu_dev * cpu_devs[X86_VENDOR_NUM] = {}; -extern void mcheck_init(struct cpuinfo_x86 *c); - extern int disable_pse; static void default_init(struct cpuinfo_x86 * c) @@ -429,9 +427,8 @@ void __devinit identify_cpu(struct cpuinfo_x86 *c) } /* Init Machine Check Exception if available. */ -#ifdef CONFIG_X86_MCE mcheck_init(c); -#endif + if (c == &boot_cpu_data) sysenter_setup(); enable_sep_cpu(); diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c index caa9f77113439c3aa4fb0276c1c21961151baf64..871366b83b3f40cbc38ee91ec099e6cf3e5e15d0 100644 --- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c @@ -377,10 +377,9 @@ acpi_cpufreq_cpu_init ( arg0.buffer.length = 12; arg0.buffer.pointer = (u8 *) arg0_buf; - data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL); + data = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL); if (!data) return (-ENOMEM); - memset(data, 0, sizeof(struct cpufreq_acpi_io)); acpi_io_data[cpu] = data; diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c index 73a5dc5b26b8403493d099b6b22073561855fa58..edcd626001dabc538db9770ae2e8113381669829 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c @@ -171,10 +171,9 @@ static int get_ranges (unsigned char *pst) unsigned int speed; u8 fid, vid; - powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table) * (number_scales + 1)), GFP_KERNEL); + powernow_table = kzalloc((sizeof(struct cpufreq_frequency_table) * (number_scales + 1)), GFP_KERNEL); if (!powernow_table) return -ENOMEM; - memset(powernow_table, 0, (sizeof(struct cpufreq_frequency_table) * (number_scales + 1))); for (j=0 ; j < number_scales; j++) { fid = *pst++; @@ -305,16 +304,13 @@ static int powernow_acpi_init(void) goto err0; } - acpi_processor_perf = kmalloc(sizeof(struct acpi_processor_performance), + acpi_processor_perf = kzalloc(sizeof(struct acpi_processor_performance), GFP_KERNEL); - if (!acpi_processor_perf) { retval = -ENOMEM; goto err0; } - memset(acpi_processor_perf, 0, sizeof(struct acpi_processor_performance)); - if (acpi_processor_register_performance(acpi_processor_perf, 0)) { retval = -EIO; goto err1; @@ -337,14 +333,12 @@ static int powernow_acpi_init(void) goto err2; } - powernow_table = kmalloc((number_scales + 1) * (sizeof(struct cpufreq_frequency_table)), GFP_KERNEL); + powernow_table = kzalloc((number_scales + 1) * (sizeof(struct cpufreq_frequency_table)), GFP_KERNEL); if (!powernow_table) { retval = -ENOMEM; goto err2; } - memset(powernow_table, 0, ((number_scales + 1) * sizeof(struct cpufreq_frequency_table))); - pc.val = (unsigned long) acpi_processor_perf->states[0].control; for (i = 0; i < number_scales; i++) { u8 fid, vid; diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c index 2d5c9adba0cdc9a183743993dd3f2a794ccc6e47..68a1fc87f4cabb6cb63b71a9c84bc0132494365a 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c @@ -462,7 +462,6 @@ static int check_supported_cpu(unsigned int cpu) oldmask = current->cpus_allowed; set_cpus_allowed(current, cpumask_of_cpu(cpu)); - schedule(); if (smp_processor_id() != cpu) { printk(KERN_ERR "limiting to cpu %u failed\n", cpu); @@ -497,9 +496,7 @@ static int check_supported_cpu(unsigned int cpu) out: set_cpus_allowed(current, oldmask); - schedule(); return rc; - } static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst, u8 maxvid) @@ -913,7 +910,6 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi /* only run on specific CPU from here on */ oldmask = current->cpus_allowed; set_cpus_allowed(current, cpumask_of_cpu(pol->cpu)); - schedule(); if (smp_processor_id() != pol->cpu) { printk(KERN_ERR "limiting to cpu %u failed\n", pol->cpu); @@ -968,8 +964,6 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi err_out: set_cpus_allowed(current, oldmask); - schedule(); - return ret; } @@ -991,12 +985,11 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol) if (!check_supported_cpu(pol->cpu)) return -ENODEV; - data = kmalloc(sizeof(struct powernow_k8_data), GFP_KERNEL); + data = kzalloc(sizeof(struct powernow_k8_data), GFP_KERNEL); if (!data) { printk(KERN_ERR PFX "unable to alloc powernow_k8_data"); return -ENOMEM; } - memset(data,0,sizeof(struct powernow_k8_data)); data->cpu = pol->cpu; @@ -1026,7 +1019,6 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol) /* only run on specific CPU from here on */ oldmask = current->cpus_allowed; set_cpus_allowed(current, cpumask_of_cpu(pol->cpu)); - schedule(); if (smp_processor_id() != pol->cpu) { printk(KERN_ERR "limiting to cpu %u failed\n", pol->cpu); @@ -1045,7 +1037,6 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol) /* run on any CPU again */ set_cpus_allowed(current, oldmask); - schedule(); pol->governor = CPUFREQ_DEFAULT_GOVERNOR; pol->cpus = cpu_core_map[pol->cpu]; @@ -1080,7 +1071,6 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol) err_out: set_cpus_allowed(current, oldmask); - schedule(); powernow_k8_cpu_exit_acpi(data); kfree(data); @@ -1116,17 +1106,14 @@ static unsigned int powernowk8_get (unsigned int cpu) set_cpus_allowed(current, oldmask); return 0; } - preempt_disable(); - + if (query_current_values_with_pending_wait(data)) goto out; khz = find_khz_freq_from_fid(data->currfid); - out: - preempt_enable_no_resched(); +out: set_cpus_allowed(current, oldmask); - return khz; } diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c index 1465974256c9a57300427cc3ca851c890f79684f..edb9873e27e37fbb7ee1f66c89c5e87436bec3bd 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c @@ -67,7 +67,7 @@ static const struct cpu_id cpu_ids[] = { [CPU_MP4HT_D0] = {15, 3, 4 }, [CPU_MP4HT_E0] = {15, 4, 1 }, }; -#define N_IDS (sizeof(cpu_ids)/sizeof(cpu_ids[0])) +#define N_IDS ARRAY_SIZE(cpu_ids) struct cpu_model { @@ -423,12 +423,11 @@ static int centrino_cpu_init_acpi(struct cpufreq_policy *policy) } } - centrino_model[cpu] = kmalloc(sizeof(struct cpu_model), GFP_KERNEL); + centrino_model[cpu] = kzalloc(sizeof(struct cpu_model), GFP_KERNEL); if (!centrino_model[cpu]) { result = -ENOMEM; goto err_unreg; } - memset(centrino_model[cpu], 0, sizeof(struct cpu_model)); centrino_model[cpu]->model_name=NULL; centrino_model[cpu]->max_freq = p.states[0].core_frequency * 1000; diff --git a/arch/i386/kernel/cpu/mcheck/k7.c b/arch/i386/kernel/cpu/mcheck/k7.c index 7c6b9c73522fe3fe5ca4ece85654226c56d86963..fc5d5215e23deb24fd871c07c26494abfbfad42d 100644 --- a/arch/i386/kernel/cpu/mcheck/k7.c +++ b/arch/i386/kernel/cpu/mcheck/k7.c @@ -68,7 +68,7 @@ static fastcall void k7_machine_check(struct pt_regs * regs, long error_code) /* AMD K7 machine check is Intel like */ -void __devinit amd_mcheck_init(struct cpuinfo_x86 *c) +void amd_mcheck_init(struct cpuinfo_x86 *c) { u32 l, h; int i; diff --git a/arch/i386/kernel/cpu/mcheck/mce.c b/arch/i386/kernel/cpu/mcheck/mce.c index 2cf25d2ba0f11ee1b4120841e30f5cd9cabe5b98..6170af3c271aee39554172a0cd9eb9ce99452113 100644 --- a/arch/i386/kernel/cpu/mcheck/mce.c +++ b/arch/i386/kernel/cpu/mcheck/mce.c @@ -16,7 +16,7 @@ #include "mce.h" -int mce_disabled __devinitdata = 0; +int mce_disabled = 0; int nr_mce_banks; EXPORT_SYMBOL_GPL(nr_mce_banks); /* non-fatal.o */ @@ -31,7 +31,7 @@ static fastcall void unexpected_machine_check(struct pt_regs * regs, long error_ void fastcall (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check; /* This has to be run for each processor */ -void __devinit mcheck_init(struct cpuinfo_x86 *c) +void mcheck_init(struct cpuinfo_x86 *c) { if (mce_disabled==1) return; diff --git a/arch/i386/kernel/cpu/mcheck/p4.c b/arch/i386/kernel/cpu/mcheck/p4.c index 1d1e885f500ae9592d007844aec7000e06ff3017..fd2c459a31ef7f70a6433ba04378059b1db29f8c 100644 --- a/arch/i386/kernel/cpu/mcheck/p4.c +++ b/arch/i386/kernel/cpu/mcheck/p4.c @@ -77,7 +77,7 @@ fastcall void smp_thermal_interrupt(struct pt_regs *regs) } /* P4/Xeon Thermal regulation detect and init */ -static void __devinit intel_init_thermal(struct cpuinfo_x86 *c) +static void intel_init_thermal(struct cpuinfo_x86 *c) { u32 l, h; unsigned int cpu = smp_processor_id(); @@ -231,7 +231,7 @@ static fastcall void intel_machine_check(struct pt_regs * regs, long error_code) } -void __devinit intel_p4_mcheck_init(struct cpuinfo_x86 *c) +void intel_p4_mcheck_init(struct cpuinfo_x86 *c) { u32 l, h; int i; diff --git a/arch/i386/kernel/cpu/mcheck/p5.c b/arch/i386/kernel/cpu/mcheck/p5.c index 3a2e24baddc78ee63ab546d9fc78760c2880310d..94bc43d950cf1eb2c1e3db71940ab60e231cac2b 100644 --- a/arch/i386/kernel/cpu/mcheck/p5.c +++ b/arch/i386/kernel/cpu/mcheck/p5.c @@ -28,7 +28,7 @@ static fastcall void pentium_machine_check(struct pt_regs * regs, long error_cod } /* Set up machine check reporting for processors with Intel style MCE */ -void __devinit intel_p5_mcheck_init(struct cpuinfo_x86 *c) +void intel_p5_mcheck_init(struct cpuinfo_x86 *c) { u32 l, h; diff --git a/arch/i386/kernel/cpu/mcheck/p6.c b/arch/i386/kernel/cpu/mcheck/p6.c index 979b18bc95c192aa4fe2740245d4923319124927..deeae42ce199b80584e752609217978a7eb19b27 100644 --- a/arch/i386/kernel/cpu/mcheck/p6.c +++ b/arch/i386/kernel/cpu/mcheck/p6.c @@ -79,7 +79,7 @@ static fastcall void intel_machine_check(struct pt_regs * regs, long error_code) } /* Set up machine check reporting for processors with Intel style MCE */ -void __devinit intel_p6_mcheck_init(struct cpuinfo_x86 *c) +void intel_p6_mcheck_init(struct cpuinfo_x86 *c) { u32 l, h; int i; diff --git a/arch/i386/kernel/cpu/mcheck/winchip.c b/arch/i386/kernel/cpu/mcheck/winchip.c index 5b9d2dd411d3a9e469a7c2806bb4e0f41a221889..9e424b6c293d3fea2727a814d02cc79b729cacfc 100644 --- a/arch/i386/kernel/cpu/mcheck/winchip.c +++ b/arch/i386/kernel/cpu/mcheck/winchip.c @@ -22,7 +22,7 @@ static fastcall void winchip_machine_check(struct pt_regs * regs, long error_cod } /* Set up machine check reporting on the Winchip C6 series */ -void __devinit winchip_mcheck_init(struct cpuinfo_x86 *c) +void winchip_mcheck_init(struct cpuinfo_x86 *c) { u32 lo, hi; machine_check_vector = winchip_machine_check; diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c index 6345b430b105fd913c1fdca36768910e2f7fd580..32b0c24ab9a6dcca721414a7027635aa06d2c828 100644 --- a/arch/i386/kernel/kprobes.c +++ b/arch/i386/kernel/kprobes.c @@ -31,22 +31,16 @@ #include #include #include -#include #include #include #include #include -static struct kprobe *current_kprobe; -static unsigned long kprobe_status, kprobe_old_eflags, kprobe_saved_eflags; -static struct kprobe *kprobe_prev; -static unsigned long kprobe_status_prev, kprobe_old_eflags_prev, kprobe_saved_eflags_prev; -static struct pt_regs jprobe_saved_regs; -static long *jprobe_saved_esp; -/* copy of the kernel stack at the probe fire time */ -static kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE]; void jprobe_return_end(void); +DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; +DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); + /* * returns non-zero if opcode modifies the interrupt flag. */ @@ -91,29 +85,30 @@ void __kprobes arch_remove_kprobe(struct kprobe *p) { } -static inline void save_previous_kprobe(void) +static inline void save_previous_kprobe(struct kprobe_ctlblk *kcb) { - kprobe_prev = current_kprobe; - kprobe_status_prev = kprobe_status; - kprobe_old_eflags_prev = kprobe_old_eflags; - kprobe_saved_eflags_prev = kprobe_saved_eflags; + kcb->prev_kprobe.kp = kprobe_running(); + kcb->prev_kprobe.status = kcb->kprobe_status; + kcb->prev_kprobe.old_eflags = kcb->kprobe_old_eflags; + kcb->prev_kprobe.saved_eflags = kcb->kprobe_saved_eflags; } -static inline void restore_previous_kprobe(void) +static inline void restore_previous_kprobe(struct kprobe_ctlblk *kcb) { - current_kprobe = kprobe_prev; - kprobe_status = kprobe_status_prev; - kprobe_old_eflags = kprobe_old_eflags_prev; - kprobe_saved_eflags = kprobe_saved_eflags_prev; + __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp; + kcb->kprobe_status = kcb->prev_kprobe.status; + kcb->kprobe_old_eflags = kcb->prev_kprobe.old_eflags; + kcb->kprobe_saved_eflags = kcb->prev_kprobe.saved_eflags; } -static inline void set_current_kprobe(struct kprobe *p, struct pt_regs *regs) +static inline void set_current_kprobe(struct kprobe *p, struct pt_regs *regs, + struct kprobe_ctlblk *kcb) { - current_kprobe = p; - kprobe_saved_eflags = kprobe_old_eflags + __get_cpu_var(current_kprobe) = p; + kcb->kprobe_saved_eflags = kcb->kprobe_old_eflags = (regs->eflags & (TF_MASK | IF_MASK)); if (is_IF_modifier(p->opcode)) - kprobe_saved_eflags &= ~IF_MASK; + kcb->kprobe_saved_eflags &= ~IF_MASK; } static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) @@ -127,6 +122,7 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) regs->eip = (unsigned long)&p->ainsn.insn; } +/* Called with kretprobe_lock held */ void __kprobes arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs) { @@ -157,9 +153,15 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) int ret = 0; kprobe_opcode_t *addr = NULL; unsigned long *lp; + struct kprobe_ctlblk *kcb; - /* We're in an interrupt, but this is clear and BUG()-safe. */ + /* + * We don't want to be preempted for the entire + * duration of kprobe processing + */ preempt_disable(); + kcb = get_kprobe_ctlblk(); + /* Check if the application is using LDT entry for its code segment and * calculate the address by reading the base address from the LDT entry. */ @@ -173,15 +175,12 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) } /* Check we're not actually recursing */ if (kprobe_running()) { - /* We *are* holding lock here, so this is safe. - Disarm the probe we just hit, and ignore it. */ p = get_kprobe(addr); if (p) { - if (kprobe_status == KPROBE_HIT_SS && + if (kcb->kprobe_status == KPROBE_HIT_SS && *p->ainsn.insn == BREAKPOINT_INSTRUCTION) { regs->eflags &= ~TF_MASK; - regs->eflags |= kprobe_saved_eflags; - unlock_kprobes(); + regs->eflags |= kcb->kprobe_saved_eflags; goto no_kprobe; } /* We have reentered the kprobe_handler(), since @@ -190,26 +189,23 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) * just single step on the instruction of the new probe * without calling any user handlers. */ - save_previous_kprobe(); - set_current_kprobe(p, regs); + save_previous_kprobe(kcb); + set_current_kprobe(p, regs, kcb); p->nmissed++; prepare_singlestep(p, regs); - kprobe_status = KPROBE_REENTER; + kcb->kprobe_status = KPROBE_REENTER; return 1; } else { - p = current_kprobe; + p = __get_cpu_var(current_kprobe); if (p->break_handler && p->break_handler(p, regs)) { goto ss_probe; } } - /* If it's not ours, can't be delete race, (we hold lock). */ goto no_kprobe; } - lock_kprobes(); p = get_kprobe(addr); if (!p) { - unlock_kprobes(); if (regs->eflags & VM_MASK) { /* We are in virtual-8086 mode. Return 0 */ goto no_kprobe; @@ -232,8 +228,8 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) goto no_kprobe; } - kprobe_status = KPROBE_HIT_ACTIVE; - set_current_kprobe(p, regs); + set_current_kprobe(p, regs, kcb); + kcb->kprobe_status = KPROBE_HIT_ACTIVE; if (p->pre_handler && p->pre_handler(p, regs)) /* handler has already set things up, so skip ss setup */ @@ -241,7 +237,7 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) ss_probe: prepare_singlestep(p, regs); - kprobe_status = KPROBE_HIT_SS; + kcb->kprobe_status = KPROBE_HIT_SS; return 1; no_kprobe: @@ -269,9 +265,10 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) struct kretprobe_instance *ri = NULL; struct hlist_head *head; struct hlist_node *node, *tmp; - unsigned long orig_ret_address = 0; + unsigned long flags, orig_ret_address = 0; unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline; + spin_lock_irqsave(&kretprobe_lock, flags); head = kretprobe_inst_table_head(current); /* @@ -310,14 +307,15 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address)); regs->eip = orig_ret_address; - unlock_kprobes(); + reset_current_kprobe(); + spin_unlock_irqrestore(&kretprobe_lock, flags); preempt_enable_no_resched(); - /* - * By returning a non-zero value, we are telling - * kprobe_handler() that we have handled unlocking - * and re-enabling preemption. - */ + /* + * By returning a non-zero value, we are telling + * kprobe_handler() that we don't want the post_handler + * to run (and have re-enabled preemption) + */ return 1; } @@ -343,7 +341,8 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) * that is atop the stack is the address following the copied instruction. * We need to make it the address following the original instruction. */ -static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) +static void __kprobes resume_execution(struct kprobe *p, + struct pt_regs *regs, struct kprobe_ctlblk *kcb) { unsigned long *tos = (unsigned long *)®s->esp; unsigned long next_eip = 0; @@ -353,7 +352,7 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) switch (p->ainsn.insn[0]) { case 0x9c: /* pushfl */ *tos &= ~(TF_MASK | IF_MASK); - *tos |= kprobe_old_eflags; + *tos |= kcb->kprobe_old_eflags; break; case 0xc3: /* ret/lret */ case 0xcb: @@ -394,27 +393,30 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) /* * Interrupts are disabled on entry as trap1 is an interrupt gate and they - * remain disabled thoroughout this function. And we hold kprobe lock. + * remain disabled thoroughout this function. */ static inline int post_kprobe_handler(struct pt_regs *regs) { - if (!kprobe_running()) + struct kprobe *cur = kprobe_running(); + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + + if (!cur) return 0; - if ((kprobe_status != KPROBE_REENTER) && current_kprobe->post_handler) { - kprobe_status = KPROBE_HIT_SSDONE; - current_kprobe->post_handler(current_kprobe, regs, 0); + if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) { + kcb->kprobe_status = KPROBE_HIT_SSDONE; + cur->post_handler(cur, regs, 0); } - resume_execution(current_kprobe, regs); - regs->eflags |= kprobe_saved_eflags; + resume_execution(cur, regs, kcb); + regs->eflags |= kcb->kprobe_saved_eflags; /*Restore back the original saved kprobes variables and continue. */ - if (kprobe_status == KPROBE_REENTER) { - restore_previous_kprobe(); + if (kcb->kprobe_status == KPROBE_REENTER) { + restore_previous_kprobe(kcb); goto out; } - unlock_kprobes(); + reset_current_kprobe(); out: preempt_enable_no_resched(); @@ -429,18 +431,19 @@ static inline int post_kprobe_handler(struct pt_regs *regs) return 1; } -/* Interrupts disabled, kprobe_lock held. */ static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) { - if (current_kprobe->fault_handler - && current_kprobe->fault_handler(current_kprobe, regs, trapnr)) + struct kprobe *cur = kprobe_running(); + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + + if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) return 1; - if (kprobe_status & KPROBE_HIT_SS) { - resume_execution(current_kprobe, regs); - regs->eflags |= kprobe_old_eflags; + if (kcb->kprobe_status & KPROBE_HIT_SS) { + resume_execution(cur, regs, kcb); + regs->eflags |= kcb->kprobe_old_eflags; - unlock_kprobes(); + reset_current_kprobe(); preempt_enable_no_resched(); } return 0; @@ -453,39 +456,41 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *data) { struct die_args *args = (struct die_args *)data; + int ret = NOTIFY_DONE; + switch (val) { case DIE_INT3: if (kprobe_handler(args->regs)) - return NOTIFY_STOP; + ret = NOTIFY_STOP; break; case DIE_DEBUG: if (post_kprobe_handler(args->regs)) - return NOTIFY_STOP; + ret = NOTIFY_STOP; break; case DIE_GPF: - if (kprobe_running() && - kprobe_fault_handler(args->regs, args->trapnr)) - return NOTIFY_STOP; - break; case DIE_PAGE_FAULT: + /* kprobe_running() needs smp_processor_id() */ + preempt_disable(); if (kprobe_running() && kprobe_fault_handler(args->regs, args->trapnr)) - return NOTIFY_STOP; + ret = NOTIFY_STOP; + preempt_enable(); break; default: break; } - return NOTIFY_DONE; + return ret; } int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) { struct jprobe *jp = container_of(p, struct jprobe, kp); unsigned long addr; + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); - jprobe_saved_regs = *regs; - jprobe_saved_esp = ®s->esp; - addr = (unsigned long)jprobe_saved_esp; + kcb->jprobe_saved_regs = *regs; + kcb->jprobe_saved_esp = ®s->esp; + addr = (unsigned long)(kcb->jprobe_saved_esp); /* * TBD: As Linus pointed out, gcc assumes that the callee @@ -494,7 +499,8 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) * we also save and restore enough stack bytes to cover * the argument area. */ - memcpy(jprobes_stack, (kprobe_opcode_t *) addr, MIN_STACK_SIZE(addr)); + memcpy(kcb->jprobes_stack, (kprobe_opcode_t *)addr, + MIN_STACK_SIZE(addr)); regs->eflags &= ~IF_MASK; regs->eip = (unsigned long)(jp->entry); return 1; @@ -502,36 +508,40 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) void __kprobes jprobe_return(void) { - preempt_enable_no_resched(); + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + asm volatile (" xchgl %%ebx,%%esp \n" " int3 \n" " .globl jprobe_return_end \n" " jprobe_return_end: \n" " nop \n"::"b" - (jprobe_saved_esp):"memory"); + (kcb->jprobe_saved_esp):"memory"); } int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) { + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); u8 *addr = (u8 *) (regs->eip - 1); - unsigned long stack_addr = (unsigned long)jprobe_saved_esp; + unsigned long stack_addr = (unsigned long)(kcb->jprobe_saved_esp); struct jprobe *jp = container_of(p, struct jprobe, kp); if ((addr > (u8 *) jprobe_return) && (addr < (u8 *) jprobe_return_end)) { - if (®s->esp != jprobe_saved_esp) { + if (®s->esp != kcb->jprobe_saved_esp) { struct pt_regs *saved_regs = - container_of(jprobe_saved_esp, struct pt_regs, esp); + container_of(kcb->jprobe_saved_esp, + struct pt_regs, esp); printk("current esp %p does not match saved esp %p\n", - ®s->esp, jprobe_saved_esp); + ®s->esp, kcb->jprobe_saved_esp); printk("Saved registers for jprobe %p\n", jp); show_registers(saved_regs); printk("Current registers\n"); show_registers(regs); BUG(); } - *regs = jprobe_saved_regs; - memcpy((kprobe_opcode_t *) stack_addr, jprobes_stack, + *regs = kcb->jprobe_saved_regs; + memcpy((kprobe_opcode_t *) stack_addr, kcb->jprobes_stack, MIN_STACK_SIZE(stack_addr)); + preempt_enable_no_resched(); return 1; } return 0; diff --git a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt.c index fe1ffa55587d483668d0f19adda973df7ea57190..983f95707e1169f75c761bdfd7c43e87479f7c67 100644 --- a/arch/i386/kernel/ldt.c +++ b/arch/i386/kernel/ldt.c @@ -18,6 +18,7 @@ #include #include #include +#include #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */ static void flush_ldt(void *null) diff --git a/arch/i386/kernel/mca.c b/arch/i386/kernel/mca.c index 8600faeea29ddb186b1bb5b271ddf8c767ebc3da..558bb207720f1ecf13f2fe624037e9bf6b307a56 100644 --- a/arch/i386/kernel/mca.c +++ b/arch/i386/kernel/mca.c @@ -132,7 +132,7 @@ static struct resource mca_standard_resources[] = { { .start = 0x100, .end = 0x107, .name = "POS (MCA)" } }; -#define MCA_STANDARD_RESOURCES (sizeof(mca_standard_resources)/sizeof(struct resource)) +#define MCA_STANDARD_RESOURCES ARRAY_SIZE(mca_standard_resources) /** * mca_read_and_store_pos - read the POS registers into a memory buffer diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c index efd11f09c99663208a14e918d69fe2a607b666fe..5ffbb4b7ad059a038b7273de448b8e5f97ac5c20 100644 --- a/arch/i386/kernel/ptrace.c +++ b/arch/i386/kernel/ptrace.c @@ -354,49 +354,12 @@ ptrace_set_thread_area(struct task_struct *child, return 0; } -asmlinkage long sys_ptrace(long request, long pid, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, long addr, long data) { - struct task_struct *child; struct user * dummy = NULL; int i, ret; unsigned long __user *datap = (unsigned long __user *)data; - lock_kernel(); - ret = -EPERM; - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - ret = security_ptrace(current->parent, current); - if (ret) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) - goto out_tsk; - switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ @@ -663,10 +626,7 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data) ret = ptrace_request(child, request, addr, data); break; } -out_tsk: - put_task_struct(child); -out: - unlock_kernel(); + out_tsk: return ret; } diff --git a/arch/i386/kernel/reboot_fixups.c b/arch/i386/kernel/reboot_fixups.c index c9b87330aeeacfb49009faa725f51c1343d3a308..10e21a4773dd4e822a82d461c4d1ee17f3f7164d 100644 --- a/arch/i386/kernel/reboot_fixups.c +++ b/arch/i386/kernel/reboot_fixups.c @@ -10,6 +10,7 @@ #include #include +#include static void cs5530a_warm_reset(struct pci_dev *dev) { @@ -42,7 +43,7 @@ void mach_reboot_fixups(void) struct pci_dev *dev; int i; - for (i=0; i < (sizeof(fixups_table)/sizeof(fixups_table[0])); i++) { + for (i=0; i < ARRAY_SIZE(fixups_table); i++) { cur = &(fixups_table[i]); dev = pci_get_device(cur->vendor, cur->device, NULL); if (!dev) diff --git a/arch/i386/kernel/scx200.c b/arch/i386/kernel/scx200.c index 69e203a0d330ea8de05182f38bb53e5681fabfcb..9c968ae67c43dd1d4c008db3f37c8bc64a9f802d 100644 --- a/arch/i386/kernel/scx200.c +++ b/arch/i386/kernel/scx200.c @@ -12,6 +12,7 @@ #include #include +#include /* Verify that the configuration block really is there */ #define scx200_cb_probe(base) (inw((base) + SCx200_CBA) == (base)) diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 01b618e73ecd14ba6f9dedea08a718865715d266..47ec76794d02ac11bdcef2416bff7796a9099572 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -68,11 +68,9 @@ EXPORT_SYMBOL(smp_num_siblings); /* Package ID of each logical CPU */ int phys_proc_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID}; -EXPORT_SYMBOL(phys_proc_id); /* Core ID of each logical CPU */ int cpu_core_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID}; -EXPORT_SYMBOL(cpu_core_id); cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly; EXPORT_SYMBOL(cpu_sibling_map); @@ -612,7 +610,7 @@ static inline void __inquire_remote_apic(int apicid) printk("Inquiring remote APIC #%d...\n", apicid); - for (i = 0; i < sizeof(regs) / sizeof(*regs); i++) { + for (i = 0; i < ARRAY_SIZE(regs); i++) { printk("... APIC #%d %s: ", apicid, names[i]); /* diff --git a/arch/i386/oprofile/Kconfig b/arch/i386/oprofile/Kconfig index 5ade19801b97a598829b4b1dff817a6cc59a028e..d8a84088471a1c011868aae0b44558d15c9f1c0b 100644 --- a/arch/i386/oprofile/Kconfig +++ b/arch/i386/oprofile/Kconfig @@ -1,7 +1,3 @@ - -menu "Profiling support" - depends on EXPERIMENTAL - config PROFILING bool "Profiling support (EXPERIMENTAL)" help @@ -19,5 +15,3 @@ config OPROFILE If unsure, say N. -endmenu - diff --git a/arch/i386/power/cpu.c b/arch/i386/power/cpu.c index 1f1572692e0b7eeaa9c318a5051c98f4d8de2402..50a0bef8c85f691bc135167e595dc5b6521a8ec0 100644 --- a/arch/i386/power/cpu.c +++ b/arch/i386/power/cpu.c @@ -118,6 +118,7 @@ void __restore_processor_state(struct saved_context *ctxt) fix_processor_context(); do_fpu_end(); mtrr_ap_init(); + mcheck_init(&boot_cpu_data); } void restore_processor_state(void) diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 3b4248cff9a7d1218182dcf7d380eda86b3b426d..d4de8a4814be36781c9b266c8205d01123e0ad9f 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -191,6 +191,7 @@ config IOSAPIC config IA64_SGI_SN_XP tristate "Support communication between SGI SSIs" + depends on IA64_GENERIC || IA64_SGI_SN2 select IA64_UNCACHED_ALLOCATOR help An SGI machine can be divided into multiple Single System @@ -426,8 +427,21 @@ config GENERIC_PENDING_IRQ source "arch/ia64/hp/sim/Kconfig" +menu "Instrumentation Support" + depends on EXPERIMENTAL + source "arch/ia64/oprofile/Kconfig" +config KPROBES + bool "Kprobes (EXPERIMENTAL)" + help + Kprobes allows you to trap at almost any kernel address and + execute a callback function. register_kprobe() establishes + a probepoint and specifies the callback. Kprobes is useful + for kernel debugging, non-intrusive instrumentation and testing. + If in doubt, say "N". +endmenu + source "arch/ia64/Kconfig.debug" source "security/Kconfig" diff --git a/arch/ia64/Kconfig.debug b/arch/ia64/Kconfig.debug index fda67ac993d7e958b5747514594e73ce9cd9bf94..de9d507ba0fd466d8b466f54d1143a46d20caaa0 100644 --- a/arch/ia64/Kconfig.debug +++ b/arch/ia64/Kconfig.debug @@ -2,17 +2,6 @@ menu "Kernel hacking" source "lib/Kconfig.debug" -config KPROBES - bool "Kprobes" - depends on DEBUG_KERNEL - help - Kprobes allows you to trap at almost any kernel address and - execute a callback function. register_kprobe() establishes - a probepoint and specifies the callback. Kprobes is useful - for kernel debugging, non-intrusive instrumentation and testing. - If in doubt, say "N". - - choice prompt "Physical memory granularity" default IA64_GRANULE_64MB diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index b42ec37be51c317911e1037d85718a9b95fdc045..19ee635eeb707566daa0e3b8d5eafd895490a2a9 100644 --- a/arch/ia64/hp/sim/simserial.c +++ b/arch/ia64/hp/sim/simserial.c @@ -642,10 +642,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp) info->event = 0; info->tty = 0; if (info->blocked_open) { - if (info->close_delay) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(info->close_delay); - } + if (info->close_delay) + schedule_timeout_interruptible(info->close_delay); wake_up_interruptible(&info->open_wait); } info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c index 471086b808a4b942781aa19abe940fb08dc8533b..96736a119c911e22fcbab6d6e7aabb1529a04a9a 100644 --- a/arch/ia64/kernel/kprobes.c +++ b/arch/ia64/kernel/kprobes.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -38,13 +37,8 @@ extern void jprobe_inst_return(void); -/* kprobe_status settings */ -#define KPROBE_HIT_ACTIVE 0x00000001 -#define KPROBE_HIT_SS 0x00000002 - -static struct kprobe *current_kprobe, *kprobe_prev; -static unsigned long kprobe_status, kprobe_status_prev; -static struct pt_regs jprobe_saved_regs; +DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; +DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); enum instruction_type {A, I, M, F, B, L, X, u}; static enum instruction_type bundle_encoding[32][3] = { @@ -313,21 +307,22 @@ static int __kprobes valid_kprobe_addr(int template, int slot, return 0; } -static inline void save_previous_kprobe(void) +static inline void save_previous_kprobe(struct kprobe_ctlblk *kcb) { - kprobe_prev = current_kprobe; - kprobe_status_prev = kprobe_status; + kcb->prev_kprobe.kp = kprobe_running(); + kcb->prev_kprobe.status = kcb->kprobe_status; } -static inline void restore_previous_kprobe(void) +static inline void restore_previous_kprobe(struct kprobe_ctlblk *kcb) { - current_kprobe = kprobe_prev; - kprobe_status = kprobe_status_prev; + __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp; + kcb->kprobe_status = kcb->prev_kprobe.status; } -static inline void set_current_kprobe(struct kprobe *p) +static inline void set_current_kprobe(struct kprobe *p, + struct kprobe_ctlblk *kcb) { - current_kprobe = p; + __get_cpu_var(current_kprobe) = p; } static void kretprobe_trampoline(void) @@ -347,10 +342,11 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) struct kretprobe_instance *ri = NULL; struct hlist_head *head; struct hlist_node *node, *tmp; - unsigned long orig_ret_address = 0; + unsigned long flags, orig_ret_address = 0; unsigned long trampoline_address = ((struct fnptr *)kretprobe_trampoline)->ip; + spin_lock_irqsave(&kretprobe_lock, flags); head = kretprobe_inst_table_head(current); /* @@ -389,17 +385,19 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address)); regs->cr_iip = orig_ret_address; - unlock_kprobes(); + reset_current_kprobe(); + spin_unlock_irqrestore(&kretprobe_lock, flags); preempt_enable_no_resched(); - /* - * By returning a non-zero value, we are telling - * kprobe_handler() that we have handled unlocking - * and re-enabling preemption. - */ + /* + * By returning a non-zero value, we are telling + * kprobe_handler() that we don't want the post_handler + * to run (and have re-enabled preemption) + */ return 1; } +/* Called with kretprobe_lock held */ void __kprobes arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs) { @@ -606,17 +604,22 @@ static int __kprobes pre_kprobes_handler(struct die_args *args) int ret = 0; struct pt_regs *regs = args->regs; kprobe_opcode_t *addr = (kprobe_opcode_t *)instruction_pointer(regs); + struct kprobe_ctlblk *kcb; + /* + * We don't want to be preempted for the entire + * duration of kprobe processing + */ preempt_disable(); + kcb = get_kprobe_ctlblk(); /* Handle recursion cases */ if (kprobe_running()) { p = get_kprobe(addr); if (p) { - if ( (kprobe_status == KPROBE_HIT_SS) && + if ((kcb->kprobe_status == KPROBE_HIT_SS) && (p->ainsn.inst_flag == INST_FLAG_BREAK_INST)) { ia64_psr(regs)->ss = 0; - unlock_kprobes(); goto no_kprobe; } /* We have reentered the pre_kprobe_handler(), since @@ -625,17 +628,17 @@ static int __kprobes pre_kprobes_handler(struct die_args *args) * just single step on the instruction of the new probe * without calling any user handlers. */ - save_previous_kprobe(); - set_current_kprobe(p); + save_previous_kprobe(kcb); + set_current_kprobe(p, kcb); p->nmissed++; prepare_ss(p, regs); - kprobe_status = KPROBE_REENTER; + kcb->kprobe_status = KPROBE_REENTER; return 1; } else if (args->err == __IA64_BREAK_JPROBE) { /* * jprobe instrumented function just completed */ - p = current_kprobe; + p = __get_cpu_var(current_kprobe); if (p->break_handler && p->break_handler(p, regs)) { goto ss_probe; } @@ -645,10 +648,8 @@ static int __kprobes pre_kprobes_handler(struct die_args *args) } } - lock_kprobes(); p = get_kprobe(addr); if (!p) { - unlock_kprobes(); if (!is_ia64_break_inst(regs)) { /* * The breakpoint instruction was removed right @@ -665,8 +666,8 @@ static int __kprobes pre_kprobes_handler(struct die_args *args) goto no_kprobe; } - kprobe_status = KPROBE_HIT_ACTIVE; - set_current_kprobe(p); + set_current_kprobe(p, kcb); + kcb->kprobe_status = KPROBE_HIT_ACTIVE; if (p->pre_handler && p->pre_handler(p, regs)) /* @@ -678,7 +679,7 @@ static int __kprobes pre_kprobes_handler(struct die_args *args) ss_probe: prepare_ss(p, regs); - kprobe_status = KPROBE_HIT_SS; + kcb->kprobe_status = KPROBE_HIT_SS; return 1; no_kprobe: @@ -688,23 +689,25 @@ static int __kprobes pre_kprobes_handler(struct die_args *args) static int __kprobes post_kprobes_handler(struct pt_regs *regs) { - if (!kprobe_running()) + struct kprobe *cur = kprobe_running(); + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + + if (!cur) return 0; - if ((kprobe_status != KPROBE_REENTER) && current_kprobe->post_handler) { - kprobe_status = KPROBE_HIT_SSDONE; - current_kprobe->post_handler(current_kprobe, regs, 0); + if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) { + kcb->kprobe_status = KPROBE_HIT_SSDONE; + cur->post_handler(cur, regs, 0); } - resume_execution(current_kprobe, regs); + resume_execution(cur, regs); /*Restore back the original saved kprobes variables and continue. */ - if (kprobe_status == KPROBE_REENTER) { - restore_previous_kprobe(); + if (kcb->kprobe_status == KPROBE_REENTER) { + restore_previous_kprobe(kcb); goto out; } - - unlock_kprobes(); + reset_current_kprobe(); out: preempt_enable_no_resched(); @@ -713,16 +716,15 @@ static int __kprobes post_kprobes_handler(struct pt_regs *regs) static int __kprobes kprobes_fault_handler(struct pt_regs *regs, int trapnr) { - if (!kprobe_running()) - return 0; + struct kprobe *cur = kprobe_running(); + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); - if (current_kprobe->fault_handler && - current_kprobe->fault_handler(current_kprobe, regs, trapnr)) + if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) return 1; - if (kprobe_status & KPROBE_HIT_SS) { - resume_execution(current_kprobe, regs); - unlock_kprobes(); + if (kcb->kprobe_status & KPROBE_HIT_SS) { + resume_execution(cur, regs); + reset_current_kprobe(); preempt_enable_no_resched(); } @@ -733,31 +735,38 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *data) { struct die_args *args = (struct die_args *)data; + int ret = NOTIFY_DONE; + switch(val) { case DIE_BREAK: if (pre_kprobes_handler(args)) - return NOTIFY_STOP; + ret = NOTIFY_STOP; break; case DIE_SS: if (post_kprobes_handler(args->regs)) - return NOTIFY_STOP; + ret = NOTIFY_STOP; break; case DIE_PAGE_FAULT: - if (kprobes_fault_handler(args->regs, args->trapnr)) - return NOTIFY_STOP; + /* kprobe_running() needs smp_processor_id() */ + preempt_disable(); + if (kprobe_running() && + kprobes_fault_handler(args->regs, args->trapnr)) + ret = NOTIFY_STOP; + preempt_enable(); default: break; } - return NOTIFY_DONE; + return ret; } int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) { struct jprobe *jp = container_of(p, struct jprobe, kp); unsigned long addr = ((struct fnptr *)(jp->entry))->ip; + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); /* save architectural state */ - jprobe_saved_regs = *regs; + kcb->jprobe_saved_regs = *regs; /* after rfi, execute the jprobe instrumented function */ regs->cr_iip = addr & ~0xFULL; @@ -775,7 +784,10 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) { - *regs = jprobe_saved_regs; + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + + *regs = kcb->jprobe_saved_regs; + preempt_enable_no_resched(); return 1; } diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index f7dfc107cb7bd6040eca8f4e7aa46b7531c4a443..410d4804fa6e0cb4086e6fb6af75760337a60d23 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -4940,7 +4940,7 @@ sys_perfmonctl (int fd, int cmd, void __user *arg, int count) if (call_made && PFM_CMD_RW_ARG(cmd) && copy_to_user(arg, args_k, base_sz*count)) ret = -EFAULT; error_args: - if (args_k) kfree(args_k); + kfree(args_k); DPRINT(("cmd=%s ret=%ld\n", PFM_CMD_NAME(cmd), ret)); diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index fc56ca2da35899e0bd5b5b42dfe2e4c399d1fc8d..3af6de36a4822e72c537a12f4a8ef6fe6f950ef7 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -92,6 +92,13 @@ extern void efi_initialize_iomem_resources(struct resource *, extern char _text[], _end[], _etext[]; unsigned long ia64_max_cacheline_size; + +int dma_get_cache_alignment(void) +{ + return ia64_max_cacheline_size; +} +EXPORT_SYMBOL(dma_get_cache_alignment); + unsigned long ia64_iobase; /* virtual address for I/O accesses */ EXPORT_SYMBOL(ia64_iobase); struct io_space io_space[MAX_IO_SPACES]; diff --git a/arch/ia64/oprofile/Kconfig b/arch/ia64/oprofile/Kconfig index 56e6f614b04a58592203d5fc3a12f69319da485a..97271ab484dc8406a181fe36f717ff2b5e3ba417 100644 --- a/arch/ia64/oprofile/Kconfig +++ b/arch/ia64/oprofile/Kconfig @@ -1,7 +1,3 @@ - -menu "Profiling support" - depends on EXPERIMENTAL - config PROFILING bool "Profiling support (EXPERIMENTAL)" help @@ -22,5 +18,3 @@ config OPROFILE If unsure, say N. -endmenu - diff --git a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c index 6df7fb60dfea5af07a03950b62dc3d200c77a600..e79bbc94216dab99289925ba8208181952eb4369 100644 --- a/arch/m68k/atari/time.c +++ b/arch/m68k/atari/time.c @@ -212,10 +212,8 @@ int atari_tt_hwclk( int op, struct rtc_time *t ) * additionally the RTC_SET bit is set to prevent an update cycle. */ - while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HWCLK_POLL_INTERVAL); - } + while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) + schedule_timeout_interruptible(HWCLK_POLL_INTERVAL); local_irq_save(flags); RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET ); diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c index f7f1d2e5b90bcec403526c14c1f183fc74d3fe4e..7e54422685cfc1ed8737d29bac74124b3a4f8cdd 100644 --- a/arch/m68k/kernel/ptrace.c +++ b/arch/m68k/kernel/ptrace.c @@ -121,48 +121,11 @@ void ptrace_disable(struct task_struct *child) child->thread.work.syscall_trace = 0; } -asmlinkage long sys_ptrace(long request, long pid, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, long addr, long data) { - struct task_struct *child; unsigned long tmp; int i, ret = 0; - lock_kernel(); - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) { - ret = -EPERM; - goto out; - } - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - goto out; - } - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (unlikely(!child)) { - ret = -ESRCH; - goto out; - } - - /* you may not mess with init */ - if (unlikely(pid == 1)) { - ret = -EPERM; - goto out_tsk; - } - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret) - goto out_tsk; - switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ @@ -317,14 +280,10 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data) ret = ptrace_request(child, request, addr, data); break; } -out_tsk: - put_task_struct(child); -out: - unlock_kernel(); + return ret; out_eio: - ret = -EIO; - goto out_tsk; + return -EIO; } asmlinkage void syscall_trace(void) diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig index 8520df9cee6dd8c6cd9464b9d28bd23ee2292c83..b96498120fe9aed0c3dc9565c89e9b93c92bb8d2 100644 --- a/arch/m68knommu/Kconfig +++ b/arch/m68knommu/Kconfig @@ -71,6 +71,11 @@ config M5206e help Motorola ColdFire 5206e processor support. +config M520x + bool "MCF520x" + help + Freescale Coldfire 5207/5208 processor support. + config M523x bool "MCF523x" help @@ -120,7 +125,7 @@ config M527x config COLDFIRE bool - depends on (M5206 || M5206e || M523x || M5249 || M527x || M5272 || M528x || M5307 || M5407) + depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M5272 || M528x || M5307 || M5407) default y choice @@ -322,6 +327,12 @@ config ELITE help Support for the Motorola M5206eLITE board. +config M5208EVB + bool "Freescale M5208EVB board support" + depends on M520x + help + Support for the Freescale Coldfire M5208EVB. + config M5235EVB bool "Freescale M5235EVB support" depends on M523x @@ -465,10 +476,10 @@ config ARNEWSH default y depends on (ARN5206 || ARN5307) -config MOTOROLA +config FREESCALE bool default y - depends on (M5206eC3 || M5235EVB || M5249C3 || M5271EVB || M5272C3 || M5275EVB || M5282EVB || M5307C3 || M5407C3) + depends on (M5206eC3 || M5208EVB || M5235EVB || M5249C3 || M5271EVB || M5272C3 || M5275EVB || M5282EVB || M5307C3 || M5407C3) config HW_FEITH bool diff --git a/arch/m68knommu/Makefile b/arch/m68knommu/Makefile index b8fdf191b8f6b3e95d05830f13dc33e7b06c1425..b6b5c14e55fd1dbc89baf0de69477d6749ddca09 100644 --- a/arch/m68knommu/Makefile +++ b/arch/m68knommu/Makefile @@ -14,6 +14,7 @@ platform-$(CONFIG_M68VZ328) := 68VZ328 platform-$(CONFIG_M68360) := 68360 platform-$(CONFIG_M5206) := 5206 platform-$(CONFIG_M5206e) := 5206e +platform-$(CONFIG_M520x) := 520x platform-$(CONFIG_M523x) := 523x platform-$(CONFIG_M5249) := 5249 platform-$(CONFIG_M527x) := 527x @@ -29,7 +30,7 @@ board-$(CONFIG_UCDIMM) := ucdimm board-$(CONFIG_UCQUICC) := uCquicc board-$(CONFIG_DRAGEN2) := de2 board-$(CONFIG_ARNEWSH) := ARNEWSH -board-$(CONFIG_MOTOROLA) := MOTOROLA +board-$(CONFIG_FREESCALE) := FREESCALE board-$(CONFIG_M5235EVB) := M5235EVB board-$(CONFIG_M5271EVB) := M5271EVB board-$(CONFIG_M5275EVB) := M5275EVB @@ -41,6 +42,7 @@ board-$(CONFIG_SECUREEDGEMP3) := MP3 board-$(CONFIG_CLEOPATRA) := CLEOPATRA board-$(CONFIG_senTec) := senTec board-$(CONFIG_SNEHA) := SNEHA +board-$(CONFIG_M5208EVB) := M5208EVB board-$(CONFIG_MOD5272) := MOD5272 BOARD := $(board-y) @@ -56,6 +58,7 @@ MODEL := $(model-y) # cpuclass-$(CONFIG_M5206) := 5307 cpuclass-$(CONFIG_M5206e) := 5307 +cpuclass-$(CONFIG_M520x) := 5307 cpuclass-$(CONFIG_M523x) := 5307 cpuclass-$(CONFIG_M5249) := 5307 cpuclass-$(CONFIG_M527x) := 5307 @@ -80,6 +83,7 @@ export PLATFORM BOARD MODEL CPUCLASS # cflags-$(CONFIG_M5206) := -m5200 -Wa,-S -Wa,-m5200 cflags-$(CONFIG_M5206e) := -m5200 -Wa,-S -Wa,-m5200 +cflags-$(CONFIG_M520x) := -m5307 -Wa,-S -Wa,-m5307 cflags-$(CONFIG_M523x) := -m5307 -Wa,-S -Wa,-m5307 cflags-$(CONFIG_M5249) := -m5200 -Wa,-S -Wa,-m5200 cflags-$(CONFIG_M527x) := -m5307 -Wa,-S -Wa,-m5307 @@ -95,7 +99,6 @@ cflags-$(CONFIG_M68360) := -m68332 AFLAGS += $(cflags-y) CFLAGS += $(cflags-y) -CFLAGS += -fno-builtin CFLAGS += -O1 -g CFLAGS += -D__linux__ CFLAGS += -DUTS_SYSNAME=\"uClinux\" diff --git a/arch/m68knommu/kernel/asm-offsets.c b/arch/m68knommu/kernel/asm-offsets.c index cd3ffe12653e1577e3a31068a9f64eecb9db45a4..b988c7bdc6e4d6fd78656b68b1e41fdea1131da0 100644 --- a/arch/m68knommu/kernel/asm-offsets.c +++ b/arch/m68knommu/kernel/asm-offsets.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #define DEFINE(sym, val) \ diff --git a/arch/m68knommu/kernel/ptrace.c b/arch/m68knommu/kernel/ptrace.c index 621d7b91ccfe5147833dc47f1de8e8c6de79c1b7..262ab8c72e5f31bb6e43151b5aa8568241e49647 100644 --- a/arch/m68knommu/kernel/ptrace.c +++ b/arch/m68knommu/kernel/ptrace.c @@ -101,43 +101,10 @@ void ptrace_disable(struct task_struct *child) put_reg(child, PT_SR, tmp); } -asmlinkage long sys_ptrace(long request, long pid, long addr, long data) +long arch_ptrace(truct task_struct *child, long request, long addr, long data) { - struct task_struct *child; int ret; - lock_kernel(); - ret = -EPERM; - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) - goto out_tsk; - switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ @@ -357,10 +324,6 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data) ret = -EIO; break; } -out_tsk: - put_task_struct(child); -out: - unlock_kernel(); return ret; } diff --git a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c index a220345e9746d063ba2997ab3dc0544651b676e2..abb80fa2b9408a1f9d898ef0fde2d07a2dee968b 100644 --- a/arch/m68knommu/kernel/setup.c +++ b/arch/m68knommu/kernel/setup.c @@ -107,6 +107,9 @@ void (*mach_power_off)( void ) = NULL; #if defined(CONFIG_M5206e) #define CPU "COLDFIRE(m5206e)" #endif +#if defined(CONFIG_M520x) + #define CPU "COLDFIRE(m520x)" +#endif #if defined(CONFIG_M523x) #define CPU "COLDFIRE(m523x)" #endif @@ -132,7 +135,7 @@ void (*mach_power_off)( void ) = NULL; #define CPU "COLDFIRE(m5407)" #endif #ifndef CPU - #define CPU "UNKOWN" + #define CPU "UNKNOWN" #endif /* (es) */ diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S index 47f06787190dfb14491db3cb2c06376471acd6e1..0eab92ca4b97a8bf4a419b10759a580cec5e7070 100644 --- a/arch/m68knommu/kernel/vmlinux.lds.S +++ b/arch/m68knommu/kernel/vmlinux.lds.S @@ -124,6 +124,14 @@ #define RAM_LENGTH 0x3e0000 #endif +/* + * The Freescale 5208EVB board has 32MB of RAM. + */ +#if defined(CONFIG_M5208EVB) +#define RAM_START 0x40020000 +#define RAM_LENGTH 0x01e00000 +#endif + /* * The senTec COBRA5272 board has nearly the same memory layout as * the M5272C3. We assume 16MiB ram. @@ -275,6 +283,7 @@ SECTIONS { *(__ksymtab_strings) /* Built-in module parameters */ + . = ALIGN(4) ; __start___param = .; *(__param) __stop___param = .; diff --git a/arch/m68knommu/platform/520x/Makefile b/arch/m68knommu/platform/520x/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e861b05106bc2e21296a1241606cf96977da4107 --- /dev/null +++ b/arch/m68knommu/platform/520x/Makefile @@ -0,0 +1,19 @@ +# +# Makefile for the M5208 specific file. +# + +# +# If you want to play with the HW breakpoints then you will +# need to add define this, which will give you a stack backtrace +# on the console port whenever a DBG interrupt occurs. You have to +# set up you HW breakpoints to trigger a DBG interrupt: +# +# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT +# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT +# + +ifdef CONFIG_FULLDEBUG +AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1 +endif + +obj-y := config.o diff --git a/arch/m68knommu/platform/520x/config.c b/arch/m68knommu/platform/520x/config.c new file mode 100644 index 0000000000000000000000000000000000000000..71dea2e0f45294e19cb0aed3c14d163e4ea37469 --- /dev/null +++ b/arch/m68knommu/platform/520x/config.c @@ -0,0 +1,65 @@ +/***************************************************************************/ + +/* + * linux/arch/m68knommu/platform/520x/config.c + * + * Copyright (C) 2005, Freescale (www.freescale.com) + * Copyright (C) 2005, Intec Automation (mike@steroidmicros.com) + * Copyright (C) 1999-2003, Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 2001-2003, SnapGear Inc. (www.snapgear.com) + */ + +/***************************************************************************/ + +#include +#include +#include +#include +#include + +/***************************************************************************/ + +/* + * DMA channel base address table. + */ +unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS]; +unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS]; + +/***************************************************************************/ + +void coldfire_pit_tick(void); +void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); +unsigned long coldfire_pit_offset(void); +void coldfire_trap_init(void); +void coldfire_reset(void); + +/***************************************************************************/ + +/* + * Program the vector to be an auto-vectored. + */ + +void mcf_autovector(unsigned int vec) +{ + /* Everything is auto-vectored on the 520x devices */ +} + +/***************************************************************************/ + +void config_BSP(char *commandp, int size) +{ +#ifdef CONFIG_BOOTPARAM + strncpy(commandp, CONFIG_BOOTPARAM_STRING, size); + commandp[size-1] = 0; +#else + memset(commandp, 0, size); +#endif + + mach_sched_init = coldfire_pit_init; + mach_tick = coldfire_pit_tick; + mach_gettimeoffset = coldfire_pit_offset; + mach_trap_init = coldfire_trap_init; + mach_reset = coldfire_reset; +} + +/***************************************************************************/ diff --git a/arch/m68knommu/platform/5307/Makefile b/arch/m68knommu/platform/5307/Makefile index 6fe5a2b8fb08476298ad4ac4171b309f72845f6f..8d1619dc1ea60a965ef16f4224d18b302e0f4cda 100644 --- a/arch/m68knommu/platform/5307/Makefile +++ b/arch/m68knommu/platform/5307/Makefile @@ -19,6 +19,7 @@ endif obj-$(CONFIG_COLDFIRE) += entry.o vectors.o ints.o obj-$(CONFIG_M5206) += timers.o obj-$(CONFIG_M5206e) += timers.o +obj-$(CONFIG_M520x) += pit.o obj-$(CONFIG_M523x) += pit.o obj-$(CONFIG_M5249) += timers.o obj-$(CONFIG_M527x) += pit.o diff --git a/arch/m68knommu/platform/5307/head.S b/arch/m68knommu/platform/5307/head.S index 7f4ba837901f6dfa74dd7e4cb2c64ee8f25f2316..c30c462b99b13830149e30d9dbc389448a8b3da6 100644 --- a/arch/m68knommu/platform/5307/head.S +++ b/arch/m68knommu/platform/5307/head.S @@ -113,6 +113,9 @@ #define MEM_BASE 0x02000000 #define VBR_BASE 0x20000000 /* vectors in SRAM */ #endif +#if defined(CONFIG_M5208EVB) +#define MEM_BASE 0x40000000 +#endif #ifndef MEM_BASE #define MEM_BASE 0x00000000 /* memory base at address 0 */ diff --git a/arch/m68knommu/platform/5307/ints.c b/arch/m68knommu/platform/5307/ints.c index 0117754d44f33143fd6978546388871d52a65919..a134fb2f056672bc144898ace95f787d3be2a754 100644 --- a/arch/m68knommu/platform/5307/ints.c +++ b/arch/m68knommu/platform/5307/ints.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include diff --git a/arch/m68knommu/platform/5307/pit.c b/arch/m68knommu/platform/5307/pit.c index a9b2c2e7e28085632e4bfd6215d636e3d76cc314..323f2677e49db2390aec84497059f454b76a6242 100644 --- a/arch/m68knommu/platform/5307/pit.c +++ b/arch/m68knommu/platform/5307/pit.c @@ -3,7 +3,7 @@ /* * pit.c -- Motorola ColdFire PIT timer. Currently this type of * hardware timer only exists in the Motorola ColdFire - * 5270/5271 and 5282 CPUs. + * 5270/5271, 5282 and other CPUs. * * Copyright (C) 1999-2004, Greg Ungerer (gerg@snapgear.com) * Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com) @@ -47,10 +47,10 @@ void coldfire_pit_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)) icrp = (volatile unsigned char *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0 + MCFINT_PIT1); - *icrp = 0x2b; /* PIT1 with level 5, priority 3 */ + *icrp = ICR_INTRCONF; - imrp = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH); - *imrp &= ~(1 << (MCFINT_PIT1 - 32)); + imrp = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFPIT_IMR); + *imrp &= ~MCFPIT_IMR_IBIT; /* Set up PIT timer 1 as poll clock */ tp = (volatile struct mcfpit *) (MCF_IPSBAR + MCFPIT_BASE1); @@ -70,7 +70,7 @@ unsigned long coldfire_pit_offset(void) unsigned long pmr, pcntr, offset; tp = (volatile struct mcfpit *) (MCF_IPSBAR + MCFPIT_BASE1); - ipr = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IPRH); + ipr = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFPIT_IMR); pmr = *(&tp->pmr); pcntr = *(&tp->pcntr); @@ -80,7 +80,7 @@ unsigned long coldfire_pit_offset(void) * timer interupt is pending, then add on a ticks worth of time. */ offset = ((pmr - pcntr) * (1000000 / HZ)) / pmr; - if ((offset < (1000000 / HZ / 2)) && (*ipr & (1 << (MCFINT_PIT1 - 32)))) + if ((offset < (1000000 / HZ / 2)) && (*ipr & MCFPIT_IMR_IBIT)) offset += 1000000 / HZ; return offset; } diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 0097a0d53b3b02a02cffe1e749732264dfeb5cca..e380a8322a94f922a65959b75f5f2f49b985c658 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -958,7 +958,7 @@ config SOC_PNX8550 bool select DMA_NONCOHERENT select HW_HAS_PCI - select SYS_HAS_CPU_R4X00 + select SYS_HAS_CPU_MIPS32_R1 select SYS_SUPPORTS_32BIT_KERNEL config SWAP_IO_SPACE diff --git a/arch/mips/boot/.gitignore b/arch/mips/boot/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ba63401c6e109cccbd8e675b248604475ca0b938 --- /dev/null +++ b/arch/mips/boot/.gitignore @@ -0,0 +1,4 @@ +mkboot +elf2ecoff +zImage +zImage.tmp diff --git a/arch/mips/configs/pnx8550-jbs_defconfig b/arch/mips/configs/pnx8550-jbs_defconfig index 95f84d7119120b4d2cb928ce4050bce46bbb78f0..555837e4c06f00866b678cb20bbb065bc2f80ca0 100644 --- a/arch/mips/configs/pnx8550-jbs_defconfig +++ b/arch/mips/configs/pnx8550-jbs_defconfig @@ -129,7 +129,7 @@ CONFIG_MIPS_L1_CACHE_SHIFT=5 # # CPU selection # -# CONFIG_CPU_MIPS32_R1 is not set +CONFIG_CPU_MIPS32_R1=y # CONFIG_CPU_MIPS32_R2 is not set # CONFIG_CPU_MIPS64_R1 is not set # CONFIG_CPU_MIPS64_R2 is not set @@ -137,7 +137,7 @@ CONFIG_MIPS_L1_CACHE_SHIFT=5 # CONFIG_CPU_TX39XX is not set # CONFIG_CPU_VR41XX is not set # CONFIG_CPU_R4300 is not set -CONFIG_CPU_R4X00=y +# CONFIG_CPU_R4X00 is not set # CONFIG_CPU_TX49XX is not set # CONFIG_CPU_R5000 is not set # CONFIG_CPU_R5432 is not set @@ -148,10 +148,11 @@ CONFIG_CPU_R4X00=y # CONFIG_CPU_RM7000 is not set # CONFIG_CPU_RM9000 is not set # CONFIG_CPU_SB1 is not set -CONFIG_SYS_HAS_CPU_R4X00=y +CONFIG_SYS_HAS_CPU_MIPS32_R1=y +CONFIG_CPU_MIPS32=y +CONFIG_CPU_MIPSR1=y CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y -CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y # # Kernel type @@ -162,11 +163,11 @@ CONFIG_PAGE_SIZE_4KB=y # CONFIG_PAGE_SIZE_8KB is not set # CONFIG_PAGE_SIZE_16KB is not set # CONFIG_PAGE_SIZE_64KB is not set +CONFIG_CPU_HAS_PREFETCH=y # CONFIG_MIPS_MT is not set # CONFIG_64BIT_PHYS_ADDR is not set # CONFIG_CPU_ADVANCED is not set CONFIG_CPU_HAS_LLSC=y -CONFIG_CPU_HAS_LLDSCD=y CONFIG_CPU_HAS_SYNC=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y diff --git a/arch/mips/configs/pnx8550-v2pci_defconfig b/arch/mips/configs/pnx8550-v2pci_defconfig index deb24c29ac0af2b8d30f8638800ca1f8776a278d..05e65206a7b459625f0fc2f73e8ee55f0af621e7 100644 --- a/arch/mips/configs/pnx8550-v2pci_defconfig +++ b/arch/mips/configs/pnx8550-v2pci_defconfig @@ -128,7 +128,7 @@ CONFIG_MIPS_L1_CACHE_SHIFT=5 # # CPU selection # -# CONFIG_CPU_MIPS32_R1 is not set +CONFIG_CPU_MIPS32_R1=y # CONFIG_CPU_MIPS32_R2 is not set # CONFIG_CPU_MIPS64_R1 is not set # CONFIG_CPU_MIPS64_R2 is not set @@ -136,7 +136,7 @@ CONFIG_MIPS_L1_CACHE_SHIFT=5 # CONFIG_CPU_TX39XX is not set # CONFIG_CPU_VR41XX is not set # CONFIG_CPU_R4300 is not set -CONFIG_CPU_R4X00=y +# CONFIG_CPU_R4X00 is not set # CONFIG_CPU_TX49XX is not set # CONFIG_CPU_R5000 is not set # CONFIG_CPU_R5432 is not set @@ -147,10 +147,11 @@ CONFIG_CPU_R4X00=y # CONFIG_CPU_RM7000 is not set # CONFIG_CPU_RM9000 is not set # CONFIG_CPU_SB1 is not set -CONFIG_SYS_HAS_CPU_R4X00=y +CONFIG_SYS_HAS_CPU_MIPS32_R1=y +CONFIG_CPU_MIPS32=y +CONFIG_CPU_MIPSR1=y CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y -CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y # # Kernel type @@ -161,6 +162,7 @@ CONFIG_PAGE_SIZE_4KB=y # CONFIG_PAGE_SIZE_8KB is not set # CONFIG_PAGE_SIZE_16KB is not set # CONFIG_PAGE_SIZE_64KB is not set +CONFIG_CPU_HAS_PREFETCH=y # CONFIG_MIPS_MT is not set # CONFIG_64BIT_PHYS_ADDR is not set CONFIG_CPU_ADVANCED=y diff --git a/arch/mips/ddb5xxx/common/rtc_ds1386.c b/arch/mips/ddb5xxx/common/rtc_ds1386.c index f5b11508ff2fc54bd9baa6209e22e2fea5101020..995896ac0e39012f9b707860a429c79244908fce 100644 --- a/arch/mips/ddb5xxx/common/rtc_ds1386.c +++ b/arch/mips/ddb5xxx/common/rtc_ds1386.c @@ -41,7 +41,9 @@ rtc_ds1386_get_time(void) u8 byte; u8 temp; unsigned int year, month, day, hour, minute, second; + unsigned long flags; + spin_lock_irqsave(&rtc_lock, flags); /* let us freeze external registers */ byte = READ_RTC(0xB); byte &= 0x3f; @@ -60,6 +62,7 @@ rtc_ds1386_get_time(void) /* enable time transfer */ byte |= 0x80; WRITE_RTC(0xB, byte); + spin_unlock_irqrestore(&rtc_lock, flags); /* calc hour */ if (temp & 0x40) { @@ -81,7 +84,9 @@ rtc_ds1386_set_time(unsigned long t) u8 byte; u8 temp; u8 year, month, day, hour, minute, second; + unsigned long flags; + spin_lock_irqsave(&rtc_lock, flags); /* let us freeze external registers */ byte = READ_RTC(0xB); byte &= 0x3f; @@ -133,6 +138,7 @@ rtc_ds1386_set_time(unsigned long t) if (second != READ_RTC(0x1)) { WRITE_RTC(0x1, second); } + spin_unlock_irqrestore(&rtc_lock, flags); return 0; } diff --git a/arch/mips/dec/time.c b/arch/mips/dec/time.c index dc7091caa7aa0a1c6b4158bae87298b06c6701b8..174822344131cf86946add567a6d08b4f8469533 100644 --- a/arch/mips/dec/time.c +++ b/arch/mips/dec/time.c @@ -37,10 +37,25 @@ #include +/* + * Returns true if a clock update is in progress + */ +static inline unsigned char dec_rtc_is_updating(void) +{ + unsigned char uip; + unsigned long flags; + + spin_lock_irqsave(&rtc_lock, flags); + uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); + spin_unlock_irqrestore(&rtc_lock, flags); + return uip; +} + static unsigned long dec_rtc_get_time(void) { unsigned int year, mon, day, hour, min, sec, real_year; int i; + unsigned long flags; /* The Linux interpretation of the DS1287 clock register contents: * When the Update-In-Progress (UIP) flag goes from 1 to 0, the @@ -49,11 +64,12 @@ static unsigned long dec_rtc_get_time(void) */ /* read RTC exactly on falling edge of update flag */ for (i = 0; i < 1000000; i++) /* may take up to 1 second... */ - if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) + if (dec_rtc_is_updating()) break; for (i = 0; i < 1000000; i++) /* must try at least 2.228 ms */ - if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) + if (!dec_rtc_is_updating()) break; + spin_lock_irqsave(&rtc_lock, flags); /* Isn't this overkill? UIP above should guarantee consistency */ do { sec = CMOS_READ(RTC_SECONDS); @@ -77,6 +93,7 @@ static unsigned long dec_rtc_get_time(void) * of unused BBU RAM locations. */ real_year = CMOS_READ(RTC_DEC_YEAR); + spin_unlock_irqrestore(&rtc_lock, flags); year += real_year - 72 + 2000; return mktime(year, mon, day, hour, min, sec); @@ -95,6 +112,8 @@ static int dec_rtc_set_mmss(unsigned long nowtime) int real_seconds, real_minutes, cmos_minutes; unsigned char save_control, save_freq_select; + /* irq are locally disabled here */ + spin_lock(&rtc_lock); /* tell the clock it's being set */ save_control = CMOS_READ(RTC_CONTROL); CMOS_WRITE((save_control | RTC_SET), RTC_CONTROL); @@ -141,6 +160,7 @@ static int dec_rtc_set_mmss(unsigned long nowtime) */ CMOS_WRITE(save_control, RTC_CONTROL); CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + spin_unlock(&rtc_lock); return retval; } diff --git a/arch/mips/jmr3927/common/rtc_ds1742.c b/arch/mips/jmr3927/common/rtc_ds1742.c index 1ae4318e1358fa6d8d02f0c26c2676743d827c47..8b407d7dc460c2a7d905c5bc43e76532734636ef 100644 --- a/arch/mips/jmr3927/common/rtc_ds1742.c +++ b/arch/mips/jmr3927/common/rtc_ds1742.c @@ -57,7 +57,9 @@ rtc_ds1742_get_time(void) { unsigned int year, month, day, hour, minute, second; unsigned int century; + unsigned long flags; + spin_lock_irqsave(&rtc_lock, flags); CMOS_WRITE(RTC_READ, RTC_CONTROL); second = BCD2BIN(CMOS_READ(RTC_SECONDS) & RTC_SECONDS_MASK); minute = BCD2BIN(CMOS_READ(RTC_MINUTES)); @@ -67,6 +69,7 @@ rtc_ds1742_get_time(void) year = BCD2BIN(CMOS_READ(RTC_YEAR)); century = BCD2BIN(CMOS_READ(RTC_CENTURY) & RTC_CENTURY_MASK); CMOS_WRITE(0, RTC_CONTROL); + spin_unlock_irqrestore(&rtc_lock, flags); year += century * 100; @@ -81,7 +84,9 @@ rtc_ds1742_set_time(unsigned long t) u8 year, month, day, hour, minute, second; u8 cmos_year, cmos_month, cmos_day, cmos_hour, cmos_minute, cmos_second; int cmos_century; + unsigned long flags; + spin_lock_irqsave(&rtc_lock, flags); CMOS_WRITE(RTC_READ, RTC_CONTROL); cmos_second = (u8)(CMOS_READ(RTC_SECONDS) & RTC_SECONDS_MASK); cmos_minute = (u8)CMOS_READ(RTC_MINUTES); @@ -139,6 +144,7 @@ rtc_ds1742_set_time(unsigned long t) /* RTC_CENTURY and RTC_CONTROL share same address... */ CMOS_WRITE(cmos_century, RTC_CONTROL); + spin_unlock_irqrestore(&rtc_lock, flags); return 0; } diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c index 908e6368420871b04578f8321ab70fd7c509b2ec..dd118c60bcd0676f69c6a841de91cf4f7ee96a23 100644 --- a/arch/mips/kernel/irixsig.c +++ b/arch/mips/kernel/irixsig.c @@ -502,8 +502,7 @@ asmlinkage int irix_sigpoll_sys(unsigned long __user *set, while(1) { long tmp = 0; - current->state = TASK_INTERRUPTIBLE; - expire = schedule_timeout(expire); + expire = schedule_timeout_interruptible(expire); for (i=0; i<=4; i++) tmp |= (current->pending.signal.sig[i] & kset.sig[i]); diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index f1b0f3e1f95b4c1ebd0dcfd23cafaffb9824dc97..510da5fda567e55317e333f179a60eeb35bd039b 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -174,51 +174,10 @@ int ptrace_setfpregs (struct task_struct *child, __u32 __user *data) return 0; } -asmlinkage long sys_ptrace(long request, long pid, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, long addr, long data) { - struct task_struct *child; int ret; -#if 0 - printk("ptrace(r=%d,pid=%d,addr=%08lx,data=%08lx)\n", - (int) request, (int) pid, (unsigned long) addr, - (unsigned long) data); -#endif - lock_kernel(); - ret = -EPERM; - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - if ((ret = security_ptrace(current->parent, current))) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) - goto out_tsk; - switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ @@ -319,7 +278,7 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data) if (!cpu_has_dsp) { tmp = 0; ret = -EIO; - goto out_tsk; + goto out; } if (child->thread.dsp.used_dsp) { dregs = __get_dsp_regs(child); @@ -333,14 +292,14 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data) if (!cpu_has_dsp) { tmp = 0; ret = -EIO; - goto out_tsk; + goto out; } tmp = child->thread.dsp.dspcontrol; break; default: tmp = 0; ret = -EIO; - goto out_tsk; + goto out; } ret = put_user(tmp, (unsigned long __user *) data); break; @@ -495,11 +454,7 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data) ret = ptrace_request(child, request, addr, data); break; } - -out_tsk: - put_task_struct(child); -out: - unlock_kernel(); + out: return ret; } diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c index 8c81f3cb4e2dc7b06ba7a3301b1f957567766dc1..1d855112bac254bac6328f243f22591e537a57ab 100644 --- a/arch/mips/kernel/rtlx.c +++ b/arch/mips/kernel/rtlx.c @@ -20,42 +20,42 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include #include -#include -#include +#include #include #include -#include #include +#include -#define RTLX_MAJOR 64 #define RTLX_TARG_VPE 1 -struct rtlx_info *rtlx; +static struct rtlx_info *rtlx; static int major; static char module_name[] = "rtlx"; -static inline int spacefree(int read, int write, int size); +static struct irqaction irq; +static int irq_num; + +static inline int spacefree(int read, int write, int size) +{ + if (read == write) { + /* + * never fill the buffer completely, so indexes are always + * equal if empty and only empty, or !equal if data available + */ + return size - 1; + } + + return ((read + size - write) % size) - 1; +} static struct chan_waitqueues { wait_queue_head_t rt_queue; wait_queue_head_t lx_queue; } channel_wqs[RTLX_CHANNELS]; -static struct irqaction irq; -static int irq_num; - extern void *vpe_get_shared(int index); static void rtlx_dispatch(struct pt_regs *regs) @@ -63,9 +63,8 @@ static void rtlx_dispatch(struct pt_regs *regs) do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ, regs); } -irqreturn_t rtlx_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t rtlx_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - irqreturn_t r = IRQ_HANDLED; int i; for (i = 0; i < RTLX_CHANNELS; i++) { @@ -75,30 +74,7 @@ irqreturn_t rtlx_interrupt(int irq, void *dev_id, struct pt_regs *regs) wake_up_interruptible(&channel_wqs[i].lx_queue); } - return r; -} - -void dump_rtlx(void) -{ - int i; - - printk("id 0x%lx state %d\n", rtlx->id, rtlx->state); - - for (i = 0; i < RTLX_CHANNELS; i++) { - struct rtlx_channel *chan = &rtlx->channel[i]; - - printk(" rt_state %d lx_state %d buffer_size %d\n", - chan->rt_state, chan->lx_state, chan->buffer_size); - - printk(" rt_read %d rt_write %d\n", - chan->rt_read, chan->rt_write); - - printk(" lx_read %d lx_write %d\n", - chan->lx_read, chan->lx_write); - - printk(" rt_buffer <%s>\n", chan->rt_buffer); - printk(" lx_buffer <%s>\n", chan->lx_buffer); - } + return IRQ_HANDLED; } /* call when we have the address of the shared structure from the SP side. */ @@ -108,7 +84,7 @@ static int rtlx_init(struct rtlx_info *rtlxi) if (rtlxi->id != RTLX_ID) { printk(KERN_WARNING "no valid RTLX id at 0x%p\n", rtlxi); - return (-ENOEXEC); + return -ENOEXEC; } /* initialise the wait queues */ @@ -120,9 +96,8 @@ static int rtlx_init(struct rtlx_info *rtlxi) /* set up for interrupt handling */ memset(&irq, 0, sizeof(struct irqaction)); - if (cpu_has_vint) { + if (cpu_has_vint) set_vi_handler(MIPS_CPU_RTLX_IRQ, rtlx_dispatch); - } irq_num = MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ; irq.handler = rtlx_interrupt; @@ -132,7 +107,8 @@ static int rtlx_init(struct rtlx_info *rtlxi) setup_irq(irq_num, &irq); rtlx = rtlxi; - return (0); + + return 0; } /* only allow one open process at a time to open each channel */ @@ -147,36 +123,36 @@ static int rtlx_open(struct inode *inode, struct file *filp) if (rtlx == NULL) { struct rtlx_info **p; if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) { - printk(" vpe_get_shared is NULL. Has an SP program been loaded?\n"); - return (-EFAULT); + printk(KERN_ERR "vpe_get_shared is NULL. " + "Has an SP program been loaded?\n"); + return -EFAULT; } if (*p == NULL) { - printk(" vpe_shared %p %p\n", p, *p); - return (-EFAULT); + printk(KERN_ERR "vpe_shared %p %p\n", p, *p); + return -EFAULT; } if ((ret = rtlx_init(*p)) < 0) - return (ret); + return ret; } chan = &rtlx->channel[minor]; - /* already open? */ - if (chan->lx_state == RTLX_STATE_OPENED) - return (-EBUSY); + if (test_and_set_bit(RTLX_STATE_OPENED, &chan->lx_state)) + return -EBUSY; - chan->lx_state = RTLX_STATE_OPENED; - return (0); + return 0; } static int rtlx_release(struct inode *inode, struct file *filp) { - int minor; + int minor = MINOR(inode->i_rdev); - minor = MINOR(inode->i_rdev); - rtlx->channel[minor].lx_state = RTLX_STATE_UNUSED; - return (0); + clear_bit(RTLX_STATE_OPENED, &rtlx->channel[minor].lx_state); + smp_mb__after_clear_bit(); + + return 0; } static unsigned int rtlx_poll(struct file *file, poll_table * wait) @@ -199,12 +175,13 @@ static unsigned int rtlx_poll(struct file *file, poll_table * wait) if (spacefree(chan->rt_read, chan->rt_write, chan->buffer_size)) mask |= POLLOUT | POLLWRNORM; - return (mask); + return mask; } static ssize_t rtlx_read(struct file *file, char __user * buffer, size_t count, loff_t * ppos) { + unsigned long failed; size_t fl = 0L; int minor; struct rtlx_channel *lx; @@ -216,7 +193,7 @@ static ssize_t rtlx_read(struct file *file, char __user * buffer, size_t count, /* data available? */ if (lx->lx_write == lx->lx_read) { if (file->f_flags & O_NONBLOCK) - return (0); // -EAGAIN makes cat whinge + return 0; /* -EAGAIN makes cat whinge */ /* go to sleep */ add_wait_queue(&channel_wqs[minor].lx_queue, &wait); @@ -232,39 +209,39 @@ static ssize_t rtlx_read(struct file *file, char __user * buffer, size_t count, } /* find out how much in total */ - count = min( count, - (size_t)(lx->lx_write + lx->buffer_size - lx->lx_read) % lx->buffer_size); + count = min(count, + (size_t)(lx->lx_write + lx->buffer_size - lx->lx_read) % lx->buffer_size); /* then how much from the read pointer onwards */ - fl = min( count, (size_t)lx->buffer_size - lx->lx_read); + fl = min(count, (size_t)lx->buffer_size - lx->lx_read); - copy_to_user (buffer, &lx->lx_buffer[lx->lx_read], fl); + failed = copy_to_user (buffer, &lx->lx_buffer[lx->lx_read], fl); + if (failed) { + count = fl - failed; + goto out; + } /* and if there is anything left at the beginning of the buffer */ - if ( count - fl ) - copy_to_user (buffer + fl, lx->lx_buffer, count - fl); + if (count - fl) { + failed = copy_to_user (buffer + fl, lx->lx_buffer, count - fl); + if (failed) { + count -= failed; + goto out; + } + } +out: /* update the index */ lx->lx_read += count; lx->lx_read %= lx->buffer_size; - return (count); -} - -static inline int spacefree(int read, int write, int size) -{ - if (read == write) { - /* never fill the buffer completely, so indexes are always equal if empty - and only empty, or !equal if data available */ - return (size - 1); - } - - return ((read + size - write) % size) - 1; + return count; } static ssize_t rtlx_write(struct file *file, const char __user * buffer, size_t count, loff_t * ppos) { + unsigned long failed; int minor; struct rtlx_channel *rt; size_t fl; @@ -277,7 +254,7 @@ static ssize_t rtlx_write(struct file *file, const char __user * buffer, if (!spacefree(rt->rt_read, rt->rt_write, rt->buffer_size)) { if (file->f_flags & O_NONBLOCK) - return (-EAGAIN); + return -EAGAIN; add_wait_queue(&channel_wqs[minor].rt_queue, &wait); set_current_state(TASK_INTERRUPTIBLE); @@ -290,52 +267,64 @@ static ssize_t rtlx_write(struct file *file, const char __user * buffer, } /* total number of bytes to copy */ - count = min( count, (size_t)spacefree(rt->rt_read, rt->rt_write, rt->buffer_size) ); + count = min(count, (size_t)spacefree(rt->rt_read, rt->rt_write, rt->buffer_size) ); /* first bit from write pointer to the end of the buffer, or count */ fl = min(count, (size_t) rt->buffer_size - rt->rt_write); - copy_from_user(&rt->rt_buffer[rt->rt_write], buffer, fl); + failed = copy_from_user(&rt->rt_buffer[rt->rt_write], buffer, fl); + if (failed) { + count = fl - failed; + goto out; + } /* if there's any left copy to the beginning of the buffer */ - if( count - fl ) - copy_from_user(rt->rt_buffer, buffer + fl, count - fl); + if (count - fl) { + failed = copy_from_user(rt->rt_buffer, buffer + fl, count - fl); + if (failed) { + count -= failed; + goto out; + } + } +out: rt->rt_write += count; rt->rt_write %= rt->buffer_size; - return(count); + return count; } static struct file_operations rtlx_fops = { - .owner = THIS_MODULE, - .open = rtlx_open, - .release = rtlx_release, - .write = rtlx_write, - .read = rtlx_read, - .poll = rtlx_poll + .owner = THIS_MODULE, + .open = rtlx_open, + .release = rtlx_release, + .write = rtlx_write, + .read = rtlx_read, + .poll = rtlx_poll }; -static int rtlx_module_init(void) +static char register_chrdev_failed[] __initdata = + KERN_ERR "rtlx_module_init: unable to register device\n"; + +static int __init rtlx_module_init(void) { - if ((major = register_chrdev(RTLX_MAJOR, module_name, &rtlx_fops)) < 0) { - printk("rtlx_module_init: unable to register device\n"); - return (-EBUSY); + major = register_chrdev(0, module_name, &rtlx_fops); + if (major < 0) { + printk(register_chrdev_failed); + return major; } - if (major == 0) - major = RTLX_MAJOR; - - return (0); + return 0; } -static void rtlx_module_exit(void) +static void __exit rtlx_module_exit(void) { unregister_chrdev(major, module_name); } module_init(rtlx_module_init); module_exit(rtlx_module_exit); + MODULE_DESCRIPTION("MIPS RTLX"); -MODULE_AUTHOR("Elizabeth Clarke, MIPS Technologies, Inc"); +MODULE_AUTHOR("Elizabeth Clarke, MIPS Technologies, Inc."); MODULE_LICENSE("GPL"); diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 9202a17db8f73f6c0fbb8633042d7e92c92a5bac..05e09eedabffb015bd24bf83a589d25647fa5158 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -384,9 +384,6 @@ int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, return 0; } -extern void setup_rt_frame_n32(struct k_sigaction * ka, - struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info); - static inline int handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs) { diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index dbe821303125864ec8fb9eaf2f2e803ae57f9f4d..e315d3f6aa6e57ccf33e018eb32ea647a3d949b1 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -647,8 +647,8 @@ static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, return (void *)((sp - frame_size) & ALMASK); } -void setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs, - int signr, sigset_t *set) +int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs, + int signr, sigset_t *set) { struct sigframe *frame; int err = 0; @@ -694,13 +694,15 @@ void setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs, current->comm, current->pid, frame, regs->cp0_epc, frame->sf_code); #endif - return; + return 1; give_sigsegv: force_sigsegv(signr, current); + return 0; } -void setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info) +int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs, + int signr, sigset_t *set, siginfo_t *info) { struct rt_sigframe32 *frame; int err = 0; @@ -763,10 +765,11 @@ void setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs, int signr, current->comm, current->pid, frame, regs->cp0_epc, frame->rs_code); #endif - return; + return 1; give_sigsegv: force_sigsegv(signr, current); + return 0; } static inline int handle_signal(unsigned long sig, siginfo_t *info, diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index 97fefcc9dbe7d332900a8b526d63d81080b33eca..06be405be3999f44fe8e30135f73ffe6a0427d86 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -58,10 +58,6 @@ typedef void *vpe_handle; -// defined here because the kernel module loader doesn't have -// anything to do with it. -#define SHN_MIPS_SCOMMON 0xff03 - #ifndef ARCH_SHF_SMALL #define ARCH_SHF_SMALL 0 #endif @@ -69,11 +65,8 @@ typedef void *vpe_handle; /* If this is set, the section belongs in the init part of the module */ #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1)) -// temp number, -#define VPE_MAJOR 63 - static char module_name[] = "vpe"; -static int major = 0; +static int major; /* grab the likely amount of memory we will need. */ #ifdef CONFIG_MIPS_VPE_LOADER_TOM @@ -98,22 +91,7 @@ enum tc_state { TC_STATE_DYNAMIC }; -struct vpe; -typedef struct tc { - enum tc_state state; - int index; - - /* parent VPE */ - struct vpe *pvpe; - - /* The list of TC's with this VPE */ - struct list_head tc; - - /* The global list of tc's */ - struct list_head list; -} tc_t; - -typedef struct vpe { +struct vpe { enum vpe_state state; /* (device) minor associated with this vpe */ @@ -135,7 +113,21 @@ typedef struct vpe { /* shared symbol address */ void *shared_ptr; -} vpe_t; +}; + +struct tc { + enum tc_state state; + int index; + + /* parent VPE */ + struct vpe *pvpe; + + /* The list of TC's with this VPE */ + struct list_head tc; + + /* The global list of tc's */ + struct list_head list; +}; struct vpecontrol_ { /* Virtual processing elements */ @@ -146,7 +138,7 @@ struct vpecontrol_ { } vpecontrol; static void release_progmem(void *ptr); -static void dump_vpe(vpe_t * v); +static void dump_vpe(struct vpe * v); extern void save_gp_address(unsigned int secbase, unsigned int rel); /* get the vpe associated with this minor */ @@ -197,13 +189,11 @@ struct vpe *alloc_vpe(int minor) { struct vpe *v; - if ((v = kmalloc(sizeof(struct vpe), GFP_KERNEL)) == NULL) { + if ((v = kzalloc(sizeof(struct vpe), GFP_KERNEL)) == NULL) { printk(KERN_WARNING "VPE: alloc_vpe no mem\n"); return NULL; } - memset(v, 0, sizeof(struct vpe)); - INIT_LIST_HEAD(&v->tc); list_add_tail(&v->list, &vpecontrol.vpe_list); @@ -216,13 +206,11 @@ struct tc *alloc_tc(int index) { struct tc *t; - if ((t = kmalloc(sizeof(struct tc), GFP_KERNEL)) == NULL) { + if ((t = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL) { printk(KERN_WARNING "VPE: alloc_tc no mem\n"); return NULL; } - memset(t, 0, sizeof(struct tc)); - INIT_LIST_HEAD(&t->tc); list_add_tail(&t->list, &vpecontrol.tc_list); @@ -412,16 +400,17 @@ static int apply_r_mips_26(struct module *me, uint32_t *location, return -ENOEXEC; } -/* Not desperately convinced this is a good check of an overflow condition - anyway. But it gets in the way of handling undefined weak symbols which - we want to set to zero. - if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { - printk(KERN_ERR - "module %s: relocation overflow\n", - me->name); - return -ENOEXEC; - } -*/ +/* + * Not desperately convinced this is a good check of an overflow condition + * anyway. But it gets in the way of handling undefined weak symbols which + * we want to set to zero. + * if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { + * printk(KERN_ERR + * "module %s: relocation overflow\n", + * me->name); + * return -ENOEXEC; + * } + */ *location = (*location & ~0x03ffffff) | ((*location + (v >> 2)) & 0x03ffffff); @@ -681,7 +670,7 @@ static void dump_tclist(void) } /* We are prepared so configure and start the VPE... */ -int vpe_run(vpe_t * v) +int vpe_run(struct vpe * v) { unsigned long val; struct tc *t; @@ -772,7 +761,7 @@ int vpe_run(vpe_t * v) return 0; } -static unsigned long find_vpe_symbols(vpe_t * v, Elf_Shdr * sechdrs, +static unsigned long find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs, unsigned int symindex, const char *strtab, struct module *mod) { @@ -792,10 +781,12 @@ static unsigned long find_vpe_symbols(vpe_t * v, Elf_Shdr * sechdrs, return 0; } -/* Allocates a VPE with some program code space(the load address), copies the contents - of the program (p)buffer performing relocatations/etc, free's it when finished. +/* + * Allocates a VPE with some program code space(the load address), copies + * the contents of the program (p)buffer performing relocatations/etc, + * free's it when finished. */ -int vpe_elfload(vpe_t * v) +int vpe_elfload(struct vpe * v) { Elf_Ehdr *hdr; Elf_Shdr *sechdrs; @@ -931,7 +922,7 @@ int vpe_elfload(vpe_t * v) return err; } -static void dump_vpe(vpe_t * v) +static void dump_vpe(struct vpe * v) { struct tc *t; @@ -947,7 +938,7 @@ static void dump_vpe(vpe_t * v) static int vpe_open(struct inode *inode, struct file *filp) { int minor; - vpe_t *v; + struct vpe *v; /* assume only 1 device at the mo. */ if ((minor = MINOR(inode->i_rdev)) != 1) { @@ -1001,7 +992,7 @@ static int vpe_open(struct inode *inode, struct file *filp) static int vpe_release(struct inode *inode, struct file *filp) { int minor, ret = 0; - vpe_t *v; + struct vpe *v; Elf_Ehdr *hdr; minor = MINOR(inode->i_rdev); @@ -1035,7 +1026,7 @@ static ssize_t vpe_write(struct file *file, const char __user * buffer, { int minor; size_t ret = count; - vpe_t *v; + struct vpe *v; minor = MINOR(file->f_dentry->d_inode->i_rdev); if ((v = get_vpe(minor)) == NULL) @@ -1180,14 +1171,11 @@ static int __init vpe_module_init(void) return -ENODEV; } - if ((major = register_chrdev(VPE_MAJOR, module_name, &vpe_fops) < 0)) { + if ((major = register_chrdev(0, module_name, &vpe_fops) < 0)) { printk("VPE loader: unable to register character device\n"); - return -EBUSY; + return major; } - if (major == 0) - major = VPE_MAJOR; - dmt(); dvpe(); diff --git a/arch/mips/lasat/ds1603.c b/arch/mips/lasat/ds1603.c index 9d7812e03dcd9322f5410963e8a63398878d57d2..7dced67c55ebe3959ba9d5efe8b4eaac9750eb05 100644 --- a/arch/mips/lasat/ds1603.c +++ b/arch/mips/lasat/ds1603.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "ds1603.h" @@ -138,19 +139,27 @@ static void rtc_end_op(void) unsigned long ds1603_read(void) { unsigned long word; + unsigned long flags; + + spin_lock_irqsave(&rtc_lock, flags); rtc_init_op(); rtc_write_byte(READ_TIME_CMD); word = rtc_read_word(); rtc_end_op(); + spin_unlock_irqrestore(&rtc_lock, flags); return word; } int ds1603_set(unsigned long time) { + unsigned long flags; + + spin_lock_irqsave(&rtc_lock, flags); rtc_init_op(); rtc_write_byte(SET_TIME_CMD); rtc_write_word(time); rtc_end_op(); + spin_unlock_irqrestore(&rtc_lock, flags); return 0; } diff --git a/arch/mips/momentum/jaguar_atx/setup.c b/arch/mips/momentum/jaguar_atx/setup.c index 768bf4406452ecc0a7855942affee8316c498eda..bab192ddc1850b81957094058d240369523736fc 100644 --- a/arch/mips/momentum/jaguar_atx/setup.c +++ b/arch/mips/momentum/jaguar_atx/setup.c @@ -149,7 +149,9 @@ arch_initcall(per_cpu_mappings); unsigned long m48t37y_get_time(void) { unsigned int year, month, day, hour, min, sec; + unsigned long flags; + spin_lock_irqsave(&rtc_lock, flags); /* stop the update */ rtc_base[0x7ff8] = 0x40; @@ -166,6 +168,7 @@ unsigned long m48t37y_get_time(void) /* start the update */ rtc_base[0x7ff8] = 0x00; + spin_unlock_irqrestore(&rtc_lock, flags); return mktime(year, month, day, hour, min, sec); } @@ -173,11 +176,13 @@ unsigned long m48t37y_get_time(void) int m48t37y_set_time(unsigned long sec) { struct rtc_time tm; + unsigned long flags; /* convert to a more useful format -- note months count from 0 */ to_tm(sec, &tm); tm.tm_mon += 1; + spin_lock_irqsave(&rtc_lock, flags); /* enable writing */ rtc_base[0x7ff8] = 0x80; @@ -201,6 +206,7 @@ int m48t37y_set_time(unsigned long sec) /* disable writing */ rtc_base[0x7ff8] = 0x00; + spin_unlock_irqrestore(&rtc_lock, flags); return 0; } diff --git a/arch/mips/momentum/ocelot_3/setup.c b/arch/mips/momentum/ocelot_3/setup.c index a7803e08f9db6cad3fcdb2e62bd60e8d7d51e8ce..c9b7ff8148ec3cd3bd12c312ddebff2e2682cf97 100644 --- a/arch/mips/momentum/ocelot_3/setup.c +++ b/arch/mips/momentum/ocelot_3/setup.c @@ -135,7 +135,9 @@ void setup_wired_tlb_entries(void) unsigned long m48t37y_get_time(void) { unsigned int year, month, day, hour, min, sec; + unsigned long flags; + spin_lock_irqsave(&rtc_lock, flags); /* stop the update */ rtc_base[0x7ff8] = 0x40; @@ -152,6 +154,7 @@ unsigned long m48t37y_get_time(void) /* start the update */ rtc_base[0x7ff8] = 0x00; + spin_unlock_irqrestore(&rtc_lock, flags); return mktime(year, month, day, hour, min, sec); } @@ -159,11 +162,13 @@ unsigned long m48t37y_get_time(void) int m48t37y_set_time(unsigned long sec) { struct rtc_time tm; + unsigned long flags; /* convert to a more useful format -- note months count from 0 */ to_tm(sec, &tm); tm.tm_mon += 1; + spin_lock_irqsave(&rtc_lock, flags); /* enable writing */ rtc_base[0x7ff8] = 0x80; @@ -187,6 +192,7 @@ int m48t37y_set_time(unsigned long sec) /* disable writing */ rtc_base[0x7ff8] = 0x00; + spin_unlock_irqrestore(&rtc_lock, flags); return 0; } diff --git a/arch/mips/momentum/ocelot_c/setup.c b/arch/mips/momentum/ocelot_c/setup.c index ce70fc96f16095d11c49d859d697103c3c0a6fb5..2755c1547473b5a0ca42956ca75066231f5da96e 100644 --- a/arch/mips/momentum/ocelot_c/setup.c +++ b/arch/mips/momentum/ocelot_c/setup.c @@ -140,7 +140,9 @@ unsigned long m48t37y_get_time(void) unsigned char* rtc_base = (unsigned char*)0xfc800000; #endif unsigned int year, month, day, hour, min, sec; + unsigned long flags; + spin_lock_irqsave(&rtc_lock, flags); /* stop the update */ rtc_base[0x7ff8] = 0x40; @@ -157,6 +159,7 @@ unsigned long m48t37y_get_time(void) /* start the update */ rtc_base[0x7ff8] = 0x00; + spin_unlock_irqrestore(&rtc_lock, flags); return mktime(year, month, day, hour, min, sec); } @@ -169,11 +172,13 @@ int m48t37y_set_time(unsigned long sec) unsigned char* rtc_base = (unsigned char*)0xfc800000; #endif struct rtc_time tm; + unsigned long flags; /* convert to a more useful format -- note months count from 0 */ to_tm(sec, &tm); tm.tm_mon += 1; + spin_lock_irqsave(&rtc_lock, flags); /* enable writing */ rtc_base[0x7ff8] = 0x80; @@ -197,6 +202,7 @@ int m48t37y_set_time(unsigned long sec) /* disable writing */ rtc_base[0x7ff8] = 0x00; + spin_unlock_irqrestore(&rtc_lock, flags); return 0; } diff --git a/arch/mips/pmc-sierra/yosemite/setup.c b/arch/mips/pmc-sierra/yosemite/setup.c index bdc2ab55bed654c46d96905f56f8330623415fe7..059755b5ed576b7c4c1560a9479dad1e50dc1eda 100644 --- a/arch/mips/pmc-sierra/yosemite/setup.c +++ b/arch/mips/pmc-sierra/yosemite/setup.c @@ -73,7 +73,9 @@ void __init bus_error_init(void) unsigned long m48t37y_get_time(void) { unsigned int year, month, day, hour, min, sec; + unsigned long flags; + spin_lock_irqsave(&rtc_lock, flags); /* Stop the update to the time */ m48t37_base->control = 0x40; @@ -88,6 +90,7 @@ unsigned long m48t37y_get_time(void) /* Start the update to the time again */ m48t37_base->control = 0x00; + spin_unlock_irqrestore(&rtc_lock, flags); return mktime(year, month, day, hour, min, sec); } @@ -95,11 +98,13 @@ unsigned long m48t37y_get_time(void) int m48t37y_set_time(unsigned long sec) { struct rtc_time tm; + unsigned long flags; /* convert to a more useful format -- note months count from 0 */ to_tm(sec, &tm); tm.tm_mon += 1; + spin_lock_irqsave(&rtc_lock, flags); /* enable writing */ m48t37_base->control = 0x80; @@ -123,6 +128,7 @@ int m48t37y_set_time(unsigned long sec) /* disable writing */ m48t37_base->control = 0x00; + spin_unlock_irqrestore(&rtc_lock, flags); return 0; } diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c index df9b5694328a1801f0e04a9b403b0227622cb194..b7300cc5c5ad0769e9062495f25cc4b4c97dd560 100644 --- a/arch/mips/sgi-ip22/ip22-time.c +++ b/arch/mips/sgi-ip22/ip22-time.c @@ -35,7 +35,9 @@ static unsigned long indy_rtc_get_time(void) { unsigned int yrs, mon, day, hrs, min, sec; unsigned int save_control; + unsigned long flags; + spin_lock_irqsave(&rtc_lock, flags); save_control = hpc3c0->rtcregs[RTC_CMD] & 0xff; hpc3c0->rtcregs[RTC_CMD] = save_control | RTC_TE; @@ -47,6 +49,7 @@ static unsigned long indy_rtc_get_time(void) yrs = BCD2BIN(hpc3c0->rtcregs[RTC_YEAR] & 0xff); hpc3c0->rtcregs[RTC_CMD] = save_control; + spin_unlock_irqrestore(&rtc_lock, flags); if (yrs < 45) yrs += 30; @@ -60,6 +63,7 @@ static int indy_rtc_set_time(unsigned long tim) { struct rtc_time tm; unsigned int save_control; + unsigned long flags; to_tm(tim, &tm); @@ -68,6 +72,7 @@ static int indy_rtc_set_time(unsigned long tim) if (tm.tm_year >= 100) tm.tm_year -= 100; + spin_lock_irqsave(&rtc_lock, flags); save_control = hpc3c0->rtcregs[RTC_CMD] & 0xff; hpc3c0->rtcregs[RTC_CMD] = save_control | RTC_TE; @@ -80,6 +85,7 @@ static int indy_rtc_set_time(unsigned long tim) hpc3c0->rtcregs[RTC_HUNDREDTH_SECOND] = 0; hpc3c0->rtcregs[RTC_CMD] = save_control; + spin_unlock_irqrestore(&rtc_lock, flags); return 0; } diff --git a/arch/mips/sibyte/swarm/rtc_m41t81.c b/arch/mips/sibyte/swarm/rtc_m41t81.c index 5b4fc26c1b36a3270ade37ebf8f4ec1ef6171e9a..c13914bdda59d56d8c2cc7d8b3b25476416fc9b0 100644 --- a/arch/mips/sibyte/swarm/rtc_m41t81.c +++ b/arch/mips/sibyte/swarm/rtc_m41t81.c @@ -144,6 +144,7 @@ static int m41t81_write(uint8_t addr, int b) int m41t81_set_time(unsigned long t) { struct rtc_time tm; + unsigned long flags; to_tm(t, &tm); @@ -153,6 +154,7 @@ int m41t81_set_time(unsigned long t) * believe we should finish writing min within a second. */ + spin_lock_irqsave(&rtc_lock, flags); tm.tm_sec = BIN2BCD(tm.tm_sec); m41t81_write(M41T81REG_SC, tm.tm_sec); @@ -180,6 +182,7 @@ int m41t81_set_time(unsigned long t) tm.tm_year %= 100; tm.tm_year = BIN2BCD(tm.tm_year); m41t81_write(M41T81REG_YR, tm.tm_year); + spin_unlock_irqrestore(&rtc_lock, flags); return 0; } @@ -187,19 +190,23 @@ int m41t81_set_time(unsigned long t) unsigned long m41t81_get_time(void) { unsigned int year, mon, day, hour, min, sec; + unsigned long flags; /* * min is valid if two reads of sec are the same. */ for (;;) { + spin_lock_irqsave(&rtc_lock, flags); sec = m41t81_read(M41T81REG_SC); min = m41t81_read(M41T81REG_MN); if (sec == m41t81_read(M41T81REG_SC)) break; + spin_unlock_irqrestore(&rtc_lock, flags); } hour = m41t81_read(M41T81REG_HR) & 0x3f; day = m41t81_read(M41T81REG_DT); mon = m41t81_read(M41T81REG_MO); year = m41t81_read(M41T81REG_YR); + spin_unlock_irqrestore(&rtc_lock, flags); sec = BCD2BIN(sec); min = BCD2BIN(min); diff --git a/arch/mips/sibyte/swarm/rtc_xicor1241.c b/arch/mips/sibyte/swarm/rtc_xicor1241.c index d9ff9323f24eb81f5eb9d37b39488bac23210bd7..f4a178836415decef787fb02366592c0e1573dd7 100644 --- a/arch/mips/sibyte/swarm/rtc_xicor1241.c +++ b/arch/mips/sibyte/swarm/rtc_xicor1241.c @@ -113,9 +113,11 @@ int xicor_set_time(unsigned long t) { struct rtc_time tm; int tmp; + unsigned long flags; to_tm(t, &tm); + spin_lock_irqsave(&rtc_lock, flags); /* unlock writes to the CCR */ xicor_write(X1241REG_SR, X1241REG_SR_WEL); xicor_write(X1241REG_SR, X1241REG_SR_WEL | X1241REG_SR_RWEL); @@ -160,6 +162,7 @@ int xicor_set_time(unsigned long t) xicor_write(X1241REG_HR, tmp); xicor_write(X1241REG_SR, 0); + spin_unlock_irqrestore(&rtc_lock, flags); return 0; } @@ -167,7 +170,9 @@ int xicor_set_time(unsigned long t) unsigned long xicor_get_time(void) { unsigned int year, mon, day, hour, min, sec, y2k; + unsigned long flags; + spin_lock_irqsave(&rtc_lock, flags); sec = xicor_read(X1241REG_SC); min = xicor_read(X1241REG_MN); hour = xicor_read(X1241REG_HR); @@ -183,6 +188,7 @@ unsigned long xicor_get_time(void) mon = xicor_read(X1241REG_MO); year = xicor_read(X1241REG_YR); y2k = xicor_read(X1241REG_Y2K); + spin_unlock_irqrestore(&rtc_lock, flags); sec = BCD2BIN(sec); min = BCD2BIN(min); diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c index 18130c3748f3e4a46c6632c93e6c5b449abd19aa..b6fe202a620d5b4b013029a71e4e8cf75edd1ad4 100644 --- a/arch/parisc/kernel/ptrace.c +++ b/arch/parisc/kernel/ptrace.c @@ -78,52 +78,13 @@ void ptrace_disable(struct task_struct *child) pa_psw(child)->l = 0; } -long sys_ptrace(long request, long pid, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, long addr, long data) { - struct task_struct *child; long ret; #ifdef DEBUG_PTRACE long oaddr=addr, odata=data; #endif - lock_kernel(); - ret = -EPERM; - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - - ret = security_ptrace(current->parent, current); - if (ret) - goto out; - - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - ret = -EPERM; - if (pid == 1) /* no messing around with init! */ - goto out_tsk; - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) - goto out_tsk; - switch (request) { case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { @@ -383,11 +344,11 @@ long sys_ptrace(long request, long pid, long addr, long data) case PTRACE_GETEVENTMSG: ret = put_user(child->ptrace_message, (unsigned int __user *) data); - goto out_tsk; + goto out; default: ret = ptrace_request(child, request, addr, data); - goto out_tsk; + goto out; } out_wake_notrap: @@ -396,10 +357,7 @@ long sys_ptrace(long request, long pid, long addr, long data) wake_up_process(child); ret = 0; out_tsk: - put_task_struct(child); -out: - unlock_kernel(); - DBG("sys_ptrace(%ld, %d, %lx, %lx) returning %ld\n", + DBG("arch_ptrace(%ld, %d, %lx, %lx) returning %ld\n", request, pid, oaddr, odata, ret); return ret; } diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index ca7acb0c79f0cc79ab989680a853d83403e2a990..1493c7896fe35f3af26a866e56f4c1b5aed5a2b5 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -404,6 +404,14 @@ config CPU_FREQ_PMAC this currently includes some models of iBook & Titanium PowerBook. +config CPU_FREQ_PMAC64 + bool "Support for some Apple G5s" + depends on CPU_FREQ && PMAC_SMU && PPC64 + select CPU_FREQ_TABLE + help + This adds support for frequency switching on Apple iMac G5, + and some of the more recent desktop G5 machines as well. + config PPC601_SYNC_FIX bool "Workarounds for PPC601 bugs" depends on 6xx && (PPC_PREP || PPC_PMAC) @@ -484,6 +492,7 @@ source "fs/Kconfig.binfmt" config FORCE_MAX_ZONEORDER int depends on PPC64 + default "9" if PPC_64K_PAGES default "13" config MATH_EMULATION @@ -605,6 +614,7 @@ config NODES_SPAN_OTHER_NODES config PPC_64K_PAGES bool "64k page size" + depends on PPC64 help This option changes the kernel logical page size to 64k. On machines without processor support for 64k pages, the kernel will simulate @@ -916,8 +926,21 @@ source "arch/powerpc/platforms/iseries/Kconfig" source "lib/Kconfig" +menu "Instrumentation Support" + depends on EXPERIMENTAL + source "arch/powerpc/oprofile/Kconfig" +config KPROBES + bool "Kprobes (EXPERIMENTAL)" + help + Kprobes allows you to trap at almost any kernel address and + execute a callback function. register_kprobe() establishes + a probepoint and specifies the callback. Kprobes is useful + for kernel debugging, non-intrusive instrumentation and testing. + If in doubt, say "N". +endmenu + source "arch/powerpc/Kconfig.debug" source "security/Kconfig" diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index 0baf64ec80d022b9f7f00549014cbb0f9af26365..30a30bf559eaa161d4678c4faad74a3e286616e5 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -9,16 +9,6 @@ config DEBUG_STACKOVERFLOW This option will cause messages to be printed if free stack space drops below a certain limit. -config KPROBES - bool "Kprobes" - depends on DEBUG_KERNEL && PPC64 - help - Kprobes allows you to trap at almost any kernel address and - execute a callback function. register_kprobe() establishes - a probepoint and specifies the callback. Kprobes is useful - for kernel debugging, non-intrusive instrumentation and testing. - If in doubt, say "N". - config DEBUG_STACK_USAGE bool "Stack utilization instrumentation" depends on DEBUG_KERNEL && PPC64 diff --git a/arch/powerpc/configs/g5_defconfig b/arch/powerpc/configs/g5_defconfig index 6323065fbf2ce0d71692bb24ba117923fb1a3ede..e76854f8c121c0ae49acbdea06a1d11284271643 100644 --- a/arch/powerpc/configs/g5_defconfig +++ b/arch/powerpc/configs/g5_defconfig @@ -1,18 +1,32 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.14-rc4 -# Thu Oct 20 08:30:23 2005 +# Linux kernel version: 2.6.14 +# Mon Nov 7 13:37:59 2005 # +CONFIG_PPC64=y CONFIG_64BIT=y +CONFIG_PPC_MERGE=y CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_GENERIC_ISA_DMA=y +CONFIG_PPC=y CONFIG_EARLY_PRINTK=y CONFIG_COMPAT=y +CONFIG_SYSVIPC_COMPAT=y CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y CONFIG_ARCH_MAY_HAVE_PC_FDC=y -CONFIG_FORCE_MAX_ZONEORDER=13 + +# +# Processor support +# +CONFIG_POWER4_ONLY=y +CONFIG_POWER4=y +CONFIG_PPC_FPU=y +CONFIG_ALTIVEC=y +CONFIG_PPC_STD_MMU=y +CONFIG_SMP=y +CONFIG_NR_CPUS=2 # # Code maturity level options @@ -67,30 +81,60 @@ CONFIG_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y CONFIG_KMOD=y CONFIG_STOP_MACHINE=y -CONFIG_SYSVIPC_COMPAT=y # # Platform support # -# CONFIG_PPC_ISERIES is not set CONFIG_PPC_MULTIPLATFORM=y +# CONFIG_PPC_ISERIES is not set +# CONFIG_EMBEDDED6xx is not set +# CONFIG_APUS is not set # CONFIG_PPC_PSERIES is not set -# CONFIG_PPC_BPA is not set CONFIG_PPC_PMAC=y +CONFIG_PPC_PMAC64=y # CONFIG_PPC_MAPLE is not set -CONFIG_PPC=y -CONFIG_PPC64=y +# CONFIG_PPC_CELL is not set CONFIG_PPC_OF=y -CONFIG_MPIC=y -CONFIG_ALTIVEC=y -CONFIG_KEXEC=y CONFIG_U3_DART=y -CONFIG_PPC_PMAC64=y -CONFIG_BOOTX_TEXT=y -CONFIG_POWER4_ONLY=y +CONFIG_MPIC=y +# CONFIG_PPC_RTAS is not set +# CONFIG_MMIO_NVRAM is not set +# CONFIG_PPC_MPC106 is not set +CONFIG_GENERIC_TBSYNC=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +# CONFIG_CPU_FREQ_DEBUG is not set +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_PMAC64=y +# CONFIG_WANT_EARLY_SERIAL is not set + +# +# Kernel options +# +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +# CONFIG_PREEMPT_BKL is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_FORCE_MAX_ZONEORDER=13 CONFIG_IOMMU_VMERGE=y -CONFIG_SMP=y -CONFIG_NR_CPUS=2 +# CONFIG_HOTPLUG_CPU is not set +CONFIG_KEXEC=y +CONFIG_IRQ_ALL_CPUS=y +# CONFIG_NUMA is not set CONFIG_ARCH_SELECT_MEMORY_MODEL=y CONFIG_ARCH_FLATMEM_ENABLE=y CONFIG_SELECT_MEMORY_MODEL=y @@ -100,28 +144,21 @@ CONFIG_FLATMEM_MANUAL=y CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set -# CONFIG_NUMA is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_PPC_64K_PAGES is not set # CONFIG_SCHED_SMT is not set -CONFIG_PREEMPT_NONE=y -# CONFIG_PREEMPT_VOLUNTARY is not set -# CONFIG_PREEMPT is not set -# CONFIG_PREEMPT_BKL is not set -# CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 -CONFIG_GENERIC_HARDIRQS=y -CONFIG_SECCOMP=y -CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_HOTPLUG_CPU is not set CONFIG_PROC_DEVICETREE=y # CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set +CONFIG_SECCOMP=y CONFIG_ISA_DMA_API=y # -# Bus Options +# Bus options # +CONFIG_GENERIC_ISA_DMA=y +# CONFIG_PPC_I8259 is not set +# CONFIG_PPC_INDIRECT_PCI is not set CONFIG_PCI=y CONFIG_PCI_DOMAINS=y CONFIG_PCI_LEGACY_PROC=y @@ -136,6 +173,7 @@ CONFIG_PCI_LEGACY_PROC=y # PCI Hotplug Support # # CONFIG_HOTPLUG_PCI is not set +CONFIG_KERNEL_START=0xc000000000000000 # # Networking @@ -276,6 +314,10 @@ CONFIG_LLC=y # CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# # CONFIG_NET_SCHED is not set CONFIG_NET_CLS_ROUTE=y @@ -348,6 +390,11 @@ CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" # CONFIG_ATA_OVER_ETH is not set # @@ -449,6 +496,7 @@ CONFIG_SCSI_SPI_ATTRS=y # # SCSI low-level drivers # +# CONFIG_ISCSI_TCP is not set # CONFIG_BLK_DEV_3W_XXXX_RAID is not set # CONFIG_SCSI_3W_9XXX is not set # CONFIG_SCSI_ACARD is not set @@ -465,10 +513,12 @@ CONFIG_SCSI_SATA_SVW=y # CONFIG_SCSI_ATA_PIIX is not set # CONFIG_SCSI_SATA_MV is not set # CONFIG_SCSI_SATA_NV is not set -# CONFIG_SCSI_SATA_PROMISE is not set +# CONFIG_SCSI_PDC_ADMA is not set # CONFIG_SCSI_SATA_QSTOR is not set +# CONFIG_SCSI_SATA_PROMISE is not set # CONFIG_SCSI_SATA_SX4 is not set # CONFIG_SCSI_SATA_SIL is not set +# CONFIG_SCSI_SATA_SIL24 is not set # CONFIG_SCSI_SATA_SIS is not set # CONFIG_SCSI_SATA_ULI is not set # CONFIG_SCSI_SATA_VIA is not set @@ -567,6 +617,9 @@ CONFIG_IEEE1394_RAWIO=y CONFIG_ADB_PMU=y CONFIG_PMAC_SMU=y CONFIG_THERM_PM72=y +CONFIG_WINDFARM=y +CONFIG_WINDFARM_PM81=y +CONFIG_WINDFARM_PM91=y # # Network device support @@ -603,6 +656,7 @@ CONFIG_SUNGEM=y # CONFIG_NET_TULIP is not set # CONFIG_HP100 is not set # CONFIG_NET_PCI is not set +# CONFIG_FEC_8XX is not set # # Ethernet (1000 Mbit) @@ -768,6 +822,7 @@ CONFIG_MAX_RAW_DEVS=256 # TPM devices # # CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set # # I2C support @@ -820,6 +875,7 @@ CONFIG_I2C_PMAC_SMU=y # CONFIG_SENSORS_PCF8591 is not set # CONFIG_SENSORS_RTC8564 is not set # CONFIG_SENSORS_MAX6875 is not set +# CONFIG_RTC_X1205_I2C is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set @@ -876,10 +932,9 @@ CONFIG_FB_OF=y # CONFIG_FB_ASILIANT is not set # CONFIG_FB_IMSTT is not set # CONFIG_FB_VGA16 is not set -# CONFIG_FB_NVIDIA is not set -CONFIG_FB_RIVA=y -# CONFIG_FB_RIVA_I2C is not set -# CONFIG_FB_RIVA_DEBUG is not set +CONFIG_FB_NVIDIA=y +CONFIG_FB_NVIDIA_I2C=y +# CONFIG_FB_RIVA is not set # CONFIG_FB_MATROX is not set # CONFIG_FB_RADEON_OLD is not set CONFIG_FB_RADEON=y @@ -924,7 +979,96 @@ CONFIG_LCD_DEVICE=y # # Sound # -# CONFIG_SOUND is not set +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_SEQUENCER=m +# CONFIG_SND_SEQ_DUMMY is not set +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_SEQUENCER_OSS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_GENERIC_DRIVER=y + +# +# Generic devices +# +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_VIRMIDI is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set + +# +# PCI devices +# +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CS46XX is not set +# CONFIG_SND_CS4281 is not set +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set +# CONFIG_SND_TRIDENT is not set +# CONFIG_SND_YMFPCI is not set +# CONFIG_SND_AD1889 is not set +# CONFIG_SND_ALS4000 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_MAESTRO3 is not set +# CONFIG_SND_FM801 is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VX222 is not set +# CONFIG_SND_HDA_INTEL is not set + +# +# ALSA PowerMac devices +# +CONFIG_SND_POWERMAC=m +CONFIG_SND_POWERMAC_AUTO_DRC=y + +# +# USB devices +# +CONFIG_SND_USB_AUDIO=m +# CONFIG_SND_USB_USX2Y is not set + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set # # USB support @@ -958,12 +1102,16 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y # # USB Device Class drivers # -# CONFIG_USB_BLUETOOTH_TTY is not set +# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set CONFIG_USB_ACM=m CONFIG_USB_PRINTER=y # -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# may also be needed; see USB_STORAGE Help for more information # CONFIG_USB_STORAGE=y # CONFIG_USB_STORAGE_DEBUG is not set @@ -1074,6 +1222,7 @@ CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y CONFIG_USB_SERIAL_KLSI=m CONFIG_USB_SERIAL_KOBIL_SCT=m CONFIG_USB_SERIAL_MCT_U232=m +# CONFIG_USB_SERIAL_NOKIA_DKU2 is not set CONFIG_USB_SERIAL_PL2303=m # CONFIG_USB_SERIAL_HP4X is not set CONFIG_USB_SERIAL_SAFE=m @@ -1310,6 +1459,20 @@ CONFIG_NLS_ISO8859_15=y # CONFIG_NLS_KOI8_U is not set CONFIG_NLS_UTF8=y +# +# Library routines +# +CONFIG_CRC_CCITT=m +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=m +CONFIG_TEXTSEARCH_BM=m +CONFIG_TEXTSEARCH_FSM=m + # # Profiling support # @@ -1331,12 +1494,14 @@ CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_INFO is not set CONFIG_DEBUG_FS=y +# CONFIG_DEBUG_VM is not set +# CONFIG_RCU_TORTURE_TEST is not set # CONFIG_DEBUG_STACKOVERFLOW is not set # CONFIG_KPROBES is not set # CONFIG_DEBUG_STACK_USAGE is not set # CONFIG_DEBUGGER is not set -# CONFIG_PPCDBG is not set CONFIG_IRQSTACKS=y +CONFIG_BOOTX_TEXT=y # # Security options @@ -1376,17 +1541,3 @@ CONFIG_CRYPTO_TEST=m # # Hardware crypto devices # - -# -# Library routines -# -CONFIG_CRC_CCITT=m -# CONFIG_CRC16 is not set -CONFIG_CRC32=y -CONFIG_LIBCRC32C=m -CONFIG_ZLIB_INFLATE=y -CONFIG_ZLIB_DEFLATE=m -CONFIG_TEXTSEARCH=y -CONFIG_TEXTSEARCH_KMP=m -CONFIG_TEXTSEARCH_BM=m -CONFIG_TEXTSEARCH_FSM=m diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 33c63bcf69f8e1670736f0dca9452c91a1774e03..cc4e9eb1c13f98041ca53467659c0f3b024cee28 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -929,6 +929,16 @@ struct cpu_spec cpu_specs[] = { .icache_bsize = 32, .dcache_bsize = 32, }, + { /* 440SPe Rev. A */ + .pvr_mask = 0xff000fff, + .pvr_value = 0x53000890, + .cpu_name = "440SPe Rev. A", + .cpu_features = CPU_FTR_SPLIT_ID_CACHE | + CPU_FTR_USE_TB, + .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, + .icache_bsize = 32, + .dcache_bsize = 32, + }, #endif /* CONFIG_44x */ #ifdef CONFIG_FSL_BOOKE { /* e200z5 */ diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index b3e95ff0dba0a63116d6e06f375d56c138dec85b..ae1433da09b27ea4cd76f0013616a35d38560855 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S @@ -603,6 +603,76 @@ _GLOBAL(real_writeb) blr #endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */ +/* + * SCOM access functions for 970 (FX only for now) + * + * unsigned long scom970_read(unsigned int address); + * void scom970_write(unsigned int address, unsigned long value); + * + * The address passed in is the 24 bits register address. This code + * is 970 specific and will not check the status bits, so you should + * know what you are doing. + */ +_GLOBAL(scom970_read) + /* interrupts off */ + mfmsr r4 + ori r0,r4,MSR_EE + xori r0,r0,MSR_EE + mtmsrd r0,1 + + /* rotate 24 bits SCOM address 8 bits left and mask out it's low 8 bits + * (including parity). On current CPUs they must be 0'd, + * and finally or in RW bit + */ + rlwinm r3,r3,8,0,15 + ori r3,r3,0x8000 + + /* do the actual scom read */ + sync + mtspr SPRN_SCOMC,r3 + isync + mfspr r3,SPRN_SCOMD + isync + mfspr r0,SPRN_SCOMC + isync + + /* XXX: fixup result on some buggy 970's (ouch ! we lost a bit, bah + * that's the best we can do). Not implemented yet as we don't use + * the scom on any of the bogus CPUs yet, but may have to be done + * ultimately + */ + + /* restore interrupts */ + mtmsrd r4,1 + blr + + +_GLOBAL(scom970_write) + /* interrupts off */ + mfmsr r5 + ori r0,r5,MSR_EE + xori r0,r0,MSR_EE + mtmsrd r0,1 + + /* rotate 24 bits SCOM address 8 bits left and mask out it's low 8 bits + * (including parity). On current CPUs they must be 0'd. + */ + + rlwinm r3,r3,8,0,15 + + sync + mtspr SPRN_SCOMD,r4 /* write data */ + isync + mtspr SPRN_SCOMC,r3 /* write command */ + isync + mfspr 3,SPRN_SCOMC + isync + + /* restore interrupts */ + mtmsrd r5,1 + blr + + /* * Create a kernel thread * kernel_thread(fn, arg, flags) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 7f64f0464d446997756c4fae4c903665d717ea19..de69fb37c7313ce83d450bdbd6f5a15eb621bdd0 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -46,10 +46,10 @@ #include #include #include +#include #ifdef CONFIG_PPC64 #include #include -#include #endif extern unsigned long _get_SP(void); @@ -203,10 +203,8 @@ int dump_spe(struct pt_regs *regs, elf_vrregset_t *evrregs) int set_dabr(unsigned long dabr) { -#ifdef CONFIG_PPC64 if (ppc_md.set_dabr) return ppc_md.set_dabr(dabr); -#endif mtspr(SPRN_DABR, dabr); return 0; diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 3675ef4bac90f09c4e12b5d02580beecafa6ea40..f645adb57534be04a39a2ed7718362b06359e812 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -1974,14 +1974,29 @@ EXPORT_SYMBOL(get_property); /* * Add a property to a node */ -void prom_add_property(struct device_node* np, struct property* prop) +int prom_add_property(struct device_node* np, struct property* prop) { - struct property **next = &np->properties; + struct property **next; prop->next = NULL; - while (*next) + write_lock(&devtree_lock); + next = &np->properties; + while (*next) { + if (strcmp(prop->name, (*next)->name) == 0) { + /* duplicate ! don't insert it */ + write_unlock(&devtree_lock); + return -1; + } next = &(*next)->next; + } *next = prop; + write_unlock(&devtree_lock); + + /* try to add to proc as well if it was initialized */ + if (np->pde) + proc_device_tree_add_prop(np->pde, prop); + + return 0; } /* I quickly hacked that one, check against spec ! */ diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index c758b6624d7bee6c777c5e0532c8b16553b7f52b..6dc33d19fc2abcfcf1c6ce3726c5cbf4adcf49a6 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -403,19 +403,19 @@ static int __init prom_next_node(phandle *nodep) } } -static int __init prom_getprop(phandle node, const char *pname, +static int inline prom_getprop(phandle node, const char *pname, void *value, size_t valuelen) { return call_prom("getprop", 4, 1, node, ADDR(pname), (u32)(unsigned long) value, (u32) valuelen); } -static int __init prom_getproplen(phandle node, const char *pname) +static int inline prom_getproplen(phandle node, const char *pname) { return call_prom("getproplen", 2, 1, node, ADDR(pname)); } -static int __init prom_setprop(phandle node, const char *pname, +static int inline prom_setprop(phandle node, const char *pname, void *value, size_t valuelen) { return call_prom("setprop", 4, 1, node, ADDR(pname), @@ -1408,8 +1408,9 @@ static int __init prom_find_machine_type(void) struct prom_t *_prom = &RELOC(prom); char compat[256]; int len, i = 0; +#ifdef CONFIG_PPC64 phandle rtas; - +#endif len = prom_getprop(_prom->root, "compatible", compat, sizeof(compat)-1); if (len > 0) { @@ -1872,7 +1873,7 @@ static void __init fixup_device_tree(void) if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) == PROM_ERROR) return; - if (u3_rev != 0x35 && u3_rev != 0x37) + if (u3_rev < 0x35 || u3_rev > 0x39) return; /* does it need fixup ? */ if (prom_getproplen(i2c, "interrupts") > 0) diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 568ea335d61626bfabb10d5421fada42f3c1d62e..3d2abd95c7aea05b23cfb8e9cc8db69ffd9e9838 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -248,46 +248,10 @@ void ptrace_disable(struct task_struct *child) clear_single_step(child); } -long sys_ptrace(long request, long pid, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, long addr, long data) { - struct task_struct *child; int ret = -EPERM; - lock_kernel(); - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - ret = security_ptrace(current->parent, current); - if (ret) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) - goto out_tsk; - switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ @@ -540,10 +504,7 @@ long sys_ptrace(long request, long pid, long addr, long data) ret = ptrace_request(child, request, addr, data); break; } -out_tsk: - put_task_struct(child); -out: - unlock_kernel(); + return ret; } diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index b7fc2d884950c2fa31e935ca7628ace355167610..9d4e07f6f1ecb5e061fa6619df534fde1491cef3 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -83,7 +84,7 @@ void call_rtas_display_status_delay(unsigned char c) while (width-- > 0) call_rtas_display_status(' '); width = 16; - udelay(500000); + mdelay(500); pending_newline = 1; } else { if (pending_newline) { @@ -608,7 +609,6 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs) return 0; } -#ifdef CONFIG_SMP /* This version can't take the spinlock, because it never returns */ struct rtas_args rtas_stop_self_args = { @@ -633,7 +633,6 @@ void rtas_stop_self(void) panic("Alas, I survived.\n"); } -#endif /* * Call early during boot, before mem init or bootmem, to retreive the RTAS diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index d43fa8c0e5ac0861058b8800dafffb7fc63a8a5a..e22856ecb5a0396f1000cae57289a24107a168dd 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -405,6 +405,46 @@ static int __init set_preferred_console(void) console_initcall(set_preferred_console); #endif /* CONFIG_PPC_MULTIPLATFORM */ +void __init check_for_initrd(void) +{ +#ifdef CONFIG_BLK_DEV_INITRD + unsigned long *prop; + + DBG(" -> check_for_initrd()\n"); + + if (of_chosen) { + prop = (unsigned long *)get_property(of_chosen, + "linux,initrd-start", NULL); + if (prop != NULL) { + initrd_start = (unsigned long)__va(*prop); + prop = (unsigned long *)get_property(of_chosen, + "linux,initrd-end", NULL); + if (prop != NULL) { + initrd_end = (unsigned long)__va(*prop); + initrd_below_start_ok = 1; + } else + initrd_start = 0; + } + } + + /* If we were passed an initrd, set the ROOT_DEV properly if the values + * look sensible. If not, clear initrd reference. + */ + if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE && + initrd_end > initrd_start) + ROOT_DEV = Root_RAM0; + else { + printk("Bogus initrd %08lx %08lx\n", initrd_start, initrd_end); + initrd_start = initrd_end = 0; + } + + if (initrd_start) + printk("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end); + + DBG(" <- check_for_initrd()\n"); +#endif /* CONFIG_BLK_DEV_INITRD */ +} + #ifdef CONFIG_SMP /** diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index b45eedbb4b3a53ec439698ca3f7b115ad2ae87be..3af2631e3fab07f0ce0a4406bd897319a783d6a5 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -286,6 +286,7 @@ void __init setup_arch(char **cmdline_p) loops_per_jiffy = 500000000 / HZ; unflatten_device_tree(); + check_for_initrd(); finish_device_tree(); smp_setup_cpu_maps(); diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index b0994050024ff0c127dfece85a4e42ade8255387..0471e843b6c53961f515a6e46a8e594cbc26a946 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -60,6 +59,7 @@ #include #include #include +#include #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) @@ -243,12 +243,6 @@ void __init early_setup(unsigned long dt_ptr) DBG(" -> early_setup()\n"); - /* - * Fill the default DBG level (do we want to keep - * that old mecanism around forever ?) - */ - ppcdbg_initialize(); - /* * Do early initializations using the flattened device * tree, like retreiving the physical memory map or @@ -401,43 +395,6 @@ static void __init initialize_cache_info(void) DBG(" <- initialize_cache_info()\n"); } -static void __init check_for_initrd(void) -{ -#ifdef CONFIG_BLK_DEV_INITRD - u64 *prop; - - DBG(" -> check_for_initrd()\n"); - - if (of_chosen) { - prop = (u64 *)get_property(of_chosen, - "linux,initrd-start", NULL); - if (prop != NULL) { - initrd_start = (unsigned long)__va(*prop); - prop = (u64 *)get_property(of_chosen, - "linux,initrd-end", NULL); - if (prop != NULL) { - initrd_end = (unsigned long)__va(*prop); - initrd_below_start_ok = 1; - } else - initrd_start = 0; - } - } - - /* If we were passed an initrd, set the ROOT_DEV properly if the values - * look sensible. If not, clear initrd reference. - */ - if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE && - initrd_end > initrd_start) - ROOT_DEV = Root_RAM0; - else - initrd_start = initrd_end = 0; - - if (initrd_start) - printk("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end); - - DBG(" <- check_for_initrd()\n"); -#endif /* CONFIG_BLK_DEV_INITRD */ -} /* * Do some initial setup of the system. The parameters are those which @@ -521,7 +478,6 @@ void __init setup_system(void) printk("-----------------------------------------------------\n"); printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size); - printk("ppc64_debug_switch = 0x%lx\n", ppc64_debug_switch); printk("ppc64_interrupt_controller = 0x%ld\n", ppc64_interrupt_controller); printk("systemcfg = 0x%p\n", systemcfg); printk("systemcfg->platform = 0x%x\n", systemcfg->platform); diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 876c57c11365a57ff36e75f5171c865fb5c35e70..081d931eae481e34671818eab5b21a208cb18012 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -44,7 +44,6 @@ #include #ifdef CONFIG_PPC64 #include "ppc32.h" -#include #include #include #else diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index ec9d0984b6a09118f89abeb7f95675247c293f9f..58194e150711992afe9315d12afcf990964e933f 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 1794a694a92868d75adbd5584b6b6ac4fa72f9a7..5c330c3366e42e2ec500cd8fe98fbdd7c94c3bc8 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 6996a593dcb39b91422fa205f2af8057c2109165..a6282b625b440203aebb48f58e59c10fb4fa1ed5 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -61,6 +61,7 @@ #include #include #include +#include #ifdef CONFIG_PPC64 #include #include @@ -69,6 +70,7 @@ #include #include #endif +#include /* keep track of when we need to update the rtc */ time_t last_rtc_update; @@ -118,10 +120,6 @@ static unsigned adjusting_time = 0; unsigned long ppc_proc_freq; unsigned long ppc_tb_freq; -#ifdef CONFIG_PPC32 /* XXX for now */ -#define boot_cpuid 0 -#endif - u64 tb_last_jiffy __cacheline_aligned_in_smp; unsigned long tb_last_stamp; diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 07e5ee40b8700aadc5cc82a395c7c20e088a402a..32f215825e8d87823157eb047c453f9fffedbc3b 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #ifdef CONFIG_PPC32 #include @@ -748,22 +747,12 @@ static int check_bug_trap(struct pt_regs *regs) return 0; if (bug->line & BUG_WARNING_TRAP) { /* this is a WARN_ON rather than BUG/BUG_ON */ -#ifdef CONFIG_XMON - xmon_printf(KERN_ERR "Badness in %s at %s:%ld\n", - bug->function, bug->file, - bug->line & ~BUG_WARNING_TRAP); -#endif /* CONFIG_XMON */ printk(KERN_ERR "Badness in %s at %s:%ld\n", bug->function, bug->file, bug->line & ~BUG_WARNING_TRAP); dump_stack(); return 1; } -#ifdef CONFIG_XMON - xmon_printf(KERN_CRIT "kernel BUG in %s at %s:%ld!\n", - bug->function, bug->file, bug->line); - xmon(regs); -#endif /* CONFIG_XMON */ printk(KERN_CRIT "kernel BUG in %s at %s:%ld!\n", bug->function, bug->file, bug->line); diff --git a/arch/powerpc/lib/locks.c b/arch/powerpc/lib/locks.c index 2a912f411eb4af13500c97271e71e2b32d650daf..35bd03c41dd19727601e15f9169bc8807f50fb75 100644 --- a/arch/powerpc/lib/locks.c +++ b/arch/powerpc/lib/locks.c @@ -23,6 +23,7 @@ #if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES) #include #include +#include void __spin_yield(raw_spinlock_t *lock) { diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 841d8b6323a8da26699086273bb4560514bc85f8..93d4fbfdb724a137ee6ab385d880e79e80795f75 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -389,5 +389,22 @@ void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig) } /* kernel has accessed a bad area */ + + printk(KERN_ALERT "Unable to handle kernel paging request for "); + switch (regs->trap) { + case 0x300: + case 0x380: + printk("data at address 0x%08lx\n", regs->dar); + break; + case 0x400: + case 0x480: + printk("instruction fetch\n"); + break; + default: + printk("unknown fault\n"); + } + printk(KERN_ALERT "Faulting instruction address: 0x%08lx\n", + regs->nip); + die("Kernel access of bad area", regs, sig); } diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index b2f3dbca695223fc988c1be9cc778243481eb221..22e474876133b334724d053a3e2434c06481acca 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -33,7 +33,6 @@ #include #include -#include #include #include #include @@ -329,12 +328,14 @@ static void __init htab_init_page_sizes(void) */ if (mmu_psize_defs[MMU_PAGE_16M].shift) mmu_huge_psize = MMU_PAGE_16M; + /* With 4k/4level pagetables, we can't (for now) cope with a + * huge page size < PMD_SIZE */ else if (mmu_psize_defs[MMU_PAGE_1M].shift) mmu_huge_psize = MMU_PAGE_1M; /* Calculate HPAGE_SHIFT and sanity check it */ - if (mmu_psize_defs[mmu_huge_psize].shift > 16 && - mmu_psize_defs[mmu_huge_psize].shift < 28) + if (mmu_psize_defs[mmu_huge_psize].shift > MIN_HUGEPTE_SHIFT && + mmu_psize_defs[mmu_huge_psize].shift < SID_SHIFT) HPAGE_SHIFT = mmu_psize_defs[mmu_huge_psize].shift; else HPAGE_SHIFT = 0; /* No huge pages dude ! */ @@ -407,12 +408,6 @@ void __init htab_initialize(void) htab_size_bytes = htab_get_table_size(); pteg_count = htab_size_bytes >> 7; - /* For debug, make the HTAB 1/8 as big as it normally would be. */ - ifppcdebug(PPCDBG_HTABSIZE) { - pteg_count >>= 3; - htab_size_bytes = pteg_count << 7; - } - htab_hash_mask = pteg_count - 1; if (systemcfg->platform & PLATFORM_LPAR) { @@ -512,6 +507,9 @@ unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap) { struct page *page; + if (!pfn_valid(pte_pfn(pte))) + return pp; + page = pte_page(pte); /* page is dirty */ diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 0073a04047e48b6a7b8144ee1538142925d7bdb3..426c269e552eec77bbee18cb086f900716cffb4a 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -212,6 +212,12 @@ static int prepare_high_area_for_htlb(struct mm_struct *mm, unsigned long area) BUG_ON(area >= NUM_HIGH_AREAS); + /* Hack, so that each addresses is controlled by exactly one + * of the high or low area bitmaps, the first high area starts + * at 4GB, not 0 */ + if (start == 0) + start = 0x100000000UL; + /* Check no VMAs are in the region */ vma = find_vma(mm, start); if (vma && (vma->vm_start < end)) diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c index dfe7fa37b41a16835b629964d2b21faefe2d97b9..ce974c83d88a6f1decd8341ccf92fbf253133c37 100644 --- a/arch/powerpc/mm/init_64.c +++ b/arch/powerpc/mm/init_64.c @@ -57,7 +57,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 7faa46b71f21ee2db7a6c4d783206c747cdaad8d..6f55efd9be957debe2c1522bda11ca50cb174a17 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -358,7 +358,7 @@ void __init mem_init(void) } codesize = (unsigned long)&_sdata - (unsigned long)&_stext; - datasize = (unsigned long)&__init_begin - (unsigned long)&_sdata; + datasize = (unsigned long)&_edata - (unsigned long)&_sdata; initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin; bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start; diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 4035cad8d7f19b84482d11f48ce067bb23e53133..da09ba03c424fb6b89ca06c795bbf2c646d5f734 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -21,6 +21,7 @@ #include #include #include +#include static int numa_enabled = 1; diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index 51b7869409715d8ce9ebf51d31a89b4258460c55..900842451bd33a339676ffddfc540cc8e7f82646 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c @@ -59,7 +59,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c index d137abd241ff09dc0c7c520794c13b1c24016269..ed7fcfe5fd370882d2264bd3e86ed04b9cbc74aa 100644 --- a/arch/powerpc/mm/ppc_mmu_32.c +++ b/arch/powerpc/mm/ppc_mmu_32.c @@ -188,9 +188,9 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, if (Hash == 0) return; - pmd = pmd_offset(pgd_offset(vma->vm_mm, address), address); + pmd = pmd_offset(pgd_offset(mm, ea), ea); if (!pmd_none(*pmd)) - add_hash_page(vma->vm_mm->context, address, pmd_val(*pmd)); + add_hash_page(mm->context, ea, pmd_val(*pmd)); } /* diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S index 3e18241b6f35218b65619762f63fc1867052aa83..950ffc5848c7950e1d449615aa61fb5782dde2cc 100644 --- a/arch/powerpc/mm/slb_low.S +++ b/arch/powerpc/mm/slb_low.S @@ -80,12 +80,17 @@ _GLOBAL(slb_miss_kernel_load_virtual) BEGIN_FTR_SECTION b 1f END_FTR_SECTION_IFCLR(CPU_FTR_16M_PAGE) + cmpldi r10,16 + + lhz r9,PACALOWHTLBAREAS(r13) + mr r11,r10 + blt 5f + lhz r9,PACAHIGHHTLBAREAS(r13) srdi r11,r10,(HTLB_AREA_SHIFT-SID_SHIFT) - srd r9,r9,r11 - lhz r11,PACALOWHTLBAREAS(r13) - srd r11,r11,r10 - or. r9,r9,r11 + +5: srd r9,r9,r11 + andi. r9,r9,1 beq 1f _GLOBAL(slb_miss_user_load_huge) li r11,0 diff --git a/arch/powerpc/oprofile/Kconfig b/arch/powerpc/oprofile/Kconfig index 19d37730b664a03cc441886740dc517fd7349c2c..eb2dece76a540626fc3fe6c0f90e4330f9c84a59 100644 --- a/arch/powerpc/oprofile/Kconfig +++ b/arch/powerpc/oprofile/Kconfig @@ -1,7 +1,3 @@ - -menu "Profiling support" - depends on EXPERIMENTAL - config PROFILING bool "Profiling support (EXPERIMENTAL)" help @@ -19,5 +15,3 @@ config OPROFILE If unsure, say N. -endmenu - diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c index 88644931584707ad11fde6282465221350e253d9..c4ee5478427b4ae322a8e1b4dd18f3600a23ce9a 100644 --- a/arch/powerpc/oprofile/op_model_power4.c +++ b/arch/powerpc/oprofile/op_model_power4.c @@ -17,6 +17,7 @@ #include #include #include +#include #define dbg(args...) @@ -81,6 +82,26 @@ static void power4_reg_setup(struct op_counter_config *ctr, extern void ppc64_enable_pmcs(void); +/* + * Older CPUs require the MMCRA sample bit to be always set, but newer + * CPUs only want it set for some groups. Eventually we will remove all + * knowledge of this bit in the kernel, oprofile userspace should be + * setting it when required. + * + * In order to keep current installations working we force the bit for + * those older CPUs. Once everyone has updated their oprofile userspace we + * can remove this hack. + */ +static inline int mmcra_must_set_sample(void) +{ + if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p) || + __is_processor(PV_970) || __is_processor(PV_970FX) || + __is_processor(PV_970MP)) + return 1; + + return 0; +} + static void power4_cpu_setup(void *unused) { unsigned int mmcr0 = mmcr0_val; @@ -98,7 +119,8 @@ static void power4_cpu_setup(void *unused) mtspr(SPRN_MMCR1, mmcr1_val); - mmcra |= MMCRA_SAMPLE_ENABLE; + if (mmcra_must_set_sample()) + mmcra |= MMCRA_SAMPLE_ENABLE; mtspr(SPRN_MMCRA, mmcra); dbg("setup on cpu %d, mmcr0 %lx\n", smp_processor_id(), diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index c1135912cc055c2df6139a64ebe346a67349c94b..a06603d84a451147d0cd646c40d18d9ef172bc94 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c @@ -35,7 +35,6 @@ #include #include -#include #include #include #include @@ -227,8 +226,6 @@ static void iSeries_enable_IRQ(unsigned int irq) /* Unmask secondary INTA */ mask = 0x80000000; HvCallPci_unmaskInterrupts(bus, subBus, deviceId, mask); - PPCDBG(PPCDBG_BUSWALK, "iSeries_enable_IRQ 0x%02X.%02X.%02X 0x%04X\n", - bus, subBus, deviceId, irq); } /* This is called by iSeries_activate_IRQs */ @@ -310,8 +307,6 @@ static void iSeries_disable_IRQ(unsigned int irq) /* Mask secondary INTA */ mask = 0x80000000; HvCallPci_maskInterrupts(bus, subBus, deviceId, mask); - PPCDBG(PPCDBG_BUSWALK, "iSeries_disable_IRQ 0x%02X.%02X.%02X 0x%04X\n", - bus, subBus, deviceId, irq); } /* diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c index 7d7d5884343fa4a77a355601420a4cd681cf7aa2..4b75131773a698eef0ec7ff1ab38e5b3b9331b97 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include @@ -207,10 +206,6 @@ static struct device_node *build_device_node(HvBusNumber Bus, struct device_node *node; struct pci_dn *pdn; - PPCDBG(PPCDBG_BUSWALK, - "-build_device_node 0x%02X.%02X.%02X Function: %02X\n", - Bus, SubBus, AgentId, Function); - node = kmalloc(sizeof(struct device_node), GFP_KERNEL); if (node == NULL) return NULL; @@ -243,8 +238,6 @@ unsigned long __init find_and_init_phbs(void) struct pci_controller *phb; HvBusNumber bus; - PPCDBG(PPCDBG_BUSWALK, "find_and_init_phbs Entry\n"); - /* Check all possible buses. */ for (bus = 0; bus < 256; bus++) { int ret = HvCallXm_testBus(bus); @@ -261,9 +254,6 @@ unsigned long __init find_and_init_phbs(void) phb->last_busno = bus; phb->ops = &iSeries_pci_ops; - PPCDBG(PPCDBG_BUSWALK, "PCI:Create iSeries pci_controller(%p), Bus: %04X\n", - phb, bus); - /* Find and connect the devices. */ scan_PHB_slots(phb); } @@ -285,11 +275,9 @@ unsigned long __init find_and_init_phbs(void) */ void iSeries_pcibios_init(void) { - PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_init Entry.\n"); iomm_table_initialize(); find_and_init_phbs(); io_page_mask = -1; - PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_init Exit.\n"); } /* @@ -301,8 +289,6 @@ void __init iSeries_pci_final_fixup(void) struct device_node *node; int DeviceCount = 0; - PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_fixup Entry.\n"); - /* Fix up at the device node and pci_dev relationship */ mf_display_src(0xC9000100); @@ -316,9 +302,6 @@ void __init iSeries_pci_final_fixup(void) ++DeviceCount; pdev->sysdata = (void *)node; PCI_DN(node)->pcidev = pdev; - PPCDBG(PPCDBG_BUSWALK, - "pdev 0x%p <==> DevNode 0x%p\n", - pdev, node); allocate_device_bars(pdev); iSeries_Device_Information(pdev, DeviceCount); iommu_devnode_init_iSeries(node); @@ -333,13 +316,10 @@ void __init iSeries_pci_final_fixup(void) void pcibios_fixup_bus(struct pci_bus *PciBus) { - PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_fixup_bus(0x%04X) Entry.\n", - PciBus->number); } void pcibios_fixup_resources(struct pci_dev *pdev) { - PPCDBG(PPCDBG_BUSWALK, "fixup_resources pdev %p\n", pdev); } /* @@ -401,9 +381,6 @@ static void scan_EADS_bridge(HvBusNumber bus, HvSubBusNumber SubBus, printk("found device at bus %d idsel %d func %d (AgentId %x)\n", bus, IdSel, Function, AgentId); /* Connect EADs: 0x18.00.12 = 0x00 */ - PPCDBG(PPCDBG_BUSWALK, - "PCI:Connect EADs: 0x%02X.%02X.%02X\n", - bus, SubBus, AgentId); HvRc = HvCallPci_getBusUnitInfo(bus, SubBus, AgentId, iseries_hv_addr(BridgeInfo), sizeof(struct HvCallPci_BridgeInfo)); @@ -414,14 +391,6 @@ static void scan_EADS_bridge(HvBusNumber bus, HvSubBusNumber SubBus, BridgeInfo->maxAgents, BridgeInfo->maxSubBusNumber, BridgeInfo->logicalSlotNumber); - PPCDBG(PPCDBG_BUSWALK, - "PCI: BridgeInfo, Type:0x%02X, SubBus:0x%02X, MaxAgents:0x%02X, MaxSubBus: 0x%02X, LSlot: 0x%02X\n", - BridgeInfo->busUnitInfo.deviceType, - BridgeInfo->subBusNumber, - BridgeInfo->maxAgents, - BridgeInfo->maxSubBusNumber, - BridgeInfo->logicalSlotNumber); - if (BridgeInfo->busUnitInfo.deviceType == HvCallPci_BridgeDevice) { /* Scan_Bridge_Slot...: 0x18.00.12 */ @@ -454,9 +423,6 @@ static int scan_bridge_slot(HvBusNumber Bus, /* iSeries_allocate_IRQ.: 0x18.00.12(0xA3) */ Irq = iSeries_allocate_IRQ(Bus, 0, EADsIdSel); - PPCDBG(PPCDBG_BUSWALK, - "PCI:- allocate and assign IRQ 0x%02X.%02X.%02X = 0x%02X\n", - Bus, 0, EADsIdSel, Irq); /* * Connect all functions of any device found. @@ -482,9 +448,6 @@ static int scan_bridge_slot(HvBusNumber Bus, printk("read vendor ID: %x\n", VendorId); /* FoundDevice: 0x18.28.10 = 0x12AE */ - PPCDBG(PPCDBG_BUSWALK, - "PCI:- FoundDevice: 0x%02X.%02X.%02X = 0x%04X, irq %d\n", - Bus, SubBus, AgentId, VendorId, Irq); HvRc = HvCallPci_configStore8(Bus, SubBus, AgentId, PCI_INTERRUPT_LINE, Irq); if (HvRc != 0) diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index c5207064977db1ac3ae901b6f86762e1a1393fc6..d3e4bf756c8382f4a8b6434787c44018093eaa5f 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c @@ -71,8 +71,6 @@ extern void hvlog(char *fmt, ...); #endif /* Function Prototypes */ -extern void ppcdbg_initialize(void); - static void build_iSeries_Memory_Map(void); static void iseries_shared_idle(void); static void iseries_dedicated_idle(void); @@ -309,8 +307,6 @@ static void __init iSeries_init_early(void) ppc64_firmware_features = FW_FEATURE_ISERIES; - ppcdbg_initialize(); - ppc64_interrupt_controller = IC_ISERIES; #if defined(CONFIG_BLK_DEV_INITRD) diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c index 3336bad67724e0f6cb30ea775d9e3a6c00e1903b..fcb094ec6aec6efa082879088bf542399c43b23e 100644 --- a/arch/powerpc/platforms/iseries/smp.c +++ b/arch/powerpc/platforms/iseries/smp.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/platforms/powermac/Makefile b/arch/powerpc/platforms/powermac/Makefile index 4369676f1d541d416665a4e1d165150ed7566f78..c9df44fcf5710f0ea558b39df6cb945efd090011 100644 --- a/arch/powerpc/platforms/powermac/Makefile +++ b/arch/powerpc/platforms/powermac/Makefile @@ -1,7 +1,8 @@ obj-y += pic.o setup.o time.o feature.o pci.o \ sleep.o low_i2c.o cache.o obj-$(CONFIG_PMAC_BACKLIGHT) += backlight.o -obj-$(CONFIG_CPU_FREQ_PMAC) += cpufreq.o +obj-$(CONFIG_CPU_FREQ_PMAC) += cpufreq_32.o +obj-$(CONFIG_CPU_FREQ_PMAC64) += cpufreq_64.o obj-$(CONFIG_NVRAM) += nvram.o # ppc64 pmac doesn't define CONFIG_NVRAM but needs nvram stuff obj-$(CONFIG_PPC64) += nvram.o diff --git a/arch/powerpc/platforms/powermac/cpufreq.c b/arch/powerpc/platforms/powermac/cpufreq_32.c similarity index 99% rename from arch/powerpc/platforms/powermac/cpufreq.c rename to arch/powerpc/platforms/powermac/cpufreq_32.c index c47f8b69725c63144935336b52eacda34d9531b9..56fd4e05fede95b68d05e91b075e91f2c2ab535b 100644 --- a/arch/powerpc/platforms/powermac/cpufreq.c +++ b/arch/powerpc/platforms/powermac/cpufreq_32.c @@ -397,18 +397,16 @@ static int pmac_cpufreq_target( struct cpufreq_policy *policy, unsigned int relation) { unsigned int newstate = 0; + int rc; if (cpufreq_frequency_table_target(policy, pmac_cpu_freqs, target_freq, relation, &newstate)) return -EINVAL; - return do_set_cpu_speed(newstate, 1); -} + rc = do_set_cpu_speed(newstate, 1); -unsigned int pmac_get_one_cpufreq(int i) -{ - /* Supports only one CPU for now */ - return (i == 0) ? cur_freq : 0; + ppc_proc_freq = cur_freq * 1000ul; + return rc; } static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy) @@ -474,6 +472,8 @@ static int pmac_cpufreq_resume(struct cpufreq_policy *policy) do_set_cpu_speed(sleep_freq == low_freq ? CPUFREQ_LOW : CPUFREQ_HIGH, 0); + ppc_proc_freq = cur_freq * 1000ul; + no_schedule = 0; return 0; } @@ -547,7 +547,7 @@ static int pmac_cpufreq_init_MacRISC3(struct device_node *cpunode) */ if (low_freq < 98000000) low_freq = 101000000; - + /* Convert those to CPU core clocks */ low_freq = (low_freq * (*ratio)) / 2000; hi_freq = (hi_freq * (*ratio)) / 2000; @@ -714,6 +714,7 @@ static int __init pmac_cpufreq_setup(void) pmac_cpu_freqs[CPUFREQ_LOW].frequency = low_freq; pmac_cpu_freqs[CPUFREQ_HIGH].frequency = hi_freq; + ppc_proc_freq = cur_freq * 1000ul; printk(KERN_INFO "Registering PowerMac CPU frequency driver\n"); printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Boot: %d Mhz\n", diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c new file mode 100644 index 0000000000000000000000000000000000000000..39150342c6f14bcef65074fb04891ebb275d9462 --- /dev/null +++ b/arch/powerpc/platforms/powermac/cpufreq_64.c @@ -0,0 +1,323 @@ +/* + * Copyright (C) 2002 - 2005 Benjamin Herrenschmidt + * and Markus Demleitner + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This driver adds basic cpufreq support for SMU & 970FX based G5 Macs, + * that is iMac G5 and latest single CPU desktop. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG + +#ifdef DEBUG +#define DBG(fmt...) printk(fmt) +#else +#define DBG(fmt...) +#endif + +/* see 970FX user manual */ + +#define SCOM_PCR 0x0aa001 /* PCR scom addr */ + +#define PCR_HILO_SELECT 0x80000000U /* 1 = PCR, 0 = PCRH */ +#define PCR_SPEED_FULL 0x00000000U /* 1:1 speed value */ +#define PCR_SPEED_HALF 0x00020000U /* 1:2 speed value */ +#define PCR_SPEED_QUARTER 0x00040000U /* 1:4 speed value */ +#define PCR_SPEED_MASK 0x000e0000U /* speed mask */ +#define PCR_SPEED_SHIFT 17 +#define PCR_FREQ_REQ_VALID 0x00010000U /* freq request valid */ +#define PCR_VOLT_REQ_VALID 0x00008000U /* volt request valid */ +#define PCR_TARGET_TIME_MASK 0x00006000U /* target time */ +#define PCR_STATLAT_MASK 0x00001f00U /* STATLAT value */ +#define PCR_SNOOPLAT_MASK 0x000000f0U /* SNOOPLAT value */ +#define PCR_SNOOPACC_MASK 0x0000000fU /* SNOOPACC value */ + +#define SCOM_PSR 0x408001 /* PSR scom addr */ +/* warning: PSR is a 64 bits register */ +#define PSR_CMD_RECEIVED 0x2000000000000000U /* command received */ +#define PSR_CMD_COMPLETED 0x1000000000000000U /* command completed */ +#define PSR_CUR_SPEED_MASK 0x0300000000000000U /* current speed */ +#define PSR_CUR_SPEED_SHIFT (56) + +/* + * The G5 only supports two frequencies (Quarter speed is not supported) + */ +#define CPUFREQ_HIGH 0 +#define CPUFREQ_LOW 1 + +static struct cpufreq_frequency_table g5_cpu_freqs[] = { + {CPUFREQ_HIGH, 0}, + {CPUFREQ_LOW, 0}, + {0, CPUFREQ_TABLE_END}, +}; + +static struct freq_attr* g5_cpu_freqs_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +/* Power mode data is an array of the 32 bits PCR values to use for + * the various frequencies, retreived from the device-tree + */ +static u32 *g5_pmode_data; +static int g5_pmode_max; +static int g5_pmode_cur; + +static DECLARE_MUTEX(g5_switch_mutex); + + +static struct smu_sdbp_fvt *g5_fvt_table; /* table of op. points */ +static int g5_fvt_count; /* number of op. points */ +static int g5_fvt_cur; /* current op. point */ + +/* ----------------- real hardware interface */ + +static void g5_switch_volt(int speed_mode) +{ + struct smu_simple_cmd cmd; + + DECLARE_COMPLETION(comp); + smu_queue_simple(&cmd, SMU_CMD_POWER_COMMAND, 8, smu_done_complete, + &comp, 'V', 'S', 'L', 'E', 'W', + 0xff, g5_fvt_cur+1, speed_mode); + wait_for_completion(&comp); +} + +static int g5_switch_freq(int speed_mode) +{ + struct cpufreq_freqs freqs; + int to; + + if (g5_pmode_cur == speed_mode) + return 0; + + down(&g5_switch_mutex); + + freqs.old = g5_cpu_freqs[g5_pmode_cur].frequency; + freqs.new = g5_cpu_freqs[speed_mode].frequency; + freqs.cpu = 0; + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + /* If frequency is going up, first ramp up the voltage */ + if (speed_mode < g5_pmode_cur) + g5_switch_volt(speed_mode); + + /* Clear PCR high */ + scom970_write(SCOM_PCR, 0); + /* Clear PCR low */ + scom970_write(SCOM_PCR, PCR_HILO_SELECT | 0); + /* Set PCR low */ + scom970_write(SCOM_PCR, PCR_HILO_SELECT | + g5_pmode_data[speed_mode]); + + /* Wait for completion */ + for (to = 0; to < 10; to++) { + unsigned long psr = scom970_read(SCOM_PSR); + + if ((psr & PSR_CMD_RECEIVED) == 0 && + (((psr >> PSR_CUR_SPEED_SHIFT) ^ + (g5_pmode_data[speed_mode] >> PCR_SPEED_SHIFT)) & 0x3) + == 0) + break; + if (psr & PSR_CMD_COMPLETED) + break; + udelay(100); + } + + /* If frequency is going down, last ramp the voltage */ + if (speed_mode > g5_pmode_cur) + g5_switch_volt(speed_mode); + + g5_pmode_cur = speed_mode; + ppc_proc_freq = g5_cpu_freqs[speed_mode].frequency * 1000ul; + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + up(&g5_switch_mutex); + + return 0; +} + +static int g5_query_freq(void) +{ + unsigned long psr = scom970_read(SCOM_PSR); + int i; + + for (i = 0; i <= g5_pmode_max; i++) + if ((((psr >> PSR_CUR_SPEED_SHIFT) ^ + (g5_pmode_data[i] >> PCR_SPEED_SHIFT)) & 0x3) == 0) + break; + return i; +} + +/* ----------------- cpufreq bookkeeping */ + +static int g5_cpufreq_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, g5_cpu_freqs); +} + +static int g5_cpufreq_target(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) +{ + unsigned int newstate = 0; + + if (cpufreq_frequency_table_target(policy, g5_cpu_freqs, + target_freq, relation, &newstate)) + return -EINVAL; + + return g5_switch_freq(newstate); +} + +static unsigned int g5_cpufreq_get_speed(unsigned int cpu) +{ + return g5_cpu_freqs[g5_pmode_cur].frequency; +} + +static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy) +{ + if (policy->cpu != 0) + return -ENODEV; + + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + policy->cur = g5_cpu_freqs[g5_query_freq()].frequency; + cpufreq_frequency_table_get_attr(g5_cpu_freqs, policy->cpu); + + return cpufreq_frequency_table_cpuinfo(policy, + g5_cpu_freqs); +} + + +static struct cpufreq_driver g5_cpufreq_driver = { + .name = "powermac", + .owner = THIS_MODULE, + .flags = CPUFREQ_CONST_LOOPS, + .init = g5_cpufreq_cpu_init, + .verify = g5_cpufreq_verify, + .target = g5_cpufreq_target, + .get = g5_cpufreq_get_speed, + .attr = g5_cpu_freqs_attr, +}; + + +static int __init g5_cpufreq_init(void) +{ + struct device_node *cpunode; + unsigned int psize, ssize; + struct smu_sdbp_header *shdr; + unsigned long max_freq; + u32 *valp; + int rc = -ENODEV; + + /* Look for CPU and SMU nodes */ + cpunode = of_find_node_by_type(NULL, "cpu"); + if (!cpunode) { + DBG("No CPU node !\n"); + return -ENODEV; + } + + /* Check 970FX for now */ + valp = (u32 *)get_property(cpunode, "cpu-version", NULL); + if (!valp) { + DBG("No cpu-version property !\n"); + goto bail_noprops; + } + if (((*valp) >> 16) != 0x3c) { + DBG("Wrong CPU version: %08x\n", *valp); + goto bail_noprops; + } + + /* Look for the powertune data in the device-tree */ + g5_pmode_data = (u32 *)get_property(cpunode, "power-mode-data",&psize); + if (!g5_pmode_data) { + DBG("No power-mode-data !\n"); + goto bail_noprops; + } + g5_pmode_max = psize / sizeof(u32) - 1; + + /* Look for the FVT table */ + shdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL); + if (!shdr) + goto bail_noprops; + g5_fvt_table = (struct smu_sdbp_fvt *)&shdr[1]; + ssize = (shdr->len * sizeof(u32)) - sizeof(struct smu_sdbp_header); + g5_fvt_count = ssize / sizeof(struct smu_sdbp_fvt); + g5_fvt_cur = 0; + + /* Sanity checking */ + if (g5_fvt_count < 1 || g5_pmode_max < 1) + goto bail_noprops; + + /* + * From what I see, clock-frequency is always the maximal frequency. + * The current driver can not slew sysclk yet, so we really only deal + * with powertune steps for now. We also only implement full freq and + * half freq in this version. So far, I haven't yet seen a machine + * supporting anything else. + */ + valp = (u32 *)get_property(cpunode, "clock-frequency", NULL); + if (!valp) + return -ENODEV; + max_freq = (*valp)/1000; + g5_cpu_freqs[0].frequency = max_freq; + g5_cpu_freqs[1].frequency = max_freq/2; + + /* Check current frequency */ + g5_pmode_cur = g5_query_freq(); + if (g5_pmode_cur > 1) + /* We don't support anything but 1:1 and 1:2, fixup ... */ + g5_pmode_cur = 1; + + /* Force apply current frequency to make sure everything is in + * sync (voltage is right for example). Firmware may leave us with + * a strange setting ... + */ + g5_switch_freq(g5_pmode_cur); + + printk(KERN_INFO "Registering G5 CPU frequency driver\n"); + printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n", + g5_cpu_freqs[1].frequency/1000, + g5_cpu_freqs[0].frequency/1000, + g5_cpu_freqs[g5_pmode_cur].frequency/1000); + + rc = cpufreq_register_driver(&g5_cpufreq_driver); + + /* We keep the CPU node on hold... hopefully, Apple G5 don't have + * hotplug CPU with a dynamic device-tree ... + */ + return rc; + + bail_noprops: + of_node_put(cpunode); + + return rc; +} + +module_init(g5_cpufreq_init); + + +MODULE_LICENSE("GPL"); diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 80b58c1ec4120d8b43de70f081d77c2955d56a11..7acb0546671fe2ea341c604573e541bd8d06cad9 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -193,18 +193,6 @@ static void pmac_show_cpuinfo(struct seq_file *m) pmac_newworld ? "NewWorld" : "OldWorld"); } -static void pmac_show_percpuinfo(struct seq_file *m, int i) -{ -#ifdef CONFIG_CPU_FREQ_PMAC - extern unsigned int pmac_get_one_cpufreq(int i); - unsigned int freq = pmac_get_one_cpufreq(i); - if (freq != 0) { - seq_printf(m, "clock\t\t: %dMHz\n", freq/1000); - return; - } -#endif /* CONFIG_CPU_FREQ_PMAC */ -} - #ifndef CONFIG_ADB_CUDA int find_via_cuda(void) { @@ -767,7 +755,6 @@ struct machdep_calls __initdata pmac_md = { .setup_arch = pmac_setup_arch, .init_early = pmac_init_early, .show_cpuinfo = pmac_show_cpuinfo, - .show_percpuinfo = pmac_show_percpuinfo, .init_IRQ = pmac_pic_init, .get_irq = mpic_get_irq, /* changed later */ .pcibios_fixup = pmac_pcibios_fixup, diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 513e2723149358c4ff06ed556c449ecc6248be2e..fcc50bfd43fd35d560175b89917bbc51d4c56cfb 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -47,6 +46,7 @@ #include #include #include +#include #include "plpar_wrappers.h" diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index ab0c6dd6ec94538beaab0c12e3b9254d224222fe..a50e5f3f396dc177da02deea3cbad714d01be4ce 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -31,13 +31,14 @@ #include #include #include -#include #include #include #include #include #include #include +#include +#include #include "plpar_wrappers.h" diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h index 382f8c5b0e7c0978892cf5f9a873ab9754477a25..3bd1b3e0600362237c410bbb7f008a67ddd68862 100644 --- a/arch/powerpc/platforms/pseries/plpar_wrappers.h +++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h @@ -107,14 +107,4 @@ static inline long plpar_put_term_char(unsigned long termno, unsigned long len, lbuf[1]); } -static inline long plpar_set_xdabr(unsigned long address, unsigned long flags) -{ - return plpar_hcall_norets(H_SET_XDABR, address, flags); -} - -static inline long plpar_set_dabr(unsigned long val) -{ - return plpar_hcall_norets(H_SET_DABR, val); -} - #endif /* _PSERIES_PLPAR_WRAPPERS_H */ diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index 6562ff4b0a8210375270b37b70307ae1a94068a1..fbd214d68b0717573ed443632bde26d055038345 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -48,7 +48,7 @@ #include #include #include -#include +#include static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX]; static DEFINE_SPINLOCK(ras_log_buf_lock); diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index 58c61219d08e0765646450c30cba107936db01ab..d7d400339458d2e5e159bd67633bc919e8b8eed6 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c @@ -286,10 +286,8 @@ static struct property *new_property(const char *name, const int length, return new; cleanup: - if (new->name) - kfree(new->name); - if (new->value) - kfree(new->value); + kfree(new->name); + kfree(new->value); kfree(new); return NULL; } diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 65bee939eeccce1d5e626f985eee080af08c9c63..e78c39368841ba39251f3f6f219a987f2206a926 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -65,6 +65,7 @@ #include #include #include +#include #include "plpar_wrappers.h" @@ -353,14 +354,15 @@ static void pSeries_mach_cpu_die(void) static int pseries_set_dabr(unsigned long dabr) { - if (firmware_has_feature(FW_FEATURE_XDABR)) { - /* We want to catch accesses from kernel and userspace */ - return plpar_set_xdabr(dabr, H_DABRX_KERNEL | H_DABRX_USER); - } - - return plpar_set_dabr(dabr); + return plpar_hcall_norets(H_SET_DABR, dabr); } +static int pseries_set_xdabr(unsigned long dabr) +{ + /* We want to catch accesses from kernel and userspace */ + return plpar_hcall_norets(H_SET_XDABR, dabr, + H_DABRX_KERNEL | H_DABRX_USER); +} /* * Early initialization. Relocation is on but do not reference unbolted pages @@ -396,8 +398,10 @@ static void __init pSeries_init_early(void) DBG("Hello World !\n"); } - if (firmware_has_feature(FW_FEATURE_XDABR | FW_FEATURE_DABR)) + if (firmware_has_feature(FW_FEATURE_DABR)) ppc_md.set_dabr = pseries_set_dabr; + else if (firmware_has_feature(FW_FEATURE_XDABR)) + ppc_md.set_dabr = pseries_set_xdabr; iommu_init_early_pSeries(); diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c index 90bce6e0c191827e6a91a6ae91d762eee4094633..b7ac32fdd7766f74ceff0d2098df4614eae83701 100644 --- a/arch/powerpc/sysdev/i8259.c +++ b/arch/powerpc/sysdev/i8259.c @@ -207,6 +207,9 @@ void __init i8259_init(unsigned long intack_addr, int offset) spin_unlock_irqrestore(&i8259_lock, flags); + for (i = 0; i < NUM_ISA_INTERRUPTS; ++i) + irq_desc[offset + i].handler = &i8259_pic; + /* reserve our resources */ setup_irq(offset + 2, &i8259_irqaction); request_resource(&ioport_resource, &pic1_iores); @@ -216,6 +219,4 @@ void __init i8259_init(unsigned long intack_addr, int offset) if (intack_addr != 0) pci_intack = ioremap(intack_addr, 1); - for (i = 0; i < NUM_ISA_INTERRUPTS; ++i) - irq_desc[offset + i].handler = &i8259_pic; } diff --git a/arch/powerpc/sysdev/u3_iommu.c b/arch/powerpc/sysdev/u3_iommu.c index 607722178c1a6695616c528c0511e8f22e23d41f..543d6590981248ff1ebdff05822c36aaeefe9ca0 100644 --- a/arch/powerpc/sysdev/u3_iommu.c +++ b/arch/powerpc/sysdev/u3_iommu.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/ppc/4xx_io/serial_sicc.c b/arch/ppc/4xx_io/serial_sicc.c index e95c48d57571d7a3af2d6f91acab38de6d231d44..84d96b857e4af93fdf6055f59ad177f1d6047ae9 100644 --- a/arch/ppc/4xx_io/serial_sicc.c +++ b/arch/ppc/4xx_io/serial_sicc.c @@ -1145,8 +1145,8 @@ static int set_serial_info(struct SICC_info *info, info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) | (info->flags & ASYNC_INTERNAL_FLAGS)); state->custom_divisor = new_serial.custom_divisor; - state->close_delay = new_serial.close_delay * HZ / 100; - state->closing_wait = new_serial.closing_wait * HZ / 100; + state->close_delay = msecs_to_jiffies(10 * new_serial.close_delay); + state->closing_wait = msecs_to_jiffies(10 * new_serial.closing_wait); info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; port->fifosize = new_serial.xmit_fifo_size; @@ -1465,10 +1465,8 @@ static void siccuart_close(struct tty_struct *tty, struct file *filp) info->event = 0; info->tty = NULL; if (info->blocked_open) { - if (info->state->close_delay) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(info->state->close_delay); - } + if (info->state->close_delay) + schedule_timeout_interruptible(info->state->close_delay); wake_up_interruptible(&info->open_wait); } info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); @@ -1496,7 +1494,7 @@ static void siccuart_wait_until_sent(struct tty_struct *tty, int timeout) * Note: we have to use pretty tight timings here to satisfy * the NIST-PCTS. */ - char_time = (info->timeout - HZ/50) / info->port->fifosize; + char_time = (info->timeout - msecs_to_jiffies(20)) / info->port->fifosize; char_time = char_time / 5; if (char_time == 0) char_time = 1; @@ -1521,8 +1519,7 @@ static void siccuart_wait_until_sent(struct tty_struct *tty, int timeout) tty->index, jiffies, expire, char_time); while ((readb(info->port->uart_base + BL_SICC_LSR) & _LSR_TX_ALL) != _LSR_TX_ALL) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(char_time); + schedule_timeout_interruptible(char_time); if (signal_pending(current)) break; if (timeout && time_after(jiffies, expire)) @@ -1773,7 +1770,7 @@ int __init siccuart_init(void) for (i = 0; i < SERIAL_SICC_NR; i++) { struct SICC_state *state = sicc_state + i; state->line = i; - state->close_delay = 5 * HZ / 10; + state->close_delay = msecs_to_jiffies(500); state->closing_wait = 30 * HZ; spin_lock_init(&state->sicc_lock); } diff --git a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c index 2086c6ad11475f167438a2b18166429c1e647488..4edeede9ccfdbc4c2636cf5b83b672ee182629e0 100644 --- a/arch/ppc/8260_io/fcc_enet.c +++ b/arch/ppc/8260_io/fcc_enet.c @@ -1309,8 +1309,7 @@ static void mii_dm9161_wait(uint mii_reg, struct net_device *dev) /* Davicom takes a bit to come up after a reset, * so wait here for a bit */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(timeout); + schedule_timeout_uninterruptible(timeout); } static phy_info_t phy_info_dm9161 = { diff --git a/arch/ppc/8xx_io/cs4218_tdm.c b/arch/ppc/8xx_io/cs4218_tdm.c index 532caa388dc258b9a90407d96a0a978c71854f9b..49eb2a7e65c0711a8ee2585b0ec2221210796c5a 100644 --- a/arch/ppc/8xx_io/cs4218_tdm.c +++ b/arch/ppc/8xx_io/cs4218_tdm.c @@ -1013,8 +1013,7 @@ static void CS_IrqCleanup(void) */ cpm_free_handler(CPMVEC_SMC2); - if (beep_buf) - kfree(beep_buf); + kfree(beep_buf); kd_mksound = orig_mksound; } #endif /* MODULE */ diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index 114b90fdea240cab6d7cf7eeeb1b8adea51a7823..8fa51b0a32d2d5390450d6478117ec1e7410a804 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -746,6 +746,16 @@ config MPC834x bool default y if MPC834x_SYS +config CPM1 + bool + depends on 8xx + default y + help + The CPM1 (Communications Processor Module) is a coprocessor on + embedded CPUs made by Motorola. Selecting this option means that + you wish to build a kernel for a machine with a CPM1 coprocessor + on it (8xx, 827x, 8560). + config CPM2 bool depends on 8260 || MPC8560 || MPC8555 @@ -1247,6 +1257,14 @@ source "drivers/pci/Kconfig" source "drivers/pcmcia/Kconfig" +config RAPIDIO + bool "RapidIO support" if MPC8540 || MPC8560 + help + If you say Y here, the kernel will include drivers and + infrastructure code to support RapidIO interconnect devices. + +source "drivers/rapidio/Kconfig" + endmenu menu "Advanced setup" diff --git a/arch/ppc/boot/simple/Makefile b/arch/ppc/boot/simple/Makefile index b7bd8f61a4adaab4afb1fd4a5bda99693bfcbc55..82df88b01bbe5a7e4c9c6679328674e5f418628e 100644 --- a/arch/ppc/boot/simple/Makefile +++ b/arch/ppc/boot/simple/Makefile @@ -67,6 +67,12 @@ zimageinitrd-$(CONFIG_BAMBOO) := zImage.initrd-TREE entrypoint-$(CONFIG_BAMBOO) := 0x01000000 extra.o-$(CONFIG_BAMBOO) := pibs.o + zimage-$(CONFIG_BUBINGA) := zImage-TREE +zimageinitrd-$(CONFIG_BUBINGA) := zImage.initrd-TREE + end-$(CONFIG_BUBINGA) := bubinga + entrypoint-$(CONFIG_BUBINGA) := 0x01000000 + extra.o-$(CONFIG_BUBINGA) := openbios.o + zimage-$(CONFIG_EBONY) := zImage-TREE zimageinitrd-$(CONFIG_EBONY) := zImage.initrd-TREE end-$(CONFIG_EBONY) := ebony @@ -79,12 +85,30 @@ zimageinitrd-$(CONFIG_LUAN) := zImage.initrd-TREE entrypoint-$(CONFIG_LUAN) := 0x01000000 extra.o-$(CONFIG_LUAN) := pibs.o + zimage-$(CONFIG_YUCCA) := zImage-TREE +zimageinitrd-$(CONFIG_YUCCA) := zImage.initrd-TREE + end-$(CONFIG_YUCCA) := yucca + entrypoint-$(CONFIG_YUCCA) := 0x01000000 + extra.o-$(CONFIG_YUCCA) := pibs.o + zimage-$(CONFIG_OCOTEA) := zImage-TREE zimageinitrd-$(CONFIG_OCOTEA) := zImage.initrd-TREE end-$(CONFIG_OCOTEA) := ocotea entrypoint-$(CONFIG_OCOTEA) := 0x01000000 extra.o-$(CONFIG_OCOTEA) := pibs.o + zimage-$(CONFIG_SYCAMORE) := zImage-TREE +zimageinitrd-$(CONFIG_SYCAMORE) := zImage.initrd-TREE + end-$(CONFIG_SYCAMORE) := sycamore + entrypoint-$(CONFIG_SYCAMORE) := 0x01000000 + extra.o-$(CONFIG_SYCAMORE) := openbios.o + + zimage-$(CONFIG_WALNUT) := zImage-TREE +zimageinitrd-$(CONFIG_WALNUT) := zImage.initrd-TREE + end-$(CONFIG_WALNUT) := walnut + entrypoint-$(CONFIG_WALNUT) := 0x01000000 + extra.o-$(CONFIG_WALNUT) := openbios.o + extra.o-$(CONFIG_EV64260) := misc-ev64260.o end-$(CONFIG_EV64260) := ev64260 cacheflag-$(CONFIG_EV64260) := -include $(clear_L2_L3) @@ -162,7 +186,8 @@ OBJCOPY_ARGS := -O elf32-powerpc # head.o and relocate.o must be at the start. boot-y := head.o relocate.o $(extra.o-y) $(misc-y) -boot-$(CONFIG_40x) += embed_config.o +boot-$(CONFIG_REDWOOD_5) += embed_config.o +boot-$(CONFIG_REDWOOD_6) += embed_config.o boot-$(CONFIG_8xx) += embed_config.o boot-$(CONFIG_8260) += embed_config.o boot-$(CONFIG_BSEIP) += iic.o diff --git a/arch/ppc/boot/simple/misc.c b/arch/ppc/boot/simple/misc.c index e02de5b467a45ff9e278f59350bdbdd1c020d5b0..f415d6c62362ca84acece2c98ee6d99154fac9f2 100644 --- a/arch/ppc/boot/simple/misc.c +++ b/arch/ppc/boot/simple/misc.c @@ -23,7 +23,7 @@ #include #include #include -#ifdef CONFIG_44x +#ifdef CONFIG_4xx #include #endif #include @@ -88,6 +88,14 @@ get_mem_size(void) return 0; } +#if defined(CONFIG_40x) +#define PPC4xx_EMAC0_MR0 EMAC0_BASE +#endif + +#if defined(CONFIG_44x) && defined(PPC44x_EMAC0_MR0) +#define PPC4xx_EMAC0_MR0 PPC44x_EMAC0_MR0 +#endif + struct bi_record * decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum) { @@ -103,13 +111,13 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum) com_port = serial_init(0, NULL); #endif -#if defined(CONFIG_44x) && defined(PPC44x_EMAC0_MR0) +#if defined(PPC4xx_EMAC0_MR0) /* Reset MAL */ mtdcr(DCRN_MALCR(DCRN_MAL_BASE), MALCR_MMSR); /* Wait for reset */ while (mfdcr(DCRN_MALCR(DCRN_MAL_BASE)) & MALCR_MMSR) {}; /* Reset EMAC */ - *(volatile unsigned long *)PPC44x_EMAC0_MR0 = 0x20000000; + *(volatile unsigned long *)PPC4xx_EMAC0_MR0 = 0x20000000; __asm__ __volatile__("eieio"); #endif @@ -164,7 +172,9 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum) puts(" "); puthex((unsigned long)(&__ramdisk_end));puts("\n"); } +#ifndef CONFIG_40x /* don't overwrite the 40x image located at 0x00400000! */ avail_ram = (char *)0x00400000; +#endif end_avail = (char *)0x00800000; puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" "); puthex((unsigned long)end_avail); puts("\n"); diff --git a/arch/ppc/boot/simple/openbios.c b/arch/ppc/boot/simple/openbios.c index c732b6d70cfbe91b039bee39c93d63537b1874b3..81f11d8b30a7ad80a426e348dc86715311bd70f3 100644 --- a/arch/ppc/boot/simple/openbios.c +++ b/arch/ppc/boot/simple/openbios.c @@ -1,19 +1,43 @@ /* * arch/ppc/boot/simple/openbios.c * - * 2005 (c) SYSGO AG - g.jaeger@sysgo.com + * Copyright (c) 2005 DENX Software Engineering + * Stefan Roese + * + * Based on original work by + * 2005 (c) SYSGO AG - g.jaeger@sysgo.com + * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without * any warranty of any kind, whether express or implied. * - * Derived from arch/ppc/boot/simple/pibs.c (from MontaVista) */ #include #include #include #include -#include +#include +#include +#ifdef CONFIG_40x +#include +#endif + +#if defined(CONFIG_BUBINGA) +#define BOARD_INFO_VECTOR 0xFFF80B50 /* openbios 1.19 moved this vector down - armin */ +#else +#define BOARD_INFO_VECTOR 0xFFFE0B50 +#endif + +#ifdef CONFIG_40x +/* Supply a default Ethernet address for those eval boards that don't + * ship with one. This is an address from the MBX board I have, so + * it is unlikely you will find it on your network. + */ +static ushort def_enet_addr[] = { 0x0800, 0x3e26, 0x1559 }; + +extern unsigned long timebase_period_ns; +#endif /* CONFIG_40x */ extern unsigned long decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum); @@ -23,15 +47,85 @@ extern unsigned long decompress_kernel(unsigned long load_addr, int num_words, bd_t hold_resid_buf __attribute__ ((__section__ (".data.boot"))); bd_t *hold_residual = &hold_resid_buf; +typedef struct openbios_board_info { + unsigned char bi_s_version[4]; /* Version of this structure */ + unsigned char bi_r_version[30]; /* Version of the IBM ROM */ + unsigned int bi_memsize; /* DRAM installed, in bytes */ +#ifdef CONFIG_405EP + unsigned char bi_enetaddr[2][6]; /* Local Ethernet MAC address */ +#else /* CONFIG_405EP */ + unsigned char bi_enetaddr[6]; /* Local Ethernet MAC address */ +#endif /* CONFIG_405EP */ + unsigned char bi_pci_enetaddr[6]; /* PCI Ethernet MAC address */ + unsigned int bi_intfreq; /* Processor speed, in Hz */ + unsigned int bi_busfreq; /* PLB Bus speed, in Hz */ + unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */ +#ifdef CONFIG_405EP + unsigned int bi_opb_busfreq; /* OPB Bus speed, in Hz */ + unsigned int bi_pllouta_freq; /* PLL OUTA speed, in Hz */ +#endif /* CONFIG_405EP */ +} openbios_bd_t; + void * load_kernel(unsigned long load_addr, int num_words, unsigned long cksum, void *ign1, void *ign2) { - decompress_kernel(load_addr, num_words, cksum); +#ifdef CONFIG_40x + openbios_bd_t *openbios_bd = NULL; + openbios_bd_t *(*get_board_info)(void) = + (openbios_bd_t *(*)(void))(*(unsigned long *)BOARD_INFO_VECTOR); + + /* + * On 40x platforms we not only need the MAC-addresses, but also the + * clocks and memsize. Now try to get all values using the OpenBIOS + * "get_board_info()" callback. + */ + if ((openbios_bd = get_board_info()) != NULL) { + /* + * Copy bd_info from OpenBIOS struct into U-Boot struct + * used by kernel + */ + hold_residual->bi_memsize = openbios_bd->bi_memsize; + hold_residual->bi_intfreq = openbios_bd->bi_intfreq; + hold_residual->bi_busfreq = openbios_bd->bi_busfreq; + hold_residual->bi_pci_busfreq = openbios_bd->bi_pci_busfreq; + memcpy(hold_residual->bi_pci_enetaddr, openbios_bd->bi_pci_enetaddr, 6); +#ifdef CONFIG_405EP + memcpy(hold_residual->bi_enetaddr, openbios_bd->bi_enetaddr[0], 6); + memcpy(hold_residual->bi_enet1addr, openbios_bd->bi_enetaddr[1], 6); + hold_residual->bi_opbfreq = openbios_bd->bi_opb_busfreq; + hold_residual->bi_procfreq = openbios_bd->bi_pllouta_freq; +#else /* CONFIG_405EP */ + memcpy(hold_residual->bi_enetaddr, openbios_bd->bi_enetaddr, 6); +#endif /* CONFIG_405EP */ + } else { + /* Hmmm...better try to stuff some defaults. + */ + hold_residual->bi_memsize = 16 * 1024 * 1024; + hold_residual->bi_intfreq = 200000000; + hold_residual->bi_busfreq = 100000000; + hold_residual->bi_pci_busfreq = 66666666; + + /* + * Only supply one mac-address in this fallback + */ + memcpy(hold_residual->bi_enetaddr, (void *)def_enet_addr, 6); +#ifdef CONFIG_405EP + hold_residual->bi_opbfreq = 50000000; + hold_residual->bi_procfreq = 200000000; +#endif /* CONFIG_405EP */ + } + timebase_period_ns = 1000000000 / hold_residual->bi_intfreq; +#endif /* CONFIG_40x */ + +#ifdef CONFIG_440GP /* simply copy the MAC addresses */ - memcpy(hold_residual->bi_enetaddr, (char *)EBONY_OPENBIOS_MAC_BASE, 6); - memcpy(hold_residual->bi_enet1addr, (char *)(EBONY_OPENBIOS_MAC_BASE+EBONY_OPENBIOS_MAC_OFFSET), 6); + memcpy(hold_residual->bi_enetaddr, (char *)OPENBIOS_MAC_BASE, 6); + memcpy(hold_residual->bi_enet1addr, (char *)(OPENBIOS_MAC_BASE+OPENBIOS_MAC_OFFSET), 6); +#endif /* CONFIG_440GP */ + + decompress_kernel(load_addr, num_words, cksum); return (void *)hold_residual; } diff --git a/arch/ppc/configs/ev64360_defconfig b/arch/ppc/configs/ev64360_defconfig index de9bbb791db98f3abac6706fd938f7b3a17d25ae..d471e578dcb58b0664acdf2765531da42c8b8a4b 100644 --- a/arch/ppc/configs/ev64360_defconfig +++ b/arch/ppc/configs/ev64360_defconfig @@ -1,17 +1,17 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.13-rc5 -# Fri Aug 5 15:18:23 2005 +# Linux kernel version: 2.6.14 +# Fri Oct 28 19:15:34 2005 # CONFIG_MMU=y CONFIG_GENERIC_HARDIRQS=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_HAVE_DEC_LOCK=y CONFIG_PPC=y CONFIG_PPC32=y CONFIG_GENERIC_NVRAM=y CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y # # Code maturity level options @@ -26,6 +26,7 @@ CONFIG_INIT_ENV_ARG_LIMIT=32 # General setup # CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y @@ -35,6 +36,7 @@ CONFIG_SYSCTL=y CONFIG_HOTPLUG=y CONFIG_KOBJECT_UEVENT=y # CONFIG_IKCONFIG is not set +CONFIG_INITRAMFS_SOURCE="" # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_EXTRA_PASS is not set @@ -74,7 +76,7 @@ CONFIG_TAU=y # CONFIG_TAU_AVERAGE is not set # CONFIG_KEXEC is not set # CONFIG_CPU_FREQ is not set -# CONFIG_PM is not set +# CONFIG_WANT_EARLY_SERIAL is not set CONFIG_PPC_STD_MMU=y CONFIG_NOT_COHERENT_CACHE=y @@ -86,22 +88,18 @@ CONFIG_NOT_COHERENT_CACHE=y # CONFIG_KATANA is not set # CONFIG_WILLOW is not set # CONFIG_CPCI690 is not set -# CONFIG_PCORE is not set # CONFIG_POWERPMC250 is not set # CONFIG_CHESTNUT is not set # CONFIG_SPRUCE is not set # CONFIG_HDPU is not set # CONFIG_EV64260 is not set # CONFIG_LOPEC is not set -# CONFIG_MCPN765 is not set # CONFIG_MVME5100 is not set # CONFIG_PPLUS is not set # CONFIG_PRPMC750 is not set # CONFIG_PRPMC800 is not set # CONFIG_SANDPOINT is not set # CONFIG_RADSTONE_PPC7D is not set -# CONFIG_ADIR is not set -# CONFIG_K2 is not set # CONFIG_PAL4 is not set # CONFIG_GEMINI is not set # CONFIG_EST8260 is not set @@ -138,10 +136,13 @@ CONFIG_FLATMEM_MANUAL=y # CONFIG_SPARSEMEM_MANUAL is not set CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=y CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="console=ttyMM0,115200 root=/dev/mtdblock1 rw rootfstype=jffs2" +# CONFIG_PM is not set +# CONFIG_SOFTWARE_SUSPEND is not set CONFIG_SECCOMP=y CONFIG_ISA_DMA_API=y @@ -152,7 +153,6 @@ CONFIG_GENERIC_ISA_DMA=y CONFIG_PCI=y CONFIG_PCI_DOMAINS=y # CONFIG_PCI_LEGACY_PROC is not set -# CONFIG_PCI_NAMES is not set # # PCCARD (PCMCIA/CardBus) support @@ -206,13 +206,18 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set # CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_BIC=y # CONFIG_IPV6 is not set # CONFIG_NETFILTER is not set +# +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + # # SCTP Configuration (EXPERIMENTAL) # @@ -239,6 +244,7 @@ CONFIG_TCP_CONG_BIC=y # CONFIG_HAMRADIO is not set # CONFIG_IRDA is not set # CONFIG_BT is not set +# CONFIG_IEEE80211 is not set # # Device Drivers @@ -251,6 +257,11 @@ CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_FW_LOADER is not set +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + # # Memory Technology Devices (MTD) # @@ -358,7 +369,6 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=32768 CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" # CONFIG_LBD is not set # CONFIG_CDROM_PKTCDVD is not set @@ -379,6 +389,7 @@ CONFIG_IOSCHED_CFQ=y # # SCSI device support # +# CONFIG_RAID_ATTRS is not set # CONFIG_SCSI is not set # @@ -419,6 +430,10 @@ CONFIG_NETDEVICES=y # # CONFIG_ARCNET is not set +# +# PHY device support +# + # # Ethernet (10 or 100Mbit) # @@ -434,6 +449,7 @@ CONFIG_NETDEVICES=y # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set # CONFIG_R8169 is not set +# CONFIG_SIS190 is not set # CONFIG_SKGE is not set # CONFIG_SK98LIN is not set # CONFIG_TIGON3 is not set @@ -446,6 +462,7 @@ CONFIG_MV643XX_ETH_0=y # # Ethernet (10000 Mbit) # +# CONFIG_CHELSIO_T1 is not set # CONFIG_IXGB is not set # CONFIG_S2IO is not set @@ -547,7 +564,20 @@ CONFIG_LEGACY_PTY_COUNT=256 # # Watchdog Cards # -# CONFIG_WATCHDOG is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_MV64X60_WDT=y + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set # CONFIG_NVRAM is not set CONFIG_GEN_RTC=y # CONFIG_GEN_RTC_X is not set @@ -571,7 +601,6 @@ CONFIG_GEN_RTC=y # I2C support # # CONFIG_I2C is not set -# CONFIG_I2C_SENSOR is not set # # Dallas's 1-wire bus @@ -582,12 +611,17 @@ CONFIG_GEN_RTC=y # Hardware Monitoring support # CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set # CONFIG_HWMON_DEBUG_CHIP is not set # # Misc devices # +# +# Multimedia Capabilities Port drivers +# + # # Multimedia devices # @@ -651,10 +685,6 @@ CONFIG_EXT2_FS=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set # CONFIG_FS_POSIX_ACL is not set - -# -# XFS support -# # CONFIG_XFS_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set @@ -663,6 +693,7 @@ CONFIG_INOTIFY=y CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set # # CD-ROM/DVD Filesystems @@ -683,11 +714,10 @@ CONFIG_DNOTIFY=y CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y CONFIG_SYSFS=y -# CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y -# CONFIG_TMPFS_XATTR is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set # # Miscellaneous filesystems @@ -735,6 +765,7 @@ CONFIG_SUNRPC=y # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set +# CONFIG_9P_FS is not set # # Partition Types @@ -751,6 +782,7 @@ CONFIG_MSDOS_PARTITION=y # Library routines # # CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=y @@ -767,6 +799,7 @@ CONFIG_ZLIB_DEFLATE=y # CONFIG_PRINTK_TIME is not set # CONFIG_DEBUG_KERNEL is not set CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_SERIAL_TEXT_DEBUG is not set # # Security options diff --git a/arch/ppc/configs/stx_gp3_defconfig b/arch/ppc/configs/stx_gp3_defconfig index 66dae8367659f7df98e962d547352e92a9de3d8e..3fedc43e44ad110f3060ffe2e0b4a9e966489dd7 100644 --- a/arch/ppc/configs/stx_gp3_defconfig +++ b/arch/ppc/configs/stx_gp3_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.11-rc2 -# Wed Jan 26 14:32:58 2005 +# Linux kernel version: 2.6.12-rc4 +# Tue May 24 18:11:04 2005 # CONFIG_MMU=y CONFIG_GENERIC_HARDIRQS=y @@ -11,6 +11,7 @@ CONFIG_HAVE_DEC_LOCK=y CONFIG_PPC=y CONFIG_PPC32=y CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y # # Code maturity level options @@ -18,6 +19,7 @@ CONFIG_GENERIC_NVRAM=y CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup @@ -29,7 +31,6 @@ CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_LOG_BUF_SHIFT=14 CONFIG_HOTPLUG=y CONFIG_KOBJECT_UEVENT=y # CONFIG_IKCONFIG is not set @@ -37,6 +38,9 @@ CONFIG_EMBEDDED=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set @@ -46,6 +50,7 @@ CONFIG_CC_ALIGN_LABELS=0 CONFIG_CC_ALIGN_LOOPS=0 CONFIG_CC_ALIGN_JUMPS=0 # CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 # # Loadable module support @@ -69,9 +74,11 @@ CONFIG_KMOD=y CONFIG_E500=y CONFIG_BOOKE=y CONFIG_FSL_BOOKE=y +# CONFIG_PHYS_64BIT is not set # CONFIG_SPE is not set CONFIG_MATH_EMULATION=y # CONFIG_CPU_FREQ is not set +# CONFIG_PM is not set CONFIG_85xx=y CONFIG_PPC_INDIRECT_PCI_BE=y @@ -96,6 +103,7 @@ CONFIG_HIGHMEM=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=m # CONFIG_CMDLINE_BOOL is not set +CONFIG_ISA_DMA_API=y # # Bus options @@ -104,15 +112,15 @@ CONFIG_PCI=y CONFIG_PCI_DOMAINS=y # CONFIG_PCI_LEGACY_PROC is not set # CONFIG_PCI_NAMES is not set +# CONFIG_PCI_DEBUG is not set # # PCCARD (PCMCIA/CardBus) support # # CONFIG_PCCARD is not set - -# -# PC-card bridges -# +CONFIG_RAPIDIO=y +CONFIG_RAPIDIO_8_BIT_TRANSPORT=y +CONFIG_RAPIDIO_DISC_TIMEOUT=30 # # Advanced setup @@ -152,7 +160,7 @@ CONFIG_PARPORT=m CONFIG_PARPORT_PC=m # CONFIG_PARPORT_PC_FIFO is not set # CONFIG_PARPORT_PC_SUPERIO is not set -# CONFIG_PARPORT_OTHER is not set +# CONFIG_PARPORT_GSC is not set # CONFIG_PARPORT_1284 is not set # @@ -264,7 +272,6 @@ CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_DMX3191D is not set # CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_IPS is not set @@ -274,7 +281,6 @@ CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_IMM is not set # CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_IPR is not set -# CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_QLOGIC_1280 is not set CONFIG_SCSI_QLA2XXX=m @@ -283,6 +289,7 @@ CONFIG_SCSI_QLA2XXX=m # CONFIG_SCSI_QLA2300 is not set # CONFIG_SCSI_QLA2322 is not set # CONFIG_SCSI_QLA6312 is not set +# CONFIG_SCSI_LPFC is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_NSP32 is not set @@ -322,7 +329,6 @@ CONFIG_NET=y # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK_DEV is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y @@ -431,7 +437,7 @@ CONFIG_IP_NF_NAT_FTP=m # # Network testing # -# CONFIG_NET_PKTGEN is not set +CONFIG_NET_PKTGEN=y # CONFIG_NETPOLL is not set # CONFIG_NET_POLL_CONTROLLER is not set # CONFIG_HAMRADIO is not set @@ -499,6 +505,7 @@ CONFIG_GFAR_NAPI=y # Wan interfaces # # CONFIG_WAN is not set +CONFIG_RIONET=y # CONFIG_FDDI is not set # CONFIG_HIPPI is not set # CONFIG_PLIP is not set @@ -535,20 +542,6 @@ CONFIG_INPUT_JOYDEV=m CONFIG_INPUT_EVDEV=m # CONFIG_INPUT_EVBUG is not set -# -# Input I/O drivers -# -# CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y -CONFIG_SERIO=y -CONFIG_SERIO_I8042=y -CONFIG_SERIO_SERPORT=y -# CONFIG_SERIO_CT82C710 is not set -# CONFIG_SERIO_PARKBD is not set -# CONFIG_SERIO_PCIPS2 is not set -CONFIG_SERIO_LIBPS2=y -# CONFIG_SERIO_RAW is not set - # # Input Device Drivers # @@ -566,6 +559,19 @@ CONFIG_MOUSE_PS2=y # CONFIG_INPUT_TOUCHSCREEN is not set # CONFIG_INPUT_MISC is not set +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y + # # Character devices # @@ -590,6 +596,7 @@ CONFIG_SERIAL_CPM_SCC2=y # CONFIG_SERIAL_CPM_SCC4 is not set # CONFIG_SERIAL_CPM_SMC1 is not set # CONFIG_SERIAL_CPM_SMC2 is not set +# CONFIG_SERIAL_JSM is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -625,6 +632,11 @@ CONFIG_DRM=m # CONFIG_DRM_SIS is not set # CONFIG_RAW_DRIVER is not set +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + # # I2C support # @@ -648,12 +660,12 @@ CONFIG_I2C_ALGOBIT=m # CONFIG_I2C_AMD8111 is not set # CONFIG_I2C_I801 is not set # CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_ISA is not set # CONFIG_I2C_MPC is not set # CONFIG_I2C_NFORCE2 is not set # CONFIG_I2C_PARPORT is not set # CONFIG_I2C_PARPORT_LIGHT is not set -# CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_PROSAVAGE is not set # CONFIG_I2C_SAVAGE4 is not set # CONFIG_SCx200_ACB is not set @@ -677,7 +689,9 @@ CONFIG_I2C_ALGOBIT=m # CONFIG_SENSORS_ASB100 is not set # CONFIG_SENSORS_DS1621 is not set # CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_FSCPOS is not set # CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set # CONFIG_SENSORS_IT87 is not set # CONFIG_SENSORS_LM63 is not set # CONFIG_SENSORS_LM75 is not set @@ -688,9 +702,11 @@ CONFIG_I2C_ALGOBIT=m # CONFIG_SENSORS_LM85 is not set # CONFIG_SENSORS_LM87 is not set # CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_MAX1619 is not set # CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SIS5595 is not set # CONFIG_SENSORS_SMSC47M1 is not set # CONFIG_SENSORS_VIA686A is not set # CONFIG_SENSORS_W83781D is not set @@ -700,10 +716,12 @@ CONFIG_I2C_ALGOBIT=m # # Other I2C Chip support # +# CONFIG_SENSORS_DS1337 is not set # CONFIG_SENSORS_EEPROM is not set # CONFIG_SENSORS_PCF8574 is not set # CONFIG_SENSORS_PCF8591 is not set # CONFIG_SENSORS_RTC8564 is not set +# CONFIG_SENSORS_M41T00 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set @@ -732,7 +750,6 @@ CONFIG_I2C_ALGOBIT=m # Graphics support # # CONFIG_FB is not set -# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound @@ -752,13 +769,9 @@ CONFIG_SOUND=m # # USB support # -# CONFIG_USB is not set CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB_ARCH_HAS_OHCI=y - -# -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information -# +# CONFIG_USB is not set # # USB Gadget Support @@ -789,6 +802,10 @@ CONFIG_JBD_DEBUG=y CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set + +# +# XFS support +# # CONFIG_XFS_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set @@ -859,7 +876,6 @@ CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y -# CONFIG_EXPORTFS is not set CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set @@ -942,8 +958,10 @@ CONFIG_ZLIB_INFLATE=m # # Kernel hacking # +# CONFIG_PRINTK_TIME is not set CONFIG_DEBUG_KERNEL=y # CONFIG_MAGIC_SYSRQ is not set +CONFIG_LOG_BUF_SHIFT=14 # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set # CONFIG_DEBUG_SPINLOCK is not set diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index c610ca933a252b125babeb5aa3e93b60dd8c675b..76a55a438f2383cc2c72294b078356c88078b9f9 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_POWER4) += cpu_setup_power4.o obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-mapping.o obj-$(CONFIG_PCI) += pci.o +obj-$(CONFIG_RAPIDIO) += rio.o obj-$(CONFIG_KGDB) += ppc-stub.o obj-$(CONFIG_SMP) += smp.o smp-tbsync.o obj-$(CONFIG_TAU) += temp.o diff --git a/arch/ppc/kernel/head_44x.S b/arch/ppc/kernel/head_44x.S index 8b49679fad549f7810a597f34857576d98d82bca..677c571aa276385427153d099451de14db4488ee 100644 --- a/arch/ppc/kernel/head_44x.S +++ b/arch/ppc/kernel/head_44x.S @@ -190,8 +190,8 @@ skpinv: addi r4,r4,1 /* Increment */ /* xlat fields */ lis r4,UART0_PHYS_IO_BASE@h /* RPN depends on SoC */ -#ifndef CONFIG_440EP - ori r4,r4,0x0001 /* ERPN is 1 for second 4GB page */ +#ifdef UART0_PHYS_ERPN + ori r4,r4,UART0_PHYS_ERPN /* Add ERPN if above 4GB */ #endif /* attrib fields */ diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index 3056ede2424d6be4f261674a2635484f813ec1ae..ae6af29938a1efc96513a6b8f33d25667d248f4f 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -25,6 +25,11 @@ #include #include +#ifdef CONFIG_8xx +#define ISYNC_8xx isync +#else +#define ISYNC_8xx +#endif .text .align 5 @@ -800,8 +805,18 @@ _GLOBAL(_insb) subi r4,r4,1 blelr- 00: lbz r5,0(r3) - eieio - stbu r5,1(r4) +01: eieio +02: stbu r5,1(r4) + ISYNC_8xx + .section .fixup,"ax" +03: blr + .text + .section __ex_table, "a" + .align 2 + .long 00b, 03b + .long 01b, 03b + .long 02b, 03b + .text bdnz 00b blr @@ -811,8 +826,18 @@ _GLOBAL(_outsb) subi r4,r4,1 blelr- 00: lbzu r5,1(r4) - stb r5,0(r3) - eieio +01: stb r5,0(r3) +02: eieio + ISYNC_8xx + .section .fixup,"ax" +03: blr + .text + .section __ex_table, "a" + .align 2 + .long 00b, 03b + .long 01b, 03b + .long 02b, 03b + .text bdnz 00b blr @@ -822,8 +847,18 @@ _GLOBAL(_insw) subi r4,r4,2 blelr- 00: lhbrx r5,0,r3 - eieio - sthu r5,2(r4) +01: eieio +02: sthu r5,2(r4) + ISYNC_8xx + .section .fixup,"ax" +03: blr + .text + .section __ex_table, "a" + .align 2 + .long 00b, 03b + .long 01b, 03b + .long 02b, 03b + .text bdnz 00b blr @@ -833,8 +868,18 @@ _GLOBAL(_outsw) subi r4,r4,2 blelr- 00: lhzu r5,2(r4) - eieio - sthbrx r5,0,r3 +01: eieio +02: sthbrx r5,0,r3 + ISYNC_8xx + .section .fixup,"ax" +03: blr + .text + .section __ex_table, "a" + .align 2 + .long 00b, 03b + .long 01b, 03b + .long 02b, 03b + .text bdnz 00b blr @@ -844,8 +889,18 @@ _GLOBAL(_insl) subi r4,r4,4 blelr- 00: lwbrx r5,0,r3 - eieio - stwu r5,4(r4) +01: eieio +02: stwu r5,4(r4) + ISYNC_8xx + .section .fixup,"ax" +03: blr + .text + .section __ex_table, "a" + .align 2 + .long 00b, 03b + .long 01b, 03b + .long 02b, 03b + .text bdnz 00b blr @@ -855,8 +910,18 @@ _GLOBAL(_outsl) subi r4,r4,4 blelr- 00: lwzu r5,4(r4) - stwbrx r5,0,r3 - eieio +01: stwbrx r5,0,r3 +02: eieio + ISYNC_8xx + .section .fixup,"ax" +03: blr + .text + .section __ex_table, "a" + .align 2 + .long 00b, 03b + .long 01b, 03b + .long 02b, 03b + .text bdnz 00b blr @@ -867,8 +932,18 @@ _GLOBAL(_insw_ns) subi r4,r4,2 blelr- 00: lhz r5,0(r3) - eieio - sthu r5,2(r4) +01: eieio +02: sthu r5,2(r4) + ISYNC_8xx + .section .fixup,"ax" +03: blr + .text + .section __ex_table, "a" + .align 2 + .long 00b, 03b + .long 01b, 03b + .long 02b, 03b + .text bdnz 00b blr @@ -879,8 +954,18 @@ _GLOBAL(_outsw_ns) subi r4,r4,2 blelr- 00: lhzu r5,2(r4) - sth r5,0(r3) - eieio +01: sth r5,0(r3) +02: eieio + ISYNC_8xx + .section .fixup,"ax" +03: blr + .text + .section __ex_table, "a" + .align 2 + .long 00b, 03b + .long 01b, 03b + .long 02b, 03b + .text bdnz 00b blr @@ -891,8 +976,18 @@ _GLOBAL(_insl_ns) subi r4,r4,4 blelr- 00: lwz r5,0(r3) - eieio - stwu r5,4(r4) +01: eieio +02: stwu r5,4(r4) + ISYNC_8xx + .section .fixup,"ax" +03: blr + .text + .section __ex_table, "a" + .align 2 + .long 00b, 03b + .long 01b, 03b + .long 02b, 03b + .text bdnz 00b blr @@ -903,8 +998,18 @@ _GLOBAL(_outsl_ns) subi r4,r4,4 blelr- 00: lwzu r5,4(r4) - stw r5,0(r3) - eieio +01: stw r5,0(r3) +02: eieio + ISYNC_8xx + .section .fixup,"ax" +03: blr + .text + .section __ex_table, "a" + .align 2 + .long 00b, 03b + .long 01b, 03b + .long 02b, 03b + .text bdnz 00b blr diff --git a/arch/ppc/kernel/rio.c b/arch/ppc/kernel/rio.c new file mode 100644 index 0000000000000000000000000000000000000000..29487fedfc76e907eba78893909b53de7ed1e439 --- /dev/null +++ b/arch/ppc/kernel/rio.c @@ -0,0 +1,52 @@ +/* + * RapidIO PPC32 support + * + * Copyright 2005 MontaVista Software, Inc. + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include + +#include + +/** + * platform_rio_init - Do platform specific RIO init + * + * Any platform specific initialization of RapdIO + * hardware is done here as well as registration + * of any active master ports in the system. + */ +void __attribute__ ((weak)) + platform_rio_init(void) +{ + printk(KERN_WARNING "RIO: No platform_rio_init() present\n"); +} + +/** + * ppc_rio_init - Do PPC32 RIO init + * + * Calls platform-specific RIO init code and then calls + * rio_init_mports() to initialize any master ports that + * have been registered with the RIO subsystem. + */ +static int __init ppc_rio_init(void) +{ + printk(KERN_INFO "RIO: RapidIO init\n"); + + /* Platform specific initialization */ + platform_rio_init(); + + /* Enumerate all registered ports */ + rio_init_mports(); + + return 0; +} + +subsys_initcall(ppc_rio_init); diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index 16adde6b429d2641827eade241cf016c22d2889b..9dbc4d28fa281cf6d8c83810e3204acb92eecf48 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -49,7 +49,7 @@ extern int xmon_sstep(struct pt_regs *regs); extern int xmon_iabr_match(struct pt_regs *regs); extern int xmon_dabr_match(struct pt_regs *regs); -void (*debugger)(struct pt_regs *regs) = xmon; +int (*debugger)(struct pt_regs *regs) = xmon; int (*debugger_bpt)(struct pt_regs *regs) = xmon_bpt; int (*debugger_sstep)(struct pt_regs *regs) = xmon_sstep; int (*debugger_iabr_match)(struct pt_regs *regs) = xmon_iabr_match; @@ -57,7 +57,7 @@ int (*debugger_dabr_match)(struct pt_regs *regs) = xmon_dabr_match; void (*debugger_fault_handler)(struct pt_regs *regs); #else #ifdef CONFIG_KGDB -void (*debugger)(struct pt_regs *regs); +int (*debugger)(struct pt_regs *regs); int (*debugger_bpt)(struct pt_regs *regs); int (*debugger_sstep)(struct pt_regs *regs); int (*debugger_iabr_match)(struct pt_regs *regs); @@ -159,7 +159,7 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) */ static inline int check_io_access(struct pt_regs *regs) { -#ifdef CONFIG_PPC_PMAC +#if defined CONFIG_PPC_PMAC || defined CONFIG_8xx unsigned long msr = regs->msr; const struct exception_table_entry *entry; unsigned int *nip = (unsigned int *)regs->nip; @@ -178,7 +178,11 @@ static inline int check_io_access(struct pt_regs *regs) nip -= 2; else if (*nip == 0x4c00012c) /* isync */ --nip; - if (*nip == 0x7c0004ac || (*nip >> 26) == 3) { + /* eieio from I/O string functions */ + else if ((*nip) == 0x7c0006ac || *(nip+1) == 0x7c0006ac) + nip += 2; + if (*nip == 0x7c0004ac || (*nip >> 26) == 3 || + (*(nip+1) >> 26) == 3) { /* sync or twi */ unsigned int rb; diff --git a/arch/ppc/platforms/4xx/Kconfig b/arch/ppc/platforms/4xx/Kconfig index 76f4476cab44b7803b7a481fb9785a2d78b73027..d8837911bbc6a473d90ae22d3c1c04f38dc90e3c 100644 --- a/arch/ppc/platforms/4xx/Kconfig +++ b/arch/ppc/platforms/4xx/Kconfig @@ -82,6 +82,12 @@ config LUAN help This option enables support for the IBM PPC440SP evaluation board. +config YUCCA + bool "Yucca" + select WANT_EARLY_SERIAL + help + This option enables support for the AMCC PPC440SPe evaluation board. + config OCOTEA bool "Ocotea" select WANT_EARLY_SERIAL @@ -124,9 +130,14 @@ config 440SP depends on LUAN default y +config 440SPE + bool + depends on YUCCA + default y + config 440 bool - depends on 440GP || 440SP || 440EP + depends on 440GP || 440SP || 440SPE || 440EP default y config 440A @@ -158,7 +169,7 @@ config BOOKE config IBM_OCP bool - depends on ASH || BAMBOO || BUBINGA || CPCI405 || EBONY || EP405 || LUAN || OCOTEA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT + depends on ASH || BAMBOO || BUBINGA || CPCI405 || EBONY || EP405 || LUAN || YUCCA || OCOTEA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT default y config XILINX_OCP @@ -168,7 +179,7 @@ config XILINX_OCP config IBM_EMAC4 bool - depends on 440GX || 440SP + depends on 440GX || 440SP || 440SPE default y config BIOS_FIXUP @@ -214,7 +225,7 @@ config EMBEDDEDBOOT config IBM_OPENBIOS bool - depends on ASH || BUBINGA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT + depends on ASH || REDWOOD_5 || REDWOOD_6 default y config PPC4xx_DMA diff --git a/arch/ppc/platforms/4xx/Makefile b/arch/ppc/platforms/4xx/Makefile index 1dd6d7fd6a9a8b08b25203af8b12a82b48968fa9..c9bb6117095477144a43f26487a338536e0f683a 100644 --- a/arch/ppc/platforms/4xx/Makefile +++ b/arch/ppc/platforms/4xx/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_EBONY) += ebony.o obj-$(CONFIG_EP405) += ep405.o obj-$(CONFIG_BUBINGA) += bubinga.o obj-$(CONFIG_LUAN) += luan.o +obj-$(CONFIG_YUCCA) += yucca.o obj-$(CONFIG_OCOTEA) += ocotea.o obj-$(CONFIG_REDWOOD_5) += redwood5.o obj-$(CONFIG_REDWOOD_6) += redwood6.o @@ -22,6 +23,7 @@ obj-$(CONFIG_440EP) += ibm440ep.o obj-$(CONFIG_440GP) += ibm440gp.o obj-$(CONFIG_440GX) += ibm440gx.o obj-$(CONFIG_440SP) += ibm440sp.o +obj-$(CONFIG_440SPE) += ppc440spe.o obj-$(CONFIG_405EP) += ibm405ep.o obj-$(CONFIG_405GPR) += ibm405gpr.o obj-$(CONFIG_VIRTEX_II_PRO) += virtex-ii_pro.o diff --git a/arch/ppc/platforms/4xx/bubinga.c b/arch/ppc/platforms/4xx/bubinga.c index 3678abf863139475d42da06b08b2784d92930c42..8110f55668c5508979919f5c2b060edb0d0d1b67 100644 --- a/arch/ppc/platforms/4xx/bubinga.c +++ b/arch/ppc/platforms/4xx/bubinga.c @@ -89,7 +89,7 @@ bubinga_early_serial_map(void) * by 16. */ uart_div = (mfdcr(DCRN_CPC0_UCR_BASE) & DCRN_CPC0_UCR_U0DIV); - uart_clock = __res.bi_pllouta_freq / uart_div; + uart_clock = __res.bi_procfreq / uart_div; /* Setup serial port access */ memset(&port, 0, sizeof(port)); diff --git a/arch/ppc/platforms/4xx/bubinga.h b/arch/ppc/platforms/4xx/bubinga.h index b1df856f8e22520834527efb6eef77fc21ed494e..b5380cfaf5c0cae05aea52094746d1e568654332 100644 --- a/arch/ppc/platforms/4xx/bubinga.h +++ b/arch/ppc/platforms/4xx/bubinga.h @@ -1,52 +1,34 @@ /* - * Support for IBM PPC 405EP evaluation board (Bubinga). + * arch/ppc/platforms/4xx/bubinga.h * - * Author: SAW (IBM), derived from walnut.h. - * Maintained by MontaVista Software + * Bubinga board definitions + * + * Copyright (c) 2005 DENX Software Engineering + * Stefan Roese + * + * Based on original work by + * SAW (IBM) + * 2003 (c) MontaVista Softare Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. * - * 2003 (c) MontaVista Softare Inc. This file is licensed under the - * terms of the GNU General Public License version 2. This program is - * licensed "as is" without any warranty of any kind, whether express - * or implied. */ #ifdef __KERNEL__ #ifndef __BUBINGA_H__ #define __BUBINGA_H__ -/* 405EP */ +#include #include - -#ifndef __ASSEMBLY__ -/* - * Data structure defining board information maintained by the boot - * ROM on IBM's evaluation board. An effort has been made to - * keep the field names consistent with the 8xx 'bd_t' board info - * structures. - */ - -typedef struct board_info { - unsigned char bi_s_version[4]; /* Version of this structure */ - unsigned char bi_r_version[30]; /* Version of the IBM ROM */ - unsigned int bi_memsize; /* DRAM installed, in bytes */ - unsigned char bi_enetaddr[2][6]; /* Local Ethernet MAC address */ unsigned char bi_pci_enetaddr[6]; /* PCI Ethernet MAC address */ - unsigned int bi_intfreq; /* Processor speed, in Hz */ - unsigned int bi_busfreq; /* PLB Bus speed, in Hz */ - unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */ - unsigned int bi_opb_busfreq; /* OPB Bus speed, in Hz */ - unsigned int bi_pllouta_freq; /* PLL OUTA speed, in Hz */ -} bd_t; - -/* Some 4xx parts use a different timebase frequency from the internal clock. -*/ -#define bi_tbfreq bi_intfreq - +#include /* Memory map for the Bubinga board. * Generic 4xx plus RTC. */ -extern void *bubinga_rtc_base; #define BUBINGA_RTC_PADDR ((uint)0xf0000000) #define BUBINGA_RTC_VADDR BUBINGA_RTC_PADDR #define BUBINGA_RTC_SIZE ((uint)8*1024) @@ -58,12 +40,18 @@ extern void *bubinga_rtc_base; * for typical configurations at various CPU speeds. * The base baud is calculated as (FWDA / EXT UART DIV / 16) */ -#define BASE_BAUD 0 +#define BASE_BAUD 0 -#define BUBINGA_FPGA_BASE 0xF0300000 +/* Flash */ +#define PPC40x_FPGA_BASE 0xF0300000 +#define PPC40x_FPGA_REG_OFFS 1 /* offset to flash map reg */ +#define PPC40x_FLASH_ONBD_N(x) (x & 0x02) +#define PPC40x_FLASH_SRAM_SEL(x) (x & 0x01) +#define PPC40x_FLASH_LOW 0xFFF00000 +#define PPC40x_FLASH_HIGH 0xFFF80000 +#define PPC40x_FLASH_SIZE 0x80000 -#define PPC4xx_MACHINE_NAME "IBM Bubinga" +#define PPC4xx_MACHINE_NAME "IBM Bubinga" -#endif /* !__ASSEMBLY__ */ #endif /* __BUBINGA_H__ */ #endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/ebony.h b/arch/ppc/platforms/4xx/ebony.h index d08faa46a0aef5b9e5e49a1761145ddaec9e175a..b91ad4272dfe2b299b253eba92bcef4c38728a8b 100644 --- a/arch/ppc/platforms/4xx/ebony.h +++ b/arch/ppc/platforms/4xx/ebony.h @@ -24,8 +24,8 @@ #define PPC44x_EMAC0_MR0 0xE0000800 /* Where to find the MAC info */ -#define EBONY_OPENBIOS_MAC_BASE 0xfffffe0c -#define EBONY_OPENBIOS_MAC_OFFSET 0x0c +#define OPENBIOS_MAC_BASE 0xfffffe0c +#define OPENBIOS_MAC_OFFSET 0x0c /* Default clock rates for Rev. B and Rev. C silicon */ #define EBONY_440GP_RB_SYSCLK 33000000 diff --git a/arch/ppc/platforms/4xx/ppc440spe.c b/arch/ppc/platforms/4xx/ppc440spe.c new file mode 100644 index 0000000000000000000000000000000000000000..6139a0b3393e15291e84d77ce7fe11861d20edb8 --- /dev/null +++ b/arch/ppc/platforms/4xx/ppc440spe.c @@ -0,0 +1,148 @@ +/* + * arch/ppc/platforms/4xx/ppc440spe.c + * + * PPC440SPe I/O descriptions + * + * Roland Dreier + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * + * Matt Porter + * Copyright 2002-2005 MontaVista Software Inc. + * + * Eugene Surovegin or + * Copyright (c) 2003, 2004 Zultys Technologies + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include +#include +#include +#include +#include + +static struct ocp_func_emac_data ppc440spe_emac0_def = { + .rgmii_idx = -1, /* No RGMII */ + .rgmii_mux = -1, /* No RGMII */ + .zmii_idx = -1, /* No ZMII */ + .zmii_mux = -1, /* No ZMII */ + .mal_idx = 0, /* MAL device index */ + .mal_rx_chan = 0, /* MAL rx channel number */ + .mal_tx_chan = 0, /* MAL tx channel number */ + .wol_irq = 61, /* WOL interrupt number */ + .mdio_idx = -1, /* No shared MDIO */ + .tah_idx = -1, /* No TAH */ +}; +OCP_SYSFS_EMAC_DATA() + +static struct ocp_func_mal_data ppc440spe_mal0_def = { + .num_tx_chans = 1, /* Number of TX channels */ + .num_rx_chans = 1, /* Number of RX channels */ + .txeob_irq = 38, /* TX End Of Buffer IRQ */ + .rxeob_irq = 39, /* RX End Of Buffer IRQ */ + .txde_irq = 34, /* TX Descriptor Error IRQ */ + .rxde_irq = 35, /* RX Descriptor Error IRQ */ + .serr_irq = 33, /* MAL System Error IRQ */ + .dcr_base = DCRN_MAL_BASE /* MAL0_CFG DCR number */ +}; +OCP_SYSFS_MAL_DATA() + +static struct ocp_func_iic_data ppc440spe_iic0_def = { + .fast_mode = 0, /* Use standad mode (100Khz) */ +}; + +static struct ocp_func_iic_data ppc440spe_iic1_def = { + .fast_mode = 0, /* Use standad mode (100Khz) */ +}; +OCP_SYSFS_IIC_DATA() + +struct ocp_def core_ocp[] = { + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 0, + .paddr = PPC440SPE_UART0_ADDR, + .irq = UART0_INT, + .pm = IBM_CPM_UART0, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 1, + .paddr = PPC440SPE_UART1_ADDR, + .irq = UART1_INT, + .pm = IBM_CPM_UART1, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_16550, + .index = 2, + .paddr = PPC440SPE_UART2_ADDR, + .irq = UART2_INT, + .pm = IBM_CPM_UART2, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_IIC, + .index = 0, + .paddr = 0x00000004f0000400ULL, + .irq = 2, + .pm = IBM_CPM_IIC0, + .additions = &ppc440spe_iic0_def, + .show = &ocp_show_iic_data + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_IIC, + .index = 1, + .paddr = 0x00000004f0000500ULL, + .irq = 3, + .pm = IBM_CPM_IIC1, + .additions = &ppc440spe_iic1_def, + .show = &ocp_show_iic_data + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_GPIO, + .index = 0, + .paddr = 0x00000004f0000700ULL, + .irq = OCP_IRQ_NA, + .pm = IBM_CPM_GPIO0, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_MAL, + .paddr = OCP_PADDR_NA, + .irq = OCP_IRQ_NA, + .pm = OCP_CPM_NA, + .additions = &ppc440spe_mal0_def, + .show = &ocp_show_mal_data, + }, + { .vendor = OCP_VENDOR_IBM, + .function = OCP_FUNC_EMAC, + .index = 0, + .paddr = 0x00000004f0000800ULL, + .irq = 60, + .pm = OCP_CPM_NA, + .additions = &ppc440spe_emac0_def, + .show = &ocp_show_emac_data, + }, + { .vendor = OCP_VENDOR_INVALID + } +}; + +/* Polarity and triggering settings for internal interrupt sources */ +struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[] __initdata = { + { .polarity = 0xffffffff, + .triggering = 0x010f0004, + .ext_irq_mask = 0x00000000, + }, + { .polarity = 0xffffffff, + .triggering = 0x001f8040, + .ext_irq_mask = 0x00007c30, /* IRQ6 - IRQ7, IRQ8 - IRQ12 */ + }, + { .polarity = 0xffffffff, + .triggering = 0x00000000, + .ext_irq_mask = 0x000000fc, /* IRQ0 - IRQ5 */ + }, + { .polarity = 0xffffffff, + .triggering = 0x00000000, + .ext_irq_mask = 0x00000000, + }, +}; diff --git a/arch/ppc/platforms/4xx/ppc440spe.h b/arch/ppc/platforms/4xx/ppc440spe.h new file mode 100644 index 0000000000000000000000000000000000000000..2216846973b837d26c00c7d53a2a6eb144f409f5 --- /dev/null +++ b/arch/ppc/platforms/4xx/ppc440spe.h @@ -0,0 +1,66 @@ +/* + * arch/ppc/platforms/4xx/ibm440spe.h + * + * PPC440SPe definitions + * + * Roland Dreier + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * + * Matt Porter + * Copyright 2004-2005 MontaVista Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifdef __KERNEL__ +#ifndef __PPC_PLATFORMS_PPC440SPE_H +#define __PPC_PLATFORMS_PPC440SPE_H + +#include + +#include + +/* UART */ +#define PPC440SPE_UART0_ADDR 0x00000004f0000200ULL +#define PPC440SPE_UART1_ADDR 0x00000004f0000300ULL +#define PPC440SPE_UART2_ADDR 0x00000004f0000600ULL +#define UART0_INT 0 +#define UART1_INT 1 +#define UART2_INT 37 + +/* Clock and Power Management */ +#define IBM_CPM_IIC0 0x80000000 /* IIC interface */ +#define IBM_CPM_IIC1 0x40000000 /* IIC interface */ +#define IBM_CPM_PCI 0x20000000 /* PCI bridge */ +#define IBM_CPM_CPU 0x02000000 /* processor core */ +#define IBM_CPM_DMA 0x01000000 /* DMA controller */ +#define IBM_CPM_BGO 0x00800000 /* PLB to OPB bus arbiter */ +#define IBM_CPM_BGI 0x00400000 /* OPB to PLB bridge */ +#define IBM_CPM_EBC 0x00200000 /* External Bux Controller */ +#define IBM_CPM_EBM 0x00100000 /* Ext Bus Master Interface */ +#define IBM_CPM_DMC 0x00080000 /* SDRAM peripheral controller */ +#define IBM_CPM_PLB 0x00040000 /* PLB bus arbiter */ +#define IBM_CPM_SRAM 0x00020000 /* SRAM memory controller */ +#define IBM_CPM_PPM 0x00002000 /* PLB Performance Monitor */ +#define IBM_CPM_UIC1 0x00001000 /* Universal Interrupt Controller */ +#define IBM_CPM_GPIO0 0x00000800 /* General Purpose IO (??) */ +#define IBM_CPM_GPT 0x00000400 /* General Purpose Timers */ +#define IBM_CPM_UART0 0x00000200 /* serial port 0 */ +#define IBM_CPM_UART1 0x00000100 /* serial port 1 */ +#define IBM_CPM_UART2 0x00000100 /* serial port 1 */ +#define IBM_CPM_UIC0 0x00000080 /* Universal Interrupt Controller */ +#define IBM_CPM_TMRCLK 0x00000040 /* CPU timers */ +#define IBM_CPM_EMAC0 0x00000020 /* EMAC 0 */ + +#define DFLT_IBM4xx_PM ~(IBM_CPM_UIC | IBM_CPM_UIC1 | IBM_CPM_CPU \ + | IBM_CPM_EBC | IBM_CPM_SRAM | IBM_CPM_BGO \ + | IBM_CPM_EBM | IBM_CPM_PLB | IBM_CPM_OPB \ + | IBM_CPM_TMRCLK | IBM_CPM_DMA | IBM_CPM_PCI \ + | IBM_CPM_TAHOE0 | IBM_CPM_TAHOE1 \ + | IBM_CPM_EMAC0 | IBM_CPM_EMAC1 \ + | IBM_CPM_EMAC2 | IBM_CPM_EMAC3 ) +#endif /* __PPC_PLATFORMS_PPC440SP_H */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/sycamore.c b/arch/ppc/platforms/4xx/sycamore.c index d8019eec47045156786eff4f43da9833f885ce5b..281b4a2ffb968ce55a46e2b4d9fc19ba9e9fb51b 100644 --- a/arch/ppc/platforms/4xx/sycamore.c +++ b/arch/ppc/platforms/4xx/sycamore.c @@ -88,9 +88,6 @@ ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) void __init sycamore_setup_arch(void) { -#define SYCAMORE_PS2_BASE 0xF0100000 -#define SYCAMORE_FPGA_BASE 0xF0300000 - void *fpga_brdc; unsigned char fpga_brdc_data; void *fpga_enable; @@ -100,7 +97,7 @@ sycamore_setup_arch(void) ppc4xx_setup_arch(); - ibm_ocp_set_emac(0, 1); + ibm_ocp_set_emac(0, 0); kb_data = ioremap(SYCAMORE_PS2_BASE, 8); if (!kb_data) { @@ -111,7 +108,7 @@ sycamore_setup_arch(void) kb_cs = kb_data + 1; - fpga_status = ioremap(SYCAMORE_FPGA_BASE, 8); + fpga_status = ioremap(PPC40x_FPGA_BASE, 8); if (!fpga_status) { printk(KERN_CRIT "sycamore_setup_arch() fpga_status ioremap failed\n"); diff --git a/arch/ppc/platforms/4xx/sycamore.h b/arch/ppc/platforms/4xx/sycamore.h index 3e7b4e2c8c570668d56a66d58af836534fa1d62f..1cd6c824fd62efcde04c5de5bb5f8eb6e7be1f3b 100644 --- a/arch/ppc/platforms/4xx/sycamore.h +++ b/arch/ppc/platforms/4xx/sycamore.h @@ -1,67 +1,52 @@ /* * arch/ppc/platforms/4xx/sycamore.h * - * Macros, definitions, and data structures specific to the IBM PowerPC - * 405GPr "Sycamore" evaluation board. + * Sycamore board definitions * - * Author: Armin Kuster + * Copyright (c) 2005 DENX Software Engineering + * Stefan Roese + * + * Based on original work by + * Armin Kuster + * 2000 (c) MontaVista, Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. * - * 2000 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. */ #ifdef __KERNEL__ #ifndef __ASM_SYCAMORE_H__ #define __ASM_SYCAMORE_H__ +#include #include +#include -#ifndef __ASSEMBLY__ -/* - * Data structure defining board information maintained by the boot - * ROM on IBM's "Sycamore" evaluation board. An effort has been made to - * keep the field names consistent with the 8xx 'bd_t' board info - * structures. - */ - -typedef struct board_info { - unsigned char bi_s_version[4]; /* Version of this structure */ - unsigned char bi_r_version[30]; /* Version of the IBM ROM */ - unsigned int bi_memsize; /* DRAM installed, in bytes */ - unsigned char bi_enetaddr[6]; /* Local Ethernet MAC address */ - unsigned char bi_pci_enetaddr[6]; /* PCI Ethernet MAC address */ - unsigned int bi_intfreq; /* Processor speed, in Hz */ - unsigned int bi_busfreq; /* PLB Bus speed, in Hz */ - unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */ -} bd_t; - -/* Some 4xx parts use a different timebase frequency from the internal clock. -*/ -#define bi_tbfreq bi_intfreq - - -/* Memory map for the IBM "Sycamore" 405GP evaluation board. +/* Memory map for the IBM "Sycamore" 405GPr evaluation board. * Generic 4xx plus RTC. */ -extern void *sycamore_rtc_base; #define SYCAMORE_RTC_PADDR ((uint)0xf0000000) #define SYCAMORE_RTC_VADDR SYCAMORE_RTC_PADDR -#define SYCAMORE_RTC_SIZE ((uint)8*1024) +#define SYCAMORE_RTC_SIZE ((uint)8*1024) -#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK -#define BASE_BAUD 201600 -#else #define BASE_BAUD 691200 -#endif -#define SYCAMORE_PS2_BASE 0xF0100000 -#define SYCAMORE_FPGA_BASE 0xF0300000 +#define SYCAMORE_PS2_BASE 0xF0100000 + +/* Flash */ +#define PPC40x_FPGA_BASE 0xF0300000 +#define PPC40x_FPGA_REG_OFFS 5 /* offset to flash map reg */ +#define PPC40x_FLASH_ONBD_N(x) (x & 0x02) +#define PPC40x_FLASH_SRAM_SEL(x) (x & 0x01) +#define PPC40x_FLASH_LOW 0xFFF00000 +#define PPC40x_FLASH_HIGH 0xFFF80000 +#define PPC40x_FLASH_SIZE 0x80000 #define PPC4xx_MACHINE_NAME "IBM Sycamore" -#endif /* !__ASSEMBLY__ */ #endif /* __ASM_SYCAMORE_H__ */ #endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/walnut.c b/arch/ppc/platforms/4xx/walnut.c index a33eda4b7489a46eab90e7b89efec6746ab5abb8..74cb33182d9fac8baf42f6c2a1b5e096c67ffd6e 100644 --- a/arch/ppc/platforms/4xx/walnut.c +++ b/arch/ppc/platforms/4xx/walnut.c @@ -90,7 +90,7 @@ walnut_setup_arch(void) kb_cs = kb_data + 1; - fpga_status = ioremap(WALNUT_FPGA_BASE, 8); + fpga_status = ioremap(PPC40x_FPGA_BASE, 8); if (!fpga_status) { printk(KERN_CRIT "walnut_setup_arch() fpga_status ioremap failed\n"); diff --git a/arch/ppc/platforms/4xx/walnut.h b/arch/ppc/platforms/4xx/walnut.h index 04cfbf3696b91ddfb49e6ac196d42db7f76c5c4b..dcf2691698c029b9350993130f7dc58f07a1a432 100644 --- a/arch/ppc/platforms/4xx/walnut.h +++ b/arch/ppc/platforms/4xx/walnut.h @@ -1,72 +1,55 @@ /* * arch/ppc/platforms/4xx/walnut.h * - * Macros, definitions, and data structures specific to the IBM PowerPC - * 405GP "Walnut" evaluation board. + * Walnut board definitions * - * Authors: Grant Erickson , Frank Rowand - * , Debbie Chu or - * source@mvista.com + * Copyright (c) 2005 DENX Software Engineering + * Stefan Roese * - * Copyright (c) 1999 Grant Erickson + * Based on original work by + * Copyright (c) 1999 Grant Erickson + * Frank Rowand + * Debbie Chu + * 2000 (c) MontaVista, Software, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. * - * 2000 (c) MontaVista, Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. */ #ifdef __KERNEL__ #ifndef __ASM_WALNUT_H__ #define __ASM_WALNUT_H__ -/* We have a 405GP core */ +#include #include - -#ifndef __ASSEMBLY__ -/* - * Data structure defining board information maintained by the boot - * ROM on IBM's "Walnut" evaluation board. An effort has been made to - * keep the field names consistent with the 8xx 'bd_t' board info - * structures. - */ - -typedef struct board_info { - unsigned char bi_s_version[4]; /* Version of this structure */ - unsigned char bi_r_version[30]; /* Version of the IBM ROM */ - unsigned int bi_memsize; /* DRAM installed, in bytes */ - unsigned char bi_enetaddr[6]; /* Local Ethernet MAC address */ - unsigned char bi_pci_enetaddr[6]; /* PCI Ethernet MAC address */ - unsigned int bi_intfreq; /* Processor speed, in Hz */ - unsigned int bi_busfreq; /* PLB Bus speed, in Hz */ - unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */ -} bd_t; - -/* Some 4xx parts use a different timebase frequency from the internal clock. -*/ -#define bi_tbfreq bi_intfreq - +#include /* Memory map for the IBM "Walnut" 405GP evaluation board. * Generic 4xx plus RTC. */ -extern void *walnut_rtc_base; #define WALNUT_RTC_PADDR ((uint)0xf0000000) #define WALNUT_RTC_VADDR WALNUT_RTC_PADDR #define WALNUT_RTC_SIZE ((uint)8*1024) -#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK -#define BASE_BAUD 201600 -#else #define BASE_BAUD 691200 -#endif #define WALNUT_PS2_BASE 0xF0100000 -#define WALNUT_FPGA_BASE 0xF0300000 + +/* Flash */ +#define PPC40x_FPGA_BASE 0xF0300000 +#define PPC40x_FPGA_REG_OFFS 5 /* offset to flash map reg */ +#define PPC40x_FLASH_ONBD_N(x) (x & 0x02) +#define PPC40x_FLASH_SRAM_SEL(x) (x & 0x01) +#define PPC40x_FLASH_LOW 0xFFF00000 +#define PPC40x_FLASH_HIGH 0xFFF80000 +#define PPC40x_FLASH_SIZE 0x80000 +#define WALNUT_FPGA_BASE PPC40x_FPGA_BASE #define PPC4xx_MACHINE_NAME "IBM Walnut" -#endif /* !__ASSEMBLY__ */ #endif /* __ASM_WALNUT_H__ */ #endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/4xx/yucca.c b/arch/ppc/platforms/4xx/yucca.c new file mode 100644 index 0000000000000000000000000000000000000000..e60f4bd437ec2c1b69053c2578067fb506d09299 --- /dev/null +++ b/arch/ppc/platforms/4xx/yucca.c @@ -0,0 +1,395 @@ +/* + * arch/ppc/platforms/4xx/yucca.c + * + * Yucca board specific routines + * + * Roland Dreier (based on luan.c by Matt Porter) + * + * Copyright 2004-2005 MontaVista Software Inc. + * Copyright (c) 2005 Cisco Systems. 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +extern bd_t __res; + +static struct ibm44x_clocks clocks __initdata; + +static void __init +yucca_calibrate_decr(void) +{ + unsigned int freq; + + if (mfspr(SPRN_CCR1) & CCR1_TCS) + freq = YUCCA_TMR_CLK; + else + freq = clocks.cpu; + + ibm44x_calibrate_decr(freq); +} + +static int +yucca_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "vendor\t\t: AMCC\n"); + seq_printf(m, "machine\t\t: PPC440SPe EVB (Yucca)\n"); + + return 0; +} + +static enum { + HOSE_UNKNOWN, + HOSE_PCIX, + HOSE_PCIE0, + HOSE_PCIE1, + HOSE_PCIE2 +} hose_type[4]; + +static inline int +yucca_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); + + if (hose_type[hose->index] == HOSE_PCIX) { + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + { 81, -1, -1, -1 }, /* IDSEL 1 - PCIX0 Slot 0 */ + }; + const long min_idsel = 1, max_idsel = 1, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; + } else if (hose_type[hose->index] == HOSE_PCIE0) { + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + { 96, 97, 98, 99 }, + }; + const long min_idsel = 1, max_idsel = 1, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; + } else if (hose_type[hose->index] == HOSE_PCIE1) { + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + { 100, 101, 102, 103 }, + }; + const long min_idsel = 1, max_idsel = 1, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; + } else if (hose_type[hose->index] == HOSE_PCIE2) { + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + { 104, 105, 106, 107 }, + }; + const long min_idsel = 1, max_idsel = 1, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; + } + return -1; +} + +static void __init yucca_set_emacdata(void) +{ + struct ocp_def *def; + struct ocp_func_emac_data *emacdata; + + /* Set phy_map, phy_mode, and mac_addr for the EMAC */ + def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, 0); + emacdata = def->additions; + emacdata->phy_map = 0x00000001; /* Skip 0x00 */ + emacdata->phy_mode = PHY_MODE_GMII; + memcpy(emacdata->mac_addr, __res.bi_enetaddr, 6); +} + +static int __init yucca_pcie_card_present(int port) +{ + void __iomem *pcie_fpga_base; + u16 reg; + + pcie_fpga_base = ioremap64(YUCCA_FPGA_REG_BASE, YUCCA_FPGA_REG_SIZE); + reg = in_be16(pcie_fpga_base + FPGA_REG1C); + iounmap(pcie_fpga_base); + + switch(port) { + case 0: return !(reg & FPGA_REG1C_PE0_PRSNT); + case 1: return !(reg & FPGA_REG1C_PE1_PRSNT); + case 2: return !(reg & FPGA_REG1C_PE2_PRSNT); + default: return 0; + } +} + +/* + * For the given slot, set rootpoint mode, send power to the slot, + * turn on the green LED and turn off the yellow LED, enable the clock + * and turn off reset. + */ +static void __init yucca_setup_pcie_fpga_rootpoint(int port) +{ + void __iomem *pcie_reg_fpga_base; + u16 power, clock, green_led, yellow_led, reset_off, rootpoint, endpoint; + + pcie_reg_fpga_base = ioremap64(YUCCA_FPGA_REG_BASE, YUCCA_FPGA_REG_SIZE); + + switch(port) { + case 0: + rootpoint = FPGA_REG1C_PE0_ROOTPOINT; + endpoint = 0; + power = FPGA_REG1A_PE0_PWRON; + green_led = FPGA_REG1A_PE0_GLED; + clock = FPGA_REG1A_PE0_REFCLK_ENABLE; + yellow_led = FPGA_REG1A_PE0_YLED; + reset_off = FPGA_REG1C_PE0_PERST; + break; + case 1: + rootpoint = 0; + endpoint = FPGA_REG1C_PE1_ENDPOINT; + power = FPGA_REG1A_PE1_PWRON; + green_led = FPGA_REG1A_PE1_GLED; + clock = FPGA_REG1A_PE1_REFCLK_ENABLE; + yellow_led = FPGA_REG1A_PE1_YLED; + reset_off = FPGA_REG1C_PE1_PERST; + break; + case 2: + rootpoint = 0; + endpoint = FPGA_REG1C_PE2_ENDPOINT; + power = FPGA_REG1A_PE2_PWRON; + green_led = FPGA_REG1A_PE2_GLED; + clock = FPGA_REG1A_PE2_REFCLK_ENABLE; + yellow_led = FPGA_REG1A_PE2_YLED; + reset_off = FPGA_REG1C_PE2_PERST; + break; + + default: + return; + } + + out_be16(pcie_reg_fpga_base + FPGA_REG1A, + ~(power | clock | green_led) & + (yellow_led | in_be16(pcie_reg_fpga_base + FPGA_REG1A))); + out_be16(pcie_reg_fpga_base + FPGA_REG1C, + ~(endpoint | reset_off) & + (rootpoint | in_be16(pcie_reg_fpga_base + FPGA_REG1C))); + + /* + * Leave device in reset for a while after powering on the + * slot to give it a chance to initialize. + */ + mdelay(250); + + out_be16(pcie_reg_fpga_base + FPGA_REG1C, + reset_off | in_be16(pcie_reg_fpga_base + FPGA_REG1C)); + + iounmap(pcie_reg_fpga_base); +} + +static void __init +yucca_setup_hoses(void) +{ + struct pci_controller *hose; + char name[20]; + int i; + + if (0 && ppc440spe_init_pcie()) { + printk(KERN_WARNING "PPC440SPe PCI Express initialization failed\n"); + return; + } + + for (i = 0; i <= 2; ++i) { + if (!yucca_pcie_card_present(i)) + continue; + + printk(KERN_INFO "PCIE%d: card present\n", i); + yucca_setup_pcie_fpga_rootpoint(i); + if (ppc440spe_init_pcie_rootport(i)) { + printk(KERN_WARNING "PCIE%d: initialization failed\n", i); + continue; + } + + hose = pcibios_alloc_controller(); + if (!hose) + return; + + sprintf(name, "PCIE%d host bridge", i); + pci_init_resource(&hose->io_resource, + YUCCA_PCIX_LOWER_IO, + YUCCA_PCIX_UPPER_IO, + IORESOURCE_IO, + name); + + hose->mem_space.start = YUCCA_PCIE_LOWER_MEM + + i * YUCCA_PCIE_MEM_SIZE; + hose->mem_space.end = hose->mem_space.start + + YUCCA_PCIE_MEM_SIZE - 1; + + pci_init_resource(&hose->mem_resources[0], + hose->mem_space.start, + hose->mem_space.end, + IORESOURCE_MEM, + name); + + hose->first_busno = 0; + hose->last_busno = 15; + hose_type[hose->index] = HOSE_PCIE0 + i; + + ppc440spe_setup_pcie(hose, i); + hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); + } + + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = yucca_map_irq; +} + +TODC_ALLOC(); + +static void __init +yucca_early_serial_map(void) +{ + struct uart_port port; + + /* Setup ioremapped serial port access */ + memset(&port, 0, sizeof(port)); + port.membase = ioremap64(PPC440SPE_UART0_ADDR, 8); + port.irq = UART0_INT; + port.uartclk = clocks.uart0; + port.regshift = 0; + port.iotype = SERIAL_IO_MEM; + port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; + port.line = 0; + + if (early_serial_setup(&port) != 0) { + printk("Early serial init of port 0 failed\n"); + } + + port.membase = ioremap64(PPC440SPE_UART1_ADDR, 8); + port.irq = UART1_INT; + port.uartclk = clocks.uart1; + port.line = 1; + + if (early_serial_setup(&port) != 0) { + printk("Early serial init of port 1 failed\n"); + } + + port.membase = ioremap64(PPC440SPE_UART2_ADDR, 8); + port.irq = UART2_INT; + port.uartclk = BASE_BAUD; + port.line = 2; + + if (early_serial_setup(&port) != 0) { + printk("Early serial init of port 2 failed\n"); + } +} + +static void __init +yucca_setup_arch(void) +{ + yucca_set_emacdata(); + +#if !defined(CONFIG_BDI_SWITCH) + /* + * The Abatron BDI JTAG debugger does not tolerate others + * mucking with the debug registers. + */ + mtspr(SPRN_DBCR0, (DBCR0_TDE | DBCR0_IDM)); +#endif + + /* + * Determine various clocks. + * To be completely correct we should get SysClk + * from FPGA, because it can be changed by on-board switches + * --ebs + */ + /* 440GX and 440SPe clocking is the same - rd */ + ibm440gx_get_clocks(&clocks, 33333333, 6 * 1843200); + ocp_sys_info.opb_bus_freq = clocks.opb; + + /* init to some ~sane value until calibrate_delay() runs */ + loops_per_jiffy = 50000000/HZ; + + /* Setup PCIXn host bridges */ + yucca_setup_hoses(); + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = Root_RAM0; + else +#endif +#ifdef CONFIG_ROOT_NFS + ROOT_DEV = Root_NFS; +#else + ROOT_DEV = Root_HDA1; +#endif + + yucca_early_serial_map(); + + /* Identify the system */ + printk("Yucca port (Roland Dreier )\n"); +} + +void __init platform_init(unsigned long r3, unsigned long r4, + unsigned long r5, unsigned long r6, unsigned long r7) +{ + ibm44x_platform_init(r3, r4, r5, r6, r7); + + ppc_md.setup_arch = yucca_setup_arch; + ppc_md.show_cpuinfo = yucca_show_cpuinfo; + ppc_md.find_end_of_memory = ibm440sp_find_end_of_memory; + ppc_md.get_irq = NULL; /* Set in ppc4xx_pic_init() */ + + ppc_md.calibrate_decr = yucca_calibrate_decr; +#ifdef CONFIG_KGDB + ppc_md.early_serial_map = yucca_early_serial_map; +#endif +} diff --git a/arch/ppc/platforms/4xx/yucca.h b/arch/ppc/platforms/4xx/yucca.h new file mode 100644 index 0000000000000000000000000000000000000000..01a4afea151435a5cfe1af9720a226da480832e5 --- /dev/null +++ b/arch/ppc/platforms/4xx/yucca.h @@ -0,0 +1,111 @@ +/* + * arch/ppc/platforms/4xx/yucca.h + * + * Yucca board definitions + * + * Roland Dreier (based on luan.h by Matt Porter) + * + * Copyright 2004-2005 MontaVista Software Inc. + * Copyright (c) 2005 Cisco Systems. 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. + * + */ + +#ifdef __KERNEL__ +#ifndef __ASM_YUCCA_H__ +#define __ASM_YUCCA_H__ + +#include +#include + +/* F/W TLB mapping used in bootloader glue to reset EMAC */ +#define PPC44x_EMAC0_MR0 0xa0000800 + +/* Location of MAC addresses in PIBS image */ +#define PIBS_FLASH_BASE 0xffe00000 +#define PIBS_MAC_BASE (PIBS_FLASH_BASE+0x1b0400) + +/* External timer clock frequency */ +#define YUCCA_TMR_CLK 25000000 + +/* + * FPGA registers + */ +#define YUCCA_FPGA_REG_BASE 0x00000004e2000000ULL +#define YUCCA_FPGA_REG_SIZE 0x24 + +#define FPGA_REG1A 0x1a + +#define FPGA_REG1A_PE0_GLED 0x8000 +#define FPGA_REG1A_PE1_GLED 0x4000 +#define FPGA_REG1A_PE2_GLED 0x2000 +#define FPGA_REG1A_PE0_YLED 0x1000 +#define FPGA_REG1A_PE1_YLED 0x0800 +#define FPGA_REG1A_PE2_YLED 0x0400 +#define FPGA_REG1A_PE0_PWRON 0x0200 +#define FPGA_REG1A_PE1_PWRON 0x0100 +#define FPGA_REG1A_PE2_PWRON 0x0080 +#define FPGA_REG1A_PE0_REFCLK_ENABLE 0x0040 +#define FPGA_REG1A_PE1_REFCLK_ENABLE 0x0020 +#define FPGA_REG1A_PE2_REFCLK_ENABLE 0x0010 +#define FPGA_REG1A_PE_SPREAD0 0x0008 +#define FPGA_REG1A_PE_SPREAD1 0x0004 +#define FPGA_REG1A_PE_SELSOURCE_0 0x0002 +#define FPGA_REG1A_PE_SELSOURCE_1 0x0001 + +#define FPGA_REG1C 0x1c + +#define FPGA_REG1C_PE0_ROOTPOINT 0x8000 +#define FPGA_REG1C_PE1_ENDPOINT 0x4000 +#define FPGA_REG1C_PE2_ENDPOINT 0x2000 +#define FPGA_REG1C_PE0_PRSNT 0x1000 +#define FPGA_REG1C_PE1_PRSNT 0x0800 +#define FPGA_REG1C_PE2_PRSNT 0x0400 +#define FPGA_REG1C_PE0_WAKE 0x0080 +#define FPGA_REG1C_PE1_WAKE 0x0040 +#define FPGA_REG1C_PE2_WAKE 0x0020 +#define FPGA_REG1C_PE0_PERST 0x0010 +#define FPGA_REG1C_PE1_PERST 0x0008 +#define FPGA_REG1C_PE2_PERST 0x0004 + +/* + * Serial port defines + */ +#define RS_TABLE_SIZE 3 + +/* PIBS defined UART mappings, used before early_serial_setup */ +#define UART0_IO_BASE 0xa0000200 +#define UART1_IO_BASE 0xa0000300 +#define UART2_IO_BASE 0xa0000600 + +#define BASE_BAUD 11059200 +#define STD_UART_OP(num) \ + { 0, BASE_BAUD, 0, UART##num##_INT, \ + (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \ + iomem_base: (void*)UART##num##_IO_BASE, \ + io_type: SERIAL_IO_MEM}, + +#define SERIAL_PORT_DFNS \ + STD_UART_OP(0) \ + STD_UART_OP(1) \ + STD_UART_OP(2) + +/* PCI support */ +#define YUCCA_PCIX_LOWER_IO 0x00000000 +#define YUCCA_PCIX_UPPER_IO 0x0000ffff +#define YUCCA_PCIX_LOWER_MEM 0x80000000 +#define YUCCA_PCIX_UPPER_MEM 0x8fffffff +#define YUCCA_PCIE_LOWER_MEM 0x90000000 +#define YUCCA_PCIE_MEM_SIZE 0x10000000 + +#define YUCCA_PCIX_MEM_SIZE 0x10000000 +#define YUCCA_PCIX_MEM_OFFSET 0x00000000 +#define YUCCA_PCIE_MEM_SIZE 0x10000000 +#define YUCCA_PCIE_MEM_OFFSET 0x00000000 + +#endif /* __ASM_YUCCA_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/ppc/platforms/85xx/mpc85xx_ads_common.c b/arch/ppc/platforms/85xx/mpc85xx_ads_common.c index bd3ac0136756bc260c31cec5f0686826d055adcd..16ad092d8a06396a4ffed0f44037c5dce99a44ec 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_ads_common.c +++ b/arch/ppc/platforms/85xx/mpc85xx_ads_common.c @@ -45,6 +45,8 @@ #include +#include + #include #ifndef CONFIG_PCI @@ -189,3 +191,11 @@ mpc85xx_exclude_device(u_char bus, u_char devfn) } #endif /* CONFIG_PCI */ + +#ifdef CONFIG_RAPIDIO +void platform_rio_init(void) +{ + /* 512MB RIO LAW at 0xc0000000 */ + mpc85xx_rio_setup(0xc0000000, 0x20000000); +} +#endif /* CONFIG_RAPIDIO */ diff --git a/arch/ppc/platforms/85xx/stx_gp3.c b/arch/ppc/platforms/85xx/stx_gp3.c index 1e1b85f8193a480a12030e7e84f6c07ff9fdbabb..15ce9d070634eb26793e2800365674d5ddc84cb7 100644 --- a/arch/ppc/platforms/85xx/stx_gp3.c +++ b/arch/ppc/platforms/85xx/stx_gp3.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -57,6 +58,7 @@ #include #include +#include unsigned char __res[sizeof(bd_t)]; @@ -273,6 +275,18 @@ int mpc85xx_exclude_device(u_char bus, u_char devfn) } #endif /* CONFIG_PCI */ +#ifdef CONFIG_RAPIDIO +void +platform_rio_init(void) +{ + /* + * The STx firmware configures the RapidIO Local Access Window + * at 0xc0000000 with a size of 512MB. + */ + mpc85xx_rio_setup(0xc0000000, 0x20000000); +} +#endif /* CONFIG_RAPIDIO */ + void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) diff --git a/arch/ppc/platforms/ev64360.c b/arch/ppc/platforms/ev64360.c index b1324564456e80e28c220c113a4608022d9ace2e..b9d844f88c2bc8088ebbab314a8498e860e93238 100644 --- a/arch/ppc/platforms/ev64360.c +++ b/arch/ppc/platforms/ev64360.c @@ -52,6 +52,8 @@ static u32 ev64360_bus_frequency; unsigned char __res[sizeof(bd_t)]; +TODC_ALLOC(); + static int __init ev64360_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) { @@ -182,6 +184,9 @@ ev64360_setup_peripherals(void) EV64360_RTC_WINDOW_BASE, EV64360_RTC_WINDOW_SIZE, 0); bh.ci->enable_window_32bit(&bh, MV64x60_CPU2DEV_1_WIN); + TODC_INIT(TODC_TYPE_DS1501, 0, 0, + ioremap(EV64360_RTC_WINDOW_BASE, EV64360_RTC_WINDOW_SIZE), 8); + mv64x60_set_32bit_window(&bh, MV64x60_CPU2SRAM_WIN, EV64360_INTERNAL_SRAM_BASE, MV64360_SRAM_SIZE, 0); bh.ci->enable_window_32bit(&bh, MV64x60_CPU2SRAM_WIN); @@ -496,6 +501,13 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.power_off = ev64360_power_off; ppc_md.halt = ev64360_halt; ppc_md.find_end_of_memory = ev64360_find_end_of_memory; + ppc_md.init = NULL; + + ppc_md.time_init = todc_time_init; + ppc_md.set_rtc_time = todc_set_rtc_time; + ppc_md.get_rtc_time = todc_get_rtc_time; + ppc_md.nvram_read_val = todc_direct_read_val; + ppc_md.nvram_write_val = todc_direct_write_val; ppc_md.calibrate_decr = ev64360_calibrate_decr; #if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(CONFIG_SERIAL_MPSC_CONSOLE) diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile index b4ef15b45c4ab8306e0e0118a36e6b6a5146ac60..5bd33baac24322d85208114089af1b8edcbc7bec 100644 --- a/arch/ppc/syslib/Makefile +++ b/arch/ppc/syslib/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_440EP) += ibm440gx_common.o obj-$(CONFIG_440GP) += ibm440gp_common.o obj-$(CONFIG_440GX) += ibm440gx_common.o obj-$(CONFIG_440SP) += ibm440gx_common.o ibm440sp_common.o +obj-$(CONFIG_440SPE) += ibm440gx_common.o ibm440sp_common.o ppc440spe_pcie.o ifeq ($(CONFIG_4xx),y) ifeq ($(CONFIG_VIRTEX_II_PRO),y) obj-$(CONFIG_40x) += xilinx_pic.o @@ -32,6 +33,7 @@ obj-$(CONFIG_PPC4xx_DMA) += ppc4xx_dma.o obj-$(CONFIG_PPC4xx_EDMA) += ppc4xx_sgdma.o ifeq ($(CONFIG_40x),y) obj-$(CONFIG_PCI) += pci_auto.o ppc405_pci.o +obj-$(CONFIG_RAPIDIO) += ppc85xx_rio.o endif endif obj-$(CONFIG_8xx) += m8xx_setup.o ppc8xx_pic.o $(wdt-mpc8xx-y) \ @@ -46,12 +48,14 @@ obj-$(CONFIG_BAMBOO) += pci_auto.o todc_time.o obj-$(CONFIG_CPCI690) += todc_time.o pci_auto.o obj-$(CONFIG_EBONY) += pci_auto.o todc_time.o obj-$(CONFIG_EV64260) += todc_time.o pci_auto.o +obj-$(CONFIG_EV64360) += todc_time.o obj-$(CONFIG_CHESTNUT) += mv64360_pic.o pci_auto.o obj-$(CONFIG_GEMINI) += open_pic.o obj-$(CONFIG_GT64260) += gt64260_pic.o obj-$(CONFIG_LOPEC) += pci_auto.o todc_time.o obj-$(CONFIG_HDPU) += pci_auto.o obj-$(CONFIG_LUAN) += pci_auto.o todc_time.o +obj-$(CONFIG_YUCCA) += pci_auto.o todc_time.o obj-$(CONFIG_KATANA) += pci_auto.o obj-$(CONFIG_MV64360) += mv64360_pic.o obj-$(CONFIG_MV64X60) += mv64x60.o mv64x60_win.o diff --git a/arch/ppc/syslib/ibm440sp_common.c b/arch/ppc/syslib/ibm440sp_common.c index 417d4cff77a0d5a3e4acaecb74fa8b28ee0dbf8f..cdafda127d81f1a5615e133f110e53513542671f 100644 --- a/arch/ppc/syslib/ibm440sp_common.c +++ b/arch/ppc/syslib/ibm440sp_common.c @@ -1,7 +1,7 @@ /* * arch/ppc/syslib/ibm440sp_common.c * - * PPC440SP system library + * PPC440SP/PPC440SPe system library * * Matt Porter * Copyright 2002-2005 MontaVista Software Inc. @@ -35,7 +35,7 @@ unsigned long __init ibm440sp_find_end_of_memory(void) u32 mem_size = 0; /* Read two bank sizes and sum */ - for (i=0; i<2; i++) + for (i=0; i< MQ0_NUM_BANKS; i++) switch (mfdcr(DCRN_MQ0_BS0BAS + i) & MQ0_CONFIG_SIZE_MASK) { case MQ0_CONFIG_SIZE_8M: mem_size += PPC44x_MEM_SIZE_8M; diff --git a/arch/ppc/syslib/ibm44x_common.c b/arch/ppc/syslib/ibm44x_common.c index 5152c8e41340cca5f0a4437dd4fdb6c697b9677f..71db11d2215840016704ff8768418e655358f3b2 100644 --- a/arch/ppc/syslib/ibm44x_common.c +++ b/arch/ppc/syslib/ibm44x_common.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -214,9 +215,20 @@ void __init ibm44x_platform_init(unsigned long r3, unsigned long r4, unsigned lo /* Called from machine_check_exception */ void platform_machine_check(struct pt_regs *regs) { +#if defined(CONFIG_440SP) || defined(CONFIG_440SPE) + printk("PLB0: BEAR=0x%08x%08x ACR= 0x%08x BESR= 0x%08x%08x\n", + mfdcr(DCRN_PLB0_BEARH), mfdcr(DCRN_PLB0_BEARL), + mfdcr(DCRN_PLB0_ACR), mfdcr(DCRN_PLB0_BESRH), + mfdcr(DCRN_PLB0_BESRL)); + printk("PLB1: BEAR=0x%08x%08x ACR= 0x%08x BESR= 0x%08x%08x\n", + mfdcr(DCRN_PLB1_BEARH), mfdcr(DCRN_PLB1_BEARL), + mfdcr(DCRN_PLB1_ACR), mfdcr(DCRN_PLB1_BESRH), + mfdcr(DCRN_PLB1_BESRL)); +#else printk("PLB0: BEAR=0x%08x%08x ACR= 0x%08x BESR= 0x%08x\n", mfdcr(DCRN_PLB0_BEARH), mfdcr(DCRN_PLB0_BEARL), mfdcr(DCRN_PLB0_ACR), mfdcr(DCRN_PLB0_BESR)); +#endif printk("POB0: BEAR=0x%08x%08x BESR0=0x%08x BESR1=0x%08x\n", mfdcr(DCRN_POB0_BEARH), mfdcr(DCRN_POB0_BEARL), mfdcr(DCRN_POB0_BESR0), mfdcr(DCRN_POB0_BESR1)); diff --git a/arch/ppc/syslib/m8xx_wdt.c b/arch/ppc/syslib/m8xx_wdt.c index c5ac5ce5d7d2d29e1cdac44f15cd24ee5e95447d..a21632d37e5ab7263f498664ef08ff448625086e 100644 --- a/arch/ppc/syslib/m8xx_wdt.c +++ b/arch/ppc/syslib/m8xx_wdt.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -29,8 +30,8 @@ void m8xx_wdt_reset(void) { volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR; - out_be16(imap->im_siu_conf.sc_swsr, 0x556c); /* write magic1 */ - out_be16(imap->im_siu_conf.sc_swsr, 0xaa39); /* write magic2 */ + out_be16(&imap->im_siu_conf.sc_swsr, 0x556c); /* write magic1 */ + out_be16(&imap->im_siu_conf.sc_swsr, 0xaa39); /* write magic2 */ } static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev, struct pt_regs *regs) @@ -39,7 +40,7 @@ static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev, struct pt_regs *regs) m8xx_wdt_reset(); - out_be16(imap->im_sit.sit_piscr, in_be16(imap->im_sit.sit_piscr | PISCR_PS)); /* clear irq */ + out_be16(&imap->im_sit.sit_piscr, in_be16(&imap->im_sit.sit_piscr) | PISCR_PS); /* clear irq */ return IRQ_HANDLED; } @@ -51,7 +52,7 @@ void __init m8xx_wdt_handler_install(bd_t * binfo) u32 sypcr; u32 pitrtclk; - sypcr = in_be32(imap->im_siu_conf.sc_sypcr); + sypcr = in_be32(&imap->im_siu_conf.sc_sypcr); if (!(sypcr & 0x04)) { printk(KERN_NOTICE "m8xx_wdt: wdt disabled (SYPCR: 0x%08X)\n", @@ -87,9 +88,9 @@ void __init m8xx_wdt_handler_install(bd_t * binfo) else pitc = pitrtclk * wdt_timeout / binfo->bi_intfreq / 2; - out_be32(imap->im_sit.sit_pitc, pitc << 16); + out_be32(&imap->im_sit.sit_pitc, pitc << 16); - out_be16(imap->im_sit.sit_piscr, (mk_int_int_mask(PIT_INTERRUPT) << 8) | PISCR_PIE | PISCR_PTE); + out_be16(&imap->im_sit.sit_piscr, (mk_int_int_mask(PIT_INTERRUPT) << 8) | PISCR_PIE | PISCR_PTE); if (setup_irq(PIT_INTERRUPT, &m8xx_wdt_irqaction)) panic("m8xx_wdt: error setting up the watchdog irq!"); diff --git a/arch/ppc/syslib/ppc405_pci.c b/arch/ppc/syslib/ppc405_pci.c index 81c83bf98df49fb10a20e953b422464eb42d7ce4..d6d838b16dacf65542fcfb532ef5fb3cd58ed009 100644 --- a/arch/ppc/syslib/ppc405_pci.c +++ b/arch/ppc/syslib/ppc405_pci.c @@ -89,13 +89,6 @@ ppc4xx_find_bridges(void) isa_mem_base = 0; pci_dram_offset = 0; -#if (PSR_PCI_ARBIT_EN > 1) - /* Check if running in slave mode */ - if ((mfdcr(DCRN_CHPSR) & PSR_PCI_ARBIT_EN) == 0) { - printk("Running as PCI slave, kernel PCI disabled !\n"); - return; - } -#endif /* Setup PCI32 hose */ hose_a = pcibios_alloc_controller(); if (!hose_a) diff --git a/arch/ppc/syslib/ppc440spe_pcie.c b/arch/ppc/syslib/ppc440spe_pcie.c new file mode 100644 index 0000000000000000000000000000000000000000..1509fc1ddfb647558106799f8861d7a998cc2be4 --- /dev/null +++ b/arch/ppc/syslib/ppc440spe_pcie.c @@ -0,0 +1,442 @@ +/* + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Roland Dreier + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ppc440spe_pcie.h" + +static int +pcie_read_config(struct pci_bus *bus, unsigned int devfn, int offset, + int len, u32 *val) +{ + struct pci_controller *hose = bus->sysdata; + + if (PCI_SLOT(devfn) != 1) + return PCIBIOS_DEVICE_NOT_FOUND; + + offset += devfn << 12; + + /* + * Note: the caller has already checked that offset is + * suitably aligned and that len is 1, 2 or 4. + */ + switch (len) { + case 1: + *val = in_8(hose->cfg_data + offset); + break; + case 2: + *val = in_le16(hose->cfg_data + offset); + break; + default: + *val = in_le32(hose->cfg_data + offset); + break; + } + + if (0) printk("%s: read %x(%d) @ %x\n", __func__, *val, len, offset); + + return PCIBIOS_SUCCESSFUL; +} + +static int +pcie_write_config(struct pci_bus *bus, unsigned int devfn, int offset, + int len, u32 val) +{ + struct pci_controller *hose = bus->sysdata; + + if (PCI_SLOT(devfn) != 1) + return PCIBIOS_DEVICE_NOT_FOUND; + + offset += devfn << 12; + + switch (len) { + case 1: + out_8(hose->cfg_data + offset, val); + break; + case 2: + out_le16(hose->cfg_data + offset, val); + break; + default: + out_le32(hose->cfg_data + offset, val); + break; + } + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops pcie_pci_ops = +{ + .read = pcie_read_config, + .write = pcie_write_config +}; + +enum { + PTYPE_ENDPOINT = 0x0, + PTYPE_LEGACY_ENDPOINT = 0x1, + PTYPE_ROOT_PORT = 0x4, + + LNKW_X1 = 0x1, + LNKW_X4 = 0x4, + LNKW_X8 = 0x8 +}; + +static void check_error(void) +{ + u32 valPE0, valPE1, valPE2; + + /* SDR0_PEGPLLLCT1 reset */ + if (!(valPE0 = SDR_READ(PESDR0_PLLLCT1) & 0x01000000)) { + printk(KERN_INFO "PCIE: SDR0_PEGPLLLCT1 reset error 0x%8x\n", valPE0); + } + + valPE0 = SDR_READ(PESDR0_RCSSET); + valPE1 = SDR_READ(PESDR1_RCSSET); + valPE2 = SDR_READ(PESDR2_RCSSET); + + /* SDR0_PExRCSSET rstgu */ + if ( !(valPE0 & 0x01000000) || + !(valPE1 & 0x01000000) || + !(valPE2 & 0x01000000)) { + printk(KERN_INFO "PCIE: SDR0_PExRCSSET rstgu error\n"); + } + + /* SDR0_PExRCSSET rstdl */ + if ( !(valPE0 & 0x00010000) || + !(valPE1 & 0x00010000) || + !(valPE2 & 0x00010000)) { + printk(KERN_INFO "PCIE: SDR0_PExRCSSET rstdl error\n"); + } + + /* SDR0_PExRCSSET rstpyn */ + if ( (valPE0 & 0x00001000) || + (valPE1 & 0x00001000) || + (valPE2 & 0x00001000)) { + printk(KERN_INFO "PCIE: SDR0_PExRCSSET rstpyn error\n"); + } + + /* SDR0_PExRCSSET hldplb */ + if ( (valPE0 & 0x10000000) || + (valPE1 & 0x10000000) || + (valPE2 & 0x10000000)) { + printk(KERN_INFO "PCIE: SDR0_PExRCSSET hldplb error\n"); + } + + /* SDR0_PExRCSSET rdy */ + if ( (valPE0 & 0x00100000) || + (valPE1 & 0x00100000) || + (valPE2 & 0x00100000)) { + printk(KERN_INFO "PCIE: SDR0_PExRCSSET rdy error\n"); + } + + /* SDR0_PExRCSSET shutdown */ + if ( (valPE0 & 0x00000100) || + (valPE1 & 0x00000100) || + (valPE2 & 0x00000100)) { + printk(KERN_INFO "PCIE: SDR0_PExRCSSET shutdown error\n"); + } +} + +/* + * Initialize PCI Express core as described in User Manual section 27.12.1 + */ +int ppc440spe_init_pcie(void) +{ + /* Set PLL clock receiver to LVPECL */ + SDR_WRITE(PESDR0_PLLLCT1, SDR_READ(PESDR0_PLLLCT1) | 1 << 28); + + check_error(); + + printk(KERN_INFO "PCIE initialization OK\n"); + + if (!(SDR_READ(PESDR0_PLLLCT2) & 0x10000)) + printk(KERN_INFO "PESDR_PLLCT2 resistance calibration failed (0x%08x)\n", + SDR_READ(PESDR0_PLLLCT2)); + + /* De-assert reset of PCIe PLL, wait for lock */ + SDR_WRITE(PESDR0_PLLLCT1, SDR_READ(PESDR0_PLLLCT1) & ~(1 << 24)); + udelay(3); + + return 0; +} + +int ppc440spe_init_pcie_rootport(int port) +{ + static int core_init; + void __iomem *utl_base; + u32 val = 0; + int i; + + if (!core_init) { + ++core_init; + i = ppc440spe_init_pcie(); + if (i) + return i; + } + + /* + * Initialize various parts of the PCI Express core for our port: + * + * - Set as a root port and enable max width + * (PXIE0 -> X8, PCIE1 and PCIE2 -> X4). + * - Set up UTL configuration. + * - Increase SERDES drive strength to levels suggested by AMCC. + * - De-assert RSTPYN, RSTDL and RSTGU. + */ + switch (port) { + case 0: + SDR_WRITE(PESDR0_DLPSET, PTYPE_ROOT_PORT << 20 | LNKW_X8 << 12); + + SDR_WRITE(PESDR0_UTLSET1, 0x21222222); + SDR_WRITE(PESDR0_UTLSET2, 0x11000000); + + SDR_WRITE(PESDR0_HSSL0SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL1SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL2SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL3SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL4SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL5SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL6SET1, 0x35000000); + SDR_WRITE(PESDR0_HSSL7SET1, 0x35000000); + + SDR_WRITE(PESDR0_RCSSET, + (SDR_READ(PESDR0_RCSSET) & ~(1 << 24 | 1 << 16)) | 1 << 12); + break; + + case 1: + SDR_WRITE(PESDR1_DLPSET, PTYPE_ROOT_PORT << 20 | LNKW_X4 << 12); + + SDR_WRITE(PESDR1_UTLSET1, 0x21222222); + SDR_WRITE(PESDR1_UTLSET2, 0x11000000); + + SDR_WRITE(PESDR1_HSSL0SET1, 0x35000000); + SDR_WRITE(PESDR1_HSSL1SET1, 0x35000000); + SDR_WRITE(PESDR1_HSSL2SET1, 0x35000000); + SDR_WRITE(PESDR1_HSSL3SET1, 0x35000000); + + SDR_WRITE(PESDR1_RCSSET, + (SDR_READ(PESDR1_RCSSET) & ~(1 << 24 | 1 << 16)) | 1 << 12); + break; + + case 2: + SDR_WRITE(PESDR2_DLPSET, PTYPE_ROOT_PORT << 20 | LNKW_X4 << 12); + + SDR_WRITE(PESDR2_UTLSET1, 0x21222222); + SDR_WRITE(PESDR2_UTLSET2, 0x11000000); + + SDR_WRITE(PESDR2_HSSL0SET1, 0x35000000); + SDR_WRITE(PESDR2_HSSL1SET1, 0x35000000); + SDR_WRITE(PESDR2_HSSL2SET1, 0x35000000); + SDR_WRITE(PESDR2_HSSL3SET1, 0x35000000); + + SDR_WRITE(PESDR2_RCSSET, + (SDR_READ(PESDR2_RCSSET) & ~(1 << 24 | 1 << 16)) | 1 << 12); + break; + } + + mdelay(1000); + + switch (port) { + case 0: val = SDR_READ(PESDR0_RCSSTS); break; + case 1: val = SDR_READ(PESDR1_RCSSTS); break; + case 2: val = SDR_READ(PESDR2_RCSSTS); break; + } + + if (!(val & (1 << 20))) + printk(KERN_INFO "PCIE%d: PGRST inactive\n", port); + else + printk(KERN_WARNING "PGRST for PCIE%d failed %08x\n", port, val); + + switch (port) { + case 0: printk(KERN_INFO "PCIE0: LOOP %08x\n", SDR_READ(PESDR0_LOOP)); break; + case 1: printk(KERN_INFO "PCIE1: LOOP %08x\n", SDR_READ(PESDR1_LOOP)); break; + case 2: printk(KERN_INFO "PCIE2: LOOP %08x\n", SDR_READ(PESDR2_LOOP)); break; + } + + /* + * Map UTL registers at 0xc_1000_0n00 + */ + switch (port) { + case 0: + mtdcr(DCRN_PEGPL_REGBAH(PCIE0), 0x0000000c); + mtdcr(DCRN_PEGPL_REGBAL(PCIE0), 0x10000000); + mtdcr(DCRN_PEGPL_REGMSK(PCIE0), 0x00007001); + mtdcr(DCRN_PEGPL_SPECIAL(PCIE0), 0x68782800); + break; + + case 1: + mtdcr(DCRN_PEGPL_REGBAH(PCIE1), 0x0000000c); + mtdcr(DCRN_PEGPL_REGBAL(PCIE1), 0x10001000); + mtdcr(DCRN_PEGPL_REGMSK(PCIE1), 0x00007001); + mtdcr(DCRN_PEGPL_SPECIAL(PCIE1), 0x68782800); + break; + + case 2: + mtdcr(DCRN_PEGPL_REGBAH(PCIE2), 0x0000000c); + mtdcr(DCRN_PEGPL_REGBAL(PCIE2), 0x10002000); + mtdcr(DCRN_PEGPL_REGMSK(PCIE2), 0x00007001); + mtdcr(DCRN_PEGPL_SPECIAL(PCIE2), 0x68782800); + } + + utl_base = ioremap64(0xc10000000ull + 0x1000 * port, 0x100); + + /* + * Set buffer allocations and then assert VRB and TXE. + */ + out_be32(utl_base + PEUTL_OUTTR, 0x08000000); + out_be32(utl_base + PEUTL_INTR, 0x02000000); + out_be32(utl_base + PEUTL_OPDBSZ, 0x10000000); + out_be32(utl_base + PEUTL_PBBSZ, 0x53000000); + out_be32(utl_base + PEUTL_IPHBSZ, 0x08000000); + out_be32(utl_base + PEUTL_IPDBSZ, 0x10000000); + out_be32(utl_base + PEUTL_RCIRQEN, 0x00f00000); + out_be32(utl_base + PEUTL_PCTL, 0x80800066); + + iounmap(utl_base); + + /* + * We map PCI Express configuration access into the 512MB regions + * PCIE0: 0xc_4000_0000 + * PCIE1: 0xc_8000_0000 + * PCIE2: 0xc_c000_0000 + */ + switch (port) { + case 0: + mtdcr(DCRN_PEGPL_CFGBAH(PCIE0), 0x0000000c); + mtdcr(DCRN_PEGPL_CFGBAL(PCIE0), 0x40000000); + mtdcr(DCRN_PEGPL_CFGMSK(PCIE0), 0xe0000001); /* 512MB region, valid */ + break; + + case 1: + mtdcr(DCRN_PEGPL_CFGBAH(PCIE1), 0x0000000c); + mtdcr(DCRN_PEGPL_CFGBAL(PCIE1), 0x80000000); + mtdcr(DCRN_PEGPL_CFGMSK(PCIE1), 0xe0000001); /* 512MB region, valid */ + break; + + case 2: + mtdcr(DCRN_PEGPL_CFGBAH(PCIE2), 0x0000000c); + mtdcr(DCRN_PEGPL_CFGBAL(PCIE2), 0xc0000000); + mtdcr(DCRN_PEGPL_CFGMSK(PCIE2), 0xe0000001); /* 512MB region, valid */ + break; + } + + /* + * Check for VC0 active and assert RDY. + */ + switch (port) { + case 0: + if (!(SDR_READ(PESDR0_RCSSTS) & (1 << 16))) + printk(KERN_WARNING "PCIE0: VC0 not active\n"); + SDR_WRITE(PESDR0_RCSSET, SDR_READ(PESDR0_RCSSET) | 1 << 20); + break; + case 1: + if (!(SDR_READ(PESDR1_RCSSTS) & (1 << 16))) + printk(KERN_WARNING "PCIE0: VC0 not active\n"); + SDR_WRITE(PESDR1_RCSSET, SDR_READ(PESDR1_RCSSET) | 1 << 20); + break; + case 2: + if (!(SDR_READ(PESDR2_RCSSTS) & (1 << 16))) + printk(KERN_WARNING "PCIE0: VC0 not active\n"); + SDR_WRITE(PESDR2_RCSSET, SDR_READ(PESDR2_RCSSET) | 1 << 20); + break; + } + +#if 0 + /* Dump all config regs */ + for (i = 0x300; i <= 0x320; ++i) + printk("[%04x] 0x%08x\n", i, SDR_READ(i)); + for (i = 0x340; i <= 0x353; ++i) + printk("[%04x] 0x%08x\n", i, SDR_READ(i)); + for (i = 0x370; i <= 0x383; ++i) + printk("[%04x] 0x%08x\n", i, SDR_READ(i)); + for (i = 0x3a0; i <= 0x3a2; ++i) + printk("[%04x] 0x%08x\n", i, SDR_READ(i)); + for (i = 0x3c0; i <= 0x3c3; ++i) + printk("[%04x] 0x%08x\n", i, SDR_READ(i)); +#endif + + mdelay(100); + + return 0; +} + +void ppc440spe_setup_pcie(struct pci_controller *hose, int port) +{ + void __iomem *mbase; + + /* + * Map 16MB, which is enough for 4 bits of bus # + */ + hose->cfg_data = ioremap64(0xc40000000ull + port * 0x40000000, + 1 << 24); + hose->ops = &pcie_pci_ops; + + /* + * Set bus numbers on our root port + */ + mbase = ioremap64(0xc50000000ull + port * 0x40000000, 4096); + out_8(mbase + PCI_PRIMARY_BUS, 0); + out_8(mbase + PCI_SECONDARY_BUS, 0); + + /* + * Set up outbound translation to hose->mem_space from PLB + * addresses at an offset of 0xd_0000_0000. We set the low + * bits of the mask to 11 to turn off splitting into 8 + * subregions and to enable the outbound translation. + */ + out_le32(mbase + PECFG_POM0LAH, 0); + out_le32(mbase + PECFG_POM0LAL, hose->mem_space.start); + + switch (port) { + case 0: + mtdcr(DCRN_PEGPL_OMR1BAH(PCIE0), 0x0000000d); + mtdcr(DCRN_PEGPL_OMR1BAL(PCIE0), hose->mem_space.start); + mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE0), 0x7fffffff); + mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE0), + ~(hose->mem_space.end - hose->mem_space.start) | 3); + break; + case 1: + mtdcr(DCRN_PEGPL_OMR1BAH(PCIE1), 0x0000000d); + mtdcr(DCRN_PEGPL_OMR1BAL(PCIE1), hose->mem_space.start); + mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE1), 0x7fffffff); + mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE1), + ~(hose->mem_space.end - hose->mem_space.start) | 3); + + break; + case 2: + mtdcr(DCRN_PEGPL_OMR1BAH(PCIE2), 0x0000000d); + mtdcr(DCRN_PEGPL_OMR1BAL(PCIE2), hose->mem_space.start); + mtdcr(DCRN_PEGPL_OMR1MSKH(PCIE2), 0x7fffffff); + mtdcr(DCRN_PEGPL_OMR1MSKL(PCIE2), + ~(hose->mem_space.end - hose->mem_space.start) | 3); + break; + } + + /* Set up 16GB inbound memory window at 0 */ + out_le32(mbase + PCI_BASE_ADDRESS_0, 0); + out_le32(mbase + PCI_BASE_ADDRESS_1, 0); + out_le32(mbase + PECFG_BAR0HMPA, 0x7fffffc); + out_le32(mbase + PECFG_BAR0LMPA, 0); + out_le32(mbase + PECFG_PIM0LAL, 0); + out_le32(mbase + PECFG_PIM0LAH, 0); + out_le32(mbase + PECFG_PIMEN, 0x1); + + /* Enable I/O, Mem, and Busmaster cycles */ + out_le16(mbase + PCI_COMMAND, + in_le16(mbase + PCI_COMMAND) | + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + + iounmap(mbase); +} diff --git a/arch/ppc/syslib/ppc440spe_pcie.h b/arch/ppc/syslib/ppc440spe_pcie.h new file mode 100644 index 0000000000000000000000000000000000000000..55b765ad3272b3bbb01f813c7d18a97fd503af0a --- /dev/null +++ b/arch/ppc/syslib/ppc440spe_pcie.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Roland Dreier + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __PPC_SYSLIB_PPC440SPE_PCIE_H +#define __PPC_SYSLIB_PPC440SPE_PCIE_H + +#define DCRN_SDR0_CFGADDR 0x00e +#define DCRN_SDR0_CFGDATA 0x00f + +#define DCRN_PCIE0_BASE 0x100 +#define DCRN_PCIE1_BASE 0x120 +#define DCRN_PCIE2_BASE 0x140 +#define PCIE0 DCRN_PCIE0_BASE +#define PCIE1 DCRN_PCIE1_BASE +#define PCIE2 DCRN_PCIE2_BASE + +#define DCRN_PEGPL_CFGBAH(base) (base + 0x00) +#define DCRN_PEGPL_CFGBAL(base) (base + 0x01) +#define DCRN_PEGPL_CFGMSK(base) (base + 0x02) +#define DCRN_PEGPL_MSGBAH(base) (base + 0x03) +#define DCRN_PEGPL_MSGBAL(base) (base + 0x04) +#define DCRN_PEGPL_MSGMSK(base) (base + 0x05) +#define DCRN_PEGPL_OMR1BAH(base) (base + 0x06) +#define DCRN_PEGPL_OMR1BAL(base) (base + 0x07) +#define DCRN_PEGPL_OMR1MSKH(base) (base + 0x08) +#define DCRN_PEGPL_OMR1MSKL(base) (base + 0x09) +#define DCRN_PEGPL_REGBAH(base) (base + 0x12) +#define DCRN_PEGPL_REGBAL(base) (base + 0x13) +#define DCRN_PEGPL_REGMSK(base) (base + 0x14) +#define DCRN_PEGPL_SPECIAL(base) (base + 0x15) + +/* + * System DCRs (SDRs) + */ +#define PESDR0_PLLLCT1 0x03a0 +#define PESDR0_PLLLCT2 0x03a1 +#define PESDR0_PLLLCT3 0x03a2 + +#define PESDR0_UTLSET1 0x0300 +#define PESDR0_UTLSET2 0x0301 +#define PESDR0_DLPSET 0x0302 +#define PESDR0_LOOP 0x0303 +#define PESDR0_RCSSET 0x0304 +#define PESDR0_RCSSTS 0x0305 +#define PESDR0_HSSL0SET1 0x0306 +#define PESDR0_HSSL0SET2 0x0307 +#define PESDR0_HSSL0STS 0x0308 +#define PESDR0_HSSL1SET1 0x0309 +#define PESDR0_HSSL1SET2 0x030a +#define PESDR0_HSSL1STS 0x030b +#define PESDR0_HSSL2SET1 0x030c +#define PESDR0_HSSL2SET2 0x030d +#define PESDR0_HSSL2STS 0x030e +#define PESDR0_HSSL3SET1 0x030f +#define PESDR0_HSSL3SET2 0x0310 +#define PESDR0_HSSL3STS 0x0311 +#define PESDR0_HSSL4SET1 0x0312 +#define PESDR0_HSSL4SET2 0x0313 +#define PESDR0_HSSL4STS 0x0314 +#define PESDR0_HSSL5SET1 0x0315 +#define PESDR0_HSSL5SET2 0x0316 +#define PESDR0_HSSL5STS 0x0317 +#define PESDR0_HSSL6SET1 0x0318 +#define PESDR0_HSSL6SET2 0x0319 +#define PESDR0_HSSL6STS 0x031a +#define PESDR0_HSSL7SET1 0x031b +#define PESDR0_HSSL7SET2 0x031c +#define PESDR0_HSSL7STS 0x031d +#define PESDR0_HSSCTLSET 0x031e +#define PESDR0_LANE_ABCD 0x031f +#define PESDR0_LANE_EFGH 0x0320 + +#define PESDR1_UTLSET1 0x0340 +#define PESDR1_UTLSET2 0x0341 +#define PESDR1_DLPSET 0x0342 +#define PESDR1_LOOP 0x0343 +#define PESDR1_RCSSET 0x0344 +#define PESDR1_RCSSTS 0x0345 +#define PESDR1_HSSL0SET1 0x0346 +#define PESDR1_HSSL0SET2 0x0347 +#define PESDR1_HSSL0STS 0x0348 +#define PESDR1_HSSL1SET1 0x0349 +#define PESDR1_HSSL1SET2 0x034a +#define PESDR1_HSSL1STS 0x034b +#define PESDR1_HSSL2SET1 0x034c +#define PESDR1_HSSL2SET2 0x034d +#define PESDR1_HSSL2STS 0x034e +#define PESDR1_HSSL3SET1 0x034f +#define PESDR1_HSSL3SET2 0x0350 +#define PESDR1_HSSL3STS 0x0351 +#define PESDR1_HSSCTLSET 0x0352 +#define PESDR1_LANE_ABCD 0x0353 + +#define PESDR2_UTLSET1 0x0370 +#define PESDR2_UTLSET2 0x0371 +#define PESDR2_DLPSET 0x0372 +#define PESDR2_LOOP 0x0373 +#define PESDR2_RCSSET 0x0374 +#define PESDR2_RCSSTS 0x0375 +#define PESDR2_HSSL0SET1 0x0376 +#define PESDR2_HSSL0SET2 0x0377 +#define PESDR2_HSSL0STS 0x0378 +#define PESDR2_HSSL1SET1 0x0379 +#define PESDR2_HSSL1SET2 0x037a +#define PESDR2_HSSL1STS 0x037b +#define PESDR2_HSSL2SET1 0x037c +#define PESDR2_HSSL2SET2 0x037d +#define PESDR2_HSSL2STS 0x037e +#define PESDR2_HSSL3SET1 0x037f +#define PESDR2_HSSL3SET2 0x0380 +#define PESDR2_HSSL3STS 0x0381 +#define PESDR2_HSSCTLSET 0x0382 +#define PESDR2_LANE_ABCD 0x0383 + +/* + * UTL register offsets + */ +#define PEUTL_PBBSZ 0x20 +#define PEUTL_OPDBSZ 0x68 +#define PEUTL_IPHBSZ 0x70 +#define PEUTL_IPDBSZ 0x78 +#define PEUTL_OUTTR 0x90 +#define PEUTL_INTR 0x98 +#define PEUTL_PCTL 0xa0 +#define PEUTL_RCIRQEN 0xb8 + +/* + * Config space register offsets + */ +#define PECFG_BAR0LMPA 0x210 +#define PECFG_BAR0HMPA 0x214 +#define PECFG_PIMEN 0x33c +#define PECFG_PIM0LAL 0x340 +#define PECFG_PIM0LAH 0x344 +#define PECFG_POM0LAL 0x380 +#define PECFG_POM0LAH 0x384 + +int ppc440spe_init_pcie(void); +int ppc440spe_init_pcie_rootport(int port); +void ppc440spe_setup_pcie(struct pci_controller *hose, int port); + +#endif /* __PPC_SYSLIB_PPC440SPE_PCIE_H */ diff --git a/arch/ppc/syslib/ppc4xx_pic.c b/arch/ppc/syslib/ppc4xx_pic.c index 0b435633a0d174da0991570bf73cacc6406108c0..aa4165144ec27481c61ea55b286d5c51557e34a0 100644 --- a/arch/ppc/syslib/ppc4xx_pic.c +++ b/arch/ppc/syslib/ppc4xx_pic.c @@ -38,6 +38,7 @@ extern unsigned char ppc4xx_uic_ext_irq_cfg[] __attribute__ ((weak)); #define IRQ_MASK_UICx(irq) (1 << (31 - ((irq) & 0x1f))) #define IRQ_MASK_UIC1(irq) IRQ_MASK_UICx(irq) #define IRQ_MASK_UIC2(irq) IRQ_MASK_UICx(irq) +#define IRQ_MASK_UIC3(irq) IRQ_MASK_UICx(irq) #define UIC_HANDLERS(n) \ static void ppc4xx_uic##n##_enable(unsigned int irq) \ @@ -88,7 +89,38 @@ static void ppc4xx_uic##n##_end(unsigned int irq) \ .end = ppc4xx_uic##n##_end, \ } \ -#if NR_UICS == 3 +#if NR_UICS == 4 +#define ACK_UIC0_PARENT +#define ACK_UIC1_PARENT mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC1NC); +#define ACK_UIC2_PARENT mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC2NC); +#define ACK_UIC3_PARENT mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC3NC); +UIC_HANDLERS(0); +UIC_HANDLERS(1); +UIC_HANDLERS(2); +UIC_HANDLERS(3); + +static int ppc4xx_pic_get_irq(struct pt_regs *regs) +{ + u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0)); + if (uic0 & UIC0_UIC1NC) + return 64 - ffs(mfdcr(DCRN_UIC_MSR(UIC1))); + else if (uic0 & UIC0_UIC2NC) + return 96 - ffs(mfdcr(DCRN_UIC_MSR(UIC2))); + else if (uic0 & UIC0_UIC3NC) + return 128 - ffs(mfdcr(DCRN_UIC_MSR(UIC3))); + else + return uic0 ? 32 - ffs(uic0) : -1; +} + +static void __init ppc4xx_pic_impl_init(void) +{ + /* Enable cascade interrupts in UIC0 */ + ppc_cached_irq_mask[0] |= UIC0_UIC1NC | UIC0_UIC2NC | UIC0_UIC3NC; + mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC1NC | UIC0_UIC2NC | UIC0_UIC3NC); + mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[0]); +} + +#elif NR_UICS == 3 #define ACK_UIC0_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC0NC); #define ACK_UIC1_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC1NC); #define ACK_UIC2_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC2NC); @@ -170,6 +202,9 @@ static struct ppc4xx_uic_impl { { .decl = DECLARE_UIC(1), .base = UIC1 }, #if NR_UICS > 2 { .decl = DECLARE_UIC(2), .base = UIC2 }, +#if NR_UICS > 3 + { .decl = DECLARE_UIC(3), .base = UIC3 }, +#endif #endif #endif }; diff --git a/arch/ppc/syslib/ppc85xx_rio.c b/arch/ppc/syslib/ppc85xx_rio.c new file mode 100644 index 0000000000000000000000000000000000000000..297f3b549177096d8f421ab836394fb324968f72 --- /dev/null +++ b/arch/ppc/syslib/ppc85xx_rio.c @@ -0,0 +1,938 @@ +/* + * MPC85xx RapidIO support + * + * Copyright 2005 MontaVista Software, Inc. + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define RIO_REGS_BASE (CCSRBAR + 0xc0000) +#define RIO_ATMU_REGS_OFFSET 0x10c00 +#define RIO_MSG_REGS_OFFSET 0x11000 +#define RIO_MAINT_WIN_SIZE 0x400000 +#define RIO_DBELL_WIN_SIZE 0x1000 + +#define RIO_MSG_OMR_MUI 0x00000002 +#define RIO_MSG_OSR_TE 0x00000080 +#define RIO_MSG_OSR_QOI 0x00000020 +#define RIO_MSG_OSR_QFI 0x00000010 +#define RIO_MSG_OSR_MUB 0x00000004 +#define RIO_MSG_OSR_EOMI 0x00000002 +#define RIO_MSG_OSR_QEI 0x00000001 + +#define RIO_MSG_IMR_MI 0x00000002 +#define RIO_MSG_ISR_TE 0x00000080 +#define RIO_MSG_ISR_QFI 0x00000010 +#define RIO_MSG_ISR_DIQI 0x00000001 + +#define RIO_MSG_DESC_SIZE 32 +#define RIO_MSG_BUFFER_SIZE 4096 +#define RIO_MIN_TX_RING_SIZE 2 +#define RIO_MAX_TX_RING_SIZE 2048 +#define RIO_MIN_RX_RING_SIZE 2 +#define RIO_MAX_RX_RING_SIZE 2048 + +#define DOORBELL_DMR_DI 0x00000002 +#define DOORBELL_DSR_TE 0x00000080 +#define DOORBELL_DSR_QFI 0x00000010 +#define DOORBELL_DSR_DIQI 0x00000001 +#define DOORBELL_TID_OFFSET 0x03 +#define DOORBELL_SID_OFFSET 0x05 +#define DOORBELL_INFO_OFFSET 0x06 + +#define DOORBELL_MESSAGE_SIZE 0x08 +#define DBELL_SID(x) (*(u8 *)(x + DOORBELL_SID_OFFSET)) +#define DBELL_TID(x) (*(u8 *)(x + DOORBELL_TID_OFFSET)) +#define DBELL_INF(x) (*(u16 *)(x + DOORBELL_INFO_OFFSET)) + +#define is_power_of_2(x) (((x) & ((x) - 1)) == 0) + +struct rio_atmu_regs { + u32 rowtar; + u32 pad1; + u32 rowbar; + u32 pad2; + u32 rowar; + u32 pad3[3]; +}; + +struct rio_msg_regs { + u32 omr; + u32 osr; + u32 pad1; + u32 odqdpar; + u32 pad2; + u32 osar; + u32 odpr; + u32 odatr; + u32 odcr; + u32 pad3; + u32 odqepar; + u32 pad4[13]; + u32 imr; + u32 isr; + u32 pad5; + u32 ifqdpar; + u32 pad6; + u32 ifqepar; + u32 pad7[250]; + u32 dmr; + u32 dsr; + u32 pad8; + u32 dqdpar; + u32 pad9; + u32 dqepar; + u32 pad10[26]; + u32 pwmr; + u32 pwsr; + u32 pad11; + u32 pwqbar; +}; + +struct rio_tx_desc { + u32 res1; + u32 saddr; + u32 dport; + u32 dattr; + u32 res2; + u32 res3; + u32 dwcnt; + u32 res4; +}; + +static u32 regs_win; +static struct rio_atmu_regs *atmu_regs; +static struct rio_atmu_regs *maint_atmu_regs; +static struct rio_atmu_regs *dbell_atmu_regs; +static u32 dbell_win; +static u32 maint_win; +static struct rio_msg_regs *msg_regs; + +static struct rio_dbell_ring { + void *virt; + dma_addr_t phys; +} dbell_ring; + +static struct rio_msg_tx_ring { + void *virt; + dma_addr_t phys; + void *virt_buffer[RIO_MAX_TX_RING_SIZE]; + dma_addr_t phys_buffer[RIO_MAX_TX_RING_SIZE]; + int tx_slot; + int size; + void *dev_id; +} msg_tx_ring; + +static struct rio_msg_rx_ring { + void *virt; + dma_addr_t phys; + void *virt_buffer[RIO_MAX_RX_RING_SIZE]; + int rx_slot; + int size; + void *dev_id; +} msg_rx_ring; + +/** + * mpc85xx_rio_doorbell_send - Send a MPC85xx doorbell message + * @index: ID of RapidIO interface + * @destid: Destination ID of target device + * @data: 16-bit info field of RapidIO doorbell message + * + * Sends a MPC85xx doorbell message. Returns %0 on success or + * %-EINVAL on failure. + */ +static int mpc85xx_rio_doorbell_send(int index, u16 destid, u16 data) +{ + pr_debug("mpc85xx_doorbell_send: index %d destid %4.4x data %4.4x\n", + index, destid, data); + out_be32((void *)&dbell_atmu_regs->rowtar, destid << 22); + out_be16((void *)(dbell_win), data); + + return 0; +} + +/** + * mpc85xx_local_config_read - Generate a MPC85xx local config space read + * @index: ID of RapdiIO interface + * @offset: Offset into configuration space + * @len: Length (in bytes) of the maintenance transaction + * @data: Value to be read into + * + * Generates a MPC85xx local configuration space read. Returns %0 on + * success or %-EINVAL on failure. + */ +static int mpc85xx_local_config_read(int index, u32 offset, int len, u32 * data) +{ + pr_debug("mpc85xx_local_config_read: index %d offset %8.8x\n", index, + offset); + *data = in_be32((void *)(regs_win + offset)); + + return 0; +} + +/** + * mpc85xx_local_config_write - Generate a MPC85xx local config space write + * @index: ID of RapdiIO interface + * @offset: Offset into configuration space + * @len: Length (in bytes) of the maintenance transaction + * @data: Value to be written + * + * Generates a MPC85xx local configuration space write. Returns %0 on + * success or %-EINVAL on failure. + */ +static int mpc85xx_local_config_write(int index, u32 offset, int len, u32 data) +{ + pr_debug + ("mpc85xx_local_config_write: index %d offset %8.8x data %8.8x\n", + index, offset, data); + out_be32((void *)(regs_win + offset), data); + + return 0; +} + +/** + * mpc85xx_rio_config_read - Generate a MPC85xx read maintenance transaction + * @index: ID of RapdiIO interface + * @destid: Destination ID of transaction + * @hopcount: Number of hops to target device + * @offset: Offset into configuration space + * @len: Length (in bytes) of the maintenance transaction + * @val: Location to be read into + * + * Generates a MPC85xx read maintenance transaction. Returns %0 on + * success or %-EINVAL on failure. + */ +static int +mpc85xx_rio_config_read(int index, u16 destid, u8 hopcount, u32 offset, int len, + u32 * val) +{ + u8 *data; + + pr_debug + ("mpc85xx_rio_config_read: index %d destid %d hopcount %d offset %8.8x len %d\n", + index, destid, hopcount, offset, len); + out_be32((void *)&maint_atmu_regs->rowtar, + (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9)); + + data = (u8 *) maint_win + offset; + switch (len) { + case 1: + *val = in_8((u8 *) data); + break; + case 2: + *val = in_be16((u16 *) data); + break; + default: + *val = in_be32((u32 *) data); + break; + } + + return 0; +} + +/** + * mpc85xx_rio_config_write - Generate a MPC85xx write maintenance transaction + * @index: ID of RapdiIO interface + * @destid: Destination ID of transaction + * @hopcount: Number of hops to target device + * @offset: Offset into configuration space + * @len: Length (in bytes) of the maintenance transaction + * @val: Value to be written + * + * Generates an MPC85xx write maintenance transaction. Returns %0 on + * success or %-EINVAL on failure. + */ +static int +mpc85xx_rio_config_write(int index, u16 destid, u8 hopcount, u32 offset, + int len, u32 val) +{ + u8 *data; + pr_debug + ("mpc85xx_rio_config_write: index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n", + index, destid, hopcount, offset, len, val); + out_be32((void *)&maint_atmu_regs->rowtar, + (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9)); + + data = (u8 *) maint_win + offset; + switch (len) { + case 1: + out_8((u8 *) data, val); + break; + case 2: + out_be16((u16 *) data, val); + break; + default: + out_be32((u32 *) data, val); + break; + } + + return 0; +} + +/** + * rio_hw_add_outb_message - Add message to the MPC85xx outbound message queue + * @mport: Master port with outbound message queue + * @rdev: Target of outbound message + * @mbox: Outbound mailbox + * @buffer: Message to add to outbound queue + * @len: Length of message + * + * Adds the @buffer message to the MPC85xx outbound message queue. Returns + * %0 on success or %-EINVAL on failure. + */ +int +rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, + void *buffer, size_t len) +{ + u32 omr; + struct rio_tx_desc *desc = + (struct rio_tx_desc *)msg_tx_ring.virt + msg_tx_ring.tx_slot; + int ret = 0; + + pr_debug + ("RIO: rio_hw_add_outb_message(): destid %4.4x mbox %d buffer %8.8x len %8.8x\n", + rdev->destid, mbox, (int)buffer, len); + + if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) { + ret = -EINVAL; + goto out; + } + + /* Copy and clear rest of buffer */ + memcpy(msg_tx_ring.virt_buffer[msg_tx_ring.tx_slot], buffer, len); + if (len < (RIO_MAX_MSG_SIZE - 4)) + memset((void *)((u32) msg_tx_ring. + virt_buffer[msg_tx_ring.tx_slot] + len), 0, + RIO_MAX_MSG_SIZE - len); + + /* Set mbox field for message */ + desc->dport = mbox & 0x3; + + /* Enable EOMI interrupt, set priority, and set destid */ + desc->dattr = 0x28000000 | (rdev->destid << 2); + + /* Set transfer size aligned to next power of 2 (in double words) */ + desc->dwcnt = is_power_of_2(len) ? len : 1 << get_bitmask_order(len); + + /* Set snooping and source buffer address */ + desc->saddr = 0x00000004 | msg_tx_ring.phys_buffer[msg_tx_ring.tx_slot]; + + /* Increment enqueue pointer */ + omr = in_be32((void *)&msg_regs->omr); + out_be32((void *)&msg_regs->omr, omr | RIO_MSG_OMR_MUI); + + /* Go to next descriptor */ + if (++msg_tx_ring.tx_slot == msg_tx_ring.size) + msg_tx_ring.tx_slot = 0; + + out: + return ret; +} + +EXPORT_SYMBOL_GPL(rio_hw_add_outb_message); + +/** + * mpc85xx_rio_tx_handler - MPC85xx outbound message interrupt handler + * @irq: Linux interrupt number + * @dev_instance: Pointer to interrupt-specific data + * @regs: Register context + * + * Handles outbound message interrupts. Executes a register outbound + * mailbox event handler and acks the interrupt occurence. + */ +static irqreturn_t +mpc85xx_rio_tx_handler(int irq, void *dev_instance, struct pt_regs *regs) +{ + int osr; + struct rio_mport *port = (struct rio_mport *)dev_instance; + + osr = in_be32((void *)&msg_regs->osr); + + if (osr & RIO_MSG_OSR_TE) { + pr_info("RIO: outbound message transmission error\n"); + out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_TE); + goto out; + } + + if (osr & RIO_MSG_OSR_QOI) { + pr_info("RIO: outbound message queue overflow\n"); + out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_QOI); + goto out; + } + + if (osr & RIO_MSG_OSR_EOMI) { + u32 dqp = in_be32((void *)&msg_regs->odqdpar); + int slot = (dqp - msg_tx_ring.phys) >> 5; + port->outb_msg[0].mcback(port, msg_tx_ring.dev_id, -1, slot); + + /* Ack the end-of-message interrupt */ + out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_EOMI); + } + + out: + return IRQ_HANDLED; +} + +/** + * rio_open_outb_mbox - Initialize MPC85xx outbound mailbox + * @mport: Master port implementing the outbound message unit + * @dev_id: Device specific pointer to pass on event + * @mbox: Mailbox to open + * @entries: Number of entries in the outbound mailbox ring + * + * Initializes buffer ring, request the outbound message interrupt, + * and enables the outbound message unit. Returns %0 on success and + * %-EINVAL or %-ENOMEM on failure. + */ +int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries) +{ + int i, j, rc = 0; + + if ((entries < RIO_MIN_TX_RING_SIZE) || + (entries > RIO_MAX_TX_RING_SIZE) || (!is_power_of_2(entries))) { + rc = -EINVAL; + goto out; + } + + /* Initialize shadow copy ring */ + msg_tx_ring.dev_id = dev_id; + msg_tx_ring.size = entries; + + for (i = 0; i < msg_tx_ring.size; i++) { + if (! + (msg_tx_ring.virt_buffer[i] = + dma_alloc_coherent(NULL, RIO_MSG_BUFFER_SIZE, + &msg_tx_ring.phys_buffer[i], + GFP_KERNEL))) { + rc = -ENOMEM; + for (j = 0; j < msg_tx_ring.size; j++) + if (msg_tx_ring.virt_buffer[j]) + dma_free_coherent(NULL, + RIO_MSG_BUFFER_SIZE, + msg_tx_ring. + virt_buffer[j], + msg_tx_ring. + phys_buffer[j]); + goto out; + } + } + + /* Initialize outbound message descriptor ring */ + if (!(msg_tx_ring.virt = dma_alloc_coherent(NULL, + msg_tx_ring.size * + RIO_MSG_DESC_SIZE, + &msg_tx_ring.phys, + GFP_KERNEL))) { + rc = -ENOMEM; + goto out_dma; + } + memset(msg_tx_ring.virt, 0, msg_tx_ring.size * RIO_MSG_DESC_SIZE); + msg_tx_ring.tx_slot = 0; + + /* Point dequeue/enqueue pointers at first entry in ring */ + out_be32((void *)&msg_regs->odqdpar, msg_tx_ring.phys); + out_be32((void *)&msg_regs->odqepar, msg_tx_ring.phys); + + /* Configure for snooping */ + out_be32((void *)&msg_regs->osar, 0x00000004); + + /* Clear interrupt status */ + out_be32((void *)&msg_regs->osr, 0x000000b3); + + /* Hook up outbound message handler */ + if ((rc = + request_irq(MPC85xx_IRQ_RIO_TX, mpc85xx_rio_tx_handler, 0, + "msg_tx", (void *)mport)) < 0) + goto out_irq; + + /* + * Configure outbound message unit + * Snooping + * Interrupts (all enabled, except QEIE) + * Chaining mode + * Disable + */ + out_be32((void *)&msg_regs->omr, 0x00100220); + + /* Set number of entries */ + out_be32((void *)&msg_regs->omr, + in_be32((void *)&msg_regs->omr) | + ((get_bitmask_order(entries) - 2) << 12)); + + /* Now enable the unit */ + out_be32((void *)&msg_regs->omr, in_be32((void *)&msg_regs->omr) | 0x1); + + out: + return rc; + + out_irq: + dma_free_coherent(NULL, msg_tx_ring.size * RIO_MSG_DESC_SIZE, + msg_tx_ring.virt, msg_tx_ring.phys); + + out_dma: + for (i = 0; i < msg_tx_ring.size; i++) + dma_free_coherent(NULL, RIO_MSG_BUFFER_SIZE, + msg_tx_ring.virt_buffer[i], + msg_tx_ring.phys_buffer[i]); + + return rc; +} + +/** + * rio_close_outb_mbox - Shut down MPC85xx outbound mailbox + * @mport: Master port implementing the outbound message unit + * @mbox: Mailbox to close + * + * Disables the outbound message unit, free all buffers, and + * frees the outbound message interrupt. + */ +void rio_close_outb_mbox(struct rio_mport *mport, int mbox) +{ + /* Disable inbound message unit */ + out_be32((void *)&msg_regs->omr, 0); + + /* Free ring */ + dma_free_coherent(NULL, msg_tx_ring.size * RIO_MSG_DESC_SIZE, + msg_tx_ring.virt, msg_tx_ring.phys); + + /* Free interrupt */ + free_irq(MPC85xx_IRQ_RIO_TX, (void *)mport); +} + +/** + * mpc85xx_rio_rx_handler - MPC85xx inbound message interrupt handler + * @irq: Linux interrupt number + * @dev_instance: Pointer to interrupt-specific data + * @regs: Register context + * + * Handles inbound message interrupts. Executes a registered inbound + * mailbox event handler and acks the interrupt occurence. + */ +static irqreturn_t +mpc85xx_rio_rx_handler(int irq, void *dev_instance, struct pt_regs *regs) +{ + int isr; + struct rio_mport *port = (struct rio_mport *)dev_instance; + + isr = in_be32((void *)&msg_regs->isr); + + if (isr & RIO_MSG_ISR_TE) { + pr_info("RIO: inbound message reception error\n"); + out_be32((void *)&msg_regs->isr, RIO_MSG_ISR_TE); + goto out; + } + + /* XXX Need to check/dispatch until queue empty */ + if (isr & RIO_MSG_ISR_DIQI) { + /* + * We implement *only* mailbox 0, but can receive messages + * for any mailbox/letter to that mailbox destination. So, + * make the callback with an unknown/invalid mailbox number + * argument. + */ + port->inb_msg[0].mcback(port, msg_rx_ring.dev_id, -1, -1); + + /* Ack the queueing interrupt */ + out_be32((void *)&msg_regs->isr, RIO_MSG_ISR_DIQI); + } + + out: + return IRQ_HANDLED; +} + +/** + * rio_open_inb_mbox - Initialize MPC85xx inbound mailbox + * @mport: Master port implementing the inbound message unit + * @dev_id: Device specific pointer to pass on event + * @mbox: Mailbox to open + * @entries: Number of entries in the inbound mailbox ring + * + * Initializes buffer ring, request the inbound message interrupt, + * and enables the inbound message unit. Returns %0 on success + * and %-EINVAL or %-ENOMEM on failure. + */ +int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries) +{ + int i, rc = 0; + + if ((entries < RIO_MIN_RX_RING_SIZE) || + (entries > RIO_MAX_RX_RING_SIZE) || (!is_power_of_2(entries))) { + rc = -EINVAL; + goto out; + } + + /* Initialize client buffer ring */ + msg_rx_ring.dev_id = dev_id; + msg_rx_ring.size = entries; + msg_rx_ring.rx_slot = 0; + for (i = 0; i < msg_rx_ring.size; i++) + msg_rx_ring.virt_buffer[i] = NULL; + + /* Initialize inbound message ring */ + if (!(msg_rx_ring.virt = dma_alloc_coherent(NULL, + msg_rx_ring.size * + RIO_MAX_MSG_SIZE, + &msg_rx_ring.phys, + GFP_KERNEL))) { + rc = -ENOMEM; + goto out; + } + + /* Point dequeue/enqueue pointers at first entry in ring */ + out_be32((void *)&msg_regs->ifqdpar, (u32) msg_rx_ring.phys); + out_be32((void *)&msg_regs->ifqepar, (u32) msg_rx_ring.phys); + + /* Clear interrupt status */ + out_be32((void *)&msg_regs->isr, 0x00000091); + + /* Hook up inbound message handler */ + if ((rc = + request_irq(MPC85xx_IRQ_RIO_RX, mpc85xx_rio_rx_handler, 0, + "msg_rx", (void *)mport)) < 0) { + dma_free_coherent(NULL, RIO_MSG_BUFFER_SIZE, + msg_tx_ring.virt_buffer[i], + msg_tx_ring.phys_buffer[i]); + goto out; + } + + /* + * Configure inbound message unit: + * Snooping + * 4KB max message size + * Unmask all interrupt sources + * Disable + */ + out_be32((void *)&msg_regs->imr, 0x001b0060); + + /* Set number of queue entries */ + out_be32((void *)&msg_regs->imr, + in_be32((void *)&msg_regs->imr) | + ((get_bitmask_order(entries) - 2) << 12)); + + /* Now enable the unit */ + out_be32((void *)&msg_regs->imr, in_be32((void *)&msg_regs->imr) | 0x1); + + out: + return rc; +} + +/** + * rio_close_inb_mbox - Shut down MPC85xx inbound mailbox + * @mport: Master port implementing the inbound message unit + * @mbox: Mailbox to close + * + * Disables the inbound message unit, free all buffers, and + * frees the inbound message interrupt. + */ +void rio_close_inb_mbox(struct rio_mport *mport, int mbox) +{ + /* Disable inbound message unit */ + out_be32((void *)&msg_regs->imr, 0); + + /* Free ring */ + dma_free_coherent(NULL, msg_rx_ring.size * RIO_MAX_MSG_SIZE, + msg_rx_ring.virt, msg_rx_ring.phys); + + /* Free interrupt */ + free_irq(MPC85xx_IRQ_RIO_RX, (void *)mport); +} + +/** + * rio_hw_add_inb_buffer - Add buffer to the MPC85xx inbound message queue + * @mport: Master port implementing the inbound message unit + * @mbox: Inbound mailbox number + * @buf: Buffer to add to inbound queue + * + * Adds the @buf buffer to the MPC85xx inbound message queue. Returns + * %0 on success or %-EINVAL on failure. + */ +int rio_hw_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf) +{ + int rc = 0; + + pr_debug("RIO: rio_hw_add_inb_buffer(), msg_rx_ring.rx_slot %d\n", + msg_rx_ring.rx_slot); + + if (msg_rx_ring.virt_buffer[msg_rx_ring.rx_slot]) { + printk(KERN_ERR + "RIO: error adding inbound buffer %d, buffer exists\n", + msg_rx_ring.rx_slot); + rc = -EINVAL; + goto out; + } + + msg_rx_ring.virt_buffer[msg_rx_ring.rx_slot] = buf; + if (++msg_rx_ring.rx_slot == msg_rx_ring.size) + msg_rx_ring.rx_slot = 0; + + out: + return rc; +} + +EXPORT_SYMBOL_GPL(rio_hw_add_inb_buffer); + +/** + * rio_hw_get_inb_message - Fetch inbound message from the MPC85xx message unit + * @mport: Master port implementing the inbound message unit + * @mbox: Inbound mailbox number + * + * Gets the next available inbound message from the inbound message queue. + * A pointer to the message is returned on success or NULL on failure. + */ +void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox) +{ + u32 imr; + u32 phys_buf, virt_buf; + void *buf = NULL; + int buf_idx; + + phys_buf = in_be32((void *)&msg_regs->ifqdpar); + + /* If no more messages, then bail out */ + if (phys_buf == in_be32((void *)&msg_regs->ifqepar)) + goto out2; + + virt_buf = (u32) msg_rx_ring.virt + (phys_buf - msg_rx_ring.phys); + buf_idx = (phys_buf - msg_rx_ring.phys) / RIO_MAX_MSG_SIZE; + buf = msg_rx_ring.virt_buffer[buf_idx]; + + if (!buf) { + printk(KERN_ERR + "RIO: inbound message copy failed, no buffers\n"); + goto out1; + } + + /* Copy max message size, caller is expected to allocate that big */ + memcpy(buf, (void *)virt_buf, RIO_MAX_MSG_SIZE); + + /* Clear the available buffer */ + msg_rx_ring.virt_buffer[buf_idx] = NULL; + + out1: + imr = in_be32((void *)&msg_regs->imr); + out_be32((void *)&msg_regs->imr, imr | RIO_MSG_IMR_MI); + + out2: + return buf; +} + +EXPORT_SYMBOL_GPL(rio_hw_get_inb_message); + +/** + * mpc85xx_rio_dbell_handler - MPC85xx doorbell interrupt handler + * @irq: Linux interrupt number + * @dev_instance: Pointer to interrupt-specific data + * @regs: Register context + * + * Handles doorbell interrupts. Parses a list of registered + * doorbell event handlers and executes a matching event handler. + */ +static irqreturn_t +mpc85xx_rio_dbell_handler(int irq, void *dev_instance, struct pt_regs *regs) +{ + int dsr; + struct rio_mport *port = (struct rio_mport *)dev_instance; + + dsr = in_be32((void *)&msg_regs->dsr); + + if (dsr & DOORBELL_DSR_TE) { + pr_info("RIO: doorbell reception error\n"); + out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_TE); + goto out; + } + + if (dsr & DOORBELL_DSR_QFI) { + pr_info("RIO: doorbell queue full\n"); + out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_QFI); + goto out; + } + + /* XXX Need to check/dispatch until queue empty */ + if (dsr & DOORBELL_DSR_DIQI) { + u32 dmsg = + (u32) dbell_ring.virt + + (in_be32((void *)&msg_regs->dqdpar) & 0xfff); + u32 dmr; + struct rio_dbell *dbell; + int found = 0; + + pr_debug + ("RIO: processing doorbell, sid %2.2x tid %2.2x info %4.4x\n", + DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg)); + + list_for_each_entry(dbell, &port->dbells, node) { + if ((dbell->res->start <= DBELL_INF(dmsg)) && + (dbell->res->end >= DBELL_INF(dmsg))) { + found = 1; + break; + } + } + if (found) { + dbell->dinb(port, dbell->dev_id, DBELL_SID(dmsg), DBELL_TID(dmsg), + DBELL_INF(dmsg)); + } else { + pr_debug + ("RIO: spurious doorbell, sid %2.2x tid %2.2x info %4.4x\n", + DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg)); + } + dmr = in_be32((void *)&msg_regs->dmr); + out_be32((void *)&msg_regs->dmr, dmr | DOORBELL_DMR_DI); + out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_DIQI); + } + + out: + return IRQ_HANDLED; +} + +/** + * mpc85xx_rio_doorbell_init - MPC85xx doorbell interface init + * @mport: Master port implementing the inbound doorbell unit + * + * Initializes doorbell unit hardware and inbound DMA buffer + * ring. Called from mpc85xx_rio_setup(). Returns %0 on success + * or %-ENOMEM on failure. + */ +static int mpc85xx_rio_doorbell_init(struct rio_mport *mport) +{ + int rc = 0; + + /* Map outbound doorbell window immediately after maintenance window */ + if (!(dbell_win = + (u32) ioremap(mport->iores.start + RIO_MAINT_WIN_SIZE, + RIO_DBELL_WIN_SIZE))) { + printk(KERN_ERR + "RIO: unable to map outbound doorbell window\n"); + rc = -ENOMEM; + goto out; + } + + /* Initialize inbound doorbells */ + if (!(dbell_ring.virt = dma_alloc_coherent(NULL, + 512 * DOORBELL_MESSAGE_SIZE, + &dbell_ring.phys, + GFP_KERNEL))) { + printk(KERN_ERR "RIO: unable allocate inbound doorbell ring\n"); + rc = -ENOMEM; + iounmap((void *)dbell_win); + goto out; + } + + /* Point dequeue/enqueue pointers at first entry in ring */ + out_be32((void *)&msg_regs->dqdpar, (u32) dbell_ring.phys); + out_be32((void *)&msg_regs->dqepar, (u32) dbell_ring.phys); + + /* Clear interrupt status */ + out_be32((void *)&msg_regs->dsr, 0x00000091); + + /* Hook up doorbell handler */ + if ((rc = + request_irq(MPC85xx_IRQ_RIO_BELL, mpc85xx_rio_dbell_handler, 0, + "dbell_rx", (void *)mport) < 0)) { + iounmap((void *)dbell_win); + dma_free_coherent(NULL, 512 * DOORBELL_MESSAGE_SIZE, + dbell_ring.virt, dbell_ring.phys); + printk(KERN_ERR + "MPC85xx RIO: unable to request inbound doorbell irq"); + goto out; + } + + /* Configure doorbells for snooping, 512 entries, and enable */ + out_be32((void *)&msg_regs->dmr, 0x00108161); + + out: + return rc; +} + +static char *cmdline = NULL; + +static int mpc85xx_rio_get_hdid(int index) +{ + /* XXX Need to parse multiple entries in some format */ + if (!cmdline) + return -1; + + return simple_strtol(cmdline, NULL, 0); +} + +static int mpc85xx_rio_get_cmdline(char *s) +{ + if (!s) + return 0; + + cmdline = s; + return 1; +} + +__setup("riohdid=", mpc85xx_rio_get_cmdline); + +/** + * mpc85xx_rio_setup - Setup MPC85xx RapidIO interface + * @law_start: Starting physical address of RapidIO LAW + * @law_size: Size of RapidIO LAW + * + * Initializes MPC85xx RapidIO hardware interface, configures + * master port with system-specific info, and registers the + * master port with the RapidIO subsystem. + */ +void mpc85xx_rio_setup(int law_start, int law_size) +{ + struct rio_ops *ops; + struct rio_mport *port; + + ops = kmalloc(sizeof(struct rio_ops), GFP_KERNEL); + ops->lcread = mpc85xx_local_config_read; + ops->lcwrite = mpc85xx_local_config_write; + ops->cread = mpc85xx_rio_config_read; + ops->cwrite = mpc85xx_rio_config_write; + ops->dsend = mpc85xx_rio_doorbell_send; + + port = kmalloc(sizeof(struct rio_mport), GFP_KERNEL); + port->id = 0; + port->index = 0; + INIT_LIST_HEAD(&port->dbells); + port->iores.start = law_start; + port->iores.end = law_start + law_size; + port->iores.flags = IORESOURCE_MEM; + + rio_init_dbell_res(&port->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff); + rio_init_mbox_res(&port->riores[RIO_INB_MBOX_RESOURCE], 0, 0); + rio_init_mbox_res(&port->riores[RIO_OUTB_MBOX_RESOURCE], 0, 0); + strcpy(port->name, "RIO0 mport"); + + port->ops = ops; + port->host_deviceid = mpc85xx_rio_get_hdid(port->id); + + rio_register_mport(port); + + regs_win = (u32) ioremap(RIO_REGS_BASE, 0x20000); + atmu_regs = (struct rio_atmu_regs *)(regs_win + RIO_ATMU_REGS_OFFSET); + maint_atmu_regs = atmu_regs + 1; + dbell_atmu_regs = atmu_regs + 2; + msg_regs = (struct rio_msg_regs *)(regs_win + RIO_MSG_REGS_OFFSET); + + /* Configure maintenance transaction window */ + out_be32((void *)&maint_atmu_regs->rowbar, 0x000c0000); + out_be32((void *)&maint_atmu_regs->rowar, 0x80077015); + + maint_win = (u32) ioremap(law_start, RIO_MAINT_WIN_SIZE); + + /* Configure outbound doorbell window */ + out_be32((void *)&dbell_atmu_regs->rowbar, 0x000c0400); + out_be32((void *)&dbell_atmu_regs->rowar, 0x8004200b); + mpc85xx_rio_doorbell_init(port); +} diff --git a/arch/ppc/syslib/ppc85xx_rio.h b/arch/ppc/syslib/ppc85xx_rio.h new file mode 100644 index 0000000000000000000000000000000000000000..c0827a2c3eeca4d9680d424a99936c771c08dc15 --- /dev/null +++ b/arch/ppc/syslib/ppc85xx_rio.h @@ -0,0 +1,21 @@ +/* + * MPC85xx RapidIO definitions + * + * Copyright 2005 MontaVista Software, Inc. + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __PPC_SYSLIB_PPC85XX_RIO_H +#define __PPC_SYSLIB_PPC85XX_RIO_H + +#include +#include + +extern void mpc85xx_rio_setup(int law_start, int law_size); + +#endif /* __PPC_SYSLIB_PPC85XX_RIO_H */ diff --git a/arch/ppc/syslib/ppc_sys.c b/arch/ppc/syslib/ppc_sys.c index 62ee86e80711da6e70862d2f49bd7dafc2fe4caf..603f0119081602e866d83324acf09f7c7a93808d 100644 --- a/arch/ppc/syslib/ppc_sys.c +++ b/arch/ppc/syslib/ppc_sys.c @@ -14,6 +14,7 @@ * option) any later version. */ +#include #include int (*ppc_sys_device_fixup) (struct platform_device * pdev); diff --git a/arch/ppc/syslib/prom.c b/arch/ppc/syslib/prom.c index 278da6ee62ea22f2c3bfa330562460d9c9e9e107..03b1fc9b95012d8a287171b974a176ac877cd784 100644 --- a/arch/ppc/syslib/prom.c +++ b/arch/ppc/syslib/prom.c @@ -1165,7 +1165,7 @@ get_property(struct device_node *np, const char *name, int *lenp) /* * Add a property to a node */ -void +int prom_add_property(struct device_node* np, struct property* prop) { struct property **next = &np->properties; @@ -1174,6 +1174,8 @@ prom_add_property(struct device_node* np, struct property* prop) while (*next) next = &(*next)->next; *next = prop; + + return 0; } /* I quickly hacked that one, check against spec ! */ @@ -1335,10 +1337,8 @@ release_OF_resource(struct device_node* node, int index) if (!res) return -ENODEV; - if (res->name) { - kfree(res->name); - res->name = NULL; - } + kfree(res->name); + res->name = NULL; release_resource(res); kfree(res); diff --git a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c index 66bfaa3211a262fb1a748d636119df5e41cb2024..2b483b4f1602b12a73d2b60ba55fea20faa53e31 100644 --- a/arch/ppc/xmon/xmon.c +++ b/arch/ppc/xmon/xmon.c @@ -220,8 +220,7 @@ static void get_tb(unsigned *p) p[1] = lo; } -void -xmon(struct pt_regs *excp) +int xmon(struct pt_regs *excp) { struct pt_regs regs; int msr, cmd; @@ -290,6 +289,8 @@ xmon(struct pt_regs *excp) #endif /* CONFIG_SMP */ set_msr(msr); /* restore interrupt enable */ get_tb(start_tb[smp_processor_id()]); + + return cmd != 'X'; } irqreturn_t diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig index 2130cc31595753643d1db643a57e610ea97265cd..29552348e58165db414bf6f609ae19e31e9fad7a 100644 --- a/arch/ppc64/Kconfig +++ b/arch/ppc64/Kconfig @@ -56,6 +56,7 @@ config PPC_STD_MMU # max order + 1 config FORCE_MAX_ZONEORDER int + default "9" if PPC_64K_PAGES default "13" source "init/Kconfig" @@ -173,6 +174,16 @@ config KEXEC support. As of this writing the exact hardware interface is strongly in flux, so no good recommendation can be made. +source "drivers/cpufreq/Kconfig" + +config CPU_FREQ_PMAC64 + bool "Support for some Apple G5s" + depends on CPU_FREQ && PMAC_SMU && PPC64 + select CPU_FREQ_TABLE + help + This adds support for frequency switching on Apple iMac G5, + and some of the more recent desktop G5 machines as well. + config IBMVIO depends on PPC_PSERIES || PPC_ISERIES bool diff --git a/arch/ppc64/Kconfig.debug b/arch/ppc64/Kconfig.debug index f16a5030527bd1e8f8818dc7337d49ba049054f3..b258c9314a1bda2b2bdf4f6e962e600a0ce206ba 100644 --- a/arch/ppc64/Kconfig.debug +++ b/arch/ppc64/Kconfig.debug @@ -55,10 +55,6 @@ config XMON_DEFAULT xmon is normally disabled unless booted with 'xmon=on'. Use 'xmon=off' to disable xmon init during runtime. -config PPCDBG - bool "Include PPCDBG realtime debugging" - depends on DEBUG_KERNEL - config IRQSTACKS bool "Use separate kernel stacks when processing interrupts" help diff --git a/arch/ppc64/boot/main.c b/arch/ppc64/boot/main.c index c1dc876bccab04d424ec7e0b9527c81b0f203462..e0dde24a72cebda62a135314b8c819230b4fd09a 100644 --- a/arch/ppc64/boot/main.c +++ b/arch/ppc64/boot/main.c @@ -203,8 +203,15 @@ void start(unsigned long a1, unsigned long a2, void *promptr, void *sp) if (elf64ph->p_type == PT_LOAD && elf64ph->p_offset != 0) break; } - vmlinux.size = (unsigned long)elf64ph->p_filesz; - vmlinux.memsize = (unsigned long)elf64ph->p_memsz; + vmlinux.size = (unsigned long)elf64ph->p_filesz + + (unsigned long)elf64ph->p_offset; + /* We need to claim the memsize plus the file offset since gzip + * will expand the header (file offset), then the kernel, then + * possible rubbish we don't care about. But the kernel bss must + * be claimed (it will be zero'd by the kernel itself) + */ + vmlinux.memsize = (unsigned long)elf64ph->p_memsz + + (unsigned long)elf64ph->p_offset; printf("Allocating 0x%lx bytes for kernel ...\n\r", vmlinux.memsize); vmlinux.addr = try_claim(vmlinux.memsize); if (vmlinux.addr == 0) { diff --git a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c index 8abd2ad928325e3cc29876859cddae39577d7542..8fec27469802290251e91f6221e6c883dd31d891 100644 --- a/arch/ppc64/kernel/idle.c +++ b/arch/ppc64/kernel/idle.c @@ -28,6 +28,7 @@ #include #include #include +#include extern void power4_idle(void); diff --git a/arch/ppc64/kernel/kprobes.c b/arch/ppc64/kernel/kprobes.c index ed876a5178ae6bedf663488915c0dc27cdd0ff83..511af54e6230ca13eeba65dd7765dcb9f7c8947c 100644 --- a/arch/ppc64/kernel/kprobes.c +++ b/arch/ppc64/kernel/kprobes.c @@ -30,19 +30,14 @@ #include #include #include -#include #include #include #include #include static DECLARE_MUTEX(kprobe_mutex); - -static struct kprobe *current_kprobe; -static unsigned long kprobe_status, kprobe_saved_msr; -static struct kprobe *kprobe_prev; -static unsigned long kprobe_status_prev, kprobe_saved_msr_prev; -static struct pt_regs jprobe_saved_regs; +DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; +DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); int __kprobes arch_prepare_kprobe(struct kprobe *p) { @@ -108,20 +103,28 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) regs->nip = (unsigned long)p->ainsn.insn; } -static inline void save_previous_kprobe(void) +static inline void save_previous_kprobe(struct kprobe_ctlblk *kcb) +{ + kcb->prev_kprobe.kp = kprobe_running(); + kcb->prev_kprobe.status = kcb->kprobe_status; + kcb->prev_kprobe.saved_msr = kcb->kprobe_saved_msr; +} + +static inline void restore_previous_kprobe(struct kprobe_ctlblk *kcb) { - kprobe_prev = current_kprobe; - kprobe_status_prev = kprobe_status; - kprobe_saved_msr_prev = kprobe_saved_msr; + __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp; + kcb->kprobe_status = kcb->prev_kprobe.status; + kcb->kprobe_saved_msr = kcb->prev_kprobe.saved_msr; } -static inline void restore_previous_kprobe(void) +static inline void set_current_kprobe(struct kprobe *p, struct pt_regs *regs, + struct kprobe_ctlblk *kcb) { - current_kprobe = kprobe_prev; - kprobe_status = kprobe_status_prev; - kprobe_saved_msr = kprobe_saved_msr_prev; + __get_cpu_var(current_kprobe) = p; + kcb->kprobe_saved_msr = regs->msr; } +/* Called with kretprobe_lock held */ void __kprobes arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs) { @@ -145,19 +148,24 @@ static inline int kprobe_handler(struct pt_regs *regs) struct kprobe *p; int ret = 0; unsigned int *addr = (unsigned int *)regs->nip; + struct kprobe_ctlblk *kcb; + + /* + * We don't want to be preempted for the entire + * duration of kprobe processing + */ + preempt_disable(); + kcb = get_kprobe_ctlblk(); /* Check we're not actually recursing */ if (kprobe_running()) { - /* We *are* holding lock here, so this is safe. - Disarm the probe we just hit, and ignore it. */ p = get_kprobe(addr); if (p) { kprobe_opcode_t insn = *p->ainsn.insn; - if (kprobe_status == KPROBE_HIT_SS && + if (kcb->kprobe_status == KPROBE_HIT_SS && is_trap(insn)) { regs->msr &= ~MSR_SE; - regs->msr |= kprobe_saved_msr; - unlock_kprobes(); + regs->msr |= kcb->kprobe_saved_msr; goto no_kprobe; } /* We have reentered the kprobe_handler(), since @@ -166,27 +174,24 @@ static inline int kprobe_handler(struct pt_regs *regs) * just single step on the instruction of the new probe * without calling any user handlers. */ - save_previous_kprobe(); - current_kprobe = p; - kprobe_saved_msr = regs->msr; + save_previous_kprobe(kcb); + set_current_kprobe(p, regs, kcb); + kcb->kprobe_saved_msr = regs->msr; p->nmissed++; prepare_singlestep(p, regs); - kprobe_status = KPROBE_REENTER; + kcb->kprobe_status = KPROBE_REENTER; return 1; } else { - p = current_kprobe; + p = __get_cpu_var(current_kprobe); if (p->break_handler && p->break_handler(p, regs)) { goto ss_probe; } } - /* If it's not ours, can't be delete race, (we hold lock). */ goto no_kprobe; } - lock_kprobes(); p = get_kprobe(addr); if (!p) { - unlock_kprobes(); if (*addr != BREAKPOINT_INSTRUCTION) { /* * PowerPC has multiple variants of the "trap" @@ -209,24 +214,19 @@ static inline int kprobe_handler(struct pt_regs *regs) goto no_kprobe; } - kprobe_status = KPROBE_HIT_ACTIVE; - current_kprobe = p; - kprobe_saved_msr = regs->msr; + kcb->kprobe_status = KPROBE_HIT_ACTIVE; + set_current_kprobe(p, regs, kcb); if (p->pre_handler && p->pre_handler(p, regs)) /* handler has already set things up, so skip ss setup */ return 1; ss_probe: prepare_singlestep(p, regs); - kprobe_status = KPROBE_HIT_SS; - /* - * This preempt_disable() matches the preempt_enable_no_resched() - * in post_kprobe_handler(). - */ - preempt_disable(); + kcb->kprobe_status = KPROBE_HIT_SS; return 1; no_kprobe: + preempt_enable_no_resched(); return ret; } @@ -251,9 +251,10 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) struct kretprobe_instance *ri = NULL; struct hlist_head *head; struct hlist_node *node, *tmp; - unsigned long orig_ret_address = 0; + unsigned long flags, orig_ret_address = 0; unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline; + spin_lock_irqsave(&kretprobe_lock, flags); head = kretprobe_inst_table_head(current); /* @@ -292,12 +293,14 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address)); regs->nip = orig_ret_address; - unlock_kprobes(); + reset_current_kprobe(); + spin_unlock_irqrestore(&kretprobe_lock, flags); + preempt_enable_no_resched(); /* * By returning a non-zero value, we are telling - * kprobe_handler() that we have handled unlocking - * and re-enabling preemption. + * kprobe_handler() that we don't want the post_handler + * to run (and have re-enabled preemption) */ return 1; } @@ -323,23 +326,26 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) static inline int post_kprobe_handler(struct pt_regs *regs) { - if (!kprobe_running()) + struct kprobe *cur = kprobe_running(); + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + + if (!cur) return 0; - if ((kprobe_status != KPROBE_REENTER) && current_kprobe->post_handler) { - kprobe_status = KPROBE_HIT_SSDONE; - current_kprobe->post_handler(current_kprobe, regs, 0); + if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) { + kcb->kprobe_status = KPROBE_HIT_SSDONE; + cur->post_handler(cur, regs, 0); } - resume_execution(current_kprobe, regs); - regs->msr |= kprobe_saved_msr; + resume_execution(cur, regs); + regs->msr |= kcb->kprobe_saved_msr; /*Restore back the original saved kprobes variables and continue. */ - if (kprobe_status == KPROBE_REENTER) { - restore_previous_kprobe(); + if (kcb->kprobe_status == KPROBE_REENTER) { + restore_previous_kprobe(kcb); goto out; } - unlock_kprobes(); + reset_current_kprobe(); out: preempt_enable_no_resched(); @@ -354,19 +360,20 @@ static inline int post_kprobe_handler(struct pt_regs *regs) return 1; } -/* Interrupts disabled, kprobe_lock held. */ static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) { - if (current_kprobe->fault_handler - && current_kprobe->fault_handler(current_kprobe, regs, trapnr)) + struct kprobe *cur = kprobe_running(); + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + + if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) return 1; - if (kprobe_status & KPROBE_HIT_SS) { - resume_execution(current_kprobe, regs); + if (kcb->kprobe_status & KPROBE_HIT_SS) { + resume_execution(cur, regs); regs->msr &= ~MSR_SE; - regs->msr |= kprobe_saved_msr; + regs->msr |= kcb->kprobe_saved_msr; - unlock_kprobes(); + reset_current_kprobe(); preempt_enable_no_resched(); } return 0; @@ -381,11 +388,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, struct die_args *args = (struct die_args *)data; int ret = NOTIFY_DONE; - /* - * Interrupts are not disabled here. We need to disable - * preemption, because kprobe_running() uses smp_processor_id(). - */ - preempt_disable(); switch (val) { case DIE_BPT: if (kprobe_handler(args->regs)) @@ -396,22 +398,25 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, ret = NOTIFY_STOP; break; case DIE_PAGE_FAULT: + /* kprobe_running() needs smp_processor_id() */ + preempt_disable(); if (kprobe_running() && kprobe_fault_handler(args->regs, args->trapnr)) ret = NOTIFY_STOP; + preempt_enable(); break; default: break; } - preempt_enable_no_resched(); return ret; } int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) { struct jprobe *jp = container_of(p, struct jprobe, kp); + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); - memcpy(&jprobe_saved_regs, regs, sizeof(struct pt_regs)); + memcpy(&kcb->jprobe_saved_regs, regs, sizeof(struct pt_regs)); /* setup return addr to the jprobe handler routine */ regs->nip = (unsigned long)(((func_descr_t *)jp->entry)->entry); @@ -431,12 +436,15 @@ void __kprobes jprobe_return_end(void) int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) { + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + /* * FIXME - we should ideally be validating that we got here 'cos * of the "trap" in jprobe_return() above, before restoring the * saved regs... */ - memcpy(regs, &jprobe_saved_regs, sizeof(struct pt_regs)); + memcpy(regs, &kcb->jprobe_saved_regs, sizeof(struct pt_regs)); + preempt_enable_no_resched(); return 1; } diff --git a/arch/ppc64/kernel/lparcfg.c b/arch/ppc64/kernel/lparcfg.c index e86155770bbc5ff761352dfc556b7c146295e77d..3e7b2f28ec8302a4b9025a5cdde84296b9c30e7e 100644 --- a/arch/ppc64/kernel/lparcfg.c +++ b/arch/ppc64/kernel/lparcfg.c @@ -599,9 +599,7 @@ int __init lparcfg_init(void) void __exit lparcfg_cleanup(void) { if (proc_ppc64_lparcfg) { - if (proc_ppc64_lparcfg->data) { - kfree(proc_ppc64_lparcfg->data); - } + kfree(proc_ppc64_lparcfg->data); remove_proc_entry("lparcfg", proc_ppc64_lparcfg->parent); } } diff --git a/arch/ppc64/kernel/machine_kexec.c b/arch/ppc64/kernel/machine_kexec.c index ff8679f260f3819a61bcf0f791c36fe677b18757..07ea03598c004774cfed9fde43bf0c587592eec8 100644 --- a/arch/ppc64/kernel/machine_kexec.c +++ b/arch/ppc64/kernel/machine_kexec.c @@ -24,6 +24,7 @@ #include #include /* _end */ #include +#include #define HASH_GROUP_SIZE 0x80 /* size of each hash group, asm/mmu.h */ diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S index 077507ffbab80e1601b69e037ccb970d0956f6c6..914632ec587d46fea767a47375160b1b0c2a2ab1 100644 --- a/arch/ppc64/kernel/misc.S +++ b/arch/ppc64/kernel/misc.S @@ -560,7 +560,7 @@ _GLOBAL(real_readb) isync blr - /* +/* * Do an IO access in real mode */ _GLOBAL(real_writeb) @@ -592,6 +592,76 @@ _GLOBAL(real_writeb) blr #endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */ +/* + * SCOM access functions for 970 (FX only for now) + * + * unsigned long scom970_read(unsigned int address); + * void scom970_write(unsigned int address, unsigned long value); + * + * The address passed in is the 24 bits register address. This code + * is 970 specific and will not check the status bits, so you should + * know what you are doing. + */ +_GLOBAL(scom970_read) + /* interrupts off */ + mfmsr r4 + ori r0,r4,MSR_EE + xori r0,r0,MSR_EE + mtmsrd r0,1 + + /* rotate 24 bits SCOM address 8 bits left and mask out it's low 8 bits + * (including parity). On current CPUs they must be 0'd, + * and finally or in RW bit + */ + rlwinm r3,r3,8,0,15 + ori r3,r3,0x8000 + + /* do the actual scom read */ + sync + mtspr SPRN_SCOMC,r3 + isync + mfspr r3,SPRN_SCOMD + isync + mfspr r0,SPRN_SCOMC + isync + + /* XXX: fixup result on some buggy 970's (ouch ! we lost a bit, bah + * that's the best we can do). Not implemented yet as we don't use + * the scom on any of the bogus CPUs yet, but may have to be done + * ultimately + */ + + /* restore interrupts */ + mtmsrd r4,1 + blr + + +_GLOBAL(scom970_write) + /* interrupts off */ + mfmsr r5 + ori r0,r5,MSR_EE + xori r0,r0,MSR_EE + mtmsrd r0,1 + + /* rotate 24 bits SCOM address 8 bits left and mask out it's low 8 bits + * (including parity). On current CPUs they must be 0'd. + */ + + rlwinm r3,r3,8,0,15 + + sync + mtspr SPRN_SCOMD,r4 /* write data */ + isync + mtspr SPRN_SCOMC,r3 /* write command */ + isync + mfspr 3,SPRN_SCOMC + isync + + /* restore interrupts */ + mtmsrd r5,1 + blr + + /* * Create a kernel thread * kernel_thread(fn, arg, flags) diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c index 3d2106b022a11f1376947255374278e2b6d30fcb..30247ff74972d3ef3a4048b3baca0d24141e5420 100644 --- a/arch/ppc64/kernel/pci.c +++ b/arch/ppc64/kernel/pci.c @@ -295,8 +295,8 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev) } } -static struct pci_dev *of_create_pci_dev(struct device_node *node, - struct pci_bus *bus, int devfn) +struct pci_dev *of_create_pci_dev(struct device_node *node, + struct pci_bus *bus, int devfn) { struct pci_dev *dev; const char *type; @@ -354,10 +354,9 @@ static struct pci_dev *of_create_pci_dev(struct device_node *node, return dev; } +EXPORT_SYMBOL(of_create_pci_dev); -static void of_scan_pci_bridge(struct device_node *node, struct pci_dev *dev); - -static void __devinit of_scan_bus(struct device_node *node, +void __devinit of_scan_bus(struct device_node *node, struct pci_bus *bus) { struct device_node *child = NULL; @@ -381,9 +380,10 @@ static void __devinit of_scan_bus(struct device_node *node, do_bus_setup(bus); } +EXPORT_SYMBOL(of_scan_bus); -static void __devinit of_scan_pci_bridge(struct device_node *node, - struct pci_dev *dev) +void __devinit of_scan_pci_bridge(struct device_node *node, + struct pci_dev *dev) { struct pci_bus *bus; u32 *busrange, *ranges; @@ -464,9 +464,10 @@ static void __devinit of_scan_pci_bridge(struct device_node *node, else if (mode == PCI_PROBE_NORMAL) pci_scan_child_bus(bus); } +EXPORT_SYMBOL(of_scan_pci_bridge); #endif /* CONFIG_PPC_MULTIPLATFORM */ -static void __devinit scan_phb(struct pci_controller *hose) +void __devinit scan_phb(struct pci_controller *hose) { struct pci_bus *bus; struct device_node *node = hose->arch_data; diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c index dece31e58bc4b69c4cf8aaf4a05be977584d65cc..3402fbee62c74af1faf5ccd7013afc4199c4ce2b 100644 --- a/arch/ppc64/kernel/prom.c +++ b/arch/ppc64/kernel/prom.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -46,7 +47,6 @@ #include #include #include -#include #include #include #include @@ -1866,17 +1866,32 @@ get_property(struct device_node *np, const char *name, int *lenp) EXPORT_SYMBOL(get_property); /* - * Add a property to a node + * Add a property to a node. */ -void +int prom_add_property(struct device_node* np, struct property* prop) { - struct property **next = &np->properties; + struct property **next; prop->next = NULL; - while (*next) + write_lock(&devtree_lock); + next = &np->properties; + while (*next) { + if (strcmp(prop->name, (*next)->name) == 0) { + /* duplicate ! don't insert it */ + write_unlock(&devtree_lock); + return -1; + } next = &(*next)->next; + } *next = prop; + write_unlock(&devtree_lock); + + /* try to add to proc as well if it was initialized */ + if (np->pde) + proc_device_tree_add_prop(np->pde, prop); + + return 0; } #if 0 diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c index a4bbca6dbb8b4624f01d150840ebeff031f0860b..e4c880dab997bf9cc7baeb33efe3cd54bcca22fc 100644 --- a/arch/ppc64/kernel/prom_init.c +++ b/arch/ppc64/kernel/prom_init.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include @@ -1825,7 +1824,7 @@ static void __init fixup_device_tree(void) if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) == PROM_ERROR) return; - if (u3_rev != 0x35 && u3_rev != 0x37) + if (u3_rev < 0x35 || u3_rev > 0x39) return; /* does it need fixup ? */ if (prom_getproplen(i2c, "interrupts") > 0) diff --git a/arch/ppc64/kernel/rtas_pci.c b/arch/ppc64/kernel/rtas_pci.c index 3ad15c90fbbd29f55017735666719c96e79a561c..3c3f19192fcc9e164feab51b342e4d4344c94047 100644 --- a/arch/ppc64/kernel/rtas_pci.c +++ b/arch/ppc64/kernel/rtas_pci.c @@ -440,7 +440,6 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) struct device_node *root = of_find_node_by_path("/"); unsigned int root_size_cells = 0; struct pci_controller *phb; - struct pci_bus *bus; int primary; root_size_cells = prom_n_size_cells(root); @@ -456,10 +455,7 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) of_node_put(root); pci_devs_phb_init_dynamic(phb); - phb->last_busno = 0xff; - bus = pci_scan_bus(phb->first_busno, phb->ops, phb->arch_data); - phb->bus = bus; - phb->last_busno = bus->subordinate; + scan_phb(phb); return phb; } diff --git a/arch/ppc64/kernel/scanlog.c b/arch/ppc64/kernel/scanlog.c index 215bf8900304ea8aa135434feeb26b33b53c6c41..2edc947f7c44b2a9908f43ad098633018dc38bf6 100644 --- a/arch/ppc64/kernel/scanlog.c +++ b/arch/ppc64/kernel/scanlog.c @@ -225,8 +225,7 @@ int __init scanlog_init(void) void __exit scanlog_cleanup(void) { if (proc_ppc64_scan_log_dump) { - if (proc_ppc64_scan_log_dump->data) - kfree(proc_ppc64_scan_log_dump->data); + kfree(proc_ppc64_scan_log_dump->data); remove_proc_entry("scan-log-dump", proc_ppc64_scan_log_dump->parent); } } diff --git a/arch/ppc64/kernel/sysfs.c b/arch/ppc64/kernel/sysfs.c index 6654b350979cfd3a868c029677fff0239d9972ed..e99ec62c2c52abba20b1e4f36da62e70f4d925bc 100644 --- a/arch/ppc64/kernel/sysfs.c +++ b/arch/ppc64/kernel/sysfs.c @@ -20,6 +20,7 @@ #include #include #include +#include static DEFINE_PER_CPU(struct cpu, cpu_devices); diff --git a/arch/ppc64/kernel/udbg.c b/arch/ppc64/kernel/udbg.c index d49c3613c8ece531898535748256ec5af39796bb..0d878e72fc449257623c78a778434becd0aa6eda 100644 --- a/arch/ppc64/kernel/udbg.c +++ b/arch/ppc64/kernel/udbg.c @@ -10,12 +10,10 @@ */ #include -#define WANT_PPCDBG_TAB /* Only defined here */ #include #include #include #include -#include #include void (*udbg_putc)(unsigned char c); @@ -89,59 +87,6 @@ void udbg_printf(const char *fmt, ...) va_end(args); } -/* PPCDBG stuff */ - -u64 ppc64_debug_switch; - -/* Special print used by PPCDBG() macro */ -void udbg_ppcdbg(unsigned long debug_flags, const char *fmt, ...) -{ - unsigned long active_debugs = debug_flags & ppc64_debug_switch; - - if (active_debugs) { - va_list ap; - unsigned char buf[UDBG_BUFSIZE]; - unsigned long i, len = 0; - - for (i=0; i < PPCDBG_NUM_FLAGS; i++) { - if (((1U << i) & active_debugs) && - trace_names[i]) { - len += strlen(trace_names[i]); - udbg_puts(trace_names[i]); - break; - } - } - - snprintf(buf, UDBG_BUFSIZE, " [%s]: ", current->comm); - len += strlen(buf); - udbg_puts(buf); - - while (len < 18) { - udbg_puts(" "); - len++; - } - - va_start(ap, fmt); - vsnprintf(buf, UDBG_BUFSIZE, fmt, ap); - udbg_puts(buf); - va_end(ap); - } -} - -unsigned long udbg_ifdebug(unsigned long flags) -{ - return (flags & ppc64_debug_switch); -} - -/* - * Initialize the PPCDBG state. Called before relocation has been enabled. - */ -void __init ppcdbg_initialize(void) -{ - ppc64_debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | */ - /* PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */; -} - /* * Early boot console based on udbg */ diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 98db30481d97eb211d1e767ca9701767e323dc09..73a09a6ee6c8227f96192a3ef821575d3514c471 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -76,9 +76,7 @@ AFLAGS += $(aflags-y) OBJCOPYFLAGS := -O binary LDFLAGS_vmlinux := -e start -head-$(CONFIG_ARCH_S390_31) += arch/$(ARCH)/kernel/head.o -head-$(CONFIG_ARCH_S390X) += arch/$(ARCH)/kernel/head64.o -head-y += arch/$(ARCH)/kernel/init_task.o +head-y := arch/$(ARCH)/kernel/head.o arch/$(ARCH)/kernel/init_task.o core-y += arch/$(ARCH)/mm/ arch/$(ARCH)/kernel/ arch/$(ARCH)/crypto/ \ arch/$(ARCH)/appldata/ diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index c9f2f60cfa5808929e9d4515d709cad7f726a5c6..dee6ab54984d03d6358a54476191aa18fb2ee05d 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -592,12 +592,15 @@ int appldata_register_ops(struct appldata_ops *ops) */ void appldata_unregister_ops(struct appldata_ops *ops) { + void *table; spin_lock(&appldata_ops_lock); - unregister_sysctl_table(ops->sysctl_header); list_del(&ops->list); - kfree(ops->ctl_table); + /* at that point any incoming access will fail */ + table = ops->ctl_table; ops->ctl_table = NULL; spin_unlock(&appldata_ops_lock); + unregister_sysctl_table(ops->sysctl_header); + kfree(table); P_INFO("%s-ops unregistered!\n", ops->name); } /********************** module-ops management **************************/ diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 8584dd8232181a5cec925779ad799688dbccfc82..7434c32bc6312720a47af11f822a0348f4ad3e4e 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -8,9 +8,7 @@ obj-y := bitmap.o traps.o time.o process.o \ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ semaphore.o s390_ext.o debug.o profile.o irq.o reipl_diag.o -extra-$(CONFIG_ARCH_S390_31) += head.o -extra-$(CONFIG_ARCH_S390X) += head64.o -extra-y += init_task.o vmlinux.lds +extra-y += head.o init_task.o vmlinux.lds obj-$(CONFIG_MODULES) += s390_ksyms.o module.o obj-$(CONFIG_SMP) += smp.o diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 9b30f4cf32c4736806791f0904231705f1fc9353..27b07730b7b8d172f4330aaea690f53e82152628 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -288,7 +288,7 @@ sysc_sigpending: bo BASED(sysc_restart) tm __TI_flags+3(%r9),_TIF_SINGLE_STEP bo BASED(sysc_singlestep) - b BASED(sysc_leave) # out of here, do NOT recheck + b BASED(sysc_work_loop) # # _TIF_RESTART_SVC is set, set up registers and restart svc @@ -645,7 +645,7 @@ io_sigpending: l %r1,BASED(.Ldo_signal) basr %r14,%r1 # call do_signal stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts - b BASED(io_leave) # out of here, do NOT recheck + b BASED(io_work_loop) /* * External interrupt handler routine diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 7b9b4a2ba1d7c3ee58c6b16aba372c278d52addb..4eb71ffcf484d16e985b73c821e836e040fb5e1d 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -283,7 +283,7 @@ sysc_sigpending: jo sysc_restart tm __TI_flags+7(%r9),_TIF_SINGLE_STEP jo sysc_singlestep - j sysc_leave # out of here, do NOT recheck + j sysc_work_loop # # _TIF_RESTART_SVC is set, set up registers and restart svc @@ -684,7 +684,7 @@ io_sigpending: slgr %r3,%r3 # clear *oldset brasl %r14,do_signal # call do_signal stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts - j sysc_leave # out of here, do NOT recheck + j io_work_loop /* * External interrupt handler routine diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index 039354d72348eae678124fe62a9dc30dff2ac53f..d31a97c89f684813a5e02777ee6d1c05d7b21633 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -1,11 +1,12 @@ /* * arch/s390/kernel/head.S * - * S390 version - * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Hartmut Penner (hp@de.ibm.com), - * Martin Schwidefsky (schwidefsky@de.ibm.com), - * Rob van der Heij (rvdhei@iae.nl) + * (C) Copyright IBM Corp. 1999, 2005 + * + * Author(s): Hartmut Penner + * Martin Schwidefsky + * Rob van der Heij + * Heiko Carstens * * There are 5 different IPL methods * 1) load the image directly into ram at address 0 and do an PSW restart @@ -19,12 +20,7 @@ * 5) direct call of start by the SALIPL loader * We use the cpuid to distinguish between VM and native ipl * params for kernel are pushed to 0x10400 (see setup.h) - - Changes: - Okt 25 2000 - added code to skip HDR and EOF to allow SL tape IPL (5 retries) - changed first CCW from rewind to backspace block - + * */ #include @@ -34,6 +30,12 @@ #include #include +#ifdef CONFIG_ARCH_S390X +#define ARCH_OFFSET 4 +#else +#define ARCH_OFFSET 0 +#endif + #ifndef CONFIG_IPL .org 0 .long 0x00080000,0x80000000+startup # Just a restart PSW @@ -201,7 +203,7 @@ ssch 0(%r3) # load chunk of 1600 bytes bnz .Llderr .Lwait4irq: - mvc __LC_IO_NEW_PSW(8),.Lnewpsw # set up IO interrupt psw + mvc 0x78(8),.Lnewpsw # set up IO interrupt psw lpsw .Lwaitpsw .Lioint: c %r1,0xb8 # compare subchannel number @@ -265,13 +267,13 @@ iplstart: la %r2,IPL_BS # load start address bas %r14,.Lloader # load rest of ipl image l %r12,.Lparm # pointer to parameter area - st %r1,IPL_DEVICE-PARMAREA(%r12) # store ipl device number + st %r1,IPL_DEVICE+ARCH_OFFSET-PARMAREA(%r12) # save ipl device number # # load parameter file from ipl device # .Lagain1: - l %r2,INITRD_START-PARMAREA(%r12) # use ramdisk location as temp + l %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) # ramdisk loc. is temp bas %r14,.Lloader # load parameter file ltr %r2,%r2 # got anything ? bz .Lnopf @@ -279,7 +281,7 @@ iplstart: bnh .Lnotrunc la %r2,895 .Lnotrunc: - l %r4,INITRD_START-PARMAREA(%r12) + l %r4,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) clc 0(3,%r4),.L_hdr # if it is HDRx bz .Lagain1 # skip dataset header clc 0(3,%r4),.L_eof # if it is EOFx @@ -322,14 +324,14 @@ iplstart: # load ramdisk from ipl device # .Lagain2: - l %r2,INITRD_START-PARMAREA(%r12) # load adr. of ramdisk + l %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) # addr of ramdisk bas %r14,.Lloader # load ramdisk - st %r2,INITRD_SIZE-PARMAREA(%r12) # store size of ramdisk + st %r2,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r12) # store size of ramdisk ltr %r2,%r2 bnz .Lrdcont - st %r2,INITRD_START-PARMAREA(%r12) # no ramdisk found, null it + st %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) # no ramdisk found .Lrdcont: - l %r2,INITRD_START-PARMAREA(%r12) + l %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) clc 0(3,%r2),.L_hdr # skip HDRx and EOFx bz .Lagain2 @@ -432,10 +434,10 @@ start: la %r3,1(%r3) .done: l %r1,.memsize - st %r3,0(%r1) + st %r3,ARCH_OFFSET(%r1) slr %r0,%r0 - st %r0,INITRD_SIZE-PARMAREA(%r11) - st %r0,INITRD_START-PARMAREA(%r11) + st %r0,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r11) + st %r0,INITRD_START+ARCH_OFFSET-PARMAREA(%r11) j startup # continue with startup .tbl: .long _ebcasc # translate table .cmd: .long COMMAND_LINE # address of command line buffer @@ -478,304 +480,23 @@ start: .byte 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7 .byte 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff -# -# startup-code at 0x10000, running in real mode -# this is called either by the ipl loader or directly by PSW restart -# or linload or SALIPL -# - .org 0x10000 -startup:basr %r13,0 # get base -.LPG1: l %r1, .Lget_ipl_device_addr-.LPG1(%r13) - basr %r14, %r1 - lctl %c0,%c15,.Lctl-.LPG1(%r13) # load control registers - la %r12,_pstart-.LPG1(%r13) # pointer to parameter area - # move IPL device to lowcore - mvc __LC_IPLDEV(4),IPL_DEVICE-PARMAREA(%r12) - -# -# clear bss memory -# - l %r2,.Lbss_bgn-.LPG1(%r13) # start of bss - l %r3,.Lbss_end-.LPG1(%r13) # end of bss - sr %r3,%r2 # length of bss - sr %r4,%r4 # - sr %r5,%r5 # set src,length and pad to zero - sr %r0,%r0 # - mvcle %r2,%r4,0 # clear mem - jo .-4 # branch back, if not finish - - l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word -.Lservicecall: - stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts - - stctl %r0, %r0,.Lcr-.LPG1(%r13) # get cr0 - la %r1,0x200 # set bit 22 - o %r1,.Lcr-.LPG1(%r13) # or old cr0 with r1 - st %r1,.Lcr-.LPG1(%r13) - lctl %r0, %r0,.Lcr-.LPG1(%r13) # load modified cr0 - - mvc __LC_EXT_NEW_PSW(8),.Lpcext-.LPG1(%r13) # set postcall psw - la %r1, .Lsclph-.LPG1(%r13) - a %r1,__LC_EXT_NEW_PSW+4 # set handler - st %r1,__LC_EXT_NEW_PSW+4 - - la %r4,_pstart-.LPG1(%r13) # %r4 is our index for sccb stuff - la %r1, .Lsccb-PARMAREA(%r4) # our sccb - .insn rre,0xb2200000,%r2,%r1 # service call - ipm %r1 - srl %r1,28 # get cc code - xr %r3, %r3 - chi %r1,3 - be .Lfchunk-.LPG1(%r13) # leave - chi %r1,2 - be .Lservicecall-.LPG1(%r13) - lpsw .Lwaitsclp-.LPG1(%r13) -.Lsclph: - lh %r1,.Lsccbr-PARMAREA(%r4) - chi %r1,0x10 # 0x0010 is the sucess code - je .Lprocsccb # let's process the sccb - chi %r1,0x1f0 - bne .Lfchunk-.LPG1(%r13) # unhandled error code - c %r2, .Lrcp-.LPG1(%r13) # Did we try Read SCP forced - bne .Lfchunk-.LPG1(%r13) # if no, give up - l %r2, .Lrcp2-.LPG1(%r13) # try with Read SCP - b .Lservicecall-.LPG1(%r13) -.Lprocsccb: - lhi %r1,0 - icm %r1,3,.Lscpincr1-PARMAREA(%r4) # use this one if != 0 - jnz .Lscnd - lhi %r1,0x800 # otherwise report 2GB -.Lscnd: - lhi %r3,0x800 # limit reported memory size to 2GB - cr %r1,%r3 - jl .Lno2gb - lr %r1,%r3 -.Lno2gb: - xr %r3,%r3 # same logic - ic %r3,.Lscpa1-PARMAREA(%r4) - chi %r3,0x00 - jne .Lcompmem - l %r3,.Lscpa2-PARMAREA(%r13) -.Lcompmem: - mr %r2,%r1 # mem in MB on 128-bit - l %r1,.Lonemb-.LPG1(%r13) - mr %r2,%r1 # mem size in bytes in %r3 - b .Lfchunk-.LPG1(%r13) - - .align 4 -.Lget_ipl_device_addr: - .long .Lget_ipl_device -.Lpmask: - .byte 0 -.align 8 -.Lpcext:.long 0x00080000,0x80000000 -.Lcr: - .long 0x00 # place holder for cr0 -.Lwaitsclp: - .long 0x020A0000 - .long .Lsclph -.Lrcp: - .int 0x00120001 # Read SCP forced code -.Lrcp2: - .int 0x00020001 # Read SCP code -.Lonemb: - .int 0x100000 -.Lfchunk: - -# -# find memory chunks. -# - lr %r9,%r3 # end of mem - mvc __LC_PGM_NEW_PSW(8),.Lpcmem-.LPG1(%r13) - la %r1,1 # test in increments of 128KB - sll %r1,17 - l %r3,.Lmchunk-.LPG1(%r13) # get pointer to memory_chunk array - slr %r4,%r4 # set start of chunk to zero - slr %r5,%r5 # set end of chunk to zero - slr %r6,%r6 # set access code to zero - la %r10, MEMORY_CHUNKS # number of chunks -.Lloop: - tprot 0(%r5),0 # test protection of first byte - ipm %r7 - srl %r7,28 - clr %r6,%r7 # compare cc with last access code - be .Lsame-.LPG1(%r13) - b .Lchkmem-.LPG1(%r13) -.Lsame: - ar %r5,%r1 # add 128KB to end of chunk - bno .Lloop-.LPG1(%r13) # r1 < 0x80000000 -> loop -.Lchkmem: # > 2GB or tprot got a program check - clr %r4,%r5 # chunk size > 0? - be .Lchkloop-.LPG1(%r13) - st %r4,0(%r3) # store start address of chunk - lr %r0,%r5 - slr %r0,%r4 - st %r0,4(%r3) # store size of chunk - st %r6,8(%r3) # store type of chunk - la %r3,12(%r3) - l %r4,.Lmemsize-.LPG1(%r13) # address of variable memory_size - st %r5,0(%r4) # store last end to memory size - ahi %r10,-1 # update chunk number -.Lchkloop: - lr %r6,%r7 # set access code to last cc - # we got an exception or we're starting a new - # chunk , we must check if we should - # still try to find valid memory (if we detected - # the amount of available storage), and if we - # have chunks left - xr %r0,%r0 - clr %r0,%r9 # did we detect memory? - je .Ldonemem # if not, leave - chi %r10,0 # do we have chunks left? - je .Ldonemem - alr %r5,%r1 # add 128KB to end of chunk - lr %r4,%r5 # potential new chunk - clr %r5,%r9 # should we go on? - jl .Lloop -.Ldonemem: - l %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags -# -# find out if we are running under VM -# - stidp __LC_CPUID # store cpuid - tm __LC_CPUID,0xff # running under VM ? - bno .Lnovm-.LPG1(%r13) - oi 3(%r12),1 # set VM flag -.Lnovm: - lh %r0,__LC_CPUID+4 # get cpu version - chi %r0,0x7490 # running on a P/390 ? - bne .Lnop390-.LPG1(%r13) - oi 3(%r12),4 # set P/390 flag -.Lnop390: - -# -# find out if we have an IEEE fpu -# - mvc __LC_PGM_NEW_PSW(8),.Lpcfpu-.LPG1(%r13) - efpc %r0,0 # test IEEE extract fpc instruction - oi 3(%r12),2 # set IEEE fpu flag -.Lchkfpu: - -# -# find out if we have the CSP instruction -# - mvc __LC_PGM_NEW_PSW(8),.Lpccsp-.LPG1(%r13) - la %r0,0 - lr %r1,%r0 - la %r2,4 - csp %r0,%r2 # Test CSP instruction - oi 3(%r12),8 # set CSP flag -.Lchkcsp: - -# -# find out if we have the MVPG instruction -# - mvc __LC_PGM_NEW_PSW(8),.Lpcmvpg-.LPG1(%r13) - sr %r0,%r0 - la %r1,0 - la %r2,0 - mvpg %r1,%r2 # Test CSP instruction - oi 3(%r12),16 # set MVPG flag -.Lchkmvpg: - -# -# find out if we have the IDTE instruction -# - mvc __LC_PGM_NEW_PSW(8),.Lpcidte-.LPG1(%r13) - .long 0xb2b10000 # store facility list - tm 0xc8,0x08 # check bit for clearing-by-ASCE - bno .Lchkidte-.LPG1(%r13) - lhi %r1,2094 - lhi %r2,0 - .long 0xb98e2001 - oi 3(%r12),0x80 # set IDTE flag -.Lchkidte: - - lpsw .Lentry-.LPG1(13) # jump to _stext in primary-space, - # virtual and never return ... - .align 8 -.Lentry:.long 0x00080000,0x80000000 + _stext -.Lctl: .long 0x04b50002 # cr0: various things - .long 0 # cr1: primary space segment table - .long .Lduct # cr2: dispatchable unit control table - .long 0 # cr3: instruction authorization - .long 0 # cr4: instruction authorization - .long 0xffffffff # cr5: primary-aste origin - .long 0 # cr6: I/O interrupts - .long 0 # cr7: secondary space segment table - .long 0 # cr8: access registers translation - .long 0 # cr9: tracing off - .long 0 # cr10: tracing off - .long 0 # cr11: tracing off - .long 0 # cr12: tracing off - .long 0 # cr13: home space segment table - .long 0xc0000000 # cr14: machine check handling off - .long 0 # cr15: linkage stack operations -.Lpcmem:.long 0x00080000,0x80000000 + .Lchkmem -.Lpcfpu:.long 0x00080000,0x80000000 + .Lchkfpu -.Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp -.Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg -.Lpcidte:.long 0x00080000,0x80000000 + .Lchkidte -.Lmemsize:.long memory_size -.Lmchunk:.long memory_chunk -.Lmflags:.long machine_flags -.Lbss_bgn: .long __bss_start -.Lbss_end: .long _end - - .org PARMAREA-64 -.Lduct: .long 0,0,0,0,0,0,0,0 - .long 0,0,0,0,0,0,0,0 - -# -# params at 10400 (setup.h) -# - .org PARMAREA - .global _pstart -_pstart: - .long 0,0 # IPL_DEVICE - .long 0,RAMDISK_ORIGIN # INITRD_START - .long 0,RAMDISK_SIZE # INITRD_SIZE - - .org COMMAND_LINE - .byte "root=/dev/ram0 ro" - .byte 0 - .org 0x11000 -.Lsccb: - .hword 0x1000 # length, one page - .byte 0x00,0x00,0x00 - .byte 0x80 # variable response bit set -.Lsccbr: - .hword 0x00 # response code -.Lscpincr1: - .hword 0x00 -.Lscpa1: - .byte 0x00 - .fill 89,1,0 -.Lscpa2: - .int 0x00 -.Lscpincr2: - .quad 0x00 - .fill 3984,1,0 - .org 0x12000 - .global _pend -_pend: - +.macro GET_IPL_DEVICE .Lget_ipl_device: basr %r12,0 -.LPG2: l %r1,0xb8 # get sid +.LGID: l %r1,0xb8 # get sid sll %r1,15 # test if subchannel is enabled srl %r1,31 ltr %r1,%r1 bz 0(%r14) # subchannel disabled l %r1,0xb8 - la %r5,.Lipl_schib-.LPG2(%r12) + la %r5,.Lipl_schib-.LGID(%r12) stsch 0(%r5) # get schib of subchannel bnz 0(%r14) # schib not available tm 5(%r5),0x01 # devno valid? bno 0(%r14) - la %r6,ipl_parameter_flags-.LPG2(%r12) + la %r6,ipl_parameter_flags-.LGID(%r12) oi 3(%r6),0x01 # set flag - la %r2,ipl_devno-.LPG2(%r12) + la %r2,ipl_devno-.LGID(%r12) mvc 0(2,%r2),6(%r5) # store devno tm 4(%r5),0x80 # qdio capable device? bno 0(%r14) @@ -816,46 +537,10 @@ ipl_parameter_flags: .globl ipl_devno ipl_devno: .word 0 +.endm -#ifdef CONFIG_SHARED_KERNEL - .org 0x100000 +#ifdef CONFIG_ARCH_S390X +#include "head64.S" +#else +#include "head31.S" #endif - -# -# startup-code, running in virtual mode -# - .globl _stext -_stext: basr %r13,0 # get base -.LPG3: -# -# Setup stack -# - l %r15,.Linittu-.LPG3(%r13) - mvc __LC_CURRENT(4),__TI_task(%r15) - ahi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union + THREAD_SIZE - st %r15,__LC_KERNEL_STACK # set end of kernel stack - ahi %r15,-96 - xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain - -# check control registers - stctl %c0,%c15,0(%r15) - oi 2(%r15),0x40 # enable sigp emergency signal - oi 0(%r15),0x10 # switch on low address protection - lctl %c0,%c15,0(%r15) - -# - lam 0,15,.Laregs-.LPG3(%r13) # load access regs needed by uaccess - l %r14,.Lstart-.LPG3(%r13) - basr %r14,%r14 # call start_kernel -# -# We returned from start_kernel ?!? PANIK -# - basr %r13,0 - lpsw .Ldw-.(%r13) # load disabled wait psw -# - .align 8 -.Ldw: .long 0x000a0000,0x00000000 -.Linittu: .long init_thread_union -.Lstart: .long start_kernel -.Laregs: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S new file mode 100644 index 0000000000000000000000000000000000000000..2d3b089bfb83d37acbc8427889034573ed2d1213 --- /dev/null +++ b/arch/s390/kernel/head31.S @@ -0,0 +1,336 @@ +/* + * arch/s390/kernel/head31.S + * + * (C) Copyright IBM Corp. 2005 + * + * Author(s): Hartmut Penner + * Martin Schwidefsky + * Rob van der Heij + * Heiko Carstens + * + */ + +# +# startup-code at 0x10000, running in absolute addressing mode +# this is called either by the ipl loader or directly by PSW restart +# or linload or SALIPL +# + .org 0x10000 +startup:basr %r13,0 # get base +.LPG1: l %r1, .Lget_ipl_device_addr-.LPG1(%r13) + basr %r14, %r1 + lctl %c0,%c15,.Lctl-.LPG1(%r13) # load control registers + la %r12,_pstart-.LPG1(%r13) # pointer to parameter area + # move IPL device to lowcore + mvc __LC_IPLDEV(4),IPL_DEVICE-PARMAREA(%r12) + +# +# clear bss memory +# + l %r2,.Lbss_bgn-.LPG1(%r13) # start of bss + l %r3,.Lbss_end-.LPG1(%r13) # end of bss + sr %r3,%r2 # length of bss + sr %r4,%r4 + sr %r5,%r5 # set src,length and pad to zero + sr %r0,%r0 + mvcle %r2,%r4,0 # clear mem + jo .-4 # branch back, if not finish + + l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word +.Lservicecall: + stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts + + stctl %r0, %r0,.Lcr-.LPG1(%r13) # get cr0 + la %r1,0x200 # set bit 22 + o %r1,.Lcr-.LPG1(%r13) # or old cr0 with r1 + st %r1,.Lcr-.LPG1(%r13) + lctl %r0, %r0,.Lcr-.LPG1(%r13) # load modified cr0 + + mvc __LC_EXT_NEW_PSW(8),.Lpcext-.LPG1(%r13) # set postcall psw + la %r1, .Lsclph-.LPG1(%r13) + a %r1,__LC_EXT_NEW_PSW+4 # set handler + st %r1,__LC_EXT_NEW_PSW+4 + + la %r4,_pstart-.LPG1(%r13) # %r4 is our index for sccb stuff + la %r1, .Lsccb-PARMAREA(%r4) # our sccb + .insn rre,0xb2200000,%r2,%r1 # service call + ipm %r1 + srl %r1,28 # get cc code + xr %r3, %r3 + chi %r1,3 + be .Lfchunk-.LPG1(%r13) # leave + chi %r1,2 + be .Lservicecall-.LPG1(%r13) + lpsw .Lwaitsclp-.LPG1(%r13) +.Lsclph: + lh %r1,.Lsccbr-PARMAREA(%r4) + chi %r1,0x10 # 0x0010 is the sucess code + je .Lprocsccb # let's process the sccb + chi %r1,0x1f0 + bne .Lfchunk-.LPG1(%r13) # unhandled error code + c %r2, .Lrcp-.LPG1(%r13) # Did we try Read SCP forced + bne .Lfchunk-.LPG1(%r13) # if no, give up + l %r2, .Lrcp2-.LPG1(%r13) # try with Read SCP + b .Lservicecall-.LPG1(%r13) +.Lprocsccb: + lhi %r1,0 + icm %r1,3,.Lscpincr1-PARMAREA(%r4) # use this one if != 0 + jnz .Lscnd + lhi %r1,0x800 # otherwise report 2GB +.Lscnd: + lhi %r3,0x800 # limit reported memory size to 2GB + cr %r1,%r3 + jl .Lno2gb + lr %r1,%r3 +.Lno2gb: + xr %r3,%r3 # same logic + ic %r3,.Lscpa1-PARMAREA(%r4) + chi %r3,0x00 + jne .Lcompmem + l %r3,.Lscpa2-PARMAREA(%r13) +.Lcompmem: + mr %r2,%r1 # mem in MB on 128-bit + l %r1,.Lonemb-.LPG1(%r13) + mr %r2,%r1 # mem size in bytes in %r3 + b .Lfchunk-.LPG1(%r13) + + .align 4 +.Lget_ipl_device_addr: + .long .Lget_ipl_device +.Lpmask: + .byte 0 +.align 8 +.Lpcext:.long 0x00080000,0x80000000 +.Lcr: + .long 0x00 # place holder for cr0 +.Lwaitsclp: + .long 0x010a0000,0x80000000 + .Lsclph +.Lrcp: + .int 0x00120001 # Read SCP forced code +.Lrcp2: + .int 0x00020001 # Read SCP code +.Lonemb: + .int 0x100000 +.Lfchunk: + +# +# find memory chunks. +# + lr %r9,%r3 # end of mem + mvc __LC_PGM_NEW_PSW(8),.Lpcmem-.LPG1(%r13) + la %r1,1 # test in increments of 128KB + sll %r1,17 + l %r3,.Lmchunk-.LPG1(%r13) # get pointer to memory_chunk array + slr %r4,%r4 # set start of chunk to zero + slr %r5,%r5 # set end of chunk to zero + slr %r6,%r6 # set access code to zero + la %r10, MEMORY_CHUNKS # number of chunks +.Lloop: + tprot 0(%r5),0 # test protection of first byte + ipm %r7 + srl %r7,28 + clr %r6,%r7 # compare cc with last access code + be .Lsame-.LPG1(%r13) + b .Lchkmem-.LPG1(%r13) +.Lsame: + ar %r5,%r1 # add 128KB to end of chunk + bno .Lloop-.LPG1(%r13) # r1 < 0x80000000 -> loop +.Lchkmem: # > 2GB or tprot got a program check + clr %r4,%r5 # chunk size > 0? + be .Lchkloop-.LPG1(%r13) + st %r4,0(%r3) # store start address of chunk + lr %r0,%r5 + slr %r0,%r4 + st %r0,4(%r3) # store size of chunk + st %r6,8(%r3) # store type of chunk + la %r3,12(%r3) + l %r4,.Lmemsize-.LPG1(%r13) # address of variable memory_size + st %r5,0(%r4) # store last end to memory size + ahi %r10,-1 # update chunk number +.Lchkloop: + lr %r6,%r7 # set access code to last cc + # we got an exception or we're starting a new + # chunk , we must check if we should + # still try to find valid memory (if we detected + # the amount of available storage), and if we + # have chunks left + xr %r0,%r0 + clr %r0,%r9 # did we detect memory? + je .Ldonemem # if not, leave + chi %r10,0 # do we have chunks left? + je .Ldonemem + alr %r5,%r1 # add 128KB to end of chunk + lr %r4,%r5 # potential new chunk + clr %r5,%r9 # should we go on? + jl .Lloop +.Ldonemem: + l %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags +# +# find out if we are running under VM +# + stidp __LC_CPUID # store cpuid + tm __LC_CPUID,0xff # running under VM ? + bno .Lnovm-.LPG1(%r13) + oi 3(%r12),1 # set VM flag +.Lnovm: + lh %r0,__LC_CPUID+4 # get cpu version + chi %r0,0x7490 # running on a P/390 ? + bne .Lnop390-.LPG1(%r13) + oi 3(%r12),4 # set P/390 flag +.Lnop390: + +# +# find out if we have an IEEE fpu +# + mvc __LC_PGM_NEW_PSW(8),.Lpcfpu-.LPG1(%r13) + efpc %r0,0 # test IEEE extract fpc instruction + oi 3(%r12),2 # set IEEE fpu flag +.Lchkfpu: + +# +# find out if we have the CSP instruction +# + mvc __LC_PGM_NEW_PSW(8),.Lpccsp-.LPG1(%r13) + la %r0,0 + lr %r1,%r0 + la %r2,4 + csp %r0,%r2 # Test CSP instruction + oi 3(%r12),8 # set CSP flag +.Lchkcsp: + +# +# find out if we have the MVPG instruction +# + mvc __LC_PGM_NEW_PSW(8),.Lpcmvpg-.LPG1(%r13) + sr %r0,%r0 + la %r1,0 + la %r2,0 + mvpg %r1,%r2 # Test CSP instruction + oi 3(%r12),16 # set MVPG flag +.Lchkmvpg: + +# +# find out if we have the IDTE instruction +# + mvc __LC_PGM_NEW_PSW(8),.Lpcidte-.LPG1(%r13) + .long 0xb2b10000 # store facility list + tm 0xc8,0x08 # check bit for clearing-by-ASCE + bno .Lchkidte-.LPG1(%r13) + lhi %r1,2094 + lhi %r2,0 + .long 0xb98e2001 + oi 3(%r12),0x80 # set IDTE flag +.Lchkidte: + + lpsw .Lentry-.LPG1(13) # jump to _stext in primary-space, + # virtual and never return ... + .align 8 +.Lentry:.long 0x00080000,0x80000000 + _stext +.Lctl: .long 0x04b50002 # cr0: various things + .long 0 # cr1: primary space segment table + .long .Lduct # cr2: dispatchable unit control table + .long 0 # cr3: instruction authorization + .long 0 # cr4: instruction authorization + .long 0xffffffff # cr5: primary-aste origin + .long 0 # cr6: I/O interrupts + .long 0 # cr7: secondary space segment table + .long 0 # cr8: access registers translation + .long 0 # cr9: tracing off + .long 0 # cr10: tracing off + .long 0 # cr11: tracing off + .long 0 # cr12: tracing off + .long 0 # cr13: home space segment table + .long 0xc0000000 # cr14: machine check handling off + .long 0 # cr15: linkage stack operations +.Lpcmem:.long 0x00080000,0x80000000 + .Lchkmem +.Lpcfpu:.long 0x00080000,0x80000000 + .Lchkfpu +.Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp +.Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg +.Lpcidte:.long 0x00080000,0x80000000 + .Lchkidte +.Lmemsize:.long memory_size +.Lmchunk:.long memory_chunk +.Lmflags:.long machine_flags +.Lbss_bgn: .long __bss_start +.Lbss_end: .long _end + + .org PARMAREA-64 +.Lduct: .long 0,0,0,0,0,0,0,0 + .long 0,0,0,0,0,0,0,0 + +# +# params at 10400 (setup.h) +# + .org PARMAREA + .global _pstart +_pstart: + .long 0,0 # IPL_DEVICE + .long 0,RAMDISK_ORIGIN # INITRD_START + .long 0,RAMDISK_SIZE # INITRD_SIZE + + .org COMMAND_LINE + .byte "root=/dev/ram0 ro" + .byte 0 + .org 0x11000 +.Lsccb: + .hword 0x1000 # length, one page + .byte 0x00,0x00,0x00 + .byte 0x80 # variable response bit set +.Lsccbr: + .hword 0x00 # response code +.Lscpincr1: + .hword 0x00 +.Lscpa1: + .byte 0x00 + .fill 89,1,0 +.Lscpa2: + .int 0x00 +.Lscpincr2: + .quad 0x00 + .fill 3984,1,0 + .org 0x12000 + .global _pend +_pend: + + GET_IPL_DEVICE + +#ifdef CONFIG_SHARED_KERNEL + .org 0x100000 +#endif + +# +# startup-code, running in virtual mode +# + .globl _stext +_stext: basr %r13,0 # get base +.LPG3: +# +# Setup stack +# + l %r15,.Linittu-.LPG3(%r13) + mvc __LC_CURRENT(4),__TI_task(%r15) + ahi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union+THREAD_SIZE + st %r15,__LC_KERNEL_STACK # set end of kernel stack + ahi %r15,-96 + xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain + +# check control registers + stctl %c0,%c15,0(%r15) + oi 2(%r15),0x40 # enable sigp emergency signal + oi 0(%r15),0x10 # switch on low address protection + lctl %c0,%c15,0(%r15) + +# + lam 0,15,.Laregs-.LPG3(%r13) # load access regs needed by uaccess + l %r14,.Lstart-.LPG3(%r13) + basr %r14,%r14 # call start_kernel +# +# We returned from start_kernel ?!? PANIK +# + basr %r13,0 + lpsw .Ldw-.(%r13) # load disabled wait psw +# + .align 8 +.Ldw: .long 0x000a0000,0x00000000 +.Linittu:.long init_thread_union +.Lstart:.long start_kernel +.Laregs:.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index 193aafa72f54a200158d6320728b0ca0b3037654..f08c06f45d5ceea01fcb70ab3051037af13fcf70 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -1,482 +1,17 @@ /* - * arch/s390/kernel/head.S + * arch/s390/kernel/head64.S * - * S390 version - * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Hartmut Penner (hp@de.ibm.com), - * Martin Schwidefsky (schwidefsky@de.ibm.com), - * Rob van der Heij (rvdhei@iae.nl) + * (C) Copyright IBM Corp. 1999,2005 + * + * Author(s): Hartmut Penner + * Martin Schwidefsky + * Rob van der Heij + * Heiko Carstens * - * There are 5 different IPL methods - * 1) load the image directly into ram at address 0 and do an PSW restart - * 2) linload will load the image from address 0x10000 to memory 0x10000 - * and start the code thru LPSW 0x0008000080010000 (VM only, deprecated) - * 3) generate the tape ipl header, store the generated image on a tape - * and ipl from it - * In case of SL tape you need to IPL 5 times to get past VOL1 etc - * 4) generate the vm reader ipl header, move the generated image to the - * VM reader (use option NOH!) and do a ipl from reader (VM only) - * 5) direct call of start by the SALIPL loader - * We use the cpuid to distinguish between VM and native ipl - * params for kernel are pushed to 0x10400 (see setup.h) - - Changes: - Okt 25 2000 - added code to skip HDR and EOF to allow SL tape IPL (5 retries) - changed first CCW from rewind to backspace block - */ -#include -#include -#include -#include -#include -#include - -#ifndef CONFIG_IPL - .org 0 - .long 0x00080000,0x80000000+startup # Just a restart PSW -#else -#ifdef CONFIG_IPL_TAPE -#define IPL_BS 1024 - .org 0 - .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded - .long 0x27000000,0x60000001 # by ipl to addresses 0-23. - .long 0x02000000,0x20000000+IPL_BS # (a PSW and two CCWs). - .long 0x00000000,0x00000000 # external old psw - .long 0x00000000,0x00000000 # svc old psw - .long 0x00000000,0x00000000 # program check old psw - .long 0x00000000,0x00000000 # machine check old psw - .long 0x00000000,0x00000000 # io old psw - .long 0x00000000,0x00000000 - .long 0x00000000,0x00000000 - .long 0x00000000,0x00000000 - .long 0x000a0000,0x00000058 # external new psw - .long 0x000a0000,0x00000060 # svc new psw - .long 0x000a0000,0x00000068 # program check new psw - .long 0x000a0000,0x00000070 # machine check new psw - .long 0x00080000,0x80000000+.Lioint # io new psw - - .org 0x100 -# -# subroutine for loading from tape -# Paramters: -# R1 = device number -# R2 = load address -.Lloader: - st %r14,.Lldret - la %r3,.Lorbread # r3 = address of orb - la %r5,.Lirb # r5 = address of irb - st %r2,.Lccwread+4 # initialize CCW data addresses - lctl %c6,%c6,.Lcr6 - slr %r2,%r2 -.Lldlp: - la %r6,3 # 3 retries -.Lssch: - ssch 0(%r3) # load chunk of IPL_BS bytes - bnz .Llderr -.Lw4end: - bas %r14,.Lwait4io - tm 8(%r5),0x82 # do we have a problem ? - bnz .Lrecov - slr %r7,%r7 - icm %r7,3,10(%r5) # get residual count - lcr %r7,%r7 - la %r7,IPL_BS(%r7) # IPL_BS-residual=#bytes read - ar %r2,%r7 # add to total size - tm 8(%r5),0x01 # found a tape mark ? - bnz .Ldone - l %r0,.Lccwread+4 # update CCW data addresses - ar %r0,%r7 - st %r0,.Lccwread+4 - b .Lldlp -.Ldone: - l %r14,.Lldret - br %r14 # r2 contains the total size -.Lrecov: - bas %r14,.Lsense # do the sensing - bct %r6,.Lssch # dec. retry count & branch - b .Llderr -# -# Sense subroutine -# -.Lsense: - st %r14,.Lsnsret - la %r7,.Lorbsense - ssch 0(%r7) # start sense command - bnz .Llderr - bas %r14,.Lwait4io - l %r14,.Lsnsret - tm 8(%r5),0x82 # do we have a problem ? - bnz .Llderr - br %r14 -# -# Wait for interrupt subroutine -# -.Lwait4io: - lpsw .Lwaitpsw -.Lioint: - c %r1,0xb8 # compare subchannel number - bne .Lwait4io - tsch 0(%r5) - slr %r0,%r0 - tm 8(%r5),0x82 # do we have a problem ? - bnz .Lwtexit - tm 8(%r5),0x04 # got device end ? - bz .Lwait4io -.Lwtexit: - br %r14 -.Llderr: - lpsw .Lcrash - - .align 8 -.Lorbread: - .long 0x00000000,0x0080ff00,.Lccwread - .align 8 -.Lorbsense: - .long 0x00000000,0x0080ff00,.Lccwsense - .align 8 -.Lccwread: - .long 0x02200000+IPL_BS,0x00000000 -.Lccwsense: - .long 0x04200001,0x00000000 -.Lwaitpsw: - .long 0x020a0000,0x80000000+.Lioint - -.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -.Lcr6: .long 0xff000000 - .align 8 -.Lcrash:.long 0x000a0000,0x00000000 -.Lldret:.long 0 -.Lsnsret: .long 0 -#endif /* CONFIG_IPL_TAPE */ - -#ifdef CONFIG_IPL_VM -#define IPL_BS 0x730 - .org 0 - .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded - .long 0x02000018,0x60000050 # by ipl to addresses 0-23. - .long 0x02000068,0x60000050 # (a PSW and two CCWs). - .fill 80-24,1,0x40 # bytes 24-79 are discarded !! - .long 0x020000f0,0x60000050 # The next 160 byte are loaded - .long 0x02000140,0x60000050 # to addresses 0x18-0xb7 - .long 0x02000190,0x60000050 # They form the continuation - .long 0x020001e0,0x60000050 # of the CCW program started - .long 0x02000230,0x60000050 # by ipl and load the range - .long 0x02000280,0x60000050 # 0x0f0-0x730 from the image - .long 0x020002d0,0x60000050 # to the range 0x0f0-0x730 - .long 0x02000320,0x60000050 # in memory. At the end of - .long 0x02000370,0x60000050 # the channel program the PSW - .long 0x020003c0,0x60000050 # at location 0 is loaded. - .long 0x02000410,0x60000050 # Initial processing starts - .long 0x02000460,0x60000050 # at 0xf0 = iplstart. - .long 0x020004b0,0x60000050 - .long 0x02000500,0x60000050 - .long 0x02000550,0x60000050 - .long 0x020005a0,0x60000050 - .long 0x020005f0,0x60000050 - .long 0x02000640,0x60000050 - .long 0x02000690,0x60000050 - .long 0x020006e0,0x20000050 - - .org 0xf0 -# -# subroutine for loading cards from the reader -# -.Lloader: - la %r3,.Lorb # r2 = address of orb into r2 - la %r5,.Lirb # r4 = address of irb - la %r6,.Lccws - la %r7,20 -.Linit: - st %r2,4(%r6) # initialize CCW data addresses - la %r2,0x50(%r2) - la %r6,8(%r6) - bct 7,.Linit - - lctl %c6,%c6,.Lcr6 # set IO subclass mask - slr %r2,%r2 -.Lldlp: - ssch 0(%r3) # load chunk of 1600 bytes - bnz .Llderr -.Lwait4irq: - mvc 0x78(8),.Lnewpsw # set up IO interrupt psw - lpsw .Lwaitpsw -.Lioint: - c %r1,0xb8 # compare subchannel number - bne .Lwait4irq - tsch 0(%r5) - - slr %r0,%r0 - ic %r0,8(%r5) # get device status - chi %r0,8 # channel end ? - be .Lcont - chi %r0,12 # channel end + device end ? - be .Lcont - - l %r0,4(%r5) - s %r0,8(%r3) # r0/8 = number of ccws executed - mhi %r0,10 # *10 = number of bytes in ccws - lh %r3,10(%r5) # get residual count - sr %r0,%r3 # #ccws*80-residual=#bytes read - ar %r2,%r0 - - br %r14 # r2 contains the total size - -.Lcont: - ahi %r2,0x640 # add 0x640 to total size - la %r6,.Lccws - la %r7,20 -.Lincr: - l %r0,4(%r6) # update CCW data addresses - ahi %r0,0x640 - st %r0,4(%r6) - ahi %r6,8 - bct 7,.Lincr - - b .Lldlp -.Llderr: - lpsw .Lcrash - - .align 8 -.Lorb: .long 0x00000000,0x0080ff00,.Lccws -.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -.Lcr6: .long 0xff000000 -.Lloadp:.long 0,0 - .align 8 -.Lcrash:.long 0x000a0000,0x00000000 -.Lnewpsw: - .long 0x00080000,0x80000000+.Lioint -.Lwaitpsw: - .long 0x020a0000,0x80000000+.Lioint - - .align 8 -.Lccws: .rept 19 - .long 0x02600050,0x00000000 - .endr - .long 0x02200050,0x00000000 -#endif /* CONFIG_IPL_VM */ - -iplstart: - lh %r1,0xb8 # test if subchannel number - bct %r1,.Lnoload # is valid - l %r1,0xb8 # load ipl subchannel number - la %r2,IPL_BS # load start address - bas %r14,.Lloader # load rest of ipl image - larl %r12,_pstart # pointer to parameter area - st %r1,IPL_DEVICE+4-PARMAREA(%r12) # store ipl device number - -# -# load parameter file from ipl device # -.Lagain1: - l %r2,INITRD_START+4-PARMAREA(%r12)# use ramdisk location as temp - bas %r14,.Lloader # load parameter file - ltr %r2,%r2 # got anything ? - bz .Lnopf - chi %r2,895 - bnh .Lnotrunc - la %r2,895 -.Lnotrunc: - l %r4,INITRD_START+4-PARMAREA(%r12) - clc 0(3,%r4),.L_hdr # if it is HDRx - bz .Lagain1 # skip dataset header - clc 0(3,%r4),.L_eof # if it is EOFx - bz .Lagain1 # skip dateset trailer - la %r5,0(%r4,%r2) - lr %r3,%r2 -.Lidebc: - tm 0(%r5),0x80 # high order bit set ? - bo .Ldocv # yes -> convert from EBCDIC - ahi %r5,-1 - bct %r3,.Lidebc - b .Lnocv -.Ldocv: - l %r3,.Lcvtab - tr 0(256,%r4),0(%r3) # convert parameters to ascii - tr 256(256,%r4),0(%r3) - tr 512(256,%r4),0(%r3) - tr 768(122,%r4),0(%r3) -.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line - mvc 0(256,%r3),0(%r4) - mvc 256(256,%r3),256(%r4) - mvc 512(256,%r3),512(%r4) - mvc 768(122,%r3),768(%r4) - slr %r0,%r0 - b .Lcntlp -.Ldelspc: - ic %r0,0(%r2,%r3) - chi %r0,0x20 # is it a space ? - be .Lcntlp - ahi %r2,1 - b .Leolp -.Lcntlp: - brct %r2,.Ldelspc -.Leolp: - slr %r0,%r0 - stc %r0,0(%r2,%r3) # terminate buffer -.Lnopf: - -# -# load ramdisk from ipl device -# -.Lagain2: - l %r2,INITRD_START+4-PARMAREA(%r12)# load adr. of ramdisk - bas %r14,.Lloader # load ramdisk - st %r2,INITRD_SIZE+4-PARMAREA(%r12) # store size of ramdisk - ltr %r2,%r2 - bnz .Lrdcont - st %r2,INITRD_START+4-PARMAREA(%r12)# no ramdisk found, null it -.Lrdcont: - l %r2,INITRD_START+4-PARMAREA(%r12) - clc 0(3,%r2),.L_hdr # skip HDRx and EOFx - bz .Lagain2 - clc 0(3,%r2),.L_eof - bz .Lagain2 - -#ifdef CONFIG_IPL_VM -# -# reset files in VM reader -# - stidp __LC_CPUID # store cpuid - tm __LC_CPUID,0xff # running VM ? - bno .Lnoreset - la %r2,.Lreset - lhi %r3,26 - diag %r2,%r3,8 - la %r5,.Lirb - stsch 0(%r5) # check if irq is pending - tm 30(%r5),0x0f # by verifying if any of the - bnz .Lwaitforirq # activity or status control - tm 31(%r5),0xff # bits is set in the schib - bz .Lnoreset -.Lwaitforirq: - mvc 0x78(8),.Lrdrnewpsw # set up IO interrupt psw -.Lwaitrdrirq: - lpsw .Lrdrwaitpsw -.Lrdrint: - c %r1,0xb8 # compare subchannel number - bne .Lwaitrdrirq - la %r5,.Lirb - tsch 0(%r5) -.Lnoreset: - b .Lnoload - - .align 8 -.Lrdrnewpsw: - .long 0x00080000,0x80000000+.Lrdrint -.Lrdrwaitpsw: - .long 0x020a0000,0x80000000+.Lrdrint -#endif - -# -# everything loaded, go for it -# -.Lnoload: - l %r1,.Lstartup - br %r1 - -.Lstartup: .long startup -.Lcvtab:.long _ebcasc # ebcdic to ascii table -.Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40 - .byte 0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6 - .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold" -.L_eof: .long 0xc5d6c600 /* C'EOF' */ -.L_hdr: .long 0xc8c4d900 /* C'HDR' */ -#endif /* CONFIG_IPL */ - -# -# SALIPL loader support. Based on a patch by Rob van der Heij. -# This entry point is called directly from the SALIPL loader and -# doesn't need a builtin ipl record. -# - .org 0x800 - .globl start -start: - stm %r0,%r15,0x07b0 # store registers - basr %r12,%r0 -.base: - l %r11,.parm - l %r8,.cmd # pointer to command buffer - - ltr %r9,%r9 # do we have SALIPL parameters? - bp .sk8x8 - - mvc 0(64,%r8),0x00b0 # copy saved registers - xc 64(240-64,%r8),0(%r8) # remainder of buffer - tr 0(64,%r8),.lowcase - b .gotr -.sk8x8: - mvc 0(240,%r8),0(%r9) # copy iplparms into buffer -.gotr: - l %r10,.tbl # EBCDIC to ASCII table - tr 0(240,%r8),0(%r10) - stidp __LC_CPUID # Are we running on VM maybe - cli __LC_CPUID,0xff - bnz .test - .long 0x83300060 # diag 3,0,x'0060' - storage size - b .done -.test: - mvc 0x68(8),.pgmnw # set up pgm check handler - l %r2,.fourmeg - lr %r3,%r2 - bctr %r3,%r0 # 4M-1 -.loop: iske %r0,%r3 - ar %r3,%r2 -.pgmx: - sr %r3,%r2 - la %r3,1(%r3) -.done: - l %r1,.memsize - st %r3,4(%r1) - slr %r0,%r0 - st %r0,INITRD_SIZE+4-PARMAREA(%r11) - st %r0,INITRD_START+4-PARMAREA(%r11) - j startup # continue with startup -.tbl: .long _ebcasc # translate table -.cmd: .long COMMAND_LINE # address of command line buffer -.parm: .long PARMAREA -.fourmeg: .long 0x00400000 # 4M -.pgmnw: .long 0x00080000,.pgmx -.memsize: .long memory_size -.lowcase: - .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 - .byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f - .byte 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17 - .byte 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f - .byte 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27 - .byte 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f - .byte 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37 - .byte 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f - .byte 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47 - .byte 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f - .byte 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57 - .byte 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f - .byte 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67 - .byte 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f - .byte 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77 - .byte 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f - - .byte 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87 - .byte 0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f - .byte 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97 - .byte 0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f - .byte 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7 - .byte 0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf - .byte 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7 - .byte 0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf - .byte 0xc0,0x81,0x82,0x83,0x84,0x85,0x86,0x87 # .abcdefg - .byte 0x88,0x89,0xca,0xcb,0xcc,0xcd,0xce,0xcf # hi - .byte 0xd0,0x91,0x92,0x93,0x94,0x95,0x96,0x97 # .jklmnop - .byte 0x98,0x99,0xda,0xdb,0xdc,0xdd,0xde,0xdf # qr - .byte 0xe0,0xe1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7 # ..stuvwx - .byte 0xa8,0xa9,0xea,0xeb,0xec,0xed,0xee,0xef # yz - .byte 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7 - .byte 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff - -# -# startup-code at 0x10000, running in real mode +# startup-code at 0x10000, running in absolute addressing mode # this is called either by the ipl loader or directly by PSW restart # or linload or SALIPL # @@ -530,7 +65,7 @@ startup:basr %r13,0 # get base be .Lfchunk-.LPG1(%r13) # leave chi %r1,2 be .Lservicecall-.LPG1(%r13) - lpsw .Lwaitsclp-.LPG1(%r13) + lpswe .Lwaitsclp-.LPG1(%r13) .Lsclph: lh %r1,.Lsccbr-PARMAREA(%r4) chi %r1,0x10 # 0x0010 is the sucess code @@ -567,8 +102,7 @@ startup:basr %r13,0 # get base .Lcr: .quad 0x00 # place holder for cr0 .Lwaitsclp: - .long 0x020A0000 - .quad .Lsclph + .quad 0x0102000180000000,.Lsclph .Lrcp: .int 0x00120001 # Read SCP forced code .Lrcp2: @@ -751,62 +285,7 @@ _pstart: .global _pend _pend: -.Lget_ipl_device: - basr %r12,0 -.LPG2: l %r1,0xb8 # get sid - sll %r1,15 # test if subchannel is enabled - srl %r1,31 - ltr %r1,%r1 - bz 0(%r14) # subchannel disabled - l %r1,0xb8 - la %r5,.Lipl_schib-.LPG2(%r12) - stsch 0(%r5) # get schib of subchannel - bnz 0(%r14) # schib not available - tm 5(%r5),0x01 # devno valid? - bno 0(%r14) - la %r6,ipl_parameter_flags-.LPG2(%r12) - oi 3(%r6),0x01 # set flag - la %r2,ipl_devno-.LPG2(%r12) - mvc 0(2,%r2),6(%r5) # store devno - tm 4(%r5),0x80 # qdio capable device? - bno 0(%r14) - oi 3(%r6),0x02 # set flag - - # copy ipl parameters - - lhi %r0,4096 - l %r2,20(%r0) # get address of parameter list - lhi %r3,IPL_PARMBLOCK_ORIGIN - st %r3,20(%r0) - lhi %r4,1 - cr %r2,%r3 # start parameters < destination ? - jl 0f - lhi %r1,1 # copy direction is upwards - j 1f -0: lhi %r1,-1 # copy direction is downwards - ar %r2,%r0 - ar %r3,%r0 - ar %r2,%r1 - ar %r3,%r1 -1: mvc 0(1,%r3),0(%r2) # finally copy ipl parameters - ar %r3,%r1 - ar %r2,%r1 - sr %r0,%r4 - jne 1b - b 0(%r14) - - .align 4 -.Lipl_schib: - .rept 13 - .long 0 - .endr - - .globl ipl_parameter_flags -ipl_parameter_flags: - .long 0 - .globl ipl_devno -ipl_devno: - .word 0 + GET_IPL_DEVICE #ifdef CONFIG_SHARED_KERNEL .org 0x100000 diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 9a1d95894f3df95e8201f210894ab88dcf651e07..c36353e8c1404b22ae5dfbd8f0b0bd8f1a8214b8 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -237,6 +237,8 @@ int sysctl_hz_timer = 1; */ static inline void stop_hz_timer(void) { + unsigned long flags; + unsigned long seq, next; __u64 timer, todval; if (sysctl_hz_timer != 0) @@ -257,7 +259,11 @@ static inline void stop_hz_timer(void) * This cpu is going really idle. Set up the clock comparator * for the next event. */ - timer = (__u64) (next_timer_interrupt() - jiffies) + jiffies_64; + next = next_timer_interrupt(); + do { + seq = read_seqbegin_irqsave(&xtime_lock, flags); + timer = (__u64)(next - jiffies) + jiffies_64; + } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); todval = -1ULL; /* Be careful about overflows. */ if (timer < (-1ULL / CLK_TICKS_PER_JIFFY)) { diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 6b8703ec2ae66edf93f527a44d4ecaf2af108f42..c5bd36fae56b29294db4953a5375441a5e047720 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -57,7 +57,6 @@ int sysctl_userprocess_debug = 0; extern pgm_check_handler_t do_protection_exception; extern pgm_check_handler_t do_dat_exception; -extern pgm_check_handler_t do_pseudo_page_fault; #ifdef CONFIG_PFAULT extern int pfault_init(void); extern void pfault_fini(void); @@ -676,20 +675,6 @@ asmlinkage void kernel_stack_overflow(struct pt_regs * regs) panic("Corrupt kernel stack, can't continue."); } -#ifndef CONFIG_ARCH_S390X -static int -pagex_reboot_event(struct notifier_block *this, unsigned long event, void *ptr) -{ - if (MACHINE_IS_VM) - cpcmd("SET PAGEX OFF", NULL, 0, NULL); - return NOTIFY_DONE; -} - -static struct notifier_block pagex_reboot_notifier = { - .notifier_call = &pagex_reboot_event, -}; -#endif - /* init is done in lowcore.S and head.S */ void __init trap_init(void) @@ -717,9 +702,7 @@ void __init trap_init(void) pgm_check_table[0x11] = &do_dat_exception; pgm_check_table[0x12] = &translation_exception; pgm_check_table[0x13] = &special_op_exception; -#ifndef CONFIG_ARCH_S390X - pgm_check_table[0x14] = &do_pseudo_page_fault; -#else /* CONFIG_ARCH_S390X */ +#ifdef CONFIG_ARCH_S390X pgm_check_table[0x38] = &do_dat_exception; pgm_check_table[0x39] = &do_dat_exception; pgm_check_table[0x3A] = &do_dat_exception; @@ -731,12 +714,10 @@ void __init trap_init(void) pgm_check_table[0x40] = &do_monitor_call; if (MACHINE_IS_VM) { +#ifdef CONFIG_PFAULT /* - * First try to get pfault pseudo page faults going. - * If this isn't available turn on pagex page faults. + * Try to get pfault pseudo page faults going. */ -#ifdef CONFIG_PFAULT - /* request the 0x2603 external interrupt */ if (register_early_external_interrupt(0x2603, pfault_interrupt, &ext_int_pfault) != 0) panic("Couldn't request external interrupt 0x2603"); @@ -747,10 +728,6 @@ void __init trap_init(void) /* Tough luck, no pfault. */ unregister_early_external_interrupt(0x2603, pfault_interrupt, &ext_int_pfault); -#endif -#ifndef CONFIG_ARCH_S390X - register_reboot_notifier(&pagex_reboot_notifier); - cpcmd("SET PAGEX ON", NULL, 0, NULL); #endif } } diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index c5348108ca3ce23e8da4a6681c32330ebad73122..506a33b51e4f789317a3a854fb7eef9221aa7827 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c @@ -234,8 +234,8 @@ query_segment_type (struct dcss_segment *seg) rc = 0; out_free: - if (qin) kfree(qin); - if (qout) kfree(qout); + kfree(qin); + kfree(qout); return rc; } @@ -394,7 +394,7 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long segtype_string[seg->vm_segtype]); goto out; out_free: - kfree (seg); + kfree(seg); out: return rc; } @@ -505,7 +505,7 @@ segment_modify_shared (char *name, int do_nonshared) list_del(&seg->list); dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy); - kfree (seg); + kfree(seg); out_unlock: spin_unlock(&dcss_lock); return rc; diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 856a971759b1a2d0776c347914d1dc3015885659..64e32da777541b69f053d18ec7a3508b0ea40c0b 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -352,115 +352,6 @@ void do_dat_exception(struct pt_regs *regs, unsigned long error_code) do_exception(regs, error_code & 0xff, 0); } -#ifndef CONFIG_ARCH_S390X - -typedef struct _pseudo_wait_t { - struct _pseudo_wait_t *next; - wait_queue_head_t queue; - unsigned long address; - int resolved; -} pseudo_wait_t; - -static pseudo_wait_t *pseudo_lock_queue = NULL; -static spinlock_t pseudo_wait_spinlock; /* spinlock to protect lock queue */ - -/* - * This routine handles 'pagex' pseudo page faults. - */ -asmlinkage void -do_pseudo_page_fault(struct pt_regs *regs, unsigned long error_code) -{ - pseudo_wait_t wait_struct; - pseudo_wait_t *ptr, *last, *next; - unsigned long address; - - /* - * get the failing address - * more specific the segment and page table portion of - * the address - */ - address = S390_lowcore.trans_exc_code & 0xfffff000; - - if (address & 0x80000000) { - /* high bit set -> a page has been swapped in by VM */ - address &= 0x7fffffff; - spin_lock(&pseudo_wait_spinlock); - last = NULL; - ptr = pseudo_lock_queue; - while (ptr != NULL) { - next = ptr->next; - if (address == ptr->address) { - /* - * This is one of the processes waiting - * for the page. Unchain from the queue. - * There can be more than one process - * waiting for the same page. VM presents - * an initial and a completion interrupt for - * every process that tries to access a - * page swapped out by VM. - */ - if (last == NULL) - pseudo_lock_queue = next; - else - last->next = next; - /* now wake up the process */ - ptr->resolved = 1; - wake_up(&ptr->queue); - } else - last = ptr; - ptr = next; - } - spin_unlock(&pseudo_wait_spinlock); - } else { - /* Pseudo page faults in kernel mode is a bad idea */ - if (!(regs->psw.mask & PSW_MASK_PSTATE)) { - /* - * VM presents pseudo page faults if the interrupted - * state was not disabled for interrupts. So we can - * get pseudo page fault interrupts while running - * in kernel mode. We simply access the page here - * while we are running disabled. VM will then swap - * in the page synchronously. - */ - if (check_user_space(regs, error_code) == 0) - /* dereference a virtual kernel address */ - __asm__ __volatile__ ( - " ic 0,0(%0)" - : : "a" (address) : "0"); - else - /* dereference a virtual user address */ - __asm__ __volatile__ ( - " la 2,0(%0)\n" - " sacf 512\n" - " ic 2,0(2)\n" - "0:sacf 0\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 0b,0b\n" - ".previous" - : : "a" (address) : "2" ); - - return; - } - /* initialize and add element to pseudo_lock_queue */ - init_waitqueue_head (&wait_struct.queue); - wait_struct.address = address; - wait_struct.resolved = 0; - spin_lock(&pseudo_wait_spinlock); - wait_struct.next = pseudo_lock_queue; - pseudo_lock_queue = &wait_struct; - spin_unlock(&pseudo_wait_spinlock); - /* - * The instruction that caused the program check will - * be repeated. Don't signal single step via SIGTRAP. - */ - clear_tsk_thread_flag(current, TIF_SINGLE_STEP); - /* go to sleep */ - wait_event(wait_struct.queue, wait_struct.resolved); - } -} -#endif /* CONFIG_ARCH_S390X */ - #ifdef CONFIG_PFAULT /* * 'pfault' pseudo page faults routines. @@ -508,7 +399,7 @@ int pfault_init(void) " .quad 0b,1b\n" #endif /* CONFIG_ARCH_S390X */ ".previous" - : "=d" (rc) : "a" (&refbk) : "cc" ); + : "=d" (rc) : "a" (&refbk), "m" (refbk) : "cc" ); __ctl_set_bit(0, 9); return rc; } @@ -532,7 +423,7 @@ void pfault_fini(void) " .quad 0b,0b\n" #endif /* CONFIG_ARCH_S390X */ ".previous" - : : "a" (&refbk) : "cc" ); + : : "a" (&refbk), "m" (refbk) : "cc" ); } asmlinkage void diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 3e804c736e640eb9340128cf2adb18435a2ee61c..64f5ae0ff96d1474c3f4052848ced900c78d5a1f 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -490,16 +490,6 @@ config CPU_SUBTYPE_ST40 depends on CPU_SUBTYPE_ST40STB1 || CPU_SUBTYPE_ST40GX1 default y -config ARCH_DISCONTIGMEM_ENABLE - bool - depends on SH_HP690 - default y - help - Say Y to upport efficient handling of discontiguous physical memory, - for architectures which are either NUMA (Non-Uniform Memory Access) - or have huge holes in the physical address space for other reasons. - See for more. - source "mm/Kconfig" config ZERO_PAGE_OFFSET @@ -770,24 +760,6 @@ source "fs/Kconfig.binfmt" endmenu -menu "SH initrd options" - depends on BLK_DEV_INITRD - -config EMBEDDED_RAMDISK - bool "Embed root filesystem ramdisk into the kernel" - -config EMBEDDED_RAMDISK_IMAGE - string "Filename of gziped ramdisk image" - depends on EMBEDDED_RAMDISK - default "ramdisk.gz" - help - This is the filename of the ramdisk image to be built into the - kernel. Relative pathnames are relative to arch/sh/ramdisk/. - The ramdisk image is not part of the kernel distribution; you must - provide one yourself. - -endmenu - source "net/Kconfig" source "drivers/Kconfig" diff --git a/arch/sh/Makefile b/arch/sh/Makefile index 4a3049080b4190cc61518d2625195e95d1737f65..67192d6b00d8ec550c853e1fdc9b7010e1ea02e3 100644 --- a/arch/sh/Makefile +++ b/arch/sh/Makefile @@ -60,14 +60,6 @@ LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) core-y += arch/sh/kernel/ arch/sh/mm/ -# -# ramdisk/initrd support -# You need a compressed ramdisk image, named -# CONFIG_EMBEDDED_RAMDISK_IMAGE. Relative pathnames -# are relative to arch/sh/ramdisk/. -# -core-$(CONFIG_EMBEDDED_RAMDISK) += arch/sh/ramdisk/ - # Boards machdir-$(CONFIG_SH_SOLUTION_ENGINE) := se/770x machdir-$(CONFIG_SH_7751_SOLUTION_ENGINE) := se/7751 diff --git a/arch/sh/drivers/Makefile b/arch/sh/drivers/Makefile index bd6726cde398b307ff19d9a435ec64f386892254..338c3729d2705095a338743e2cb6b5528275dbd2 100644 --- a/arch/sh/drivers/Makefile +++ b/arch/sh/drivers/Makefile @@ -2,6 +2,7 @@ # Makefile for the Linux SuperH-specific device drivers. # -obj-$(CONFIG_PCI) += pci/ -obj-$(CONFIG_SH_DMA) += dma/ +obj-$(CONFIG_PCI) += pci/ +obj-$(CONFIG_SH_DMA) += dma/ +obj-$(CONFIG_SUPERHYWAY) += superhyway/ diff --git a/arch/sh/drivers/superhyway/Makefile b/arch/sh/drivers/superhyway/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5b8e0c7ca3a57b087232644c9174a2c9bab5ef59 --- /dev/null +++ b/arch/sh/drivers/superhyway/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the SuperHyway specific kernel interface routines under Linux. +# + +obj-$(CONFIG_CPU_SUBTYPE_SH4_202) += ops-sh4-202.o + diff --git a/arch/sh/drivers/superhyway/ops-sh4-202.c b/arch/sh/drivers/superhyway/ops-sh4-202.c new file mode 100644 index 0000000000000000000000000000000000000000..a55c98a9052bd4303041adc267a2d1373e00a29b --- /dev/null +++ b/arch/sh/drivers/superhyway/ops-sh4-202.c @@ -0,0 +1,171 @@ +/* + * arch/sh/drivers/superhyway/ops-sh4-202.c + * + * SuperHyway bus support for SH4-202 + * + * Copyright (C) 2005 Paul Mundt + * + * 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 + +#define PHYS_EMI_CBLOCK P4SEGADDR(0x1ec00000) +#define PHYS_EMI_DBLOCK P4SEGADDR(0x08000000) +#define PHYS_FEMI_CBLOCK P4SEGADDR(0x1f800000) +#define PHYS_FEMI_DBLOCK P4SEGADDR(0x00000000) + +#define PHYS_EPBR_BLOCK P4SEGADDR(0x1de00000) +#define PHYS_DMAC_BLOCK P4SEGADDR(0x1fa00000) +#define PHYS_PBR_BLOCK P4SEGADDR(0x1fc00000) + +static struct resource emi_resources[] = { + [0] = { + .start = PHYS_EMI_CBLOCK, + .end = PHYS_EMI_CBLOCK + 0x00300000 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = PHYS_EMI_DBLOCK, + .end = PHYS_EMI_DBLOCK + 0x08000000 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct superhyway_device emi_device = { + .name = "emi", + .num_resources = ARRAY_SIZE(emi_resources), + .resource = emi_resources, +}; + +static struct resource femi_resources[] = { + [0] = { + .start = PHYS_FEMI_CBLOCK, + .end = PHYS_FEMI_CBLOCK + 0x00100000 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = PHYS_FEMI_DBLOCK, + .end = PHYS_FEMI_DBLOCK + 0x08000000 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct superhyway_device femi_device = { + .name = "femi", + .num_resources = ARRAY_SIZE(femi_resources), + .resource = femi_resources, +}; + +static struct resource epbr_resources[] = { + [0] = { + .start = P4SEGADDR(0x1e7ffff8), + .end = P4SEGADDR(0x1e7ffff8 + (sizeof(u32) * 2) - 1), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = PHYS_EPBR_BLOCK, + .end = PHYS_EPBR_BLOCK + 0x00a00000 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct superhyway_device epbr_device = { + .name = "epbr", + .num_resources = ARRAY_SIZE(epbr_resources), + .resource = epbr_resources, +}; + +static struct resource dmac_resource = { + .start = PHYS_DMAC_BLOCK, + .end = PHYS_DMAC_BLOCK + 0x00100000 - 1, + .flags = IORESOURCE_MEM, +}; + +static struct superhyway_device dmac_device = { + .name = "dmac", + .num_resources = 1, + .resource = &dmac_resource, +}; + +static struct resource pbr_resources[] = { + [0] = { + .start = P4SEGADDR(0x1ffffff8), + .end = P4SEGADDR(0x1ffffff8 + (sizeof(u32) * 2) - 1), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = PHYS_PBR_BLOCK, + .end = PHYS_PBR_BLOCK + 0x00400000 - (sizeof(u32) * 2) - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct superhyway_device pbr_device = { + .name = "pbr", + .num_resources = ARRAY_SIZE(pbr_resources), + .resource = pbr_resources, +}; + +static struct superhyway_device *sh4202_devices[] __initdata = { + &emi_device, &femi_device, &epbr_device, &dmac_device, &pbr_device, +}; + +static int sh4202_read_vcr(unsigned long base, struct superhyway_vcr_info *vcr) +{ + u32 vcrh, vcrl; + u64 tmp; + + /* + * XXX: Even though the SH4-202 Evaluation Device documentation + * indicates that VCRL is mapped first with VCRH at a + 0x04 + * offset, the opposite seems to be true. + * + * Some modules (PBR and ePBR for instance) also appear to have + * VCRL/VCRH flipped in the documentation, but on the SH4-202 + * itself it appears that these are all consistently mapped with + * VCRH preceeding VCRL. + * + * Do not trust the documentation, for it is evil. + */ + vcrh = ctrl_inl(base); + vcrl = ctrl_inl(base + sizeof(u32)); + + tmp = ((u64)vcrh << 32) | vcrl; + memcpy(vcr, &tmp, sizeof(u64)); + + return 0; +} + +static int sh4202_write_vcr(unsigned long base, struct superhyway_vcr_info vcr) +{ + u64 tmp = *(u64 *)&vcr; + + ctrl_outl((tmp >> 32) & 0xffffffff, base); + ctrl_outl(tmp & 0xffffffff, base + sizeof(u32)); + + return 0; +} + +static struct superhyway_ops sh4202_superhyway_ops = { + .read_vcr = sh4202_read_vcr, + .write_vcr = sh4202_write_vcr, +}; + +struct superhyway_bus superhyway_channels[] = { + { &sh4202_superhyway_ops, }, + { 0, }, +}; + +int __init superhyway_scan_bus(struct superhyway_bus *bus) +{ + return superhyway_add_devices(bus, sh4202_devices, + ARRAY_SIZE(sh4202_devices)); +} + diff --git a/arch/sh/kernel/ptrace.c b/arch/sh/kernel/ptrace.c index 1fbe5a428e31fe54c017a58bff0d5b82efaea24e..1a8be06519ecf4c5de4fc7bcd5ed8dc56bad069b 100644 --- a/arch/sh/kernel/ptrace.c +++ b/arch/sh/kernel/ptrace.c @@ -80,48 +80,11 @@ void ptrace_disable(struct task_struct *child) /* nothing to do.. */ } -asmlinkage long sys_ptrace(long request, long pid, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, long addr, long data) { - struct task_struct *child; struct user * dummy = NULL; int ret; - lock_kernel(); - ret = -EPERM; - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - ret = security_ptrace(current->parent, current); - if (ret) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) - goto out_tsk; - switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ @@ -289,10 +252,7 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data) ret = ptrace_request(child, request, addr, data); break; } -out_tsk: - put_task_struct(child); -out: - unlock_kernel(); + return ret; } diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 25b9d9ebe858b83163f00b83666a839124379b01..036050b377cdd6458ae1cf1858bfb445a4aad4aa 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -83,9 +83,9 @@ static struct sh_machine_vector* __init get_mv_byname(const char* name); /* ... */ #define COMMAND_LINE ((char *) (PARAM+0x100)) -#define RAMDISK_IMAGE_START_MASK 0x07FF +#define RAMDISK_IMAGE_START_MASK 0x07FF #define RAMDISK_PROMPT_FLAG 0x8000 -#define RAMDISK_LOAD_FLAG 0x4000 +#define RAMDISK_LOAD_FLAG 0x4000 static char command_line[COMMAND_LINE_SIZE] = { 0, }; @@ -284,18 +284,6 @@ void __init setup_arch(char **cmdline_p) #define PFN_DOWN(x) ((x) >> PAGE_SHIFT) #define PFN_PHYS(x) ((x) << PAGE_SHIFT) -#ifdef CONFIG_DISCONTIGMEM - NODE_DATA(0)->bdata = &discontig_node_bdata[0]; - NODE_DATA(1)->bdata = &discontig_node_bdata[1]; - - bootmap_size = init_bootmem_node(NODE_DATA(1), - PFN_UP(__MEMORY_START_2ND), - PFN_UP(__MEMORY_START_2ND), - PFN_DOWN(__MEMORY_START_2ND+__MEMORY_SIZE_2ND)); - free_bootmem_node(NODE_DATA(1), __MEMORY_START_2ND, __MEMORY_SIZE_2ND); - reserve_bootmem_node(NODE_DATA(1), __MEMORY_START_2ND, bootmap_size); -#endif - /* * Find the highest page frame number we have available */ @@ -306,10 +294,10 @@ void __init setup_arch(char **cmdline_p) */ max_low_pfn = max_pfn; - /* + /* * Partially used pages are not usable - thus * we are rounding upwards: - */ + */ start_pfn = PFN_UP(__pa(_end)); /* @@ -360,12 +348,12 @@ void __init setup_arch(char **cmdline_p) reserve_bootmem_node(NODE_DATA(0), __MEMORY_START, PAGE_SIZE); #ifdef CONFIG_BLK_DEV_INITRD - ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); - if (&__rd_start != &__rd_end) { + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + if (&__rd_start != &__rd_end) { LOADER_TYPE = 1; INITRD_START = PHYSADDR((unsigned long)&__rd_start) - __MEMORY_START; INITRD_SIZE = (unsigned long)&__rd_end - (unsigned long)&__rd_start; - } + } if (LOADER_TYPE && INITRD_START) { if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) { diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 4e9c854845a4461155b5fd040de85dcdf4c19784..e342565f75fbc464684faf8e54f28e05134475ea 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -51,11 +51,6 @@ unsigned long mmu_context_cache = NO_CONTEXT; #define MAX_LOW_PFN (NODE_DATA(0)->bdata->node_low_pfn) #endif -#ifdef CONFIG_DISCONTIGMEM -pg_data_t discontig_page_data[MAX_NUMNODES]; -bootmem_data_t discontig_node_bdata[MAX_NUMNODES]; -#endif - void (*copy_page)(void *from, void *to); void (*clear_page)(void *to); @@ -216,15 +211,6 @@ void __init paging_init(void) #endif NODE_DATA(0)->node_mem_map = NULL; free_area_init_node(0, NODE_DATA(0), zones_size, __MEMORY_START >> PAGE_SHIFT, 0); - -#ifdef CONFIG_DISCONTIGMEM - /* - * And for discontig, do some more fixups on the zone sizes.. - */ - zones_size[ZONE_DMA] = __MEMORY_SIZE_2ND >> PAGE_SHIFT; - zones_size[ZONE_NORMAL] = 0; - free_area_init_node(1, NODE_DATA(1), zones_size, __MEMORY_START_2ND >> PAGE_SHIFT, 0); -#endif } void __init mem_init(void) @@ -248,7 +234,7 @@ void __init mem_init(void) memset(empty_zero_page, 0, PAGE_SIZE); __flush_wback_region(empty_zero_page, PAGE_SIZE); - /* + /* * Setup wrappers for copy/clear_page(), these will get overridden * later in the boot process if a better method is available. */ @@ -257,9 +243,6 @@ void __init mem_init(void) /* this will put all low memory onto the freelists */ totalram_pages += free_all_bootmem_node(NODE_DATA(0)); -#ifdef CONFIG_DISCONTIGMEM - totalram_pages += free_all_bootmem_node(NODE_DATA(1)); -#endif reservedpages = 0; for (tmp = 0; tmp < num_physpages; tmp++) /* @@ -286,7 +269,7 @@ void __init mem_init(void) void free_initmem(void) { unsigned long addr; - + addr = (unsigned long)(&__init_begin); for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { ClearPageReserved(virt_to_page(addr)); diff --git a/arch/sh/mm/tlb-sh3.c b/arch/sh/mm/tlb-sh3.c index 7a0d5c10bf20908dfad7a58fb8f96300f1f61f2e..46b09e26e0825fa411a593fdd4f5755e01d4f77a 100644 --- a/arch/sh/mm/tlb-sh3.c +++ b/arch/sh/mm/tlb-sh3.c @@ -40,12 +40,17 @@ void update_mmu_cache(struct vm_area_struct * vma, return; #if defined(CONFIG_SH7705_CACHE_32KB) - struct page *page; - page = pte_page(pte); - if (VALID_PAGE(page) && !test_bit(PG_mapped, &page->flags)) { - unsigned long phys = pte_val(pte) & PTE_PHYS_MASK; - __flush_wback_region((void *)P1SEGADDR(phys), PAGE_SIZE); - __set_bit(PG_mapped, &page->flags); + { + struct page *page = pte_page(pte); + unsigned long pfn = pte_pfn(pte); + + if (pfn_valid(pfn) && !test_bit(PG_mapped, &page->flags)) { + unsigned long phys = pte_val(pte) & PTE_PHYS_MASK; + + __flush_wback_region((void *)P1SEGADDR(phys), + PAGE_SIZE); + __set_bit(PG_mapped, &page->flags); + } } #endif @@ -80,7 +85,7 @@ void __flush_tlb_page(unsigned long asid, unsigned long page) */ addr = MMU_TLB_ADDRESS_ARRAY | (page & 0x1F000); data = (page & 0xfffe0000) | asid; /* VALID bit is off */ - + if ((cpu_data->flags & CPU_HAS_MMU_PAGE_ASSOC)) { addr |= MMU_PAGE_ASSOC_BIT; ways = 1; /* we already know the way .. */ diff --git a/arch/sh/ramdisk/Makefile b/arch/sh/ramdisk/Makefile deleted file mode 100644 index 99e1c68673cfa35eab15ce7f6bdd633408b435a9..0000000000000000000000000000000000000000 --- a/arch/sh/ramdisk/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# -# Makefile for a ramdisk image -# - -obj-y += ramdisk.o - - -O_FORMAT = $(shell $(OBJDUMP) -i | head -n 2 | grep elf32) -img := $(subst ",,$(CONFIG_EMBEDDED_RAMDISK_IMAGE)) -# add $(src) when $(img) is relative -img := $(subst $(src)//,/,$(src)/$(img)) - -quiet_cmd_ramdisk = LD $@ -define cmd_ramdisk - $(LD) -T $(srctree)/$(src)/ld.script -b binary --oformat $(O_FORMAT) \ - -o $@ $(img) -endef - -$(obj)/ramdisk.o: $(img) $(srctree)/$(src)/ld.script - $(call cmd,ramdisk) diff --git a/arch/sh/ramdisk/ld.script b/arch/sh/ramdisk/ld.script deleted file mode 100644 index 94beee248c044e6fa69c0f168032c1ec7febef9e..0000000000000000000000000000000000000000 --- a/arch/sh/ramdisk/ld.script +++ /dev/null @@ -1,9 +0,0 @@ -OUTPUT_ARCH(sh) -SECTIONS -{ - .initrd : - { - *(.data) - } -} - diff --git a/arch/sh64/kernel/ptrace.c b/arch/sh64/kernel/ptrace.c index 71f2eec00b99d3f6004457a2be1fec1347ee651d..cd22e94713165ce9e9335936a78852d68d522658 100644 --- a/arch/sh64/kernel/ptrace.c +++ b/arch/sh64/kernel/ptrace.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -121,61 +122,11 @@ put_fpu_long(struct task_struct *task, unsigned long addr, unsigned long data) return 0; } -asmlinkage long sys_ptrace(long request, long pid, long addr, long data) + +long arch_ptrace(struct task_struct *child, long request, long addr, long data) { - struct task_struct *child; - extern void poke_real_address_q(unsigned long long addr, unsigned long long data); -#define WPC_DBRMODE 0x0d104008 - static int first_call = 1; int ret; - lock_kernel(); - - if (first_call) { - /* Set WPC.DBRMODE to 0. This makes all debug events get - * delivered through RESVEC, i.e. into the handlers in entry.S. - * (If the kernel was downloaded using a remote gdb, WPC.DBRMODE - * would normally be left set to 1, which makes debug events get - * delivered through DBRVEC, i.e. into the remote gdb's - * handlers. This prevents ptrace getting them, and confuses - * the remote gdb.) */ - printk("DBRMODE set to 0 to permit native debugging\n"); - poke_real_address_q(WPC_DBRMODE, 0); - first_call = 0; - } - - ret = -EPERM; - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) - goto out_tsk; - switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ @@ -313,13 +264,33 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data) ret = ptrace_request(child, request, addr, data); break; } -out_tsk: - put_task_struct(child); -out: - unlock_kernel(); return ret; } +asmlinkage int sh64_ptrace(long request, long pid, long addr, long data) +{ + extern void poke_real_address_q(unsigned long long addr, unsigned long long data); +#define WPC_DBRMODE 0x0d104008 + static int first_call = 1; + + lock_kernel(); + if (first_call) { + /* Set WPC.DBRMODE to 0. This makes all debug events get + * delivered through RESVEC, i.e. into the handlers in entry.S. + * (If the kernel was downloaded using a remote gdb, WPC.DBRMODE + * would normally be left set to 1, which makes debug events get + * delivered through DBRVEC, i.e. into the remote gdb's + * handlers. This prevents ptrace getting them, and confuses + * the remote gdb.) */ + printk("DBRMODE set to 0 to permit native debugging\n"); + poke_real_address_q(WPC_DBRMODE, 0); + first_call = 0; + } + unlock_kernel(); + + return sys_ptrace(request, pid, addr, data); +} + asmlinkage void syscall_trace(void) { struct task_struct *tsk = current; diff --git a/arch/sh64/kernel/syscalls.S b/arch/sh64/kernel/syscalls.S index a3d037805f1cf7e7d418e328cca61555e79479dd..c0079d54c85044d9ccdf19696b88fa091a5b109c 100644 --- a/arch/sh64/kernel/syscalls.S +++ b/arch/sh64/kernel/syscalls.S @@ -46,7 +46,7 @@ sys_call_table: .long sys_setuid16 .long sys_getuid16 .long sys_stime /* 25 */ - .long sys_ptrace + .long sh64_ptrace .long sys_alarm .long sys_fstat .long sys_pause diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 6537445dac0e8e30b519505d3639dfec42995e60..3cfb8be3ff6d0f9fe5be0c600a9f035787f767d4 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -201,6 +201,14 @@ config SUN_OPENPROMFS Only choose N if you know in advance that you will not need to modify OpenPROM settings on the running system. +config SPARC_LED + tristate "Sun4m LED driver" + help + This driver toggles the front-panel LED on sun4m systems + in a user-specifyable manner. It's state can be probed + by reading /proc/led and it's blinking mode can be changed + via writes to /proc/led + source "fs/Kconfig.binfmt" config SUNOS_EMUL diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 3d22ba2af01cf5ac1c02103f9bd8593b25672302..1b83e21841b58adac62ed9f424068f886c5a2345 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_SUN_AUXIO) += auxio.o obj-$(CONFIG_PCI) += ebus.o obj-$(CONFIG_SUN_PM) += apc.o pmc.o obj-$(CONFIG_MODULES) += module.o sparc_ksyms.o +obj-$(CONFIG_SPARC_LED) += led.o ifdef CONFIG_SUNOS_EMUL obj-y += sys_sunos.o sunos_ioctl.o diff --git a/arch/sparc/kernel/led.c b/arch/sparc/kernel/led.c new file mode 100644 index 0000000000000000000000000000000000000000..2a3afca453c9ec4b94caf91ab378d0d2e7f55d4d --- /dev/null +++ b/arch/sparc/kernel/led.c @@ -0,0 +1,139 @@ +#include +#include +#include +#include +#include + +#include + +#define LED_MAX_LENGTH 8 /* maximum chars written to proc file */ + +static inline void led_toggle(void) +{ + unsigned char val = get_auxio(); + unsigned char on, off; + + if (val & AUXIO_LED) { + on = 0; + off = AUXIO_LED; + } else { + on = AUXIO_LED; + off = 0; + } + + set_auxio(on, off); +} + +static struct timer_list led_blink_timer; + +static void led_blink(unsigned long timeout) +{ + led_toggle(); + + /* reschedule */ + if (!timeout) { /* blink according to load */ + led_blink_timer.expires = jiffies + + ((1 + (avenrun[0] >> FSHIFT)) * HZ); + led_blink_timer.data = 0; + } else { /* blink at user specified interval */ + led_blink_timer.expires = jiffies + (timeout * HZ); + led_blink_timer.data = timeout; + } + add_timer(&led_blink_timer); +} + +static int led_read_proc(char *buf, char **start, off_t offset, int count, + int *eof, void *data) +{ + int len = 0; + + if (get_auxio() & AUXIO_LED) + len = sprintf(buf, "on\n"); + else + len = sprintf(buf, "off\n"); + + return len; +} + +static int led_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char *buf = NULL; + + if (count > LED_MAX_LENGTH) + count = LED_MAX_LENGTH; + + buf = kmalloc(sizeof(char) * (count + 1), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (copy_from_user(buf, buffer, count)) { + kfree(buf); + return -EFAULT; + } + + buf[count] = '\0'; + + /* work around \n when echo'ing into proc */ + if (buf[count - 1] == '\n') + buf[count - 1] = '\0'; + + /* before we change anything we want to stop any running timers, + * otherwise calls such as on will have no persistent effect + */ + del_timer_sync(&led_blink_timer); + + if (!strcmp(buf, "on")) { + auxio_set_led(AUXIO_LED_ON); + } else if (!strcmp(buf, "toggle")) { + led_toggle(); + } else if ((*buf > '0') && (*buf <= '9')) { + led_blink(simple_strtoul(buf, NULL, 10)); + } else if (!strcmp(buf, "load")) { + led_blink(0); + } else { + auxio_set_led(AUXIO_LED_OFF); + } + + kfree(buf); + + return count; +} + +static struct proc_dir_entry *led; + +#define LED_VERSION "0.1" + +static int __init led_init(void) +{ + init_timer(&led_blink_timer); + led_blink_timer.function = led_blink; + + led = create_proc_entry("led", 0, NULL); + if (!led) + return -ENOMEM; + + led->read_proc = led_read_proc; /* reader function */ + led->write_proc = led_write_proc; /* writer function */ + led->owner = THIS_MODULE; + + printk(KERN_INFO + "led: version %s, Lars Kotthoff \n", + LED_VERSION); + + return 0; +} + +static void __exit led_exit(void) +{ + remove_proc_entry("led", NULL); + del_timer_sync(&led_blink_timer); +} + +module_init(led_init); +module_exit(led_exit); + +MODULE_AUTHOR("Lars Kotthoff "); +MODULE_DESCRIPTION("Provides control of the front LED on SPARC systems."); +MODULE_LICENSE("GPL"); +MODULE_VERSION(LED_VERSION); diff --git a/arch/sparc/kernel/sunos_ioctl.c b/arch/sparc/kernel/sunos_ioctl.c index df1c0b31a93069706ebf36cc7aba362019efea6e..a6ba3d26222c1c173d4e5960ba26904705178843 100644 --- a/arch/sparc/kernel/sunos_ioctl.c +++ b/arch/sparc/kernel/sunos_ioctl.c @@ -23,7 +23,6 @@ #include #include #include -#include #if 0 extern char sunkbd_type; diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index 1e9d8638a28a249823d31f53c7d629d392240088..3fded69b19228ca4a81013149b638d97b554143d 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -377,8 +377,21 @@ source "drivers/fc4/Kconfig" source "fs/Kconfig" +menu "Instrumentation Support" + depends on EXPERIMENTAL + source "arch/sparc64/oprofile/Kconfig" +config KPROBES + bool "Kprobes (EXPERIMENTAL)" + help + Kprobes allows you to trap at almost any kernel address and + execute a callback function. register_kprobe() establishes + a probepoint and specifies the callback. Kprobes is useful + for kernel debugging, non-intrusive instrumentation and testing. + If in doubt, say "N". +endmenu + source "arch/sparc64/Kconfig.debug" source "security/Kconfig" diff --git a/arch/sparc64/Kconfig.debug b/arch/sparc64/Kconfig.debug index fa06ea04837b9525da90580e0c4db0a3d9f3a952..3e31be494e54ab7902d4df0639ce0bdab8ffe559 100644 --- a/arch/sparc64/Kconfig.debug +++ b/arch/sparc64/Kconfig.debug @@ -11,16 +11,6 @@ config DEBUG_STACK_USAGE This option will slow down process creation somewhat. -config KPROBES - bool "Kprobes" - depends on DEBUG_KERNEL - help - Kprobes allows you to trap at almost any kernel address and - execute a callback function. register_kprobe() establishes - a probepoint and specifies the callback. Kprobes is useful - for kernel debugging, non-intrusive instrumentation and testing. - If in doubt, say "N". - config DEBUG_DCFLUSH bool "D-cache flush debugging" depends on DEBUG_KERNEL diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c index e6a00325075ac2d44df6b59a3087711a18d1fe04..92e26304de90b76fe87bdaf091f197503983ba7a 100644 --- a/arch/sparc64/kernel/ioctl32.c +++ b/arch/sparc64/kernel/ioctl32.c @@ -11,33 +11,14 @@ #define INCLUDES #include "compat_ioctl.c" -#include #include #include -#include -#include -#include -#include -#include -#include -#include /* Use this to get at 32-bit user passed pointers. * See sys_sparc32.c for description about it. */ #define A(__x) compat_ptr(__x) -static __inline__ void *alloc_user_space(long len) -{ - struct pt_regs *regs = current_thread_info()->kregs; - unsigned long usp = regs->u_regs[UREG_I6]; - - if (!(test_thread_flag(TIF_32BIT))) - usp += STACK_BIAS; - - return (void *) (usp - len); -} - #define CODE #include "compat_ioctl.c" @@ -111,357 +92,6 @@ static int fbiogscursor(unsigned int fd, unsigned int cmd, unsigned long arg) return sys_ioctl (fd, FBIOSCURSOR, (unsigned long)p); } -#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE) -/* This really belongs in include/linux/drm.h -DaveM */ -#include "../../../drivers/char/drm/drm.h" - -typedef struct drm32_version { - int version_major; /* Major version */ - int version_minor; /* Minor version */ - int version_patchlevel;/* Patch level */ - int name_len; /* Length of name buffer */ - u32 name; /* Name of driver */ - int date_len; /* Length of date buffer */ - u32 date; /* User-space buffer to hold date */ - int desc_len; /* Length of desc buffer */ - u32 desc; /* User-space buffer to hold desc */ -} drm32_version_t; -#define DRM32_IOCTL_VERSION DRM_IOWR(0x00, drm32_version_t) - -static int drm32_version(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - drm32_version_t __user *uversion = (drm32_version_t __user *)arg; - drm_version_t __user *p = compat_alloc_user_space(sizeof(*p)); - compat_uptr_t addr; - int n; - int ret; - - if (clear_user(p, 3 * sizeof(int)) || - get_user(n, &uversion->name_len) || - put_user(n, &p->name_len) || - get_user(addr, &uversion->name) || - put_user(compat_ptr(addr), &p->name) || - get_user(n, &uversion->date_len) || - put_user(n, &p->date_len) || - get_user(addr, &uversion->date) || - put_user(compat_ptr(addr), &p->date) || - get_user(n, &uversion->desc_len) || - put_user(n, &p->desc_len) || - get_user(addr, &uversion->desc) || - put_user(compat_ptr(addr), &p->desc)) - return -EFAULT; - - ret = sys_ioctl(fd, DRM_IOCTL_VERSION, (unsigned long)p); - if (ret) - return ret; - - if (copy_in_user(uversion, p, 3 * sizeof(int)) || - get_user(n, &p->name_len) || - put_user(n, &uversion->name_len) || - get_user(n, &p->date_len) || - put_user(n, &uversion->date_len) || - get_user(n, &p->desc_len) || - put_user(n, &uversion->desc_len)) - return -EFAULT; - - return 0; -} - -typedef struct drm32_unique { - int unique_len; /* Length of unique */ - u32 unique; /* Unique name for driver instantiation */ -} drm32_unique_t; -#define DRM32_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm32_unique_t) -#define DRM32_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm32_unique_t) - -static int drm32_getsetunique(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - drm32_unique_t __user *uarg = (drm32_unique_t __user *)arg; - drm_unique_t __user *p = compat_alloc_user_space(sizeof(*p)); - compat_uptr_t addr; - int n; - int ret; - - if (get_user(n, &uarg->unique_len) || - put_user(n, &p->unique_len) || - get_user(addr, &uarg->unique) || - put_user(compat_ptr(addr), &p->unique)) - return -EFAULT; - - if (cmd == DRM32_IOCTL_GET_UNIQUE) - ret = sys_ioctl (fd, DRM_IOCTL_GET_UNIQUE, (unsigned long)p); - else - ret = sys_ioctl (fd, DRM_IOCTL_SET_UNIQUE, (unsigned long)p); - - if (ret) - return ret; - - if (get_user(n, &p->unique_len) || put_user(n, &uarg->unique_len)) - return -EFAULT; - - return 0; -} - -typedef struct drm32_map { - u32 offset; /* Requested physical address (0 for SAREA)*/ - u32 size; /* Requested physical size (bytes) */ - drm_map_type_t type; /* Type of memory to map */ - drm_map_flags_t flags; /* Flags */ - u32 handle; /* User-space: "Handle" to pass to mmap */ - /* Kernel-space: kernel-virtual address */ - int mtrr; /* MTRR slot used */ - /* Private data */ -} drm32_map_t; -#define DRM32_IOCTL_ADD_MAP DRM_IOWR(0x15, drm32_map_t) - -static int drm32_addmap(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - drm32_map_t __user *uarg = (drm32_map_t __user *) arg; - drm_map_t karg; - mm_segment_t old_fs; - u32 tmp; - int ret; - - ret = get_user(karg.offset, &uarg->offset); - ret |= get_user(karg.size, &uarg->size); - ret |= get_user(karg.type, &uarg->type); - ret |= get_user(karg.flags, &uarg->flags); - ret |= get_user(tmp, &uarg->handle); - ret |= get_user(karg.mtrr, &uarg->mtrr); - if (ret) - return -EFAULT; - - karg.handle = (void *) (unsigned long) tmp; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - ret = sys_ioctl(fd, DRM_IOCTL_ADD_MAP, (unsigned long) &karg); - set_fs(old_fs); - - if (!ret) { - ret = put_user(karg.offset, &uarg->offset); - ret |= put_user(karg.size, &uarg->size); - ret |= put_user(karg.type, &uarg->type); - ret |= put_user(karg.flags, &uarg->flags); - tmp = (u32) (long)karg.handle; - ret |= put_user(tmp, &uarg->handle); - ret |= put_user(karg.mtrr, &uarg->mtrr); - if (ret) - ret = -EFAULT; - } - - return ret; -} - -typedef struct drm32_buf_info { - int count; /* Entries in list */ - u32 list; /* (drm_buf_desc_t *) */ -} drm32_buf_info_t; -#define DRM32_IOCTL_INFO_BUFS DRM_IOWR(0x18, drm32_buf_info_t) - -static int drm32_info_bufs(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - drm32_buf_info_t __user *uarg = (drm32_buf_info_t __user *)arg; - drm_buf_info_t __user *p = compat_alloc_user_space(sizeof(*p)); - compat_uptr_t addr; - int n; - int ret; - - if (get_user(n, &uarg->count) || put_user(n, &p->count) || - get_user(addr, &uarg->list) || put_user(compat_ptr(addr), &p->list)) - return -EFAULT; - - ret = sys_ioctl(fd, DRM_IOCTL_INFO_BUFS, (unsigned long)p); - if (ret) - return ret; - - if (get_user(n, &p->count) || put_user(n, &uarg->count)) - return -EFAULT; - - return 0; -} - -typedef struct drm32_buf_free { - int count; - u32 list; /* (int *) */ -} drm32_buf_free_t; -#define DRM32_IOCTL_FREE_BUFS DRM_IOW( 0x1a, drm32_buf_free_t) - -static int drm32_free_bufs(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - drm32_buf_free_t __user *uarg = (drm32_buf_free_t __user *)arg; - drm_buf_free_t __user *p = compat_alloc_user_space(sizeof(*p)); - compat_uptr_t addr; - int n; - - if (get_user(n, &uarg->count) || put_user(n, &p->count) || - get_user(addr, &uarg->list) || put_user(compat_ptr(addr), &p->list)) - return -EFAULT; - - return sys_ioctl(fd, DRM_IOCTL_FREE_BUFS, (unsigned long)p); -} - -typedef struct drm32_buf_pub { - int idx; /* Index into master buflist */ - int total; /* Buffer size */ - int used; /* Amount of buffer in use (for DMA) */ - u32 address; /* Address of buffer (void *) */ -} drm32_buf_pub_t; - -typedef struct drm32_buf_map { - int count; /* Length of buflist */ - u32 virtual; /* Mmaped area in user-virtual (void *) */ - u32 list; /* Buffer information (drm_buf_pub_t *) */ -} drm32_buf_map_t; -#define DRM32_IOCTL_MAP_BUFS DRM_IOWR(0x19, drm32_buf_map_t) - -static int drm32_map_bufs(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - drm32_buf_map_t __user *uarg = (drm32_buf_map_t __user *)arg; - drm32_buf_pub_t __user *ulist; - drm_buf_map_t __user *arg64; - drm_buf_pub_t __user *list; - int orig_count, ret, i; - int n; - compat_uptr_t addr; - - if (get_user(orig_count, &uarg->count)) - return -EFAULT; - - arg64 = compat_alloc_user_space(sizeof(drm_buf_map_t) + - (size_t)orig_count * sizeof(drm_buf_pub_t)); - list = (void __user *)(arg64 + 1); - - if (put_user(orig_count, &arg64->count) || - put_user(list, &arg64->list) || - get_user(addr, &uarg->virtual) || - put_user(compat_ptr(addr), &arg64->virtual) || - get_user(addr, &uarg->list)) - return -EFAULT; - - ulist = compat_ptr(addr); - - for (i = 0; i < orig_count; i++) { - if (get_user(n, &ulist[i].idx) || - put_user(n, &list[i].idx) || - get_user(n, &ulist[i].total) || - put_user(n, &list[i].total) || - get_user(n, &ulist[i].used) || - put_user(n, &list[i].used) || - get_user(addr, &ulist[i].address) || - put_user(compat_ptr(addr), &list[i].address)) - return -EFAULT; - } - - ret = sys_ioctl(fd, DRM_IOCTL_MAP_BUFS, (unsigned long) arg64); - if (ret) - return ret; - - for (i = 0; i < orig_count; i++) { - void __user *p; - if (get_user(n, &list[i].idx) || - put_user(n, &ulist[i].idx) || - get_user(n, &list[i].total) || - put_user(n, &ulist[i].total) || - get_user(n, &list[i].used) || - put_user(n, &ulist[i].used) || - get_user(p, &list[i].address) || - put_user((unsigned long)p, &ulist[i].address)) - return -EFAULT; - } - - if (get_user(n, &arg64->count) || put_user(n, &uarg->count)) - return -EFAULT; - - return 0; -} - -typedef struct drm32_dma { - /* Indices here refer to the offset into - buflist in drm_buf_get_t. */ - int context; /* Context handle */ - int send_count; /* Number of buffers to send */ - u32 send_indices; /* List of handles to buffers (int *) */ - u32 send_sizes; /* Lengths of data to send (int *) */ - drm_dma_flags_t flags; /* Flags */ - int request_count; /* Number of buffers requested */ - int request_size; /* Desired size for buffers */ - u32 request_indices; /* Buffer information (int *) */ - u32 request_sizes; /* (int *) */ - int granted_count; /* Number of buffers granted */ -} drm32_dma_t; -#define DRM32_IOCTL_DMA DRM_IOWR(0x29, drm32_dma_t) - -/* RED PEN The DRM layer blindly dereferences the send/request - * index/size arrays even though they are userland - * pointers. -DaveM - */ -static int drm32_dma(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - drm32_dma_t __user *uarg = (drm32_dma_t __user *) arg; - drm_dma_t __user *p = compat_alloc_user_space(sizeof(*p)); - compat_uptr_t addr; - int ret; - - if (copy_in_user(p, uarg, 2 * sizeof(int)) || - get_user(addr, &uarg->send_indices) || - put_user(compat_ptr(addr), &p->send_indices) || - get_user(addr, &uarg->send_sizes) || - put_user(compat_ptr(addr), &p->send_sizes) || - copy_in_user(&p->flags, &uarg->flags, sizeof(drm_dma_flags_t)) || - copy_in_user(&p->request_count, &uarg->request_count, sizeof(int))|| - copy_in_user(&p->request_size, &uarg->request_size, sizeof(int)) || - get_user(addr, &uarg->request_indices) || - put_user(compat_ptr(addr), &p->request_indices) || - get_user(addr, &uarg->request_sizes) || - put_user(compat_ptr(addr), &p->request_sizes) || - copy_in_user(&p->granted_count, &uarg->granted_count, sizeof(int))) - return -EFAULT; - - ret = sys_ioctl(fd, DRM_IOCTL_DMA, (unsigned long)p); - if (ret) - return ret; - - if (copy_in_user(uarg, p, 2 * sizeof(int)) || - copy_in_user(&uarg->flags, &p->flags, sizeof(drm_dma_flags_t)) || - copy_in_user(&uarg->request_count, &p->request_count, sizeof(int))|| - copy_in_user(&uarg->request_size, &p->request_size, sizeof(int)) || - copy_in_user(&uarg->granted_count, &p->granted_count, sizeof(int))) - return -EFAULT; - - return 0; -} - -typedef struct drm32_ctx_res { - int count; - u32 contexts; /* (drm_ctx_t *) */ -} drm32_ctx_res_t; -#define DRM32_IOCTL_RES_CTX DRM_IOWR(0x26, drm32_ctx_res_t) - -static int drm32_res_ctx(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - drm32_ctx_res_t __user *uarg = (drm32_ctx_res_t __user *) arg; - drm_ctx_res_t __user *p = compat_alloc_user_space(sizeof(*p)); - compat_uptr_t addr; - int ret; - - if (copy_in_user(p, uarg, sizeof(int)) || - get_user(addr, &uarg->contexts) || - put_user(compat_ptr(addr), &p->contexts)) - return -EFAULT; - - ret = sys_ioctl(fd, DRM_IOCTL_RES_CTX, (unsigned long)p); - if (ret) - return ret; - - if (copy_in_user(uarg, p, sizeof(int))) - return -EFAULT; - - return 0; -} - -#endif - typedef int (* ioctl32_handler_t)(unsigned int, unsigned int, unsigned long, struct file *); #define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL((cmd),sys_ioctl) @@ -485,103 +115,14 @@ COMPATIBLE_IOCTL(FBIOSCURPOS) COMPATIBLE_IOCTL(FBIOGCURPOS) COMPATIBLE_IOCTL(FBIOGCURMAX) /* Little k */ -COMPATIBLE_IOCTL(KIOCTYPE) -COMPATIBLE_IOCTL(KIOCLAYOUT) -COMPATIBLE_IOCTL(KIOCGTRANS) -COMPATIBLE_IOCTL(KIOCTRANS) -COMPATIBLE_IOCTL(KIOCCMD) -COMPATIBLE_IOCTL(KIOCSDIRECT) -COMPATIBLE_IOCTL(KIOCSLED) -COMPATIBLE_IOCTL(KIOCGLED) -COMPATIBLE_IOCTL(KIOCSRATE) -COMPATIBLE_IOCTL(KIOCGRATE) -COMPATIBLE_IOCTL(VUIDSFORMAT) -COMPATIBLE_IOCTL(VUIDGFORMAT) /* Little v, the video4linux ioctls */ COMPATIBLE_IOCTL(_IOR('p', 20, int[7])) /* RTCGET */ COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */ -COMPATIBLE_IOCTL(ENVCTRL_RD_WARNING_TEMPERATURE) -COMPATIBLE_IOCTL(ENVCTRL_RD_SHUTDOWN_TEMPERATURE) -COMPATIBLE_IOCTL(ENVCTRL_RD_CPU_TEMPERATURE) -COMPATIBLE_IOCTL(ENVCTRL_RD_FAN_STATUS) -COMPATIBLE_IOCTL(ENVCTRL_RD_VOLTAGE_STATUS) -COMPATIBLE_IOCTL(ENVCTRL_RD_SCSI_TEMPERATURE) -COMPATIBLE_IOCTL(ENVCTRL_RD_ETHERNET_TEMPERATURE) -COMPATIBLE_IOCTL(ENVCTRL_RD_MTHRBD_TEMPERATURE) -COMPATIBLE_IOCTL(ENVCTRL_RD_CPU_VOLTAGE) -COMPATIBLE_IOCTL(ENVCTRL_RD_GLOBALADDRESS) -/* COMPATIBLE_IOCTL(D7SIOCRD) same value as ENVCTRL_RD_VOLTAGE_STATUS */ -COMPATIBLE_IOCTL(D7SIOCWR) -COMPATIBLE_IOCTL(D7SIOCTM) -/* OPENPROMIO, SunOS/Solaris only, the NetBSD one's have - * embedded pointers in the arg which we'd need to clean up... - */ -COMPATIBLE_IOCTL(OPROMGETOPT) -COMPATIBLE_IOCTL(OPROMSETOPT) -COMPATIBLE_IOCTL(OPROMNXTOPT) -COMPATIBLE_IOCTL(OPROMSETOPT2) -COMPATIBLE_IOCTL(OPROMNEXT) -COMPATIBLE_IOCTL(OPROMCHILD) -COMPATIBLE_IOCTL(OPROMGETPROP) -COMPATIBLE_IOCTL(OPROMNXTPROP) -COMPATIBLE_IOCTL(OPROMU2P) -COMPATIBLE_IOCTL(OPROMGETCONS) -COMPATIBLE_IOCTL(OPROMGETFBNAME) -COMPATIBLE_IOCTL(OPROMGETBOOTARGS) -COMPATIBLE_IOCTL(OPROMSETCUR) -COMPATIBLE_IOCTL(OPROMPCI2NODE) -COMPATIBLE_IOCTL(OPROMPATH2NODE) -/* Big L */ -COMPATIBLE_IOCTL(LOOP_SET_STATUS64) -COMPATIBLE_IOCTL(LOOP_GET_STATUS64) -/* Big A */ -COMPATIBLE_IOCTL(AUDIO_GETINFO) -COMPATIBLE_IOCTL(AUDIO_SETINFO) -COMPATIBLE_IOCTL(AUDIO_DRAIN) -COMPATIBLE_IOCTL(AUDIO_GETDEV) -COMPATIBLE_IOCTL(AUDIO_GETDEV_SUNOS) -COMPATIBLE_IOCTL(AUDIO_FLUSH) -COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI) -#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE) -COMPATIBLE_IOCTL(DRM_IOCTL_GET_MAGIC) -COMPATIBLE_IOCTL(DRM_IOCTL_IRQ_BUSID) -COMPATIBLE_IOCTL(DRM_IOCTL_AUTH_MAGIC) -COMPATIBLE_IOCTL(DRM_IOCTL_BLOCK) -COMPATIBLE_IOCTL(DRM_IOCTL_UNBLOCK) -COMPATIBLE_IOCTL(DRM_IOCTL_CONTROL) -COMPATIBLE_IOCTL(DRM_IOCTL_ADD_BUFS) -COMPATIBLE_IOCTL(DRM_IOCTL_MARK_BUFS) -COMPATIBLE_IOCTL(DRM_IOCTL_ADD_CTX) -COMPATIBLE_IOCTL(DRM_IOCTL_RM_CTX) -COMPATIBLE_IOCTL(DRM_IOCTL_MOD_CTX) -COMPATIBLE_IOCTL(DRM_IOCTL_GET_CTX) -COMPATIBLE_IOCTL(DRM_IOCTL_SWITCH_CTX) -COMPATIBLE_IOCTL(DRM_IOCTL_NEW_CTX) -COMPATIBLE_IOCTL(DRM_IOCTL_ADD_DRAW) -COMPATIBLE_IOCTL(DRM_IOCTL_RM_DRAW) -COMPATIBLE_IOCTL(DRM_IOCTL_LOCK) -COMPATIBLE_IOCTL(DRM_IOCTL_UNLOCK) -COMPATIBLE_IOCTL(DRM_IOCTL_FINISH) -#endif /* DRM */ -COMPATIBLE_IOCTL(WIOCSTART) -COMPATIBLE_IOCTL(WIOCSTOP) -COMPATIBLE_IOCTL(WIOCGSTAT) /* And these ioctls need translation */ /* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */ HANDLE_IOCTL(FBIOPUTCMAP32, fbiogetputcmap) HANDLE_IOCTL(FBIOGETCMAP32, fbiogetputcmap) HANDLE_IOCTL(FBIOSCURSOR32, fbiogscursor) -#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE) -HANDLE_IOCTL(DRM32_IOCTL_VERSION, drm32_version) -HANDLE_IOCTL(DRM32_IOCTL_GET_UNIQUE, drm32_getsetunique) -HANDLE_IOCTL(DRM32_IOCTL_SET_UNIQUE, drm32_getsetunique) -HANDLE_IOCTL(DRM32_IOCTL_ADD_MAP, drm32_addmap) -HANDLE_IOCTL(DRM32_IOCTL_INFO_BUFS, drm32_info_bufs) -HANDLE_IOCTL(DRM32_IOCTL_FREE_BUFS, drm32_free_bufs) -HANDLE_IOCTL(DRM32_IOCTL_MAP_BUFS, drm32_map_bufs) -HANDLE_IOCTL(DRM32_IOCTL_DMA, drm32_dma) -HANDLE_IOCTL(DRM32_IOCTL_RES_CTX, drm32_res_ctx) -#endif /* DRM */ #if 0 HANDLE_IOCTL(RTC32_IRQP_READ, do_rtc_ioctl) HANDLE_IOCTL(RTC32_IRQP_SET, do_rtc_ioctl) diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c index 0d66d07c8c6eead89fa6e5799ec6ba5fcf57873f..96bd09b098f431876c87778594983f0bf514f85d 100644 --- a/arch/sparc64/kernel/kprobes.c +++ b/arch/sparc64/kernel/kprobes.c @@ -38,6 +38,9 @@ * - Mark that we are no longer actively in a kprobe. */ +DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; +DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); + int __kprobes arch_prepare_kprobe(struct kprobe *p) { return 0; @@ -66,46 +69,39 @@ void __kprobes arch_remove_kprobe(struct kprobe *p) { } -static struct kprobe *current_kprobe; -static unsigned long current_kprobe_orig_tnpc; -static unsigned long current_kprobe_orig_tstate_pil; -static unsigned int kprobe_status; -static struct kprobe *kprobe_prev; -static unsigned long kprobe_orig_tnpc_prev; -static unsigned long kprobe_orig_tstate_pil_prev; -static unsigned int kprobe_status_prev; - -static inline void save_previous_kprobe(void) +static inline void save_previous_kprobe(struct kprobe_ctlblk *kcb) { - kprobe_status_prev = kprobe_status; - kprobe_orig_tnpc_prev = current_kprobe_orig_tnpc; - kprobe_orig_tstate_pil_prev = current_kprobe_orig_tstate_pil; - kprobe_prev = current_kprobe; + kcb->prev_kprobe.kp = kprobe_running(); + kcb->prev_kprobe.status = kcb->kprobe_status; + kcb->prev_kprobe.orig_tnpc = kcb->kprobe_orig_tnpc; + kcb->prev_kprobe.orig_tstate_pil = kcb->kprobe_orig_tstate_pil; } -static inline void restore_previous_kprobe(void) +static inline void restore_previous_kprobe(struct kprobe_ctlblk *kcb) { - kprobe_status = kprobe_status_prev; - current_kprobe_orig_tnpc = kprobe_orig_tnpc_prev; - current_kprobe_orig_tstate_pil = kprobe_orig_tstate_pil_prev; - current_kprobe = kprobe_prev; + __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp; + kcb->kprobe_status = kcb->prev_kprobe.status; + kcb->kprobe_orig_tnpc = kcb->prev_kprobe.orig_tnpc; + kcb->kprobe_orig_tstate_pil = kcb->prev_kprobe.orig_tstate_pil; } -static inline void set_current_kprobe(struct kprobe *p, struct pt_regs *regs) +static inline void set_current_kprobe(struct kprobe *p, struct pt_regs *regs, + struct kprobe_ctlblk *kcb) { - current_kprobe_orig_tnpc = regs->tnpc; - current_kprobe_orig_tstate_pil = (regs->tstate & TSTATE_PIL); - current_kprobe = p; + __get_cpu_var(current_kprobe) = p; + kcb->kprobe_orig_tnpc = regs->tnpc; + kcb->kprobe_orig_tstate_pil = (regs->tstate & TSTATE_PIL); } -static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) +static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs, + struct kprobe_ctlblk *kcb) { regs->tstate |= TSTATE_PIL; /*single step inline, if it a breakpoint instruction*/ if (p->opcode == BREAKPOINT_INSTRUCTION) { regs->tpc = (unsigned long) p->addr; - regs->tnpc = current_kprobe_orig_tnpc; + regs->tnpc = kcb->kprobe_orig_tnpc; } else { regs->tpc = (unsigned long) &p->ainsn.insn[0]; regs->tnpc = (unsigned long) &p->ainsn.insn[1]; @@ -117,19 +113,21 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) struct kprobe *p; void *addr = (void *) regs->tpc; int ret = 0; + struct kprobe_ctlblk *kcb; + /* + * We don't want to be preempted for the entire + * duration of kprobe processing + */ preempt_disable(); + kcb = get_kprobe_ctlblk(); if (kprobe_running()) { - /* We *are* holding lock here, so this is safe. - * Disarm the probe we just hit, and ignore it. - */ p = get_kprobe(addr); if (p) { - if (kprobe_status == KPROBE_HIT_SS) { + if (kcb->kprobe_status == KPROBE_HIT_SS) { regs->tstate = ((regs->tstate & ~TSTATE_PIL) | - current_kprobe_orig_tstate_pil); - unlock_kprobes(); + kcb->kprobe_orig_tstate_pil); goto no_kprobe; } /* We have reentered the kprobe_handler(), since @@ -138,25 +136,22 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) * just single step on the instruction of the new probe * without calling any user handlers. */ - save_previous_kprobe(); - set_current_kprobe(p, regs); + save_previous_kprobe(kcb); + set_current_kprobe(p, regs, kcb); p->nmissed++; - kprobe_status = KPROBE_REENTER; - prepare_singlestep(p, regs); + kcb->kprobe_status = KPROBE_REENTER; + prepare_singlestep(p, regs, kcb); return 1; } else { - p = current_kprobe; + p = __get_cpu_var(current_kprobe); if (p->break_handler && p->break_handler(p, regs)) goto ss_probe; } - /* If it's not ours, can't be delete race, (we hold lock). */ goto no_kprobe; } - lock_kprobes(); p = get_kprobe(addr); if (!p) { - unlock_kprobes(); if (*(u32 *)addr != BREAKPOINT_INSTRUCTION) { /* * The breakpoint instruction was removed right @@ -171,14 +166,14 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) goto no_kprobe; } - set_current_kprobe(p, regs); - kprobe_status = KPROBE_HIT_ACTIVE; + set_current_kprobe(p, regs, kcb); + kcb->kprobe_status = KPROBE_HIT_ACTIVE; if (p->pre_handler && p->pre_handler(p, regs)) return 1; ss_probe: - prepare_singlestep(p, regs); - kprobe_status = KPROBE_HIT_SS; + prepare_singlestep(p, regs, kcb); + kcb->kprobe_status = KPROBE_HIT_SS; return 1; no_kprobe: @@ -260,11 +255,12 @@ static void __kprobes retpc_fixup(struct pt_regs *regs, u32 insn, * This function prepares to return from the post-single-step * breakpoint trap. */ -static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) +static void __kprobes resume_execution(struct kprobe *p, + struct pt_regs *regs, struct kprobe_ctlblk *kcb) { u32 insn = p->ainsn.insn[0]; - regs->tpc = current_kprobe_orig_tnpc; + regs->tpc = kcb->kprobe_orig_tnpc; regs->tnpc = relbranch_fixup(insn, (unsigned long) p->addr, (unsigned long) &p->ainsn.insn[0], @@ -272,44 +268,48 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) retpc_fixup(regs, insn, (unsigned long) p->addr); regs->tstate = ((regs->tstate & ~TSTATE_PIL) | - current_kprobe_orig_tstate_pil); + kcb->kprobe_orig_tstate_pil); } static inline int post_kprobe_handler(struct pt_regs *regs) { - if (!kprobe_running()) + struct kprobe *cur = kprobe_running(); + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + + if (!cur) return 0; - if ((kprobe_status != KPROBE_REENTER) && current_kprobe->post_handler) { - kprobe_status = KPROBE_HIT_SSDONE; - current_kprobe->post_handler(current_kprobe, regs, 0); + if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) { + kcb->kprobe_status = KPROBE_HIT_SSDONE; + cur->post_handler(cur, regs, 0); } - resume_execution(current_kprobe, regs); + resume_execution(cur, regs, kcb); /*Restore back the original saved kprobes variables and continue. */ - if (kprobe_status == KPROBE_REENTER) { - restore_previous_kprobe(); + if (kcb->kprobe_status == KPROBE_REENTER) { + restore_previous_kprobe(kcb); goto out; } - unlock_kprobes(); + reset_current_kprobe(); out: preempt_enable_no_resched(); return 1; } -/* Interrupts disabled, kprobe_lock held. */ static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) { - if (current_kprobe->fault_handler - && current_kprobe->fault_handler(current_kprobe, regs, trapnr)) + struct kprobe *cur = kprobe_running(); + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + + if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) return 1; - if (kprobe_status & KPROBE_HIT_SS) { - resume_execution(current_kprobe, regs); + if (kcb->kprobe_status & KPROBE_HIT_SS) { + resume_execution(cur, regs, kcb); - unlock_kprobes(); + reset_current_kprobe(); preempt_enable_no_resched(); } return 0; @@ -322,29 +322,30 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *data) { struct die_args *args = (struct die_args *)data; + int ret = NOTIFY_DONE; + switch (val) { case DIE_DEBUG: if (kprobe_handler(args->regs)) - return NOTIFY_STOP; + ret = NOTIFY_STOP; break; case DIE_DEBUG_2: if (post_kprobe_handler(args->regs)) - return NOTIFY_STOP; + ret = NOTIFY_STOP; break; case DIE_GPF: - if (kprobe_running() && - kprobe_fault_handler(args->regs, args->trapnr)) - return NOTIFY_STOP; - break; case DIE_PAGE_FAULT: + /* kprobe_running() needs smp_processor_id() */ + preempt_disable(); if (kprobe_running() && kprobe_fault_handler(args->regs, args->trapnr)) - return NOTIFY_STOP; + ret = NOTIFY_STOP; + preempt_enable(); break; default: break; } - return NOTIFY_DONE; + return ret; } asmlinkage void __kprobes kprobe_trap(unsigned long trap_level, @@ -368,24 +369,21 @@ asmlinkage void __kprobes kprobe_trap(unsigned long trap_level, } /* Jprobes support. */ -static struct pt_regs jprobe_saved_regs; -static struct pt_regs *jprobe_saved_regs_location; -static struct sparc_stackf jprobe_saved_stack; - int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) { struct jprobe *jp = container_of(p, struct jprobe, kp); + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); - jprobe_saved_regs_location = regs; - memcpy(&jprobe_saved_regs, regs, sizeof(*regs)); + kcb->jprobe_saved_regs_location = regs; + memcpy(&(kcb->jprobe_saved_regs), regs, sizeof(*regs)); /* Save a whole stack frame, this gets arguments * pushed onto the stack after using up all the * arg registers. */ - memcpy(&jprobe_saved_stack, + memcpy(&(kcb->jprobe_saved_stack), (char *) (regs->u_regs[UREG_FP] + STACK_BIAS), - sizeof(jprobe_saved_stack)); + sizeof(kcb->jprobe_saved_stack)); regs->tpc = (unsigned long) jp->entry; regs->tnpc = ((unsigned long) jp->entry) + 0x4UL; @@ -396,7 +394,6 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) void __kprobes jprobe_return(void) { - preempt_enable_no_resched(); __asm__ __volatile__( ".globl jprobe_return_trap_instruction\n" "jprobe_return_trap_instruction:\n\t" @@ -410,14 +407,15 @@ extern void __show_regs(struct pt_regs * regs); int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) { u32 *addr = (u32 *) regs->tpc; + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); if (addr == (u32 *) jprobe_return_trap_instruction) { - if (jprobe_saved_regs_location != regs) { + if (kcb->jprobe_saved_regs_location != regs) { printk("JPROBE: Current regs (%p) does not match " "saved regs (%p).\n", - regs, jprobe_saved_regs_location); + regs, kcb->jprobe_saved_regs_location); printk("JPROBE: Saved registers\n"); - __show_regs(jprobe_saved_regs_location); + __show_regs(kcb->jprobe_saved_regs_location); printk("JPROBE: Current registers\n"); __show_regs(regs); BUG(); @@ -426,12 +424,13 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) * first so that UREG_FP is the original one for * the stack frame restore. */ - memcpy(regs, &jprobe_saved_regs, sizeof(*regs)); + memcpy(regs, &(kcb->jprobe_saved_regs), sizeof(*regs)); memcpy((char *) (regs->u_regs[UREG_FP] + STACK_BIAS), - &jprobe_saved_stack, - sizeof(jprobe_saved_stack)); + &(kcb->jprobe_saved_stack), + sizeof(kcb->jprobe_saved_stack)); + preempt_enable_no_resched(); return 1; } return 0; diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index c1f34237cdf2f2cc1777c7e4842d3b3da6a3610e..bf1849dd9c49f5192301c9167a13a47490b0f07e 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -154,6 +154,7 @@ int prom_callback(long *args) pud_t *pudp; pmd_t *pmdp; pte_t *ptep; + pte_t pte; for_each_process(p) { mm = p->mm; @@ -178,8 +179,9 @@ int prom_callback(long *args) * being called from inside OBP. */ ptep = pte_offset_map(pmdp, va); - if (pte_present(*ptep)) { - tte = pte_val(*ptep); + pte = *ptep; + if (pte_present(pte)) { + tte = pte_val(pte); res = PROM_TRUE; } pte_unmap(ptep); @@ -218,6 +220,7 @@ int prom_callback(long *args) pud_t *pudp; pmd_t *pmdp; pte_t *ptep; + pte_t pte; int error; if ((va >= LOW_OBP_ADDRESS) && (va < HI_OBP_ADDRESS)) { @@ -240,8 +243,9 @@ int prom_callback(long *args) * being called from inside OBP. */ ptep = pte_offset_kernel(pmdp, va); - if (pte_present(*ptep)) { - tte = pte_val(*ptep); + pte = *ptep; + if (pte_present(pte)) { + tte = pte_val(pte); res = PROM_TRUE; } goto done; diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index aecccd0df1d129a6981ae85d86ef87d11bf47638..009a86e5ded48702cecd4ed4e18b8d67ea8cab70 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -863,6 +863,7 @@ static void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, pud_t *pudp = pud_offset(pgdp, address); pmd_t *pmdp = pmd_offset(pudp, address); pte_t *ptep; + pte_t pte; regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); @@ -873,9 +874,10 @@ static void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, preempt_disable(); ptep = pte_offset_map(pmdp, address); - if (pte_present(*ptep)) { + pte = *ptep; + if (pte_present(pte)) { unsigned long page = (unsigned long) - page_address(pte_page(*ptep)); + page_address(pte_page(pte)); wmb(); __asm__ __volatile__("flush %0 + %1" diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index b137fd63f5e12691a87c24113d8581f1e8daf45c..5d90ee9aebf1a29eb1d18e165b73551875b9c584 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -839,43 +839,29 @@ void smp_flush_tlb_all(void) * questionable (in theory the big win for threads is the massive sharing of * address space state across processors). */ + +/* This currently is only used by the hugetlb arch pre-fault + * hook on UltraSPARC-III+ and later when changing the pagesize + * bits of the context register for an address space. + */ void smp_flush_tlb_mm(struct mm_struct *mm) { - /* - * This code is called from two places, dup_mmap and exit_mmap. In the - * former case, we really need a flush. In the later case, the callers - * are single threaded exec_mmap (really need a flush), multithreaded - * exec_mmap case (do not need to flush, since the caller gets a new - * context via activate_mm), and all other callers of mmput() whence - * the flush can be optimized since the associated threads are dead and - * the mm is being torn down (__exit_mm and other mmput callers) or the - * owning thread is dissociating itself from the mm. The - * (atomic_read(&mm->mm_users) == 0) check ensures real work is done - * for single thread exec and dup_mmap cases. An alternate check might - * have been (current->mm != mm). - * Kanoj Sarcar - */ - if (atomic_read(&mm->mm_users) == 0) - return; - - { - u32 ctx = CTX_HWBITS(mm->context); - int cpu = get_cpu(); + u32 ctx = CTX_HWBITS(mm->context); + int cpu = get_cpu(); - if (atomic_read(&mm->mm_users) == 1) { - mm->cpu_vm_mask = cpumask_of_cpu(cpu); - goto local_flush_and_out; - } + if (atomic_read(&mm->mm_users) == 1) { + mm->cpu_vm_mask = cpumask_of_cpu(cpu); + goto local_flush_and_out; + } - smp_cross_call_masked(&xcall_flush_tlb_mm, - ctx, 0, 0, - mm->cpu_vm_mask); + smp_cross_call_masked(&xcall_flush_tlb_mm, + ctx, 0, 0, + mm->cpu_vm_mask); - local_flush_and_out: - __flush_tlb_mm(ctx, SECONDARY_CONTEXT); +local_flush_and_out: + __flush_tlb_mm(ctx, SECONDARY_CONTEXT); - put_cpu(); - } + put_cpu(); } void smp_flush_tlb_pending(struct mm_struct *mm, unsigned long nr, unsigned long *vaddrs) @@ -883,34 +869,13 @@ void smp_flush_tlb_pending(struct mm_struct *mm, unsigned long nr, unsigned long u32 ctx = CTX_HWBITS(mm->context); int cpu = get_cpu(); - if (mm == current->active_mm && atomic_read(&mm->mm_users) == 1) { + if (mm == current->active_mm && atomic_read(&mm->mm_users) == 1) mm->cpu_vm_mask = cpumask_of_cpu(cpu); - goto local_flush_and_out; - } else { - /* This optimization is not valid. Normally - * we will be holding the page_table_lock, but - * there is an exception which is copy_page_range() - * when forking. The lock is held during the individual - * page table updates in the parent, but not at the - * top level, which is where we are invoked. - */ - if (0) { - cpumask_t this_cpu_mask = cpumask_of_cpu(cpu); - - /* By virtue of running under the mm->page_table_lock, - * and mmu_context.h:switch_mm doing the same, the - * following operation is safe. - */ - if (cpus_equal(mm->cpu_vm_mask, this_cpu_mask)) - goto local_flush_and_out; - } - } - - smp_cross_call_masked(&xcall_flush_tlb_pending, - ctx, nr, (unsigned long) vaddrs, - mm->cpu_vm_mask); + else + smp_cross_call_masked(&xcall_flush_tlb_pending, + ctx, nr, (unsigned long) vaddrs, + mm->cpu_vm_mask); -local_flush_and_out: __flush_tlb_pending(ctx, nr, vaddrs); put_cpu(); diff --git a/arch/sparc64/kernel/sunos_ioctl32.c b/arch/sparc64/kernel/sunos_ioctl32.c index 7654b8a7f03a6ffb400ac8bbb27a8a02aab82d68..3f619ead22cc89a70ed5905e782a041153626463 100644 --- a/arch/sparc64/kernel/sunos_ioctl32.c +++ b/arch/sparc64/kernel/sunos_ioctl32.c @@ -24,7 +24,6 @@ #include #include #include -#include #define SUNOS_NR_OPEN 256 diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 38c5525087a2149c0c921a51c1fe64a5b2c4f7fa..459c8fbe02b4df734af56e0d16cde8d0b7859ea9 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -60,17 +60,6 @@ static void __iomem *mstk48t59_regs; static int set_rtc_mmss(unsigned long); -static __init unsigned long dummy_get_tick(void) -{ - return 0; -} - -static __initdata struct sparc64_tick_ops dummy_tick_ops = { - .get_tick = dummy_get_tick, -}; - -struct sparc64_tick_ops *tick_ops __read_mostly = &dummy_tick_ops; - #define TICK_PRIV_BIT (1UL << 63) #ifdef CONFIG_SMP @@ -200,6 +189,8 @@ static struct sparc64_tick_ops tick_operations __read_mostly = { .softint_mask = 1UL << 0, }; +struct sparc64_tick_ops *tick_ops __read_mostly = &tick_operations; + static void stick_init_tick(unsigned long offset) { tick_disable_protection(); diff --git a/arch/sparc64/kernel/us2e_cpufreq.c b/arch/sparc64/kernel/us2e_cpufreq.c index 686e526bec04c91ffe1e7c145537b1a74680fb20..b35dc8dc995a066810c5c4dac01658c4ab9f8944 100644 --- a/arch/sparc64/kernel/us2e_cpufreq.c +++ b/arch/sparc64/kernel/us2e_cpufreq.c @@ -388,10 +388,8 @@ static int __init us2e_freq_init(void) kfree(driver); cpufreq_us2e_driver = NULL; } - if (us2e_freq_table) { - kfree(us2e_freq_table); - us2e_freq_table = NULL; - } + kfree(us2e_freq_table); + us2e_freq_table = NULL; return ret; } @@ -402,7 +400,6 @@ static void __exit us2e_freq_exit(void) { if (cpufreq_us2e_driver) { cpufreq_unregister_driver(cpufreq_us2e_driver); - kfree(cpufreq_us2e_driver); cpufreq_us2e_driver = NULL; kfree(us2e_freq_table); diff --git a/arch/sparc64/kernel/us3_cpufreq.c b/arch/sparc64/kernel/us3_cpufreq.c index 0340041f614352a5cd22ddae1a946c8b1cf53e0f..6d1f9a3c464f55ed63c158527ea6d88502606b7d 100644 --- a/arch/sparc64/kernel/us3_cpufreq.c +++ b/arch/sparc64/kernel/us3_cpufreq.c @@ -249,10 +249,8 @@ static int __init us3_freq_init(void) kfree(driver); cpufreq_us3_driver = NULL; } - if (us3_freq_table) { - kfree(us3_freq_table); - us3_freq_table = NULL; - } + kfree(us3_freq_table); + us3_freq_table = NULL; return ret; } @@ -263,7 +261,6 @@ static void __exit us3_freq_exit(void) { if (cpufreq_us3_driver) { cpufreq_unregister_driver(cpufreq_us3_driver); - kfree(cpufreq_us3_driver); cpufreq_us3_driver = NULL; kfree(us3_freq_table); diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index 31fbc67719a1f653f643c346615a261173541a98..3be278d916dbcaeb679fafdefc3f03cb01a78c16 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c @@ -109,7 +109,7 @@ static void bad_kernel_pc(struct pt_regs *regs) * this. Additionally, to prevent kswapd from ripping ptes from * under us, raise interrupts around the time that we look at the * pte, kswapd will have to wait to get his smp ipi response from - * us. This saves us having to get page_table_lock. + * us. vmtruncate likewise. This saves us having to get pte lock. */ static unsigned int get_user_insn(unsigned long tpc) { diff --git a/arch/sparc64/oprofile/Kconfig b/arch/sparc64/oprofile/Kconfig index 5ade19801b97a598829b4b1dff817a6cc59a028e..d8a84088471a1c011868aae0b44558d15c9f1c0b 100644 --- a/arch/sparc64/oprofile/Kconfig +++ b/arch/sparc64/oprofile/Kconfig @@ -1,7 +1,3 @@ - -menu "Profiling support" - depends on EXPERIMENTAL - config PROFILING bool "Profiling support (EXPERIMENTAL)" help @@ -19,5 +15,3 @@ config OPROFILE If unsure, say N. -endmenu - diff --git a/arch/um/Kconfig b/arch/um/Kconfig index cd06ed7d842d93d54f18886efcf512d5471c009d..3b5f47c469073df1ca4b0bac35bc06dff2aaaeaf 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -65,6 +65,30 @@ config STATIC_LINK chroot, and you disable CONFIG_MODE_TT, you probably want to say Y here. +config HOST_2G_2G + bool "2G/2G host address space split" + default n + depends on MODE_TT + help + This is needed when the host on which you run has a 2G/2G memory + split, instead of the customary 3G/1G. + + Note that to enable such a host + configuration, which makes sense only in some cases, you need special + host patches. + + So, if you do not know what to do here, say 'N'. + +config KERNEL_HALF_GIGS + int "Kernel address space size (in .5G units)" + default "1" + depends on MODE_TT + help + This determines the amount of address space that UML will allocate for + its own, measured in half Gigabyte units. The default is 1. + Change this only if you need to boot UML with an unusually large amount + of physical memory. + config MODE_SKAS bool "Separate Kernel Address Space support" default y @@ -182,19 +206,6 @@ config MAGIC_SYSRQ The keys are documented in . Don't say Y unless you really know what this hack does. -config HOST_2G_2G - bool "2G/2G host address space split" - default n - help - This is needed when the host on which you run has a 2G/2G memory - split, instead of the customary 3G/1G. - - Note that to enable such a host - configuration, which makes sense only in some cases, you need special - host patches. - - So, if you do not know what to do here, say 'N'. - config SMP bool "Symmetric multi-processing support (EXPERIMENTAL)" default n @@ -241,15 +252,6 @@ config NEST_LEVEL set to the host's CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS. Only change this if you are running nested UMLs. -config KERNEL_HALF_GIGS - int "Kernel address space size (in .5G units)" - default "1" - help - This determines the amount of address space that UML will allocate for - its own, measured in half Gigabyte units. The default is 1. - Change this only if you need to boot UML with an unusually large amount - of physical memory. - config HIGHMEM bool "Highmem support" depends on !64BIT diff --git a/arch/um/Makefile b/arch/um/Makefile index e1ffad2246053651339c07281a5aa003aa60c3d9..e55d32e903bc1a4095a3f44123f2fb22ccd40abc 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -60,7 +60,7 @@ AFLAGS += $(ARCH_INCLUDE) USER_CFLAGS := $(patsubst -I%,,$(CFLAGS)) USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \ - $(MODE_INCLUDE) + $(MODE_INCLUDE) -D_FILE_OFFSET_BITS=64 # -Derrno=kernel_errno - This turns all kernel references to errno into # kernel_errno to separate them from the libc errno. This allows -fno-common diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386 index aef7c50f8e1365a6478de2d84471bab6213e1547..1f7dcb064aee65602eac0d5fbb18cc77aad6754e 100644 --- a/arch/um/Makefile-i386 +++ b/arch/um/Makefile-i386 @@ -17,8 +17,6 @@ ifeq ("$(origin SUBARCH)", "command line") ifneq ("$(shell uname -m | sed -e s/i.86/i386/)", "$(SUBARCH)") CFLAGS += $(call cc-option,-m32) USER_CFLAGS += $(call cc-option,-m32) -HOSTCFLAGS += $(call cc-option,-m32) -HOSTLDFLAGS += $(call cc-option,-m32) AFLAGS += $(call cc-option,-m32) LINK-y += $(call cc-option,-m32) UML_OBJCOPYFLAGS += -F $(ELF_FORMAT) diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c index de3bce71aeb3e8f3b3d283da35a77949a6444022..1c55d580248993c9ef1dd7249ccf8bb8e548c745 100644 --- a/arch/um/drivers/chan_user.c +++ b/arch/um/drivers/chan_user.c @@ -16,7 +16,6 @@ #include "user_util.h" #include "chan_user.h" #include "user.h" -#include "helper.h" #include "os.h" #include "choose-mode.h" #include "mode.h" diff --git a/arch/um/drivers/harddog_kern.c b/arch/um/drivers/harddog_kern.c index 147ec19f6bb9dc98c2dd026c25bd49cf9cc1a959..49acb2badf3229437c7a0149bc3da5be8d7d2109 100644 --- a/arch/um/drivers/harddog_kern.c +++ b/arch/um/drivers/harddog_kern.c @@ -46,7 +46,6 @@ #include #include #include -#include "helper.h" #include "mconsole.h" MODULE_LICENSE("GPL"); diff --git a/arch/um/drivers/harddog_user.c b/arch/um/drivers/harddog_user.c index d934181b8d4c67238b3fa10a5941952884743e1b..def013b5a3c7a5ec373dae711829b4ae10f76349 100644 --- a/arch/um/drivers/harddog_user.c +++ b/arch/um/drivers/harddog_user.c @@ -8,7 +8,6 @@ #include #include "user_util.h" #include "user.h" -#include "helper.h" #include "mconsole.h" #include "os.h" #include "choose-mode.h" diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 721e2601a75da2e8b8fbcbb94dc1797831bc0e7c..fe865d9a37212d690d859dc4dc2209cb4d584a36 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -96,7 +96,6 @@ irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) static int uml_net_open(struct net_device *dev) { struct uml_net_private *lp = dev->priv; - char addr[sizeof("255.255.255.255\0")]; int err; spin_lock(&lp->lock); @@ -107,7 +106,7 @@ static int uml_net_open(struct net_device *dev) } if(!lp->have_mac){ - dev_ip_addr(dev, addr, &lp->mac[2]); + dev_ip_addr(dev, &lp->mac[2]); set_ether_mac(dev, lp->mac); } @@ -664,8 +663,6 @@ static int uml_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr) { struct in_ifaddr *ifa = ptr; - u32 addr = ifa->ifa_address; - u32 netmask = ifa->ifa_mask; struct net_device *dev = ifa->ifa_dev->dev; struct uml_net_private *lp; void (*proc)(unsigned char *, unsigned char *, void *); @@ -685,14 +682,8 @@ static int uml_inetaddr_event(struct notifier_block *this, unsigned long event, break; } if(proc != NULL){ - addr_buf[0] = addr & 0xff; - addr_buf[1] = (addr >> 8) & 0xff; - addr_buf[2] = (addr >> 16) & 0xff; - addr_buf[3] = addr >> 24; - netmask_buf[0] = netmask & 0xff; - netmask_buf[1] = (netmask >> 8) & 0xff; - netmask_buf[2] = (netmask >> 16) & 0xff; - netmask_buf[3] = netmask >> 24; + memcpy(addr_buf, &ifa->ifa_address, sizeof(addr_buf)); + memcpy(netmask_buf, &ifa->ifa_mask, sizeof(netmask_buf)); (*proc)(addr_buf, netmask_buf, &lp->user); } return(NOTIFY_DONE); @@ -774,27 +765,18 @@ int setup_etheraddr(char *str, unsigned char *addr) return(1); } -void dev_ip_addr(void *d, char *buf, char *bin_buf) +void dev_ip_addr(void *d, unsigned char *bin_buf) { struct net_device *dev = d; struct in_device *ip = dev->ip_ptr; struct in_ifaddr *in; - u32 addr; if((ip == NULL) || ((in = ip->ifa_list) == NULL)){ printk(KERN_WARNING "dev_ip_addr - device not assigned an " "IP address\n"); return; } - addr = in->ifa_address; - sprintf(buf, "%d.%d.%d.%d", addr & 0xff, (addr >> 8) & 0xff, - (addr >> 16) & 0xff, addr >> 24); - if(bin_buf){ - bin_buf[0] = addr & 0xff; - bin_buf[1] = (addr >> 8) & 0xff; - bin_buf[2] = (addr >> 16) & 0xff; - bin_buf[3] = addr >> 24; - } + memcpy(bin_buf, &in->ifa_address, sizeof(in->ifa_address)); } void set_ether_mac(void *d, unsigned char *addr) @@ -829,14 +811,8 @@ void iter_addresses(void *d, void (*cb)(unsigned char *, unsigned char *, if(ip == NULL) return; in = ip->ifa_list; while(in != NULL){ - address[0] = in->ifa_address & 0xff; - address[1] = (in->ifa_address >> 8) & 0xff; - address[2] = (in->ifa_address >> 16) & 0xff; - address[3] = in->ifa_address >> 24; - netmask[0] = in->ifa_mask & 0xff; - netmask[1] = (in->ifa_mask >> 8) & 0xff; - netmask[2] = (in->ifa_mask >> 16) & 0xff; - netmask[3] = in->ifa_mask >> 24; + memcpy(address, &in->ifa_address, sizeof(address)); + memcpy(netmask, &in->ifa_mask, sizeof(netmask)); (*cb)(address, netmask, arg); in = in->ifa_next; } diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c index 3730d4f1271368e43ee147303973b8490ab153ea..098fa65981aba6404eb9422137466d39d5ffc38b 100644 --- a/arch/um/drivers/net_user.c +++ b/arch/um/drivers/net_user.c @@ -16,7 +16,6 @@ #include "user_util.h" #include "kern_util.h" #include "net_user.h" -#include "helper.h" #include "os.h" int tap_open_common(void *dev, char *gate_addr) diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c index 14dd2002d2da6946bd61ac133198f112338cff31..ed4a1a6c5d83fa03fb515f69a2fc30340f596301 100644 --- a/arch/um/drivers/port_user.c +++ b/arch/um/drivers/port_user.c @@ -18,7 +18,6 @@ #include "user.h" #include "chan_user.h" #include "port.h" -#include "helper.h" #include "os.h" struct port_chan { diff --git a/arch/um/drivers/random.c b/arch/um/drivers/random.c index f9e22198e011c911c7c2f1d36a1b8da742c2325e..ba471f5864a6d7d6815f3847a36aa78b4ed1a5e3 100644 --- a/arch/um/drivers/random.c +++ b/arch/um/drivers/random.c @@ -58,10 +58,8 @@ static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size, if (filp->f_flags & O_NONBLOCK) return ret ? : -EAGAIN; - if(need_resched()){ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - } + if(need_resched()) + schedule_timeout_interruptible(1); } else return n; if (signal_pending (current)) diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c index 71af444e591f8bff7b097ac57dc85376529fb677..89fbec185cc16ec10d2d8df49410cf8bb32080a1 100644 --- a/arch/um/drivers/slip_user.c +++ b/arch/um/drivers/slip_user.c @@ -14,7 +14,6 @@ #include "net_user.h" #include "slip.h" #include "slip_common.h" -#include "helper.h" #include "os.h" void slip_user_init(void *data, void *dev) diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c index 8d91f663d82c684267567f2489f8059b738590e8..b94c66114bc85d7a56fe4d9f6d29d4d31a633c13 100644 --- a/arch/um/drivers/slirp_user.c +++ b/arch/um/drivers/slirp_user.c @@ -13,7 +13,6 @@ #include "net_user.h" #include "slirp.h" #include "slip_common.h" -#include "helper.h" #include "os.h" void slirp_user_init(void *data, void *dev) diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c index 90e0e5ff451e1cc2f21909ff90b6a40575172baa..b530f1a6540d506a556e38c90dc3afec63f2f7f6 100644 --- a/arch/um/drivers/xterm.c +++ b/arch/um/drivers/xterm.c @@ -14,7 +14,6 @@ #include #include "kern_util.h" #include "chan_user.h" -#include "helper.h" #include "user_util.h" #include "user.h" #include "os.h" diff --git a/arch/um/include/helper.h b/arch/um/include/helper.h deleted file mode 100644 index 162ac31192fdf49a76678dd0ee2cec3693840809..0000000000000000000000000000000000000000 --- a/arch/um/include/helper.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __HELPER_H__ -#define __HELPER_H__ - -extern int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, - unsigned long *stack_out); -extern int run_helper_thread(int (*proc)(void *), void *arg, - unsigned int flags, unsigned long *stack_out, - int stack_order); -extern int helper_wait(int pid); - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/mem_user.h b/arch/um/include/mem_user.h index 9fef4123a65a72af9baada02ecd1cb775d571d8b..a1064c5823bfe92c8e5c83c71592e37ceacd5e69 100644 --- a/arch/um/include/mem_user.h +++ b/arch/um/include/mem_user.h @@ -57,7 +57,7 @@ extern int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem); extern unsigned long get_vm(unsigned long len); extern void setup_physmem(unsigned long start, unsigned long usable, - unsigned long len, unsigned long highmem); + unsigned long len, unsigned long long highmem); extern void add_iomem(char *name, int fd, unsigned long size); extern unsigned long phys_offset(unsigned long phys); extern void unmap_physmem(void); diff --git a/arch/um/include/net_user.h b/arch/um/include/net_user.h index 89885a77a771f203edbbf39d6fadd6742e54e2e2..800c403920bc707780135d0227c32d9b3d8cc96b 100644 --- a/arch/um/include/net_user.h +++ b/arch/um/include/net_user.h @@ -25,7 +25,7 @@ struct net_user_info { }; extern void ether_user_init(void *data, void *dev); -extern void dev_ip_addr(void *d, char *buf, char *bin_buf); +extern void dev_ip_addr(void *d, unsigned char *bin_buf); extern void set_ether_mac(void *d, unsigned char *addr); extern void iter_addresses(void *d, void (*cb)(unsigned char *, unsigned char *, void *), diff --git a/arch/um/include/os.h b/arch/um/include/os.h index 2e58e304b8be6ce3dc867ba2418432735fc07058..2cccfa5b8ab5f53cc5f340800b1486bf3b582925 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h @@ -167,7 +167,7 @@ extern int can_do_skas(void); #endif /* mem.c */ -extern int create_mem_file(unsigned long len); +extern int create_mem_file(unsigned long long len); /* process.c */ extern unsigned long os_process_pc(int pid); @@ -199,6 +199,20 @@ extern void forward_pending_sigio(int target); extern int start_fork_tramp(void *arg, unsigned long temp_stack, int clone_flags, int (*tramp)(void *)); +/* uaccess.c */ +extern unsigned long __do_user_copy(void *to, const void *from, int n, + void **fault_addr, void **fault_catcher, + void (*op)(void *to, const void *from, + int n), int *faulted_out); + +/* helper.c */ +extern int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, + unsigned long *stack_out); +extern int run_helper_thread(int (*proc)(void *), void *arg, + unsigned int flags, unsigned long *stack_out, + int stack_order); +extern int helper_wait(int pid); + #endif /* diff --git a/arch/um/include/sysdep-i386/stub.h b/arch/um/include/sysdep-i386/stub.h index d3699fe1c6133b001e9b09c50e904f3fc5b944d5..a49ceb199ee57e2c5150f93373dc994fe7d00f30 100644 --- a/arch/um/include/sysdep-i386/stub.h +++ b/arch/um/include/sysdep-i386/stub.h @@ -16,45 +16,69 @@ extern void stub_clone_handler(void); #define STUB_MMAP_NR __NR_mmap2 #define MMAP_OFFSET(o) ((o) >> PAGE_SHIFT) +static inline long stub_syscall1(long syscall, long arg1) +{ + long ret; + + __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1)); + + return ret; +} + static inline long stub_syscall2(long syscall, long arg1, long arg2) { long ret; - __asm__("movl %0, %%ecx; " : : "g" (arg2) : "%ecx"); - __asm__("movl %0, %%ebx; " : : "g" (arg1) : "%ebx"); - __asm__("movl %0, %%eax; " : : "g" (syscall) : "%eax"); - __asm__("int $0x80;" : : : "%eax"); - __asm__ __volatile__("movl %%eax, %0; " : "=g" (ret) :); - return(ret); + __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1), + "c" (arg2)); + + return ret; } static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3) { - __asm__("movl %0, %%edx; " : : "g" (arg3) : "%edx"); - return(stub_syscall2(syscall, arg1, arg2)); + long ret; + + __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1), + "c" (arg2), "d" (arg3)); + + return ret; } static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3, long arg4) { - __asm__("movl %0, %%esi; " : : "g" (arg4) : "%esi"); - return(stub_syscall3(syscall, arg1, arg2, arg3)); + long ret; + + __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1), + "c" (arg2), "d" (arg3), "S" (arg4)); + + return ret; +} + +static inline long stub_syscall5(long syscall, long arg1, long arg2, long arg3, + long arg4, long arg5) +{ + long ret; + + __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1), + "c" (arg2), "d" (arg3), "S" (arg4), "D" (arg5)); + + return ret; } static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) { long ret; - __asm__("movl %0, %%eax; " : : "g" (syscall) : "%eax"); - __asm__("movl %0, %%ebx; " : : "g" (arg1) : "%ebx"); - __asm__("movl %0, %%ecx; " : : "g" (arg2) : "%ecx"); - __asm__("movl %0, %%edx; " : : "g" (arg3) : "%edx"); - __asm__("movl %0, %%esi; " : : "g" (arg4) : "%esi"); - __asm__("movl %0, %%edi; " : : "g" (arg5) : "%edi"); - __asm__ __volatile__("pushl %%ebp ; movl %1, %%ebp; " - "int $0x80; popl %%ebp ; " - "movl %%eax, %0; " : "=g" (ret) : "g" (arg6) : "%eax"); - return(ret); + + __asm__ volatile ("push %%ebp ; movl %%eax,%%ebp ; movl %1,%%eax ; " + "int $0x80 ; pop %%ebp" + : "=a" (ret) + : "g" (syscall), "b" (arg1), "c" (arg2), "d" (arg3), + "S" (arg4), "D" (arg5), "0" (arg6)); + + return ret; } static inline void trap_myself(void) diff --git a/arch/um/include/sysdep-x86_64/stub.h b/arch/um/include/sysdep-x86_64/stub.h index f599058d8263a95d8fb27ab335e66a7e35b833a6..2bd6e7a972866c0d8130101a3a78679af0b91f13 100644 --- a/arch/um/include/sysdep-x86_64/stub.h +++ b/arch/um/include/sysdep-x86_64/stub.h @@ -17,37 +17,72 @@ extern void stub_clone_handler(void); #define STUB_MMAP_NR __NR_mmap #define MMAP_OFFSET(o) (o) +#define __syscall_clobber "r11","rcx","memory" +#define __syscall "syscall" + static inline long stub_syscall2(long syscall, long arg1, long arg2) { long ret; - __asm__("movq %0, %%rsi; " : : "g" (arg2) : "%rsi"); - __asm__("movq %0, %%rdi; " : : "g" (arg1) : "%rdi"); - __asm__("movq %0, %%rax; " : : "g" (syscall) : "%rax"); - __asm__("syscall;" : : : "%rax", "%r11", "%rcx"); - __asm__ __volatile__("movq %%rax, %0; " : "=g" (ret) :); - return(ret); + __asm__ volatile (__syscall + : "=a" (ret) + : "0" (syscall), "D" (arg1), "S" (arg2) : __syscall_clobber ); + + return ret; } static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3) { - __asm__("movq %0, %%rdx; " : : "g" (arg3) : "%rdx"); - return(stub_syscall2(syscall, arg1, arg2)); + long ret; + + __asm__ volatile (__syscall + : "=a" (ret) + : "0" (syscall), "D" (arg1), "S" (arg2), "d" (arg3) + : __syscall_clobber ); + + return ret; } static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3, long arg4) { - __asm__("movq %0, %%r10; " : : "g" (arg4) : "%r10"); - return(stub_syscall3(syscall, arg1, arg2, arg3)); + long ret; + + __asm__ volatile ("movq %5,%%r10 ; " __syscall + : "=a" (ret) + : "0" (syscall), "D" (arg1), "S" (arg2), "d" (arg3), + "g" (arg4) + : __syscall_clobber, "r10" ); + + return ret; +} + +static inline long stub_syscall5(long syscall, long arg1, long arg2, long arg3, + long arg4, long arg5) +{ + long ret; + + __asm__ volatile ("movq %5,%%r10 ; movq %6,%%r8 ; " __syscall + : "=a" (ret) + : "0" (syscall), "D" (arg1), "S" (arg2), "d" (arg3), + "g" (arg4), "g" (arg5) + : __syscall_clobber, "r10", "r8" ); + + return ret; } static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) { - __asm__("movq %0, %%r9; " : : "g" (arg6) : "%r9"); - __asm__("movq %0, %%r8; " : : "g" (arg5) : "%r8"); - return(stub_syscall4(syscall, arg1, arg2, arg3, arg4)); + long ret; + + __asm__ volatile ("movq %5,%%r10 ; movq %6,%%r8 ; " + "movq %7, %%r9; " __syscall : "=a" (ret) + : "0" (syscall), "D" (arg1), "S" (arg2), "d" (arg3), + "g" (arg4), "g" (arg5), "g" (arg6) + : __syscall_clobber, "r10", "r8", "r9" ); + + return ret; } static inline void trap_myself(void) diff --git a/arch/um/include/uml_uaccess.h b/arch/um/include/uml_uaccess.h index f77eb64284538574e6e9f831d8679ab374950bdc..c0df11d06f5e791adaa27546b8d8270c7aac885e 100644 --- a/arch/um/include/uml_uaccess.h +++ b/arch/um/include/uml_uaccess.h @@ -8,10 +8,6 @@ extern int __do_copy_to_user(void *to, const void *from, int n, void **fault_addr, void **fault_catcher); -extern unsigned long __do_user_copy(void *to, const void *from, int n, - void **fault_addr, void **fault_catcher, - void (*op)(void *to, const void *from, - int n), int *faulted_out); void __do_copy(void *to, const void *from, int n); #endif diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 1a0001b3850caf86c00ef2c61f0258ed67666c5c..3de9d21e36bf042156b8b6c61cd8831c8885abea 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -7,10 +7,10 @@ extra-y := vmlinux.lds clean-files := obj-y = config.o exec_kern.o exitcode.o \ - helper.o init_task.o irq.o irq_user.o ksyms.o main.o mem.o physmem.o \ + init_task.o irq.o irq_user.o ksyms.o mem.o physmem.o \ process_kern.o ptrace.o reboot.o resource.o sigio_user.o sigio_kern.o \ signal_kern.o signal_user.o smp.o syscall_kern.o sysrq.o time.o \ - time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o \ + time_kern.o tlb.o trap_kern.o trap_user.o uaccess.o um_arch.o \ umid.o user_util.o obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o @@ -24,8 +24,7 @@ obj-$(CONFIG_MODE_SKAS) += skas/ user-objs-$(CONFIG_TTY_LOG) += tty_log.o -USER_OBJS := $(user-objs-y) config.o helper.o main.o time.o tty_log.o umid.o \ - user_util.o +USER_OBJS := $(user-objs-y) config.o time.o tty_log.o umid.o user_util.o include arch/um/scripts/Makefile.rules diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c index a97a72e516aa6f6c6b7b4e6e0e4814b6e24f3a69..7713e7a6f476fcdf910a99565be74ccdb01828f5 100644 --- a/arch/um/kernel/ksyms.c +++ b/arch/um/kernel/ksyms.c @@ -20,7 +20,6 @@ #include "user_util.h" #include "mem_user.h" #include "os.h" -#include "helper.h" EXPORT_SYMBOL(stop); EXPORT_SYMBOL(uml_physmem); diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index 462cc9d65386a60bcfc57969158c0fc1263f85c8..fa4f915be5c59e15fb5c393e12f40e0a0f77f24e 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -234,8 +234,8 @@ void paging_init(void) empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE); for(i=0;i> PAGE_SHIFT) - (uml_physmem >> PAGE_SHIFT); - zones_size[2] = highmem >> PAGE_SHIFT; + zones_size[ZONE_DMA] = (end_iomem >> PAGE_SHIFT) - (uml_physmem >> PAGE_SHIFT); + zones_size[ZONE_HIGHMEM] = highmem >> PAGE_SHIFT; free_area_init(zones_size); /* diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c index ea670fcc8af5b3c52b020afe31fbd09f02df97cd..f3b583a878a6c9a4504e68f4bbce985251101fe6 100644 --- a/arch/um/kernel/physmem.c +++ b/arch/um/kernel/physmem.c @@ -246,7 +246,7 @@ int is_remapped(void *virt) /* Changed during early boot */ unsigned long high_physmem; -extern unsigned long physmem_size; +extern unsigned long long physmem_size; int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem) { @@ -321,7 +321,7 @@ void map_memory(unsigned long virt, unsigned long phys, unsigned long len, extern int __syscall_stub_start, __binary_start; void setup_physmem(unsigned long start, unsigned long reserve_end, - unsigned long len, unsigned long highmem) + unsigned long len, unsigned long long highmem) { unsigned long reserve = reserve_end - start; int pfn = PFN_UP(__pa(reserve_end)); diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 71af4d5038994014f12e5030dd3187bcbaae9450..98e09395c093c1d75be57ab82ed3b46c084e533f 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -43,53 +43,10 @@ void ptrace_disable(struct task_struct *child) extern int peek_user(struct task_struct * child, long addr, long data); extern int poke_user(struct task_struct * child, long addr, long data); -long sys_ptrace(long request, long pid, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, long addr, long data) { - struct task_struct *child; int i, ret; - lock_kernel(); - ret = -EPERM; - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - - ret = security_ptrace(current->parent, current); - if (ret) - goto out; - - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - -#ifdef SUBACH_PTRACE_SPECIAL - SUBARCH_PTRACE_SPECIAL(child,request,addr,data); -#endif - - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) - goto out_tsk; - switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ @@ -282,10 +239,7 @@ long sys_ptrace(long request, long pid, long addr, long data) ret = ptrace_request(child, request, addr, data); break; } - out_tsk: - put_task_struct(child); - out: - unlock_kernel(); + return ret; } diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c index a52751108aa125c3299926efdb8d8aad53496a72..48b1f644b9a624a66ce16c782c832d84c4c2a074 100644 --- a/arch/um/kernel/sigio_user.c +++ b/arch/um/kernel/sigio_user.c @@ -18,7 +18,6 @@ #include "kern_util.h" #include "user_util.h" #include "sigio.h" -#include "helper.h" #include "os.h" /* Changed during early boot */ @@ -225,7 +224,7 @@ static int need_poll(int n) next_poll.used = n; return(0); } - if(next_poll.poll != NULL) kfree(next_poll.poll); + kfree(next_poll.poll); next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd)); if(next_poll.poll == NULL){ printk("need_poll : failed to allocate new pollfds\n"); diff --git a/arch/um/kernel/skas/include/mmu-skas.h b/arch/um/kernel/skas/include/mmu-skas.h index 09536f81ee42f6e527154d5085fa4f73865da114..44110c521e498bb2d86033d3dea5e71584346804 100644 --- a/arch/um/kernel/skas/include/mmu-skas.h +++ b/arch/um/kernel/skas/include/mmu-skas.h @@ -8,6 +8,7 @@ #include "linux/config.h" #include "mm_id.h" +#include "asm/ldt.h" struct mmu_context_skas { struct mm_id id; @@ -15,6 +16,7 @@ struct mmu_context_skas { #ifdef CONFIG_3_LEVEL_PGTABLES unsigned long last_pmd; #endif + uml_ldt_t ldt; }; extern void switch_mm_skas(struct mm_id * mm_idp); diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h index 060934740f9f94e65ed1b4dafd2587b9836766ff..daa2f85b684c7dd14845b6d1a63560abad1de67c 100644 --- a/arch/um/kernel/skas/include/skas.h +++ b/arch/um/kernel/skas/include/skas.h @@ -10,7 +10,8 @@ #include "sysdep/ptrace.h" extern int userspace_pid[]; -extern int proc_mm, ptrace_faultinfo; +extern int proc_mm, ptrace_faultinfo, ptrace_ldt; +extern int skas_needs_stub; extern void switch_threads(void *me, void *next); extern void thread_wait(void *sw, void *fb); diff --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c index 147466d7ff4f1b90e6273f3b4f99e68f1ffb7c9f..88ab96c609cecec84b1e960a512dc7a10035d8a7 100644 --- a/arch/um/kernel/skas/mem.c +++ b/arch/um/kernel/skas/mem.c @@ -20,7 +20,7 @@ unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, *task_size_out = CONFIG_HOST_TASK_SIZE; #else *host_size_out = top; - if (proc_mm && ptrace_faultinfo) + if (!skas_needs_stub) *task_size_out = top; else *task_size_out = CONFIG_STUB_START & PGDIR_MASK; #endif diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index 9e5e39cea821f8fe772c54b9363e7731cb22fc9a..677871f1b37c65d2379cd4b4b3f58e2fc9aec067 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c @@ -15,6 +15,7 @@ #include "asm/mmu.h" #include "asm/pgalloc.h" #include "asm/pgtable.h" +#include "asm/ldt.h" #include "os.h" #include "skas.h" @@ -74,13 +75,12 @@ static int init_stub_pte(struct mm_struct *mm, unsigned long proc, int init_new_context_skas(struct task_struct *task, struct mm_struct *mm) { - struct mm_struct *cur_mm = current->mm; - struct mm_id *cur_mm_id = &cur_mm->context.skas.id; - struct mm_id *mm_id = &mm->context.skas.id; + struct mmu_context_skas *from_mm = NULL; + struct mmu_context_skas *to_mm = &mm->context.skas; unsigned long stack = 0; - int from, ret = -ENOMEM; + int from_fd, ret = -ENOMEM; - if(!proc_mm || !ptrace_faultinfo){ + if(skas_needs_stub){ stack = get_zeroed_page(GFP_KERNEL); if(stack == 0) goto out; @@ -102,33 +102,43 @@ int init_new_context_skas(struct task_struct *task, struct mm_struct *mm) mm->nr_ptes--; } - mm_id->stack = stack; + + to_mm->id.stack = stack; + if(current->mm != NULL && current->mm != &init_mm) + from_mm = ¤t->mm->context.skas; if(proc_mm){ - if((cur_mm != NULL) && (cur_mm != &init_mm)) - from = cur_mm_id->u.mm_fd; - else from = -1; + if(from_mm) + from_fd = from_mm->id.u.mm_fd; + else from_fd = -1; - ret = new_mm(from, stack); + ret = new_mm(from_fd, stack); if(ret < 0){ printk("init_new_context_skas - new_mm failed, " "errno = %d\n", ret); goto out_free; } - mm_id->u.mm_fd = ret; + to_mm->id.u.mm_fd = ret; } else { - if((cur_mm != NULL) && (cur_mm != &init_mm)) - mm_id->u.pid = copy_context_skas0(stack, - cur_mm_id->u.pid); - else mm_id->u.pid = start_userspace(stack); + if(from_mm) + to_mm->id.u.pid = copy_context_skas0(stack, + from_mm->id.u.pid); + else to_mm->id.u.pid = start_userspace(stack); + } + + ret = init_new_ldt(to_mm, from_mm); + if(ret < 0){ + printk("init_new_context_skas - init_ldt" + " failed, errno = %d\n", ret); + goto out_free; } return 0; out_free: - if(mm_id->stack != 0) - free_page(mm_id->stack); + if(to_mm->id.stack != 0) + free_page(to_mm->id.stack); out: return ret; } diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index 5cd0e992978969c8d076b3fd9ce4fd0fe9d3a4c1..599d679bd4fcb3bfdebff8355d69e8d5b7a13274 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -69,6 +69,17 @@ void wait_stub_done(int pid, int sig, char * fname) if((n < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status) != SIGTRAP)){ + unsigned long regs[FRAME_SIZE]; + if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) + printk("Failed to get registers from stub, " + "errno = %d\n", errno); + else { + int i; + + printk("Stub registers -\n"); + for(i = 0; i < FRAME_SIZE; i++) + printk("\t%d - %lx\n", i, regs[i]); + } panic("%s : failed to wait for SIGUSR1/SIGTRAP, " "pid = %d, n = %d, errno = %d, status = 0x%x\n", fname, pid, n, errno, status); @@ -370,9 +381,9 @@ int copy_context_skas0(unsigned long new_stack, int pid) } /* - * This is used only, if proc_mm is available, while PTRACE_FAULTINFO - * isn't. Opening /proc/mm creates a new mm_context, which lacks the stub-pages - * Thus, we map them using /proc/mm-fd + * This is used only, if stub pages are needed, while proc_mm is + * availabl. Opening /proc/mm creates a new mm_context, which lacks + * the stub-pages. Thus, we map them using /proc/mm-fd */ void map_stub_pages(int fd, unsigned long code, unsigned long data, unsigned long stack) diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c index efe92e8aa2a9e37ffba7974d1dd6ee842928e131..9c990253966c596af858b1dbd176084012cd48d2 100644 --- a/arch/um/kernel/skas/process_kern.c +++ b/arch/um/kernel/skas/process_kern.c @@ -145,7 +145,7 @@ int new_mm(int from, unsigned long stack) "err = %d\n", -n); } - if(!ptrace_faultinfo) + if(skas_needs_stub) map_stub_pages(fd, CONFIG_STUB_CODE, CONFIG_STUB_DATA, stack); return(fd); diff --git a/arch/um/kernel/tt/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c index 8c220f054b611a3349114e69eb8fe8cb188e39ab..6c92bbccb49c30658295c9ea226258ce62c3b5af 100644 --- a/arch/um/kernel/tt/uaccess_user.c +++ b/arch/um/kernel/tt/uaccess_user.c @@ -10,6 +10,7 @@ #include "uml_uaccess.h" #include "task.h" #include "kern_util.h" +#include "os.h" int __do_copy_from_user(void *to, const void *from, int n, void **fault_addr, void **fault_catcher) diff --git a/arch/um/kernel/uaccess.c b/arch/um/kernel/uaccess.c new file mode 100644 index 0000000000000000000000000000000000000000..054e3de0784e3607ed4e74b032bae7f511f13198 --- /dev/null +++ b/arch/um/kernel/uaccess.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk) + * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +/* These are here rather than tt/uaccess.c because skas mode needs them in + * order to do SIGBUS recovery when a tmpfs mount runs out of room. + */ + +#include +#include "os.h" + +void __do_copy(void *to, const void *from, int n) +{ + memcpy(to, from, n); +} + + +int __do_copy_to_user(void *to, const void *from, int n, + void **fault_addr, void **fault_catcher) +{ + unsigned long fault; + int faulted; + + fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, + __do_copy, &faulted); + if(!faulted) return(0); + else return(n - (fault - (unsigned long) to)); +} diff --git a/arch/um/kernel/uaccess_user.c b/arch/um/kernel/uaccess_user.c deleted file mode 100644 index d035257ed0aff1e666889ad585bf7756e38c81cd..0000000000000000000000000000000000000000 --- a/arch/um/kernel/uaccess_user.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk) - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include -#include - -/* These are here rather than tt/uaccess.c because skas mode needs them in - * order to do SIGBUS recovery when a tmpfs mount runs out of room. - */ - -unsigned long __do_user_copy(void *to, const void *from, int n, - void **fault_addr, void **fault_catcher, - void (*op)(void *to, const void *from, - int n), int *faulted_out) -{ - unsigned long *faddrp = (unsigned long *) fault_addr, ret; - - sigjmp_buf jbuf; - *fault_catcher = &jbuf; - if(sigsetjmp(jbuf, 1) == 0){ - (*op)(to, from, n); - ret = 0; - *faulted_out = 0; - } - else { - ret = *faddrp; - *faulted_out = 1; - } - *fault_addr = NULL; - *fault_catcher = NULL; - return ret; -} - -void __do_copy(void *to, const void *from, int n) -{ - memcpy(to, from, n); -} - - -int __do_copy_to_user(void *to, const void *from, int n, - void **fault_addr, void **fault_catcher) -{ - unsigned long fault; - int faulted; - - fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, - __do_copy, &faulted); - if(!faulted) return(0); - else return(n - (fault - (unsigned long) to)); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 93dc782dc1cc8f5d790b2151694c4caf757238d0..142a9493912b29955140df360e86a721a2c355a1 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -137,7 +137,7 @@ static char *argv1_end = NULL; /* Set in early boot */ static int have_root __initdata = 0; -long physmem_size = 32 * 1024 * 1024; +long long physmem_size = 32 * 1024 * 1024; void set_cmdline(char *cmd) { @@ -402,7 +402,7 @@ int linux_main(int argc, char **argv) #ifndef CONFIG_HIGHMEM highmem = 0; printf("CONFIG_HIGHMEM not enabled - physical memory shrunk " - "to %ld bytes\n", physmem_size); + "to %lu bytes\n", physmem_size); #endif } @@ -414,8 +414,8 @@ int linux_main(int argc, char **argv) setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem); if(init_maps(physmem_size, iomem_size, highmem)){ - printf("Failed to allocate mem_map for %ld bytes of physical " - "memory and %ld bytes of highmem\n", physmem_size, + printf("Failed to allocate mem_map for %lu bytes of physical " + "memory and %lu bytes of highmem\n", physmem_size, highmem); exit(1); } @@ -426,7 +426,7 @@ int linux_main(int argc, char **argv) end_vm = start_vm + virtmem_size; if(virtmem_size < physmem_size) - printf("Kernel virtual memory size shrunk to %ld bytes\n", + printf("Kernel virtual memory size shrunk to %lu bytes\n", virtmem_size); uml_postsetup(); diff --git a/arch/um/kernel/user_util.c b/arch/um/kernel/user_util.c index 41d17c71511c51cf01077d51d2c6637863892c59..4c231161f25717b2bcbfad0c31598a87488beab0 100644 --- a/arch/um/kernel/user_util.c +++ b/arch/um/kernel/user_util.c @@ -27,7 +27,6 @@ #include "user.h" #include "mem_user.h" #include "init.h" -#include "helper.h" #include "ptrace_user.h" #include "uml-config.h" diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index d15ec2af6a224cda56b45d66cd8bf048c1c04d90..b83ac8e21c354eb6f7a27b21599569c31157143b 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile @@ -3,11 +3,12 @@ # Licensed under the GPL # -obj-y = aio.o elf_aux.o file.o mem.o process.o signal.o start_up.o time.o \ - tt.o tty.o user_syms.o drivers/ sys-$(SUBARCH)/ +obj-y = aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \ + start_up.o time.o tt.o tty.o uaccess.o user_syms.o drivers/ \ + sys-$(SUBARCH)/ -USER_OBJS := aio.o elf_aux.o file.o mem.o process.o signal.o start_up.o \ - time.o tt.o tty.o +USER_OBJS := aio.o elf_aux.o file.o helper.o main.o mem.o process.o signal.o \ + start_up.o time.o tt.o tty.o uaccess.o elf_aux.o: $(ARCH_DIR)/kernel-offsets.h CFLAGS_elf_aux.o += -I$(objtree)/arch/um diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c index 41cfb09442013325f7511949f8d6171e2bbac487..ffa759addd3c657e7292c07482d49d6dbc24bc38 100644 --- a/arch/um/os-Linux/aio.c +++ b/arch/um/os-Linux/aio.c @@ -10,7 +10,6 @@ #include #include #include "os.h" -#include "helper.h" #include "aio.h" #include "init.h" #include "user.h" diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c index cd4d6544da715eef01010a61ea46ff127651f9af..901b85e8a1c65c4df84ae87018b3d55cefd45698 100644 --- a/arch/um/os-Linux/drivers/ethertap_user.c +++ b/arch/um/os-Linux/drivers/ethertap_user.c @@ -19,7 +19,6 @@ #include "user_util.h" #include "net_user.h" #include "etap.h" -#include "helper.h" #include "os.h" #define MAX_PACKET ETH_MAX_PACKET diff --git a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c index 4ba9b17adf13cac85f62dfc224218bbeb9b354d7..52945338b64d503ea13c0d20ad4d45ba607e53f5 100644 --- a/arch/um/os-Linux/drivers/tuntap_user.c +++ b/arch/um/os-Linux/drivers/tuntap_user.c @@ -20,7 +20,6 @@ #include "kern_util.h" #include "user_util.h" #include "user.h" -#include "helper.h" #include "os.h" #define MAX_PACKET ETH_MAX_PACKET diff --git a/arch/um/kernel/helper.c b/arch/um/os-Linux/helper.c similarity index 93% rename from arch/um/kernel/helper.c rename to arch/um/os-Linux/helper.c index 33fb0bd3b11a13af3f0db7ddf272af3aa4f3e871..36cc8475bcdacc76aba1d932a7d2a41eff6392d8 100644 --- a/arch/um/kernel/helper.c +++ b/arch/um/os-Linux/helper.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -13,7 +13,6 @@ #include "user.h" #include "kern_util.h" #include "user_util.h" -#include "helper.h" #include "os.h" struct helper_data { @@ -46,7 +45,7 @@ static int helper_child(void *arg) errval = errno; printk("execvp of '%s' failed - errno = %d\n", argv[0], errno); os_write_file(data->fd, &errval, sizeof(errval)); - os_kill_process(os_getpid(), 0); + kill(os_getpid(), SIGKILL); return(0); } @@ -90,7 +89,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, goto out_close; } - os_close_file(fds[1]); + close(fds[1]); fds[1] = -1; /*Read the errno value from the child.*/ @@ -98,7 +97,8 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, if(n < 0){ printk("run_helper : read on pipe failed, ret = %d\n", -n); ret = n; - os_kill_process(pid, 1); + kill(pid, SIGKILL); + CATCH_EINTR(waitpid(pid, NULL, 0)); } else if(n != 0){ CATCH_EINTR(n = waitpid(pid, NULL, 0)); @@ -109,8 +109,8 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, out_close: if (fds[1] != -1) - os_close_file(fds[1]); - os_close_file(fds[0]); + close(fds[1]); + close(fds[0]); out_free: if(stack_out == NULL) free_stack(stack, 0); @@ -118,7 +118,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, return(ret); } -int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, +int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, unsigned long *stack_out, int stack_order) { unsigned long stack, sp; @@ -131,7 +131,7 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, pid = clone(proc, (void *) sp, flags | SIGCHLD, arg); if(pid < 0){ err = -errno; - printk("run_helper_thread : clone failed, errno = %d\n", + printk("run_helper_thread : clone failed, errno = %d\n", errno); return err; } diff --git a/arch/um/kernel/main.c b/arch/um/os-Linux/main.c similarity index 82% rename from arch/um/kernel/main.c rename to arch/um/os-Linux/main.c index d31027f0fe392e9753fbe04e9ef106f719a2b5d4..23da27d22569da2308b373f0edd42a2b5757c710 100644 --- a/arch/um/kernel/main.c +++ b/arch/um/os-Linux/main.c @@ -157,25 +157,25 @@ int main(int argc, char **argv, char **envp) */ change_sig(SIGPROF, 0); - /* This signal stuff used to be in the reboot case. However, - * sometimes a SIGVTALRM can come in when we're halting (reproducably - * when writing out gcov information, presumably because that takes - * some time) and cause a segfault. - */ - - /* stop timers and set SIG*ALRM to be ignored */ - disable_timer(); - - /* disable SIGIO for the fds and set SIGIO to be ignored */ - err = deactivate_all_fds(); - if(err) - printf("deactivate_all_fds failed, errno = %d\n", -err); - - /* Let any pending signals fire now. This ensures - * that they won't be delivered after the exec, when - * they are definitely not expected. - */ - unblock_signals(); + /* This signal stuff used to be in the reboot case. However, + * sometimes a SIGVTALRM can come in when we're halting (reproducably + * when writing out gcov information, presumably because that takes + * some time) and cause a segfault. + */ + + /* stop timers and set SIG*ALRM to be ignored */ + disable_timer(); + + /* disable SIGIO for the fds and set SIGIO to be ignored */ + err = deactivate_all_fds(); + if(err) + printf("deactivate_all_fds failed, errno = %d\n", -err); + + /* Let any pending signals fire now. This ensures + * that they won't be delivered after the exec, when + * they are definitely not expected. + */ + unblock_signals(); /* Reboot */ if(ret){ @@ -257,14 +257,3 @@ void __wrap_free(void *ptr) } else __real_free(ptr); } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c index 8e71edaaf80b1f53b2a66afe2ec208df375c15c1..9d7d69a523bb551f069898bed0f2f2be7c4ef247 100644 --- a/arch/um/os-Linux/mem.c +++ b/arch/um/os-Linux/mem.c @@ -88,7 +88,7 @@ int make_tempfile(const char *template, char **out_tempname, int do_unlink) * This proc is used in start_up.c * So it isn't 'static'. */ -int create_tmp_file(unsigned long len) +int create_tmp_file(unsigned long long len) { int fd, err; char zero; @@ -121,7 +121,7 @@ int create_tmp_file(unsigned long len) return(fd); } -static int create_anon_file(unsigned long len) +static int create_anon_file(unsigned long long len) { void *addr; int fd; @@ -144,7 +144,7 @@ static int create_anon_file(unsigned long len) extern int have_devanon; -int create_mem_file(unsigned long len) +int create_mem_file(unsigned long long len) { int err, fd; diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index b99ab414542fcb6700b39285fe28aeb5f881c33b..37517d49c4aea948054a70a17ec36c8f6b255b57 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -135,7 +135,9 @@ static int stop_ptraced_child(int pid, void *stack, int exitcode, } int ptrace_faultinfo = 1; +int ptrace_ldt = 1; int proc_mm = 1; +int skas_needs_stub = 0; static int __init skas0_cmd_param(char *str, int* add) { @@ -294,7 +296,7 @@ static void __init check_ptrace(void) check_sysemu(); } -extern int create_tmp_file(unsigned long len); +extern int create_tmp_file(unsigned long long len); static void check_tmpexec(void) { @@ -352,14 +354,26 @@ __uml_setup("noptracefaultinfo", noptracefaultinfo_cmd_param, " it. To support PTRACE_FAULTINFO, the host needs to be patched\n" " using the current skas3 patch.\n\n"); +static int __init noptraceldt_cmd_param(char *str, int* add) +{ + ptrace_ldt = 0; + return 0; +} + +__uml_setup("noptraceldt", noptraceldt_cmd_param, +"noptraceldt\n" +" Turns off usage of PTRACE_LDT, even if host supports it.\n" +" To support PTRACE_LDT, the host needs to be patched using\n" +" the current skas3 patch.\n\n"); + #ifdef UML_CONFIG_MODE_SKAS -static inline void check_skas3_ptrace_support(void) +static inline void check_skas3_ptrace_faultinfo(void) { struct ptrace_faultinfo fi; void *stack; int pid, n; - printf("Checking for the skas3 patch in the host..."); + printf(" - PTRACE_FAULTINFO..."); pid = start_ptraced_child(&stack); n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi); @@ -381,9 +395,49 @@ static inline void check_skas3_ptrace_support(void) stop_ptraced_child(pid, stack, 1, 1); } -int can_do_skas(void) +static inline void check_skas3_ptrace_ldt(void) +{ +#ifdef PTRACE_LDT + void *stack; + int pid, n; + unsigned char ldtbuf[40]; + struct ptrace_ldt ldt_op = (struct ptrace_ldt) { + .func = 2, /* read default ldt */ + .ptr = ldtbuf, + .bytecount = sizeof(ldtbuf)}; + + printf(" - PTRACE_LDT..."); + pid = start_ptraced_child(&stack); + + n = ptrace(PTRACE_LDT, pid, 0, (unsigned long) &ldt_op); + if (n < 0) { + if(errno == EIO) + printf("not found\n"); + else { + perror("not found"); + } + ptrace_ldt = 0; + } + else { + if(ptrace_ldt) + printf("found\n"); + else + printf("found, but use is disabled\n"); + } + + stop_ptraced_child(pid, stack, 1, 1); +#else + /* PTRACE_LDT might be disabled via cmdline option. + * We want to override this, else we might use the stub + * without real need + */ + ptrace_ldt = 1; +#endif +} + +static inline void check_skas3_proc_mm(void) { - printf("Checking for /proc/mm..."); + printf(" - /proc/mm..."); if (os_access("/proc/mm", OS_ACC_W_OK) < 0) { proc_mm = 0; printf("not found\n"); @@ -394,8 +448,19 @@ int can_do_skas(void) else printf("found\n"); } +} + +int can_do_skas(void) +{ + printf("Checking for the skas3 patch in the host:\n"); + + check_skas3_proc_mm(); + check_skas3_ptrace_faultinfo(); + check_skas3_ptrace_ldt(); + + if(!proc_mm || !ptrace_faultinfo || !ptrace_ldt) + skas_needs_stub = 1; - check_skas3_ptrace_support(); return 1; } #else diff --git a/arch/um/os-Linux/uaccess.c b/arch/um/os-Linux/uaccess.c new file mode 100644 index 0000000000000000000000000000000000000000..38d710158c3d816822c37a43cf3c32c0e0263255 --- /dev/null +++ b/arch/um/os-Linux/uaccess.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk) + * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include + +unsigned long __do_user_copy(void *to, const void *from, int n, + void **fault_addr, void **fault_catcher, + void (*op)(void *to, const void *from, + int n), int *faulted_out) +{ + unsigned long *faddrp = (unsigned long *) fault_addr, ret; + + sigjmp_buf jbuf; + *fault_catcher = &jbuf; + if(sigsetjmp(jbuf, 1) == 0){ + (*op)(to, from, n); + ret = 0; + *faulted_out = 0; + } + else { + ret = *faddrp; + *faulted_out = 1; + } + *fault_addr = NULL; + *fault_catcher = NULL; + return ret; +} + diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules index 651d9d88b6564dd0c901aa451a5a6e1b2cbad5bb..b3fbf125709b83d5a1bf7814fab538455aa95f26 100644 --- a/arch/um/scripts/Makefile.rules +++ b/arch/um/scripts/Makefile.rules @@ -26,8 +26,13 @@ define unprofile $(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1))) endef +# cmd_make_link checks to see if the $(foo-dir) variable starts with a /. If +# so, it's considered to be a path relative to $(srcdir) rather than +# $(srcdir)/arch/$(SUBARCH). This is because x86_64 wants to get ldt.c from +# arch/um/sys-i386 rather than arch/i386 like the other borrowed files. So, +# it sets $(ldt.c-dir) to /arch/um/sys-i386. quiet_cmd_make_link = SYMLINK $@ -cmd_make_link = ln -sf $(srctree)/arch/$(SUBARCH)/$($(notdir $@)-dir)/$(notdir $@) $@ +cmd_make_link = rm -f $@; ln -sf $(srctree)$(if $(filter-out /%,$($(notdir $@)-dir)),/arch/$(SUBARCH))/$($(notdir $@)-dir)/$(notdir $@) $@ # this needs to be before the foreach, because targets does not accept # complete paths like $(obj)/$(f). To make sure this works, use a := assignment diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c index 36b5c2c13289fd900e96f48d87c667f552b49721..6360f1c958d048db6fc46272f7671b5e5f21d0e6 100644 --- a/arch/um/sys-i386/ldt.c +++ b/arch/um/sys-i386/ldt.c @@ -3,53 +3,26 @@ * Licensed under the GPL */ +#include "linux/stddef.h" #include "linux/config.h" #include "linux/sched.h" #include "linux/slab.h" #include "linux/types.h" +#include "linux/errno.h" #include "asm/uaccess.h" -#include "asm/ptrace.h" #include "asm/smp.h" #include "asm/ldt.h" +#include "asm/unistd.h" #include "choose-mode.h" #include "kern.h" #include "mode_kern.h" -#ifdef CONFIG_MODE_TT - extern int modify_ldt(int func, void *ptr, unsigned long bytecount); -static int do_modify_ldt_tt(int func, void *ptr, unsigned long bytecount) -{ - return modify_ldt(func, ptr, bytecount); -} - -#endif - -#ifdef CONFIG_MODE_SKAS - -#include "skas.h" -#include "skas_ptrace.h" - -static int do_modify_ldt_skas(int func, void *ptr, unsigned long bytecount) -{ - struct ptrace_ldt ldt; - u32 cpu; - int res; - - ldt = ((struct ptrace_ldt) { .func = func, - .ptr = ptr, - .bytecount = bytecount }); - - cpu = get_cpu(); - res = ptrace(PTRACE_LDT, userspace_pid[cpu], 0, (unsigned long) &ldt); - put_cpu(); - - return res; -} -#endif +#ifdef CONFIG_MODE_TT -int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) +static long do_modify_ldt_tt(int func, void __user *ptr, + unsigned long bytecount) { struct user_desc info; int res = 0; @@ -89,8 +62,7 @@ int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) goto out; } - res = CHOOSE_MODE_PROC(do_modify_ldt_tt, do_modify_ldt_skas, func, - p, bytecount); + res = modify_ldt(func, p, bytecount); if(res < 0) goto out; @@ -108,3 +80,467 @@ int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) kfree(buf); return res; } + +#endif + +#ifdef CONFIG_MODE_SKAS + +#include "skas.h" +#include "skas_ptrace.h" +#include "asm/mmu_context.h" + +long write_ldt_entry(struct mm_id * mm_idp, int func, struct user_desc * desc, + void **addr, int done) +{ + long res; + + if(proc_mm){ + /* This is a special handling for the case, that the mm to + * modify isn't current->active_mm. + * If this is called directly by modify_ldt, + * (current->active_mm->context.skas.u == mm_idp) + * will be true. So no call to switch_mm_skas(mm_idp) is done. + * If this is called in case of init_new_ldt or PTRACE_LDT, + * mm_idp won't belong to current->active_mm, but child->mm. + * So we need to switch child's mm into our userspace, then + * later switch back. + * + * Note: I'm unshure: should interrupts be disabled here? + */ + if(!current->active_mm || current->active_mm == &init_mm || + mm_idp != ¤t->active_mm->context.skas.id) + switch_mm_skas(mm_idp); + } + + if(ptrace_ldt) { + struct ptrace_ldt ldt_op = (struct ptrace_ldt) { + .func = func, + .ptr = desc, + .bytecount = sizeof(*desc)}; + u32 cpu; + int pid; + + if(!proc_mm) + pid = mm_idp->u.pid; + else { + cpu = get_cpu(); + pid = userspace_pid[cpu]; + } + + res = ptrace(PTRACE_LDT, pid, 0, (unsigned long) &ldt_op); + if(res) + res = errno; + + if(proc_mm) + put_cpu(); + } + else { + void *stub_addr; + res = syscall_stub_data(mm_idp, (unsigned long *)desc, + (sizeof(*desc) + sizeof(long) - 1) & + ~(sizeof(long) - 1), + addr, &stub_addr); + if(!res){ + unsigned long args[] = { func, + (unsigned long)stub_addr, + sizeof(*desc), + 0, 0, 0 }; + res = run_syscall_stub(mm_idp, __NR_modify_ldt, args, + 0, addr, done); + } + } + + if(proc_mm){ + /* This is the second part of special handling, that makes + * PTRACE_LDT possible to implement. + */ + if(current->active_mm && current->active_mm != &init_mm && + mm_idp != ¤t->active_mm->context.skas.id) + switch_mm_skas(¤t->active_mm->context.skas.id); + } + + return res; +} + +static long read_ldt_from_host(void __user * ptr, unsigned long bytecount) +{ + int res, n; + struct ptrace_ldt ptrace_ldt = (struct ptrace_ldt) { + .func = 0, + .bytecount = bytecount, + .ptr = (void *)kmalloc(bytecount, GFP_KERNEL)}; + u32 cpu; + + if(ptrace_ldt.ptr == NULL) + return -ENOMEM; + + /* This is called from sys_modify_ldt only, so userspace_pid gives + * us the right number + */ + + cpu = get_cpu(); + res = ptrace(PTRACE_LDT, userspace_pid[cpu], 0, + (unsigned long) &ptrace_ldt); + put_cpu(); + if(res < 0) + goto out; + + n = copy_to_user(ptr, ptrace_ldt.ptr, res); + if(n != 0) + res = -EFAULT; + + out: + kfree(ptrace_ldt.ptr); + + return res; +} + +/* + * In skas mode, we hold our own ldt data in UML. + * Thus, the code implementing sys_modify_ldt_skas + * is very similar to (and mostly stolen from) sys_modify_ldt + * for arch/i386/kernel/ldt.c + * The routines copied and modified in part are: + * - read_ldt + * - read_default_ldt + * - write_ldt + * - sys_modify_ldt_skas + */ + +static int read_ldt(void __user * ptr, unsigned long bytecount) +{ + int i, err = 0; + unsigned long size; + uml_ldt_t * ldt = ¤t->mm->context.skas.ldt; + + if(!ldt->entry_count) + goto out; + if(bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES) + bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES; + err = bytecount; + + if(ptrace_ldt){ + return read_ldt_from_host(ptr, bytecount); + } + + down(&ldt->semaphore); + if(ldt->entry_count <= LDT_DIRECT_ENTRIES){ + size = LDT_ENTRY_SIZE*LDT_DIRECT_ENTRIES; + if(size > bytecount) + size = bytecount; + if(copy_to_user(ptr, ldt->entries, size)) + err = -EFAULT; + bytecount -= size; + ptr += size; + } + else { + for(i=0; ientry_count/LDT_ENTRIES_PER_PAGE && bytecount; + i++){ + size = PAGE_SIZE; + if(size > bytecount) + size = bytecount; + if(copy_to_user(ptr, ldt->pages[i], size)){ + err = -EFAULT; + break; + } + bytecount -= size; + ptr += size; + } + } + up(&ldt->semaphore); + + if(bytecount == 0 || err == -EFAULT) + goto out; + + if(clear_user(ptr, bytecount)) + err = -EFAULT; + +out: + return err; +} + +static int read_default_ldt(void __user * ptr, unsigned long bytecount) +{ + int err; + + if(bytecount > 5*LDT_ENTRY_SIZE) + bytecount = 5*LDT_ENTRY_SIZE; + + err = bytecount; + /* UML doesn't support lcall7 and lcall27. + * So, we don't really have a default ldt, but emulate + * an empty ldt of common host default ldt size. + */ + if(clear_user(ptr, bytecount)) + err = -EFAULT; + + return err; +} + +static int write_ldt(void __user * ptr, unsigned long bytecount, int func) +{ + uml_ldt_t * ldt = ¤t->mm->context.skas.ldt; + struct mm_id * mm_idp = ¤t->mm->context.skas.id; + int i, err; + struct user_desc ldt_info; + struct ldt_entry entry0, *ldt_p; + void *addr = NULL; + + err = -EINVAL; + if(bytecount != sizeof(ldt_info)) + goto out; + err = -EFAULT; + if(copy_from_user(&ldt_info, ptr, sizeof(ldt_info))) + goto out; + + err = -EINVAL; + if(ldt_info.entry_number >= LDT_ENTRIES) + goto out; + if(ldt_info.contents == 3){ + if (func == 1) + goto out; + if (ldt_info.seg_not_present == 0) + goto out; + } + + if(!ptrace_ldt) + down(&ldt->semaphore); + + err = write_ldt_entry(mm_idp, func, &ldt_info, &addr, 1); + if(err) + goto out_unlock; + else if(ptrace_ldt) { + /* With PTRACE_LDT available, this is used as a flag only */ + ldt->entry_count = 1; + goto out; + } + + if(ldt_info.entry_number >= ldt->entry_count && + ldt_info.entry_number >= LDT_DIRECT_ENTRIES){ + for(i=ldt->entry_count/LDT_ENTRIES_PER_PAGE; + i*LDT_ENTRIES_PER_PAGE <= ldt_info.entry_number; + i++){ + if(i == 0) + memcpy(&entry0, ldt->entries, sizeof(entry0)); + ldt->pages[i] = (struct ldt_entry *) + __get_free_page(GFP_KERNEL|__GFP_ZERO); + if(!ldt->pages[i]){ + err = -ENOMEM; + /* Undo the change in host */ + memset(&ldt_info, 0, sizeof(ldt_info)); + write_ldt_entry(mm_idp, 1, &ldt_info, &addr, 1); + goto out_unlock; + } + if(i == 0) { + memcpy(ldt->pages[0], &entry0, sizeof(entry0)); + memcpy(ldt->pages[0]+1, ldt->entries+1, + sizeof(entry0)*(LDT_DIRECT_ENTRIES-1)); + } + ldt->entry_count = (i + 1) * LDT_ENTRIES_PER_PAGE; + } + } + if(ldt->entry_count <= ldt_info.entry_number) + ldt->entry_count = ldt_info.entry_number + 1; + + if(ldt->entry_count <= LDT_DIRECT_ENTRIES) + ldt_p = ldt->entries + ldt_info.entry_number; + else + ldt_p = ldt->pages[ldt_info.entry_number/LDT_ENTRIES_PER_PAGE] + + ldt_info.entry_number%LDT_ENTRIES_PER_PAGE; + + if(ldt_info.base_addr == 0 && ldt_info.limit == 0 && + (func == 1 || LDT_empty(&ldt_info))){ + ldt_p->a = 0; + ldt_p->b = 0; + } + else{ + if (func == 1) + ldt_info.useable = 0; + ldt_p->a = LDT_entry_a(&ldt_info); + ldt_p->b = LDT_entry_b(&ldt_info); + } + err = 0; + +out_unlock: + up(&ldt->semaphore); +out: + return err; +} + +static long do_modify_ldt_skas(int func, void __user *ptr, + unsigned long bytecount) +{ + int ret = -ENOSYS; + + switch (func) { + case 0: + ret = read_ldt(ptr, bytecount); + break; + case 1: + case 0x11: + ret = write_ldt(ptr, bytecount, func); + break; + case 2: + ret = read_default_ldt(ptr, bytecount); + break; + } + return ret; +} + +short dummy_list[9] = {0, -1}; +short * host_ldt_entries = NULL; + +void ldt_get_host_info(void) +{ + long ret; + struct ldt_entry * ldt; + int i, size, k, order; + + host_ldt_entries = dummy_list+1; + + for(i = LDT_PAGES_MAX-1, order=0; i; i>>=1, order++); + + ldt = (struct ldt_entry *) + __get_free_pages(GFP_KERNEL|__GFP_ZERO, order); + if(ldt == NULL) { + printk("ldt_get_host_info: couldn't allocate buffer for host ldt\n"); + return; + } + + ret = modify_ldt(0, ldt, (1<ldt.semaphore); + + if(!from_mm){ + /* + * We have to initialize a clean ldt. + */ + if(proc_mm) { + /* + * If the new mm was created using proc_mm, host's + * default-ldt currently is assigned, which normally + * contains the call-gates for lcall7 and lcall27. + * To remove these gates, we simply write an empty + * entry as number 0 to the host. + */ + err = write_ldt_entry(&new_mm->id, 1, &desc, + &addr, 1); + } + else{ + /* + * Now we try to retrieve info about the ldt, we + * inherited from the host. All ldt-entries found + * will be reset in the following loop + */ + if(host_ldt_entries == NULL) + ldt_get_host_info(); + for(num_p=host_ldt_entries; *num_p != -1; num_p++){ + desc.entry_number = *num_p; + err = write_ldt_entry(&new_mm->id, 1, &desc, + &addr, *(num_p + 1) == -1); + if(err) + break; + } + } + new_mm->ldt.entry_count = 0; + } + else if (!ptrace_ldt) { + /* Our local LDT is used to supply the data for + * modify_ldt(READLDT), if PTRACE_LDT isn't available, + * i.e., we have to use the stub for modify_ldt, which + * can't handle the big read buffer of up to 64kB. + */ + down(&from_mm->ldt.semaphore); + if(from_mm->ldt.entry_count <= LDT_DIRECT_ENTRIES){ + memcpy(new_mm->ldt.entries, from_mm->ldt.entries, + sizeof(new_mm->ldt.entries)); + } + else{ + i = from_mm->ldt.entry_count / LDT_ENTRIES_PER_PAGE; + while(i-->0){ + page = __get_free_page(GFP_KERNEL|__GFP_ZERO); + if (!page){ + err = -ENOMEM; + break; + } + new_mm->ldt.pages[i] = (struct ldt_entry*)page; + memcpy(new_mm->ldt.pages[i], + from_mm->ldt.pages[i], PAGE_SIZE); + } + } + new_mm->ldt.entry_count = from_mm->ldt.entry_count; + up(&from_mm->ldt.semaphore); + } + + return err; +} + + +void free_ldt(struct mmu_context_skas * mm) +{ + int i; + + if(!ptrace_ldt && mm->ldt.entry_count > LDT_DIRECT_ENTRIES){ + i = mm->ldt.entry_count / LDT_ENTRIES_PER_PAGE; + while(i-- > 0){ + free_page((long )mm->ldt.pages[i]); + } + } + mm->ldt.entry_count = 0; +} +#endif + +int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) +{ + return(CHOOSE_MODE_PROC(do_modify_ldt_tt, do_modify_ldt_skas, func, + ptr, bytecount)); +} diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile index 06c3633457a2b28a9a6ad8b69dc523bb60d3ced9..ea977df395a10eb3254625e46b06483ce35d6b6b 100644 --- a/arch/um/sys-x86_64/Makefile +++ b/arch/um/sys-x86_64/Makefile @@ -5,7 +5,7 @@ # #XXX: why into lib-y? -lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o mem.o memcpy.o \ +lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o ldt.o mem.o memcpy.o \ ptrace.o ptrace_user.o sigcontext.o signal.o stub.o \ stub_segv.o syscalls.o syscall_table.o sysrq.o thunk.o @@ -14,7 +14,7 @@ obj-$(CONFIG_MODULES) += module.o um_module.o USER_OBJS := ptrace_user.o sigcontext.o -SYMLINKS = bitops.c csum-copy.S csum-partial.c csum-wrappers.c memcpy.S \ +SYMLINKS = bitops.c csum-copy.S csum-partial.c csum-wrappers.c ldt.c memcpy.S \ thunk.S module.c include arch/um/scripts/Makefile.rules @@ -23,6 +23,7 @@ bitops.c-dir = lib csum-copy.S-dir = lib csum-partial.c-dir = lib csum-wrappers.c-dir = lib +ldt.c-dir = /arch/um/sys-i386 memcpy.S-dir = lib thunk.S-dir = lib module.c-dir = kernel diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c index 3259a4db453462e0d50b438ae295ff8cf9568326..6acee5c4ada6fcdff56ddd95313865dd295df508 100644 --- a/arch/um/sys-x86_64/syscalls.c +++ b/arch/um/sys-x86_64/syscalls.c @@ -28,81 +28,6 @@ asmlinkage long sys_uname64(struct new_utsname __user * name) return err ? -EFAULT : 0; } -#ifdef CONFIG_MODE_TT -extern int modify_ldt(int func, void *ptr, unsigned long bytecount); - -long sys_modify_ldt_tt(int func, void *ptr, unsigned long bytecount) -{ - /* XXX This should check VERIFY_WRITE depending on func, check this - * in i386 as well. - */ - if (!access_ok(VERIFY_READ, ptr, bytecount)) - return -EFAULT; - return(modify_ldt(func, ptr, bytecount)); -} -#endif - -#ifdef CONFIG_MODE_SKAS -extern int userspace_pid[]; - -#include "skas_ptrace.h" - -long sys_modify_ldt_skas(int func, void *ptr, unsigned long bytecount) -{ - struct ptrace_ldt ldt; - void *buf; - int res, n; - - buf = kmalloc(bytecount, GFP_KERNEL); - if(buf == NULL) - return(-ENOMEM); - - res = 0; - - switch(func){ - case 1: - case 0x11: - res = copy_from_user(buf, ptr, bytecount); - break; - } - - if(res != 0){ - res = -EFAULT; - goto out; - } - - ldt = ((struct ptrace_ldt) { .func = func, - .ptr = buf, - .bytecount = bytecount }); -#warning Need to look up userspace_pid by cpu - res = ptrace(PTRACE_LDT, userspace_pid[0], 0, (unsigned long) &ldt); - if(res < 0) - goto out; - - switch(func){ - case 0: - case 2: - n = res; - res = copy_to_user(ptr, buf, n); - if(res != 0) - res = -EFAULT; - else - res = n; - break; - } - - out: - kfree(buf); - return(res); -} -#endif - -long sys_modify_ldt(int func, void *ptr, unsigned long bytecount) -{ - return(CHOOSE_MODE_PROC(sys_modify_ldt_tt, sys_modify_ldt_skas, func, - ptr, bytecount)); -} - #ifdef CONFIG_MODE_TT extern long arch_prctl(int code, unsigned long addr); diff --git a/arch/v850/kernel/ptrace.c b/arch/v850/kernel/ptrace.c index d6077ff47d229282b3fcd7a1f0a8341bd932f392..18492d02aaf6dcffb146233fe14450493c9fcbce 100644 --- a/arch/v850/kernel/ptrace.c +++ b/arch/v850/kernel/ptrace.c @@ -113,45 +113,10 @@ static int set_single_step (struct task_struct *t, int val) return 1; } -long sys_ptrace(long request, long pid, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, long addr, long data) { - struct task_struct *child; int rval; - lock_kernel(); - - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) { - rval = -EPERM; - goto out; - } - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - rval = 0; - goto out; - } - rval = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - - rval = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; - - if (request == PTRACE_ATTACH) { - rval = ptrace_attach(child); - goto out_tsk; - } - rval = ptrace_check_attach(child, request == PTRACE_KILL); - if (rval < 0) - goto out_tsk; - switch (request) { unsigned long val, copied; @@ -248,11 +213,7 @@ long sys_ptrace(long request, long pid, long addr, long data) rval = -EIO; goto out; } - -out_tsk: - put_task_struct(child); -out: - unlock_kernel(); + out: return rval; } diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index 21afa69a086d6826c41b6d26650486a941377b34..4cce2f6f170c0712dda1a1e6f60cbf545def6b70 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -532,8 +532,21 @@ source "drivers/firmware/Kconfig" source fs/Kconfig +menu "Instrumentation Support" + depends on EXPERIMENTAL + source "arch/x86_64/oprofile/Kconfig" +config KPROBES + bool "Kprobes (EXPERIMENTAL)" + help + Kprobes allows you to trap at almost any kernel address and + execute a callback function. register_kprobe() establishes + a probepoint and specifies the callback. Kprobes is useful + for kernel debugging, non-intrusive instrumentation and testing. + If in doubt, say "N". +endmenu + source "arch/x86_64/Kconfig.debug" source "security/Kconfig" diff --git a/arch/x86_64/Kconfig.debug b/arch/x86_64/Kconfig.debug index 9cf1410d2f5ab0fbcab1a965637f556571c2a6df..d584ecc27ea1902e038329335486a60b8e72f9eb 100644 --- a/arch/x86_64/Kconfig.debug +++ b/arch/x86_64/Kconfig.debug @@ -33,16 +33,6 @@ config IOMMU_DEBUG options. See Documentation/x86_64/boot-options.txt for more details. -config KPROBES - bool "Kprobes" - depends on DEBUG_KERNEL - help - Kprobes allows you to trap at almost any kernel address and - execute a callback function. register_kprobe() establishes - a probepoint and specifies the callback. Kprobes is useful - for kernel debugging, non-intrusive instrumentation and testing. - If in doubt, say "N". - config IOMMU_LEAK bool "IOMMU leak tracing" depends on DEBUG_KERNEL diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c index 76a28b007be95fcb17344fe48c7a1b93935a6bc0..dddeb678b440df5782af858f8db64100082c6f8a 100644 --- a/arch/x86_64/kernel/kprobes.c +++ b/arch/x86_64/kernel/kprobes.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -44,17 +43,10 @@ #include static DECLARE_MUTEX(kprobe_mutex); - -static struct kprobe *current_kprobe; -static unsigned long kprobe_status, kprobe_old_rflags, kprobe_saved_rflags; -static struct kprobe *kprobe_prev; -static unsigned long kprobe_status_prev, kprobe_old_rflags_prev, kprobe_saved_rflags_prev; -static struct pt_regs jprobe_saved_regs; -static long *jprobe_saved_rsp; void jprobe_return_end(void); -/* copy of the kernel stack at the probe fire time */ -static kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE]; +DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; +DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); /* * returns non-zero if opcode modifies the interrupt flag. @@ -236,29 +228,30 @@ void __kprobes arch_remove_kprobe(struct kprobe *p) up(&kprobe_mutex); } -static inline void save_previous_kprobe(void) +static inline void save_previous_kprobe(struct kprobe_ctlblk *kcb) { - kprobe_prev = current_kprobe; - kprobe_status_prev = kprobe_status; - kprobe_old_rflags_prev = kprobe_old_rflags; - kprobe_saved_rflags_prev = kprobe_saved_rflags; + kcb->prev_kprobe.kp = kprobe_running(); + kcb->prev_kprobe.status = kcb->kprobe_status; + kcb->prev_kprobe.old_rflags = kcb->kprobe_old_rflags; + kcb->prev_kprobe.saved_rflags = kcb->kprobe_saved_rflags; } -static inline void restore_previous_kprobe(void) +static inline void restore_previous_kprobe(struct kprobe_ctlblk *kcb) { - current_kprobe = kprobe_prev; - kprobe_status = kprobe_status_prev; - kprobe_old_rflags = kprobe_old_rflags_prev; - kprobe_saved_rflags = kprobe_saved_rflags_prev; + __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp; + kcb->kprobe_status = kcb->prev_kprobe.status; + kcb->kprobe_old_rflags = kcb->prev_kprobe.old_rflags; + kcb->kprobe_saved_rflags = kcb->prev_kprobe.saved_rflags; } -static inline void set_current_kprobe(struct kprobe *p, struct pt_regs *regs) +static inline void set_current_kprobe(struct kprobe *p, struct pt_regs *regs, + struct kprobe_ctlblk *kcb) { - current_kprobe = p; - kprobe_saved_rflags = kprobe_old_rflags + __get_cpu_var(current_kprobe) = p; + kcb->kprobe_saved_rflags = kcb->kprobe_old_rflags = (regs->eflags & (TF_MASK | IF_MASK)); if (is_IF_modifier(p->ainsn.insn)) - kprobe_saved_rflags &= ~IF_MASK; + kcb->kprobe_saved_rflags &= ~IF_MASK; } static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) @@ -272,6 +265,7 @@ static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) regs->rip = (unsigned long)p->ainsn.insn; } +/* Called with kretprobe_lock held */ void __kprobes arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs) { @@ -292,32 +286,30 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe *rp, } } -/* - * Interrupts are disabled on entry as trap3 is an interrupt gate and they - * remain disabled thorough out this function. - */ int __kprobes kprobe_handler(struct pt_regs *regs) { struct kprobe *p; int ret = 0; kprobe_opcode_t *addr = (kprobe_opcode_t *)(regs->rip - sizeof(kprobe_opcode_t)); + struct kprobe_ctlblk *kcb; - /* We're in an interrupt, but this is clear and BUG()-safe. */ + /* + * We don't want to be preempted for the entire + * duration of kprobe processing + */ preempt_disable(); + kcb = get_kprobe_ctlblk(); /* Check we're not actually recursing */ if (kprobe_running()) { - /* We *are* holding lock here, so this is safe. - Disarm the probe we just hit, and ignore it. */ p = get_kprobe(addr); if (p) { - if (kprobe_status == KPROBE_HIT_SS && + if (kcb->kprobe_status == KPROBE_HIT_SS && *p->ainsn.insn == BREAKPOINT_INSTRUCTION) { regs->eflags &= ~TF_MASK; - regs->eflags |= kprobe_saved_rflags; - unlock_kprobes(); + regs->eflags |= kcb->kprobe_saved_rflags; goto no_kprobe; - } else if (kprobe_status == KPROBE_HIT_SSDONE) { + } else if (kcb->kprobe_status == KPROBE_HIT_SSDONE) { /* TODO: Provide re-entrancy from * post_kprobes_handler() and avoid exception * stack corruption while single-stepping on @@ -325,6 +317,7 @@ int __kprobes kprobe_handler(struct pt_regs *regs) */ arch_disarm_kprobe(p); regs->rip = (unsigned long)p->addr; + reset_current_kprobe(); ret = 1; } else { /* We have reentered the kprobe_handler(), since @@ -334,27 +327,24 @@ int __kprobes kprobe_handler(struct pt_regs *regs) * of the new probe without calling any user * handlers. */ - save_previous_kprobe(); - set_current_kprobe(p, regs); + save_previous_kprobe(kcb); + set_current_kprobe(p, regs, kcb); p->nmissed++; prepare_singlestep(p, regs); - kprobe_status = KPROBE_REENTER; + kcb->kprobe_status = KPROBE_REENTER; return 1; } } else { - p = current_kprobe; + p = __get_cpu_var(current_kprobe); if (p->break_handler && p->break_handler(p, regs)) { goto ss_probe; } } - /* If it's not ours, can't be delete race, (we hold lock). */ goto no_kprobe; } - lock_kprobes(); p = get_kprobe(addr); if (!p) { - unlock_kprobes(); if (*addr != BREAKPOINT_INSTRUCTION) { /* * The breakpoint instruction was removed right @@ -372,8 +362,8 @@ int __kprobes kprobe_handler(struct pt_regs *regs) goto no_kprobe; } - kprobe_status = KPROBE_HIT_ACTIVE; - set_current_kprobe(p, regs); + set_current_kprobe(p, regs, kcb); + kcb->kprobe_status = KPROBE_HIT_ACTIVE; if (p->pre_handler && p->pre_handler(p, regs)) /* handler has already set things up, so skip ss setup */ @@ -381,7 +371,7 @@ int __kprobes kprobe_handler(struct pt_regs *regs) ss_probe: prepare_singlestep(p, regs); - kprobe_status = KPROBE_HIT_SS; + kcb->kprobe_status = KPROBE_HIT_SS; return 1; no_kprobe: @@ -409,9 +399,10 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) struct kretprobe_instance *ri = NULL; struct hlist_head *head; struct hlist_node *node, *tmp; - unsigned long orig_ret_address = 0; + unsigned long flags, orig_ret_address = 0; unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline; + spin_lock_irqsave(&kretprobe_lock, flags); head = kretprobe_inst_table_head(current); /* @@ -450,13 +441,14 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address)); regs->rip = orig_ret_address; - unlock_kprobes(); + reset_current_kprobe(); + spin_unlock_irqrestore(&kretprobe_lock, flags); preempt_enable_no_resched(); /* * By returning a non-zero value, we are telling - * kprobe_handler() that we have handled unlocking - * and re-enabling preemption. + * kprobe_handler() that we don't want the post_handler + * to run (and have re-enabled preemption) */ return 1; } @@ -483,7 +475,8 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) * that is atop the stack is the address following the copied instruction. * We need to make it the address following the original instruction. */ -static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) +static void __kprobes resume_execution(struct kprobe *p, + struct pt_regs *regs, struct kprobe_ctlblk *kcb) { unsigned long *tos = (unsigned long *)regs->rsp; unsigned long next_rip = 0; @@ -498,7 +491,7 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) switch (*insn) { case 0x9c: /* pushfl */ *tos &= ~(TF_MASK | IF_MASK); - *tos |= kprobe_old_rflags; + *tos |= kcb->kprobe_old_rflags; break; case 0xc3: /* ret/lret */ case 0xcb: @@ -537,30 +530,28 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) } } -/* - * Interrupts are disabled on entry as trap1 is an interrupt gate and they - * remain disabled thoroughout this function. And we hold kprobe lock. - */ int __kprobes post_kprobe_handler(struct pt_regs *regs) { - if (!kprobe_running()) + struct kprobe *cur = kprobe_running(); + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + + if (!cur) return 0; - if ((kprobe_status != KPROBE_REENTER) && current_kprobe->post_handler) { - kprobe_status = KPROBE_HIT_SSDONE; - current_kprobe->post_handler(current_kprobe, regs, 0); + if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) { + kcb->kprobe_status = KPROBE_HIT_SSDONE; + cur->post_handler(cur, regs, 0); } - resume_execution(current_kprobe, regs); - regs->eflags |= kprobe_saved_rflags; + resume_execution(cur, regs, kcb); + regs->eflags |= kcb->kprobe_saved_rflags; /* Restore the original saved kprobes variables and continue. */ - if (kprobe_status == KPROBE_REENTER) { - restore_previous_kprobe(); + if (kcb->kprobe_status == KPROBE_REENTER) { + restore_previous_kprobe(kcb); goto out; - } else { - unlock_kprobes(); } + reset_current_kprobe(); out: preempt_enable_no_resched(); @@ -575,18 +566,19 @@ int __kprobes post_kprobe_handler(struct pt_regs *regs) return 1; } -/* Interrupts disabled, kprobe_lock held. */ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) { - if (current_kprobe->fault_handler - && current_kprobe->fault_handler(current_kprobe, regs, trapnr)) + struct kprobe *cur = kprobe_running(); + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + + if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) return 1; - if (kprobe_status & KPROBE_HIT_SS) { - resume_execution(current_kprobe, regs); - regs->eflags |= kprobe_old_rflags; + if (kcb->kprobe_status & KPROBE_HIT_SS) { + resume_execution(cur, regs, kcb); + regs->eflags |= kcb->kprobe_old_rflags; - unlock_kprobes(); + reset_current_kprobe(); preempt_enable_no_resched(); } return 0; @@ -599,39 +591,41 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *data) { struct die_args *args = (struct die_args *)data; + int ret = NOTIFY_DONE; + switch (val) { case DIE_INT3: if (kprobe_handler(args->regs)) - return NOTIFY_STOP; + ret = NOTIFY_STOP; break; case DIE_DEBUG: if (post_kprobe_handler(args->regs)) - return NOTIFY_STOP; + ret = NOTIFY_STOP; break; case DIE_GPF: - if (kprobe_running() && - kprobe_fault_handler(args->regs, args->trapnr)) - return NOTIFY_STOP; - break; case DIE_PAGE_FAULT: + /* kprobe_running() needs smp_processor_id() */ + preempt_disable(); if (kprobe_running() && kprobe_fault_handler(args->regs, args->trapnr)) - return NOTIFY_STOP; + ret = NOTIFY_STOP; + preempt_enable(); break; default: break; } - return NOTIFY_DONE; + return ret; } int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) { struct jprobe *jp = container_of(p, struct jprobe, kp); unsigned long addr; + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); - jprobe_saved_regs = *regs; - jprobe_saved_rsp = (long *) regs->rsp; - addr = (unsigned long)jprobe_saved_rsp; + kcb->jprobe_saved_regs = *regs; + kcb->jprobe_saved_rsp = (long *) regs->rsp; + addr = (unsigned long)(kcb->jprobe_saved_rsp); /* * As Linus pointed out, gcc assumes that the callee * owns the argument space and could overwrite it, e.g. @@ -639,7 +633,8 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) * we also save and restore enough stack bytes to cover * the argument area. */ - memcpy(jprobes_stack, (kprobe_opcode_t *) addr, MIN_STACK_SIZE(addr)); + memcpy(kcb->jprobes_stack, (kprobe_opcode_t *)addr, + MIN_STACK_SIZE(addr)); regs->eflags &= ~IF_MASK; regs->rip = (unsigned long)(jp->entry); return 1; @@ -647,36 +642,40 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) void __kprobes jprobe_return(void) { - preempt_enable_no_resched(); + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + asm volatile (" xchg %%rbx,%%rsp \n" " int3 \n" " .globl jprobe_return_end \n" " jprobe_return_end: \n" " nop \n"::"b" - (jprobe_saved_rsp):"memory"); + (kcb->jprobe_saved_rsp):"memory"); } int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) { + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); u8 *addr = (u8 *) (regs->rip - 1); - unsigned long stack_addr = (unsigned long)jprobe_saved_rsp; + unsigned long stack_addr = (unsigned long)(kcb->jprobe_saved_rsp); struct jprobe *jp = container_of(p, struct jprobe, kp); if ((addr > (u8 *) jprobe_return) && (addr < (u8 *) jprobe_return_end)) { - if ((long *)regs->rsp != jprobe_saved_rsp) { + if ((long *)regs->rsp != kcb->jprobe_saved_rsp) { struct pt_regs *saved_regs = - container_of(jprobe_saved_rsp, struct pt_regs, rsp); + container_of(kcb->jprobe_saved_rsp, + struct pt_regs, rsp); printk("current rsp %p does not match saved rsp %p\n", - (long *)regs->rsp, jprobe_saved_rsp); + (long *)regs->rsp, kcb->jprobe_saved_rsp); printk("Saved registers for jprobe %p\n", jp); show_registers(saved_regs); printk("Current registers\n"); show_registers(regs); BUG(); } - *regs = jprobe_saved_regs; - memcpy((kprobe_opcode_t *) stack_addr, jprobes_stack, + *regs = kcb->jprobe_saved_regs; + memcpy((kprobe_opcode_t *) stack_addr, kcb->jprobes_stack, MIN_STACK_SIZE(stack_addr)); + preempt_enable_no_resched(); return 1; } return 0; diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c index bbf64b59a21e217b64085f7ce378d7fa332a4bab..a87b6cebe80fc45e3fced915120c619215e5e87a 100644 --- a/arch/x86_64/kernel/ptrace.c +++ b/arch/x86_64/kernel/ptrace.c @@ -313,48 +313,11 @@ static unsigned long getreg(struct task_struct *child, unsigned long regno) } -asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data) +long arch_ptrace(struct task_struct *child, long request, long addr, long data) { - struct task_struct *child; long i, ret; unsigned ui; - /* This lock_kernel fixes a subtle race with suid exec */ - lock_kernel(); - ret = -EPERM; - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - ret = security_ptrace(current->parent, current); - if (ret) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) - goto out_tsk; - switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ @@ -608,10 +571,6 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data ret = ptrace_request(child, request, addr, data); break; } -out_tsk: - put_task_struct(child); -out: - unlock_kernel(); return ret; } diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index 658a81b33f3bf1a1d31087f2e3b3637bd76ddab0..4b5b088ec1022a5d28c6e0e2dae76df9c4eed785 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -65,8 +65,6 @@ int smp_num_siblings = 1; /* Package ID of each logical CPU */ u8 phys_proc_id[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID }; u8 cpu_core_id[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID }; -EXPORT_SYMBOL(phys_proc_id); -EXPORT_SYMBOL(cpu_core_id); /* Bitmask of currently online CPUs */ cpumask_t cpu_online_map __read_mostly; diff --git a/arch/x86_64/oprofile/Kconfig b/arch/x86_64/oprofile/Kconfig index 5ade19801b97a598829b4b1dff817a6cc59a028e..d8a84088471a1c011868aae0b44558d15c9f1c0b 100644 --- a/arch/x86_64/oprofile/Kconfig +++ b/arch/x86_64/oprofile/Kconfig @@ -1,7 +1,3 @@ - -menu "Profiling support" - depends on EXPERIMENTAL - config PROFILING bool "Profiling support (EXPERIMENTAL)" help @@ -19,5 +15,3 @@ config OPROFILE If unsure, say N. -endmenu - diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c index 14460743de079dd32263a003b6d58d640f335027..ab5c4c65b5c416848b553efda177b10038243858 100644 --- a/arch/xtensa/kernel/ptrace.c +++ b/arch/xtensa/kernel/ptrace.c @@ -45,58 +45,10 @@ void ptrace_disable(struct task_struct *child) /* Nothing to do.. */ } -long sys_ptrace(long request, long pid, long addr, long data) +long arch_ptrace(struct task_struct *child, long request, long addr, long data) { - struct task_struct *child; int ret = -EPERM; - lock_kernel(); - -#if 0 - if ((int)request != 1) - printk("ptrace(r=%d,pid=%d,addr=%08lx,data=%08lx)\n", - (int) request, (int) pid, (unsigned long) addr, - (unsigned long) data); -#endif - - if (request == PTRACE_TRACEME) { - - /* Are we already being traced? */ - - if (current->ptrace & PT_PTRACED) - goto out; - - if ((ret = security_ptrace(current->parent, current))) - goto out; - - /* Set the ptrace bit in the process flags. */ - - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out; - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - - if ((ret = ptrace_check_attach(child, request == PTRACE_KILL)) < 0) - goto out_tsk; - switch (request) { case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: @@ -375,10 +327,7 @@ long sys_ptrace(long request, long pid, long addr, long data) ret = ptrace_request(child, request, addr, data); goto out; } -out_tsk: - put_task_struct(child); -out: - unlock_kernel(); + out: return ret; } diff --git a/block/Kconfig b/block/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..eb48edb80c1d19ad53ecd9379c3b3739272ba94a --- /dev/null +++ b/block/Kconfig @@ -0,0 +1,14 @@ +# +# Block layer core configuration +# +#XXX - it makes sense to enable this only for 32-bit subarch's, not for x86_64 +#for instance. +config LBD + bool "Support for Large Block Devices" + depends on X86 || (MIPS && 32BIT) || PPC32 || ARCH_S390_31 || SUPERH || UML + help + Say Y here if you want to attach large (bigger than 2TB) discs to + your machine, or if you want to have a raid or loopback device + bigger than 2TB. Otherwise say N. + +source block/Kconfig.iosched diff --git a/drivers/block/Kconfig.iosched b/block/Kconfig.iosched similarity index 94% rename from drivers/block/Kconfig.iosched rename to block/Kconfig.iosched index 5b90d2fa63b8382d80de600d0410e4a1cf0518e2..f3b7753aac9940a34e6b6af58f7a7f26762c8b50 100644 --- a/drivers/block/Kconfig.iosched +++ b/block/Kconfig.iosched @@ -46,13 +46,13 @@ choice block devices. config DEFAULT_AS - bool "Anticipatory" if IOSCHED_AS + bool "Anticipatory" if IOSCHED_AS=y config DEFAULT_DEADLINE - bool "Deadline" if IOSCHED_DEADLINE + bool "Deadline" if IOSCHED_DEADLINE=y config DEFAULT_CFQ - bool "CFQ" if IOSCHED_CFQ + bool "CFQ" if IOSCHED_CFQ=y config DEFAULT_NOOP bool "No-op" diff --git a/block/Makefile b/block/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7e4f93e2b44e9a87503a90bce18c246245cd040a --- /dev/null +++ b/block/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the kernel block layer +# + +obj-y := elevator.o ll_rw_blk.o ioctl.o genhd.o scsi_ioctl.o + +obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o +obj-$(CONFIG_IOSCHED_AS) += as-iosched.o +obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o +obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o diff --git a/drivers/block/as-iosched.c b/block/as-iosched.c similarity index 95% rename from drivers/block/as-iosched.c rename to block/as-iosched.c index c6744ff382944a590767cef1827e627c1915c7ad..a78e160b59a3545b8a06b78e2c78e503f1494d24 100644 --- a/drivers/block/as-iosched.c +++ b/block/as-iosched.c @@ -4,7 +4,7 @@ * Anticipatory & deadline i/o scheduler. * * Copyright (C) 2002 Jens Axboe - * Nick Piggin + * Nick Piggin * */ #include @@ -69,7 +69,7 @@ /* Bits in as_io_context.state */ enum as_io_states { - AS_TASK_RUNNING=0, /* Process has not exitted */ + AS_TASK_RUNNING=0, /* Process has not exited */ AS_TASK_IOSTARTED, /* Process has started some IO */ AS_TASK_IORUNNING, /* Process has completed some IO */ }; @@ -102,6 +102,9 @@ struct as_data { unsigned long exit_prob; /* probability a task will exit while being waited on */ + unsigned long exit_no_coop; /* probablility an exited task will + not be part of a later cooperating + request */ unsigned long new_ttime_total; /* mean thinktime on new proc */ unsigned long new_ttime_mean; u64 new_seek_total; /* mean seek on new proc */ @@ -636,37 +639,152 @@ static void as_antic_timeout(unsigned long data) kblockd_schedule_work(&ad->antic_work); if (aic->ttime_samples == 0) { - /* process anticipated on has exitted or timed out*/ + /* process anticipated on has exited or timed out*/ ad->exit_prob = (7*ad->exit_prob + 256)/8; } + if (!test_bit(AS_TASK_RUNNING, &aic->state)) { + /* process not "saved" by a cooperating request */ + ad->exit_no_coop = (7*ad->exit_no_coop + 256)/8; + } } spin_unlock_irqrestore(q->queue_lock, flags); } +static void as_update_thinktime(struct as_data *ad, struct as_io_context *aic, + unsigned long ttime) +{ + /* fixed point: 1.0 == 1<<8 */ + if (aic->ttime_samples == 0) { + ad->new_ttime_total = (7*ad->new_ttime_total + 256*ttime) / 8; + ad->new_ttime_mean = ad->new_ttime_total / 256; + + ad->exit_prob = (7*ad->exit_prob)/8; + } + aic->ttime_samples = (7*aic->ttime_samples + 256) / 8; + aic->ttime_total = (7*aic->ttime_total + 256*ttime) / 8; + aic->ttime_mean = (aic->ttime_total + 128) / aic->ttime_samples; +} + +static void as_update_seekdist(struct as_data *ad, struct as_io_context *aic, + sector_t sdist) +{ + u64 total; + + if (aic->seek_samples == 0) { + ad->new_seek_total = (7*ad->new_seek_total + 256*(u64)sdist)/8; + ad->new_seek_mean = ad->new_seek_total / 256; + } + + /* + * Don't allow the seek distance to get too large from the + * odd fragment, pagein, etc + */ + if (aic->seek_samples <= 60) /* second&third seek */ + sdist = min(sdist, (aic->seek_mean * 4) + 2*1024*1024); + else + sdist = min(sdist, (aic->seek_mean * 4) + 2*1024*64); + + aic->seek_samples = (7*aic->seek_samples + 256) / 8; + aic->seek_total = (7*aic->seek_total + (u64)256*sdist) / 8; + total = aic->seek_total + (aic->seek_samples/2); + do_div(total, aic->seek_samples); + aic->seek_mean = (sector_t)total; +} + +/* + * as_update_iohist keeps a decaying histogram of IO thinktimes, and + * updates @aic->ttime_mean based on that. It is called when a new + * request is queued. + */ +static void as_update_iohist(struct as_data *ad, struct as_io_context *aic, + struct request *rq) +{ + struct as_rq *arq = RQ_DATA(rq); + int data_dir = arq->is_sync; + unsigned long thinktime = 0; + sector_t seek_dist; + + if (aic == NULL) + return; + + if (data_dir == REQ_SYNC) { + unsigned long in_flight = atomic_read(&aic->nr_queued) + + atomic_read(&aic->nr_dispatched); + spin_lock(&aic->lock); + if (test_bit(AS_TASK_IORUNNING, &aic->state) || + test_bit(AS_TASK_IOSTARTED, &aic->state)) { + /* Calculate read -> read thinktime */ + if (test_bit(AS_TASK_IORUNNING, &aic->state) + && in_flight == 0) { + thinktime = jiffies - aic->last_end_request; + thinktime = min(thinktime, MAX_THINKTIME-1); + } + as_update_thinktime(ad, aic, thinktime); + + /* Calculate read -> read seek distance */ + if (aic->last_request_pos < rq->sector) + seek_dist = rq->sector - aic->last_request_pos; + else + seek_dist = aic->last_request_pos - rq->sector; + as_update_seekdist(ad, aic, seek_dist); + } + aic->last_request_pos = rq->sector + rq->nr_sectors; + set_bit(AS_TASK_IOSTARTED, &aic->state); + spin_unlock(&aic->lock); + } +} + /* * as_close_req decides if one request is considered "close" to the * previous one issued. */ -static int as_close_req(struct as_data *ad, struct as_rq *arq) +static int as_close_req(struct as_data *ad, struct as_io_context *aic, + struct as_rq *arq) { unsigned long delay; /* milliseconds */ sector_t last = ad->last_sector[ad->batch_data_dir]; sector_t next = arq->request->sector; sector_t delta; /* acceptable close offset (in sectors) */ + sector_t s; if (ad->antic_status == ANTIC_OFF || !ad->ioc_finished) delay = 0; else delay = ((jiffies - ad->antic_start) * 1000) / HZ; - if (delay <= 1) - delta = 64; + if (delay == 0) + delta = 8192; else if (delay <= 20 && delay <= ad->antic_expire) - delta = 64 << (delay-1); + delta = 8192 << delay; else return 1; - return (last - (delta>>1) <= next) && (next <= last + delta); + if ((last <= next + (delta>>1)) && (next <= last + delta)) + return 1; + + if (last < next) + s = next - last; + else + s = last - next; + + if (aic->seek_samples == 0) { + /* + * Process has just started IO. Use past statistics to + * gauge success possibility + */ + if (ad->new_seek_mean > s) { + /* this request is better than what we're expecting */ + return 1; + } + + } else { + if (aic->seek_mean > s) { + /* this request is better than what we're expecting */ + return 1; + } + } + + return 0; } /* @@ -678,7 +796,7 @@ static int as_close_req(struct as_data *ad, struct as_rq *arq) * dispatch it ASAP, because we know that application will not be submitting * any new reads. * - * If the task which has submitted the request has exitted, break anticipation. + * If the task which has submitted the request has exited, break anticipation. * * If this task has queued some other IO, do not enter enticipation. */ @@ -686,7 +804,6 @@ static int as_can_break_anticipation(struct as_data *ad, struct as_rq *arq) { struct io_context *ioc; struct as_io_context *aic; - sector_t s; ioc = ad->io_context; BUG_ON(!ioc); @@ -708,13 +825,6 @@ static int as_can_break_anticipation(struct as_data *ad, struct as_rq *arq) if (!aic) return 0; - if (!test_bit(AS_TASK_RUNNING, &aic->state)) { - /* process anticipated on has exitted */ - if (aic->ttime_samples == 0) - ad->exit_prob = (7*ad->exit_prob + 256)/8; - return 1; - } - if (atomic_read(&aic->nr_queued) > 0) { /* process has more requests queued */ return 1; @@ -725,57 +835,45 @@ static int as_can_break_anticipation(struct as_data *ad, struct as_rq *arq) return 1; } - if (arq && arq->is_sync == REQ_SYNC && as_close_req(ad, arq)) { + if (arq && arq->is_sync == REQ_SYNC && as_close_req(ad, aic, arq)) { /* * Found a close request that is not one of ours. * - * This makes close requests from another process reset - * our thinktime delay. Is generally useful when there are + * This makes close requests from another process update + * our IO history. Is generally useful when there are * two or more cooperating processes working in the same * area. */ - spin_lock(&aic->lock); - aic->last_end_request = jiffies; - spin_unlock(&aic->lock); + if (!test_bit(AS_TASK_RUNNING, &aic->state)) { + if (aic->ttime_samples == 0) + ad->exit_prob = (7*ad->exit_prob + 256)/8; + + ad->exit_no_coop = (7*ad->exit_no_coop)/8; + } + + as_update_iohist(ad, aic, arq->request); return 1; } + if (!test_bit(AS_TASK_RUNNING, &aic->state)) { + /* process anticipated on has exited */ + if (aic->ttime_samples == 0) + ad->exit_prob = (7*ad->exit_prob + 256)/8; + + if (ad->exit_no_coop > 128) + return 1; + } if (aic->ttime_samples == 0) { if (ad->new_ttime_mean > ad->antic_expire) return 1; - if (ad->exit_prob > 128) + if (ad->exit_prob * ad->exit_no_coop > 128*256) return 1; } else if (aic->ttime_mean > ad->antic_expire) { /* the process thinks too much between requests */ return 1; } - if (!arq) - return 0; - - if (ad->last_sector[REQ_SYNC] < arq->request->sector) - s = arq->request->sector - ad->last_sector[REQ_SYNC]; - else - s = ad->last_sector[REQ_SYNC] - arq->request->sector; - - if (aic->seek_samples == 0) { - /* - * Process has just started IO. Use past statistics to - * guage success possibility - */ - if (ad->new_seek_mean > s) { - /* this request is better than what we're expecting */ - return 1; - } - - } else { - if (aic->seek_mean > s) { - /* this request is better than what we're expecting */ - return 1; - } - } - return 0; } @@ -809,94 +907,11 @@ static int as_can_anticipate(struct as_data *ad, struct as_rq *arq) * Status is either ANTIC_OFF so start waiting, * ANTIC_WAIT_REQ so continue waiting for request to finish * or ANTIC_WAIT_NEXT so continue waiting for an acceptable request. - * */ return 1; } -static void as_update_thinktime(struct as_data *ad, struct as_io_context *aic, unsigned long ttime) -{ - /* fixed point: 1.0 == 1<<8 */ - if (aic->ttime_samples == 0) { - ad->new_ttime_total = (7*ad->new_ttime_total + 256*ttime) / 8; - ad->new_ttime_mean = ad->new_ttime_total / 256; - - ad->exit_prob = (7*ad->exit_prob)/8; - } - aic->ttime_samples = (7*aic->ttime_samples + 256) / 8; - aic->ttime_total = (7*aic->ttime_total + 256*ttime) / 8; - aic->ttime_mean = (aic->ttime_total + 128) / aic->ttime_samples; -} - -static void as_update_seekdist(struct as_data *ad, struct as_io_context *aic, sector_t sdist) -{ - u64 total; - - if (aic->seek_samples == 0) { - ad->new_seek_total = (7*ad->new_seek_total + 256*(u64)sdist)/8; - ad->new_seek_mean = ad->new_seek_total / 256; - } - - /* - * Don't allow the seek distance to get too large from the - * odd fragment, pagein, etc - */ - if (aic->seek_samples <= 60) /* second&third seek */ - sdist = min(sdist, (aic->seek_mean * 4) + 2*1024*1024); - else - sdist = min(sdist, (aic->seek_mean * 4) + 2*1024*64); - - aic->seek_samples = (7*aic->seek_samples + 256) / 8; - aic->seek_total = (7*aic->seek_total + (u64)256*sdist) / 8; - total = aic->seek_total + (aic->seek_samples/2); - do_div(total, aic->seek_samples); - aic->seek_mean = (sector_t)total; -} - -/* - * as_update_iohist keeps a decaying histogram of IO thinktimes, and - * updates @aic->ttime_mean based on that. It is called when a new - * request is queued. - */ -static void as_update_iohist(struct as_data *ad, struct as_io_context *aic, struct request *rq) -{ - struct as_rq *arq = RQ_DATA(rq); - int data_dir = arq->is_sync; - unsigned long thinktime; - sector_t seek_dist; - - if (aic == NULL) - return; - - if (data_dir == REQ_SYNC) { - unsigned long in_flight = atomic_read(&aic->nr_queued) - + atomic_read(&aic->nr_dispatched); - spin_lock(&aic->lock); - if (test_bit(AS_TASK_IORUNNING, &aic->state) || - test_bit(AS_TASK_IOSTARTED, &aic->state)) { - /* Calculate read -> read thinktime */ - if (test_bit(AS_TASK_IORUNNING, &aic->state) - && in_flight == 0) { - thinktime = jiffies - aic->last_end_request; - thinktime = min(thinktime, MAX_THINKTIME-1); - } else - thinktime = 0; - as_update_thinktime(ad, aic, thinktime); - - /* Calculate read -> read seek distance */ - if (aic->last_request_pos < rq->sector) - seek_dist = rq->sector - aic->last_request_pos; - else - seek_dist = aic->last_request_pos - rq->sector; - as_update_seekdist(ad, aic, seek_dist); - } - aic->last_request_pos = rq->sector + rq->nr_sectors; - set_bit(AS_TASK_IOSTARTED, &aic->state); - spin_unlock(&aic->lock); - } -} - /* * as_update_arq must be called whenever a request (arq) is added to * the sort_list. This function keeps caches up to date, and checks if the @@ -1201,7 +1216,7 @@ static int as_dispatch_request(request_queue_t *q, int force) || ad->changed_batch) return 0; - if (!(reads && writes && as_batch_expired(ad)) ) { + if (!(reads && writes && as_batch_expired(ad))) { /* * batch is still running or no reads or no writes */ @@ -1316,7 +1331,8 @@ static int as_dispatch_request(request_queue_t *q, int force) * Add arq to a list behind alias */ static inline void -as_add_aliased_request(struct as_data *ad, struct as_rq *arq, struct as_rq *alias) +as_add_aliased_request(struct as_data *ad, struct as_rq *arq, + struct as_rq *alias) { struct request *req = arq->request; struct list_head *insert = alias->request->queuelist.prev; @@ -1441,8 +1457,8 @@ static int as_queue_empty(request_queue_t *q) && list_empty(&ad->fifo_list[REQ_SYNC]); } -static struct request * -as_former_request(request_queue_t *q, struct request *rq) +static struct request *as_former_request(request_queue_t *q, + struct request *rq) { struct as_rq *arq = RQ_DATA(rq); struct rb_node *rbprev = rb_prev(&arq->rb_node); @@ -1454,8 +1470,8 @@ as_former_request(request_queue_t *q, struct request *rq) return ret; } -static struct request * -as_latter_request(request_queue_t *q, struct request *rq) +static struct request *as_latter_request(request_queue_t *q, + struct request *rq) { struct as_rq *arq = RQ_DATA(rq); struct rb_node *rbnext = rb_next(&arq->rb_node); @@ -1537,7 +1553,7 @@ static void as_merged_request(request_queue_t *q, struct request *req) * currently don't bother. Ditto the next function. */ as_del_arq_rb(ad, arq); - if ((alias = as_add_arq_rb(ad, arq)) ) { + if ((alias = as_add_arq_rb(ad, arq))) { list_del_init(&arq->fifo); as_add_aliased_request(ad, arq, alias); if (next_arq) @@ -1551,9 +1567,8 @@ static void as_merged_request(request_queue_t *q, struct request *req) } } -static void -as_merged_requests(request_queue_t *q, struct request *req, - struct request *next) +static void as_merged_requests(request_queue_t *q, struct request *req, + struct request *next) { struct as_data *ad = q->elevator->elevator_data; struct as_rq *arq = RQ_DATA(req); @@ -1576,7 +1591,7 @@ as_merged_requests(request_queue_t *q, struct request *req, next_arq = as_find_next_arq(ad, arq); as_del_arq_rb(ad, arq); - if ((alias = as_add_arq_rb(ad, arq)) ) { + if ((alias = as_add_arq_rb(ad, arq))) { list_del_init(&arq->fifo); as_add_aliased_request(ad, arq, alias); if (next_arq) @@ -1806,9 +1821,14 @@ static ssize_t as_est_show(struct as_data *ad, char *page) { int pos = 0; - pos += sprintf(page+pos, "%lu %% exit probability\n", 100*ad->exit_prob/256); + pos += sprintf(page+pos, "%lu %% exit probability\n", + 100*ad->exit_prob/256); + pos += sprintf(page+pos, "%lu %% probability of exiting without a " + "cooperating process submitting IO\n", + 100*ad->exit_no_coop/256); pos += sprintf(page+pos, "%lu ms new thinktime\n", ad->new_ttime_mean); - pos += sprintf(page+pos, "%llu sectors new seek distance\n", (unsigned long long)ad->new_seek_mean); + pos += sprintf(page+pos, "%llu sectors new seek distance\n", + (unsigned long long)ad->new_seek_mean); return pos; } diff --git a/drivers/block/cfq-iosched.c b/block/cfq-iosched.c similarity index 100% rename from drivers/block/cfq-iosched.c rename to block/cfq-iosched.c diff --git a/drivers/block/deadline-iosched.c b/block/deadline-iosched.c similarity index 100% rename from drivers/block/deadline-iosched.c rename to block/deadline-iosched.c diff --git a/drivers/block/elevator.c b/block/elevator.c similarity index 100% rename from drivers/block/elevator.c rename to block/elevator.c diff --git a/drivers/block/genhd.c b/block/genhd.c similarity index 100% rename from drivers/block/genhd.c rename to block/genhd.c diff --git a/drivers/block/ioctl.c b/block/ioctl.c similarity index 100% rename from drivers/block/ioctl.c rename to block/ioctl.c diff --git a/drivers/block/ll_rw_blk.c b/block/ll_rw_blk.c similarity index 99% rename from drivers/block/ll_rw_blk.c rename to block/ll_rw_blk.c index 2747741677fb0d92c10dc76c272763eb6f2b1a96..5f52e30b43f812c75cef8289571e9a1a35bd2808 100644 --- a/drivers/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -706,7 +706,6 @@ EXPORT_SYMBOL(blk_queue_dma_alignment); /** * blk_queue_find_tag - find a request by its tag and queue - * * @q: The request queue for the device * @tag: The tag of the request * diff --git a/drivers/block/noop-iosched.c b/block/noop-iosched.c similarity index 100% rename from drivers/block/noop-iosched.c rename to block/noop-iosched.c diff --git a/drivers/block/scsi_ioctl.c b/block/scsi_ioctl.c similarity index 100% rename from drivers/block/scsi_ioctl.c rename to block/scsi_ioctl.c diff --git a/drivers/Makefile b/drivers/Makefile index 65670be6ff1a15ac86d8213a08533cbaf498037a..fac1e1603097d46bcc66e076c083601cfa37c52f 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_PCI) += pci/ usb/ obj-$(CONFIG_PARISC) += parisc/ +obj-$(CONFIG_RAPIDIO) += rapidio/ obj-y += video/ obj-$(CONFIG_ACPI) += acpi/ # PnP must come after ACPI since it will eventually need to check if acpi @@ -67,3 +68,4 @@ obj-$(CONFIG_INFINIBAND) += infiniband/ obj-$(CONFIG_SGI_IOC4) += sn/ obj-y += firmware/ obj-$(CONFIG_CRYPTO) += crypto/ +obj-$(CONFIG_SUPERH) += sh/ diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 10dd695a1dd93e06d43497b5b4c49ce8680a7cac..27ec12c1fab084c2ea1bba43c24be5e00c636e71 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -118,11 +118,9 @@ static int acpi_container_remove(struct acpi_device *device, int type) { acpi_status status = AE_OK; struct acpi_container *pc = NULL; - pc = (struct acpi_container *)acpi_driver_data(device); - - if (pc) - kfree(pc); + pc = (struct acpi_container *)acpi_driver_data(device); + kfree(pc); return status; } diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index d528c750a3801bd65591639baec49d3f64a381fe..e3cd0b16031ad32c70ee1b47516c23b02856cbcb 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -313,8 +313,7 @@ acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler) void acpi_os_sleep(acpi_integer ms) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(((signed long)ms * HZ) / 1000); + schedule_timeout_interruptible(msecs_to_jiffies(ms)); } EXPORT_SYMBOL(acpi_os_sleep); @@ -838,8 +837,7 @@ acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout) ret = down_trylock(sem); for (i = timeout; (i > 0 && ret < 0); i -= quantum_ms) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); + schedule_timeout_interruptible(1); ret = down_trylock(sem); } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index c6db591479de3e02504d40ac8e0cee2d2bebdeab..23e2c6968a1164f9f54aa6f9a5493c619965019a 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -28,8 +28,7 @@ static int acpi_bus_trim(struct acpi_device *start, int rmdevice); static void acpi_device_release(struct kobject *kobj) { struct acpi_device *dev = container_of(kobj, struct acpi_device, kobj); - if (dev->pnp.cid_list) - kfree(dev->pnp.cid_list); + kfree(dev->pnp.cid_list); kfree(dev); } @@ -1117,8 +1116,7 @@ acpi_add_single_object(struct acpi_device **child, if (!result) *child = device; else { - if (device->pnp.cid_list) - kfree(device->pnp.cid_list); + kfree(device->pnp.cid_list); kfree(device); } diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index e383d6109ae109c6963d43abe7ca71449e554518..f051b151580d7de14647213f6c4497a75a4eff57 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -334,8 +334,7 @@ acpi_video_device_lcd_query_levels(struct acpi_video_device *device, return_VALUE(0); err: - if (buffer.pointer) - kfree(buffer.pointer); + kfree(buffer.pointer); return_VALUE(status); } @@ -1488,8 +1487,7 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video) } active_device_list[count].value.int_val = ACPI_VIDEO_HEAD_END; - if (video->attached_array) - kfree(video->attached_array); + kfree(video->attached_array); video->attached_array = active_device_list; video->attached_count = count; @@ -1645,8 +1643,7 @@ static int acpi_video_bus_put_devices(struct acpi_video_bus *video) printk(KERN_WARNING PREFIX "hhuuhhuu bug in acpi video driver.\n"); - if (data->brightness) - kfree(data->brightness); + kfree(data->brightness); kfree(data); } @@ -1831,8 +1828,7 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type) acpi_video_bus_put_devices(video); acpi_video_bus_remove_fs(device); - if (video->attached_array) - kfree(video->attached_array); + kfree(video->attached_array); kfree(video); return_VALUE(0); diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index 89c57875f3e53c25f666cbb943933cb518396adb..f3a0c562bcb53ff019aa8db27cfd40860a1a6335 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -3,6 +3,7 @@ */ #include +#include #include "power.h" diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 3760edfdc65cc54f9cb6525eb2d26ebd0833b1e4..70eaa5c7ac088c7db5ed6c8363bf8b5e1f75f881 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -417,14 +417,12 @@ static void DAC960_DestroyAuxiliaryStructures(DAC960_Controller_T *Controller) * Remember the beginning of the group, but don't free it * until we've reached the beginning of the next group. */ - if (CommandGroup != NULL) - kfree(CommandGroup); - CommandGroup = Command; + kfree(CommandGroup); + CommandGroup = Command; } Controller->Commands[i] = NULL; } - if (CommandGroup != NULL) - kfree(CommandGroup); + kfree(CommandGroup); if (Controller->CombinedStatusBuffer != NULL) { @@ -435,30 +433,23 @@ static void DAC960_DestroyAuxiliaryStructures(DAC960_Controller_T *Controller) if (ScatterGatherPool != NULL) pci_pool_destroy(ScatterGatherPool); - if (Controller->FirmwareType == DAC960_V1_Controller) return; + if (Controller->FirmwareType == DAC960_V1_Controller) + return; if (RequestSensePool != NULL) pci_pool_destroy(RequestSensePool); - for (i = 0; i < DAC960_MaxLogicalDrives; i++) - if (Controller->V2.LogicalDeviceInformation[i] != NULL) - { + for (i = 0; i < DAC960_MaxLogicalDrives; i++) { kfree(Controller->V2.LogicalDeviceInformation[i]); Controller->V2.LogicalDeviceInformation[i] = NULL; - } + } for (i = 0; i < DAC960_V2_MaxPhysicalDevices; i++) { - if (Controller->V2.PhysicalDeviceInformation[i] != NULL) - { - kfree(Controller->V2.PhysicalDeviceInformation[i]); - Controller->V2.PhysicalDeviceInformation[i] = NULL; - } - if (Controller->V2.InquiryUnitSerialNumber[i] != NULL) - { - kfree(Controller->V2.InquiryUnitSerialNumber[i]); - Controller->V2.InquiryUnitSerialNumber[i] = NULL; - } + kfree(Controller->V2.PhysicalDeviceInformation[i]); + Controller->V2.PhysicalDeviceInformation[i] = NULL; + kfree(Controller->V2.InquiryUnitSerialNumber[i]); + Controller->V2.InquiryUnitSerialNumber[i] = NULL; } } diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 51b0af1cebee15f0406ceaf4517538bb9a39edb3..7b1cd93892be4e271d5f94ef60982607020efa76 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -409,16 +409,6 @@ config BLK_DEV_INITRD for details. -#XXX - it makes sense to enable this only for 32-bit subarch's, not for x86_64 -#for instance. -config LBD - bool "Support for Large Block Devices" - depends on X86 || (MIPS && 32BIT) || PPC32 || ARCH_S390_31 || SUPERH || UML - help - Say Y here if you want to attach large (bigger than 2TB) discs to - your machine, or if you want to have a raid or loopback device - bigger than 2TB. Otherwise say N. - config CDROM_PKTCDVD tristate "Packet writing on CD/DVD media" depends on !UML @@ -455,8 +445,6 @@ config CDROM_PKTCDVD_WCACHE source "drivers/s390/block/Kconfig" -source "drivers/block/Kconfig.iosched" - config ATA_OVER_ETH tristate "ATA over Ethernet support" depends on NET diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 1cf09a1c065be0e3dc29df117a2f73693c4c202c..3ec1f8df87b16d92cbbd4b0ab01fe065a4c3731a 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -4,21 +4,7 @@ # 12 June 2000, Christoph Hellwig # Rewritten to use lists instead of if-statements. # -# Note : at this point, these files are compiled on all systems. -# In the future, some of these should be built conditionally. -# - -# -# NOTE that ll_rw_blk.c must come early in linkage order - it starts the -# kblockd threads -# - -obj-y := elevator.o ll_rw_blk.o ioctl.o genhd.o scsi_ioctl.o -obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o -obj-$(CONFIG_IOSCHED_AS) += as-iosched.o -obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o -obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o obj-$(CONFIG_MAC_FLOPPY) += swim3.o obj-$(CONFIG_BLK_DEV_FD) += floppy.o obj-$(CONFIG_BLK_DEV_FD98) += floppy98.o diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 486b6e1c7dfb96aaa1a8e98e06169d7ce7164f27..a97c80b57737528b3e5cf6b1da2f351584dc14ca 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1096,14 +1096,11 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, cleanup1: if (buff) { for(i=0; icmd_pool_bits) - kfree(hba[i]->cmd_pool_bits); + kfree(hba[i]->cmd_pool_bits); if(hba[i]->cmd_pool) pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct), diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index e425ad3eebba80618be8c56f6282f9ed99bad740..af7cb2bfd67051d02b568fed8b24e3aea3e8e44b 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -176,6 +177,7 @@ struct swim3 { struct floppy_state { enum swim_state state; + spinlock_t lock; struct swim3 __iomem *swim3; /* hardware registers */ struct dbdma_regs __iomem *dma; /* DMA controller registers */ int swim3_intr; /* interrupt number for SWIM3 */ @@ -304,7 +306,6 @@ static void do_fd_request(request_queue_t * q) #endif /* CONFIG_PMAC_MEDIABAY */ start_request(&floppy_states[i]); } - sti(); } static void start_request(struct floppy_state *fs) @@ -370,7 +371,7 @@ static void set_timeout(struct floppy_state *fs, int nticks, { unsigned long flags; - save_flags(flags); cli(); + spin_lock_irqsave(&fs->lock, flags); if (fs->timeout_pending) del_timer(&fs->timeout); fs->timeout.expires = jiffies + nticks; @@ -378,7 +379,7 @@ static void set_timeout(struct floppy_state *fs, int nticks, fs->timeout.data = (unsigned long) fs; add_timer(&fs->timeout); fs->timeout_pending = 1; - restore_flags(flags); + spin_unlock_irqrestore(&fs->lock, flags); } static inline void scan_track(struct floppy_state *fs) @@ -790,14 +791,13 @@ static int grab_drive(struct floppy_state *fs, enum swim_state state, { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&fs->lock, flags); if (fs->state != idle) { ++fs->wanted; while (fs->state != available) { if (interruptible && signal_pending(current)) { --fs->wanted; - restore_flags(flags); + spin_unlock_irqrestore(&fs->lock, flags); return -EINTR; } interruptible_sleep_on(&fs->wait); @@ -805,7 +805,7 @@ static int grab_drive(struct floppy_state *fs, enum swim_state state, --fs->wanted; } fs->state = state; - restore_flags(flags); + spin_unlock_irqrestore(&fs->lock, flags); return 0; } @@ -813,11 +813,10 @@ static void release_drive(struct floppy_state *fs) { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&fs->lock, flags); fs->state = idle; start_request(fs); - restore_flags(flags); + spin_unlock_irqrestore(&fs->lock, flags); } static int fd_eject(struct floppy_state *fs) @@ -1109,6 +1108,7 @@ static int swim3_add_device(struct device_node *swim) pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 1); memset(fs, 0, sizeof(*fs)); + spin_lock_init(&fs->lock); fs->state = idle; fs->swim3 = (struct swim3 __iomem *) ioremap(swim->addrs[0].address, 0x200); diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c index 5fd3e4cb7525a94e376d03a10a6cf18768d5ef5d..8e7fb355177528fe544d32a990d5d7849ed85fda 100644 --- a/drivers/bluetooth/bcm203x.c +++ b/drivers/bluetooth/bcm203x.c @@ -179,14 +179,12 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id if (ignore || (intf->cur_altsetting->desc.bInterfaceNumber != 0)) return -ENODEV; - data = kmalloc(sizeof(*data), GFP_KERNEL); + data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) { BT_ERR("Can't allocate memory for data structure"); return -ENOMEM; } - memset(data, 0, sizeof(*data)); - data->udev = udev; data->state = BCM203X_LOAD_MINIDRV; diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c index 1e9db0156ea7d5e574f62cf08283fd5bd19f45f3..067e27893e4a8e4d5b1cbcc1692edd26d0034228 100644 --- a/drivers/bluetooth/bfusb.c +++ b/drivers/bluetooth/bfusb.c @@ -673,13 +673,11 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i } /* Initialize control structure and load firmware */ - if (!(bfusb = kmalloc(sizeof(struct bfusb), GFP_KERNEL))) { + if (!(bfusb = kzalloc(sizeof(struct bfusb), GFP_KERNEL))) { BT_ERR("Can't allocate memory for control structure"); goto done; } - memset(bfusb, 0, sizeof(struct bfusb)); - bfusb->udev = udev; bfusb->bulk_in_ep = bulk_in_ep->desc.bEndpointAddress; bfusb->bulk_out_ep = bulk_out_ep->desc.bEndpointAddress; diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 26fe9c0e1d20e4c1ef51c47428cf5672ae5db56c..f36c563d72c4f49f8334ee8e6a9ee3c8793f51a9 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -870,10 +870,9 @@ static dev_link_t *bluecard_attach(void) int ret; /* Create new info device */ - info = kmalloc(sizeof(*info), GFP_KERNEL); + info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return NULL; - memset(info, 0, sizeof(*info)); link = &info->link; link->priv = info; diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c index 0db0400519c95ee5f32bd576f371580ae8c6f463..394796315adcb18decd1ca61d13b62e1aae4ffe6 100644 --- a/drivers/bluetooth/bpa10x.c +++ b/drivers/bluetooth/bpa10x.c @@ -84,8 +84,8 @@ struct bpa10x_data { struct hci_vendor_hdr { __u8 type; - __u16 snum; - __u16 dlen; + __le16 snum; + __le16 dlen; } __attribute__ ((packed)); static void bpa10x_recv_bulk(struct bpa10x_data *data, unsigned char *buf, int count) @@ -553,14 +553,12 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id * if (intf->cur_altsetting->desc.bInterfaceNumber > 0) return -ENODEV; - data = kmalloc(sizeof(*data), GFP_KERNEL); + data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) { BT_ERR("Can't allocate data structure"); return -ENOMEM; } - memset(data, 0, sizeof(*data)); - data->udev = udev; rwlock_init(&data->lock); diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 2e0338d80f32c1db8ba8e2f1a4e524e08298aeb6..d2a0add19cc88a52ddcd703495fdcf0584b00022 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -671,10 +671,9 @@ static dev_link_t *bt3c_attach(void) int ret; /* Create new info device */ - info = kmalloc(sizeof(*info), GFP_KERNEL); + info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return NULL; - memset(info, 0, sizeof(*info)); link = &info->link; link->priv = info; diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index 89486ea7a0216db3712b3182fddde49824920d15..529a28a3209d1999961b12b02b6eba8ea80b7b63 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -590,10 +590,9 @@ static dev_link_t *btuart_attach(void) int ret; /* Create new info device */ - info = kmalloc(sizeof(*info), GFP_KERNEL); + info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return NULL; - memset(info, 0, sizeof(*info)); link = &info->link; link->priv = info; diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 84c1f88394225504ff7c2e02f77a8f043db85960..dec5980a1cd6811f79906b278ed09c0cf9d70c44 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -569,10 +569,9 @@ static dev_link_t *dtl1_attach(void) int ret; /* Create new info device */ - info = kmalloc(sizeof(*info), GFP_KERNEL); + info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return NULL; - memset(info, 0, sizeof(*info)); link = &info->link; link->priv = info; diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 0a4761415ac39be6cedd01b0d77c4cb570bd2495..8fddfdfd0fbdcca1c779cc12736051f8c9439c6c 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -715,10 +715,9 @@ static int bcsp_open(struct hci_uart *hu) BT_DBG("hu %p", hu); - bcsp = kmalloc(sizeof(*bcsp), GFP_ATOMIC); + bcsp = kzalloc(sizeof(*bcsp), GFP_ATOMIC); if (!bcsp) return -ENOMEM; - memset(bcsp, 0, sizeof(*bcsp)); hu->priv = bcsp; skb_queue_head_init(&bcsp->unack); diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index 12e369a66fc24be1e2dba29cae82a679576ca32d..4804d474dc8735d4a2365258385551134134c616 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -76,12 +76,10 @@ static int h4_open(struct hci_uart *hu) BT_DBG("hu %p", hu); - h4 = kmalloc(sizeof(*h4), GFP_ATOMIC); + h4 = kzalloc(sizeof(*h4), GFP_ATOMIC); if (!h4) return -ENOMEM; - memset(h4, 0, sizeof(*h4)); - skb_queue_head_init(&h4->txq); hu->priv = h4; diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 4a775f6ea3907134fe8f0fa64b69086bc515e31a..573ff6c1be5f6080362407f17f0785729317025c 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -272,13 +272,11 @@ static int hci_uart_tty_open(struct tty_struct *tty) if (hu) return -EEXIST; - if (!(hu = kmalloc(sizeof(struct hci_uart), GFP_KERNEL))) { + if (!(hu = kzalloc(sizeof(struct hci_uart), GFP_KERNEL))) { BT_ERR("Can't allocate controll structure"); return -ENFILE; } - memset(hu, 0, sizeof(struct hci_uart)); - tty->disc_data = hu; hu->tty = tty; diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c index 6756cb20b753875e7a22cc3c7f047d2e134b9ea6..057cb2b6e6d1f537723051c122eca2d59fec0c82 100644 --- a/drivers/bluetooth/hci_usb.c +++ b/drivers/bluetooth/hci_usb.c @@ -65,6 +65,7 @@ #endif static int ignore = 0; +static int ignore_dga = 0; static int ignore_csr = 0; static int ignore_sniffer = 0; static int reset = 0; @@ -841,6 +842,9 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id if (ignore || id->driver_info & HCI_IGNORE) return -ENODEV; + if (ignore_dga && id->driver_info & HCI_DIGIANSWER) + return -ENODEV; + if (ignore_csr && id->driver_info & HCI_CSR) return -ENODEV; @@ -875,13 +879,11 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id goto done; } - if (!(husb = kmalloc(sizeof(struct hci_usb), GFP_KERNEL))) { + if (!(husb = kzalloc(sizeof(struct hci_usb), GFP_KERNEL))) { BT_ERR("Can't allocate: control structure"); goto done; } - memset(husb, 0, sizeof(struct hci_usb)); - husb->udev = udev; husb->bulk_out_ep = bulk_out_ep; husb->bulk_in_ep = bulk_in_ep; @@ -1072,6 +1074,9 @@ module_exit(hci_usb_exit); module_param(ignore, bool, 0644); MODULE_PARM_DESC(ignore, "Ignore devices from the matching table"); +module_param(ignore_dga, bool, 0644); +MODULE_PARM_DESC(ignore_dga, "Ignore devices with id 08fd:0001"); + module_param(ignore_csr, bool, 0644); MODULE_PARM_DESC(ignore_csr, "Ignore devices with id 0a12:0001"); diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 52cbd45c308fa0189d9d0a6ef044ebc49651a379..85738223ff0c47648c50b5985652baa0e1387e87 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -261,12 +261,10 @@ static int vhci_open(struct inode *inode, struct file *file) struct vhci_data *vhci; struct hci_dev *hdev; - vhci = kmalloc(sizeof(struct vhci_data), GFP_KERNEL); + vhci = kzalloc(sizeof(struct vhci_data), GFP_KERNEL); if (!vhci) return -ENOMEM; - memset(vhci, 0, sizeof(struct vhci_data)); - skb_queue_head_init(&vhci->readq); init_waitqueue_head(&vhci->read_wait); diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c index b89420e6d7047ce41e7c252363e07e8b4de43904..a0b580c22d80942dbd75536609076f219edce33b 100644 --- a/drivers/cdrom/mcdx.c +++ b/drivers/cdrom/mcdx.c @@ -1085,7 +1085,7 @@ static int __init mcdx_init_drive(int drive) xtrace(INIT, "kmalloc space for stuffpt's\n"); xtrace(MALLOC, "init() malloc %d bytes\n", size); - if (!(stuffp = kmalloc(size, GFP_KERNEL))) { + if (!(stuffp = kzalloc(size, GFP_KERNEL))) { xwarn("init() malloc failed\n"); return 1; } @@ -1101,8 +1101,6 @@ static int __init mcdx_init_drive(int drive) sizeof(*stuffp), stuffp); /* set default values */ - memset(stuffp, 0, sizeof(*stuffp)); - stuffp->present = 0; /* this should be 0 already */ stuffp->toc = NULL; /* this should be NULL already */ diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index b02fc2267159675c32e8e6a58c27ab8173a9161f..ba54b58725781e4678a41409318c0e45ff72b7ad 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c @@ -389,6 +389,7 @@ static struct pci_device_id agp_ali_pci_table[] = { MODULE_DEVICE_TABLE(pci, agp_ali_pci_table); static struct pci_driver agp_ali_pci_driver = { + .owner = THIS_MODULE, .name = "agpgart-ali", .id_table = agp_ali_pci_table, .probe = agp_ali_probe, diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index 3a41672e4d6682112f19a19ee8ceae2752984be0..40fcd88b2ceac6dbd759300b930bb8f62153d520 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -94,19 +94,16 @@ static int amd_create_gatt_pages(int nr_tables) int retval = 0; int i; - tables = kmalloc((nr_tables + 1) * sizeof(struct amd_page_map *), - GFP_KERNEL); + tables = kzalloc((nr_tables + 1) * sizeof(struct amd_page_map *),GFP_KERNEL); if (tables == NULL) return -ENOMEM; - memset (tables, 0, sizeof(struct amd_page_map *) * (nr_tables + 1)); for (i = 0; i < nr_tables; i++) { - entry = kmalloc(sizeof(struct amd_page_map), GFP_KERNEL); + entry = kzalloc(sizeof(struct amd_page_map), GFP_KERNEL); if (entry == NULL) { retval = -ENOMEM; break; } - memset (entry, 0, sizeof(struct amd_page_map)); tables[i] = entry; retval = amd_create_page_map(entry); if (retval != 0) @@ -518,6 +515,7 @@ static struct pci_device_id agp_amdk7_pci_table[] = { MODULE_DEVICE_TABLE(pci, agp_amdk7_pci_table); static struct pci_driver agp_amdk7_pci_driver = { + .owner = THIS_MODULE, .name = "agpgart-amdk7", .id_table = agp_amdk7_pci_table, .probe = agp_amdk7_probe, diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 0e6c3a31d3448a820f4f8a95d8f43d6d6d2a9915..8f748fddca9456d9cdb591d63d67aea049dc3e27 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -13,6 +13,7 @@ #include #include #include +#include #include /* PAGE_SIZE */ #include "agp.h" @@ -702,6 +703,7 @@ static struct pci_device_id agp_amd64_pci_table[] = { MODULE_DEVICE_TABLE(pci, agp_amd64_pci_table); static struct pci_driver agp_amd64_pci_driver = { + .owner = THIS_MODULE, .name = "agpgart-amd64", .id_table = agp_amd64_pci_table, .probe = agp_amd64_probe, diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index 0b6e72642d6e5a0126038d5cd553f39fd87d4d0c..fbd415565463426bf299188b47d5b482f6d4d47f 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -118,14 +118,12 @@ static int ati_create_gatt_pages(int nr_tables) int retval = 0; int i; - tables = kmalloc((nr_tables + 1) * sizeof(ati_page_map *), - GFP_KERNEL); + tables = kzalloc((nr_tables + 1) * sizeof(ati_page_map *),GFP_KERNEL); if (tables == NULL) return -ENOMEM; - memset(tables, 0, sizeof(ati_page_map *) * (nr_tables + 1)); for (i = 0; i < nr_tables; i++) { - entry = kmalloc(sizeof(ati_page_map), GFP_KERNEL); + entry = kzalloc(sizeof(ati_page_map), GFP_KERNEL); if (entry == NULL) { while (i>0) { kfree (tables[i-1]); @@ -136,7 +134,6 @@ static int ati_create_gatt_pages(int nr_tables) retval = -ENOMEM; break; } - memset(entry, 0, sizeof(ati_page_map)); tables[i] = entry; retval = ati_create_page_map(entry); if (retval != 0) break; @@ -524,6 +521,7 @@ static struct pci_device_id agp_ati_pci_table[] = { MODULE_DEVICE_TABLE(pci, agp_ati_pci_table); static struct pci_driver agp_ati_pci_driver = { + .owner = THIS_MODULE, .name = "agpgart-ati", .id_table = agp_ati_pci_table, .probe = agp_ati_probe, diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index 82b43c541c8dca52ad90c0ea6c6b984a50c455ee..73f333f491bde21a3cd14656e15c8d7d740450b5 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c @@ -222,12 +222,12 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge) struct agp_bridge_data *agp_alloc_bridge(void) { - struct agp_bridge_data *bridge = kmalloc(sizeof(*bridge), GFP_KERNEL); - + struct agp_bridge_data *bridge; + + bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); if (!bridge) return NULL; - memset(bridge, 0, sizeof(*bridge)); atomic_set(&bridge->agp_in_use, 0); atomic_set(&bridge->current_memory_agp, 0); diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c index ac19fdcd21c1c7583246256edba92157b42d278e..d41e0a62e32efe77017abf86570d2f4147b75e7b 100644 --- a/drivers/char/agp/efficeon-agp.c +++ b/drivers/char/agp/efficeon-agp.c @@ -219,7 +219,7 @@ static int efficeon_create_gatt_table(struct agp_bridge_data *bridge) efficeon_private.l1_table[index] = page; - value = virt_to_gart(page) | pati | present | index; + value = virt_to_gart((unsigned long *)page) | pati | present | index; pci_write_config_dword(agp_bridge->dev, EFFICEON_ATTPAGE, value); @@ -429,6 +429,7 @@ static struct pci_device_id agp_efficeon_pci_table[] = { MODULE_DEVICE_TABLE(pci, agp_efficeon_pci_table); static struct pci_driver agp_efficeon_pci_driver = { + .owner = THIS_MODULE, .name = "agpgart-efficeon", .id_table = agp_efficeon_pci_table, .probe = agp_efficeon_probe, diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c index 3dfb6648547bb8d3e854abd31f492f554e8bc2ee..17f520c9d4714aa90a145f200c31675b38699882 100644 --- a/drivers/char/agp/frontend.c +++ b/drivers/char/agp/frontend.c @@ -189,13 +189,12 @@ static int agp_create_segment(struct agp_client *client, struct agp_region *regi struct agp_segment *user_seg; size_t i; - seg = kmalloc((sizeof(struct agp_segment_priv) * region->seg_count), GFP_KERNEL); + seg = kzalloc((sizeof(struct agp_segment_priv) * region->seg_count), GFP_KERNEL); if (seg == NULL) { kfree(region->seg_list); region->seg_list = NULL; return -ENOMEM; } - memset(seg, 0, (sizeof(struct agp_segment_priv) * region->seg_count)); user_seg = region->seg_list; for (i = 0; i < region->seg_count; i++) { @@ -332,14 +331,11 @@ static struct agp_controller *agp_create_controller(pid_t id) { struct agp_controller *controller; - controller = kmalloc(sizeof(struct agp_controller), GFP_KERNEL); - + controller = kzalloc(sizeof(struct agp_controller), GFP_KERNEL); if (controller == NULL) return NULL; - memset(controller, 0, sizeof(struct agp_controller)); controller->pid = id; - return controller; } @@ -540,12 +536,10 @@ static struct agp_client *agp_create_client(pid_t id) { struct agp_client *new_client; - new_client = kmalloc(sizeof(struct agp_client), GFP_KERNEL); - + new_client = kzalloc(sizeof(struct agp_client), GFP_KERNEL); if (new_client == NULL) return NULL; - memset(new_client, 0, sizeof(struct agp_client)); new_client->pid = id; agp_insert_client(new_client); return new_client; @@ -709,11 +703,10 @@ static int agp_open(struct inode *inode, struct file *file) if (minor != AGPGART_MINOR) goto err_out; - priv = kmalloc(sizeof(struct agp_file_private), GFP_KERNEL); + priv = kzalloc(sizeof(struct agp_file_private), GFP_KERNEL); if (priv == NULL) goto err_out_nomem; - memset(priv, 0, sizeof(struct agp_file_private)); set_bit(AGP_FF_ALLOW_CLIENT, &priv->access_flags); priv->my_pid = current->pid; diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index ac9da0ca36b7b1425a679ab74f3277e008ba661b..c4a38715c6f9751c3127497e2592b5717f1a2f32 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -105,12 +105,10 @@ struct agp_memory *agp_create_memory(int scratch_pages) { struct agp_memory *new; - new = kmalloc(sizeof(struct agp_memory), GFP_KERNEL); - + new = kzalloc(sizeof(struct agp_memory), GFP_KERNEL); if (new == NULL) return NULL; - memset(new, 0, sizeof(struct agp_memory)); new->key = agp_get_key(); if (new->key < 0) { @@ -414,7 +412,8 @@ static void agp_v2_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_ u32 tmp; if (*requested_mode & AGP2_RESERVED_MASK) { - printk(KERN_INFO PFX "reserved bits set in mode 0x%x. Fixed.\n", *requested_mode); + printk(KERN_INFO PFX "reserved bits set (%x) in mode 0x%x. Fixed.\n", + *requested_mode & AGP2_RESERVED_MASK, *requested_mode); *requested_mode &= ~AGP2_RESERVED_MASK; } @@ -492,7 +491,8 @@ static void agp_v3_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_ u32 tmp; if (*requested_mode & AGP3_RESERVED_MASK) { - printk(KERN_INFO PFX "reserved bits set in mode 0x%x. Fixed.\n", *requested_mode); + printk(KERN_INFO PFX "reserved bits set (%x) in mode 0x%x. Fixed.\n", + *requested_mode & AGP3_RESERVED_MASK, *requested_mode); *requested_mode &= ~AGP3_RESERVED_MASK; } diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c index a2d9e5e48bbeeff576bb7f0ac953b837017695b3..58944cd271ead9c55120a43ffa014bd5f34ac9cf 100644 --- a/drivers/char/agp/i460-agp.c +++ b/drivers/char/agp/i460-agp.c @@ -227,10 +227,9 @@ static int i460_configure (void) */ if (I460_IO_PAGE_SHIFT > PAGE_SHIFT) { size = current_size->num_entries * sizeof(i460.lp_desc[0]); - i460.lp_desc = kmalloc(size, GFP_KERNEL); + i460.lp_desc = kzalloc(size, GFP_KERNEL); if (!i460.lp_desc) return -ENOMEM; - memset(i460.lp_desc, 0, size); } return 0; } @@ -366,13 +365,12 @@ static int i460_alloc_large_page (struct lp_desc *lp) } map_size = ((I460_KPAGES_PER_IOPAGE + BITS_PER_LONG - 1) & -BITS_PER_LONG)/8; - lp->alloced_map = kmalloc(map_size, GFP_KERNEL); + lp->alloced_map = kzalloc(map_size, GFP_KERNEL); if (!lp->alloced_map) { free_pages((unsigned long) lpage, order); printk(KERN_ERR PFX "Out of memory, we're in trouble...\n"); return -ENOMEM; } - memset(lp->alloced_map, 0, map_size); lp->paddr = virt_to_gart(lpage); lp->refcount = 0; @@ -619,6 +617,7 @@ static struct pci_device_id agp_intel_i460_pci_table[] = { MODULE_DEVICE_TABLE(pci, agp_intel_i460_pci_table); static struct pci_driver agp_intel_i460_pci_driver = { + .owner = THIS_MODULE, .name = "agpgart-intel-i460", .id_table = agp_intel_i460_pci_table, .probe = agp_intel_i460_probe, diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 1f7d415f432ca4f94a7b9f6dc0b3f531df3fa52d..bf4cc9ffd5b1dd737f0921b8319f3efeabdc2b77 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -1824,6 +1824,7 @@ static struct pci_device_id agp_intel_pci_table[] = { MODULE_DEVICE_TABLE(pci, agp_intel_pci_table); static struct pci_driver agp_intel_pci_driver = { + .owner = THIS_MODULE, .name = "agpgart-intel", .id_table = agp_intel_pci_table, .probe = agp_intel_probe, diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index 80dafa3030bd5433a9e128dc62820ea6cc95f180..3aed0c5e2f9256ebadcf6670caa91d8b393d6842 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c @@ -398,6 +398,7 @@ static struct pci_device_id agp_nvidia_pci_table[] = { MODULE_DEVICE_TABLE(pci, agp_nvidia_pci_table); static struct pci_driver agp_nvidia_pci_driver = { + .owner = THIS_MODULE, .name = "agpgart-nvidia", .id_table = agp_nvidia_pci_table, .probe = agp_nvidia_probe, diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c index 7957fc91f6ada9faad5df39d4381e52e90267ce4..4df7734b51c2b37824715038e5e0f9eb1c38fa00 100644 --- a/drivers/char/agp/sgi-agp.c +++ b/drivers/char/agp/sgi-agp.c @@ -289,6 +289,8 @@ static int __devinit agp_sgi_init(void) j = 0; list_for_each_entry(info, &tioca_list, ca_list) { struct list_head *tmp; + if (list_empty(info->ca_devices)) + continue; list_for_each(tmp, info->ca_devices) { u8 cap_ptr; pdev = pci_dev_b(tmp); diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c index ebc05554045c73b16f099d81aad774ad3b478fb6..a701361a889084b20278a4c55aa0676516778143 100644 --- a/drivers/char/agp/sis-agp.c +++ b/drivers/char/agp/sis-agp.c @@ -332,6 +332,7 @@ static struct pci_device_id agp_sis_pci_table[] = { MODULE_DEVICE_TABLE(pci, agp_sis_pci_table); static struct pci_driver agp_sis_pci_driver = { + .owner = THIS_MODULE, .name = "agpgart-sis", .id_table = agp_sis_pci_table, .probe = agp_sis_probe, diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c index 71ea59a1dbebf982fecbd86cc06fa516d2bcd152..5a5392dd1254765de3b7345e317bbe9dac5878a4 100644 --- a/drivers/char/agp/sworks-agp.c +++ b/drivers/char/agp/sworks-agp.c @@ -102,19 +102,17 @@ static int serverworks_create_gatt_pages(int nr_tables) int retval = 0; int i; - tables = kmalloc((nr_tables + 1) * sizeof(struct serverworks_page_map *), + tables = kzalloc((nr_tables + 1) * sizeof(struct serverworks_page_map *), GFP_KERNEL); - if (tables == NULL) { + if (tables == NULL) return -ENOMEM; - } - memset(tables, 0, sizeof(struct serverworks_page_map *) * (nr_tables + 1)); + for (i = 0; i < nr_tables; i++) { - entry = kmalloc(sizeof(struct serverworks_page_map), GFP_KERNEL); + entry = kzalloc(sizeof(struct serverworks_page_map), GFP_KERNEL); if (entry == NULL) { retval = -ENOMEM; break; } - memset(entry, 0, sizeof(struct serverworks_page_map)); tables[i] = entry; retval = serverworks_create_page_map(entry); if (retval != 0) break; @@ -244,13 +242,27 @@ static int serverworks_fetch_size(void) */ static void serverworks_tlbflush(struct agp_memory *temp) { + unsigned long timeout; + writeb(1, serverworks_private.registers+SVWRKS_POSTFLUSH); - while (readb(serverworks_private.registers+SVWRKS_POSTFLUSH) == 1) + timeout = jiffies + 3*HZ; + while (readb(serverworks_private.registers+SVWRKS_POSTFLUSH) == 1) { cpu_relax(); + if (time_after(jiffies, timeout)) { + printk(KERN_ERR PFX "TLB post flush took more than 3 seconds\n"); + break; + } + } writel(1, serverworks_private.registers+SVWRKS_DIRFLUSH); - while(readl(serverworks_private.registers+SVWRKS_DIRFLUSH) == 1) + timeout = jiffies + 3*HZ; + while (readl(serverworks_private.registers+SVWRKS_DIRFLUSH) == 1) { cpu_relax(); + if (time_after(jiffies, timeout)) { + printk(KERN_ERR PFX "TLB Dir flush took more than 3 seconds\n"); + break; + } + } } static int serverworks_configure(void) @@ -533,6 +545,7 @@ static struct pci_device_id agp_serverworks_pci_table[] = { MODULE_DEVICE_TABLE(pci, agp_serverworks_pci_table); static struct pci_driver agp_serverworks_pci_driver = { + .owner = THIS_MODULE, .name = "agpgart-serverworks", .id_table = agp_serverworks_pci_table, .probe = agp_serverworks_probe, diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index c8255312b8c1f3728fb608928ebf554913cff4d2..183c50acab279860a9a3b399c3de277b9df60f49 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c @@ -658,6 +658,7 @@ static struct pci_device_id agp_uninorth_pci_table[] = { MODULE_DEVICE_TABLE(pci, agp_uninorth_pci_table); static struct pci_driver agp_uninorth_pci_driver = { + .owner = THIS_MODULE, .name = "agpgart-uninorth", .id_table = agp_uninorth_pci_table, .probe = agp_uninorth_probe, diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c index c847df575cf5b96437b73dfb64311122a16326bf..5d9a13700074401ddf98e14b52ab249e69ab3d2c 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c @@ -518,6 +518,7 @@ MODULE_DEVICE_TABLE(pci, agp_via_pci_table); static struct pci_driver agp_via_pci_driver = { + .owner = THIS_MODULE, .name = "agpgart-via", .id_table = agp_via_pci_table, .probe = agp_via_probe, diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c index 406dea914635f166a529ddb7529bb01f805f19ce..c85a4fa60da7e235b207a6ba84d305928ec1e142 100644 --- a/drivers/char/consolemap.c +++ b/drivers/char/consolemap.c @@ -345,17 +345,15 @@ static void con_release_unimap(struct uni_pagedir *p) for (i = 0; i < 32; i++) { if ((p1 = p->uni_pgdir[i]) != NULL) { for (j = 0; j < 32; j++) - if (p1[j]) - kfree(p1[j]); + kfree(p1[j]); kfree(p1); } p->uni_pgdir[i] = NULL; } - for (i = 0; i < 4; i++) - if (p->inverse_translations[i]) { - kfree(p->inverse_translations[i]); - p->inverse_translations[i] = NULL; - } + for (i = 0; i < 4; i++) { + kfree(p->inverse_translations[i]); + p->inverse_translations[i] = NULL; + } } void con_free_unimap(struct vc_data *vc) diff --git a/drivers/char/drm/ffb_context.c b/drivers/char/drm/ffb_context.c index 8a6cc2751bc9253a2f2b779177972081e0c23cfe..1383727b443ad98fb28795b1f71c7ecd02ff0d46 100644 --- a/drivers/char/drm/ffb_context.c +++ b/drivers/char/drm/ffb_context.c @@ -526,10 +526,8 @@ int ffb_driver_rmctx(struct inode *inode, struct file *filp, unsigned int cmd, if (idx < 0 || idx >= FFB_MAX_CTXS) return -EINVAL; - if (fpriv->hw_state[idx] != NULL) { - kfree(fpriv->hw_state[idx]); - fpriv->hw_state[idx] = NULL; - } + kfree(fpriv->hw_state[idx]); + fpriv->hw_state[idx] = NULL; return 0; } diff --git a/drivers/char/drm/ffb_drv.c b/drivers/char/drm/ffb_drv.c index 5c121d6df9f2d4139d4ae76a7451bd6e826da216..c13f9abb41e9b2f3ad88a8303e525ebf874b35d5 100644 --- a/drivers/char/drm/ffb_drv.c +++ b/drivers/char/drm/ffb_drv.c @@ -245,14 +245,12 @@ static void ffb_driver_release(drm_device_t * dev, struct file *filp) static void ffb_driver_pretakedown(drm_device_t * dev) { - if (dev->dev_private) - kfree(dev->dev_private); + kfree(dev->dev_private); } static int ffb_driver_postcleanup(drm_device_t * dev) { - if (ffb_position != NULL) - kfree(ffb_position); + kfree(ffb_position); return 0; } diff --git a/drivers/char/ip2/i2ellis.c b/drivers/char/ip2/i2ellis.c index f834d05ccc976bb90828047c29fd1af28350e7fa..dd761a1e4f084709bd1e5c3dfac6ccbab5878826 100644 --- a/drivers/char/ip2/i2ellis.c +++ b/drivers/char/ip2/i2ellis.c @@ -106,9 +106,7 @@ iiEllisInit(void) static void iiEllisCleanup(void) { - if ( pDelayTimer != NULL ) { - kfree ( pDelayTimer ); - } + kfree(pDelayTimer); } //****************************************************************************** diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index 33862670e285542fe7f4733fc299aef0346db31c..58dcdee1cd719ab3d165907fb76f53c6e55c5db6 100644 --- a/drivers/char/ipmi/ipmi_bt_sm.c +++ b/drivers/char/ipmi/ipmi_bt_sm.c @@ -28,6 +28,8 @@ #include /* For printk. */ #include +#include +#include #include /* for completion codes */ #include "ipmi_si_sm.h" @@ -36,6 +38,8 @@ static int bt_debug = 0x00; /* Production value 0, see following flags */ #define BT_DEBUG_ENABLE 1 #define BT_DEBUG_MSG 2 #define BT_DEBUG_STATES 4 +module_param(bt_debug, int, 0644); +MODULE_PARM_DESC(bt_debug, "debug bitmask, 1=enable, 2=messages, 4=states"); /* Typical "Get BT Capabilities" values are 2-3 retries, 5-10 seconds, and 64 byte buffers. However, one HP implementation wants 255 bytes of @@ -43,7 +47,7 @@ static int bt_debug = 0x00; /* Production value 0, see following flags */ Since the Open IPMI architecture is single-message oriented at this stage, the queue depth of BT is of no concern. */ -#define BT_NORMAL_TIMEOUT 2000000 /* seconds in microseconds */ +#define BT_NORMAL_TIMEOUT 5000000 /* seconds in microseconds */ #define BT_RETRY_LIMIT 2 #define BT_RESET_DELAY 6000000 /* 6 seconds after warm reset */ @@ -202,7 +206,7 @@ static int bt_get_result(struct si_sm_data *bt, msg_len = bt->read_count - 2; /* account for length & seq */ /* Always NetFn, Cmd, cCode */ if (msg_len < 3 || msg_len > IPMI_MAX_MSG_LENGTH) { - printk(KERN_WARNING "BT results: bad msg_len = %d\n", msg_len); + printk(KERN_DEBUG "BT results: bad msg_len = %d\n", msg_len); data[0] = bt->write_data[1] | 0x4; /* Kludge a response */ data[1] = bt->write_data[3]; data[2] = IPMI_ERR_UNSPECIFIED; @@ -240,7 +244,7 @@ static void reset_flags(struct si_sm_data *bt) BT_CONTROL(BT_B_BUSY); BT_CONTROL(BT_CLR_WR_PTR); BT_CONTROL(BT_SMS_ATN); -#ifdef DEVELOPMENT_ONLY_NOT_FOR_PRODUCTION + if (BT_STATUS & BT_B2H_ATN) { int i; BT_CONTROL(BT_H_BUSY); @@ -250,7 +254,6 @@ static void reset_flags(struct si_sm_data *bt) BMC2HOST; BT_CONTROL(BT_H_BUSY); } -#endif } static inline void write_all_bytes(struct si_sm_data *bt) @@ -295,7 +298,7 @@ static inline int read_all_bytes(struct si_sm_data *bt) printk ("\n"); } if (bt->seq != bt->write_data[2]) /* idiot check */ - printk(KERN_WARNING "BT: internal error: sequence mismatch\n"); + printk(KERN_DEBUG "BT: internal error: sequence mismatch\n"); /* per the spec, the (NetFn, Seq, Cmd) tuples should match */ if ((bt->read_data[3] == bt->write_data[3]) && /* Cmd */ @@ -321,18 +324,17 @@ static void error_recovery(struct si_sm_data *bt, char *reason) bt->timeout = BT_NORMAL_TIMEOUT; /* various places want to retry */ status = BT_STATUS; - printk(KERN_WARNING "BT: %s in %s %s ", reason, STATE2TXT, + printk(KERN_DEBUG "BT: %s in %s %s\n", reason, STATE2TXT, STATUS2TXT(buf)); (bt->error_retries)++; if (bt->error_retries > BT_RETRY_LIMIT) { - printk("retry limit (%d) exceeded\n", BT_RETRY_LIMIT); + printk(KERN_DEBUG "retry limit (%d) exceeded\n", BT_RETRY_LIMIT); bt->state = BT_STATE_HOSED; if (!bt->nonzero_status) printk(KERN_ERR "IPMI: BT stuck, try power cycle\n"); - else if (bt->seq == FIRST_SEQ + BT_RETRY_LIMIT) { - /* most likely during insmod */ - printk(KERN_WARNING "IPMI: BT reset (takes 5 secs)\n"); + else if (bt->error_retries <= BT_RETRY_LIMIT + 1) { + printk(KERN_DEBUG "IPMI: BT reset (takes 5 secs)\n"); bt->state = BT_STATE_RESET1; } return; @@ -340,11 +342,11 @@ static void error_recovery(struct si_sm_data *bt, char *reason) /* Sometimes the BMC queues get in an "off-by-one" state...*/ if ((bt->state == BT_STATE_B2H_WAIT) && (status & BT_B2H_ATN)) { - printk("retry B2H_WAIT\n"); + printk(KERN_DEBUG "retry B2H_WAIT\n"); return; } - printk("restart command\n"); + printk(KERN_DEBUG "restart command\n"); bt->state = BT_STATE_RESTART; } @@ -372,17 +374,6 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) return SI_SM_HOSED; if (bt->state != BT_STATE_IDLE) { /* do timeout test */ - - /* Certain states, on error conditions, can lock up a CPU - because they are effectively in an infinite loop with - CALL_WITHOUT_DELAY (right back here with time == 0). - Prevent infinite lockup by ALWAYS decrementing timeout. */ - - /* FIXME: bt_event is sometimes called with time > BT_NORMAL_TIMEOUT - (noticed in ipmi_smic_sm.c January 2004) */ - - if ((time <= 0) || (time >= BT_NORMAL_TIMEOUT)) - time = 100; bt->timeout -= time; if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) { error_recovery(bt, "timed out"); @@ -483,6 +474,7 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) break; case BT_STATE_RESTART: /* don't reset retries! */ + reset_flags(bt); bt->write_data[2] = ++bt->seq; bt->read_count = 0; bt->nonzero_status = 0; diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c index d21853a594a3b74c2354988d523f8cdd0bbcf71d..da1554194d3db10677996060fb37d66ecdfe4058 100644 --- a/drivers/char/ipmi/ipmi_kcs_sm.c +++ b/drivers/char/ipmi/ipmi_kcs_sm.c @@ -38,16 +38,25 @@ */ #include /* For printk. */ +#include +#include #include +#include #include /* for completion codes */ #include "ipmi_si_sm.h" -/* Set this if you want a printout of why the state machine was hosed - when it gets hosed. */ -#define DEBUG_HOSED_REASON +/* kcs_debug is a bit-field + * KCS_DEBUG_ENABLE - turned on for now + * KCS_DEBUG_MSG - commands and their responses + * KCS_DEBUG_STATES - state machine + */ +#define KCS_DEBUG_STATES 4 +#define KCS_DEBUG_MSG 2 +#define KCS_DEBUG_ENABLE 1 -/* Print the state machine state on entry every time. */ -#undef DEBUG_STATE +static int kcs_debug; +module_param(kcs_debug, int, 0644); +MODULE_PARM_DESC(kcs_debug, "debug bitmask, 1=enable, 2=messages, 4=states"); /* The states the KCS driver may be in. */ enum kcs_states { @@ -91,6 +100,7 @@ enum kcs_states { #define IBF_RETRY_TIMEOUT 1000000 #define OBF_RETRY_TIMEOUT 1000000 #define MAX_ERROR_RETRIES 10 +#define ERROR0_OBF_WAIT_JIFFIES (2*HZ) struct si_sm_data { @@ -107,6 +117,7 @@ struct si_sm_data unsigned int error_retries; long ibf_timeout; long obf_timeout; + unsigned long error0_timeout; }; static unsigned int init_kcs_data(struct si_sm_data *kcs, @@ -175,11 +186,11 @@ static inline void start_error_recovery(struct si_sm_data *kcs, char *reason) { (kcs->error_retries)++; if (kcs->error_retries > MAX_ERROR_RETRIES) { -#ifdef DEBUG_HOSED_REASON - printk("ipmi_kcs_sm: kcs hosed: %s\n", reason); -#endif + if (kcs_debug & KCS_DEBUG_ENABLE) + printk(KERN_DEBUG "ipmi_kcs_sm: kcs hosed: %s\n", reason); kcs->state = KCS_HOSED; } else { + kcs->error0_timeout = jiffies + ERROR0_OBF_WAIT_JIFFIES; kcs->state = KCS_ERROR0; } } @@ -248,14 +259,21 @@ static void restart_kcs_transaction(struct si_sm_data *kcs) static int start_kcs_transaction(struct si_sm_data *kcs, unsigned char *data, unsigned int size) { + unsigned int i; + if ((size < 2) || (size > MAX_KCS_WRITE_SIZE)) { return -1; } - if ((kcs->state != KCS_IDLE) && (kcs->state != KCS_HOSED)) { return -2; } - + if (kcs_debug & KCS_DEBUG_MSG) { + printk(KERN_DEBUG "start_kcs_transaction -"); + for (i = 0; i < size; i ++) { + printk(" %02x", (unsigned char) (data [i])); + } + printk ("\n"); + } kcs->error_retries = 0; memcpy(kcs->write_data, data, size); kcs->write_count = size; @@ -305,9 +323,9 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) status = read_status(kcs); -#ifdef DEBUG_STATE - printk(" State = %d, %x\n", kcs->state, status); -#endif + if (kcs_debug & KCS_DEBUG_STATES) + printk(KERN_DEBUG "KCS: State = %d, %x\n", kcs->state, status); + /* All states wait for ibf, so just do it here. */ if (!check_ibf(kcs, status, time)) return SI_SM_CALL_WITH_DELAY; @@ -409,6 +427,10 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) case KCS_ERROR0: clear_obf(kcs, status); + status = read_status(kcs); + if (GET_STATUS_OBF(status)) /* controller isn't responding */ + if (time_before(jiffies, kcs->error0_timeout)) + return SI_SM_CALL_WITH_TICK_DELAY; write_cmd(kcs, KCS_GET_STATUS_ABORT); kcs->state = KCS_ERROR1; break; diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 32fa82c78c73c16336a8527b7b9b4acceffa581a..c1d06ba449b60455fcffdeb908fca20f4952df8d 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -38,13 +38,13 @@ #include #include #include -#include #include #include #include #include #include #include +#include #define PFX "IPMI message handler: " @@ -65,10 +65,19 @@ struct proc_dir_entry *proc_ipmi_root = NULL; the max message timer. This is in milliseconds. */ #define MAX_MSG_TIMEOUT 60000 + +/* + * The main "user" data structure. + */ struct ipmi_user { struct list_head link; + /* Set to "0" when the user is destroyed. */ + int valid; + + struct kref refcount; + /* The upper layer that handles receive messages. */ struct ipmi_user_hndl *handler; void *handler_data; @@ -87,6 +96,15 @@ struct cmd_rcvr ipmi_user_t user; unsigned char netfn; unsigned char cmd; + + /* + * This is used to form a linked lised during mass deletion. + * Since this is in an RCU list, we cannot use the link above + * or change any data until the RCU period completes. So we + * use this next variable during mass deletion so we can have + * a list and don't have to wait and restart the search on + * every individual deletion of a command. */ + struct cmd_rcvr *next; }; struct seq_table @@ -150,13 +168,11 @@ struct ipmi_smi /* What interface number are we? */ int intf_num; - /* The list of upper layers that are using me. We read-lock - this when delivering messages to the upper layer to keep - the user from going away while we are processing the - message. This means that you cannot add or delete a user - from the receive callback. */ - rwlock_t users_lock; - struct list_head users; + struct kref refcount; + + /* The list of upper layers that are using me. seq_lock + * protects this. */ + struct list_head users; /* Used for wake ups at startup. */ wait_queue_head_t waitq; @@ -193,7 +209,7 @@ struct ipmi_smi /* The list of command receivers that are registered for commands on this interface. */ - rwlock_t cmd_rcvr_lock; + struct semaphore cmd_rcvrs_lock; struct list_head cmd_rcvrs; /* Events that were queues because no one was there to receive @@ -296,16 +312,17 @@ struct ipmi_smi unsigned int events; }; +/* Used to mark an interface entry that cannot be used but is not a + * free entry, either, primarily used at creation and deletion time so + * a slot doesn't get reused too quickly. */ +#define IPMI_INVALID_INTERFACE_ENTRY ((ipmi_smi_t) ((long) 1)) +#define IPMI_INVALID_INTERFACE(i) (((i) == NULL) \ + || (i == IPMI_INVALID_INTERFACE_ENTRY)) + #define MAX_IPMI_INTERFACES 4 static ipmi_smi_t ipmi_interfaces[MAX_IPMI_INTERFACES]; -/* Used to keep interfaces from going away while operations are - operating on interfaces. Grab read if you are not modifying the - interfaces, write if you are. */ -static DECLARE_RWSEM(interfaces_sem); - -/* Directly protects the ipmi_interfaces data structure. This is - claimed in the timer interrupt. */ +/* Directly protects the ipmi_interfaces data structure. */ static DEFINE_SPINLOCK(interfaces_lock); /* List of watchers that want to know when smi's are added and @@ -313,20 +330,72 @@ static DEFINE_SPINLOCK(interfaces_lock); static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers); static DECLARE_RWSEM(smi_watchers_sem); + +static void free_recv_msg_list(struct list_head *q) +{ + struct ipmi_recv_msg *msg, *msg2; + + list_for_each_entry_safe(msg, msg2, q, link) { + list_del(&msg->link); + ipmi_free_recv_msg(msg); + } +} + +static void clean_up_interface_data(ipmi_smi_t intf) +{ + int i; + struct cmd_rcvr *rcvr, *rcvr2; + struct list_head list; + + free_recv_msg_list(&intf->waiting_msgs); + free_recv_msg_list(&intf->waiting_events); + + /* Wholesale remove all the entries from the list in the + * interface and wait for RCU to know that none are in use. */ + down(&intf->cmd_rcvrs_lock); + list_add_rcu(&list, &intf->cmd_rcvrs); + list_del_rcu(&intf->cmd_rcvrs); + up(&intf->cmd_rcvrs_lock); + synchronize_rcu(); + + list_for_each_entry_safe(rcvr, rcvr2, &list, link) + kfree(rcvr); + + for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) { + if ((intf->seq_table[i].inuse) + && (intf->seq_table[i].recv_msg)) + { + ipmi_free_recv_msg(intf->seq_table[i].recv_msg); + } + } +} + +static void intf_free(struct kref *ref) +{ + ipmi_smi_t intf = container_of(ref, struct ipmi_smi, refcount); + + clean_up_interface_data(intf); + kfree(intf); +} + int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher) { - int i; + int i; + unsigned long flags; - down_read(&interfaces_sem); down_write(&smi_watchers_sem); list_add(&(watcher->link), &smi_watchers); + up_write(&smi_watchers_sem); + spin_lock_irqsave(&interfaces_lock, flags); for (i = 0; i < MAX_IPMI_INTERFACES; i++) { - if (ipmi_interfaces[i] != NULL) { - watcher->new_smi(i); - } + ipmi_smi_t intf = ipmi_interfaces[i]; + if (IPMI_INVALID_INTERFACE(intf)) + continue; + spin_unlock_irqrestore(&interfaces_lock, flags); + watcher->new_smi(i); + spin_lock_irqsave(&interfaces_lock, flags); } - up_write(&smi_watchers_sem); - up_read(&interfaces_sem); + spin_unlock_irqrestore(&interfaces_lock, flags); return 0; } @@ -471,8 +540,8 @@ static void deliver_response(struct ipmi_recv_msg *msg) } ipmi_free_recv_msg(msg); } else { - msg->user->handler->ipmi_recv_hndl(msg, - msg->user->handler_data); + ipmi_user_t user = msg->user; + user->handler->ipmi_recv_hndl(msg, user->handler_data); } } @@ -662,15 +731,18 @@ int ipmi_create_user(unsigned int if_num, if (! new_user) return -ENOMEM; - down_read(&interfaces_sem); - if ((if_num >= MAX_IPMI_INTERFACES) || ipmi_interfaces[if_num] == NULL) - { - rv = -EINVAL; - goto out_unlock; + spin_lock_irqsave(&interfaces_lock, flags); + intf = ipmi_interfaces[if_num]; + if ((if_num >= MAX_IPMI_INTERFACES) || IPMI_INVALID_INTERFACE(intf)) { + spin_unlock_irqrestore(&interfaces_lock, flags); + return -EINVAL; } - intf = ipmi_interfaces[if_num]; + /* Note that each existing user holds a refcount to the interface. */ + kref_get(&intf->refcount); + spin_unlock_irqrestore(&interfaces_lock, flags); + kref_init(&new_user->refcount); new_user->handler = handler; new_user->handler_data = handler_data; new_user->intf = intf; @@ -678,98 +750,92 @@ int ipmi_create_user(unsigned int if_num, if (!try_module_get(intf->handlers->owner)) { rv = -ENODEV; - goto out_unlock; + goto out_err; } if (intf->handlers->inc_usecount) { rv = intf->handlers->inc_usecount(intf->send_info); if (rv) { module_put(intf->handlers->owner); - goto out_unlock; + goto out_err; } } - write_lock_irqsave(&intf->users_lock, flags); - list_add_tail(&new_user->link, &intf->users); - write_unlock_irqrestore(&intf->users_lock, flags); - - out_unlock: - if (rv) { - kfree(new_user); - } else { - *user = new_user; - } + new_user->valid = 1; + spin_lock_irqsave(&intf->seq_lock, flags); + list_add_rcu(&new_user->link, &intf->users); + spin_unlock_irqrestore(&intf->seq_lock, flags); + *user = new_user; + return 0; - up_read(&interfaces_sem); + out_err: + kfree(new_user); + kref_put(&intf->refcount, intf_free); return rv; } -static int ipmi_destroy_user_nolock(ipmi_user_t user) +static void free_user(struct kref *ref) +{ + ipmi_user_t user = container_of(ref, struct ipmi_user, refcount); + kfree(user); +} + +int ipmi_destroy_user(ipmi_user_t user) { int rv = -ENODEV; - ipmi_user_t t_user; - struct cmd_rcvr *rcvr, *rcvr2; + ipmi_smi_t intf = user->intf; int i; unsigned long flags; + struct cmd_rcvr *rcvr; + struct list_head *entry1, *entry2; + struct cmd_rcvr *rcvrs = NULL; - /* Find the user and delete them from the list. */ - list_for_each_entry(t_user, &(user->intf->users), link) { - if (t_user == user) { - list_del(&t_user->link); - rv = 0; - break; - } - } + user->valid = 1; - if (rv) { - goto out_unlock; - } + /* Remove the user from the interface's sequence table. */ + spin_lock_irqsave(&intf->seq_lock, flags); + list_del_rcu(&user->link); - /* Remove the user from the interfaces sequence table. */ - spin_lock_irqsave(&(user->intf->seq_lock), flags); for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) { - if (user->intf->seq_table[i].inuse - && (user->intf->seq_table[i].recv_msg->user == user)) + if (intf->seq_table[i].inuse + && (intf->seq_table[i].recv_msg->user == user)) { - user->intf->seq_table[i].inuse = 0; + intf->seq_table[i].inuse = 0; } } - spin_unlock_irqrestore(&(user->intf->seq_lock), flags); - - /* Remove the user from the command receiver's table. */ - write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags); - list_for_each_entry_safe(rcvr, rcvr2, &(user->intf->cmd_rcvrs), link) { + spin_unlock_irqrestore(&intf->seq_lock, flags); + + /* + * Remove the user from the command receiver's table. First + * we build a list of everything (not using the standard link, + * since other things may be using it till we do + * synchronize_rcu()) then free everything in that list. + */ + down(&intf->cmd_rcvrs_lock); + list_for_each_safe_rcu(entry1, entry2, &intf->cmd_rcvrs) { + rcvr = list_entry(entry1, struct cmd_rcvr, link); if (rcvr->user == user) { - list_del(&rcvr->link); - kfree(rcvr); + list_del_rcu(&rcvr->link); + rcvr->next = rcvrs; + rcvrs = rcvr; } } - write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags); + up(&intf->cmd_rcvrs_lock); + synchronize_rcu(); + while (rcvrs) { + rcvr = rcvrs; + rcvrs = rcvr->next; + kfree(rcvr); + } - kfree(user); + module_put(intf->handlers->owner); + if (intf->handlers->dec_usecount) + intf->handlers->dec_usecount(intf->send_info); - out_unlock: + kref_put(&intf->refcount, intf_free); - return rv; -} - -int ipmi_destroy_user(ipmi_user_t user) -{ - int rv; - ipmi_smi_t intf = user->intf; - unsigned long flags; + kref_put(&user->refcount, free_user); - down_read(&interfaces_sem); - write_lock_irqsave(&intf->users_lock, flags); - rv = ipmi_destroy_user_nolock(user); - if (!rv) { - module_put(intf->handlers->owner); - if (intf->handlers->dec_usecount) - intf->handlers->dec_usecount(intf->send_info); - } - - write_unlock_irqrestore(&intf->users_lock, flags); - up_read(&interfaces_sem); return rv; } @@ -823,62 +889,78 @@ int ipmi_get_my_LUN(ipmi_user_t user, int ipmi_set_gets_events(ipmi_user_t user, int val) { - unsigned long flags; - struct ipmi_recv_msg *msg, *msg2; + unsigned long flags; + ipmi_smi_t intf = user->intf; + struct ipmi_recv_msg *msg, *msg2; + struct list_head msgs; - read_lock(&(user->intf->users_lock)); - spin_lock_irqsave(&(user->intf->events_lock), flags); + INIT_LIST_HEAD(&msgs); + + spin_lock_irqsave(&intf->events_lock, flags); user->gets_events = val; if (val) { /* Deliver any queued events. */ - list_for_each_entry_safe(msg, msg2, &(user->intf->waiting_events), link) { + list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link) { list_del(&msg->link); - msg->user = user; - deliver_response(msg); + list_add_tail(&msg->link, &msgs); } } - - spin_unlock_irqrestore(&(user->intf->events_lock), flags); - read_unlock(&(user->intf->users_lock)); + + /* Hold the events lock while doing this to preserve order. */ + list_for_each_entry_safe(msg, msg2, &msgs, link) { + msg->user = user; + kref_get(&user->refcount); + deliver_response(msg); + } + + spin_unlock_irqrestore(&intf->events_lock, flags); return 0; } +static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf, + unsigned char netfn, + unsigned char cmd) +{ + struct cmd_rcvr *rcvr; + + list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) { + if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) + return rcvr; + } + return NULL; +} + int ipmi_register_for_cmd(ipmi_user_t user, unsigned char netfn, unsigned char cmd) { - struct cmd_rcvr *cmp; - unsigned long flags; - struct cmd_rcvr *rcvr; - int rv = 0; + ipmi_smi_t intf = user->intf; + struct cmd_rcvr *rcvr; + struct cmd_rcvr *entry; + int rv = 0; rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL); if (! rcvr) return -ENOMEM; + rcvr->cmd = cmd; + rcvr->netfn = netfn; + rcvr->user = user; - read_lock(&(user->intf->users_lock)); - write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags); + down(&intf->cmd_rcvrs_lock); /* Make sure the command/netfn is not already registered. */ - list_for_each_entry(cmp, &(user->intf->cmd_rcvrs), link) { - if ((cmp->netfn == netfn) && (cmp->cmd == cmd)) { - rv = -EBUSY; - break; - } - } - - if (! rv) { - rcvr->cmd = cmd; - rcvr->netfn = netfn; - rcvr->user = user; - list_add_tail(&(rcvr->link), &(user->intf->cmd_rcvrs)); + entry = find_cmd_rcvr(intf, netfn, cmd); + if (entry) { + rv = -EBUSY; + goto out_unlock; } - write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags); - read_unlock(&(user->intf->users_lock)); + list_add_rcu(&rcvr->link, &intf->cmd_rcvrs); + out_unlock: + up(&intf->cmd_rcvrs_lock); if (rv) kfree(rcvr); @@ -889,31 +971,28 @@ int ipmi_unregister_for_cmd(ipmi_user_t user, unsigned char netfn, unsigned char cmd) { - unsigned long flags; - struct cmd_rcvr *rcvr; - int rv = -ENOENT; + ipmi_smi_t intf = user->intf; + struct cmd_rcvr *rcvr; - read_lock(&(user->intf->users_lock)); - write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags); + down(&intf->cmd_rcvrs_lock); /* Make sure the command/netfn is not already registered. */ - list_for_each_entry(rcvr, &(user->intf->cmd_rcvrs), link) { - if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) { - rv = 0; - list_del(&rcvr->link); - kfree(rcvr); - break; - } + rcvr = find_cmd_rcvr(intf, netfn, cmd); + if ((rcvr) && (rcvr->user == user)) { + list_del_rcu(&rcvr->link); + up(&intf->cmd_rcvrs_lock); + synchronize_rcu(); + kfree(rcvr); + return 0; + } else { + up(&intf->cmd_rcvrs_lock); + return -ENOENT; } - write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags); - read_unlock(&(user->intf->users_lock)); - - return rv; } void ipmi_user_set_run_to_completion(ipmi_user_t user, int val) { - user->intf->handlers->set_run_to_completion(user->intf->send_info, - val); + ipmi_smi_t intf = user->intf; + intf->handlers->set_run_to_completion(intf->send_info, val); } static unsigned char @@ -1010,19 +1089,19 @@ static inline void format_lan_msg(struct ipmi_smi_msg *smi_msg, supplied in certain circumstances (mainly at panic time). If messages are supplied, they will be freed, even if an error occurs. */ -static inline int i_ipmi_request(ipmi_user_t user, - ipmi_smi_t intf, - struct ipmi_addr *addr, - long msgid, - struct kernel_ipmi_msg *msg, - void *user_msg_data, - void *supplied_smi, - struct ipmi_recv_msg *supplied_recv, - int priority, - unsigned char source_address, - unsigned char source_lun, - int retries, - unsigned int retry_time_ms) +static int i_ipmi_request(ipmi_user_t user, + ipmi_smi_t intf, + struct ipmi_addr *addr, + long msgid, + struct kernel_ipmi_msg *msg, + void *user_msg_data, + void *supplied_smi, + struct ipmi_recv_msg *supplied_recv, + int priority, + unsigned char source_address, + unsigned char source_lun, + int retries, + unsigned int retry_time_ms) { int rv = 0; struct ipmi_smi_msg *smi_msg; @@ -1051,6 +1130,8 @@ static inline int i_ipmi_request(ipmi_user_t user, } recv_msg->user = user; + if (user) + kref_get(&user->refcount); recv_msg->msgid = msgid; /* Store the message to send in the receive message so timeout responses can get the proper response data. */ @@ -1725,11 +1806,11 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, unsigned char version_major, unsigned char version_minor, unsigned char slave_addr, - ipmi_smi_t *intf) + ipmi_smi_t *new_intf) { int i, j; int rv; - ipmi_smi_t new_intf; + ipmi_smi_t intf; unsigned long flags; @@ -1745,189 +1826,142 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, return -ENODEV; } - new_intf = kmalloc(sizeof(*new_intf), GFP_KERNEL); - if (!new_intf) + intf = kmalloc(sizeof(*intf), GFP_KERNEL); + if (!intf) return -ENOMEM; - memset(new_intf, 0, sizeof(*new_intf)); - - new_intf->proc_dir = NULL; + memset(intf, 0, sizeof(*intf)); + intf->intf_num = -1; + kref_init(&intf->refcount); + intf->version_major = version_major; + intf->version_minor = version_minor; + for (j = 0; j < IPMI_MAX_CHANNELS; j++) { + intf->channels[j].address = IPMI_BMC_SLAVE_ADDR; + intf->channels[j].lun = 2; + } + if (slave_addr != 0) + intf->channels[0].address = slave_addr; + INIT_LIST_HEAD(&intf->users); + intf->handlers = handlers; + intf->send_info = send_info; + spin_lock_init(&intf->seq_lock); + for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) { + intf->seq_table[j].inuse = 0; + intf->seq_table[j].seqid = 0; + } + intf->curr_seq = 0; +#ifdef CONFIG_PROC_FS + spin_lock_init(&intf->proc_entry_lock); +#endif + spin_lock_init(&intf->waiting_msgs_lock); + INIT_LIST_HEAD(&intf->waiting_msgs); + spin_lock_init(&intf->events_lock); + INIT_LIST_HEAD(&intf->waiting_events); + intf->waiting_events_count = 0; + init_MUTEX(&intf->cmd_rcvrs_lock); + INIT_LIST_HEAD(&intf->cmd_rcvrs); + init_waitqueue_head(&intf->waitq); + + spin_lock_init(&intf->counter_lock); + intf->proc_dir = NULL; rv = -ENOMEM; - - down_write(&interfaces_sem); + spin_lock_irqsave(&interfaces_lock, flags); for (i = 0; i < MAX_IPMI_INTERFACES; i++) { if (ipmi_interfaces[i] == NULL) { - new_intf->intf_num = i; - new_intf->version_major = version_major; - new_intf->version_minor = version_minor; - for (j = 0; j < IPMI_MAX_CHANNELS; j++) { - new_intf->channels[j].address - = IPMI_BMC_SLAVE_ADDR; - new_intf->channels[j].lun = 2; - } - if (slave_addr != 0) - new_intf->channels[0].address = slave_addr; - rwlock_init(&(new_intf->users_lock)); - INIT_LIST_HEAD(&(new_intf->users)); - new_intf->handlers = handlers; - new_intf->send_info = send_info; - spin_lock_init(&(new_intf->seq_lock)); - for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) { - new_intf->seq_table[j].inuse = 0; - new_intf->seq_table[j].seqid = 0; - } - new_intf->curr_seq = 0; -#ifdef CONFIG_PROC_FS - spin_lock_init(&(new_intf->proc_entry_lock)); -#endif - spin_lock_init(&(new_intf->waiting_msgs_lock)); - INIT_LIST_HEAD(&(new_intf->waiting_msgs)); - spin_lock_init(&(new_intf->events_lock)); - INIT_LIST_HEAD(&(new_intf->waiting_events)); - new_intf->waiting_events_count = 0; - rwlock_init(&(new_intf->cmd_rcvr_lock)); - init_waitqueue_head(&new_intf->waitq); - INIT_LIST_HEAD(&(new_intf->cmd_rcvrs)); - - spin_lock_init(&(new_intf->counter_lock)); - - spin_lock_irqsave(&interfaces_lock, flags); - ipmi_interfaces[i] = new_intf; - spin_unlock_irqrestore(&interfaces_lock, flags); - + intf->intf_num = i; + /* Reserve the entry till we are done. */ + ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY; rv = 0; - *intf = new_intf; break; } } + spin_unlock_irqrestore(&interfaces_lock, flags); + if (rv) + goto out; - downgrade_write(&interfaces_sem); - - if (rv == 0) - rv = add_proc_entries(*intf, i); - - if (rv == 0) { - if ((version_major > 1) - || ((version_major == 1) && (version_minor >= 5))) - { - /* Start scanning the channels to see what is - available. */ - (*intf)->null_user_handler = channel_handler; - (*intf)->curr_channel = 0; - rv = send_channel_info_cmd(*intf, 0); - if (rv) - goto out; + /* FIXME - this is an ugly kludge, this sets the intf for the + caller before sending any messages with it. */ + *new_intf = intf; - /* Wait for the channel info to be read. */ - up_read(&interfaces_sem); - wait_event((*intf)->waitq, - ((*intf)->curr_channel>=IPMI_MAX_CHANNELS)); - down_read(&interfaces_sem); + if ((version_major > 1) + || ((version_major == 1) && (version_minor >= 5))) + { + /* Start scanning the channels to see what is + available. */ + intf->null_user_handler = channel_handler; + intf->curr_channel = 0; + rv = send_channel_info_cmd(intf, 0); + if (rv) + goto out; - if (ipmi_interfaces[i] != new_intf) - /* Well, it went away. Just return. */ - goto out; - } else { - /* Assume a single IPMB channel at zero. */ - (*intf)->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB; - (*intf)->channels[0].protocol - = IPMI_CHANNEL_PROTOCOL_IPMB; - } - - /* Call all the watcher interfaces to tell - them that a new interface is available. */ - call_smi_watchers(i); + /* Wait for the channel info to be read. */ + wait_event(intf->waitq, + intf->curr_channel >= IPMI_MAX_CHANNELS); + } else { + /* Assume a single IPMB channel at zero. */ + intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB; + intf->channels[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB; } - out: - up_read(&interfaces_sem); + if (rv == 0) + rv = add_proc_entries(intf, i); + out: if (rv) { - if (new_intf->proc_dir) - remove_proc_entries(new_intf); - kfree(new_intf); + if (intf->proc_dir) + remove_proc_entries(intf); + kref_put(&intf->refcount, intf_free); + if (i < MAX_IPMI_INTERFACES) { + spin_lock_irqsave(&interfaces_lock, flags); + ipmi_interfaces[i] = NULL; + spin_unlock_irqrestore(&interfaces_lock, flags); + } + } else { + spin_lock_irqsave(&interfaces_lock, flags); + ipmi_interfaces[i] = intf; + spin_unlock_irqrestore(&interfaces_lock, flags); + call_smi_watchers(i); } return rv; } -static void free_recv_msg_list(struct list_head *q) -{ - struct ipmi_recv_msg *msg, *msg2; - - list_for_each_entry_safe(msg, msg2, q, link) { - list_del(&msg->link); - ipmi_free_recv_msg(msg); - } -} - -static void free_cmd_rcvr_list(struct list_head *q) -{ - struct cmd_rcvr *rcvr, *rcvr2; - - list_for_each_entry_safe(rcvr, rcvr2, q, link) { - list_del(&rcvr->link); - kfree(rcvr); - } -} - -static void clean_up_interface_data(ipmi_smi_t intf) -{ - int i; - - free_recv_msg_list(&(intf->waiting_msgs)); - free_recv_msg_list(&(intf->waiting_events)); - free_cmd_rcvr_list(&(intf->cmd_rcvrs)); - - for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) { - if ((intf->seq_table[i].inuse) - && (intf->seq_table[i].recv_msg)) - { - ipmi_free_recv_msg(intf->seq_table[i].recv_msg); - } - } -} - int ipmi_unregister_smi(ipmi_smi_t intf) { - int rv = -ENODEV; int i; struct ipmi_smi_watcher *w; unsigned long flags; - down_write(&interfaces_sem); - if (list_empty(&(intf->users))) - { - for (i = 0; i < MAX_IPMI_INTERFACES; i++) { - if (ipmi_interfaces[i] == intf) { - remove_proc_entries(intf); - spin_lock_irqsave(&interfaces_lock, flags); - ipmi_interfaces[i] = NULL; - clean_up_interface_data(intf); - spin_unlock_irqrestore(&interfaces_lock,flags); - kfree(intf); - rv = 0; - goto out_call_watcher; - } + spin_lock_irqsave(&interfaces_lock, flags); + for (i = 0; i < MAX_IPMI_INTERFACES; i++) { + if (ipmi_interfaces[i] == intf) { + /* Set the interface number reserved until we + * are done. */ + ipmi_interfaces[i] = IPMI_INVALID_INTERFACE_ENTRY; + intf->intf_num = -1; + break; } - } else { - rv = -EBUSY; } - up_write(&interfaces_sem); + spin_unlock_irqrestore(&interfaces_lock,flags); - return rv; + if (i == MAX_IPMI_INTERFACES) + return -ENODEV; - out_call_watcher: - downgrade_write(&interfaces_sem); + remove_proc_entries(intf); /* Call all the watcher interfaces to tell them that an interface is gone. */ down_read(&smi_watchers_sem); - list_for_each_entry(w, &smi_watchers, link) { + list_for_each_entry(w, &smi_watchers, link) w->smi_gone(i); - } up_read(&smi_watchers_sem); - up_read(&interfaces_sem); + + /* Allow the entry to be reused now. */ + spin_lock_irqsave(&interfaces_lock, flags); + ipmi_interfaces[i] = NULL; + spin_unlock_irqrestore(&interfaces_lock,flags); + + kref_put(&intf->refcount, intf_free); return 0; } @@ -1998,14 +2032,14 @@ static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf, static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, struct ipmi_smi_msg *msg) { - struct cmd_rcvr *rcvr; - int rv = 0; - unsigned char netfn; - unsigned char cmd; - ipmi_user_t user = NULL; - struct ipmi_ipmb_addr *ipmb_addr; - struct ipmi_recv_msg *recv_msg; - unsigned long flags; + struct cmd_rcvr *rcvr; + int rv = 0; + unsigned char netfn; + unsigned char cmd; + ipmi_user_t user = NULL; + struct ipmi_ipmb_addr *ipmb_addr; + struct ipmi_recv_msg *recv_msg; + unsigned long flags; if (msg->rsp_size < 10) { /* Message not big enough, just ignore it. */ @@ -2023,16 +2057,14 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, netfn = msg->rsp[4] >> 2; cmd = msg->rsp[8]; - read_lock(&(intf->cmd_rcvr_lock)); - - /* Find the command/netfn. */ - list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) { - if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) { - user = rcvr->user; - break; - } - } - read_unlock(&(intf->cmd_rcvr_lock)); + rcu_read_lock(); + rcvr = find_cmd_rcvr(intf, netfn, cmd); + if (rcvr) { + user = rcvr->user; + kref_get(&user->refcount); + } else + user = NULL; + rcu_read_unlock(); if (user == NULL) { /* We didn't find a user, deliver an error response. */ @@ -2079,6 +2111,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, message, so requeue it for handling later. */ rv = 1; + kref_put(&user->refcount, free_user); } else { /* Extract the source address from the data. */ ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr; @@ -2179,14 +2212,14 @@ static int handle_lan_get_msg_rsp(ipmi_smi_t intf, static int handle_lan_get_msg_cmd(ipmi_smi_t intf, struct ipmi_smi_msg *msg) { - struct cmd_rcvr *rcvr; - int rv = 0; - unsigned char netfn; - unsigned char cmd; - ipmi_user_t user = NULL; - struct ipmi_lan_addr *lan_addr; - struct ipmi_recv_msg *recv_msg; - unsigned long flags; + struct cmd_rcvr *rcvr; + int rv = 0; + unsigned char netfn; + unsigned char cmd; + ipmi_user_t user = NULL; + struct ipmi_lan_addr *lan_addr; + struct ipmi_recv_msg *recv_msg; + unsigned long flags; if (msg->rsp_size < 12) { /* Message not big enough, just ignore it. */ @@ -2204,19 +2237,17 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf, netfn = msg->rsp[6] >> 2; cmd = msg->rsp[10]; - read_lock(&(intf->cmd_rcvr_lock)); - - /* Find the command/netfn. */ - list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) { - if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) { - user = rcvr->user; - break; - } - } - read_unlock(&(intf->cmd_rcvr_lock)); + rcu_read_lock(); + rcvr = find_cmd_rcvr(intf, netfn, cmd); + if (rcvr) { + user = rcvr->user; + kref_get(&user->refcount); + } else + user = NULL; + rcu_read_unlock(); if (user == NULL) { - /* We didn't find a user, deliver an error response. */ + /* We didn't find a user, just give up. */ spin_lock_irqsave(&intf->counter_lock, flags); intf->unhandled_commands++; spin_unlock_irqrestore(&intf->counter_lock, flags); @@ -2235,6 +2266,7 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf, message, so requeue it for handling later. */ rv = 1; + kref_put(&user->refcount, free_user); } else { /* Extract the source address from the data. */ lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr; @@ -2286,8 +2318,6 @@ static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg, recv_msg->msg.data_len = msg->rsp_size - 3; } -/* This will be called with the intf->users_lock read-locked, so no need - to do that here. */ static int handle_read_event_rsp(ipmi_smi_t intf, struct ipmi_smi_msg *msg) { @@ -2313,7 +2343,7 @@ static int handle_read_event_rsp(ipmi_smi_t intf, INIT_LIST_HEAD(&msgs); - spin_lock_irqsave(&(intf->events_lock), flags); + spin_lock_irqsave(&intf->events_lock, flags); spin_lock(&intf->counter_lock); intf->events++; @@ -2321,12 +2351,14 @@ static int handle_read_event_rsp(ipmi_smi_t intf, /* Allocate and fill in one message for every user that is getting events. */ - list_for_each_entry(user, &(intf->users), link) { + rcu_read_lock(); + list_for_each_entry_rcu(user, &intf->users, link) { if (! user->gets_events) continue; recv_msg = ipmi_alloc_recv_msg(); if (! recv_msg) { + rcu_read_unlock(); list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) { list_del(&recv_msg->link); ipmi_free_recv_msg(recv_msg); @@ -2342,8 +2374,10 @@ static int handle_read_event_rsp(ipmi_smi_t intf, copy_event_into_recv_msg(recv_msg, msg); recv_msg->user = user; + kref_get(&user->refcount); list_add_tail(&(recv_msg->link), &msgs); } + rcu_read_unlock(); if (deliver_count) { /* Now deliver all the messages. */ @@ -2382,9 +2416,8 @@ static int handle_bmc_rsp(ipmi_smi_t intf, struct ipmi_smi_msg *msg) { struct ipmi_recv_msg *recv_msg; - int found = 0; - struct ipmi_user *user; unsigned long flags; + struct ipmi_user *user; recv_msg = (struct ipmi_recv_msg *) msg->user_data; if (recv_msg == NULL) @@ -2396,16 +2429,9 @@ static int handle_bmc_rsp(ipmi_smi_t intf, return 0; } + user = recv_msg->user; /* Make sure the user still exists. */ - list_for_each_entry(user, &(intf->users), link) { - if (user == recv_msg->user) { - /* Found it, so we can deliver it */ - found = 1; - break; - } - } - - if ((! found) && recv_msg->user) { + if (user && !user->valid) { /* The user for the message went away, so give up. */ spin_lock_irqsave(&intf->counter_lock, flags); intf->unhandled_local_responses++; @@ -2486,7 +2512,7 @@ static int handle_new_recv_msg(ipmi_smi_t intf, { /* It's a response to a response we sent. For this we deliver a send message response to the user. */ - struct ipmi_recv_msg *recv_msg = msg->user_data; + struct ipmi_recv_msg *recv_msg = msg->user_data; requeue = 0; if (msg->rsp_size < 2) @@ -2498,13 +2524,18 @@ static int handle_new_recv_msg(ipmi_smi_t intf, /* Invalid channel number */ goto out; - if (recv_msg) { - recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE; - recv_msg->msg.data = recv_msg->msg_data; - recv_msg->msg.data_len = 1; - recv_msg->msg_data[0] = msg->rsp[2]; - deliver_response(recv_msg); - } + if (!recv_msg) + goto out; + + /* Make sure the user still exists. */ + if (!recv_msg->user || !recv_msg->user->valid) + goto out; + + recv_msg->recv_type = IPMI_RESPONSE_RESPONSE_TYPE; + recv_msg->msg.data = recv_msg->msg_data; + recv_msg->msg.data_len = 1; + recv_msg->msg_data[0] = msg->rsp[2]; + deliver_response(recv_msg); } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) && (msg->rsp[1] == IPMI_GET_MSG_CMD)) { @@ -2570,14 +2601,11 @@ void ipmi_smi_msg_received(ipmi_smi_t intf, int rv; - /* Lock the user lock so the user can't go away while we are - working on it. */ - read_lock(&(intf->users_lock)); - if ((msg->data_size >= 2) && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2)) && (msg->data[1] == IPMI_SEND_MSG_CMD) - && (msg->user_data == NULL)) { + && (msg->user_data == NULL)) + { /* This is the local response to a command send, start the timer for these. The user_data will not be NULL if this is a response send, and we will let @@ -2612,46 +2640,46 @@ void ipmi_smi_msg_received(ipmi_smi_t intf, } ipmi_free_smi_msg(msg); - goto out_unlock; + goto out; } /* To preserve message order, if the list is not empty, we tack this message onto the end of the list. */ - spin_lock_irqsave(&(intf->waiting_msgs_lock), flags); - if (!list_empty(&(intf->waiting_msgs))) { - list_add_tail(&(msg->link), &(intf->waiting_msgs)); - spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags); - goto out_unlock; + spin_lock_irqsave(&intf->waiting_msgs_lock, flags); + if (!list_empty(&intf->waiting_msgs)) { + list_add_tail(&msg->link, &intf->waiting_msgs); + spin_unlock(&intf->waiting_msgs_lock); + goto out; } - spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags); + spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); rv = handle_new_recv_msg(intf, msg); if (rv > 0) { /* Could not handle the message now, just add it to a list to handle later. */ - spin_lock_irqsave(&(intf->waiting_msgs_lock), flags); - list_add_tail(&(msg->link), &(intf->waiting_msgs)); - spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags); + spin_lock(&intf->waiting_msgs_lock); + list_add_tail(&msg->link, &intf->waiting_msgs); + spin_unlock(&intf->waiting_msgs_lock); } else if (rv == 0) { ipmi_free_smi_msg(msg); } - out_unlock: - read_unlock(&(intf->users_lock)); + out: + return; } void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf) { ipmi_user_t user; - read_lock(&(intf->users_lock)); - list_for_each_entry(user, &(intf->users), link) { + rcu_read_lock(); + list_for_each_entry_rcu(user, &intf->users, link) { if (! user->handler->ipmi_watchdog_pretimeout) continue; user->handler->ipmi_watchdog_pretimeout(user->handler_data); } - read_unlock(&(intf->users_lock)); + rcu_read_unlock(); } static void @@ -2691,8 +2719,65 @@ smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, return smi_msg; } -static void -ipmi_timeout_handler(long timeout_period) +static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, + struct list_head *timeouts, long timeout_period, + int slot, unsigned long *flags) +{ + struct ipmi_recv_msg *msg; + + if (!ent->inuse) + return; + + ent->timeout -= timeout_period; + if (ent->timeout > 0) + return; + + if (ent->retries_left == 0) { + /* The message has used all its retries. */ + ent->inuse = 0; + msg = ent->recv_msg; + list_add_tail(&msg->link, timeouts); + spin_lock(&intf->counter_lock); + if (ent->broadcast) + intf->timed_out_ipmb_broadcasts++; + else if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE) + intf->timed_out_lan_commands++; + else + intf->timed_out_ipmb_commands++; + spin_unlock(&intf->counter_lock); + } else { + struct ipmi_smi_msg *smi_msg; + /* More retries, send again. */ + + /* Start with the max timer, set to normal + timer after the message is sent. */ + ent->timeout = MAX_MSG_TIMEOUT; + ent->retries_left--; + spin_lock(&intf->counter_lock); + if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE) + intf->retransmitted_lan_commands++; + else + intf->retransmitted_ipmb_commands++; + spin_unlock(&intf->counter_lock); + + smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot, + ent->seqid); + if (! smi_msg) + return; + + spin_unlock_irqrestore(&intf->seq_lock, *flags); + /* Send the new message. We send with a zero + * priority. It timed out, I doubt time is + * that critical now, and high priority + * messages are really only for messages to the + * local MC, which don't get resent. */ + intf->handlers->sender(intf->send_info, + smi_msg, 0); + spin_lock_irqsave(&intf->seq_lock, *flags); + } +} + +static void ipmi_timeout_handler(long timeout_period) { ipmi_smi_t intf; struct list_head timeouts; @@ -2706,14 +2791,14 @@ ipmi_timeout_handler(long timeout_period) spin_lock(&interfaces_lock); for (i = 0; i < MAX_IPMI_INTERFACES; i++) { intf = ipmi_interfaces[i]; - if (intf == NULL) + if (IPMI_INVALID_INTERFACE(intf)) continue; - - read_lock(&(intf->users_lock)); + kref_get(&intf->refcount); + spin_unlock(&interfaces_lock); /* See if any waiting messages need to be processed. */ - spin_lock_irqsave(&(intf->waiting_msgs_lock), flags); - list_for_each_entry_safe(smi_msg, smi_msg2, &(intf->waiting_msgs), link) { + spin_lock_irqsave(&intf->waiting_msgs_lock, flags); + list_for_each_entry_safe(smi_msg, smi_msg2, &intf->waiting_msgs, link) { if (! handle_new_recv_msg(intf, smi_msg)) { list_del(&smi_msg->link); ipmi_free_smi_msg(smi_msg); @@ -2723,73 +2808,23 @@ ipmi_timeout_handler(long timeout_period) break; } } - spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags); + spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); /* Go through the seq table and find any messages that have timed out, putting them in the timeouts list. */ - spin_lock_irqsave(&(intf->seq_lock), flags); - for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) { - struct seq_table *ent = &(intf->seq_table[j]); - if (!ent->inuse) - continue; - - ent->timeout -= timeout_period; - if (ent->timeout > 0) - continue; - - if (ent->retries_left == 0) { - /* The message has used all its retries. */ - ent->inuse = 0; - msg = ent->recv_msg; - list_add_tail(&(msg->link), &timeouts); - spin_lock(&intf->counter_lock); - if (ent->broadcast) - intf->timed_out_ipmb_broadcasts++; - else if (ent->recv_msg->addr.addr_type - == IPMI_LAN_ADDR_TYPE) - intf->timed_out_lan_commands++; - else - intf->timed_out_ipmb_commands++; - spin_unlock(&intf->counter_lock); - } else { - struct ipmi_smi_msg *smi_msg; - /* More retries, send again. */ - - /* Start with the max timer, set to normal - timer after the message is sent. */ - ent->timeout = MAX_MSG_TIMEOUT; - ent->retries_left--; - spin_lock(&intf->counter_lock); - if (ent->recv_msg->addr.addr_type - == IPMI_LAN_ADDR_TYPE) - intf->retransmitted_lan_commands++; - else - intf->retransmitted_ipmb_commands++; - spin_unlock(&intf->counter_lock); - smi_msg = smi_from_recv_msg(intf, - ent->recv_msg, j, ent->seqid); - if (! smi_msg) - continue; - - spin_unlock_irqrestore(&(intf->seq_lock),flags); - /* Send the new message. We send with a zero - * priority. It timed out, I doubt time is - * that critical now, and high priority - * messages are really only for messages to the - * local MC, which don't get resent. */ - intf->handlers->sender(intf->send_info, - smi_msg, 0); - spin_lock_irqsave(&(intf->seq_lock), flags); - } - } - spin_unlock_irqrestore(&(intf->seq_lock), flags); - - list_for_each_entry_safe(msg, msg2, &timeouts, link) { + spin_lock_irqsave(&intf->seq_lock, flags); + for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) + check_msg_timeout(intf, &(intf->seq_table[j]), + &timeouts, timeout_period, j, + &flags); + spin_unlock_irqrestore(&intf->seq_lock, flags); + + list_for_each_entry_safe(msg, msg2, &timeouts, link) handle_msg_timeout(msg); - } - read_unlock(&(intf->users_lock)); + kref_put(&intf->refcount, intf_free); + spin_lock(&interfaces_lock); } spin_unlock(&interfaces_lock); } @@ -2802,7 +2837,7 @@ static void ipmi_request_event(void) spin_lock(&interfaces_lock); for (i = 0; i < MAX_IPMI_INTERFACES; i++) { intf = ipmi_interfaces[i]; - if (intf == NULL) + if (IPMI_INVALID_INTERFACE(intf)) continue; intf->handlers->request_events(intf->send_info); @@ -2884,6 +2919,13 @@ struct ipmi_recv_msg *ipmi_alloc_recv_msg(void) return rv; } +void ipmi_free_recv_msg(struct ipmi_recv_msg *msg) +{ + if (msg->user) + kref_put(&msg->user->refcount, free_user); + msg->done(msg); +} + #ifdef CONFIG_IPMI_PANIC_EVENT static void dummy_smi_done_handler(struct ipmi_smi_msg *msg) @@ -2964,7 +3006,7 @@ static void send_panic_events(char *str) /* For every registered interface, send the event. */ for (i = 0; i < MAX_IPMI_INTERFACES; i++) { intf = ipmi_interfaces[i]; - if (intf == NULL) + if (IPMI_INVALID_INTERFACE(intf)) continue; /* Send the event announcing the panic. */ @@ -2995,7 +3037,7 @@ static void send_panic_events(char *str) int j; intf = ipmi_interfaces[i]; - if (intf == NULL) + if (IPMI_INVALID_INTERFACE(intf)) continue; /* First job here is to figure out where to send the @@ -3131,7 +3173,7 @@ static int panic_event(struct notifier_block *this, /* For every registered interface, set it to run to completion. */ for (i = 0; i < MAX_IPMI_INTERFACES; i++) { intf = ipmi_interfaces[i]; - if (intf == NULL) + if (IPMI_INVALID_INTERFACE(intf)) continue; intf->handlers->set_run_to_completion(intf->send_info, 1); @@ -3160,9 +3202,8 @@ static int ipmi_init_msghandler(void) printk(KERN_INFO "ipmi message handler version " IPMI_DRIVER_VERSION "\n"); - for (i = 0; i < MAX_IPMI_INTERFACES; i++) { + for (i = 0; i < MAX_IPMI_INTERFACES; i++) ipmi_interfaces[i] = NULL; - } #ifdef CONFIG_PROC_FS proc_ipmi_root = proc_mkdir("ipmi", NULL); @@ -3258,3 +3299,4 @@ EXPORT_SYMBOL(ipmi_get_my_LUN); EXPORT_SYMBOL(ipmi_smi_add_proc_entry); EXPORT_SYMBOL(proc_ipmi_root); EXPORT_SYMBOL(ipmi_user_set_run_to_completion); +EXPORT_SYMBOL(ipmi_free_recv_msg); diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index f66947722e1282196a4d60e8c777d8ea250b3750..e053eade0366b070a90772305f91a3f884f5fd38 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c @@ -56,7 +56,7 @@ static int poweroff_powercycle; /* parameter definition to allow user to flag power cycle */ module_param(poweroff_powercycle, int, 0644); -MODULE_PARM_DESC(poweroff_powercycles, " Set to non-zero to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down."); +MODULE_PARM_DESC(poweroff_powercycle, " Set to non-zero to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down."); /* Stuff from the get device id command. */ static unsigned int mfg_id; @@ -611,9 +611,7 @@ static int ipmi_poweroff_init (void) } #endif -#ifdef CONFIG_PROC_FS rv = ipmi_smi_watcher_register(&smi_watcher); -#endif if (rv) { unregister_sysctl_table(ipmi_table_header); printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index b6e5cbfb09f81d897c1dd95079c4e9281dda4ba5..ea89dca3dbb58f16b057ea9878173059b6611e6b 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -51,6 +51,8 @@ #include #include #include +#include +#include #include #ifdef CONFIG_HIGH_RES_TIMERS #include @@ -125,6 +127,7 @@ struct ipmi_device_id { struct smi_info { + int intf_num; ipmi_smi_t intf; struct si_sm_data *si_sm; struct si_sm_handlers *handlers; @@ -192,8 +195,7 @@ struct smi_info unsigned long last_timeout_jiffies; /* Used to gracefully stop the timer without race conditions. */ - volatile int stop_operation; - volatile int timer_stopped; + atomic_t stop_operation; /* The driver will disable interrupts when it gets into a situation where it cannot handle messages due to lack of @@ -220,8 +222,16 @@ struct smi_info unsigned long events; unsigned long watchdog_pretimeouts; unsigned long incoming_messages; + + struct task_struct *thread; }; +static struct notifier_block *xaction_notifier_list; +static int register_xaction_notifier(struct notifier_block * nb) +{ + return notifier_chain_register(&xaction_notifier_list, nb); +} + static void si_restart_short_timer(struct smi_info *smi_info); static void deliver_recv_msg(struct smi_info *smi_info, @@ -281,6 +291,11 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) do_gettimeofday(&t); printk("**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif + err = notifier_call_chain(&xaction_notifier_list, 0, smi_info); + if (err & NOTIFY_STOP_MASK) { + rv = SI_SM_CALL_WITHOUT_DELAY; + goto out; + } err = smi_info->handlers->start_transaction( smi_info->si_sm, smi_info->curr_msg->data, @@ -291,6 +306,7 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) rv = SI_SM_CALL_WITHOUT_DELAY; } + out: spin_unlock(&(smi_info->msg_lock)); return rv; @@ -766,6 +782,29 @@ static void set_run_to_completion(void *send_info, int i_run_to_completion) spin_unlock_irqrestore(&(smi_info->si_lock), flags); } +static int ipmi_thread(void *data) +{ + struct smi_info *smi_info = data; + unsigned long flags; + enum si_sm_result smi_result; + + set_user_nice(current, 19); + while (!kthread_should_stop()) { + spin_lock_irqsave(&(smi_info->si_lock), flags); + smi_result=smi_event_handler(smi_info, 0); + spin_unlock_irqrestore(&(smi_info->si_lock), flags); + if (smi_result == SI_SM_CALL_WITHOUT_DELAY) { + /* do nothing */ + } + else if (smi_result == SI_SM_CALL_WITH_DELAY) + udelay(1); + else + schedule_timeout_interruptible(1); + } + return 0; +} + + static void poll(void *send_info) { struct smi_info *smi_info = send_info; @@ -819,15 +858,13 @@ static void smi_timeout(unsigned long data) enum si_sm_result smi_result; unsigned long flags; unsigned long jiffies_now; - unsigned long time_diff; + long time_diff; #ifdef DEBUG_TIMING struct timeval t; #endif - if (smi_info->stop_operation) { - smi_info->timer_stopped = 1; + if (atomic_read(&smi_info->stop_operation)) return; - } spin_lock_irqsave(&(smi_info->si_lock), flags); #ifdef DEBUG_TIMING @@ -835,7 +872,7 @@ static void smi_timeout(unsigned long data) printk("**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif jiffies_now = jiffies; - time_diff = ((jiffies_now - smi_info->last_timeout_jiffies) + time_diff = (((long)jiffies_now - (long)smi_info->last_timeout_jiffies) * SI_USEC_PER_JIFFY); smi_result = smi_event_handler(smi_info, time_diff); @@ -900,7 +937,7 @@ static irqreturn_t si_irq_handler(int irq, void *data, struct pt_regs *regs) smi_info->interrupts++; spin_unlock(&smi_info->count_lock); - if (smi_info->stop_operation) + if (atomic_read(&smi_info->stop_operation)) goto out; #ifdef DEBUG_TIMING @@ -1419,7 +1456,7 @@ static u32 ipmi_acpi_gpe(void *context) smi_info->interrupts++; spin_unlock(&smi_info->count_lock); - if (smi_info->stop_operation) + if (atomic_read(&smi_info->stop_operation)) goto out; #ifdef DEBUG_TIMING @@ -1919,7 +1956,8 @@ static int try_get_dev_id(struct smi_info *smi_info) smi_result = smi_info->handlers->event(smi_info->si_sm, 0); for (;;) { - if (smi_result == SI_SM_CALL_WITH_DELAY) { + if (smi_result == SI_SM_CALL_WITH_DELAY || + smi_result == SI_SM_CALL_WITH_TICK_DELAY) { schedule_timeout_uninterruptible(1); smi_result = smi_info->handlers->event( smi_info->si_sm, 100); @@ -2052,6 +2090,9 @@ static int oem_data_avail_to_receive_msg_avail(struct smi_info *smi_info) * IPMI Version = 0x51 IPMI 1.5 * Manufacturer ID = A2 02 00 Dell IANA * + * Additionally, PowerEdge systems with IPMI < 1.5 may also assert + * OEM0_DATA_AVAIL and needs to be treated as RECEIVE_MSG_AVAIL. + * */ #define DELL_POWEREDGE_8G_BMC_DEVICE_ID 0x20 #define DELL_POWEREDGE_8G_BMC_DEVICE_REV 0x80 @@ -2061,16 +2102,87 @@ static void setup_dell_poweredge_oem_data_handler(struct smi_info *smi_info) { struct ipmi_device_id *id = &smi_info->device_id; const char mfr[3]=DELL_IANA_MFR_ID; - if (! memcmp(mfr, id->manufacturer_id, sizeof(mfr)) - && (id->device_id == DELL_POWEREDGE_8G_BMC_DEVICE_ID) - && (id->device_revision == DELL_POWEREDGE_8G_BMC_DEVICE_REV) - && (id->ipmi_version == DELL_POWEREDGE_8G_BMC_IPMI_VERSION)) - { - smi_info->oem_data_avail_handler = - oem_data_avail_to_receive_msg_avail; + if (! memcmp(mfr, id->manufacturer_id, sizeof(mfr))) { + if (id->device_id == DELL_POWEREDGE_8G_BMC_DEVICE_ID && + id->device_revision == DELL_POWEREDGE_8G_BMC_DEVICE_REV && + id->ipmi_version == DELL_POWEREDGE_8G_BMC_IPMI_VERSION) { + smi_info->oem_data_avail_handler = + oem_data_avail_to_receive_msg_avail; + } + else if (ipmi_version_major(id) < 1 || + (ipmi_version_major(id) == 1 && + ipmi_version_minor(id) < 5)) { + smi_info->oem_data_avail_handler = + oem_data_avail_to_receive_msg_avail; + } } } +#define CANNOT_RETURN_REQUESTED_LENGTH 0xCA +static void return_hosed_msg_badsize(struct smi_info *smi_info) +{ + struct ipmi_smi_msg *msg = smi_info->curr_msg; + + /* Make it a reponse */ + msg->rsp[0] = msg->data[0] | 4; + msg->rsp[1] = msg->data[1]; + msg->rsp[2] = CANNOT_RETURN_REQUESTED_LENGTH; + msg->rsp_size = 3; + smi_info->curr_msg = NULL; + deliver_recv_msg(smi_info, msg); +} + +/* + * dell_poweredge_bt_xaction_handler + * @info - smi_info.device_id must be populated + * + * Dell PowerEdge servers with the BT interface (x6xx and 1750) will + * not respond to a Get SDR command if the length of the data + * requested is exactly 0x3A, which leads to command timeouts and no + * data returned. This intercepts such commands, and causes userspace + * callers to try again with a different-sized buffer, which succeeds. + */ + +#define STORAGE_NETFN 0x0A +#define STORAGE_CMD_GET_SDR 0x23 +static int dell_poweredge_bt_xaction_handler(struct notifier_block *self, + unsigned long unused, + void *in) +{ + struct smi_info *smi_info = in; + unsigned char *data = smi_info->curr_msg->data; + unsigned int size = smi_info->curr_msg->data_size; + if (size >= 8 && + (data[0]>>2) == STORAGE_NETFN && + data[1] == STORAGE_CMD_GET_SDR && + data[7] == 0x3A) { + return_hosed_msg_badsize(smi_info); + return NOTIFY_STOP; + } + return NOTIFY_DONE; +} + +static struct notifier_block dell_poweredge_bt_xaction_notifier = { + .notifier_call = dell_poweredge_bt_xaction_handler, +}; + +/* + * setup_dell_poweredge_bt_xaction_handler + * @info - smi_info.device_id must be filled in already + * + * Fills in smi_info.device_id.start_transaction_pre_hook + * when we know what function to use there. + */ +static void +setup_dell_poweredge_bt_xaction_handler(struct smi_info *smi_info) +{ + struct ipmi_device_id *id = &smi_info->device_id; + const char mfr[3]=DELL_IANA_MFR_ID; + if (! memcmp(mfr, id->manufacturer_id, sizeof(mfr)) && + smi_info->si_type == SI_BT) + register_xaction_notifier(&dell_poweredge_bt_xaction_notifier); +} + /* * setup_oem_data_handler * @info - smi_info.device_id must be filled in already @@ -2084,6 +2196,18 @@ static void setup_oem_data_handler(struct smi_info *smi_info) setup_dell_poweredge_oem_data_handler(smi_info); } +static void setup_xaction_handlers(struct smi_info *smi_info) +{ + setup_dell_poweredge_bt_xaction_handler(smi_info); +} + +static inline void wait_for_timer_and_thread(struct smi_info *smi_info) +{ + if (smi_info->thread != ERR_PTR(-ENOMEM)) + kthread_stop(smi_info->thread); + del_timer_sync(&smi_info->si_timer); +} + /* Returns 0 if initialized, or negative on an error. */ static int init_one_smi(int intf_num, struct smi_info **smi) { @@ -2179,6 +2303,7 @@ static int init_one_smi(int intf_num, struct smi_info **smi) goto out_err; setup_oem_data_handler(new_smi); + setup_xaction_handlers(new_smi); /* Try to claim any interrupts. */ new_smi->irq_setup(new_smi); @@ -2190,8 +2315,8 @@ static int init_one_smi(int intf_num, struct smi_info **smi) new_smi->run_to_completion = 0; new_smi->interrupt_disabled = 0; - new_smi->timer_stopped = 0; - new_smi->stop_operation = 0; + atomic_set(&new_smi->stop_operation, 0); + new_smi->intf_num = intf_num; /* Start clearing the flags before we enable interrupts or the timer to avoid racing with the timer. */ @@ -2209,7 +2334,11 @@ static int init_one_smi(int intf_num, struct smi_info **smi) new_smi->si_timer.function = smi_timeout; new_smi->last_timeout_jiffies = jiffies; new_smi->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES; + add_timer(&(new_smi->si_timer)); + if (new_smi->si_type != SI_BT) + new_smi->thread = kthread_run(ipmi_thread, new_smi, + "kipmi%d", new_smi->intf_num); rv = ipmi_register_smi(&handlers, new_smi, @@ -2251,12 +2380,8 @@ static int init_one_smi(int intf_num, struct smi_info **smi) return 0; out_err_stop_timer: - new_smi->stop_operation = 1; - - /* Wait for the timer to stop. This avoids problems with race - conditions removing the timer here. */ - while (!new_smi->timer_stopped) - schedule_timeout_uninterruptible(1); + atomic_inc(&new_smi->stop_operation); + wait_for_timer_and_thread(new_smi); out_err: if (new_smi->intf) @@ -2362,8 +2487,7 @@ static void __exit cleanup_one_si(struct smi_info *to_clean) spin_lock_irqsave(&(to_clean->si_lock), flags); spin_lock(&(to_clean->msg_lock)); - to_clean->stop_operation = 1; - + atomic_inc(&to_clean->stop_operation); to_clean->irq_cleanup(to_clean); spin_unlock(&(to_clean->msg_lock)); @@ -2374,10 +2498,7 @@ static void __exit cleanup_one_si(struct smi_info *to_clean) interrupt. */ synchronize_sched(); - /* Wait for the timer to stop. This avoids problems with race - conditions removing the timer here. */ - while (!to_clean->timer_stopped) - schedule_timeout_uninterruptible(1); + wait_for_timer_and_thread(to_clean); /* Interrupts and timeouts are stopped, now make sure the interface is in a clean state. */ diff --git a/drivers/char/ipmi/ipmi_si_sm.h b/drivers/char/ipmi/ipmi_si_sm.h index 62791dd429856d3755fe4898e83791b25dabaca3..bf3d4962d6a5973c51d99f21cb7b5de0ad2be867 100644 --- a/drivers/char/ipmi/ipmi_si_sm.h +++ b/drivers/char/ipmi/ipmi_si_sm.h @@ -62,6 +62,7 @@ enum si_sm_result { SI_SM_CALL_WITHOUT_DELAY, /* Call the driver again immediately */ SI_SM_CALL_WITH_DELAY, /* Delay some before calling again. */ + SI_SM_CALL_WITH_TICK_DELAY, /* Delay at least 1 tick before calling again. */ SI_SM_TRANSACTION_COMPLETE, /* A transaction is finished. */ SI_SM_IDLE, /* The SM is in idle state. */ SI_SM_HOSED, /* The hardware violated the state machine. */ diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c index add2aa2732f0c56c4324088a1a18b08ec08c7b9a..39d7e5ef1a2ba82ff6d9b3526f397b0e2184a550 100644 --- a/drivers/char/ipmi/ipmi_smic_sm.c +++ b/drivers/char/ipmi/ipmi_smic_sm.c @@ -43,6 +43,8 @@ #include /* For printk. */ #include +#include +#include #include /* for completion codes */ #include "ipmi_si_sm.h" @@ -56,6 +58,8 @@ #define SMIC_DEBUG_ENABLE 1 static int smic_debug = 1; +module_param(smic_debug, int, 0644); +MODULE_PARM_DESC(smic_debug, "debug bitmask, 1=enable, 2=messages, 4=states"); enum smic_states { SMIC_IDLE, @@ -76,11 +80,17 @@ enum smic_states { #define SMIC_MAX_ERROR_RETRIES 3 /* Timeouts in microseconds. */ -#define SMIC_RETRY_TIMEOUT 100000 +#define SMIC_RETRY_TIMEOUT 2000000 /* SMIC Flags Register Bits */ #define SMIC_RX_DATA_READY 0x80 #define SMIC_TX_DATA_READY 0x40 +/* + * SMIC_SMI and SMIC_EVM_DATA_AVAIL are only used by + * a few systems, and then only by Systems Management + * Interrupts, not by the OS. Always ignore these bits. + * + */ #define SMIC_SMI 0x10 #define SMIC_EVM_DATA_AVAIL 0x08 #define SMIC_SMS_DATA_AVAIL 0x04 @@ -364,8 +374,7 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) switch (smic->state) { case SMIC_IDLE: /* in IDLE we check for available messages */ - if (flags & (SMIC_SMI | - SMIC_EVM_DATA_AVAIL | SMIC_SMS_DATA_AVAIL)) + if (flags & SMIC_SMS_DATA_AVAIL) { return SI_SM_ATTN; } diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 2da64bf7469c6963e008e6215c610dae78dd3e3a..1f3159eb1ede18fd146a23c6d14e670acb75860c 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -47,6 +47,9 @@ #include #include #include +#include +#include +#include #ifdef CONFIG_X86_LOCAL_APIC #include #endif @@ -158,27 +161,120 @@ static struct fasync_struct *fasync_q = NULL; static char pretimeout_since_last_heartbeat = 0; static char expect_close; +static DECLARE_RWSEM(register_sem); + +/* Parameters to ipmi_set_timeout */ +#define IPMI_SET_TIMEOUT_NO_HB 0 +#define IPMI_SET_TIMEOUT_HB_IF_NECESSARY 1 +#define IPMI_SET_TIMEOUT_FORCE_HB 2 + +static int ipmi_set_timeout(int do_heartbeat); + /* If true, the driver will start running as soon as it is configured and ready. */ static int start_now = 0; -module_param(timeout, int, 0); +static int set_param_int(const char *val, struct kernel_param *kp) +{ + char *endp; + int l; + int rv = 0; + + if (!val) + return -EINVAL; + l = simple_strtoul(val, &endp, 0); + if (endp == val) + return -EINVAL; + + down_read(®ister_sem); + *((int *)kp->arg) = l; + if (watchdog_user) + rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); + up_read(®ister_sem); + + return rv; +} + +static int get_param_int(char *buffer, struct kernel_param *kp) +{ + return sprintf(buffer, "%i", *((int *)kp->arg)); +} + +typedef int (*action_fn)(const char *intval, char *outval); + +static int action_op(const char *inval, char *outval); +static int preaction_op(const char *inval, char *outval); +static int preop_op(const char *inval, char *outval); +static void check_parms(void); + +static int set_param_str(const char *val, struct kernel_param *kp) +{ + action_fn fn = (action_fn) kp->arg; + int rv = 0; + const char *end; + char valcp[16]; + int len; + + /* Truncate leading and trailing spaces. */ + while (isspace(*val)) + val++; + end = val + strlen(val) - 1; + while ((end >= val) && isspace(*end)) + end--; + len = end - val + 1; + if (len > sizeof(valcp) - 1) + return -EINVAL; + memcpy(valcp, val, len); + valcp[len] = '\0'; + + down_read(®ister_sem); + rv = fn(valcp, NULL); + if (rv) + goto out_unlock; + + check_parms(); + if (watchdog_user) + rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); + + out_unlock: + up_read(®ister_sem); + return rv; +} + +static int get_param_str(char *buffer, struct kernel_param *kp) +{ + action_fn fn = (action_fn) kp->arg; + int rv; + + rv = fn(NULL, buffer); + if (rv) + return rv; + return strlen(buffer); +} + +module_param_call(timeout, set_param_int, get_param_int, &timeout, 0644); MODULE_PARM_DESC(timeout, "Timeout value in seconds."); -module_param(pretimeout, int, 0); + +module_param_call(pretimeout, set_param_int, get_param_int, &pretimeout, 0644); MODULE_PARM_DESC(pretimeout, "Pretimeout value in seconds."); -module_param_string(action, action, sizeof(action), 0); + +module_param_call(action, set_param_str, get_param_str, action_op, 0644); MODULE_PARM_DESC(action, "Timeout action. One of: " "reset, none, power_cycle, power_off."); -module_param_string(preaction, preaction, sizeof(preaction), 0); + +module_param_call(preaction, set_param_str, get_param_str, preaction_op, 0644); MODULE_PARM_DESC(preaction, "Pretimeout action. One of: " "pre_none, pre_smi, pre_nmi, pre_int."); -module_param_string(preop, preop, sizeof(preop), 0); + +module_param_call(preop, set_param_str, get_param_str, preop_op, 0644); MODULE_PARM_DESC(preop, "Pretimeout driver operation. One of: " "preop_none, preop_panic, preop_give_data."); + module_param(start_now, int, 0); MODULE_PARM_DESC(start_now, "Set to 1 to start the watchdog as" "soon as the driver is loaded."); -module_param(nowayout, int, 0); + +module_param(nowayout, int, 0644); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); /* Default state of the timer. */ @@ -200,6 +296,8 @@ static int ipmi_start_timer_on_heartbeat = 0; static unsigned char ipmi_version_major; static unsigned char ipmi_version_minor; +/* If a pretimeout occurs, this is used to allow only one panic to happen. */ +static atomic_t preop_panic_excl = ATOMIC_INIT(-1); static int ipmi_heartbeat(void); static void panic_halt_ipmi_heartbeat(void); @@ -294,11 +392,6 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg, return rv; } -/* Parameters to ipmi_set_timeout */ -#define IPMI_SET_TIMEOUT_NO_HB 0 -#define IPMI_SET_TIMEOUT_HB_IF_NECESSARY 1 -#define IPMI_SET_TIMEOUT_FORCE_HB 2 - static int ipmi_set_timeout(int do_heartbeat) { int send_heartbeat_now; @@ -732,8 +825,6 @@ static struct miscdevice ipmi_wdog_miscdev = { .fops = &ipmi_wdog_fops }; -static DECLARE_RWSEM(register_sem); - static void ipmi_wdog_msg_handler(struct ipmi_recv_msg *msg, void *handler_data) { @@ -749,9 +840,10 @@ static void ipmi_wdog_msg_handler(struct ipmi_recv_msg *msg, static void ipmi_wdog_pretimeout_handler(void *handler_data) { if (preaction_val != WDOG_PRETIMEOUT_NONE) { - if (preop_val == WDOG_PREOP_PANIC) - panic("Watchdog pre-timeout"); - else if (preop_val == WDOG_PREOP_GIVE_DATA) { + if (preop_val == WDOG_PREOP_PANIC) { + if (atomic_inc_and_test(&preop_panic_excl)) + panic("Watchdog pre-timeout"); + } else if (preop_val == WDOG_PREOP_GIVE_DATA) { spin_lock(&ipmi_read_lock); data_to_read = 1; wake_up_interruptible(&read_q); @@ -825,7 +917,8 @@ ipmi_nmi(void *dev_id, struct pt_regs *regs, int cpu, int handled) an error and not work unless we re-enable the timer. So do so. */ pretimeout_since_last_heartbeat = 1; - panic(PFX "pre-timeout"); + if (atomic_inc_and_test(&preop_panic_excl)) + panic(PFX "pre-timeout"); } return NOTIFY_DONE; @@ -839,6 +932,7 @@ static struct nmi_handler ipmi_nmi_handler = .handler = ipmi_nmi, .priority = 0, /* Call us last. */ }; +int nmi_handler_registered; #endif static int wdog_reboot_handler(struct notifier_block *this, @@ -921,59 +1015,86 @@ static struct ipmi_smi_watcher smi_watcher = .smi_gone = ipmi_smi_gone }; -static int __init ipmi_wdog_init(void) +static int action_op(const char *inval, char *outval) { - int rv; + if (outval) + strcpy(outval, action); + + if (!inval) + return 0; - if (strcmp(action, "reset") == 0) { + if (strcmp(inval, "reset") == 0) action_val = WDOG_TIMEOUT_RESET; - } else if (strcmp(action, "none") == 0) { + else if (strcmp(inval, "none") == 0) action_val = WDOG_TIMEOUT_NONE; - } else if (strcmp(action, "power_cycle") == 0) { + else if (strcmp(inval, "power_cycle") == 0) action_val = WDOG_TIMEOUT_POWER_CYCLE; - } else if (strcmp(action, "power_off") == 0) { + else if (strcmp(inval, "power_off") == 0) action_val = WDOG_TIMEOUT_POWER_DOWN; - } else { - action_val = WDOG_TIMEOUT_RESET; - printk(KERN_INFO PFX "Unknown action '%s', defaulting to" - " reset\n", action); - } + else + return -EINVAL; + strcpy(action, inval); + return 0; +} + +static int preaction_op(const char *inval, char *outval) +{ + if (outval) + strcpy(outval, preaction); - if (strcmp(preaction, "pre_none") == 0) { + if (!inval) + return 0; + + if (strcmp(inval, "pre_none") == 0) preaction_val = WDOG_PRETIMEOUT_NONE; - } else if (strcmp(preaction, "pre_smi") == 0) { + else if (strcmp(inval, "pre_smi") == 0) preaction_val = WDOG_PRETIMEOUT_SMI; #ifdef HAVE_NMI_HANDLER - } else if (strcmp(preaction, "pre_nmi") == 0) { + else if (strcmp(inval, "pre_nmi") == 0) preaction_val = WDOG_PRETIMEOUT_NMI; #endif - } else if (strcmp(preaction, "pre_int") == 0) { + else if (strcmp(inval, "pre_int") == 0) preaction_val = WDOG_PRETIMEOUT_MSG_INT; - } else { - preaction_val = WDOG_PRETIMEOUT_NONE; - printk(KERN_INFO PFX "Unknown preaction '%s', defaulting to" - " none\n", preaction); - } + else + return -EINVAL; + strcpy(preaction, inval); + return 0; +} + +static int preop_op(const char *inval, char *outval) +{ + if (outval) + strcpy(outval, preop); - if (strcmp(preop, "preop_none") == 0) { + if (!inval) + return 0; + + if (strcmp(inval, "preop_none") == 0) preop_val = WDOG_PREOP_NONE; - } else if (strcmp(preop, "preop_panic") == 0) { + else if (strcmp(inval, "preop_panic") == 0) preop_val = WDOG_PREOP_PANIC; - } else if (strcmp(preop, "preop_give_data") == 0) { + else if (strcmp(inval, "preop_give_data") == 0) preop_val = WDOG_PREOP_GIVE_DATA; - } else { - preop_val = WDOG_PREOP_NONE; - printk(KERN_INFO PFX "Unknown preop '%s', defaulting to" - " none\n", preop); - } + else + return -EINVAL; + strcpy(preop, inval); + return 0; +} +static void check_parms(void) +{ #ifdef HAVE_NMI_HANDLER + int do_nmi = 0; + int rv; + if (preaction_val == WDOG_PRETIMEOUT_NMI) { + do_nmi = 1; if (preop_val == WDOG_PREOP_GIVE_DATA) { printk(KERN_WARNING PFX "Pretimeout op is to give data" " but NMI pretimeout is enabled, setting" " pretimeout op to none\n"); - preop_val = WDOG_PREOP_NONE; + preop_op("preop_none", NULL); + do_nmi = 0; } #ifdef CONFIG_X86_LOCAL_APIC if (nmi_watchdog == NMI_IO_APIC) { @@ -983,18 +1104,48 @@ static int __init ipmi_wdog_init(void) " Disabling IPMI nmi pretimeout.\n", nmi_watchdog); preaction_val = WDOG_PRETIMEOUT_NONE; - } else { + do_nmi = 0; + } #endif + } + if (do_nmi && !nmi_handler_registered) { rv = request_nmi(&ipmi_nmi_handler); if (rv) { - printk(KERN_WARNING PFX "Can't register nmi handler\n"); - return rv; - } -#ifdef CONFIG_X86_LOCAL_APIC - } -#endif + printk(KERN_WARNING PFX + "Can't register nmi handler\n"); + return; + } else + nmi_handler_registered = 1; + } else if (!do_nmi && nmi_handler_registered) { + release_nmi(&ipmi_nmi_handler); + nmi_handler_registered = 0; } #endif +} + +static int __init ipmi_wdog_init(void) +{ + int rv; + + if (action_op(action, NULL)) { + action_op("reset", NULL); + printk(KERN_INFO PFX "Unknown action '%s', defaulting to" + " reset\n", action); + } + + if (preaction_op(preaction, NULL)) { + preaction_op("pre_none", NULL); + printk(KERN_INFO PFX "Unknown preaction '%s', defaulting to" + " none\n", preaction); + } + + if (preop_op(preop, NULL)) { + preop_op("preop_none", NULL); + printk(KERN_INFO PFX "Unknown preop '%s', defaulting to" + " none\n", preop); + } + + check_parms(); rv = ipmi_smi_watcher_register(&smi_watcher); if (rv) { @@ -1021,7 +1172,7 @@ static __exit void ipmi_unregister_watchdog(void) down_write(®ister_sem); #ifdef HAVE_NMI_HANDLER - if (preaction_val == WDOG_PRETIMEOUT_NMI) + if (nmi_handler_registered) release_nmi(&ipmi_nmi_handler); #endif diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index e3ddbdb85a2f3d4d6addf22ddc360cfbafa57299..ce3bc0d45f1f0c8fb2794257e5971078688045ac 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -860,10 +860,9 @@ static void __exit istallion_module_exit(void) if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"))) printk("STALLION: failed to un-register serial memory device, " "errno=%d\n", -i); - if (stli_tmpwritebuf != (char *) NULL) - kfree(stli_tmpwritebuf); - if (stli_txcookbuf != (char *) NULL) - kfree(stli_txcookbuf); + + kfree(stli_tmpwritebuf); + kfree(stli_txcookbuf); for (i = 0; (i < stli_nrbrds); i++) { if ((brdp = stli_brds[i]) == (stlibrd_t *) NULL) diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 45d012d85e8c3d436d33c46e1b809f8dee9216d3..3b965a651da4352cf91b91ca6f9a11fd7663929c 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -470,6 +470,8 @@ static struct tty_operations mxser_ops = { .stop = mxser_stop, .start = mxser_start, .hangup = mxser_hangup, + .break_ctl = mxser_rs_break, + .wait_until_sent = mxser_wait_until_sent, .tiocmget = mxser_tiocmget, .tiocmset = mxser_tiocmset, }; @@ -492,14 +494,18 @@ static int __init mxser_module_init(void) static void __exit mxser_module_exit(void) { - int i, err = 0; + int i, err; if (verbose) printk(KERN_DEBUG "Unloading module mxser ...\n"); - if ((err |= tty_unregister_driver(mxvar_sdriver))) + err = tty_unregister_driver(mxvar_sdriver); + if (!err) + put_tty_driver(mxvar_sdriver); + else printk(KERN_ERR "Couldn't unregister MOXA Smartio/Industio family serial driver\n"); + for (i = 0; i < MXSER_BOARDS; i++) { struct pci_dev *pdev; @@ -688,7 +694,6 @@ static int mxser_get_PCI_conf(int busnum, int devnum, int board_type, struct mxs static int mxser_init(void) { int i, m, retval, b, n; - int ret1; struct pci_dev *pdev = NULL; int index; unsigned char busnum, devnum; @@ -722,24 +727,6 @@ static int mxser_init(void) mxvar_sdriver->termios = mxvar_termios; mxvar_sdriver->termios_locked = mxvar_termios_locked; - mxvar_sdriver->open = mxser_open; - mxvar_sdriver->close = mxser_close; - mxvar_sdriver->write = mxser_write; - mxvar_sdriver->put_char = mxser_put_char; - mxvar_sdriver->flush_chars = mxser_flush_chars; - mxvar_sdriver->write_room = mxser_write_room; - mxvar_sdriver->chars_in_buffer = mxser_chars_in_buffer; - mxvar_sdriver->flush_buffer = mxser_flush_buffer; - mxvar_sdriver->ioctl = mxser_ioctl; - mxvar_sdriver->throttle = mxser_throttle; - mxvar_sdriver->unthrottle = mxser_unthrottle; - mxvar_sdriver->set_termios = mxser_set_termios; - mxvar_sdriver->stop = mxser_stop; - mxvar_sdriver->start = mxser_start; - mxvar_sdriver->hangup = mxser_hangup; - mxvar_sdriver->break_ctl = mxser_rs_break; - mxvar_sdriver->wait_until_sent = mxser_wait_until_sent; - mxvar_diagflag = 0; memset(mxvar_table, 0, MXSER_PORTS * sizeof(struct mxser_struct)); memset(&mxvar_log, 0, sizeof(struct mxser_log)); @@ -870,14 +857,11 @@ static int mxser_init(void) } #endif - ret1 = 0; - if (!(ret1 = tty_register_driver(mxvar_sdriver))) { - return 0; - } else + retval = tty_register_driver(mxvar_sdriver); + if (retval) { printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family driver !\n"); + put_tty_driver(mxvar_sdriver); - - if (ret1) { for (i = 0; i < MXSER_BOARDS; i++) { if (mxsercfg[i].board_type == -1) continue; @@ -886,10 +870,10 @@ static int mxser_init(void) //todo: release io, vector } } - return -1; + return retval; } - return (0); + return 0; } static void mxser_do_softint(void *private_) @@ -933,6 +917,9 @@ static int mxser_open(struct tty_struct *tty, struct file *filp) struct mxser_struct *info; int retval, line; + /* initialize driver_data in case something fails */ + tty->driver_data = NULL; + line = tty->index; if (line == MXSER_PORTS) return 0; @@ -995,7 +982,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) if (tty->index == MXSER_PORTS) return; if (!info) - BUG(); + return; spin_lock_irqsave(&info->slock, flags); diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c index 5079beda69b5af142af8e9bfaa4ffd62c635c881..c3660d8781a4ef35e6fce62532d2629bfa4039ab 100644 --- a/drivers/char/n_hdlc.c +++ b/drivers/char/n_hdlc.c @@ -264,8 +264,7 @@ static void n_hdlc_release(struct n_hdlc *n_hdlc) } else break; } - if (n_hdlc->tbuf) - kfree(n_hdlc->tbuf); + kfree(n_hdlc->tbuf); kfree(n_hdlc); } /* end of n_hdlc_release() */ diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 02d7f046c10aeae25e831b2f15f9f85e63a22d99..2c326ea53421be1797e4405e20a69926a51c8e78 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -2994,8 +2994,7 @@ int rx_alloc_buffers(MGSLPC_INFO *info) void rx_free_buffers(MGSLPC_INFO *info) { - if (info->rx_buf) - kfree(info->rx_buf); + kfree(info->rx_buf); info->rx_buf = NULL; } diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 928b850cc679839707c47e44d3e13ab4a06ac09e..d3bc731fbb2773cbe6c94c92505781cb63a0bb50 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -2512,10 +2512,8 @@ static void rp_cleanup_module(void) "rocketport driver\n", -retval); put_tty_driver(rocket_driver); - for (i = 0; i < MAX_RP_PORTS; i++) { - if (rp_table[i]) - kfree(rp_table[i]); - } + for (i = 0; i < MAX_RP_PORTS; i++) + kfree(rp_table[i]); for (i = 0; i < NUM_BOARDS; i++) { if (rcktpt_io_addr[i] <= 0 || is_PCI[i]) diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 63fff7c1244a29941dba32b1047ad63a31644831..a7f099fb7dfed7b86d3d386baa85018215d07b35 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -149,8 +149,22 @@ static void get_rtc_alm_time (struct rtc_time *alm_tm); #ifdef RTC_IRQ static void rtc_dropped_irq(unsigned long data); -static void set_rtc_irq_bit(unsigned char bit); -static void mask_rtc_irq_bit(unsigned char bit); +static void set_rtc_irq_bit_locked(unsigned char bit); +static void mask_rtc_irq_bit_locked(unsigned char bit); + +static inline void set_rtc_irq_bit(unsigned char bit) +{ + spin_lock_irq(&rtc_lock); + set_rtc_irq_bit_locked(bit); + spin_unlock_irq(&rtc_lock); +} + +static void mask_rtc_irq_bit(unsigned char bit) +{ + spin_lock_irq(&rtc_lock); + mask_rtc_irq_bit_locked(bit); + spin_unlock_irq(&rtc_lock); +} #endif static int rtc_proc_open(struct inode *inode, struct file *file); @@ -401,18 +415,19 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) } case RTC_PIE_OFF: /* Mask periodic int. enab. bit */ { - mask_rtc_irq_bit(RTC_PIE); + unsigned long flags; /* can be called from isr via rtc_control() */ + spin_lock_irqsave (&rtc_lock, flags); + mask_rtc_irq_bit_locked(RTC_PIE); if (rtc_status & RTC_TIMER_ON) { - spin_lock_irq (&rtc_lock); rtc_status &= ~RTC_TIMER_ON; del_timer(&rtc_irq_timer); - spin_unlock_irq (&rtc_lock); } + spin_unlock_irqrestore (&rtc_lock, flags); return 0; } case RTC_PIE_ON: /* Allow periodic ints */ { - + unsigned long flags; /* can be called from isr via rtc_control() */ /* * We don't really want Joe User enabling more * than 64Hz of interrupts on a multi-user machine. @@ -421,14 +436,14 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) (!capable(CAP_SYS_RESOURCE))) return -EACCES; + spin_lock_irqsave (&rtc_lock, flags); if (!(rtc_status & RTC_TIMER_ON)) { - spin_lock_irq (&rtc_lock); rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100; add_timer(&rtc_irq_timer); rtc_status |= RTC_TIMER_ON; - spin_unlock_irq (&rtc_lock); } - set_rtc_irq_bit(RTC_PIE); + set_rtc_irq_bit_locked(RTC_PIE); + spin_unlock_irqrestore (&rtc_lock, flags); return 0; } case RTC_UIE_OFF: /* Mask ints from RTC updates. */ @@ -609,6 +624,7 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) { int tmp = 0; unsigned char val; + unsigned long flags; /* can be called from isr via rtc_control() */ /* * The max we can do is 8192Hz. @@ -631,9 +647,9 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) if (arg != (1<tty != (struct tty_struct *) NULL) stl_hangup(portp->tty); - if (portp->tx.buf != (char *) NULL) - kfree(portp->tx.buf); + kfree(portp->tx.buf); kfree(portp); } kfree(panelp); diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 0133dc0e25d087cfd4cabedb261d28f0572fdd98..5d1ffa3bd4c3e0bd7d9a39e1cfc68ebbfb7c515c 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -4016,9 +4016,7 @@ static int mgsl_alloc_intermediate_rxbuffer_memory(struct mgsl_struct *info) */ static void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info) { - if ( info->intermediate_rxbuffer ) - kfree(info->intermediate_rxbuffer); - + kfree(info->intermediate_rxbuffer); info->intermediate_rxbuffer = NULL; } /* end of mgsl_free_intermediate_rxbuffer_memory() */ @@ -4072,10 +4070,8 @@ static void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info) int i; for ( i=0; inum_tx_holding_buffers; ++i ) { - if ( info->tx_holding_buffers[i].buffer ) { - kfree(info->tx_holding_buffers[i].buffer); - info->tx_holding_buffers[i].buffer=NULL; - } + kfree(info->tx_holding_buffers[i].buffer); + info->tx_holding_buffers[i].buffer = NULL; } info->get_tx_holding_index = 0; diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index f185724448b142e6da58b3761e10ac74f85f9a05..7c063c5abc5596532b5aa2aec0c4586d40253210 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -2788,10 +2788,8 @@ static void shutdown(SLMP_INFO * info) del_timer(&info->tx_timer); del_timer(&info->status_timer); - if (info->tx_buf) { - kfree(info->tx_buf); - info->tx_buf = NULL; - } + kfree(info->tx_buf); + info->tx_buf = NULL; spin_lock_irqsave(&info->lock,flags); @@ -3611,8 +3609,7 @@ int alloc_tmp_rx_buf(SLMP_INFO *info) void free_tmp_rx_buf(SLMP_INFO *info) { - if (info->tmp_rx_buf) - kfree(info->tmp_rx_buf); + kfree(info->tmp_rx_buf); info->tmp_rx_buf = NULL; } diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 8d125c974a2d4d7f92a0f5f4b9aa39b6d6f3bc45..680a8e3318877b6c6bd7f09ae61d46abd5605871 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -287,10 +287,6 @@ static int __init init_nsc(void) int lo, hi; int nscAddrBase = TPM_ADDR; - driver_register(&nsc_drv); - - /* select PM channel 1 */ - tpm_write_index(nscAddrBase,NSC_LDN_INDEX, 0x12); /* verify that it is a National part (SID) */ if (tpm_read_index(TPM_ADDR, NSC_SID_INDEX) != 0xEF) { @@ -300,6 +296,8 @@ static int __init init_nsc(void) return -ENODEV; } + driver_register(&nsc_drv); + hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI); lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO); tpm_nsc.base = (hi<<8) | lo; @@ -307,11 +305,11 @@ static int __init init_nsc(void) /* enable the DPM module */ tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01); - pdev = kmalloc(sizeof(struct platform_device), GFP_KERNEL); - if ( !pdev ) - return -ENOMEM; - - memset(pdev, 0, sizeof(struct platform_device)); + pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL); + if (!pdev) { + rc = -ENOMEM; + goto err_unreg_drv; + } pdev->name = "tpm_nscl0"; pdev->id = -1; @@ -319,26 +317,16 @@ static int __init init_nsc(void) pdev->dev.release = tpm_nsc_remove; pdev->dev.driver = &nsc_drv; - if ((rc=platform_device_register(pdev)) < 0) { - kfree(pdev); - pdev = NULL; - return rc; - } + if ((rc = platform_device_register(pdev)) < 0) + goto err_free_dev; if (request_region(tpm_nsc.base, 2, "tpm_nsc0") == NULL ) { - platform_device_unregister(pdev); - kfree(pdev); - pdev = NULL; - return -EBUSY; + rc = -EBUSY; + goto err_unreg_dev; } - if ((rc = tpm_register_hardware(&pdev->dev, &tpm_nsc)) < 0) { - release_region(tpm_nsc.base, 2); - platform_device_unregister(pdev); - kfree(pdev); - pdev = NULL; - return rc; - } + if ((rc = tpm_register_hardware(&pdev->dev, &tpm_nsc)) < 0) + goto err_rel_reg; dev_dbg(&pdev->dev, "NSC TPM detected\n"); dev_dbg(&pdev->dev, @@ -374,6 +362,16 @@ static int __init init_nsc(void) tpm_read_index(nscAddrBase, 0x27) & 0x1F); return 0; + +err_rel_reg: + release_region(tpm_nsc.base, 2); +err_unreg_dev: + platform_device_unregister(pdev); +err_free_dev: + kfree(pdev); +err_unreg_drv: + driver_unregister(&nsc_drv); + return rc; } static void __exit cleanup_nsc(void) diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index c586bfa852eec510c2e486a331e4564655791fab..4b1eef51ec5926d97918331f20740c3664067375 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1416,14 +1416,11 @@ static int init_dev(struct tty_driver *driver, int idx, /* Release locally allocated memory ... nothing placed in slots */ free_mem_out: - if (o_tp) - kfree(o_tp); + kfree(o_tp); if (o_tty) free_tty_struct(o_tty); - if (ltp) - kfree(ltp); - if (tp) - kfree(tp); + kfree(ltp); + kfree(tp); free_tty_struct(tty); fail_no_mem: diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index 003dda147cd093a226d52a485d7b98d64186874d..24011e7c81ff72fa6bade2d7c889c8a0c2c48c5a 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -80,6 +80,9 @@ do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_str if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) return -EFAULT; + if (!capable(CAP_SYS_TTY_CONFIG)) + perm = 0; + switch (cmd) { case KDGKBENT: key_map = key_maps[s]; @@ -193,7 +196,7 @@ do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) int ret; if (!capable(CAP_SYS_TTY_CONFIG)) - return -EPERM; + perm = 0; kbs = kmalloc(sizeof(*kbs), GFP_KERNEL); if (!kbs) { diff --git a/drivers/connector/Kconfig b/drivers/connector/Kconfig index 0bc2059c1e088b4e618ca18bf37f61948719ba6f..e0bdc0db9640e51647dda54472a5919eb3b0ec45 100644 --- a/drivers/connector/Kconfig +++ b/drivers/connector/Kconfig @@ -10,4 +10,12 @@ config CONNECTOR Connector support can also be built as a module. If so, the module will be called cn.ko. +config PROC_EVENTS + boolean "Report process events to userspace" + depends on CONNECTOR=y + default y + ---help--- + Provide a connector that reports process events to userspace. Send + events such as fork, exec, id change (uid, gid, suid, etc), and exit. + endmenu diff --git a/drivers/connector/Makefile b/drivers/connector/Makefile index 12ca79e8234d3fbe10226316a404d7bbb0cbf82b..1f255e46e9164128e432481bafae04197a23f2a3 100644 --- a/drivers/connector/Makefile +++ b/drivers/connector/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_CONNECTOR) += cn.o +obj-$(CONFIG_PROC_EVENTS) += cn_proc.o cn-y += cn_queue.o connector.o diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c new file mode 100644 index 0000000000000000000000000000000000000000..fcdf0fff13a6cc449e431957e061e67d253eefbe --- /dev/null +++ b/drivers/connector/cn_proc.c @@ -0,0 +1,222 @@ +/* + * cn_proc.c - process events connector + * + * Copyright (C) Matt Helsley, IBM Corp. 2005 + * Based on cn_fork.c by Guillaume Thouvenin + * Original copyright notice follows: + * Copyright (C) 2005 BULL SA. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include + +#define CN_PROC_MSG_SIZE (sizeof(struct cn_msg) + sizeof(struct proc_event)) + +static atomic_t proc_event_num_listeners = ATOMIC_INIT(0); +static struct cb_id cn_proc_event_id = { CN_IDX_PROC, CN_VAL_PROC }; + +/* proc_counts is used as the sequence number of the netlink message */ +static DEFINE_PER_CPU(__u32, proc_event_counts) = { 0 }; + +static inline void get_seq(__u32 *ts, int *cpu) +{ + *ts = get_cpu_var(proc_event_counts)++; + *cpu = smp_processor_id(); + put_cpu_var(proc_counts); +} + +void proc_fork_connector(struct task_struct *task) +{ + struct cn_msg *msg; + struct proc_event *ev; + __u8 buffer[CN_PROC_MSG_SIZE]; + + if (atomic_read(&proc_event_num_listeners) < 1) + return; + + msg = (struct cn_msg*)buffer; + ev = (struct proc_event*)msg->data; + get_seq(&msg->seq, &ev->cpu); + ev->what = PROC_EVENT_FORK; + ev->event_data.fork.parent_pid = task->real_parent->pid; + ev->event_data.fork.parent_tgid = task->real_parent->tgid; + ev->event_data.fork.child_pid = task->pid; + ev->event_data.fork.child_tgid = task->tgid; + + memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); + msg->ack = 0; /* not used */ + msg->len = sizeof(*ev); + /* If cn_netlink_send() failed, the data is not sent */ + cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); +} + +void proc_exec_connector(struct task_struct *task) +{ + struct cn_msg *msg; + struct proc_event *ev; + __u8 buffer[CN_PROC_MSG_SIZE]; + + if (atomic_read(&proc_event_num_listeners) < 1) + return; + + msg = (struct cn_msg*)buffer; + ev = (struct proc_event*)msg->data; + get_seq(&msg->seq, &ev->cpu); + ev->what = PROC_EVENT_EXEC; + ev->event_data.exec.process_pid = task->pid; + ev->event_data.exec.process_tgid = task->tgid; + + memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); + msg->ack = 0; /* not used */ + msg->len = sizeof(*ev); + cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); +} + +void proc_id_connector(struct task_struct *task, int which_id) +{ + struct cn_msg *msg; + struct proc_event *ev; + __u8 buffer[CN_PROC_MSG_SIZE]; + + if (atomic_read(&proc_event_num_listeners) < 1) + return; + + msg = (struct cn_msg*)buffer; + ev = (struct proc_event*)msg->data; + ev->what = which_id; + ev->event_data.id.process_pid = task->pid; + ev->event_data.id.process_tgid = task->tgid; + if (which_id == PROC_EVENT_UID) { + ev->event_data.id.r.ruid = task->uid; + ev->event_data.id.e.euid = task->euid; + } else if (which_id == PROC_EVENT_GID) { + ev->event_data.id.r.rgid = task->gid; + ev->event_data.id.e.egid = task->egid; + } else + return; + get_seq(&msg->seq, &ev->cpu); + + memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); + msg->ack = 0; /* not used */ + msg->len = sizeof(*ev); + cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); +} + +void proc_exit_connector(struct task_struct *task) +{ + struct cn_msg *msg; + struct proc_event *ev; + __u8 buffer[CN_PROC_MSG_SIZE]; + + if (atomic_read(&proc_event_num_listeners) < 1) + return; + + msg = (struct cn_msg*)buffer; + ev = (struct proc_event*)msg->data; + get_seq(&msg->seq, &ev->cpu); + ev->what = PROC_EVENT_EXIT; + ev->event_data.exit.process_pid = task->pid; + ev->event_data.exit.process_tgid = task->tgid; + ev->event_data.exit.exit_code = task->exit_code; + ev->event_data.exit.exit_signal = task->exit_signal; + + memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); + msg->ack = 0; /* not used */ + msg->len = sizeof(*ev); + cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); +} + +/* + * Send an acknowledgement message to userspace + * + * Use 0 for success, EFOO otherwise. + * Note: this is the negative of conventional kernel error + * values because it's not being returned via syscall return + * mechanisms. + */ +static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack) +{ + struct cn_msg *msg; + struct proc_event *ev; + __u8 buffer[CN_PROC_MSG_SIZE]; + + if (atomic_read(&proc_event_num_listeners) < 1) + return; + + msg = (struct cn_msg*)buffer; + ev = (struct proc_event*)msg->data; + msg->seq = rcvd_seq; + ev->cpu = -1; + ev->what = PROC_EVENT_NONE; + ev->event_data.ack.err = err; + memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); + msg->ack = rcvd_ack + 1; + msg->len = sizeof(*ev); + cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); +} + +/** + * cn_proc_mcast_ctl + * @data: message sent from userspace via the connector + */ +static void cn_proc_mcast_ctl(void *data) +{ + struct cn_msg *msg = data; + enum proc_cn_mcast_op *mc_op = NULL; + int err = 0; + + if (msg->len != sizeof(*mc_op)) + return; + + mc_op = (enum proc_cn_mcast_op*)msg->data; + switch (*mc_op) { + case PROC_CN_MCAST_LISTEN: + atomic_inc(&proc_event_num_listeners); + break; + case PROC_CN_MCAST_IGNORE: + atomic_dec(&proc_event_num_listeners); + break; + default: + err = EINVAL; + break; + } + cn_proc_ack(err, msg->seq, msg->ack); +} + +/* + * cn_proc_init - initialization entry point + * + * Adds the connector callback to the connector driver. + */ +static int __init cn_proc_init(void) +{ + int err; + + if ((err = cn_add_callback(&cn_proc_event_id, "cn_proc", + &cn_proc_mcast_ctl))) { + printk(KERN_WARNING "cn_proc failed to register\n"); + return err; + } + return 0; +} + +module_init(cn_proc_init); diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 6c6121b85a54ba36168a73a737a0163e179f79a7..25acf478c9e82c5f2d40cd6c89e9c8fcdb2862be 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -593,12 +593,11 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) goto module_out; } - policy = kmalloc(sizeof(struct cpufreq_policy), GFP_KERNEL); + policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL); if (!policy) { ret = -ENOMEM; goto nomem_out; } - memset(policy, 0, sizeof(struct cpufreq_policy)); policy->cpu = cpu; policy->cpus = cpumask_of_cpu(cpu); diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index c1fc9c62bb51d0c1d2620f522d7c6ebbb0f432bc..17741111246b9f21362710cdc1099c31cb69512d 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -48,7 +48,10 @@ * All times here are in uS. */ static unsigned int def_sampling_rate; -#define MIN_SAMPLING_RATE (def_sampling_rate / 2) +#define MIN_SAMPLING_RATE_RATIO (2) +/* for correct statistics, we need at least 10 ticks between each measure */ +#define MIN_STAT_SAMPLING_RATE (MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10)) +#define MIN_SAMPLING_RATE (def_sampling_rate / MIN_SAMPLING_RATE_RATIO) #define MAX_SAMPLING_RATE (500 * def_sampling_rate) #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000) #define DEF_SAMPLING_DOWN_FACTOR (1) @@ -416,13 +419,16 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, if (dbs_enable == 1) { unsigned int latency; /* policy latency is in nS. Convert it to uS first */ + latency = policy->cpuinfo.transition_latency / 1000; + if (latency == 0) + latency = 1; - latency = policy->cpuinfo.transition_latency; - if (latency < 1000) - latency = 1000; - - def_sampling_rate = (latency / 1000) * + def_sampling_rate = latency * DEF_SAMPLING_RATE_LATENCY_MULTIPLIER; + + if (def_sampling_rate < MIN_STAT_SAMPLING_RATE) + def_sampling_rate = MIN_STAT_SAMPLING_RATE; + dbs_tuners_ins.sampling_rate = def_sampling_rate; dbs_tuners_ins.ignore_nice = 0; diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 3597f25d5efa8957a0ee1ed8389131a71675f91d..0bddb8e694d9bbde6acd604c540383e65524e2f9 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -193,11 +193,15 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy, unsigned int cpu = policy->cpu; if (cpufreq_stats_table[cpu]) return -EBUSY; - if ((stat = kmalloc(sizeof(struct cpufreq_stats), GFP_KERNEL)) == NULL) + if ((stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL)) == NULL) return -ENOMEM; - memset(stat, 0, sizeof (struct cpufreq_stats)); data = cpufreq_cpu_get(cpu); + if (data == NULL) { + ret = -EINVAL; + goto error_get_fail; + } + if ((ret = sysfs_create_group(&data->kobj, &stats_attr_group))) goto error_out; @@ -217,12 +221,11 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy, alloc_size += count * count * sizeof(int); #endif stat->max_state = count; - stat->time_in_state = kmalloc(alloc_size, GFP_KERNEL); + stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL); if (!stat->time_in_state) { ret = -ENOMEM; goto error_out; } - memset(stat->time_in_state, 0, alloc_size); stat->freq_table = (unsigned int *)(stat->time_in_state + count); #ifdef CONFIG_CPU_FREQ_STAT_DETAILS @@ -245,6 +248,7 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy, return 0; error_out: cpufreq_cpu_put(data); +error_get_fail: kfree(stat); cpufreq_stats_table[cpu] = NULL; return ret; diff --git a/drivers/dio/dio.c b/drivers/dio/dio.c index a620f7d9ac8e730c4258a1f8e2c5c0d334e488f6..17502d6efae788c2bb614f3833a550de9059a59c 100644 --- a/drivers/dio/dio.c +++ b/drivers/dio/dio.c @@ -224,11 +224,10 @@ static int __init dio_init(void) set_fs(fs); /* Found a board, allocate it an entry in the list */ - dev = kmalloc(sizeof(struct dio_dev), GFP_KERNEL); + dev = kzalloc(sizeof(struct dio_dev), GFP_KERNEL); if (!dev) return 0; - memset(dev, 0, sizeof(struct dio_dev)); dev->bus = &dio_bus; dev->dev.parent = &dio_bus.dev; dev->dev.bus = &dio_bus_type; diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c index 1937743c8e2971bb15b9f1d703aca168be4240e2..4196137e66dea5b9e191b86b6988766985a040ba 100644 --- a/drivers/eisa/eisa-bus.c +++ b/drivers/eisa/eisa-bus.c @@ -281,13 +281,11 @@ static int __init eisa_probe (struct eisa_root_device *root) /* First try to get hold of slot 0. If there is no device * here, simply fail, unless root->force_probe is set. */ - if (!(edev = kmalloc (sizeof (*edev), GFP_KERNEL))) { + if (!(edev = kzalloc (sizeof (*edev), GFP_KERNEL))) { printk (KERN_ERR "EISA: Couldn't allocate mainboard slot\n"); return -ENOMEM; } - memset (edev, 0, sizeof (*edev)); - if (eisa_request_resources (root, edev, 0)) { printk (KERN_WARNING \ "EISA: Cannot allocate resource for mainboard\n"); @@ -317,13 +315,11 @@ static int __init eisa_probe (struct eisa_root_device *root) force_probe: for (c = 0, i = 1; i <= root->slots; i++) { - if (!(edev = kmalloc (sizeof (*edev), GFP_KERNEL))) { + if (!(edev = kzalloc (sizeof (*edev), GFP_KERNEL))) { printk (KERN_ERR "EISA: Out of memory for slot %d\n", i); continue; } - - memset (edev, 0, sizeof (*edev)); if (eisa_request_resources (root, edev, i)) { printk (KERN_WARNING \ diff --git a/drivers/fc4/fc.c b/drivers/fc4/fc.c index e4710d1d1f9d8db1757e84965c2ccbcfcbc8f50a..5c8943509cc1b7b668a784685861c9e9fab94a89 100644 --- a/drivers/fc4/fc.c +++ b/drivers/fc4/fc.c @@ -266,13 +266,12 @@ static void fcp_report_map_done(fc_channel *fc, int i, int status) printk ("FC: Bad magic from REPORT_AL_MAP on %s - %08x\n", fc->name, p->magic); fc->state = FC_STATE_OFFLINE; } else { - fc->posmap = (fcp_posmap *)kmalloc(sizeof(fcp_posmap)+p->len, GFP_KERNEL); + fc->posmap = (fcp_posmap *)kzalloc(sizeof(fcp_posmap)+p->len, GFP_KERNEL); if (!fc->posmap) { printk("FC: Not enough memory, offlining channel\n"); fc->state = FC_STATE_OFFLINE; } else { int k; - memset(fc->posmap, 0, sizeof(fcp_posmap)+p->len); /* FIXME: This is where SOCAL transfers our AL-PA. Keep it here till we found out what other cards do... */ fc->sid = (p->magic & 0xff); @@ -351,14 +350,12 @@ void fcp_register(fc_channel *fc, u8 type, int unregister) fc->dma_scsi_rsp = fc->dma_scsi_cmd + slots * sizeof (fcp_cmd); fc->scsi_bitmap_end = (slots + 63) & ~63; size = fc->scsi_bitmap_end / 8; - fc->scsi_bitmap = kmalloc (size, GFP_KERNEL); - memset (fc->scsi_bitmap, 0, size); + fc->scsi_bitmap = kzalloc (size, GFP_KERNEL); set_bit (0, fc->scsi_bitmap); for (i = fc->can_queue; i < fc->scsi_bitmap_end; i++) set_bit (i, fc->scsi_bitmap); fc->scsi_free = fc->can_queue; - fc->cmd_slots = (fcp_cmnd **)kmalloc(slots * sizeof(fcp_cmnd*), GFP_KERNEL); - memset(fc->cmd_slots, 0, slots * sizeof(fcp_cmnd*)); + fc->cmd_slots = (fcp_cmnd **)kzalloc(slots * sizeof(fcp_cmnd*), GFP_KERNEL); fc->abort_count = 0; } else { fc->scsi_name[0] = 0; @@ -541,12 +538,11 @@ int fcp_initialize(fc_channel *fcchain, int count) FCND(("fcp_inititialize %08lx\n", (long)fcp_init)) FCND(("fc_channels %08lx\n", (long)fc_channels)) FCND((" SID %d DID %d\n", fcchain->sid, fcchain->did)) - l = kmalloc(sizeof (ls) + count, GFP_KERNEL); + l = kzalloc(sizeof (ls) + count, GFP_KERNEL); if (!l) { printk ("FC: Cannot allocate memory for initialization\n"); return -ENOMEM; } - memset (l, 0, sizeof(ls) + count); l->magic = LSMAGIC; l->count = count; FCND(("FCP Init for %d channels\n", count)) @@ -555,17 +551,15 @@ int fcp_initialize(fc_channel *fcchain, int count) l->timer.function = fcp_login_timeout; l->timer.data = (unsigned long)l; atomic_set (&l->todo, count); - l->logi = kmalloc (count * 3 * sizeof(logi), GFP_KERNEL); - l->fcmds = kmalloc (count * sizeof(fcp_cmnd), GFP_KERNEL); + l->logi = kzalloc (count * 3 * sizeof(logi), GFP_KERNEL); + l->fcmds = kzalloc (count * sizeof(fcp_cmnd), GFP_KERNEL); if (!l->logi || !l->fcmds) { - if (l->logi) kfree (l->logi); - if (l->fcmds) kfree (l->fcmds); + kfree (l->logi); + kfree (l->fcmds); kfree (l); printk ("FC: Cannot allocate DMA memory for initialization\n"); return -ENOMEM; } - memset (l->logi, 0, count * 3 * sizeof(logi)); - memset (l->fcmds, 0, count * sizeof(fcp_cmnd)); for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) { fc->state = FC_STATE_UNINITED; fc->rst_pkt = NULL; /* kmalloc when first used */ @@ -678,13 +672,11 @@ int fcp_forceoffline(fc_channel *fcchain, int count) l.timer.function = fcp_login_timeout; l.timer.data = (unsigned long)&l; atomic_set (&l.todo, count); - l.fcmds = kmalloc (count * sizeof(fcp_cmnd), GFP_KERNEL); + l.fcmds = kzalloc (count * sizeof(fcp_cmnd), GFP_KERNEL); if (!l.fcmds) { - kfree (l.fcmds); printk ("FC: Cannot allocate memory for forcing offline\n"); return -ENOMEM; } - memset (l.fcmds, 0, count * sizeof(fcp_cmnd)); FCND(("Initializing OFFLINE packets\n")) for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) { fc->state = FC_STATE_UNINITED; @@ -1114,9 +1106,8 @@ int fc_do_plogi(fc_channel *fc, unsigned char alpa, fc_wwn *node, fc_wwn *nport) logi *l; int status; - l = (logi *)kmalloc(2 * sizeof(logi), GFP_KERNEL); + l = (logi *)kzalloc(2 * sizeof(logi), GFP_KERNEL); if (!l) return -ENOMEM; - memset(l, 0, 2 * sizeof(logi)); l->code = LS_PLOGI; memcpy (&l->nport_wwn, &fc->wwn_nport, sizeof(fc_wwn)); memcpy (&l->node_wwn, &fc->wwn_node, sizeof(fc_wwn)); @@ -1149,9 +1140,8 @@ int fc_do_prli(fc_channel *fc, unsigned char alpa) prli *p; int status; - p = (prli *)kmalloc(2 * sizeof(prli), GFP_KERNEL); + p = (prli *)kzalloc(2 * sizeof(prli), GFP_KERNEL); if (!p) return -ENOMEM; - memset(p, 0, 2 * sizeof(prli)); p->code = LS_PRLI; p->params[0] = 0x08002000; p->params[3] = 0x00000022; diff --git a/drivers/fc4/soc.c b/drivers/fc4/soc.c index 247b4630277748acd536e142270cf3b5f4214002..ec1f94738c59712d47091ff38a8a8cc8ac66f2ea 100644 --- a/drivers/fc4/soc.c +++ b/drivers/fc4/soc.c @@ -556,10 +556,9 @@ static inline void soc_init(struct sbus_dev *sdev, int no) int size, i; int irq; - s = kmalloc (sizeof (struct soc), GFP_KERNEL); + s = kzalloc (sizeof (struct soc), GFP_KERNEL); if (s == NULL) return; - memset (s, 0, sizeof(struct soc)); spin_lock_init(&s->lock); s->soc_no = no; diff --git a/drivers/fc4/socal.c b/drivers/fc4/socal.c index b2377dbd84a14223f2aa8ef5340388e7593fb883..922e9613b2cf547fe6c708d2c5a7aab4af1d33fc 100644 --- a/drivers/fc4/socal.c +++ b/drivers/fc4/socal.c @@ -665,9 +665,8 @@ static inline void socal_init(struct sbus_dev *sdev, int no) int size, i; int irq, node; - s = kmalloc (sizeof (struct socal), GFP_KERNEL); + s = kzalloc (sizeof (struct socal), GFP_KERNEL); if (!s) return; - memset (s, 0, sizeof(struct socal)); spin_lock_init(&s->lock); s->socal_no = no; diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c index 125929c9048f0be47b4e59543d79a5b62a0e0ff6..ba17292eb2902b5c7acb676beeb7fb840813414a 100644 --- a/drivers/firmware/dell_rbu.c +++ b/drivers/firmware/dell_rbu.c @@ -50,7 +50,7 @@ MODULE_AUTHOR("Abhay Salunke "); MODULE_DESCRIPTION("Driver for updating BIOS image on DELL systems"); MODULE_LICENSE("GPL"); -MODULE_VERSION("3.0"); +MODULE_VERSION("3.1"); #define BIOS_SCAN_LIMIT 0xffffffff #define MAX_IMAGE_LENGTH 16 @@ -73,6 +73,11 @@ module_param_string(image_type, image_type, sizeof (image_type), 0); MODULE_PARM_DESC(image_type, "BIOS image type. choose- mono or packet or init"); +static unsigned long allocation_floor = 0x100000; +module_param(allocation_floor, ulong, 0644); +MODULE_PARM_DESC(allocation_floor, + "Minimum address for allocations when using Packet mode"); + struct packet_data { struct list_head list; size_t length; @@ -99,61 +104,122 @@ static int create_packet(void *data, size_t length) { struct packet_data *newpacket; int ordernum = 0; + int retval = 0; + unsigned int packet_array_size = 0; + void **invalid_addr_packet_array = 0; + void *packet_data_temp_buf = 0; + unsigned int idx = 0; pr_debug("create_packet: entry \n"); if (!rbu_data.packetsize) { pr_debug("create_packet: packetsize not specified\n"); - return -EINVAL; + retval = -EINVAL; + goto out_noalloc; } + spin_unlock(&rbu_data.lock); - newpacket = kmalloc(sizeof (struct packet_data), GFP_KERNEL); - spin_lock(&rbu_data.lock); + + newpacket = kzalloc(sizeof (struct packet_data), GFP_KERNEL); if (!newpacket) { printk(KERN_WARNING "dell_rbu:%s: failed to allocate new " "packet\n", __FUNCTION__); - return -ENOMEM; + retval = -ENOMEM; + spin_lock(&rbu_data.lock); + goto out_noalloc; } ordernum = get_order(length); + /* - * there is no upper limit on memory - * address for packetized mechanism + * BIOS errata mean we cannot allocate packets below 1MB or they will + * be overwritten by BIOS. + * + * array to temporarily hold packets + * that are below the allocation floor + * + * NOTE: very simplistic because we only need the floor to be at 1MB + * due to BIOS errata. This shouldn't be used for higher floors + * or you will run out of mem trying to allocate the array. */ - spin_unlock(&rbu_data.lock); - newpacket->data = (unsigned char *) __get_free_pages(GFP_KERNEL, - ordernum); - spin_lock(&rbu_data.lock); + packet_array_size = max( + (unsigned int)(allocation_floor / rbu_data.packetsize), + (unsigned int)1); + invalid_addr_packet_array = kzalloc(packet_array_size * sizeof(void*), + GFP_KERNEL); - pr_debug("create_packet: newpacket %p\n", newpacket->data); - - if (!newpacket->data) { + if (!invalid_addr_packet_array) { printk(KERN_WARNING - "dell_rbu:%s: failed to allocate new " - "packet\n", __FUNCTION__); - kfree(newpacket); - return -ENOMEM; + "dell_rbu:%s: failed to allocate " + "invalid_addr_packet_array \n", + __FUNCTION__); + retval = -ENOMEM; + spin_lock(&rbu_data.lock); + goto out_alloc_packet; } + while (!packet_data_temp_buf) { + packet_data_temp_buf = (unsigned char *) + __get_free_pages(GFP_KERNEL, ordernum); + if (!packet_data_temp_buf) { + printk(KERN_WARNING + "dell_rbu:%s: failed to allocate new " + "packet\n", __FUNCTION__); + retval = -ENOMEM; + spin_lock(&rbu_data.lock); + goto out_alloc_packet_array; + } + + if ((unsigned long)virt_to_phys(packet_data_temp_buf) + < allocation_floor) { + pr_debug("packet 0x%lx below floor at 0x%lx.\n", + (unsigned long)virt_to_phys( + packet_data_temp_buf), + allocation_floor); + invalid_addr_packet_array[idx++] = packet_data_temp_buf; + packet_data_temp_buf = 0; + } + } + spin_lock(&rbu_data.lock); + + newpacket->data = packet_data_temp_buf; + + pr_debug("create_packet: newpacket at physical addr %lx\n", + (unsigned long)virt_to_phys(newpacket->data)); + + /* packets may not have fixed size */ + newpacket->length = length; newpacket->ordernum = ordernum; ++rbu_data.num_packets; - /* - * initialize the newly created packet headers - */ + + /* initialize the newly created packet headers */ INIT_LIST_HEAD(&newpacket->list); list_add_tail(&newpacket->list, &packet_data_head.list); - /* - * packets may not have fixed size - */ - newpacket->length = length; memcpy(newpacket->data, data, length); pr_debug("create_packet: exit \n"); - return 0; +out_alloc_packet_array: + /* always free packet array */ + for (;idx>0;idx--) { + pr_debug("freeing unused packet below floor 0x%lx.\n", + (unsigned long)virt_to_phys( + invalid_addr_packet_array[idx-1])); + free_pages((unsigned long)invalid_addr_packet_array[idx-1], + ordernum); + } + kfree(invalid_addr_packet_array); + +out_alloc_packet: + /* if error, free data */ + if (retval) + kfree(newpacket); + +out_noalloc: + return retval; } static int packetize_data(void *data, size_t length) @@ -693,3 +759,6 @@ static __exit void dcdrbu_exit(void) module_exit(dcdrbu_exit); module_init(dcdrbu_init); + +/* vim:noet:ts=8:sw=8 +*/ diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index 6996476669f17397d1f9b1cab8e8b2f2a094cb6d..b4502ed65793a01a198b666ecba4fc7e45ac286a 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -715,7 +715,6 @@ edd_device_register(struct edd_device *edev, int i) if (!edev) return 1; - memset(edev, 0, sizeof (*edev)); edd_dev_set_info(edev, i); kobject_set_name(&edev->kobj, "int13_dev%02x", 0x80 + i); @@ -756,7 +755,7 @@ edd_init(void) return rc; for (i = 0; i < edd_num_devices() && !rc; i++) { - edev = kmalloc(sizeof (*edev), GFP_KERNEL); + edev = kzalloc(sizeof (*edev), GFP_KERNEL); if (!edev) return -ENOMEM; diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index 33b17c6a46fb9a32e7c84b94b6b7970f9862fe45..bda5bce681b6bbdf0962c39e50cc3e8b4c3e1877 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -614,16 +614,14 @@ efivar_create_sysfs_entry(unsigned long variable_name_size, char *short_name; struct efivar_entry *new_efivar; - short_name = kmalloc(short_name_size + 1, GFP_KERNEL); - new_efivar = kmalloc(sizeof(struct efivar_entry), GFP_KERNEL); + short_name = kzalloc(short_name_size + 1, GFP_KERNEL); + new_efivar = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL); if (!short_name || !new_efivar) { kfree(short_name); kfree(new_efivar); return 1; } - memset(short_name, 0, short_name_size+1); - memset(new_efivar, 0, sizeof(struct efivar_entry)); memcpy(new_efivar->var.VariableName, variable_name, variable_name_size); @@ -674,14 +672,12 @@ efivars_init(void) if (!efi_enabled) return -ENODEV; - variable_name = kmalloc(variable_name_size, GFP_KERNEL); + variable_name = kzalloc(variable_name_size, GFP_KERNEL); if (!variable_name) { printk(KERN_ERR "efivars: Memory allocation failed.\n"); return -ENOMEM; } - memset(variable_name, 0, variable_name_size); - printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION, EFIVARS_DATE); diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 6f48579799b588b456a59f18b41cccae19bc8d2b..dddd3eb9b3870ef060e84db9d8db4e099303c71d 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -16,6 +16,7 @@ #include #include #include +#include #define HWMON_ID_PREFIX "hwmon" #define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d" diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c index 6a82ffae1bfd6af15ce3fb89c92cae3c62edaab7..69e7e125683bb4f13b19a0d1b8fe6a4af8b22f83 100644 --- a/drivers/hwmon/max1619.c +++ b/drivers/hwmon/max1619.c @@ -193,7 +193,7 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind) int err = 0; const char *name = ""; u8 reg_config=0, reg_convrate=0, reg_status=0; - u8 man_id, chip_id; + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; @@ -238,16 +238,15 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind) } if (kind <= 0) { /* identification */ + u8 man_id, chip_id; man_id = i2c_smbus_read_byte_data(new_client, MAX1619_REG_R_MAN_ID); chip_id = i2c_smbus_read_byte_data(new_client, MAX1619_REG_R_CHIP_ID); - if ((man_id == 0x4D) && (chip_id == 0x04)){ - kind = max1619; - } - } + if ((man_id == 0x4D) && (chip_id == 0x04)) + kind = max1619; if (kind <= 0) { /* identification failed */ dev_info(&adapter->dev, @@ -255,11 +254,10 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind) "chip_id=0x%02X).\n", man_id, chip_id); goto exit_free; } - + } - if (kind == max1619){ + if (kind == max1619) name = "max1619"; - } /* We can fill in the remaining client fields */ strlcpy(new_client->name, name, I2C_NAME_SIZE); diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index 9265f32122fa4b59d072b98134c18bf383fb57d0..ffdb3a03e2b5f9bd39bc8c551f04506df4a92081 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -976,11 +976,9 @@ w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, ERROR_SC_3: i2c_detach_client(data->lm75[0]); ERROR_SC_2: - if (data->lm75[1]) - kfree(data->lm75[1]); + kfree(data->lm75[1]); ERROR_SC_1: - if (data->lm75[0]) - kfree(data->lm75[0]); + kfree(data->lm75[0]); ERROR_SC_0: return err; } diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c index f51ab652300a66a5d629ac3937622e289f379bf7..56c7d987590f51704ea22363796ab34d838c9c1b 100644 --- a/drivers/i2c/busses/i2c-amd756-s4882.c +++ b/drivers/i2c/busses/i2c-amd756-s4882.c @@ -245,10 +245,8 @@ static void __exit amd756_s4882_exit(void) kfree(s4882_adapter); s4882_adapter = NULL; } - if (s4882_algo) { - kfree(s4882_algo); - s4882_algo = NULL; - } + kfree(s4882_algo); + s4882_algo = NULL; /* Restore physical bus */ if (i2c_add_adapter(&amd756_smbus)) diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 8b9d85526596a38380dbf65ce0a3f6dcc82527d7..c2f47923d174bd6eedb352ec9164b52eac38b488 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -3292,12 +3292,9 @@ static void ide_cd_release(struct kref *kref) ide_drive_t *drive = info->drive; struct gendisk *g = info->disk; - if (info->buffer != NULL) - kfree(info->buffer); - if (info->toc != NULL) - kfree(info->toc); - if (info->changer_info != NULL) - kfree(info->changer_info); + kfree(info->buffer); + kfree(info->toc); + kfree(info->changer_info); if (devinfo->handle == drive && unregister_cdrom(devinfo)) printk(KERN_ERR "%s: %s failed to unregister device from the cdrom " "driver.\n", __FUNCTION__, drive->name); @@ -3455,7 +3452,7 @@ static int ide_cd_probe(struct device *dev) printk(KERN_INFO "ide-cd: passing drive %s to ide-scsi emulation.\n", drive->name); goto failed; } - info = kmalloc(sizeof(struct cdrom_info), GFP_KERNEL); + info = kzalloc(sizeof(struct cdrom_info), GFP_KERNEL); if (info == NULL) { printk(KERN_ERR "%s: Can't allocate a cdrom structure\n", drive->name); goto failed; @@ -3469,8 +3466,6 @@ static int ide_cd_probe(struct device *dev) ide_register_subdriver(drive, &ide_cdrom_driver); - memset(info, 0, sizeof (struct cdrom_info)); - kref_init(&info->kref); info->drive = drive; @@ -3489,12 +3484,9 @@ static int ide_cd_probe(struct device *dev) if (ide_cdrom_setup(drive)) { struct cdrom_device_info *devinfo = &info->devinfo; ide_unregister_subdriver(drive, &ide_cdrom_driver); - if (info->buffer != NULL) - kfree(info->buffer); - if (info->toc != NULL) - kfree(info->toc); - if (info->changer_info != NULL) - kfree(info->changer_info); + kfree(info->buffer); + kfree(info->toc); + kfree(info->changer_info); if (devinfo->handle == drive && unregister_cdrom(devinfo)) printk (KERN_ERR "%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name); kfree(info); diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 234f5de3e929b6c0d10ee46a994e200f16f62646..e827b39e4b3c7f0c02d1a964a6a9a3a5b0a7cb29 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -1215,7 +1215,7 @@ static int ide_disk_probe(struct device *dev) if (drive->media != ide_disk) goto failed; - idkp = kmalloc(sizeof(*idkp), GFP_KERNEL); + idkp = kzalloc(sizeof(*idkp), GFP_KERNEL); if (!idkp) goto failed; @@ -1228,8 +1228,6 @@ static int ide_disk_probe(struct device *dev) ide_register_subdriver(drive, &idedisk_driver); - memset(idkp, 0, sizeof(*idkp)); - kref_init(&idkp->kref); idkp->drive = drive; diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 29c22fc278c6510b75209ea6fea80649fe23fe77..e83f54d37f9668625d95649f766d4fe74e2741e7 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -2146,7 +2146,7 @@ static int ide_floppy_probe(struct device *dev) printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name); goto failed; } - if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) { + if ((floppy = (idefloppy_floppy_t *) kzalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) { printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name); goto failed; } @@ -2159,8 +2159,6 @@ static int ide_floppy_probe(struct device *dev) ide_register_subdriver(drive, &idefloppy_driver); - memset(floppy, 0, sizeof(*floppy)); - kref_init(&floppy->kref); floppy->drive = drive; diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index c1128ae5cd2f98319ee889b74fefd7e69916edd4..02167a5b751dbe40a0b1be304766903fceb43c52 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -596,14 +596,13 @@ static inline u8 probe_for_drive (ide_drive_t *drive) * Also note that 0 everywhere means "can't do X" */ - drive->id = kmalloc(SECTOR_WORDS *4, GFP_KERNEL); + drive->id = kzalloc(SECTOR_WORDS *4, GFP_KERNEL); drive->id_read = 0; if(drive->id == NULL) { printk(KERN_ERR "ide: out of memory for id data.\n"); return 0; } - memset(drive->id, 0, SECTOR_WORDS * 4); strcpy(drive->id->model, "UNKNOWN"); /* skip probing? */ @@ -1316,10 +1315,8 @@ static void drive_release_dev (struct device *dev) drive->devfs_name[0] = '\0'; } ide_remove_drive_from_hwgroup(drive); - if (drive->id != NULL) { - kfree(drive->id); - drive->id = NULL; - } + kfree(drive->id); + drive->id = NULL; drive->present = 0; /* Messed up locking ... */ spin_unlock_irq(&ide_lock); diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 47f2b832555fd27fefd6650c728cf81de980c363..0ac7eb8f40d537ae04c2db1b23a2d819df835e69 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -4850,7 +4850,7 @@ static int ide_tape_probe(struct device *dev) printk(KERN_WARNING "ide-tape: Use drive %s with ide-scsi emulation and osst.\n", drive->name); printk(KERN_WARNING "ide-tape: OnStream support will be removed soon from ide-tape!\n"); } - tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL); + tape = (idetape_tape_t *) kzalloc (sizeof (idetape_tape_t), GFP_KERNEL); if (tape == NULL) { printk(KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name); goto failed; @@ -4864,8 +4864,6 @@ static int ide_tape_probe(struct device *dev) ide_register_subdriver(drive, &idetape_driver); - memset(tape, 0, sizeof(*tape)); - kref_init(&tape->kref); tape->drive = drive; diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index ace8edad6e9620ac685dc0e038a89c6e1d0ef546..7ec18fa3b5ff8f8f6d0e8fc8ae7eda36a2186afe 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -528,9 +528,8 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) // printk("IDE Taskfile ...\n"); - req_task = kmalloc(tasksize, GFP_KERNEL); + req_task = kzalloc(tasksize, GFP_KERNEL); if (req_task == NULL) return -ENOMEM; - memset(req_task, 0, tasksize); if (copy_from_user(req_task, buf, tasksize)) { kfree(req_task); return -EFAULT; @@ -541,12 +540,11 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) if (taskout) { int outtotal = tasksize; - outbuf = kmalloc(taskout, GFP_KERNEL); + outbuf = kzalloc(taskout, GFP_KERNEL); if (outbuf == NULL) { err = -ENOMEM; goto abort; } - memset(outbuf, 0, taskout); if (copy_from_user(outbuf, buf + outtotal, taskout)) { err = -EFAULT; goto abort; @@ -555,12 +553,11 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) if (taskin) { int intotal = tasksize + taskout; - inbuf = kmalloc(taskin, GFP_KERNEL); + inbuf = kzalloc(taskin, GFP_KERNEL); if (inbuf == NULL) { err = -ENOMEM; goto abort; } - memset(inbuf, 0, taskin); if (copy_from_user(inbuf, buf + intotal, taskin)) { err = -EFAULT; goto abort; @@ -649,10 +646,8 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) } abort: kfree(req_task); - if (outbuf != NULL) - kfree(outbuf); - if (inbuf != NULL) - kfree(inbuf); + kfree(outbuf); + kfree(inbuf); // printk("IDE Taskfile ioctl ended. rc = %i\n", err); @@ -709,10 +704,9 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) if (args[3]) { argsize = 4 + (SECTOR_WORDS * 4 * args[3]); - argbuf = kmalloc(argsize, GFP_KERNEL); + argbuf = kzalloc(argsize, GFP_KERNEL); if (argbuf == NULL) return -ENOMEM; - memcpy(argbuf, args, 4); } if (set_transfer(drive, &tfargs)) { xfer_rate = args[1]; diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 73ca8f73917d9172bba616311437ccb3de9966e9..9fe19808d8153853332891595776b7f1e27659ba 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -864,9 +864,8 @@ static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int r down(&ide_setting_sem); while ((*p) && strcmp((*p)->name, name) < 0) p = &((*p)->next); - if ((setting = kmalloc(sizeof(*setting), GFP_KERNEL)) == NULL) + if ((setting = kzalloc(sizeof(*setting), GFP_KERNEL)) == NULL) goto abort; - memset(setting, 0, sizeof(*setting)); if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL) goto abort; strcpy(setting->name, name); @@ -889,8 +888,7 @@ static int __ide_add_setting(ide_drive_t *drive, const char *name, int rw, int r return 0; abort: up(&ide_setting_sem); - if (setting) - kfree(setting); + kfree(setting); return -1; } diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index a35a58bef1a4eb4d1752bc2929eb528956206035..1dafffa7e51333ac262495882907d78f39212cf6 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -116,9 +116,8 @@ static dev_link_t *ide_attach(void) DEBUG(0, "ide_attach()\n"); /* Create new ide device */ - info = kmalloc(sizeof(*info), GFP_KERNEL); + info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return NULL; - memset(info, 0, sizeof(*info)); link = &info->link; link->priv = info; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; @@ -221,9 +220,8 @@ static void ide_config(dev_link_t *link) DEBUG(0, "ide_config(0x%p)\n", link); - stk = kmalloc(sizeof(*stk), GFP_KERNEL); + stk = kzalloc(sizeof(*stk), GFP_KERNEL); if (!stk) goto err_mem; - memset(stk, 0, sizeof(*stk)); cfg = &stk->parse.cftable_entry; tuple.TupleData = (cisdata_t *)&stk->buf; diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 127619a109eda2ef119c9deeecd44793ae53a834..7b589d948bf98bce6405196a55444787d4eff920 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -1516,7 +1516,7 @@ static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase) static void __devinit init_iops_hpt366(ide_hwif_t *hwif) { - struct hpt_info *info = kmalloc(sizeof(struct hpt_info), GFP_KERNEL); + struct hpt_info *info = kzalloc(sizeof(struct hpt_info), GFP_KERNEL); unsigned long dmabase = pci_resource_start(hwif->pci_dev, 4); u8 did, rid; @@ -1524,7 +1524,6 @@ static void __devinit init_iops_hpt366(ide_hwif_t *hwif) printk(KERN_WARNING "hpt366: out of memory.\n"); return; } - memset(info, 0, sizeof(struct hpt_info)); ide_set_hwifdata(hwif, info); if(dmabase) { diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c index e440036e651fb63999d980db8ad82579f031d734..108fda83fea476bc2ab4d13e96ac3c09e847cd22 100644 --- a/drivers/ide/pci/it821x.c +++ b/drivers/ide/pci/it821x.c @@ -642,14 +642,13 @@ static void __devinit it821x_fixups(ide_hwif_t *hwif) static void __devinit init_hwif_it821x(ide_hwif_t *hwif) { - struct it821x_dev *idev = kmalloc(sizeof(struct it821x_dev), GFP_KERNEL); + struct it821x_dev *idev = kzalloc(sizeof(struct it821x_dev), GFP_KERNEL); u8 conf; if(idev == NULL) { printk(KERN_ERR "it821x: out of memory, falling back to legacy behaviour.\n"); goto fallback; } - memset(idev, 0, sizeof(struct it821x_dev)); ide_set_hwifdata(hwif, idev); pci_read_config_byte(hwif->pci_dev, 0x50, &conf); diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index d8c3d8ebad302dc7569dfccfe1dab300a6506110..b3e65a65d202c268a276657c0451ca7a37d565bf 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -497,16 +497,19 @@ pmu_hd_blink_init(void) if (pmu_get_model() != PMU_KEYLARGO_BASED) return 0; - dt = find_devices("device-tree"); + dt = of_find_node_by_path("/"); if (dt == NULL) return 0; model = (const char *)get_property(dt, "model", NULL); if (model == NULL) return 0; if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 && - strncmp(model, "iBook", strlen("iBook")) != 0) + strncmp(model, "iBook", strlen("iBook")) != 0) { + of_node_put(dt); return 0; - + } + of_node_put(dt); + pmu_blink_on.complete = 1; pmu_blink_off.complete = 1; spin_lock_init(&pmu_blink_lock); diff --git a/drivers/ieee1394/amdtp.c b/drivers/ieee1394/amdtp.c index e8e28569a6684feb2c0ae4e5d41447479c5480bc..75897509c4017c3a2f8175b79181cfae4c87bab8 100644 --- a/drivers/ieee1394/amdtp.c +++ b/drivers/ieee1394/amdtp.c @@ -320,8 +320,7 @@ static void ohci1394_stop_it_ctx(struct ti_ohci *ohci, int ctx, int synchronous) if ((control & OHCI1394_CONTEXT_ACTIVE) == 0) break; - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_interruptible(1); } } } diff --git a/drivers/infiniband/core/agent.c b/drivers/infiniband/core/agent.c index 7545775d38efe1957a2fe490ad23fbe4bd329622..34b724afd28daf15ca52e14270a796fc9cfcede3 100644 --- a/drivers/infiniband/core/agent.c +++ b/drivers/infiniband/core/agent.c @@ -37,6 +37,9 @@ * $Id: agent.c 1389 2004-12-27 22:56:47Z roland $ */ +#include +#include + #include "agent.h" #include "smi.h" diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 3d8175e5f0544e7cf22e97649049f8e0635cf30f..41d6b4017acb9d24aebdd5aed278b079bf382d85 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -508,8 +508,7 @@ static void unregister_mad_agent(struct ib_mad_agent_private *mad_agent_priv) wait_event(mad_agent_priv->wait, !atomic_read(&mad_agent_priv->refcount)); - if (mad_agent_priv->reg_req) - kfree(mad_agent_priv->reg_req); + kfree(mad_agent_priv->reg_req); ib_dereg_mr(mad_agent_priv->agent.mr); kfree(mad_agent_priv); } @@ -2500,8 +2499,7 @@ static int create_mad_qp(struct ib_mad_qp_info *qp_info, static void destroy_mad_qp(struct ib_mad_qp_info *qp_info) { ib_destroy_qp(qp_info->qp); - if (qp_info->snoop_table) - kfree(qp_info->snoop_table); + kfree(qp_info->snoop_table); } /* diff --git a/drivers/infiniband/core/packer.c b/drivers/infiniband/core/packer.c index 35df5010e723ecf9d466f0a27fd33f51bfe80e86..c972d72357647e874302a979d36bc22eee9c3f17 100644 --- a/drivers/infiniband/core/packer.c +++ b/drivers/infiniband/core/packer.c @@ -33,6 +33,8 @@ * $Id: packer.c 1349 2004-12-16 21:09:43Z roland $ */ +#include + #include static u64 value_read(int offset, int size, void *structure) diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index b8120650e71187c56dad658533979d5fbd24519a..08648b1a387e4bed61961d2aedf4f163a8e0a0f5 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -36,6 +36,9 @@ #include "core_priv.h" +#include +#include + #include struct ib_port { diff --git a/drivers/infiniband/core/ud_header.c b/drivers/infiniband/core/ud_header.c index 527b23450ab3d72dc12e3298e8bbdc49a871e12b..997c07db6d8fb216a132b12555d4cc27357e7531 100644 --- a/drivers/infiniband/core/ud_header.c +++ b/drivers/infiniband/core/ud_header.c @@ -34,6 +34,7 @@ */ #include +#include #include diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 72d3ef786db50acf3194612b43bbe3910b5cc955..4186cc888ea5b209f8c078b3d97e0faa4732cb11 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -40,6 +40,7 @@ #include #include +#include #include #include diff --git a/drivers/infiniband/hw/mthca/mthca_catas.c b/drivers/infiniband/hw/mthca/mthca_catas.c index 7ac52af43b999caade4645d19f1b2cd244808917..25ebab64bc4257a29548d8e398249f38d91e67a8 100644 --- a/drivers/infiniband/hw/mthca/mthca_catas.c +++ b/drivers/infiniband/hw/mthca/mthca_catas.c @@ -32,6 +32,9 @@ * $Id$ */ +#include +#include + #include "mthca_dev.h" enum { diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index 292f55be8cbd8c6eef90a0a6d884ac0261de9652..26d5161fde0719620313b01d5205f6ced2a65c84 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c @@ -32,6 +32,9 @@ * $Id: mthca_srq.c 3047 2005-08-10 03:59:35Z roland $ */ +#include +#include + #include "mthca_dev.h" #include "mthca_cmd.h" #include "mthca_memfree.h" diff --git a/drivers/input/input.c b/drivers/input/input.c index 1a1654caedd53a2ca59390bae8e97791b41298b6..0879915b14d5af21ec6a4ed0f3383962a595bc2c 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -377,7 +377,7 @@ static int input_devices_read(char *buf, char **start, off_t pos, int count, int list_for_each_entry(dev, &input_dev_list, node) { - path = dev->dynalloc ? kobject_get_path(&dev->cdev.kobj, GFP_KERNEL) : NULL; + path = kobject_get_path(&dev->cdev.kobj, GFP_KERNEL); len = sprintf(buf, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n", dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version); @@ -741,15 +741,21 @@ static void input_register_classdevice(struct input_dev *dev) sysfs_create_group(&dev->cdev.kobj, &input_dev_caps_attr_group); } -void input_register_device(struct input_dev *dev) +int input_register_device(struct input_dev *dev) { struct input_handle *handle; struct input_handler *handler; struct input_device_id *id; - set_bit(EV_SYN, dev->evbit); + if (!dev->dynalloc) { + printk(KERN_WARNING "input: device %s is statically allocated, will not register\n" + "Please convert to input_allocate_device() or contact dtor_core@ameritech.net\n", + dev->name ? dev->name : ""); + return -EINVAL; + } init_MUTEX(&dev->sem); + set_bit(EV_SYN, dev->evbit); /* * If delay and period are pre-set by the driver, then autorepeating @@ -767,8 +773,7 @@ void input_register_device(struct input_dev *dev) INIT_LIST_HEAD(&dev->h_list); list_add_tail(&dev->node, &input_dev_list); - if (dev->dynalloc) - input_register_classdevice(dev); + input_register_classdevice(dev); list_for_each_entry(handler, &input_handler_list, node) if (!handler->blacklist || !input_match_device(handler->blacklist, dev)) @@ -776,8 +781,9 @@ void input_register_device(struct input_dev *dev) if ((handle = handler->connect(handler, dev, id))) input_link_handle(handle); - input_wakeup_procfs_readers(); + + return 0; } void input_unregister_device(struct input_dev *dev) @@ -797,11 +803,10 @@ void input_unregister_device(struct input_dev *dev) list_del_init(&dev->node); - if (dev->dynalloc) { - sysfs_remove_group(&dev->cdev.kobj, &input_dev_caps_attr_group); - sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group); - class_device_unregister(&dev->cdev); - } + sysfs_remove_group(&dev->cdev.kobj, &input_dev_caps_attr_group); + sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group); + sysfs_remove_group(&dev->cdev.kobj, &input_dev_group); + class_device_unregister(&dev->cdev); input_wakeup_procfs_readers(); } diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c index 9481132532d017ee42d36cecc789a0007e7bca2b..77c4d9669ad04ac44889bf72a185cb81c14c2b9b 100644 --- a/drivers/input/keyboard/lkkbd.c +++ b/drivers/input/keyboard/lkkbd.c @@ -273,11 +273,11 @@ static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = { [0xfb] = KEY_APOSTROPHE, }; -#define CHECK_LED(LED, BITS) do { \ - if (test_bit (LED, lk->dev->led)) \ - leds_on |= BITS; \ - else \ - leds_off |= BITS; \ +#define CHECK_LED(LK, VAR_ON, VAR_OFF, LED, BITS) do { \ + if (test_bit (LED, (LK)->dev->led)) \ + VAR_ON |= BITS; \ + else \ + VAR_OFF |= BITS; \ } while (0) /* @@ -298,6 +298,42 @@ struct lkkbd { int ctrlclick_volume; }; +#ifdef LKKBD_DEBUG +/* + * Responses from the keyboard and mapping back to their names. + */ +static struct { + unsigned char value; + unsigned char *name; +} lk_response[] = { +#define RESPONSE(x) { .value = (x), .name = #x, } + RESPONSE (LK_STUCK_KEY), + RESPONSE (LK_SELFTEST_FAILED), + RESPONSE (LK_ALL_KEYS_UP), + RESPONSE (LK_METRONOME), + RESPONSE (LK_OUTPUT_ERROR), + RESPONSE (LK_INPUT_ERROR), + RESPONSE (LK_KBD_LOCKED), + RESPONSE (LK_KBD_TEST_MODE_ACK), + RESPONSE (LK_PREFIX_KEY_DOWN), + RESPONSE (LK_MODE_CHANGE_ACK), + RESPONSE (LK_RESPONSE_RESERVED), +#undef RESPONSE +}; + +static unsigned char * +response_name (unsigned char value) +{ + int i; + + for (i = 0; i < ARRAY_SIZE (lk_response); i++) + if (lk_response[i].value == value) + return lk_response[i].name; + + return ""; +} +#endif /* LKKBD_DEBUG */ + /* * Calculate volume parameter byte for a given volume. */ @@ -440,43 +476,24 @@ lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags, input_report_key (lk->dev, lk->keycode[i], 0); input_sync (lk->dev); break; - case LK_METRONOME: - DBG (KERN_INFO "Got LK_METRONOME and don't " - "know how to handle...\n"); + + case 0x01: + DBG (KERN_INFO "Got 0x01, scheduling re-initialization\n"); + lk->ignore_bytes = LK_NUM_IGNORE_BYTES; + lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data; + schedule_work (&lk->tq); break; + + case LK_METRONOME: case LK_OUTPUT_ERROR: - DBG (KERN_INFO "Got LK_OUTPUT_ERROR and don't " - "know how to handle...\n"); - break; case LK_INPUT_ERROR: - DBG (KERN_INFO "Got LK_INPUT_ERROR and don't " - "know how to handle...\n"); - break; case LK_KBD_LOCKED: - DBG (KERN_INFO "Got LK_KBD_LOCKED and don't " - "know how to handle...\n"); - break; case LK_KBD_TEST_MODE_ACK: - DBG (KERN_INFO "Got LK_KBD_TEST_MODE_ACK and don't " - "know how to handle...\n"); - break; case LK_PREFIX_KEY_DOWN: - DBG (KERN_INFO "Got LK_PREFIX_KEY_DOWN and don't " - "know how to handle...\n"); - break; case LK_MODE_CHANGE_ACK: - DBG (KERN_INFO "Got LK_MODE_CHANGE_ACK and ignored " - "it properly...\n"); - break; case LK_RESPONSE_RESERVED: - DBG (KERN_INFO "Got LK_RESPONSE_RESERVED and don't " - "know how to handle...\n"); - break; - case 0x01: - DBG (KERN_INFO "Got 0x01, scheduling re-initialization\n"); - lk->ignore_bytes = LK_NUM_IGNORE_BYTES; - lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data; - schedule_work (&lk->tq); + DBG (KERN_INFO "Got %s and don't know how to handle...\n", + response_name (data)); break; default: @@ -509,10 +526,10 @@ lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code, switch (type) { case EV_LED: - CHECK_LED (LED_CAPSL, LK_LED_SHIFTLOCK); - CHECK_LED (LED_COMPOSE, LK_LED_COMPOSE); - CHECK_LED (LED_SCROLLL, LK_LED_SCROLLLOCK); - CHECK_LED (LED_SLEEP, LK_LED_WAIT); + CHECK_LED (lk, leds_on, leds_off, LED_CAPSL, LK_LED_SHIFTLOCK); + CHECK_LED (lk, leds_on, leds_off, LED_COMPOSE, LK_LED_COMPOSE); + CHECK_LED (lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK); + CHECK_LED (lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT); if (leds_on != 0) { lk->serio->write (lk->serio, LK_CMD_LED_ON); lk->serio->write (lk->serio, leds_on); @@ -574,10 +591,10 @@ lkkbd_reinit (void *data) lk->serio->write (lk->serio, LK_CMD_SET_DEFAULTS); /* Set LEDs */ - CHECK_LED (LED_CAPSL, LK_LED_SHIFTLOCK); - CHECK_LED (LED_COMPOSE, LK_LED_COMPOSE); - CHECK_LED (LED_SCROLLL, LK_LED_SCROLLLOCK); - CHECK_LED (LED_SLEEP, LK_LED_WAIT); + CHECK_LED (lk, leds_on, leds_off, LED_CAPSL, LK_LED_SHIFTLOCK); + CHECK_LED (lk, leds_on, leds_off, LED_COMPOSE, LK_LED_COMPOSE); + CHECK_LED (lk, leds_on, leds_off, LED_SCROLLL, LK_LED_SCROLLLOCK); + CHECK_LED (lk, leds_on, leds_off, LED_SLEEP, LK_LED_WAIT); if (leds_on != 0) { lk->serio->write (lk->serio, LK_CMD_LED_ON); lk->serio->write (lk->serio, leds_on); diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c index 8935290256b392ed25457b07f711d0329cab4a07..2c510881874ab70e5827bee15619286872542ed4 100644 --- a/drivers/input/keyboard/locomokbd.c +++ b/drivers/input/keyboard/locomokbd.c @@ -76,7 +76,7 @@ static unsigned char locomokbd_keycode[LOCOMOKBD_NUMKEYS] = { struct locomokbd { unsigned char keycode[LOCOMOKBD_NUMKEYS]; - struct input_dev input; + struct input_dev *input; char phys[32]; struct locomo_dev *ldev; @@ -136,8 +136,7 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs * spin_lock_irqsave(&locomokbd->lock, flags); - if (regs) - input_regs(&locomokbd->input, regs); + input_regs(locomokbd->input, regs); locomokbd_charge_all(membase); @@ -152,16 +151,16 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs * scancode = SCANCODE(col, row); if (rowd & KB_ROWMASK(row)) { num_pressed += 1; - input_report_key(&locomokbd->input, locomokbd->keycode[scancode], 1); + input_report_key(locomokbd->input, locomokbd->keycode[scancode], 1); } else { - input_report_key(&locomokbd->input, locomokbd->keycode[scancode], 0); + input_report_key(locomokbd->input, locomokbd->keycode[scancode], 0); } } locomokbd_reset_col(membase, col); } locomokbd_activate_all(membase); - input_sync(&locomokbd->input); + input_sync(locomokbd->input); /* if any keys are pressed, enable the timer */ if (num_pressed) @@ -196,13 +195,15 @@ static void locomokbd_timer_callback(unsigned long data) static int locomokbd_probe(struct locomo_dev *dev) { struct locomokbd *locomokbd; + struct input_dev *input_dev; int i, ret; - locomokbd = kmalloc(sizeof(struct locomokbd), GFP_KERNEL); - if (!locomokbd) - return -ENOMEM; - - memset(locomokbd, 0, sizeof(struct locomokbd)); + locomokbd = kzalloc(sizeof(struct locomokbd), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!locomokbd || !input_dev) { + ret = -ENOMEM; + goto free; + } /* try and claim memory region */ if (!request_mem_region((unsigned long) dev->mapbase, @@ -224,27 +225,26 @@ static int locomokbd_probe(struct locomo_dev *dev) locomokbd->timer.function = locomokbd_timer_callback; locomokbd->timer.data = (unsigned long) locomokbd; - locomokbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + locomokbd->input = input_dev; + strcpy(locomokbd->phys, "locomokbd/input0"); + + input_dev->name = "LoCoMo keyboard"; + input_dev->phys = locomokbd->phys; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->private = locomokbd; - init_input_dev(&locomokbd->input); - locomokbd->input.keycode = locomokbd->keycode; - locomokbd->input.keycodesize = sizeof(unsigned char); - locomokbd->input.keycodemax = ARRAY_SIZE(locomokbd_keycode); - locomokbd->input.private = locomokbd; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + input_dev->keycode = locomokbd->keycode; + input_dev->keycodesize = sizeof(unsigned char); + input_dev->keycodemax = ARRAY_SIZE(locomokbd_keycode); memcpy(locomokbd->keycode, locomokbd_keycode, sizeof(locomokbd->keycode)); for (i = 0; i < LOCOMOKBD_NUMKEYS; i++) - set_bit(locomokbd->keycode[i], locomokbd->input.keybit); - clear_bit(0, locomokbd->input.keybit); - - strcpy(locomokbd->phys, "locomokbd/input0"); - - locomokbd->input.name = "LoCoMo keyboard"; - locomokbd->input.phys = locomokbd->phys; - locomokbd->input.id.bustype = BUS_XTKBD; - locomokbd->input.id.vendor = 0x0001; - locomokbd->input.id.product = 0x0001; - locomokbd->input.id.version = 0x0100; + set_bit(locomokbd->keycode[i], input_dev->keybit); + clear_bit(0, input_dev->keybit); /* attempt to get the interrupt */ ret = request_irq(dev->irq[0], locomokbd_interrupt, 0, "locomokbd", locomokbd); @@ -253,9 +253,7 @@ static int locomokbd_probe(struct locomo_dev *dev) goto out; } - input_register_device(&locomokbd->input); - - printk(KERN_INFO "input: LoCoMo keyboard on locomokbd\n"); + input_register_device(locomokbd->input); return 0; @@ -263,6 +261,7 @@ static int locomokbd_probe(struct locomo_dev *dev) release_mem_region((unsigned long) dev->mapbase, dev->length); locomo_set_drvdata(dev, NULL); free: + input_free_device(input_dev); kfree(locomokbd); return ret; @@ -276,7 +275,7 @@ static int locomokbd_remove(struct locomo_dev *dev) del_timer_sync(&locomokbd->timer); - input_unregister_device(&locomokbd->input); + input_unregister_device(locomokbd->input); locomo_set_drvdata(dev, NULL); release_mem_region((unsigned long) dev->mapbase, dev->length); diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 4015a91f4b6e7bcc0a17089f155ebb36233ce16d..948c1cc01bc95ea5291a843b107f86f2e7cf70bd 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -271,8 +271,7 @@ static int uinput_alloc_device(struct file *file, const char __user *buffer, siz goto exit; } - if (dev->name) - kfree(dev->name); + kfree(dev->name); size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1; dev->name = name = kmalloc(size, GFP_KERNEL); @@ -372,11 +371,8 @@ static int uinput_burn_device(struct uinput_device *udev) if (test_bit(UIST_CREATED, &udev->state)) uinput_destroy_device(udev); - if (udev->dev->name) - kfree(udev->dev->name); - if (udev->dev->phys) - kfree(udev->dev->phys); - + kfree(udev->dev->name); + kfree(udev->dev->phys); kfree(udev->dev); kfree(udev); diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 0f69ff46c1ae1c555771525deea8b7278b72c0d1..31a59f7abfaf616b6cc985d03958aaf553e95e5d 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -217,6 +217,9 @@ static struct ps2pp_info *get_model_info(unsigned char model) { 61, PS2PP_KIND_MX, /* MX700 */ PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, + { 66, PS2PP_KIND_MX, /* MX3100 reciver */ + PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | + PS2PP_EXTRA_BTN | PS2PP_NAV_BTN | PS2PP_HWHEEL }, { 73, 0, PS2PP_SIDE_BTN }, { 75, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 76, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c index db9bad2b3d165cec9aab180cbe50bdd5697651dc..27391c32f3ebbe3e7a04be2a8609ae30e45d1fbf 100644 --- a/drivers/isdn/hardware/avm/avm_cs.c +++ b/drivers/isdn/hardware/avm/avm_cs.c @@ -212,11 +212,8 @@ static void avmcs_detach(dev_link_t *link) /* Unlink device structure, free pieces */ *linkp = link->next; - if (link->priv) { - kfree(link->priv); - } + kfree(link->priv); kfree(link); - } /* avmcs_detach */ /*====================================================================== diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c index 625799ab0d14d5292c96d3c41e01c90148e55567..5d8ee7368f7b79828abc89ec32b9e64724417bc9 100644 --- a/drivers/isdn/hisax/avm_pci.c +++ b/drivers/isdn/hisax/avm_pci.c @@ -552,14 +552,10 @@ close_hdlcstate(struct BCState *bcs) { modehdlc(bcs, 0, 0); if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - if (bcs->hw.hdlc.rcvbuf) { - kfree(bcs->hw.hdlc.rcvbuf); - bcs->hw.hdlc.rcvbuf = NULL; - } - if (bcs->blog) { - kfree(bcs->blog); - bcs->blog = NULL; - } + kfree(bcs->hw.hdlc.rcvbuf); + bcs->hw.hdlc.rcvbuf = NULL; + kfree(bcs->blog); + bcs->blog = NULL; skb_queue_purge(&bcs->rqueue); skb_queue_purge(&bcs->squeue); if (bcs->tx_skb) { diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c index 0e22991635e7510ddd6f91f6fcd090ca213bce4a..5f5a5ae740d2aa9a2afb83b26a0f5075dc94538f 100644 --- a/drivers/isdn/hisax/avma1_cs.c +++ b/drivers/isdn/hisax/avma1_cs.c @@ -236,9 +236,7 @@ static void avma1cs_detach(dev_link_t *link) /* Unlink device structure, free pieces */ *linkp = link->next; - if (link->priv) { - kfree(link->priv); - } + kfree(link->priv); kfree(link); } /* avma1cs_detach */ diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index fbaab4352902621d183b318353c89460746a1d56..8159bcecd0c2e1c6fabe01a6dbbe13fbb2d86024 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -787,8 +787,7 @@ static void ll_unload(struct IsdnCardState *cs) ic.command = ISDN_STAT_UNLOAD; ic.driver = cs->myid; cs->iif.statcallb(&ic); - if (cs->status_buf) - kfree(cs->status_buf); + kfree(cs->status_buf); cs->status_read = NULL; cs->status_write = NULL; cs->status_end = NULL; @@ -807,10 +806,8 @@ static void closecard(int cardnr) skb_queue_purge(&csta->rq); skb_queue_purge(&csta->sq); - if (csta->rcvbuf) { - kfree(csta->rcvbuf); - csta->rcvbuf = NULL; - } + kfree(csta->rcvbuf); + csta->rcvbuf = NULL; if (csta->tx_skb) { dev_kfree_skb(csta->tx_skb); csta->tx_skb = NULL; diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c index 7cf87793e7907d5bdf4d354a1fc4011cce151ad6..637a261c93122a5929d3459e6d4a9e346b32b16e 100644 --- a/drivers/isdn/hisax/hfc_2bds0.c +++ b/drivers/isdn/hisax/hfc_2bds0.c @@ -1052,18 +1052,12 @@ init2bds0(struct IsdnCardState *cs) void release2bds0(struct IsdnCardState *cs) { - if (cs->bcs[0].hw.hfc.send) { - kfree(cs->bcs[0].hw.hfc.send); - cs->bcs[0].hw.hfc.send = NULL; - } - if (cs->bcs[1].hw.hfc.send) { - kfree(cs->bcs[1].hw.hfc.send); - cs->bcs[1].hw.hfc.send = NULL; - } - if (cs->hw.hfcD.send) { - kfree(cs->hw.hfcD.send); - cs->hw.hfcD.send = NULL; - } + kfree(cs->bcs[0].hw.hfc.send); + cs->bcs[0].hw.hfc.send = NULL; + kfree(cs->bcs[1].hw.hfc.send); + cs->bcs[1].hw.hfc.send = NULL; + kfree(cs->hw.hfcD.send); + cs->hw.hfcD.send = NULL; } void diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c index f978a5af866292489ceb58b267219c5a3b86b32e..c964539cc43e537daa1fe135dbd66afa22da2117 100644 --- a/drivers/isdn/hisax/hfc_2bs0.c +++ b/drivers/isdn/hisax/hfc_2bs0.c @@ -582,12 +582,8 @@ inithfc(struct IsdnCardState *cs) void releasehfc(struct IsdnCardState *cs) { - if (cs->bcs[0].hw.hfc.send) { - kfree(cs->bcs[0].hw.hfc.send); - cs->bcs[0].hw.hfc.send = NULL; - } - if (cs->bcs[1].hw.hfc.send) { - kfree(cs->bcs[1].hw.hfc.send); - cs->bcs[1].hw.hfc.send = NULL; - } + kfree(cs->bcs[0].hw.hfc.send); + cs->bcs[0].hw.hfc.send = NULL; + kfree(cs->bcs[1].hw.hfc.send); + cs->bcs[1].hw.hfc.send = NULL; } diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c index e2c3af49d72b9af938d47fd109924d74e7c84949..32bf0d5d0f9a0d0692414c683a6547c3050be5e9 100644 --- a/drivers/isdn/hisax/hfc_usb.c +++ b/drivers/isdn/hisax/hfc_usb.c @@ -1,7 +1,7 @@ /* * hfc_usb.c * - * $Id: hfc_usb.c,v 4.34 2005/01/26 17:25:53 martinb1 Exp $ + * $Id: hfc_usb.c,v 4.36 2005/04/08 09:55:13 martinb1 Exp $ * * modular HiSax ISDN driver for Colognechip HFC-S USB chip * @@ -44,12 +44,8 @@ #include "hisax_if.h" #include "hfc_usb.h" -/* -* Version Information -* (do not modify the CVS Makros $Revision: 4.34 $ and $Date: 2005/01/26 17:25:53 $ !) -*/ static const char *hfcusb_revision = - "Revision: 4.34 $ Date: 2005/01/26 17:25:53 $ "; + "$Revision: 4.36 $ $Date: 2005/04/08 09:55:13 $ "; /* Hisax debug support * use "modprobe debug=x" where x is bitfield of USB_DBG & ISDN_DBG @@ -63,81 +59,89 @@ module_param(debug, uint, 0); static int hfc_debug; #endif +/* private vendor specific data */ +typedef struct { + __u8 led_scheme; // led display scheme + signed short led_bits[8]; // array of 8 possible LED bitmask settings + char *vend_name; // device name +} hfcsusb_vdata; /****************************************/ /* data defining the devices to be used */ /****************************************/ -static struct usb_device_id hfc_usb_idtab[] = { - {USB_DEVICE(0x0959, 0x2bd0)}, /* Colognechip USB eval TA */ - {USB_DEVICE(0x0675, 0x1688)}, /* DrayTek miniVigor 128 USB ISDN TA */ - {USB_DEVICE(0x07b0, 0x0007)}, /* Billion USB TA 2 */ - {USB_DEVICE(0x0742, 0x2008)}, /* Stollmann USB TA */ - {USB_DEVICE(0x0742, 0x2009)}, /* Aceex USB ISDN TA */ - {USB_DEVICE(0x0742, 0x200A)}, /* OEM USB ISDN TA */ - {USB_DEVICE(0x08e3, 0x0301)}, /* OliTec ISDN USB */ - {USB_DEVICE(0x07fa, 0x0846)}, /* Bewan ISDN USB TA */ - {USB_DEVICE(0x07fa, 0x0847)}, /* Djinn Numeris USB */ - {USB_DEVICE(0x07b0, 0x0006)}, /* Twister ISDN USB TA */ - {} /* end with an all-zeroes entry */ +static struct usb_device_id hfcusb_idtab[] = { + { + .idVendor = 0x0959, + .idProduct = 0x2bd0, + .driver_info = (unsigned long) &((hfcsusb_vdata) + {LED_OFF, {4, 0, 2, 1}, + "ISDN USB TA (Cologne Chip HFC-S USB based)"}), + }, + { + .idVendor = 0x0675, + .idProduct = 0x1688, + .driver_info = (unsigned long) &((hfcsusb_vdata) + {LED_SCHEME1, {1, 2, 0, 0}, + "DrayTek miniVigor 128 USB ISDN TA"}), + }, + { + .idVendor = 0x07b0, + .idProduct = 0x0007, + .driver_info = (unsigned long) &((hfcsusb_vdata) + {LED_SCHEME1, {0x80, -64, -32, -16}, + "Billion tiny USB ISDN TA 128"}), + }, + { + .idVendor = 0x0742, + .idProduct = 0x2008, + .driver_info = (unsigned long) &((hfcsusb_vdata) + {LED_SCHEME1, {4, 0, 2, 1}, + "Stollmann USB TA"}), + }, + { + .idVendor = 0x0742, + .idProduct = 0x2009, + .driver_info = (unsigned long) &((hfcsusb_vdata) + {LED_SCHEME1, {4, 0, 2, 1}, + "Aceex USB ISDN TA"}), + }, + { + .idVendor = 0x0742, + .idProduct = 0x200A, + .driver_info = (unsigned long) &((hfcsusb_vdata) + {LED_SCHEME1, {4, 0, 2, 1}, + "OEM USB ISDN TA"}), + }, + { + .idVendor = 0x08e3, + .idProduct = 0x0301, + .driver_info = (unsigned long) &((hfcsusb_vdata) + {LED_SCHEME1, {2, 0, 1, 4}, + "Olitec USB RNIS"}), + }, + { + .idVendor = 0x07fa, + .idProduct = 0x0846, + .driver_info = (unsigned long) &((hfcsusb_vdata) + {LED_SCHEME1, {0x80, -64, -32, -16}, + "Bewan Modem RNIS USB"}), + }, + { + .idVendor = 0x07fa, + .idProduct = 0x0847, + .driver_info = (unsigned long) &((hfcsusb_vdata) + {LED_SCHEME1, {0x80, -64, -32, -16}, + "Djinn Numeris USB"}), + }, + { + .idVendor = 0x07b0, + .idProduct = 0x0006, + .driver_info = (unsigned long) &((hfcsusb_vdata) + {LED_SCHEME1, {0x80, -64, -32, -16}, + "Twister ISDN TA"}), + }, }; -/* driver internal device specific data: -* VendorID, ProductID, Devicename, LED_SCHEME, -* LED's BitMask in HFCUSB_P_DATA Register : LED_USB, LED_S0, LED_B1, LED_B2 -*/ -static vendor_data vdata[] = { - /* CologneChip Eval TA */ - {0x0959, 0x2bd0, "ISDN USB TA (Cologne Chip HFC-S USB based)", - LED_OFF, {4, 0, 2, 1} - } - , - /* DrayTek miniVigor 128 USB ISDN TA */ - {0x0675, 0x1688, "DrayTek miniVigor 128 USB ISDN TA", - LED_SCHEME1, {1, 2, 0, 0} - } - , - /* Billion TA */ - {0x07b0, 0x0007, "Billion tiny USB ISDN TA 128", - LED_SCHEME1, {0x80, -64, -32, -16} - } - , - /* Stollmann TA */ - {0x0742, 0x2008, "Stollmann USB TA", - LED_SCHEME1, {4, 0, 2, 1} - } - , - /* Aceex USB ISDN TA */ - {0x0742, 0x2009, "Aceex USB ISDN TA", - LED_SCHEME1, {4, 0, 2, 1} - } - , - /* OEM USB ISDN TA */ - {0x0742, 0x200A, "OEM USB ISDN TA", - LED_SCHEME1, {4, 0, 2, 1} - } - , - /* Olitec TA */ - {0x08e3, 0x0301, "Olitec USB RNIS", - LED_SCHEME1, {2, 0, 1, 4} - } - , - /* Bewan TA */ - {0x07fa, 0x0846, "Bewan Modem RNIS USB", - LED_SCHEME1, {0x80, -64, -32, -16} - } - , - /* Bewan TA */ - {0x07fa, 0x0847, "Djinn Numeris USB", - LED_SCHEME1, {0x80, -64, -32, -16} - } - , - /* Twister ISDN TA */ - {0x07b0, 0x0006, "Twister ISDN TA", - LED_SCHEME1, {0x80, -64, -32, -16} - } - , - {0, 0, 0} /* EOL element */ -}; /***************************************************************/ /* structure defining input+output fifos (interrupt/bulk mode) */ @@ -211,8 +215,6 @@ typedef struct hfcusb_data { volatile __u8 l1_state; /* actual l1 state */ struct timer_list t3_timer; /* timer 3 for activation/deactivation */ struct timer_list t4_timer; /* timer 4 for activation/deactivation */ - struct timer_list led_timer; /* timer flashing leds */ - } hfcusb_data; @@ -227,7 +229,7 @@ symbolic(struct hfcusb_symbolic_list list[], const int num) for (i = 0; list[i].name != NULL; i++) if (list[i].num == num) return (list[i].name); - return ""; + return ""; } @@ -335,93 +337,57 @@ set_led_bit(hfcusb_data * hfc, signed short led_bits, int unset) } } -/******************************************/ -/* invert B-channel LEDs if data is sent */ -/******************************************/ -static void -led_timer(hfcusb_data * hfc) -{ - static int cnt = 0; - - if (cnt) { - if (hfc->led_b_active & 1) - set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[2], - 0); - if (hfc->led_b_active & 2) - set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[3], - 0); - } else { - if (!(hfc->led_b_active & 1) || hfc->led_new_data & 1) - set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[2], - 1); - if (!(hfc->led_b_active & 2) || hfc->led_new_data & 2) - set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[3], - 1); - } - - write_led(hfc, hfc->led_state); - hfc->led_new_data = 0; - - cnt = !cnt; - - /* restart 4 hz timer */ - if (!timer_pending(&hfc->led_timer)) { - add_timer(&hfc->led_timer); - hfc->led_timer.expires = jiffies + (LED_TIME * HZ) / 1000; - } -} - /**************************/ /* handle LED requests */ /**************************/ static void handle_led(hfcusb_data * hfc, int event) { + hfcsusb_vdata *driver_info = + (hfcsusb_vdata *) hfcusb_idtab[hfc->vend_idx].driver_info; + /* if no scheme -> no LED action */ - if (vdata[hfc->vend_idx].led_scheme == LED_OFF) + if (driver_info->led_scheme == LED_OFF) return; switch (event) { case LED_POWER_ON: - set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[0], + set_led_bit(hfc, driver_info->led_bits[0], 0); - set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[1], + set_led_bit(hfc, driver_info->led_bits[1], 1); - set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[2], + set_led_bit(hfc, driver_info->led_bits[2], 1); - set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[3], + set_led_bit(hfc, driver_info->led_bits[3], 1); break; case LED_POWER_OFF: /* no Power off handling */ break; case LED_S0_ON: - set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[1], + set_led_bit(hfc, driver_info->led_bits[1], 0); break; case LED_S0_OFF: - set_led_bit(hfc, vdata[hfc->vend_idx].led_bits[1], + set_led_bit(hfc, driver_info->led_bits[1], 1); break; case LED_B1_ON: - hfc->led_b_active |= 1; + set_led_bit(hfc, driver_info->led_bits[2], + 0); break; case LED_B1_OFF: - hfc->led_b_active &= ~1; - break; - case LED_B1_DATA: - hfc->led_new_data |= 1; + set_led_bit(hfc, driver_info->led_bits[2], + 1); break; case LED_B2_ON: - hfc->led_b_active |= 2; + set_led_bit(hfc, driver_info->led_bits[3], + 0); break; case LED_B2_OFF: - hfc->led_b_active &= ~2; - break; - case LED_B2_DATA: - hfc->led_new_data |= 2; + set_led_bit(hfc, driver_info->led_bits[3], + 1); break; } - write_led(hfc, hfc->led_state); } @@ -725,14 +691,6 @@ tx_iso_complete(struct urb *urb, struct pt_regs *regs) current_len + 1; tx_offset += (current_len + 1); - if (!transp_mode) { - if (fifon == HFCUSB_B1_TX) - handle_led(hfc, - LED_B1_DATA); - if (fifon == HFCUSB_B2_TX) - handle_led(hfc, - LED_B2_DATA); - } } else { urb->iso_frame_desc[k].offset = tx_offset++; @@ -966,14 +924,6 @@ collect_rx_frame(usb_fifo * fifo, __u8 * data, int len, int finish) skb_trim(fifo->skbuff, 0); } } - - /* LED flashing only in HDLC mode */ - if (!transp_mode) { - if (fifon == HFCUSB_B1_RX) - handle_led(hfc, LED_B1_DATA); - if (fifon == HFCUSB_B2_RX) - handle_led(hfc, LED_B2_DATA); - } } /***********************************************/ @@ -1339,17 +1289,6 @@ usb_init(hfcusb_data * hfc) hfc->t4_timer.data = (long) hfc; hfc->t4_timer.function = (void *) l1_timer_expire_t4; - /* init the led timer */ - init_timer(&hfc->led_timer); - hfc->led_timer.data = (long) hfc; - hfc->led_timer.function = (void *) led_timer; - - /* trigger 4 hz led timer */ - if (!timer_pending(&hfc->led_timer)) { - hfc->led_timer.expires = jiffies + (LED_TIME * HZ) / 1000; - add_timer(&hfc->led_timer); - } - /* init the background machinery for control requests */ hfc->ctrl_read.bRequestType = 0xc0; hfc->ctrl_read.bRequest = 1; @@ -1440,13 +1379,18 @@ hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) attr, cfg_found, cidx, ep_addr; int cmptbl[16], small_match, iso_packet_size, packet_size, alt_used = 0; + hfcsusb_vdata *driver_info; vend_idx = 0xffff; - for (i = 0; vdata[i].vendor; i++) { - if (dev->descriptor.idVendor == vdata[i].vendor - && dev->descriptor.idProduct == vdata[i].prod_id) + for (i = 0; hfcusb_idtab[i].idVendor; i++) { + if (dev->descriptor.idVendor == hfcusb_idtab[i].idVendor + && dev->descriptor.idProduct == + hfcusb_idtab[i].idProduct) { vend_idx = i; + continue; + } } + #ifdef CONFIG_HISAX_DEBUG DBG(USB_DBG, "HFC-USB: probing interface(%d) actalt(%d) minor(%d)\n", ifnum, @@ -1457,10 +1401,6 @@ hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) ifnum, iface->desc.bAlternateSetting, intf->minor); if (vend_idx != 0xffff) { -#ifdef CONFIG_HISAX_DEBUG - DBG(USB_DBG, "HFC-S USB: found vendor idx:%d name:%s", - vend_idx, vdata[vend_idx].vend_name); -#endif /* if vendor and product ID is OK, start probing alternate settings */ alt_idx = 0; small_match = 0xffff; @@ -1687,9 +1627,11 @@ hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) usb_sndctrlpipe(context->dev, 0); context->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); - printk(KERN_INFO - "HFC-S USB: detected \"%s\"\n", - vdata[vend_idx].vend_name); + driver_info = + (hfcsusb_vdata *) hfcusb_idtab[vend_idx]. + driver_info; + printk(KERN_INFO "HFC-S USB: detected \"%s\"\n", + driver_info->vend_name); #ifdef CONFIG_HISAX_DEBUG DBG(USB_DBG, "HFC-S USB: Endpoint-Config: %s (if=%d alt=%d)\n", @@ -1740,8 +1682,6 @@ hfc_usb_disconnect(struct usb_interface del_timer(&context->t3_timer); if (timer_pending(&context->t4_timer)) del_timer(&context->t4_timer); - if (timer_pending(&context->led_timer)) - del_timer(&context->led_timer); /* tell all fifos to terminate */ for (i = 0; i < HFCUSB_NUM_FIFOS; i++) { if (context->fifos[i].usb_transfer_mode == USB_ISOC) { @@ -1785,9 +1725,11 @@ hfc_usb_disconnect(struct usb_interface /* our driver information structure */ /************************************/ static struct usb_driver hfc_drv = { - .owner = THIS_MODULE,.name = - "hfc_usb",.id_table = hfc_usb_idtab,.probe = - hfc_usb_probe,.disconnect = hfc_usb_disconnect, + .owner = THIS_MODULE, + .name = "hfc_usb", + .id_table = hfcusb_idtab, + .probe = hfc_usb_probe, + .disconnect = hfc_usb_disconnect, }; static void __exit hfc_usb_exit(void) @@ -1825,4 +1767,4 @@ module_exit(hfc_usb_exit); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(usb, hfc_usb_idtab); +MODULE_DEVICE_TABLE(usb, hfcusb_idtab); diff --git a/drivers/isdn/hisax/hfc_usb.h b/drivers/isdn/hisax/hfc_usb.h index 280dd29b30d6fbd0efaaf0f715a15637ab759b49..ec52c1a7c22afca97308f353e139eead2dd2b33a 100644 --- a/drivers/isdn/hisax/hfc_usb.h +++ b/drivers/isdn/hisax/hfc_usb.h @@ -1,7 +1,7 @@ /* * hfc_usb.h * -* $Id: hfc_usb.h,v 4.1 2005/01/26 17:25:53 martinb1 Exp $ +* $Id: hfc_usb.h,v 4.2 2005/04/07 15:27:17 martinb1 Exp $ */ #ifndef __HFC_USB_H__ @@ -91,7 +91,7 @@ /**********/ /* macros */ /**********/ -#define write_usb(a,b,c)usb_control_msg((a)->dev,(a)->ctrl_out_pipe,0,0x40,(c),(b),0,0,HFC_CTRL_TIMEOUT) +#define write_usb(a,b,c)usb_control_msg((a)->dev,(a)->ctrl_out_pipe,0,0x40,(c),(b),NULL,0,HFC_CTRL_TIMEOUT) #define read_usb(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_in_pipe,1,0xC0,0,(b),(c),1,HFC_CTRL_TIMEOUT) @@ -186,6 +186,7 @@ static int validconf[][19] = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} // EOL element }; +#ifdef CONFIG_HISAX_DEBUG // string description of chosen config static char *conf_str[] = { "4 Interrupt IN + 3 Isochron OUT", @@ -193,6 +194,7 @@ static char *conf_str[] = { "4 Isochron IN + 3 Isochron OUT", "3 Isochron IN + 3 Isochron OUT" }; +#endif typedef struct { diff --git a/drivers/isdn/hisax/hscx.c b/drivers/isdn/hisax/hscx.c index 66dbaee77bfbd005ecd5db41b32e4cd459bec8c3..c8f9951f7914a4c8d1e387544c3d5bbab4a1cd8f 100644 --- a/drivers/isdn/hisax/hscx.c +++ b/drivers/isdn/hisax/hscx.c @@ -156,14 +156,10 @@ close_hscxstate(struct BCState *bcs) { modehscx(bcs, 0, bcs->channel); if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - if (bcs->hw.hscx.rcvbuf) { - kfree(bcs->hw.hscx.rcvbuf); - bcs->hw.hscx.rcvbuf = NULL; - } - if (bcs->blog) { - kfree(bcs->blog); - bcs->blog = NULL; - } + kfree(bcs->hw.hscx.rcvbuf); + bcs->hw.hscx.rcvbuf = NULL; + kfree(bcs->blog); + bcs->blog = NULL; skb_queue_purge(&bcs->rqueue); skb_queue_purge(&bcs->squeue); if (bcs->tx_skb) { diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c index b4ca5859b1777cb1e99f88f7fb95714644a845ee..c615752b96aa21b3fb55db5be71e4df42963b3d9 100644 --- a/drivers/isdn/hisax/icc.c +++ b/drivers/isdn/hisax/icc.c @@ -571,14 +571,10 @@ setstack_icc(struct PStack *st, struct IsdnCardState *cs) static void DC_Close_icc(struct IsdnCardState *cs) { - if (cs->dc.icc.mon_rx) { - kfree(cs->dc.icc.mon_rx); - cs->dc.icc.mon_rx = NULL; - } - if (cs->dc.icc.mon_tx) { - kfree(cs->dc.icc.mon_tx); - cs->dc.icc.mon_tx = NULL; - } + kfree(cs->dc.icc.mon_rx); + cs->dc.icc.mon_rx = NULL; + kfree(cs->dc.icc.mon_tx); + cs->dc.icc.mon_tx = NULL; } static void diff --git a/drivers/isdn/hisax/ipacx.c b/drivers/isdn/hisax/ipacx.c index efba2f44801797f726f30c6033b14dfc3d65611a..2e9afae1254a1a42731936e7e68ef6e1d95cda8a 100644 --- a/drivers/isdn/hisax/ipacx.c +++ b/drivers/isdn/hisax/ipacx.c @@ -762,14 +762,10 @@ bch_close_state(struct BCState *bcs) { bch_mode(bcs, 0, bcs->channel); if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - if (bcs->hw.hscx.rcvbuf) { - kfree(bcs->hw.hscx.rcvbuf); - bcs->hw.hscx.rcvbuf = NULL; - } - if (bcs->blog) { - kfree(bcs->blog); - bcs->blog = NULL; - } + kfree(bcs->hw.hscx.rcvbuf); + bcs->hw.hscx.rcvbuf = NULL; + kfree(bcs->blog); + bcs->blog = NULL; skb_queue_purge(&bcs->rqueue); skb_queue_purge(&bcs->squeue); if (bcs->tx_skb) { diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c index 85e063a08d23e3410215e8c519a729b59a5352de..565b7892c2672780dc31d773e8d5a492b37a6229 100644 --- a/drivers/isdn/hisax/isac.c +++ b/drivers/isdn/hisax/isac.c @@ -570,15 +570,12 @@ setstack_isac(struct PStack *st, struct IsdnCardState *cs) } static void -DC_Close_isac(struct IsdnCardState *cs) { - if (cs->dc.isac.mon_rx) { - kfree(cs->dc.isac.mon_rx); - cs->dc.isac.mon_rx = NULL; - } - if (cs->dc.isac.mon_tx) { - kfree(cs->dc.isac.mon_tx); - cs->dc.isac.mon_tx = NULL; - } +DC_Close_isac(struct IsdnCardState *cs) +{ + kfree(cs->dc.isac.mon_rx); + cs->dc.isac.mon_rx = NULL; + kfree(cs->dc.isac.mon_tx); + cs->dc.isac.mon_tx = NULL; } static void diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c index 642a87c51295c70055509678fa71a370a766f9f2..674af673ff965e9bb48b8e7c2ac9b4452e1607e5 100644 --- a/drivers/isdn/hisax/isar.c +++ b/drivers/isdn/hisax/isar.c @@ -1688,10 +1688,8 @@ close_isarstate(struct BCState *bcs) { modeisar(bcs, 0, bcs->channel); if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - if (bcs->hw.isar.rcvbuf) { - kfree(bcs->hw.isar.rcvbuf); - bcs->hw.isar.rcvbuf = NULL; - } + kfree(bcs->hw.isar.rcvbuf); + bcs->hw.isar.rcvbuf = NULL; skb_queue_purge(&bcs->rqueue); skb_queue_purge(&bcs->squeue); if (bcs->tx_skb) { diff --git a/drivers/isdn/hisax/jade.c b/drivers/isdn/hisax/jade.c index 363ae3179bbde9a255148c56c5e90a5e6d0eaf81..2659fecc26747a470ef2f099c1a98aab84dd23a0 100644 --- a/drivers/isdn/hisax/jade.c +++ b/drivers/isdn/hisax/jade.c @@ -195,14 +195,10 @@ close_jadestate(struct BCState *bcs) { modejade(bcs, 0, bcs->channel); if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - if (bcs->hw.hscx.rcvbuf) { - kfree(bcs->hw.hscx.rcvbuf); - bcs->hw.hscx.rcvbuf = NULL; - } - if (bcs->blog) { - kfree(bcs->blog); - bcs->blog = NULL; - } + kfree(bcs->hw.hscx.rcvbuf); + bcs->hw.hscx.rcvbuf = NULL; + kfree(bcs->blog); + bcs->blog = NULL; skb_queue_purge(&bcs->rqueue); skb_queue_purge(&bcs->squeue); if (bcs->tx_skb) { diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c index 94da03c30c51507c1af9c74d449e04930a4a3c52..47a47ef0968bf3d0abaf612fdfd58598187b94c8 100644 --- a/drivers/isdn/hisax/netjet.c +++ b/drivers/isdn/hisax/netjet.c @@ -855,14 +855,10 @@ close_tigerstate(struct BCState *bcs) { mode_tiger(bcs, 0, bcs->channel); if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - if (bcs->hw.tiger.rcvbuf) { - kfree(bcs->hw.tiger.rcvbuf); - bcs->hw.tiger.rcvbuf = NULL; - } - if (bcs->hw.tiger.sendbuf) { - kfree(bcs->hw.tiger.sendbuf); - bcs->hw.tiger.sendbuf = NULL; - } + kfree(bcs->hw.tiger.rcvbuf); + bcs->hw.tiger.rcvbuf = NULL; + kfree(bcs->hw.tiger.sendbuf); + bcs->hw.tiger.sendbuf = NULL; skb_queue_purge(&bcs->rqueue); skb_queue_purge(&bcs->squeue); if (bcs->tx_skb) { @@ -967,20 +963,12 @@ inittiger(struct IsdnCardState *cs) static void releasetiger(struct IsdnCardState *cs) { - if (cs->bcs[0].hw.tiger.send) { - kfree(cs->bcs[0].hw.tiger.send); - cs->bcs[0].hw.tiger.send = NULL; - } - if (cs->bcs[1].hw.tiger.send) { - cs->bcs[1].hw.tiger.send = NULL; - } - if (cs->bcs[0].hw.tiger.rec) { - kfree(cs->bcs[0].hw.tiger.rec); - cs->bcs[0].hw.tiger.rec = NULL; - } - if (cs->bcs[1].hw.tiger.rec) { - cs->bcs[1].hw.tiger.rec = NULL; - } + kfree(cs->bcs[0].hw.tiger.send); + cs->bcs[0].hw.tiger.send = NULL; + cs->bcs[1].hw.tiger.send = NULL; + kfree(cs->bcs[0].hw.tiger.rec); + cs->bcs[0].hw.tiger.rec = NULL; + cs->bcs[1].hw.tiger.rec = NULL; } void diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c index 89fbeb58485de92d158631bf69822d314176a9c4..b096b64b0253cd2e95806356d698d128af5b2b2b 100644 --- a/drivers/isdn/hisax/st5481_usb.c +++ b/drivers/isdn/hisax/st5481_usb.c @@ -335,14 +335,12 @@ void st5481_release_usb(struct st5481_adapter *adapter) // Stop and free Control and Interrupt URBs usb_kill_urb(ctrl->urb); - if (ctrl->urb->transfer_buffer) - kfree(ctrl->urb->transfer_buffer); + kfree(ctrl->urb->transfer_buffer); usb_free_urb(ctrl->urb); ctrl->urb = NULL; usb_kill_urb(intr->urb); - if (intr->urb->transfer_buffer) - kfree(intr->urb->transfer_buffer); + kfree(intr->urb->transfer_buffer); usb_free_urb(intr->urb); ctrl->urb = NULL; } @@ -457,8 +455,7 @@ st5481_setup_isocpipes(struct urb* urb[2], struct usb_device *dev, err: for (j = 0; j < 2; j++) { if (urb[j]) { - if (urb[j]->transfer_buffer) - kfree(urb[j]->transfer_buffer); + kfree(urb[j]->transfer_buffer); urb[j]->transfer_buffer = NULL; usb_free_urb(urb[j]); urb[j] = NULL; @@ -473,8 +470,7 @@ void st5481_release_isocpipes(struct urb* urb[2]) for (j = 0; j < 2; j++) { usb_kill_urb(urb[j]); - if (urb[j]->transfer_buffer) - kfree(urb[j]->transfer_buffer); + kfree(urb[j]->transfer_buffer); usb_free_urb(urb[j]); urb[j] = NULL; } diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c index 7baf8e4884716080266b3eb3df37a7d41152da41..0352ee5f706ca904244839b102edb84746ca580a 100644 --- a/drivers/isdn/hisax/w6692.c +++ b/drivers/isdn/hisax/w6692.c @@ -819,14 +819,10 @@ close_w6692state(struct BCState *bcs) { W6692Bmode(bcs, 0, bcs->channel); if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - if (bcs->hw.w6692.rcvbuf) { - kfree(bcs->hw.w6692.rcvbuf); - bcs->hw.w6692.rcvbuf = NULL; - } - if (bcs->blog) { - kfree(bcs->blog); - bcs->blog = NULL; - } + kfree(bcs->hw.w6692.rcvbuf); + bcs->hw.w6692.rcvbuf = NULL; + kfree(bcs->blog); + bcs->blog = NULL; skb_queue_purge(&bcs->rqueue); skb_queue_purge(&bcs->squeue); if (bcs->tx_skb) { diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c index 639582f61f41e416e98dbb493a70a9a3d1f7df15..87f59a0e2a959cbabd23ded727e53949dc49eb75 100644 --- a/drivers/isdn/hysdn/hysdn_procconf.c +++ b/drivers/isdn/hysdn/hysdn_procconf.c @@ -359,8 +359,7 @@ hysdn_conf_close(struct inode *ino, struct file *filep) } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { /* read access -> output card info data */ - if (filep->private_data) - kfree(filep->private_data); /* release memory */ + kfree(filep->private_data); /* release memory */ } unlock_kernel(); return (retval); diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index d97a9be5469c45deb6f8d5965a3a84125c446314..1a19a0f894288907c30ea2fbb91790db3d67a584 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -364,10 +364,8 @@ isdn_ppp_release(int min, struct file *file) isdn_net_hangup(&p->dev); } for (i = 0; i < NUM_RCV_BUFFS; i++) { - if (is->rq[i].buf) { - kfree(is->rq[i].buf); - is->rq[i].buf = NULL; - } + kfree(is->rq[i].buf); + is->rq[i].buf = NULL; } is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */ is->last = is->rq; @@ -378,14 +376,10 @@ isdn_ppp_release(int min, struct file *file) is->slcomp = NULL; #endif #ifdef CONFIG_IPPP_FILTER - if (is->pass_filter) { - kfree(is->pass_filter); - is->pass_filter = NULL; - } - if (is->active_filter) { - kfree(is->active_filter); - is->active_filter = NULL; - } + kfree(is->pass_filter); + is->pass_filter = NULL; + kfree(is->active_filter); + is->active_filter = NULL; #endif /* TODO: if this was the previous master: link the stuff to the new master */ @@ -914,8 +908,7 @@ isdn_ppp_cleanup(void) kfree(ippp_table[i]); #ifdef CONFIG_ISDN_MPP - if (isdn_ppp_bundle_arr) - kfree(isdn_ppp_bundle_arr); + kfree(isdn_ppp_bundle_arr); #endif /* CONFIG_ISDN_MPP */ } diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index b37ef1f06b3dffa55e36c313f7dd7238a1b6ceb0..8c404b4e2482d4769a263514faa9b68eb05ca4e6 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -712,22 +712,14 @@ isdn_tty_modem_hup(modem_info * info, int local) #endif info->emu.vpar[4] = 0; info->emu.vpar[5] = 8; - if (info->dtmf_state) { - kfree(info->dtmf_state); - info->dtmf_state = NULL; - } - if (info->silence_state) { - kfree(info->silence_state); - info->silence_state = NULL; - } - if (info->adpcms) { - kfree(info->adpcms); - info->adpcms = NULL; - } - if (info->adpcmr) { - kfree(info->adpcmr); - info->adpcmr = NULL; - } + kfree(info->dtmf_state); + info->dtmf_state = NULL; + kfree(info->silence_state); + info->silence_state = NULL; + kfree(info->adpcms); + info->adpcms = NULL; + kfree(info->adpcmr); + info->adpcmr = NULL; #endif if ((info->msr & UART_MSR_RI) && (info->emu.mdmreg[REG_RUNG] & BIT_RUNG)) @@ -1721,8 +1713,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp) */ timeout = jiffies + HZ; while (!(info->lsr & UART_LSR_TEMT)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(20); + schedule_timeout_interruptible(20); if (time_after(jiffies,timeout)) break; } diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c index 386df71eee7473f0c7582c26331bdee63c623b68..6649f8bc99512247cdbfb6142dbfcce40f0669b0 100644 --- a/drivers/isdn/icn/icn.c +++ b/drivers/isdn/icn/icn.c @@ -947,8 +947,7 @@ icn_loadproto(u_char __user * buffer, icn_card * card) icn_maprelease_channel(card, 0); return -EIO; } - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(10); + schedule_timeout_interruptible(10); } } writeb(0x20, &sbuf_n); diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c index 14e1f8fbc61f05643dd4abcf3f4ee1ba4261981a..33d33970041173e54fe52cd25f21fe7e5275abf3 100644 --- a/drivers/isdn/isdnloop/isdnloop.c +++ b/drivers/isdn/isdnloop/isdnloop.c @@ -1161,12 +1161,9 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card) if (a) { if (!card->leased) { card->leased = 1; - while (card->ptype == ISDN_PTYPE_UNKNOWN) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(10); - } - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(10); + while (card->ptype == ISDN_PTYPE_UNKNOWN) + schedule_timeout_interruptible(10); + schedule_timeout_interruptible(10); sprintf(cbuf, "00;FV2ON\n01;EAZ1\n02;EAZ2\n"); i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); printk(KERN_INFO diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c index 5de861f4081605ec66d0c375291dda166c8bae80..94f21486bb24d667b4c22b29e2c507e30262919b 100644 --- a/drivers/isdn/pcbit/drv.c +++ b/drivers/isdn/pcbit/drv.c @@ -561,10 +561,8 @@ void pcbit_l3_receive(struct pcbit_dev * dev, ulong msg, else pcbit_fsm_event(dev, chan, EV_USR_RELEASE_REQ, NULL); - if (cbdata.data.setup.CalledPN) - kfree(cbdata.data.setup.CalledPN); - if (cbdata.data.setup.CallingPN) - kfree(cbdata.data.setup.CallingPN); + kfree(cbdata.data.setup.CalledPN); + kfree(cbdata.data.setup.CallingPN); break; case MSG_CONN_CONF: diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c index 1ebed041672d0c3876c892c515e218997a58f38a..62b7acfad8a4fcd289b05735d1f51a21790c658e 100644 --- a/drivers/isdn/sc/init.c +++ b/drivers/isdn/sc/init.c @@ -529,8 +529,7 @@ static int identify_board(unsigned long rambase, unsigned int iobase) */ x = 0; while((inb(iobase + FIFOSTAT_OFFSET) & RF_HAS_DATA) && x < 100) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_interruptible(1); x++; } if(x == 100) { diff --git a/drivers/isdn/sc/message.c b/drivers/isdn/sc/message.c index ca204da3257d3918ae150c30d8b08a2e92bd35db..0a0fe6b8039bbe8cea80b815a1526799c31c8376 100644 --- a/drivers/isdn/sc/message.c +++ b/drivers/isdn/sc/message.c @@ -208,8 +208,7 @@ int send_and_receive(int card, tries = 0; /* wait for the response */ while (tries < timeout) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_interruptible(1); pr_debug("SAR waiting..\n"); diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index bc3e096d84f75a5660e1c98ba9db99d955a1a075..a0ea44c3e8b10ec9ca68689718c3da6423961e3b 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -169,6 +169,25 @@ config THERM_PM72 This driver provides thermostat and fan control for the desktop G5 machines. +config WINDFARM + tristate "New PowerMac thermal control infrastructure" + +config WINDFARM_PM81 + tristate "Support for thermal management on iMac G5" + depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU + select I2C_PMAC_SMU + help + This driver provides thermal control for the iMacG5 + +config WINDFARM_PM91 + tristate "Support for thermal management on PowerMac9,1" + depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU + select I2C_PMAC_SMU + help + This driver provides thermal control for the PowerMac9,1 + which is the recent (SMU based) single CPU desktop G5 + + config ANSLCD tristate "Support for ANS LCD display" depends on ADB_CUDA && PPC_PMAC diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile index 236291bd48a4117fe4e7eb12ae8075a9142a2ebd..f4657aa81fb0474d92f1c525af90015db1d5a6c3 100644 --- a/drivers/macintosh/Makefile +++ b/drivers/macintosh/Makefile @@ -26,3 +26,12 @@ obj-$(CONFIG_ADB_MACIO) += macio-adb.o obj-$(CONFIG_THERM_PM72) += therm_pm72.o obj-$(CONFIG_THERM_WINDTUNNEL) += therm_windtunnel.o obj-$(CONFIG_THERM_ADT746X) += therm_adt746x.o +obj-$(CONFIG_WINDFARM) += windfarm_core.o +obj-$(CONFIG_WINDFARM_PM81) += windfarm_smu_controls.o \ + windfarm_smu_sensors.o \ + windfarm_lm75_sensor.o windfarm_pid.o \ + windfarm_cpufreq_clamp.o windfarm_pm81.o +obj-$(CONFIG_WINDFARM_PM91) += windfarm_smu_controls.o \ + windfarm_smu_sensors.o \ + windfarm_lm75_sensor.o windfarm_pid.o \ + windfarm_cpufreq_clamp.o windfarm_pm91.o diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index 8f02c155fdc0e26693ce5babe3abe1b5e14221be..c0b46bceb5df88709348e4e6e4bdc68ec93499ed 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -857,8 +857,7 @@ adbhid_input_register(int id, int default_id, int original_handler_id, static void adbhid_input_unregister(int id) { input_unregister_device(adbhid[id]->input); - if (adbhid[id]->keycode) - kfree(adbhid[id]->keycode); + kfree(adbhid[id]->keycode); kfree(adbhid[id]); adbhid[id] = NULL; } diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index 34f3c7e2d832921e783e21e9c22b806d07b71421..e8378274d710f02f0d93facd8de2fa050ec6e4f4 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c @@ -47,13 +47,13 @@ #include #include -#define VERSION "0.6" +#define VERSION "0.7" #define AUTHOR "(c) 2005 Benjamin Herrenschmidt, IBM Corp." #undef DEBUG_SMU #ifdef DEBUG_SMU -#define DPRINTK(fmt, args...) do { printk(KERN_DEBUG fmt , ##args); } while (0) +#define DPRINTK(fmt, args...) do { udbg_printf(KERN_DEBUG fmt , ##args); } while (0) #else #define DPRINTK(fmt, args...) do { } while (0) #endif @@ -92,7 +92,7 @@ struct smu_device { * for now, just hard code that */ static struct smu_device *smu; - +static DECLARE_MUTEX(smu_part_access); /* * SMU driver low level stuff @@ -113,9 +113,11 @@ static void smu_start_cmd(void) DPRINTK("SMU: starting cmd %x, %d bytes data\n", cmd->cmd, cmd->data_len); - DPRINTK("SMU: data buffer: %02x %02x %02x %02x ...\n", + DPRINTK("SMU: data buffer: %02x %02x %02x %02x %02x %02x %02x %02x\n", ((u8 *)cmd->data_buf)[0], ((u8 *)cmd->data_buf)[1], - ((u8 *)cmd->data_buf)[2], ((u8 *)cmd->data_buf)[3]); + ((u8 *)cmd->data_buf)[2], ((u8 *)cmd->data_buf)[3], + ((u8 *)cmd->data_buf)[4], ((u8 *)cmd->data_buf)[5], + ((u8 *)cmd->data_buf)[6], ((u8 *)cmd->data_buf)[7]); /* Fill the SMU command buffer */ smu->cmd_buf->cmd = cmd->cmd; @@ -440,7 +442,7 @@ int smu_present(void) EXPORT_SYMBOL(smu_present); -int smu_init (void) +int __init smu_init (void) { struct device_node *np; u32 *data; @@ -588,6 +590,8 @@ static void smu_expose_childs(void *unused) sprintf(name, "smu-i2c-%02x", *reg); of_platform_device_create(np, name, &smu->of_dev->dev); } + if (device_is_compatible(np, "smu-sensors")) + of_platform_device_create(np, "smu-sensors", &smu->of_dev->dev); } } @@ -845,6 +849,156 @@ int smu_queue_i2c(struct smu_i2c_cmd *cmd) return 0; } +/* + * Handling of "partitions" + */ + +static int smu_read_datablock(u8 *dest, unsigned int addr, unsigned int len) +{ + DECLARE_COMPLETION(comp); + unsigned int chunk; + struct smu_cmd cmd; + int rc; + u8 params[8]; + + /* We currently use a chunk size of 0xe. We could check the + * SMU firmware version and use bigger sizes though + */ + chunk = 0xe; + + while (len) { + unsigned int clen = min(len, chunk); + + cmd.cmd = SMU_CMD_MISC_ee_COMMAND; + cmd.data_len = 7; + cmd.data_buf = params; + cmd.reply_len = chunk; + cmd.reply_buf = dest; + cmd.done = smu_done_complete; + cmd.misc = ∁ + params[0] = SMU_CMD_MISC_ee_GET_DATABLOCK_REC; + params[1] = 0x4; + *((u32 *)¶ms[2]) = addr; + params[6] = clen; + + rc = smu_queue_cmd(&cmd); + if (rc) + return rc; + wait_for_completion(&comp); + if (cmd.status != 0) + return rc; + if (cmd.reply_len != clen) { + printk(KERN_DEBUG "SMU: short read in " + "smu_read_datablock, got: %d, want: %d\n", + cmd.reply_len, clen); + return -EIO; + } + len -= clen; + addr += clen; + dest += clen; + } + return 0; +} + +static struct smu_sdbp_header *smu_create_sdb_partition(int id) +{ + DECLARE_COMPLETION(comp); + struct smu_simple_cmd cmd; + unsigned int addr, len, tlen; + struct smu_sdbp_header *hdr; + struct property *prop; + + /* First query the partition info */ + smu_queue_simple(&cmd, SMU_CMD_PARTITION_COMMAND, 2, + smu_done_complete, &comp, + SMU_CMD_PARTITION_LATEST, id); + wait_for_completion(&comp); + + /* Partition doesn't exist (or other error) */ + if (cmd.cmd.status != 0 || cmd.cmd.reply_len != 6) + return NULL; + + /* Fetch address and length from reply */ + addr = *((u16 *)cmd.buffer); + len = cmd.buffer[3] << 2; + /* Calucluate total length to allocate, including the 17 bytes + * for "sdb-partition-XX" that we append at the end of the buffer + */ + tlen = sizeof(struct property) + len + 18; + + prop = kcalloc(tlen, 1, GFP_KERNEL); + if (prop == NULL) + return NULL; + hdr = (struct smu_sdbp_header *)(prop + 1); + prop->name = ((char *)prop) + tlen - 18; + sprintf(prop->name, "sdb-partition-%02x", id); + prop->length = len; + prop->value = (unsigned char *)hdr; + prop->next = NULL; + + /* Read the datablock */ + if (smu_read_datablock((u8 *)hdr, addr, len)) { + printk(KERN_DEBUG "SMU: datablock read failed while reading " + "partition %02x !\n", id); + goto failure; + } + + /* Got it, check a few things and create the property */ + if (hdr->id != id) { + printk(KERN_DEBUG "SMU: Reading partition %02x and got " + "%02x !\n", id, hdr->id); + goto failure; + } + if (prom_add_property(smu->of_node, prop)) { + printk(KERN_DEBUG "SMU: Failed creating sdb-partition-%02x " + "property !\n", id); + goto failure; + } + + return hdr; + failure: + kfree(prop); + return NULL; +} + +/* Note: Only allowed to return error code in pointers (using ERR_PTR) + * when interruptible is 1 + */ +struct smu_sdbp_header *__smu_get_sdb_partition(int id, unsigned int *size, + int interruptible) +{ + char pname[32]; + struct smu_sdbp_header *part; + + if (!smu) + return NULL; + + sprintf(pname, "sdb-partition-%02x", id); + + if (interruptible) { + int rc; + rc = down_interruptible(&smu_part_access); + if (rc) + return ERR_PTR(rc); + } else + down(&smu_part_access); + + part = (struct smu_sdbp_header *)get_property(smu->of_node, + pname, size); + if (part == NULL) { + part = smu_create_sdb_partition(id); + if (part != NULL && size) + *size = part->len << 2; + } + up(&smu_part_access); + return part; +} + +struct smu_sdbp_header *smu_get_sdb_partition(int id, unsigned int *size) +{ + return __smu_get_sdb_partition(id, size, 0); +} +EXPORT_SYMBOL(smu_get_sdb_partition); /* @@ -918,6 +1072,14 @@ static ssize_t smu_write(struct file *file, const char __user *buf, else if (hdr.cmdtype == SMU_CMDTYPE_WANTS_EVENTS) { pp->mode = smu_file_events; return 0; + } else if (hdr.cmdtype == SMU_CMDTYPE_GET_PARTITION) { + struct smu_sdbp_header *part; + part = __smu_get_sdb_partition(hdr.cmd, NULL, 1); + if (part == NULL) + return -EINVAL; + else if (IS_ERR(part)) + return PTR_ERR(part); + return 0; } else if (hdr.cmdtype != SMU_CMDTYPE_SMU) return -EINVAL; else if (pp->mode != smu_file_commands) diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c index cc507ceef15388175917ef3852c504731dd66c24..3fc8cdd94c3daa9b4154b8d721b381bb0eb09797 100644 --- a/drivers/macintosh/therm_pm72.c +++ b/drivers/macintosh/therm_pm72.c @@ -1678,10 +1678,9 @@ static int main_control_loop(void *x) } // FIXME: Deal with signals - set_current_state(TASK_INTERRUPTIBLE); elapsed = jiffies - start; if (elapsed < HZ) - schedule_timeout(HZ - elapsed); + schedule_timeout_interruptible(HZ - elapsed); } out: diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 9bc6cc6e384546faee4b068fa5aa87e0e350fe5d..5640435085694fdbefddf0e7c1a18bef2e221b75 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -2053,6 +2053,7 @@ pmu_register_sleep_notifier(struct pmu_sleep_notifier *n) __list_add(&n->list, list->prev, list); return 0; } +EXPORT_SYMBOL(pmu_register_sleep_notifier); int pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* n) @@ -2063,6 +2064,7 @@ pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* n) n->list.next = NULL; return 0; } +EXPORT_SYMBOL(pmu_unregister_sleep_notifier); #endif /* CONFIG_PM */ #if defined(CONFIG_PM) && defined(CONFIG_PPC32) @@ -2667,10 +2669,10 @@ powerbook_sleep_3400(void) asleep = 1; /* Put the CPU into sleep mode */ - asm volatile("mfspr %0,1008" : "=r" (hid0) :); + hid0 = mfspr(SPRN_HID0); hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP; - asm volatile("mtspr 1008,%0" : : "r" (hid0)); - _nmask_and_or_msr(0, MSR_POW | MSR_EE); + mtspr(SPRN_HID0, hid0); + mtmsr(mfmsr() | MSR_POW | MSR_EE); udelay(10); /* OK, we're awake again, start restoring things */ @@ -3139,8 +3141,6 @@ EXPORT_SYMBOL(pmu_i2c_stdsub_write); EXPORT_SYMBOL(pmu_i2c_simple_read); EXPORT_SYMBOL(pmu_i2c_simple_write); #if defined(CONFIG_PM) && defined(CONFIG_PPC32) -EXPORT_SYMBOL(pmu_register_sleep_notifier); -EXPORT_SYMBOL(pmu_unregister_sleep_notifier); EXPORT_SYMBOL(pmu_enable_irled); EXPORT_SYMBOL(pmu_battery_count); EXPORT_SYMBOL(pmu_batteries); diff --git a/drivers/macintosh/windfarm.h b/drivers/macintosh/windfarm.h new file mode 100644 index 0000000000000000000000000000000000000000..3f0cb0312ea3113bf897ddfa69e5318816e6857b --- /dev/null +++ b/drivers/macintosh/windfarm.h @@ -0,0 +1,131 @@ +/* + * Windfarm PowerMac thermal control. + * + * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. + * + * + * Released under the term of the GNU GPL v2. + */ + +#ifndef __WINDFARM_H__ +#define __WINDFARM_H__ + +#include +#include +#include +#include + +/* Display a 16.16 fixed point value */ +#define FIX32TOPRINT(f) ((f) >> 16),((((f) & 0xffff) * 1000) >> 16) + +/* + * Control objects + */ + +struct wf_control; + +struct wf_control_ops { + int (*set_value)(struct wf_control *ct, s32 val); + int (*get_value)(struct wf_control *ct, s32 *val); + s32 (*get_min)(struct wf_control *ct); + s32 (*get_max)(struct wf_control *ct); + void (*release)(struct wf_control *ct); + struct module *owner; +}; + +struct wf_control { + struct list_head link; + struct wf_control_ops *ops; + char *name; + int type; + struct kref ref; +}; + +#define WF_CONTROL_TYPE_GENERIC 0 +#define WF_CONTROL_RPM_FAN 1 +#define WF_CONTROL_PWM_FAN 2 + + +/* Note about lifetime rules: wf_register_control() will initialize + * the kref and wf_unregister_control will decrement it, thus the + * object creating/disposing a given control shouldn't assume it + * still exists after wf_unregister_control has been called. + * wf_find_control will inc the refcount for you + */ +extern int wf_register_control(struct wf_control *ct); +extern void wf_unregister_control(struct wf_control *ct); +extern struct wf_control * wf_find_control(const char *name); +extern int wf_get_control(struct wf_control *ct); +extern void wf_put_control(struct wf_control *ct); + +static inline int wf_control_set_max(struct wf_control *ct) +{ + s32 vmax = ct->ops->get_max(ct); + return ct->ops->set_value(ct, vmax); +} + +static inline int wf_control_set_min(struct wf_control *ct) +{ + s32 vmin = ct->ops->get_min(ct); + return ct->ops->set_value(ct, vmin); +} + +/* + * Sensor objects + */ + +struct wf_sensor; + +struct wf_sensor_ops { + int (*get_value)(struct wf_sensor *sr, s32 *val); + void (*release)(struct wf_sensor *sr); + struct module *owner; +}; + +struct wf_sensor { + struct list_head link; + struct wf_sensor_ops *ops; + char *name; + struct kref ref; +}; + +/* Same lifetime rules as controls */ +extern int wf_register_sensor(struct wf_sensor *sr); +extern void wf_unregister_sensor(struct wf_sensor *sr); +extern struct wf_sensor * wf_find_sensor(const char *name); +extern int wf_get_sensor(struct wf_sensor *sr); +extern void wf_put_sensor(struct wf_sensor *sr); + +/* For use by clients. Note that we are a bit racy here since + * notifier_block doesn't have a module owner field. I may fix + * it one day ... + * + * LOCKING NOTE ! + * + * All "events" except WF_EVENT_TICK are called with an internal mutex + * held which will deadlock if you call basically any core routine. + * So don't ! Just take note of the event and do your actual operations + * from the ticker. + * + */ +extern int wf_register_client(struct notifier_block *nb); +extern int wf_unregister_client(struct notifier_block *nb); + +/* Overtemp conditions. Those are refcounted */ +extern void wf_set_overtemp(void); +extern void wf_clear_overtemp(void); +extern int wf_is_overtemp(void); + +#define WF_EVENT_NEW_CONTROL 0 /* param is wf_control * */ +#define WF_EVENT_NEW_SENSOR 1 /* param is wf_sensor * */ +#define WF_EVENT_OVERTEMP 2 /* no param */ +#define WF_EVENT_NORMALTEMP 3 /* overtemp condition cleared */ +#define WF_EVENT_TICK 4 /* 1 second tick */ + +/* Note: If that driver gets more broad use, we could replace the + * simplistic overtemp bits with "environmental conditions". That + * could then be used to also notify of things like fan failure, + * case open, battery conditions, ... + */ + +#endif /* __WINDFARM_H__ */ diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c new file mode 100644 index 0000000000000000000000000000000000000000..6c2a471ea6c0fb6b3d7af035a0f5a4ac298d1bc0 --- /dev/null +++ b/drivers/macintosh/windfarm_core.c @@ -0,0 +1,426 @@ +/* + * Windfarm PowerMac thermal control. Core + * + * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. + * + * + * Released under the term of the GNU GPL v2. + * + * This core code tracks the list of sensors & controls, register + * clients, and holds the kernel thread used for control. + * + * TODO: + * + * Add some information about sensor/control type and data format to + * sensors/controls, and have the sysfs attribute stuff be moved + * generically here instead of hard coded in the platform specific + * driver as it us currently + * + * This however requires solving some annoying lifetime issues with + * sysfs which doesn't seem to have lifetime rules for struct attribute, + * I may have to create full features kobjects for every sensor/control + * instead which is a bit of an overkill imho + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "windfarm.h" + +#define VERSION "0.2" + +#undef DEBUG + +#ifdef DEBUG +#define DBG(args...) printk(args) +#else +#define DBG(args...) do { } while(0) +#endif + +static LIST_HEAD(wf_controls); +static LIST_HEAD(wf_sensors); +static DECLARE_MUTEX(wf_lock); +static struct notifier_block *wf_client_list; +static int wf_client_count; +static unsigned int wf_overtemp; +static unsigned int wf_overtemp_counter; +struct task_struct *wf_thread; + +/* + * Utilities & tick thread + */ + +static inline void wf_notify(int event, void *param) +{ + notifier_call_chain(&wf_client_list, event, param); +} + +int wf_critical_overtemp(void) +{ + static char * critical_overtemp_path = "/sbin/critical_overtemp"; + char *argv[] = { critical_overtemp_path, NULL }; + static char *envp[] = { "HOME=/", + "TERM=linux", + "PATH=/sbin:/usr/sbin:/bin:/usr/bin", + NULL }; + + return call_usermodehelper(critical_overtemp_path, argv, envp, 0); +} +EXPORT_SYMBOL_GPL(wf_critical_overtemp); + +static int wf_thread_func(void *data) +{ + unsigned long next, delay; + + next = jiffies; + + DBG("wf: thread started\n"); + + while(!kthread_should_stop()) { + try_to_freeze(); + + if (time_after_eq(jiffies, next)) { + wf_notify(WF_EVENT_TICK, NULL); + if (wf_overtemp) { + wf_overtemp_counter++; + /* 10 seconds overtemp, notify userland */ + if (wf_overtemp_counter > 10) + wf_critical_overtemp(); + /* 30 seconds, shutdown */ + if (wf_overtemp_counter > 30) { + printk(KERN_ERR "windfarm: Overtemp " + "for more than 30" + " seconds, shutting down\n"); + machine_power_off(); + } + } + next += HZ; + } + + delay = next - jiffies; + if (delay <= HZ) + schedule_timeout_interruptible(delay); + + /* there should be no signal, but oh well */ + if (signal_pending(current)) { + printk(KERN_WARNING "windfarm: thread got sigl !\n"); + break; + } + } + + DBG("wf: thread stopped\n"); + + return 0; +} + +static void wf_start_thread(void) +{ + wf_thread = kthread_run(wf_thread_func, NULL, "kwindfarm"); + if (IS_ERR(wf_thread)) { + printk(KERN_ERR "windfarm: failed to create thread,err %ld\n", + PTR_ERR(wf_thread)); + wf_thread = NULL; + } +} + + +static void wf_stop_thread(void) +{ + if (wf_thread) + kthread_stop(wf_thread); + wf_thread = NULL; +} + +/* + * Controls + */ + +static void wf_control_release(struct kref *kref) +{ + struct wf_control *ct = container_of(kref, struct wf_control, ref); + + DBG("wf: Deleting control %s\n", ct->name); + + if (ct->ops && ct->ops->release) + ct->ops->release(ct); + else + kfree(ct); +} + +int wf_register_control(struct wf_control *new_ct) +{ + struct wf_control *ct; + + down(&wf_lock); + list_for_each_entry(ct, &wf_controls, link) { + if (!strcmp(ct->name, new_ct->name)) { + printk(KERN_WARNING "windfarm: trying to register" + " duplicate control %s\n", ct->name); + up(&wf_lock); + return -EEXIST; + } + } + kref_init(&new_ct->ref); + list_add(&new_ct->link, &wf_controls); + + DBG("wf: Registered control %s\n", new_ct->name); + + wf_notify(WF_EVENT_NEW_CONTROL, new_ct); + up(&wf_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(wf_register_control); + +void wf_unregister_control(struct wf_control *ct) +{ + down(&wf_lock); + list_del(&ct->link); + up(&wf_lock); + + DBG("wf: Unregistered control %s\n", ct->name); + + kref_put(&ct->ref, wf_control_release); +} +EXPORT_SYMBOL_GPL(wf_unregister_control); + +struct wf_control * wf_find_control(const char *name) +{ + struct wf_control *ct; + + down(&wf_lock); + list_for_each_entry(ct, &wf_controls, link) { + if (!strcmp(ct->name, name)) { + if (wf_get_control(ct)) + ct = NULL; + up(&wf_lock); + return ct; + } + } + up(&wf_lock); + return NULL; +} +EXPORT_SYMBOL_GPL(wf_find_control); + +int wf_get_control(struct wf_control *ct) +{ + if (!try_module_get(ct->ops->owner)) + return -ENODEV; + kref_get(&ct->ref); + return 0; +} +EXPORT_SYMBOL_GPL(wf_get_control); + +void wf_put_control(struct wf_control *ct) +{ + struct module *mod = ct->ops->owner; + kref_put(&ct->ref, wf_control_release); + module_put(mod); +} +EXPORT_SYMBOL_GPL(wf_put_control); + + +/* + * Sensors + */ + + +static void wf_sensor_release(struct kref *kref) +{ + struct wf_sensor *sr = container_of(kref, struct wf_sensor, ref); + + DBG("wf: Deleting sensor %s\n", sr->name); + + if (sr->ops && sr->ops->release) + sr->ops->release(sr); + else + kfree(sr); +} + +int wf_register_sensor(struct wf_sensor *new_sr) +{ + struct wf_sensor *sr; + + down(&wf_lock); + list_for_each_entry(sr, &wf_sensors, link) { + if (!strcmp(sr->name, new_sr->name)) { + printk(KERN_WARNING "windfarm: trying to register" + " duplicate sensor %s\n", sr->name); + up(&wf_lock); + return -EEXIST; + } + } + kref_init(&new_sr->ref); + list_add(&new_sr->link, &wf_sensors); + + DBG("wf: Registered sensor %s\n", new_sr->name); + + wf_notify(WF_EVENT_NEW_SENSOR, new_sr); + up(&wf_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(wf_register_sensor); + +void wf_unregister_sensor(struct wf_sensor *sr) +{ + down(&wf_lock); + list_del(&sr->link); + up(&wf_lock); + + DBG("wf: Unregistered sensor %s\n", sr->name); + + wf_put_sensor(sr); +} +EXPORT_SYMBOL_GPL(wf_unregister_sensor); + +struct wf_sensor * wf_find_sensor(const char *name) +{ + struct wf_sensor *sr; + + down(&wf_lock); + list_for_each_entry(sr, &wf_sensors, link) { + if (!strcmp(sr->name, name)) { + if (wf_get_sensor(sr)) + sr = NULL; + up(&wf_lock); + return sr; + } + } + up(&wf_lock); + return NULL; +} +EXPORT_SYMBOL_GPL(wf_find_sensor); + +int wf_get_sensor(struct wf_sensor *sr) +{ + if (!try_module_get(sr->ops->owner)) + return -ENODEV; + kref_get(&sr->ref); + return 0; +} +EXPORT_SYMBOL_GPL(wf_get_sensor); + +void wf_put_sensor(struct wf_sensor *sr) +{ + struct module *mod = sr->ops->owner; + kref_put(&sr->ref, wf_sensor_release); + module_put(mod); +} +EXPORT_SYMBOL_GPL(wf_put_sensor); + + +/* + * Client & notification + */ + +int wf_register_client(struct notifier_block *nb) +{ + int rc; + struct wf_control *ct; + struct wf_sensor *sr; + + down(&wf_lock); + rc = notifier_chain_register(&wf_client_list, nb); + if (rc != 0) + goto bail; + wf_client_count++; + list_for_each_entry(ct, &wf_controls, link) + wf_notify(WF_EVENT_NEW_CONTROL, ct); + list_for_each_entry(sr, &wf_sensors, link) + wf_notify(WF_EVENT_NEW_SENSOR, sr); + if (wf_client_count == 1) + wf_start_thread(); + bail: + up(&wf_lock); + return rc; +} +EXPORT_SYMBOL_GPL(wf_register_client); + +int wf_unregister_client(struct notifier_block *nb) +{ + down(&wf_lock); + notifier_chain_unregister(&wf_client_list, nb); + wf_client_count++; + if (wf_client_count == 0) + wf_stop_thread(); + up(&wf_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(wf_unregister_client); + +void wf_set_overtemp(void) +{ + down(&wf_lock); + wf_overtemp++; + if (wf_overtemp == 1) { + printk(KERN_WARNING "windfarm: Overtemp condition detected !\n"); + wf_overtemp_counter = 0; + wf_notify(WF_EVENT_OVERTEMP, NULL); + } + up(&wf_lock); +} +EXPORT_SYMBOL_GPL(wf_set_overtemp); + +void wf_clear_overtemp(void) +{ + down(&wf_lock); + WARN_ON(wf_overtemp == 0); + if (wf_overtemp == 0) { + up(&wf_lock); + return; + } + wf_overtemp--; + if (wf_overtemp == 0) { + printk(KERN_WARNING "windfarm: Overtemp condition cleared !\n"); + wf_notify(WF_EVENT_NORMALTEMP, NULL); + } + up(&wf_lock); +} +EXPORT_SYMBOL_GPL(wf_clear_overtemp); + +int wf_is_overtemp(void) +{ + return (wf_overtemp != 0); +} +EXPORT_SYMBOL_GPL(wf_is_overtemp); + +static struct platform_device wf_platform_device = { + .name = "windfarm", +}; + +static int __init windfarm_core_init(void) +{ + DBG("wf: core loaded\n"); + + platform_device_register(&wf_platform_device); + return 0; +} + +static void __exit windfarm_core_exit(void) +{ + BUG_ON(wf_client_count != 0); + + DBG("wf: core unloaded\n"); + + platform_device_unregister(&wf_platform_device); +} + + +module_init(windfarm_core_init); +module_exit(windfarm_core_exit); + +MODULE_AUTHOR("Benjamin Herrenschmidt "); +MODULE_DESCRIPTION("Core component of PowerMac thermal control"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/macintosh/windfarm_cpufreq_clamp.c b/drivers/macintosh/windfarm_cpufreq_clamp.c new file mode 100644 index 0000000000000000000000000000000000000000..607dbaca69c96fbb2172556bc4a14e5ca72f93d6 --- /dev/null +++ b/drivers/macintosh/windfarm_cpufreq_clamp.c @@ -0,0 +1,105 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "windfarm.h" + +#define VERSION "0.3" + +static int clamped; +static struct wf_control *clamp_control; + +static int clamp_notifier_call(struct notifier_block *self, + unsigned long event, void *data) +{ + struct cpufreq_policy *p = data; + unsigned long max_freq; + + if (event != CPUFREQ_ADJUST) + return 0; + + max_freq = clamped ? (p->cpuinfo.min_freq) : (p->cpuinfo.max_freq); + cpufreq_verify_within_limits(p, 0, max_freq); + + return 0; +} + +static struct notifier_block clamp_notifier = { + .notifier_call = clamp_notifier_call, +}; + +static int clamp_set(struct wf_control *ct, s32 value) +{ + if (value) + printk(KERN_INFO "windfarm: Clamping CPU frequency to " + "minimum !\n"); + else + printk(KERN_INFO "windfarm: CPU frequency unclamped !\n"); + clamped = value; + cpufreq_update_policy(0); + return 0; +} + +static int clamp_get(struct wf_control *ct, s32 *value) +{ + *value = clamped; + return 0; +} + +static s32 clamp_min(struct wf_control *ct) +{ + return 0; +} + +static s32 clamp_max(struct wf_control *ct) +{ + return 1; +} + +static struct wf_control_ops clamp_ops = { + .set_value = clamp_set, + .get_value = clamp_get, + .get_min = clamp_min, + .get_max = clamp_max, + .owner = THIS_MODULE, +}; + +static int __init wf_cpufreq_clamp_init(void) +{ + struct wf_control *clamp; + + clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL); + if (clamp == NULL) + return -ENOMEM; + cpufreq_register_notifier(&clamp_notifier, CPUFREQ_POLICY_NOTIFIER); + clamp->ops = &clamp_ops; + clamp->name = "cpufreq-clamp"; + if (wf_register_control(clamp)) + goto fail; + clamp_control = clamp; + return 0; + fail: + kfree(clamp); + return -ENODEV; +} + +static void __exit wf_cpufreq_clamp_exit(void) +{ + if (clamp_control) + wf_unregister_control(clamp_control); +} + + +module_init(wf_cpufreq_clamp_init); +module_exit(wf_cpufreq_clamp_exit); + +MODULE_AUTHOR("Benjamin Herrenschmidt "); +MODULE_DESCRIPTION("CPU frequency clamp for PowerMacs thermal control"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c new file mode 100644 index 0000000000000000000000000000000000000000..a0a41ad0f2b593b7eadf0320b7c121710e9004b6 --- /dev/null +++ b/drivers/macintosh/windfarm_lm75_sensor.c @@ -0,0 +1,263 @@ +/* + * Windfarm PowerMac thermal control. LM75 sensor + * + * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. + * + * + * Released under the term of the GNU GPL v2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "windfarm.h" + +#define VERSION "0.1" + +#undef DEBUG + +#ifdef DEBUG +#define DBG(args...) printk(args) +#else +#define DBG(args...) do { } while(0) +#endif + +struct wf_lm75_sensor { + int ds1775 : 1; + int inited : 1; + struct i2c_client i2c; + struct wf_sensor sens; +}; +#define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens) +#define i2c_to_lm75(c) container_of(c, struct wf_lm75_sensor, i2c) + +static int wf_lm75_attach(struct i2c_adapter *adapter); +static int wf_lm75_detach(struct i2c_client *client); + +static struct i2c_driver wf_lm75_driver = { + .owner = THIS_MODULE, + .name = "wf_lm75", + .flags = I2C_DF_NOTIFY, + .attach_adapter = wf_lm75_attach, + .detach_client = wf_lm75_detach, +}; + +static int wf_lm75_get(struct wf_sensor *sr, s32 *value) +{ + struct wf_lm75_sensor *lm = wf_to_lm75(sr); + s32 data; + + if (lm->i2c.adapter == NULL) + return -ENODEV; + + /* Init chip if necessary */ + if (!lm->inited) { + u8 cfg_new, cfg = (u8)i2c_smbus_read_byte_data(&lm->i2c, 1); + + DBG("wf_lm75: Initializing %s, cfg was: %02x\n", + sr->name, cfg); + + /* clear shutdown bit, keep other settings as left by + * the firmware for now + */ + cfg_new = cfg & ~0x01; + i2c_smbus_write_byte_data(&lm->i2c, 1, cfg_new); + lm->inited = 1; + + /* If we just powered it up, let's wait 200 ms */ + msleep(200); + } + + /* Read temperature register */ + data = (s32)le16_to_cpu(i2c_smbus_read_word_data(&lm->i2c, 0)); + data <<= 8; + *value = data; + + return 0; +} + +static void wf_lm75_release(struct wf_sensor *sr) +{ + struct wf_lm75_sensor *lm = wf_to_lm75(sr); + + /* check if client is registered and detach from i2c */ + if (lm->i2c.adapter) { + i2c_detach_client(&lm->i2c); + lm->i2c.adapter = NULL; + } + + kfree(lm); +} + +static struct wf_sensor_ops wf_lm75_ops = { + .get_value = wf_lm75_get, + .release = wf_lm75_release, + .owner = THIS_MODULE, +}; + +static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter, + u8 addr, int ds1775, + const char *loc) +{ + struct wf_lm75_sensor *lm; + + DBG("wf_lm75: creating %s device at address 0x%02x\n", + ds1775 ? "ds1775" : "lm75", addr); + + lm = kmalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL); + if (lm == NULL) + return NULL; + memset(lm, 0, sizeof(struct wf_lm75_sensor)); + + /* Usual rant about sensor names not beeing very consistent in + * the device-tree, oh well ... + * Add more entries below as you deal with more setups + */ + if (!strcmp(loc, "Hard drive") || !strcmp(loc, "DRIVE BAY")) + lm->sens.name = "hd-temp"; + else + goto fail; + + lm->inited = 0; + lm->sens.ops = &wf_lm75_ops; + lm->ds1775 = ds1775; + lm->i2c.addr = (addr >> 1) & 0x7f; + lm->i2c.adapter = adapter; + lm->i2c.driver = &wf_lm75_driver; + strncpy(lm->i2c.name, lm->sens.name, I2C_NAME_SIZE-1); + + if (i2c_attach_client(&lm->i2c)) { + printk(KERN_ERR "windfarm: failed to attach %s %s to i2c\n", + ds1775 ? "ds1775" : "lm75", lm->i2c.name); + goto fail; + } + + if (wf_register_sensor(&lm->sens)) { + i2c_detach_client(&lm->i2c); + goto fail; + } + + return lm; + fail: + kfree(lm); + return NULL; +} + +static int wf_lm75_attach(struct i2c_adapter *adapter) +{ + u8 bus_id; + struct device_node *smu, *bus, *dev; + + /* We currently only deal with LM75's hanging off the SMU + * i2c busses. If we extend that driver to other/older + * machines, we should split this function into SMU-i2c, + * keywest-i2c, PMU-i2c, ... + */ + + DBG("wf_lm75: adapter %s detected\n", adapter->name); + + if (strncmp(adapter->name, "smu-i2c-", 8) != 0) + return 0; + smu = of_find_node_by_type(NULL, "smu"); + if (smu == NULL) + return 0; + + /* Look for the bus in the device-tree */ + bus_id = (u8)simple_strtoul(adapter->name + 8, NULL, 16); + + DBG("wf_lm75: bus ID is %x\n", bus_id); + + /* Look for sensors subdir */ + for (bus = NULL; + (bus = of_get_next_child(smu, bus)) != NULL;) { + u32 *reg; + + if (strcmp(bus->name, "i2c")) + continue; + reg = (u32 *)get_property(bus, "reg", NULL); + if (reg == NULL) + continue; + if (bus_id == *reg) + break; + } + of_node_put(smu); + if (bus == NULL) { + printk(KERN_WARNING "windfarm: SMU i2c bus 0x%x not found" + " in device-tree !\n", bus_id); + return 0; + } + + DBG("wf_lm75: bus found, looking for device...\n"); + + /* Now look for lm75(s) in there */ + for (dev = NULL; + (dev = of_get_next_child(bus, dev)) != NULL;) { + const char *loc = + get_property(dev, "hwsensor-location", NULL); + u32 *reg = (u32 *)get_property(dev, "reg", NULL); + DBG(" dev: %s... (loc: %p, reg: %p)\n", dev->name, loc, reg); + if (loc == NULL || reg == NULL) + continue; + /* real lm75 */ + if (device_is_compatible(dev, "lm75")) + wf_lm75_create(adapter, *reg, 0, loc); + /* ds1775 (compatible, better resolution */ + else if (device_is_compatible(dev, "ds1775")) + wf_lm75_create(adapter, *reg, 1, loc); + } + + of_node_put(bus); + + return 0; +} + +static int wf_lm75_detach(struct i2c_client *client) +{ + struct wf_lm75_sensor *lm = i2c_to_lm75(client); + + DBG("wf_lm75: i2c detatch called for %s\n", lm->sens.name); + + /* Mark client detached */ + lm->i2c.adapter = NULL; + + /* release sensor */ + wf_unregister_sensor(&lm->sens); + + return 0; +} + +static int __init wf_lm75_sensor_init(void) +{ + int rc; + + rc = i2c_add_driver(&wf_lm75_driver); + if (rc < 0) + return rc; + return 0; +} + +static void __exit wf_lm75_sensor_exit(void) +{ + i2c_del_driver(&wf_lm75_driver); +} + + +module_init(wf_lm75_sensor_init); +module_exit(wf_lm75_sensor_exit); + +MODULE_AUTHOR("Benjamin Herrenschmidt "); +MODULE_DESCRIPTION("LM75 sensor objects for PowerMacs thermal control"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/macintosh/windfarm_pid.c b/drivers/macintosh/windfarm_pid.c new file mode 100644 index 0000000000000000000000000000000000000000..2e803b368757ed72d4f1b53ad8af10e9a9c7b375 --- /dev/null +++ b/drivers/macintosh/windfarm_pid.c @@ -0,0 +1,145 @@ +/* + * Windfarm PowerMac thermal control. Generic PID helpers + * + * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. + * + * + * Released under the term of the GNU GPL v2. + */ + +#include +#include +#include +#include +#include + +#include "windfarm_pid.h" + +#undef DEBUG + +#ifdef DEBUG +#define DBG(args...) printk(args) +#else +#define DBG(args...) do { } while(0) +#endif + +void wf_pid_init(struct wf_pid_state *st, struct wf_pid_param *param) +{ + memset(st, 0, sizeof(struct wf_pid_state)); + st->param = *param; + st->first = 1; +} +EXPORT_SYMBOL_GPL(wf_pid_init); + +s32 wf_pid_run(struct wf_pid_state *st, s32 new_sample) +{ + s64 error, integ, deriv; + s32 target; + int i, hlen = st->param.history_len; + + /* Calculate error term */ + error = new_sample - st->param.itarget; + + /* Get samples into our history buffer */ + if (st->first) { + for (i = 0; i < hlen; i++) { + st->samples[i] = new_sample; + st->errors[i] = error; + } + st->first = 0; + st->index = 0; + } else { + st->index = (st->index + 1) % hlen; + st->samples[st->index] = new_sample; + st->errors[st->index] = error; + } + + /* Calculate integral term */ + for (i = 0, integ = 0; i < hlen; i++) + integ += st->errors[(st->index + hlen - i) % hlen]; + integ *= st->param.interval; + + /* Calculate derivative term */ + deriv = st->errors[st->index] - + st->errors[(st->index + hlen - 1) % hlen]; + deriv /= st->param.interval; + + /* Calculate target */ + target = (s32)((integ * (s64)st->param.gr + deriv * (s64)st->param.gd + + error * (s64)st->param.gp) >> 36); + if (st->param.additive) + target += st->target; + target = max(target, st->param.min); + target = min(target, st->param.max); + st->target = target; + + return st->target; +} +EXPORT_SYMBOL_GPL(wf_pid_run); + +void wf_cpu_pid_init(struct wf_cpu_pid_state *st, + struct wf_cpu_pid_param *param) +{ + memset(st, 0, sizeof(struct wf_cpu_pid_state)); + st->param = *param; + st->first = 1; +} +EXPORT_SYMBOL_GPL(wf_cpu_pid_init); + +s32 wf_cpu_pid_run(struct wf_cpu_pid_state *st, s32 new_power, s32 new_temp) +{ + s64 error, integ, deriv, prop; + s32 target, sval, adj; + int i, hlen = st->param.history_len; + + /* Calculate error term */ + error = st->param.pmaxadj - new_power; + + /* Get samples into our history buffer */ + if (st->first) { + for (i = 0; i < hlen; i++) { + st->powers[i] = new_power; + st->errors[i] = error; + } + st->temps[0] = st->temps[1] = new_temp; + st->first = 0; + st->index = st->tindex = 0; + } else { + st->index = (st->index + 1) % hlen; + st->powers[st->index] = new_power; + st->errors[st->index] = error; + st->tindex = (st->tindex + 1) % 2; + st->temps[st->tindex] = new_temp; + } + + /* Calculate integral term */ + for (i = 0, integ = 0; i < hlen; i++) + integ += st->errors[(st->index + hlen - i) % hlen]; + integ *= st->param.interval; + integ *= st->param.gr; + sval = st->param.tmax - ((integ >> 20) & 0xffffffff); + adj = min(st->param.ttarget, sval); + + DBG("integ: %lx, sval: %lx, adj: %lx\n", integ, sval, adj); + + /* Calculate derivative term */ + deriv = st->temps[st->tindex] - + st->temps[(st->tindex + 2 - 1) % 2]; + deriv /= st->param.interval; + deriv *= st->param.gd; + + /* Calculate proportional term */ + prop = (new_temp - adj); + prop *= st->param.gp; + + DBG("deriv: %lx, prop: %lx\n", deriv, prop); + + /* Calculate target */ + target = st->target + (s32)((deriv + prop) >> 36); + target = max(target, st->param.min); + target = min(target, st->param.max); + st->target = target; + + return st->target; +} +EXPORT_SYMBOL_GPL(wf_cpu_pid_run); diff --git a/drivers/macintosh/windfarm_pid.h b/drivers/macintosh/windfarm_pid.h new file mode 100644 index 0000000000000000000000000000000000000000..a364c2a2499caf0f55dc6b364e0d771c61e8a2ec --- /dev/null +++ b/drivers/macintosh/windfarm_pid.h @@ -0,0 +1,84 @@ +/* + * Windfarm PowerMac thermal control. Generic PID helpers + * + * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. + * + * + * Released under the term of the GNU GPL v2. + * + * This is a pair of generic PID helpers that can be used by + * control loops. One is the basic PID implementation, the + * other one is more specifically tailored to the loops used + * for CPU control with 2 input sample types (temp and power) + */ + +/* + * *** Simple PID *** + */ + +#define WF_PID_MAX_HISTORY 32 + +/* This parameter array is passed to the PID algorithm. Currently, + * we don't support changing parameters on the fly as it's not needed + * but could be implemented (with necessary adjustment of the history + * buffer + */ +struct wf_pid_param { + int interval; /* Interval between samples in seconds */ + int history_len; /* Size of history buffer */ + int additive; /* 1: target relative to previous value */ + s32 gd, gp, gr; /* PID gains */ + s32 itarget; /* PID input target */ + s32 min,max; /* min and max target values */ +}; + +struct wf_pid_state { + int first; /* first run of the loop */ + int index; /* index of current sample */ + s32 target; /* current target value */ + s32 samples[WF_PID_MAX_HISTORY]; /* samples history buffer */ + s32 errors[WF_PID_MAX_HISTORY]; /* error history buffer */ + + struct wf_pid_param param; +}; + +extern void wf_pid_init(struct wf_pid_state *st, struct wf_pid_param *param); +extern s32 wf_pid_run(struct wf_pid_state *st, s32 sample); + + +/* + * *** CPU PID *** + */ + +#define WF_CPU_PID_MAX_HISTORY 32 + +/* This parameter array is passed to the CPU PID algorithm. Currently, + * we don't support changing parameters on the fly as it's not needed + * but could be implemented (with necessary adjustment of the history + * buffer + */ +struct wf_cpu_pid_param { + int interval; /* Interval between samples in seconds */ + int history_len; /* Size of history buffer */ + s32 gd, gp, gr; /* PID gains */ + s32 pmaxadj; /* PID max power adjust */ + s32 ttarget; /* PID input target */ + s32 tmax; /* PID input max */ + s32 min,max; /* min and max target values */ +}; + +struct wf_cpu_pid_state { + int first; /* first run of the loop */ + int index; /* index of current power */ + int tindex; /* index of current temp */ + s32 target; /* current target value */ + s32 powers[WF_PID_MAX_HISTORY]; /* power history buffer */ + s32 errors[WF_PID_MAX_HISTORY]; /* error history buffer */ + s32 temps[2]; /* temp. history buffer */ + + struct wf_cpu_pid_param param; +}; + +extern void wf_cpu_pid_init(struct wf_cpu_pid_state *st, + struct wf_cpu_pid_param *param); +extern s32 wf_cpu_pid_run(struct wf_cpu_pid_state *st, s32 power, s32 temp); diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c new file mode 100644 index 0000000000000000000000000000000000000000..322c74b2687f4cbe6aa30ec6b3b2a484d937e6f8 --- /dev/null +++ b/drivers/macintosh/windfarm_pm81.c @@ -0,0 +1,879 @@ +/* + * Windfarm PowerMac thermal control. iMac G5 + * + * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. + * + * + * Released under the term of the GNU GPL v2. + * + * The algorithm used is the PID control algorithm, used the same + * way the published Darwin code does, using the same values that + * are present in the Darwin 8.2 snapshot property lists (note however + * that none of the code has been re-used, it's a complete re-implementation + * + * The various control loops found in Darwin config file are: + * + * PowerMac8,1 and PowerMac8,2 + * =========================== + * + * System Fans control loop. Different based on models. In addition to the + * usual PID algorithm, the control loop gets 2 additional pairs of linear + * scaling factors (scale/offsets) expressed as 4.12 fixed point values + * signed offset, unsigned scale) + * + * The targets are modified such as: + * - the linked control (second control) gets the target value as-is + * (typically the drive fan) + * - the main control (first control) gets the target value scaled with + * the first pair of factors, and is then modified as below + * - the value of the target of the CPU Fan control loop is retreived, + * scaled with the second pair of factors, and the max of that and + * the scaled target is applied to the main control. + * + * # model_id: 2 + * controls : system-fan, drive-bay-fan + * sensors : hd-temp + * PID params : G_d = 0x15400000 + * G_p = 0x00200000 + * G_r = 0x000002fd + * History = 2 entries + * Input target = 0x3a0000 + * Interval = 5s + * linear-factors : offset = 0xff38 scale = 0x0ccd + * offset = 0x0208 scale = 0x07ae + * + * # model_id: 3 + * controls : system-fan, drive-bay-fan + * sensors : hd-temp + * PID params : G_d = 0x08e00000 + * G_p = 0x00566666 + * G_r = 0x0000072b + * History = 2 entries + * Input target = 0x350000 + * Interval = 5s + * linear-factors : offset = 0xff38 scale = 0x0ccd + * offset = 0x0000 scale = 0x0000 + * + * # model_id: 5 + * controls : system-fan + * sensors : hd-temp + * PID params : G_d = 0x15400000 + * G_p = 0x00233333 + * G_r = 0x000002fd + * History = 2 entries + * Input target = 0x3a0000 + * Interval = 5s + * linear-factors : offset = 0x0000 scale = 0x1000 + * offset = 0x0091 scale = 0x0bae + * + * CPU Fan control loop. The loop is identical for all models. it + * has an additional pair of scaling factor. This is used to scale the + * systems fan control loop target result (the one before it gets scaled + * by the System Fans control loop itself). Then, the max value of the + * calculated target value and system fan value is sent to the fans + * + * controls : cpu-fan + * sensors : cpu-temp cpu-power + * PID params : From SMU sdb partition + * linear-factors : offset = 0xfb50 scale = 0x1000 + * + * CPU Slew control loop. Not implemented. The cpufreq driver in linux is + * completely separate for now, though we could find a way to link it, either + * as a client reacting to overtemp notifications, or directling monitoring + * the CPU temperature + * + * WARNING ! The CPU control loop requires the CPU tmax for the current + * operating point. However, we currently are completely separated from + * the cpufreq driver and thus do not know what the current operating + * point is. Fortunately, we also do not have any hardware supporting anything + * but operating point 0 at the moment, thus we just peek that value directly + * from the SDB partition. If we ever end up with actually slewing the system + * clock and thus changing operating points, we'll have to find a way to + * communicate with the CPU freq driver; + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "windfarm.h" +#include "windfarm_pid.h" + +#define VERSION "0.4" + +#undef DEBUG + +#ifdef DEBUG +#define DBG(args...) printk(args) +#else +#define DBG(args...) do { } while(0) +#endif + +/* define this to force CPU overtemp to 74 degree, useful for testing + * the overtemp code + */ +#undef HACKED_OVERTEMP + +static int wf_smu_mach_model; /* machine model id */ + +static struct device *wf_smu_dev; + +/* Controls & sensors */ +static struct wf_sensor *sensor_cpu_power; +static struct wf_sensor *sensor_cpu_temp; +static struct wf_sensor *sensor_hd_temp; +static struct wf_control *fan_cpu_main; +static struct wf_control *fan_hd; +static struct wf_control *fan_system; +static struct wf_control *cpufreq_clamp; + +/* Set to kick the control loop into life */ +static int wf_smu_all_controls_ok, wf_smu_all_sensors_ok, wf_smu_started; + +/* Failure handling.. could be nicer */ +#define FAILURE_FAN 0x01 +#define FAILURE_SENSOR 0x02 +#define FAILURE_OVERTEMP 0x04 + +static unsigned int wf_smu_failure_state; +static int wf_smu_readjust, wf_smu_skipping; + +/* + * ****** System Fans Control Loop ****** + * + */ + +/* Parameters for the System Fans control loop. Parameters + * not in this table such as interval, history size, ... + * are common to all versions and thus hard coded for now. + */ +struct wf_smu_sys_fans_param { + int model_id; + s32 itarget; + s32 gd, gp, gr; + + s16 offset0; + u16 scale0; + s16 offset1; + u16 scale1; +}; + +#define WF_SMU_SYS_FANS_INTERVAL 5 +#define WF_SMU_SYS_FANS_HISTORY_SIZE 2 + +/* State data used by the system fans control loop + */ +struct wf_smu_sys_fans_state { + int ticks; + s32 sys_setpoint; + s32 hd_setpoint; + s16 offset0; + u16 scale0; + s16 offset1; + u16 scale1; + struct wf_pid_state pid; +}; + +/* + * Configs for SMU Sytem Fan control loop + */ +static struct wf_smu_sys_fans_param wf_smu_sys_all_params[] = { + /* Model ID 2 */ + { + .model_id = 2, + .itarget = 0x3a0000, + .gd = 0x15400000, + .gp = 0x00200000, + .gr = 0x000002fd, + .offset0 = 0xff38, + .scale0 = 0x0ccd, + .offset1 = 0x0208, + .scale1 = 0x07ae, + }, + /* Model ID 3 */ + { + .model_id = 2, + .itarget = 0x350000, + .gd = 0x08e00000, + .gp = 0x00566666, + .gr = 0x0000072b, + .offset0 = 0xff38, + .scale0 = 0x0ccd, + .offset1 = 0x0000, + .scale1 = 0x0000, + }, + /* Model ID 5 */ + { + .model_id = 2, + .itarget = 0x3a0000, + .gd = 0x15400000, + .gp = 0x00233333, + .gr = 0x000002fd, + .offset0 = 0x0000, + .scale0 = 0x1000, + .offset1 = 0x0091, + .scale1 = 0x0bae, + }, +}; +#define WF_SMU_SYS_FANS_NUM_CONFIGS ARRAY_SIZE(wf_smu_sys_all_params) + +static struct wf_smu_sys_fans_state *wf_smu_sys_fans; + +/* + * ****** CPU Fans Control Loop ****** + * + */ + + +#define WF_SMU_CPU_FANS_INTERVAL 1 +#define WF_SMU_CPU_FANS_MAX_HISTORY 16 +#define WF_SMU_CPU_FANS_SIBLING_SCALE 0x00001000 +#define WF_SMU_CPU_FANS_SIBLING_OFFSET 0xfffffb50 + +/* State data used by the cpu fans control loop + */ +struct wf_smu_cpu_fans_state { + int ticks; + s32 cpu_setpoint; + s32 scale; + s32 offset; + struct wf_cpu_pid_state pid; +}; + +static struct wf_smu_cpu_fans_state *wf_smu_cpu_fans; + + + +/* + * ***** Implementation ***** + * + */ + +static void wf_smu_create_sys_fans(void) +{ + struct wf_smu_sys_fans_param *param = NULL; + struct wf_pid_param pid_param; + int i; + + /* First, locate the params for this model */ + for (i = 0; i < WF_SMU_SYS_FANS_NUM_CONFIGS; i++) + if (wf_smu_sys_all_params[i].model_id == wf_smu_mach_model) { + param = &wf_smu_sys_all_params[i]; + break; + } + + /* No params found, put fans to max */ + if (param == NULL) { + printk(KERN_WARNING "windfarm: System fan config not found " + "for this machine model, max fan speed\n"); + goto fail; + } + + /* Alloc & initialize state */ + wf_smu_sys_fans = kmalloc(sizeof(struct wf_smu_sys_fans_state), + GFP_KERNEL); + if (wf_smu_sys_fans == NULL) { + printk(KERN_WARNING "windfarm: Memory allocation error" + " max fan speed\n"); + goto fail; + } + wf_smu_sys_fans->ticks = 1; + wf_smu_sys_fans->scale0 = param->scale0; + wf_smu_sys_fans->offset0 = param->offset0; + wf_smu_sys_fans->scale1 = param->scale1; + wf_smu_sys_fans->offset1 = param->offset1; + + /* Fill PID params */ + pid_param.gd = param->gd; + pid_param.gp = param->gp; + pid_param.gr = param->gr; + pid_param.interval = WF_SMU_SYS_FANS_INTERVAL; + pid_param.history_len = WF_SMU_SYS_FANS_HISTORY_SIZE; + pid_param.itarget = param->itarget; + pid_param.min = fan_system->ops->get_min(fan_system); + pid_param.max = fan_system->ops->get_max(fan_system); + if (fan_hd) { + pid_param.min = + max(pid_param.min,fan_hd->ops->get_min(fan_hd)); + pid_param.max = + min(pid_param.max,fan_hd->ops->get_max(fan_hd)); + } + wf_pid_init(&wf_smu_sys_fans->pid, &pid_param); + + DBG("wf: System Fan control initialized.\n"); + DBG(" itarged=%d.%03d, min=%d RPM, max=%d RPM\n", + FIX32TOPRINT(pid_param.itarget), pid_param.min, pid_param.max); + return; + + fail: + + if (fan_system) + wf_control_set_max(fan_system); + if (fan_hd) + wf_control_set_max(fan_hd); +} + +static void wf_smu_sys_fans_tick(struct wf_smu_sys_fans_state *st) +{ + s32 new_setpoint, temp, scaled, cputarget; + int rc; + + if (--st->ticks != 0) { + if (wf_smu_readjust) + goto readjust; + return; + } + st->ticks = WF_SMU_SYS_FANS_INTERVAL; + + rc = sensor_hd_temp->ops->get_value(sensor_hd_temp, &temp); + if (rc) { + printk(KERN_WARNING "windfarm: HD temp sensor error %d\n", + rc); + wf_smu_failure_state |= FAILURE_SENSOR; + return; + } + + DBG("wf_smu: System Fans tick ! HD temp: %d.%03d\n", + FIX32TOPRINT(temp)); + + if (temp > (st->pid.param.itarget + 0x50000)) + wf_smu_failure_state |= FAILURE_OVERTEMP; + + new_setpoint = wf_pid_run(&st->pid, temp); + + DBG("wf_smu: new_setpoint: %d RPM\n", (int)new_setpoint); + + scaled = ((((s64)new_setpoint) * (s64)st->scale0) >> 12) + st->offset0; + + DBG("wf_smu: scaled setpoint: %d RPM\n", (int)scaled); + + cputarget = wf_smu_cpu_fans ? wf_smu_cpu_fans->pid.target : 0; + cputarget = ((((s64)cputarget) * (s64)st->scale1) >> 12) + st->offset1; + scaled = max(scaled, cputarget); + scaled = max(scaled, st->pid.param.min); + scaled = min(scaled, st->pid.param.max); + + DBG("wf_smu: adjusted setpoint: %d RPM\n", (int)scaled); + + if (st->sys_setpoint == scaled && new_setpoint == st->hd_setpoint) + return; + st->sys_setpoint = scaled; + st->hd_setpoint = new_setpoint; + readjust: + if (fan_system && wf_smu_failure_state == 0) { + rc = fan_system->ops->set_value(fan_system, st->sys_setpoint); + if (rc) { + printk(KERN_WARNING "windfarm: Sys fan error %d\n", + rc); + wf_smu_failure_state |= FAILURE_FAN; + } + } + if (fan_hd && wf_smu_failure_state == 0) { + rc = fan_hd->ops->set_value(fan_hd, st->hd_setpoint); + if (rc) { + printk(KERN_WARNING "windfarm: HD fan error %d\n", + rc); + wf_smu_failure_state |= FAILURE_FAN; + } + } +} + +static void wf_smu_create_cpu_fans(void) +{ + struct wf_cpu_pid_param pid_param; + struct smu_sdbp_header *hdr; + struct smu_sdbp_cpupiddata *piddata; + struct smu_sdbp_fvt *fvt; + s32 tmax, tdelta, maxpow, powadj; + + /* First, locate the PID params in SMU SBD */ + hdr = smu_get_sdb_partition(SMU_SDB_CPUPIDDATA_ID, NULL); + if (hdr == 0) { + printk(KERN_WARNING "windfarm: CPU PID fan config not found " + "max fan speed\n"); + goto fail; + } + piddata = (struct smu_sdbp_cpupiddata *)&hdr[1]; + + /* Get the FVT params for operating point 0 (the only supported one + * for now) in order to get tmax + */ + hdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL); + if (hdr) { + fvt = (struct smu_sdbp_fvt *)&hdr[1]; + tmax = ((s32)fvt->maxtemp) << 16; + } else + tmax = 0x5e0000; /* 94 degree default */ + + /* Alloc & initialize state */ + wf_smu_cpu_fans = kmalloc(sizeof(struct wf_smu_cpu_fans_state), + GFP_KERNEL); + if (wf_smu_cpu_fans == NULL) + goto fail; + wf_smu_cpu_fans->ticks = 1; + + wf_smu_cpu_fans->scale = WF_SMU_CPU_FANS_SIBLING_SCALE; + wf_smu_cpu_fans->offset = WF_SMU_CPU_FANS_SIBLING_OFFSET; + + /* Fill PID params */ + pid_param.interval = WF_SMU_CPU_FANS_INTERVAL; + pid_param.history_len = piddata->history_len; + if (pid_param.history_len > WF_CPU_PID_MAX_HISTORY) { + printk(KERN_WARNING "windfarm: History size overflow on " + "CPU control loop (%d)\n", piddata->history_len); + pid_param.history_len = WF_CPU_PID_MAX_HISTORY; + } + pid_param.gd = piddata->gd; + pid_param.gp = piddata->gp; + pid_param.gr = piddata->gr / pid_param.history_len; + + tdelta = ((s32)piddata->target_temp_delta) << 16; + maxpow = ((s32)piddata->max_power) << 16; + powadj = ((s32)piddata->power_adj) << 16; + + pid_param.tmax = tmax; + pid_param.ttarget = tmax - tdelta; + pid_param.pmaxadj = maxpow - powadj; + + pid_param.min = fan_cpu_main->ops->get_min(fan_cpu_main); + pid_param.max = fan_cpu_main->ops->get_max(fan_cpu_main); + + wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param); + + DBG("wf: CPU Fan control initialized.\n"); + DBG(" ttarged=%d.%03d, tmax=%d.%03d, min=%d RPM, max=%d RPM\n", + FIX32TOPRINT(pid_param.ttarget), FIX32TOPRINT(pid_param.tmax), + pid_param.min, pid_param.max); + + return; + + fail: + printk(KERN_WARNING "windfarm: CPU fan config not found\n" + "for this machine model, max fan speed\n"); + + if (cpufreq_clamp) + wf_control_set_max(cpufreq_clamp); + if (fan_cpu_main) + wf_control_set_max(fan_cpu_main); +} + +static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st) +{ + s32 new_setpoint, temp, power, systarget; + int rc; + + if (--st->ticks != 0) { + if (wf_smu_readjust) + goto readjust; + return; + } + st->ticks = WF_SMU_CPU_FANS_INTERVAL; + + rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp); + if (rc) { + printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n", + rc); + wf_smu_failure_state |= FAILURE_SENSOR; + return; + } + + rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power); + if (rc) { + printk(KERN_WARNING "windfarm: CPU power sensor error %d\n", + rc); + wf_smu_failure_state |= FAILURE_SENSOR; + return; + } + + DBG("wf_smu: CPU Fans tick ! CPU temp: %d.%03d, power: %d.%03d\n", + FIX32TOPRINT(temp), FIX32TOPRINT(power)); + +#ifdef HACKED_OVERTEMP + if (temp > 0x4a0000) + wf_smu_failure_state |= FAILURE_OVERTEMP; +#else + if (temp > st->pid.param.tmax) + wf_smu_failure_state |= FAILURE_OVERTEMP; +#endif + new_setpoint = wf_cpu_pid_run(&st->pid, power, temp); + + DBG("wf_smu: new_setpoint: %d RPM\n", (int)new_setpoint); + + systarget = wf_smu_sys_fans ? wf_smu_sys_fans->pid.target : 0; + systarget = ((((s64)systarget) * (s64)st->scale) >> 12) + + st->offset; + new_setpoint = max(new_setpoint, systarget); + new_setpoint = max(new_setpoint, st->pid.param.min); + new_setpoint = min(new_setpoint, st->pid.param.max); + + DBG("wf_smu: adjusted setpoint: %d RPM\n", (int)new_setpoint); + + if (st->cpu_setpoint == new_setpoint) + return; + st->cpu_setpoint = new_setpoint; + readjust: + if (fan_cpu_main && wf_smu_failure_state == 0) { + rc = fan_cpu_main->ops->set_value(fan_cpu_main, + st->cpu_setpoint); + if (rc) { + printk(KERN_WARNING "windfarm: CPU main fan" + " error %d\n", rc); + wf_smu_failure_state |= FAILURE_FAN; + } + } +} + + +/* + * ****** Attributes ****** + * + */ + +#define BUILD_SHOW_FUNC_FIX(name, data) \ +static ssize_t show_##name(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + ssize_t r; \ + s32 val = 0; \ + data->ops->get_value(data, &val); \ + r = sprintf(buf, "%d.%03d", FIX32TOPRINT(val)); \ + return r; \ +} \ +static DEVICE_ATTR(name,S_IRUGO,show_##name, NULL); + + +#define BUILD_SHOW_FUNC_INT(name, data) \ +static ssize_t show_##name(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + s32 val = 0; \ + data->ops->get_value(data, &val); \ + return sprintf(buf, "%d", val); \ +} \ +static DEVICE_ATTR(name,S_IRUGO,show_##name, NULL); + +BUILD_SHOW_FUNC_INT(cpu_fan, fan_cpu_main); +BUILD_SHOW_FUNC_INT(sys_fan, fan_system); +BUILD_SHOW_FUNC_INT(hd_fan, fan_hd); + +BUILD_SHOW_FUNC_FIX(cpu_temp, sensor_cpu_temp); +BUILD_SHOW_FUNC_FIX(cpu_power, sensor_cpu_power); +BUILD_SHOW_FUNC_FIX(hd_temp, sensor_hd_temp); + +/* + * ****** Setup / Init / Misc ... ****** + * + */ + +static void wf_smu_tick(void) +{ + unsigned int last_failure = wf_smu_failure_state; + unsigned int new_failure; + + if (!wf_smu_started) { + DBG("wf: creating control loops !\n"); + wf_smu_create_sys_fans(); + wf_smu_create_cpu_fans(); + wf_smu_started = 1; + } + + /* Skipping ticks */ + if (wf_smu_skipping && --wf_smu_skipping) + return; + + wf_smu_failure_state = 0; + if (wf_smu_sys_fans) + wf_smu_sys_fans_tick(wf_smu_sys_fans); + if (wf_smu_cpu_fans) + wf_smu_cpu_fans_tick(wf_smu_cpu_fans); + + wf_smu_readjust = 0; + new_failure = wf_smu_failure_state & ~last_failure; + + /* If entering failure mode, clamp cpufreq and ramp all + * fans to full speed. + */ + if (wf_smu_failure_state && !last_failure) { + if (cpufreq_clamp) + wf_control_set_max(cpufreq_clamp); + if (fan_system) + wf_control_set_max(fan_system); + if (fan_cpu_main) + wf_control_set_max(fan_cpu_main); + if (fan_hd) + wf_control_set_max(fan_hd); + } + + /* If leaving failure mode, unclamp cpufreq and readjust + * all fans on next iteration + */ + if (!wf_smu_failure_state && last_failure) { + if (cpufreq_clamp) + wf_control_set_min(cpufreq_clamp); + wf_smu_readjust = 1; + } + + /* Overtemp condition detected, notify and start skipping a couple + * ticks to let the temperature go down + */ + if (new_failure & FAILURE_OVERTEMP) { + wf_set_overtemp(); + wf_smu_skipping = 2; + } + + /* We only clear the overtemp condition if overtemp is cleared + * _and_ no other failure is present. Since a sensor error will + * clear the overtemp condition (can't measure temperature) at + * the control loop levels, but we don't want to keep it clear + * here in this case + */ + if (new_failure == 0 && last_failure & FAILURE_OVERTEMP) + wf_clear_overtemp(); +} + +static void wf_smu_new_control(struct wf_control *ct) +{ + if (wf_smu_all_controls_ok) + return; + + if (fan_cpu_main == NULL && !strcmp(ct->name, "cpu-fan")) { + if (wf_get_control(ct) == 0) { + fan_cpu_main = ct; + device_create_file(wf_smu_dev, &dev_attr_cpu_fan); + } + } + + if (fan_system == NULL && !strcmp(ct->name, "system-fan")) { + if (wf_get_control(ct) == 0) { + fan_system = ct; + device_create_file(wf_smu_dev, &dev_attr_sys_fan); + } + } + + if (cpufreq_clamp == NULL && !strcmp(ct->name, "cpufreq-clamp")) { + if (wf_get_control(ct) == 0) + cpufreq_clamp = ct; + } + + /* Darwin property list says the HD fan is only for model ID + * 0, 1, 2 and 3 + */ + + if (wf_smu_mach_model > 3) { + if (fan_system && fan_cpu_main && cpufreq_clamp) + wf_smu_all_controls_ok = 1; + return; + } + + if (fan_hd == NULL && !strcmp(ct->name, "drive-bay-fan")) { + if (wf_get_control(ct) == 0) { + fan_hd = ct; + device_create_file(wf_smu_dev, &dev_attr_hd_fan); + } + } + + if (fan_system && fan_hd && fan_cpu_main && cpufreq_clamp) + wf_smu_all_controls_ok = 1; +} + +static void wf_smu_new_sensor(struct wf_sensor *sr) +{ + if (wf_smu_all_sensors_ok) + return; + + if (sensor_cpu_power == NULL && !strcmp(sr->name, "cpu-power")) { + if (wf_get_sensor(sr) == 0) { + sensor_cpu_power = sr; + device_create_file(wf_smu_dev, &dev_attr_cpu_power); + } + } + + if (sensor_cpu_temp == NULL && !strcmp(sr->name, "cpu-temp")) { + if (wf_get_sensor(sr) == 0) { + sensor_cpu_temp = sr; + device_create_file(wf_smu_dev, &dev_attr_cpu_temp); + } + } + + if (sensor_hd_temp == NULL && !strcmp(sr->name, "hd-temp")) { + if (wf_get_sensor(sr) == 0) { + sensor_hd_temp = sr; + device_create_file(wf_smu_dev, &dev_attr_hd_temp); + } + } + + if (sensor_cpu_power && sensor_cpu_temp && sensor_hd_temp) + wf_smu_all_sensors_ok = 1; +} + + +static int wf_smu_notify(struct notifier_block *self, + unsigned long event, void *data) +{ + switch(event) { + case WF_EVENT_NEW_CONTROL: + DBG("wf: new control %s detected\n", + ((struct wf_control *)data)->name); + wf_smu_new_control(data); + wf_smu_readjust = 1; + break; + case WF_EVENT_NEW_SENSOR: + DBG("wf: new sensor %s detected\n", + ((struct wf_sensor *)data)->name); + wf_smu_new_sensor(data); + break; + case WF_EVENT_TICK: + if (wf_smu_all_controls_ok && wf_smu_all_sensors_ok) + wf_smu_tick(); + } + + return 0; +} + +static struct notifier_block wf_smu_events = { + .notifier_call = wf_smu_notify, +}; + +static int wf_init_pm(void) +{ + struct smu_sdbp_header *hdr; + + hdr = smu_get_sdb_partition(SMU_SDB_SENSORTREE_ID, NULL); + if (hdr != 0) { + struct smu_sdbp_sensortree *st = + (struct smu_sdbp_sensortree *)&hdr[1]; + wf_smu_mach_model = st->model_id; + } + + printk(KERN_INFO "windfarm: Initializing for iMacG5 model ID %d\n", + wf_smu_mach_model); + + return 0; +} + +static int wf_smu_probe(struct device *ddev) +{ + wf_smu_dev = ddev; + + wf_register_client(&wf_smu_events); + + return 0; +} + +static int wf_smu_remove(struct device *ddev) +{ + wf_unregister_client(&wf_smu_events); + + /* XXX We don't have yet a guarantee that our callback isn't + * in progress when returning from wf_unregister_client, so + * we add an arbitrary delay. I'll have to fix that in the core + */ + msleep(1000); + + /* Release all sensors */ + /* One more crappy race: I don't think we have any guarantee here + * that the attribute callback won't race with the sensor beeing + * disposed of, and I'm not 100% certain what best way to deal + * with that except by adding locks all over... I'll do that + * eventually but heh, who ever rmmod this module anyway ? + */ + if (sensor_cpu_power) { + device_remove_file(wf_smu_dev, &dev_attr_cpu_power); + wf_put_sensor(sensor_cpu_power); + } + if (sensor_cpu_temp) { + device_remove_file(wf_smu_dev, &dev_attr_cpu_temp); + wf_put_sensor(sensor_cpu_temp); + } + if (sensor_hd_temp) { + device_remove_file(wf_smu_dev, &dev_attr_hd_temp); + wf_put_sensor(sensor_hd_temp); + } + + /* Release all controls */ + if (fan_cpu_main) { + device_remove_file(wf_smu_dev, &dev_attr_cpu_fan); + wf_put_control(fan_cpu_main); + } + if (fan_hd) { + device_remove_file(wf_smu_dev, &dev_attr_hd_fan); + wf_put_control(fan_hd); + } + if (fan_system) { + device_remove_file(wf_smu_dev, &dev_attr_sys_fan); + wf_put_control(fan_system); + } + if (cpufreq_clamp) + wf_put_control(cpufreq_clamp); + + /* Destroy control loops state structures */ + if (wf_smu_sys_fans) + kfree(wf_smu_sys_fans); + if (wf_smu_cpu_fans) + kfree(wf_smu_cpu_fans); + + wf_smu_dev = NULL; + + return 0; +} + +static struct device_driver wf_smu_driver = { + .name = "windfarm", + .bus = &platform_bus_type, + .probe = wf_smu_probe, + .remove = wf_smu_remove, +}; + + +static int __init wf_smu_init(void) +{ + int rc = -ENODEV; + + if (machine_is_compatible("PowerMac8,1") || + machine_is_compatible("PowerMac8,2")) + rc = wf_init_pm(); + + if (rc == 0) { +#ifdef MODULE + request_module("windfarm_smu_controls"); + request_module("windfarm_smu_sensors"); + request_module("windfarm_lm75_sensor"); + +#endif /* MODULE */ + driver_register(&wf_smu_driver); + } + + return rc; +} + +static void __exit wf_smu_exit(void) +{ + + driver_unregister(&wf_smu_driver); +} + + +module_init(wf_smu_init); +module_exit(wf_smu_exit); + +MODULE_AUTHOR("Benjamin Herrenschmidt "); +MODULE_DESCRIPTION("Thermal control logic for iMac G5"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c new file mode 100644 index 0000000000000000000000000000000000000000..43243cf7410b3d887802cfce731a55c7a08b7178 --- /dev/null +++ b/drivers/macintosh/windfarm_pm91.c @@ -0,0 +1,814 @@ +/* + * Windfarm PowerMac thermal control. SMU based 1 CPU desktop control loops + * + * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. + * + * + * Released under the term of the GNU GPL v2. + * + * The algorithm used is the PID control algorithm, used the same + * way the published Darwin code does, using the same values that + * are present in the Darwin 8.2 snapshot property lists (note however + * that none of the code has been re-used, it's a complete re-implementation + * + * The various control loops found in Darwin config file are: + * + * PowerMac9,1 + * =========== + * + * Has 3 control loops: CPU fans is similar to PowerMac8,1 (though it doesn't + * try to play with other control loops fans). Drive bay is rather basic PID + * with one sensor and one fan. Slots area is a bit different as the Darwin + * driver is supposed to be capable of working in a special "AGP" mode which + * involves the presence of an AGP sensor and an AGP fan (possibly on the + * AGP card itself). I can't deal with that special mode as I don't have + * access to those additional sensor/fans for now (though ultimately, it would + * be possible to add sensor objects for them) so I'm only implementing the + * basic PCI slot control loop + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "windfarm.h" +#include "windfarm_pid.h" + +#define VERSION "0.4" + +#undef DEBUG + +#ifdef DEBUG +#define DBG(args...) printk(args) +#else +#define DBG(args...) do { } while(0) +#endif + +/* define this to force CPU overtemp to 74 degree, useful for testing + * the overtemp code + */ +#undef HACKED_OVERTEMP + +static struct device *wf_smu_dev; + +/* Controls & sensors */ +static struct wf_sensor *sensor_cpu_power; +static struct wf_sensor *sensor_cpu_temp; +static struct wf_sensor *sensor_hd_temp; +static struct wf_sensor *sensor_slots_power; +static struct wf_control *fan_cpu_main; +static struct wf_control *fan_cpu_second; +static struct wf_control *fan_cpu_third; +static struct wf_control *fan_hd; +static struct wf_control *fan_slots; +static struct wf_control *cpufreq_clamp; + +/* Set to kick the control loop into life */ +static int wf_smu_all_controls_ok, wf_smu_all_sensors_ok, wf_smu_started; + +/* Failure handling.. could be nicer */ +#define FAILURE_FAN 0x01 +#define FAILURE_SENSOR 0x02 +#define FAILURE_OVERTEMP 0x04 + +static unsigned int wf_smu_failure_state; +static int wf_smu_readjust, wf_smu_skipping; + +/* + * ****** CPU Fans Control Loop ****** + * + */ + + +#define WF_SMU_CPU_FANS_INTERVAL 1 +#define WF_SMU_CPU_FANS_MAX_HISTORY 16 + +/* State data used by the cpu fans control loop + */ +struct wf_smu_cpu_fans_state { + int ticks; + s32 cpu_setpoint; + struct wf_cpu_pid_state pid; +}; + +static struct wf_smu_cpu_fans_state *wf_smu_cpu_fans; + + + +/* + * ****** Drive Fan Control Loop ****** + * + */ + +struct wf_smu_drive_fans_state { + int ticks; + s32 setpoint; + struct wf_pid_state pid; +}; + +static struct wf_smu_drive_fans_state *wf_smu_drive_fans; + +/* + * ****** Slots Fan Control Loop ****** + * + */ + +struct wf_smu_slots_fans_state { + int ticks; + s32 setpoint; + struct wf_pid_state pid; +}; + +static struct wf_smu_slots_fans_state *wf_smu_slots_fans; + +/* + * ***** Implementation ***** + * + */ + + +static void wf_smu_create_cpu_fans(void) +{ + struct wf_cpu_pid_param pid_param; + struct smu_sdbp_header *hdr; + struct smu_sdbp_cpupiddata *piddata; + struct smu_sdbp_fvt *fvt; + s32 tmax, tdelta, maxpow, powadj; + + /* First, locate the PID params in SMU SBD */ + hdr = smu_get_sdb_partition(SMU_SDB_CPUPIDDATA_ID, NULL); + if (hdr == 0) { + printk(KERN_WARNING "windfarm: CPU PID fan config not found " + "max fan speed\n"); + goto fail; + } + piddata = (struct smu_sdbp_cpupiddata *)&hdr[1]; + + /* Get the FVT params for operating point 0 (the only supported one + * for now) in order to get tmax + */ + hdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL); + if (hdr) { + fvt = (struct smu_sdbp_fvt *)&hdr[1]; + tmax = ((s32)fvt->maxtemp) << 16; + } else + tmax = 0x5e0000; /* 94 degree default */ + + /* Alloc & initialize state */ + wf_smu_cpu_fans = kmalloc(sizeof(struct wf_smu_cpu_fans_state), + GFP_KERNEL); + if (wf_smu_cpu_fans == NULL) + goto fail; + wf_smu_cpu_fans->ticks = 1; + + /* Fill PID params */ + pid_param.interval = WF_SMU_CPU_FANS_INTERVAL; + pid_param.history_len = piddata->history_len; + if (pid_param.history_len > WF_CPU_PID_MAX_HISTORY) { + printk(KERN_WARNING "windfarm: History size overflow on " + "CPU control loop (%d)\n", piddata->history_len); + pid_param.history_len = WF_CPU_PID_MAX_HISTORY; + } + pid_param.gd = piddata->gd; + pid_param.gp = piddata->gp; + pid_param.gr = piddata->gr / pid_param.history_len; + + tdelta = ((s32)piddata->target_temp_delta) << 16; + maxpow = ((s32)piddata->max_power) << 16; + powadj = ((s32)piddata->power_adj) << 16; + + pid_param.tmax = tmax; + pid_param.ttarget = tmax - tdelta; + pid_param.pmaxadj = maxpow - powadj; + + pid_param.min = fan_cpu_main->ops->get_min(fan_cpu_main); + pid_param.max = fan_cpu_main->ops->get_max(fan_cpu_main); + + wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param); + + DBG("wf: CPU Fan control initialized.\n"); + DBG(" ttarged=%d.%03d, tmax=%d.%03d, min=%d RPM, max=%d RPM\n", + FIX32TOPRINT(pid_param.ttarget), FIX32TOPRINT(pid_param.tmax), + pid_param.min, pid_param.max); + + return; + + fail: + printk(KERN_WARNING "windfarm: CPU fan config not found\n" + "for this machine model, max fan speed\n"); + + if (cpufreq_clamp) + wf_control_set_max(cpufreq_clamp); + if (fan_cpu_main) + wf_control_set_max(fan_cpu_main); +} + +static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st) +{ + s32 new_setpoint, temp, power; + int rc; + + if (--st->ticks != 0) { + if (wf_smu_readjust) + goto readjust; + return; + } + st->ticks = WF_SMU_CPU_FANS_INTERVAL; + + rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp); + if (rc) { + printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n", + rc); + wf_smu_failure_state |= FAILURE_SENSOR; + return; + } + + rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power); + if (rc) { + printk(KERN_WARNING "windfarm: CPU power sensor error %d\n", + rc); + wf_smu_failure_state |= FAILURE_SENSOR; + return; + } + + DBG("wf_smu: CPU Fans tick ! CPU temp: %d.%03d, power: %d.%03d\n", + FIX32TOPRINT(temp), FIX32TOPRINT(power)); + +#ifdef HACKED_OVERTEMP + if (temp > 0x4a0000) + wf_smu_failure_state |= FAILURE_OVERTEMP; +#else + if (temp > st->pid.param.tmax) + wf_smu_failure_state |= FAILURE_OVERTEMP; +#endif + new_setpoint = wf_cpu_pid_run(&st->pid, power, temp); + + DBG("wf_smu: new_setpoint: %d RPM\n", (int)new_setpoint); + + if (st->cpu_setpoint == new_setpoint) + return; + st->cpu_setpoint = new_setpoint; + readjust: + if (fan_cpu_main && wf_smu_failure_state == 0) { + rc = fan_cpu_main->ops->set_value(fan_cpu_main, + st->cpu_setpoint); + if (rc) { + printk(KERN_WARNING "windfarm: CPU main fan" + " error %d\n", rc); + wf_smu_failure_state |= FAILURE_FAN; + } + } + if (fan_cpu_second && wf_smu_failure_state == 0) { + rc = fan_cpu_second->ops->set_value(fan_cpu_second, + st->cpu_setpoint); + if (rc) { + printk(KERN_WARNING "windfarm: CPU second fan" + " error %d\n", rc); + wf_smu_failure_state |= FAILURE_FAN; + } + } + if (fan_cpu_third && wf_smu_failure_state == 0) { + rc = fan_cpu_main->ops->set_value(fan_cpu_third, + st->cpu_setpoint); + if (rc) { + printk(KERN_WARNING "windfarm: CPU third fan" + " error %d\n", rc); + wf_smu_failure_state |= FAILURE_FAN; + } + } +} + +static void wf_smu_create_drive_fans(void) +{ + struct wf_pid_param param = { + .interval = 5, + .history_len = 2, + .gd = 0x01e00000, + .gp = 0x00500000, + .gr = 0x00000000, + .itarget = 0x00200000, + }; + + /* Alloc & initialize state */ + wf_smu_drive_fans = kmalloc(sizeof(struct wf_smu_drive_fans_state), + GFP_KERNEL); + if (wf_smu_drive_fans == NULL) { + printk(KERN_WARNING "windfarm: Memory allocation error" + " max fan speed\n"); + goto fail; + } + wf_smu_drive_fans->ticks = 1; + + /* Fill PID params */ + param.additive = (fan_hd->type == WF_CONTROL_RPM_FAN); + param.min = fan_hd->ops->get_min(fan_hd); + param.max = fan_hd->ops->get_max(fan_hd); + wf_pid_init(&wf_smu_drive_fans->pid, ¶m); + + DBG("wf: Drive Fan control initialized.\n"); + DBG(" itarged=%d.%03d, min=%d RPM, max=%d RPM\n", + FIX32TOPRINT(param.itarget), param.min, param.max); + return; + + fail: + if (fan_hd) + wf_control_set_max(fan_hd); +} + +static void wf_smu_drive_fans_tick(struct wf_smu_drive_fans_state *st) +{ + s32 new_setpoint, temp; + int rc; + + if (--st->ticks != 0) { + if (wf_smu_readjust) + goto readjust; + return; + } + st->ticks = st->pid.param.interval; + + rc = sensor_hd_temp->ops->get_value(sensor_hd_temp, &temp); + if (rc) { + printk(KERN_WARNING "windfarm: HD temp sensor error %d\n", + rc); + wf_smu_failure_state |= FAILURE_SENSOR; + return; + } + + DBG("wf_smu: Drive Fans tick ! HD temp: %d.%03d\n", + FIX32TOPRINT(temp)); + + if (temp > (st->pid.param.itarget + 0x50000)) + wf_smu_failure_state |= FAILURE_OVERTEMP; + + new_setpoint = wf_pid_run(&st->pid, temp); + + DBG("wf_smu: new_setpoint: %d\n", (int)new_setpoint); + + if (st->setpoint == new_setpoint) + return; + st->setpoint = new_setpoint; + readjust: + if (fan_hd && wf_smu_failure_state == 0) { + rc = fan_hd->ops->set_value(fan_hd, st->setpoint); + if (rc) { + printk(KERN_WARNING "windfarm: HD fan error %d\n", + rc); + wf_smu_failure_state |= FAILURE_FAN; + } + } +} + +static void wf_smu_create_slots_fans(void) +{ + struct wf_pid_param param = { + .interval = 1, + .history_len = 8, + .gd = 0x00000000, + .gp = 0x00000000, + .gr = 0x00020000, + .itarget = 0x00000000 + }; + + /* Alloc & initialize state */ + wf_smu_slots_fans = kmalloc(sizeof(struct wf_smu_slots_fans_state), + GFP_KERNEL); + if (wf_smu_slots_fans == NULL) { + printk(KERN_WARNING "windfarm: Memory allocation error" + " max fan speed\n"); + goto fail; + } + wf_smu_slots_fans->ticks = 1; + + /* Fill PID params */ + param.additive = (fan_slots->type == WF_CONTROL_RPM_FAN); + param.min = fan_slots->ops->get_min(fan_slots); + param.max = fan_slots->ops->get_max(fan_slots); + wf_pid_init(&wf_smu_slots_fans->pid, ¶m); + + DBG("wf: Slots Fan control initialized.\n"); + DBG(" itarged=%d.%03d, min=%d RPM, max=%d RPM\n", + FIX32TOPRINT(param.itarget), param.min, param.max); + return; + + fail: + if (fan_slots) + wf_control_set_max(fan_slots); +} + +static void wf_smu_slots_fans_tick(struct wf_smu_slots_fans_state *st) +{ + s32 new_setpoint, power; + int rc; + + if (--st->ticks != 0) { + if (wf_smu_readjust) + goto readjust; + return; + } + st->ticks = st->pid.param.interval; + + rc = sensor_slots_power->ops->get_value(sensor_slots_power, &power); + if (rc) { + printk(KERN_WARNING "windfarm: Slots power sensor error %d\n", + rc); + wf_smu_failure_state |= FAILURE_SENSOR; + return; + } + + DBG("wf_smu: Slots Fans tick ! Slots power: %d.%03d\n", + FIX32TOPRINT(power)); + +#if 0 /* Check what makes a good overtemp condition */ + if (power > (st->pid.param.itarget + 0x50000)) + wf_smu_failure_state |= FAILURE_OVERTEMP; +#endif + + new_setpoint = wf_pid_run(&st->pid, power); + + DBG("wf_smu: new_setpoint: %d\n", (int)new_setpoint); + + if (st->setpoint == new_setpoint) + return; + st->setpoint = new_setpoint; + readjust: + if (fan_slots && wf_smu_failure_state == 0) { + rc = fan_slots->ops->set_value(fan_slots, st->setpoint); + if (rc) { + printk(KERN_WARNING "windfarm: Slots fan error %d\n", + rc); + wf_smu_failure_state |= FAILURE_FAN; + } + } +} + + +/* + * ****** Attributes ****** + * + */ + +#define BUILD_SHOW_FUNC_FIX(name, data) \ +static ssize_t show_##name(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + ssize_t r; \ + s32 val = 0; \ + data->ops->get_value(data, &val); \ + r = sprintf(buf, "%d.%03d", FIX32TOPRINT(val)); \ + return r; \ +} \ +static DEVICE_ATTR(name,S_IRUGO,show_##name, NULL); + + +#define BUILD_SHOW_FUNC_INT(name, data) \ +static ssize_t show_##name(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + s32 val = 0; \ + data->ops->get_value(data, &val); \ + return sprintf(buf, "%d", val); \ +} \ +static DEVICE_ATTR(name,S_IRUGO,show_##name, NULL); + +BUILD_SHOW_FUNC_INT(cpu_fan, fan_cpu_main); +BUILD_SHOW_FUNC_INT(hd_fan, fan_hd); +BUILD_SHOW_FUNC_INT(slots_fan, fan_slots); + +BUILD_SHOW_FUNC_FIX(cpu_temp, sensor_cpu_temp); +BUILD_SHOW_FUNC_FIX(cpu_power, sensor_cpu_power); +BUILD_SHOW_FUNC_FIX(hd_temp, sensor_hd_temp); +BUILD_SHOW_FUNC_FIX(slots_power, sensor_slots_power); + +/* + * ****** Setup / Init / Misc ... ****** + * + */ + +static void wf_smu_tick(void) +{ + unsigned int last_failure = wf_smu_failure_state; + unsigned int new_failure; + + if (!wf_smu_started) { + DBG("wf: creating control loops !\n"); + wf_smu_create_drive_fans(); + wf_smu_create_slots_fans(); + wf_smu_create_cpu_fans(); + wf_smu_started = 1; + } + + /* Skipping ticks */ + if (wf_smu_skipping && --wf_smu_skipping) + return; + + wf_smu_failure_state = 0; + if (wf_smu_drive_fans) + wf_smu_drive_fans_tick(wf_smu_drive_fans); + if (wf_smu_slots_fans) + wf_smu_slots_fans_tick(wf_smu_slots_fans); + if (wf_smu_cpu_fans) + wf_smu_cpu_fans_tick(wf_smu_cpu_fans); + + wf_smu_readjust = 0; + new_failure = wf_smu_failure_state & ~last_failure; + + /* If entering failure mode, clamp cpufreq and ramp all + * fans to full speed. + */ + if (wf_smu_failure_state && !last_failure) { + if (cpufreq_clamp) + wf_control_set_max(cpufreq_clamp); + if (fan_cpu_main) + wf_control_set_max(fan_cpu_main); + if (fan_cpu_second) + wf_control_set_max(fan_cpu_second); + if (fan_cpu_third) + wf_control_set_max(fan_cpu_third); + if (fan_hd) + wf_control_set_max(fan_hd); + if (fan_slots) + wf_control_set_max(fan_slots); + } + + /* If leaving failure mode, unclamp cpufreq and readjust + * all fans on next iteration + */ + if (!wf_smu_failure_state && last_failure) { + if (cpufreq_clamp) + wf_control_set_min(cpufreq_clamp); + wf_smu_readjust = 1; + } + + /* Overtemp condition detected, notify and start skipping a couple + * ticks to let the temperature go down + */ + if (new_failure & FAILURE_OVERTEMP) { + wf_set_overtemp(); + wf_smu_skipping = 2; + } + + /* We only clear the overtemp condition if overtemp is cleared + * _and_ no other failure is present. Since a sensor error will + * clear the overtemp condition (can't measure temperature) at + * the control loop levels, but we don't want to keep it clear + * here in this case + */ + if (new_failure == 0 && last_failure & FAILURE_OVERTEMP) + wf_clear_overtemp(); +} + + +static void wf_smu_new_control(struct wf_control *ct) +{ + if (wf_smu_all_controls_ok) + return; + + if (fan_cpu_main == NULL && !strcmp(ct->name, "cpu-rear-fan-0")) { + if (wf_get_control(ct) == 0) { + fan_cpu_main = ct; + device_create_file(wf_smu_dev, &dev_attr_cpu_fan); + } + } + + if (fan_cpu_second == NULL && !strcmp(ct->name, "cpu-rear-fan-1")) { + if (wf_get_control(ct) == 0) + fan_cpu_second = ct; + } + + if (fan_cpu_third == NULL && !strcmp(ct->name, "cpu-front-fan-0")) { + if (wf_get_control(ct) == 0) + fan_cpu_third = ct; + } + + if (cpufreq_clamp == NULL && !strcmp(ct->name, "cpufreq-clamp")) { + if (wf_get_control(ct) == 0) + cpufreq_clamp = ct; + } + + if (fan_hd == NULL && !strcmp(ct->name, "drive-bay-fan")) { + if (wf_get_control(ct) == 0) { + fan_hd = ct; + device_create_file(wf_smu_dev, &dev_attr_hd_fan); + } + } + + if (fan_slots == NULL && !strcmp(ct->name, "slots-fan")) { + if (wf_get_control(ct) == 0) { + fan_slots = ct; + device_create_file(wf_smu_dev, &dev_attr_slots_fan); + } + } + + if (fan_cpu_main && (fan_cpu_second || fan_cpu_third) && fan_hd && + fan_slots && cpufreq_clamp) + wf_smu_all_controls_ok = 1; +} + +static void wf_smu_new_sensor(struct wf_sensor *sr) +{ + if (wf_smu_all_sensors_ok) + return; + + if (sensor_cpu_power == NULL && !strcmp(sr->name, "cpu-power")) { + if (wf_get_sensor(sr) == 0) { + sensor_cpu_power = sr; + device_create_file(wf_smu_dev, &dev_attr_cpu_power); + } + } + + if (sensor_cpu_temp == NULL && !strcmp(sr->name, "cpu-temp")) { + if (wf_get_sensor(sr) == 0) { + sensor_cpu_temp = sr; + device_create_file(wf_smu_dev, &dev_attr_cpu_temp); + } + } + + if (sensor_hd_temp == NULL && !strcmp(sr->name, "hd-temp")) { + if (wf_get_sensor(sr) == 0) { + sensor_hd_temp = sr; + device_create_file(wf_smu_dev, &dev_attr_hd_temp); + } + } + + if (sensor_slots_power == NULL && !strcmp(sr->name, "slots-power")) { + if (wf_get_sensor(sr) == 0) { + sensor_slots_power = sr; + device_create_file(wf_smu_dev, &dev_attr_slots_power); + } + } + + if (sensor_cpu_power && sensor_cpu_temp && + sensor_hd_temp && sensor_slots_power) + wf_smu_all_sensors_ok = 1; +} + + +static int wf_smu_notify(struct notifier_block *self, + unsigned long event, void *data) +{ + switch(event) { + case WF_EVENT_NEW_CONTROL: + DBG("wf: new control %s detected\n", + ((struct wf_control *)data)->name); + wf_smu_new_control(data); + wf_smu_readjust = 1; + break; + case WF_EVENT_NEW_SENSOR: + DBG("wf: new sensor %s detected\n", + ((struct wf_sensor *)data)->name); + wf_smu_new_sensor(data); + break; + case WF_EVENT_TICK: + if (wf_smu_all_controls_ok && wf_smu_all_sensors_ok) + wf_smu_tick(); + } + + return 0; +} + +static struct notifier_block wf_smu_events = { + .notifier_call = wf_smu_notify, +}; + +static int wf_init_pm(void) +{ + printk(KERN_INFO "windfarm: Initializing for Desktop G5 model\n"); + + return 0; +} + +static int wf_smu_probe(struct device *ddev) +{ + wf_smu_dev = ddev; + + wf_register_client(&wf_smu_events); + + return 0; +} + +static int wf_smu_remove(struct device *ddev) +{ + wf_unregister_client(&wf_smu_events); + + /* XXX We don't have yet a guarantee that our callback isn't + * in progress when returning from wf_unregister_client, so + * we add an arbitrary delay. I'll have to fix that in the core + */ + msleep(1000); + + /* Release all sensors */ + /* One more crappy race: I don't think we have any guarantee here + * that the attribute callback won't race with the sensor beeing + * disposed of, and I'm not 100% certain what best way to deal + * with that except by adding locks all over... I'll do that + * eventually but heh, who ever rmmod this module anyway ? + */ + if (sensor_cpu_power) { + device_remove_file(wf_smu_dev, &dev_attr_cpu_power); + wf_put_sensor(sensor_cpu_power); + } + if (sensor_cpu_temp) { + device_remove_file(wf_smu_dev, &dev_attr_cpu_temp); + wf_put_sensor(sensor_cpu_temp); + } + if (sensor_hd_temp) { + device_remove_file(wf_smu_dev, &dev_attr_hd_temp); + wf_put_sensor(sensor_hd_temp); + } + if (sensor_slots_power) { + device_remove_file(wf_smu_dev, &dev_attr_slots_power); + wf_put_sensor(sensor_slots_power); + } + + /* Release all controls */ + if (fan_cpu_main) { + device_remove_file(wf_smu_dev, &dev_attr_cpu_fan); + wf_put_control(fan_cpu_main); + } + if (fan_cpu_second) + wf_put_control(fan_cpu_second); + if (fan_cpu_third) + wf_put_control(fan_cpu_third); + if (fan_hd) { + device_remove_file(wf_smu_dev, &dev_attr_hd_fan); + wf_put_control(fan_hd); + } + if (fan_slots) { + device_remove_file(wf_smu_dev, &dev_attr_slots_fan); + wf_put_control(fan_slots); + } + if (cpufreq_clamp) + wf_put_control(cpufreq_clamp); + + /* Destroy control loops state structures */ + if (wf_smu_slots_fans) + kfree(wf_smu_cpu_fans); + if (wf_smu_drive_fans) + kfree(wf_smu_cpu_fans); + if (wf_smu_cpu_fans) + kfree(wf_smu_cpu_fans); + + wf_smu_dev = NULL; + + return 0; +} + +static struct device_driver wf_smu_driver = { + .name = "windfarm", + .bus = &platform_bus_type, + .probe = wf_smu_probe, + .remove = wf_smu_remove, +}; + + +static int __init wf_smu_init(void) +{ + int rc = -ENODEV; + + if (machine_is_compatible("PowerMac9,1")) + rc = wf_init_pm(); + + if (rc == 0) { +#ifdef MODULE + request_module("windfarm_smu_controls"); + request_module("windfarm_smu_sensors"); + request_module("windfarm_lm75_sensor"); + +#endif /* MODULE */ + driver_register(&wf_smu_driver); + } + + return rc; +} + +static void __exit wf_smu_exit(void) +{ + + driver_unregister(&wf_smu_driver); +} + + +module_init(wf_smu_init); +module_exit(wf_smu_exit); + +MODULE_AUTHOR("Benjamin Herrenschmidt "); +MODULE_DESCRIPTION("Thermal control logic for PowerMac9,1"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c new file mode 100644 index 0000000000000000000000000000000000000000..2c3158c81ff24b38e10d7d915a02a33eed1d8b5d --- /dev/null +++ b/drivers/macintosh/windfarm_smu_controls.c @@ -0,0 +1,282 @@ +/* + * Windfarm PowerMac thermal control. SMU based controls + * + * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. + * + * + * Released under the term of the GNU GPL v2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "windfarm.h" + +#define VERSION "0.3" + +#undef DEBUG + +#ifdef DEBUG +#define DBG(args...) printk(args) +#else +#define DBG(args...) do { } while(0) +#endif + +/* + * SMU fans control object + */ + +static LIST_HEAD(smu_fans); + +struct smu_fan_control { + struct list_head link; + int fan_type; /* 0 = rpm, 1 = pwm */ + u32 reg; /* index in SMU */ + s32 value; /* current value */ + s32 min, max; /* min/max values */ + struct wf_control ctrl; +}; +#define to_smu_fan(c) container_of(c, struct smu_fan_control, ctrl) + +static int smu_set_fan(int pwm, u8 id, u16 value) +{ + struct smu_cmd cmd; + u8 buffer[16]; + DECLARE_COMPLETION(comp); + int rc; + + /* Fill SMU command structure */ + cmd.cmd = SMU_CMD_FAN_COMMAND; + cmd.data_len = 14; + cmd.reply_len = 16; + cmd.data_buf = cmd.reply_buf = buffer; + cmd.status = 0; + cmd.done = smu_done_complete; + cmd.misc = ∁ + + /* Fill argument buffer */ + memset(buffer, 0, 16); + buffer[0] = pwm ? 0x10 : 0x00; + buffer[1] = 0x01 << id; + *((u16 *)&buffer[2 + id * 2]) = value; + + rc = smu_queue_cmd(&cmd); + if (rc) + return rc; + wait_for_completion(&comp); + return cmd.status; +} + +static void smu_fan_release(struct wf_control *ct) +{ + struct smu_fan_control *fct = to_smu_fan(ct); + + kfree(fct); +} + +static int smu_fan_set(struct wf_control *ct, s32 value) +{ + struct smu_fan_control *fct = to_smu_fan(ct); + + if (value < fct->min) + value = fct->min; + if (value > fct->max) + value = fct->max; + fct->value = value; + + return smu_set_fan(fct->fan_type, fct->reg, value); +} + +static int smu_fan_get(struct wf_control *ct, s32 *value) +{ + struct smu_fan_control *fct = to_smu_fan(ct); + *value = fct->value; /* todo: read from SMU */ + return 0; +} + +static s32 smu_fan_min(struct wf_control *ct) +{ + struct smu_fan_control *fct = to_smu_fan(ct); + return fct->min; +} + +static s32 smu_fan_max(struct wf_control *ct) +{ + struct smu_fan_control *fct = to_smu_fan(ct); + return fct->max; +} + +static struct wf_control_ops smu_fan_ops = { + .set_value = smu_fan_set, + .get_value = smu_fan_get, + .get_min = smu_fan_min, + .get_max = smu_fan_max, + .release = smu_fan_release, + .owner = THIS_MODULE, +}; + +static struct smu_fan_control *smu_fan_create(struct device_node *node, + int pwm_fan) +{ + struct smu_fan_control *fct; + s32 *v; u32 *reg; + char *l; + + fct = kmalloc(sizeof(struct smu_fan_control), GFP_KERNEL); + if (fct == NULL) + return NULL; + fct->ctrl.ops = &smu_fan_ops; + l = (char *)get_property(node, "location", NULL); + if (l == NULL) + goto fail; + + fct->fan_type = pwm_fan; + fct->ctrl.type = pwm_fan ? WF_CONTROL_PWM_FAN : WF_CONTROL_RPM_FAN; + + /* We use the name & location here the same way we do for SMU sensors, + * see the comment in windfarm_smu_sensors.c. The locations are a bit + * less consistent here between the iMac and the desktop models, but + * that is good enough for our needs for now at least. + * + * One problem though is that Apple seem to be inconsistent with case + * and the kernel doesn't have strcasecmp =P + */ + + fct->ctrl.name = NULL; + + /* Names used on desktop models */ + if (!strcmp(l, "Rear Fan 0") || !strcmp(l, "Rear Fan") || + !strcmp(l, "Rear fan 0") || !strcmp(l, "Rear fan")) + fct->ctrl.name = "cpu-rear-fan-0"; + else if (!strcmp(l, "Rear Fan 1") || !strcmp(l, "Rear fan 1")) + fct->ctrl.name = "cpu-rear-fan-1"; + else if (!strcmp(l, "Front Fan 0") || !strcmp(l, "Front Fan") || + !strcmp(l, "Front fan 0") || !strcmp(l, "Front fan")) + fct->ctrl.name = "cpu-front-fan-0"; + else if (!strcmp(l, "Front Fan 1") || !strcmp(l, "Front fan 1")) + fct->ctrl.name = "cpu-front-fan-1"; + else if (!strcmp(l, "Slots Fan") || !strcmp(l, "Slots fan")) + fct->ctrl.name = "slots-fan"; + else if (!strcmp(l, "Drive Bay") || !strcmp(l, "Drive bay")) + fct->ctrl.name = "drive-bay-fan"; + + /* Names used on iMac models */ + if (!strcmp(l, "System Fan") || !strcmp(l, "System fan")) + fct->ctrl.name = "system-fan"; + else if (!strcmp(l, "CPU Fan") || !strcmp(l, "CPU fan")) + fct->ctrl.name = "cpu-fan"; + else if (!strcmp(l, "Hard Drive") || !strcmp(l, "Hard drive")) + fct->ctrl.name = "drive-bay-fan"; + + /* Unrecognized fan, bail out */ + if (fct->ctrl.name == NULL) + goto fail; + + /* Get min & max values*/ + v = (s32 *)get_property(node, "min-value", NULL); + if (v == NULL) + goto fail; + fct->min = *v; + v = (s32 *)get_property(node, "max-value", NULL); + if (v == NULL) + goto fail; + fct->max = *v; + + /* Get "reg" value */ + reg = (u32 *)get_property(node, "reg", NULL); + if (reg == NULL) + goto fail; + fct->reg = *reg; + + if (wf_register_control(&fct->ctrl)) + goto fail; + + return fct; + fail: + kfree(fct); + return NULL; +} + + +static int __init smu_controls_init(void) +{ + struct device_node *smu, *fans, *fan; + + if (!smu_present()) + return -ENODEV; + + smu = of_find_node_by_type(NULL, "smu"); + if (smu == NULL) + return -ENODEV; + + /* Look for RPM fans */ + for (fans = NULL; (fans = of_get_next_child(smu, fans)) != NULL;) + if (!strcmp(fans->name, "rpm-fans")) + break; + for (fan = NULL; + fans && (fan = of_get_next_child(fans, fan)) != NULL;) { + struct smu_fan_control *fct; + + fct = smu_fan_create(fan, 0); + if (fct == NULL) { + printk(KERN_WARNING "windfarm: Failed to create SMU " + "RPM fan %s\n", fan->name); + continue; + } + list_add(&fct->link, &smu_fans); + } + of_node_put(fans); + + + /* Look for PWM fans */ + for (fans = NULL; (fans = of_get_next_child(smu, fans)) != NULL;) + if (!strcmp(fans->name, "pwm-fans")) + break; + for (fan = NULL; + fans && (fan = of_get_next_child(fans, fan)) != NULL;) { + struct smu_fan_control *fct; + + fct = smu_fan_create(fan, 1); + if (fct == NULL) { + printk(KERN_WARNING "windfarm: Failed to create SMU " + "PWM fan %s\n", fan->name); + continue; + } + list_add(&fct->link, &smu_fans); + } + of_node_put(fans); + of_node_put(smu); + + return 0; +} + +static void __exit smu_controls_exit(void) +{ + struct smu_fan_control *fct; + + while (!list_empty(&smu_fans)) { + fct = list_entry(smu_fans.next, struct smu_fan_control, link); + list_del(&fct->link); + wf_unregister_control(&fct->ctrl); + } +} + + +module_init(smu_controls_init); +module_exit(smu_controls_exit); + +MODULE_AUTHOR("Benjamin Herrenschmidt "); +MODULE_DESCRIPTION("SMU control objects for PowerMacs thermal control"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c new file mode 100644 index 0000000000000000000000000000000000000000..b558cc209d4930394c05006719929469b11b2ca8 --- /dev/null +++ b/drivers/macintosh/windfarm_smu_sensors.c @@ -0,0 +1,479 @@ +/* + * Windfarm PowerMac thermal control. SMU based sensors + * + * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. + * + * + * Released under the term of the GNU GPL v2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "windfarm.h" + +#define VERSION "0.2" + +#undef DEBUG + +#ifdef DEBUG +#define DBG(args...) printk(args) +#else +#define DBG(args...) do { } while(0) +#endif + +/* + * Various SMU "partitions" calibration objects for which we + * keep pointers here for use by bits & pieces of the driver + */ +static struct smu_sdbp_cpuvcp *cpuvcp; +static int cpuvcp_version; +static struct smu_sdbp_cpudiode *cpudiode; +static struct smu_sdbp_slotspow *slotspow; +static u8 *debugswitches; + +/* + * SMU basic sensors objects + */ + +static LIST_HEAD(smu_ads); + +struct smu_ad_sensor { + struct list_head link; + u32 reg; /* index in SMU */ + struct wf_sensor sens; +}; +#define to_smu_ads(c) container_of(c, struct smu_ad_sensor, sens) + +static void smu_ads_release(struct wf_sensor *sr) +{ + struct smu_ad_sensor *ads = to_smu_ads(sr); + + kfree(ads); +} + +static int smu_read_adc(u8 id, s32 *value) +{ + struct smu_simple_cmd cmd; + DECLARE_COMPLETION(comp); + int rc; + + rc = smu_queue_simple(&cmd, SMU_CMD_READ_ADC, 1, + smu_done_complete, &comp, id); + if (rc) + return rc; + wait_for_completion(&comp); + if (cmd.cmd.status != 0) + return cmd.cmd.status; + if (cmd.cmd.reply_len != 2) { + printk(KERN_ERR "winfarm: read ADC 0x%x returned %d bytes !\n", + id, cmd.cmd.reply_len); + return -EIO; + } + *value = *((u16 *)cmd.buffer); + return 0; +} + +static int smu_cputemp_get(struct wf_sensor *sr, s32 *value) +{ + struct smu_ad_sensor *ads = to_smu_ads(sr); + int rc; + s32 val; + s64 scaled; + + rc = smu_read_adc(ads->reg, &val); + if (rc) { + printk(KERN_ERR "windfarm: read CPU temp failed, err %d\n", + rc); + return rc; + } + + /* Ok, we have to scale & adjust, taking units into account */ + scaled = (s64)(((u64)val) * (u64)cpudiode->m_value); + scaled >>= 3; + scaled += ((s64)cpudiode->b_value) << 9; + *value = (s32)(scaled << 1); + + return 0; +} + +static int smu_cpuamp_get(struct wf_sensor *sr, s32 *value) +{ + struct smu_ad_sensor *ads = to_smu_ads(sr); + s32 val, scaled; + int rc; + + rc = smu_read_adc(ads->reg, &val); + if (rc) { + printk(KERN_ERR "windfarm: read CPU current failed, err %d\n", + rc); + return rc; + } + + /* Ok, we have to scale & adjust, taking units into account */ + scaled = (s32)(val * (u32)cpuvcp->curr_scale); + scaled += (s32)cpuvcp->curr_offset; + *value = scaled << 4; + + return 0; +} + +static int smu_cpuvolt_get(struct wf_sensor *sr, s32 *value) +{ + struct smu_ad_sensor *ads = to_smu_ads(sr); + s32 val, scaled; + int rc; + + rc = smu_read_adc(ads->reg, &val); + if (rc) { + printk(KERN_ERR "windfarm: read CPU voltage failed, err %d\n", + rc); + return rc; + } + + /* Ok, we have to scale & adjust, taking units into account */ + scaled = (s32)(val * (u32)cpuvcp->volt_scale); + scaled += (s32)cpuvcp->volt_offset; + *value = scaled << 4; + + return 0; +} + +static int smu_slotspow_get(struct wf_sensor *sr, s32 *value) +{ + struct smu_ad_sensor *ads = to_smu_ads(sr); + s32 val, scaled; + int rc; + + rc = smu_read_adc(ads->reg, &val); + if (rc) { + printk(KERN_ERR "windfarm: read slots power failed, err %d\n", + rc); + return rc; + } + + /* Ok, we have to scale & adjust, taking units into account */ + scaled = (s32)(val * (u32)slotspow->pow_scale); + scaled += (s32)slotspow->pow_offset; + *value = scaled << 4; + + return 0; +} + + +static struct wf_sensor_ops smu_cputemp_ops = { + .get_value = smu_cputemp_get, + .release = smu_ads_release, + .owner = THIS_MODULE, +}; +static struct wf_sensor_ops smu_cpuamp_ops = { + .get_value = smu_cpuamp_get, + .release = smu_ads_release, + .owner = THIS_MODULE, +}; +static struct wf_sensor_ops smu_cpuvolt_ops = { + .get_value = smu_cpuvolt_get, + .release = smu_ads_release, + .owner = THIS_MODULE, +}; +static struct wf_sensor_ops smu_slotspow_ops = { + .get_value = smu_slotspow_get, + .release = smu_ads_release, + .owner = THIS_MODULE, +}; + + +static struct smu_ad_sensor *smu_ads_create(struct device_node *node) +{ + struct smu_ad_sensor *ads; + char *c, *l; + u32 *v; + + ads = kmalloc(sizeof(struct smu_ad_sensor), GFP_KERNEL); + if (ads == NULL) + return NULL; + c = (char *)get_property(node, "device_type", NULL); + l = (char *)get_property(node, "location", NULL); + if (c == NULL || l == NULL) + goto fail; + + /* We currently pick the sensors based on the OF name and location + * properties, while Darwin uses the sensor-id's. + * The problem with the IDs is that they are model specific while it + * looks like apple has been doing a reasonably good job at keeping + * the names and locations consistents so I'll stick with the names + * and locations for now. + */ + if (!strcmp(c, "temp-sensor") && + !strcmp(l, "CPU T-Diode")) { + ads->sens.ops = &smu_cputemp_ops; + ads->sens.name = "cpu-temp"; + } else if (!strcmp(c, "current-sensor") && + !strcmp(l, "CPU Current")) { + ads->sens.ops = &smu_cpuamp_ops; + ads->sens.name = "cpu-current"; + } else if (!strcmp(c, "voltage-sensor") && + !strcmp(l, "CPU Voltage")) { + ads->sens.ops = &smu_cpuvolt_ops; + ads->sens.name = "cpu-voltage"; + } else if (!strcmp(c, "power-sensor") && + !strcmp(l, "Slots Power")) { + ads->sens.ops = &smu_slotspow_ops; + ads->sens.name = "slots-power"; + if (slotspow == NULL) { + DBG("wf: slotspow partition (%02x) not found\n", + SMU_SDB_SLOTSPOW_ID); + goto fail; + } + } else + goto fail; + + v = (u32 *)get_property(node, "reg", NULL); + if (v == NULL) + goto fail; + ads->reg = *v; + + if (wf_register_sensor(&ads->sens)) + goto fail; + return ads; + fail: + kfree(ads); + return NULL; +} + +/* + * SMU Power combo sensor object + */ + +struct smu_cpu_power_sensor { + struct list_head link; + struct wf_sensor *volts; + struct wf_sensor *amps; + int fake_volts : 1; + int quadratic : 1; + struct wf_sensor sens; +}; +#define to_smu_cpu_power(c) container_of(c, struct smu_cpu_power_sensor, sens) + +static struct smu_cpu_power_sensor *smu_cpu_power; + +static void smu_cpu_power_release(struct wf_sensor *sr) +{ + struct smu_cpu_power_sensor *pow = to_smu_cpu_power(sr); + + if (pow->volts) + wf_put_sensor(pow->volts); + if (pow->amps) + wf_put_sensor(pow->amps); + kfree(pow); +} + +static int smu_cpu_power_get(struct wf_sensor *sr, s32 *value) +{ + struct smu_cpu_power_sensor *pow = to_smu_cpu_power(sr); + s32 volts, amps, power; + u64 tmps, tmpa, tmpb; + int rc; + + rc = pow->amps->ops->get_value(pow->amps, &s); + if (rc) + return rc; + + if (pow->fake_volts) { + *value = amps * 12 - 0x30000; + return 0; + } + + rc = pow->volts->ops->get_value(pow->volts, &volts); + if (rc) + return rc; + + power = (s32)((((u64)volts) * ((u64)amps)) >> 16); + if (!pow->quadratic) { + *value = power; + return 0; + } + tmps = (((u64)power) * ((u64)power)) >> 16; + tmpa = ((u64)cpuvcp->power_quads[0]) * tmps; + tmpb = ((u64)cpuvcp->power_quads[1]) * ((u64)power); + *value = (tmpa >> 28) + (tmpb >> 28) + (cpuvcp->power_quads[2] >> 12); + + return 0; +} + +static struct wf_sensor_ops smu_cpu_power_ops = { + .get_value = smu_cpu_power_get, + .release = smu_cpu_power_release, + .owner = THIS_MODULE, +}; + + +static struct smu_cpu_power_sensor * +smu_cpu_power_create(struct wf_sensor *volts, struct wf_sensor *amps) +{ + struct smu_cpu_power_sensor *pow; + + pow = kmalloc(sizeof(struct smu_cpu_power_sensor), GFP_KERNEL); + if (pow == NULL) + return NULL; + pow->sens.ops = &smu_cpu_power_ops; + pow->sens.name = "cpu-power"; + + wf_get_sensor(volts); + pow->volts = volts; + wf_get_sensor(amps); + pow->amps = amps; + + /* Some early machines need a faked voltage */ + if (debugswitches && ((*debugswitches) & 0x80)) { + printk(KERN_INFO "windfarm: CPU Power sensor using faked" + " voltage !\n"); + pow->fake_volts = 1; + } else + pow->fake_volts = 0; + + /* Try to use quadratic transforms on PowerMac8,1 and 9,1 for now, + * I yet have to figure out what's up with 8,2 and will have to + * adjust for later, unless we can 100% trust the SDB partition... + */ + if ((machine_is_compatible("PowerMac8,1") || + machine_is_compatible("PowerMac8,2") || + machine_is_compatible("PowerMac9,1")) && + cpuvcp_version >= 2) { + pow->quadratic = 1; + DBG("windfarm: CPU Power using quadratic transform\n"); + } else + pow->quadratic = 0; + + if (wf_register_sensor(&pow->sens)) + goto fail; + return pow; + fail: + kfree(pow); + return NULL; +} + +static int smu_fetch_param_partitions(void) +{ + struct smu_sdbp_header *hdr; + + /* Get CPU voltage/current/power calibration data */ + hdr = smu_get_sdb_partition(SMU_SDB_CPUVCP_ID, NULL); + if (hdr == NULL) { + DBG("wf: cpuvcp partition (%02x) not found\n", + SMU_SDB_CPUVCP_ID); + return -ENODEV; + } + cpuvcp = (struct smu_sdbp_cpuvcp *)&hdr[1]; + /* Keep version around */ + cpuvcp_version = hdr->version; + + /* Get CPU diode calibration data */ + hdr = smu_get_sdb_partition(SMU_SDB_CPUDIODE_ID, NULL); + if (hdr == NULL) { + DBG("wf: cpudiode partition (%02x) not found\n", + SMU_SDB_CPUDIODE_ID); + return -ENODEV; + } + cpudiode = (struct smu_sdbp_cpudiode *)&hdr[1]; + + /* Get slots power calibration data if any */ + hdr = smu_get_sdb_partition(SMU_SDB_SLOTSPOW_ID, NULL); + if (hdr != NULL) + slotspow = (struct smu_sdbp_slotspow *)&hdr[1]; + + /* Get debug switches if any */ + hdr = smu_get_sdb_partition(SMU_SDB_DEBUG_SWITCHES_ID, NULL); + if (hdr != NULL) + debugswitches = (u8 *)&hdr[1]; + + return 0; +} + +static int __init smu_sensors_init(void) +{ + struct device_node *smu, *sensors, *s; + struct smu_ad_sensor *volt_sensor = NULL, *curr_sensor = NULL; + int rc; + + if (!smu_present()) + return -ENODEV; + + /* Get parameters partitions */ + rc = smu_fetch_param_partitions(); + if (rc) + return rc; + + smu = of_find_node_by_type(NULL, "smu"); + if (smu == NULL) + return -ENODEV; + + /* Look for sensors subdir */ + for (sensors = NULL; + (sensors = of_get_next_child(smu, sensors)) != NULL;) + if (!strcmp(sensors->name, "sensors")) + break; + + of_node_put(smu); + + /* Create basic sensors */ + for (s = NULL; + sensors && (s = of_get_next_child(sensors, s)) != NULL;) { + struct smu_ad_sensor *ads; + + ads = smu_ads_create(s); + if (ads == NULL) + continue; + list_add(&ads->link, &smu_ads); + /* keep track of cpu voltage & current */ + if (!strcmp(ads->sens.name, "cpu-voltage")) + volt_sensor = ads; + else if (!strcmp(ads->sens.name, "cpu-current")) + curr_sensor = ads; + } + + of_node_put(sensors); + + /* Create CPU power sensor if possible */ + if (volt_sensor && curr_sensor) + smu_cpu_power = smu_cpu_power_create(&volt_sensor->sens, + &curr_sensor->sens); + + return 0; +} + +static void __exit smu_sensors_exit(void) +{ + struct smu_ad_sensor *ads; + + /* dispose of power sensor */ + if (smu_cpu_power) + wf_unregister_sensor(&smu_cpu_power->sens); + + /* dispose of basic sensors */ + while (!list_empty(&smu_ads)) { + ads = list_entry(smu_ads.next, struct smu_ad_sensor, link); + list_del(&ads->link); + wf_unregister_sensor(&ads->sens); + } +} + + +module_init(smu_sensors_init); +module_exit(smu_sensors_exit); + +MODULE_AUTHOR("Benjamin Herrenschmidt "); +MODULE_DESCRIPTION("SMU sensor objects for PowerMacs thermal control"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 6497295ebfb93150d1cf4087bfca7b60c3e2bf63..1223e98ecd70f538419790c48bfe19f664561480 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1587,8 +1587,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i /* make sure we don't swamp the stripe cache if someone else * is trying to get access */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 0); spin_lock(&sh->lock); diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c index 6437a95ffc1cd573da840c4a0c29674973a14efb..7757869477019ea5a87a186b6b46ced5fcb1fcd7 100644 --- a/drivers/md/raid6main.c +++ b/drivers/md/raid6main.c @@ -1746,8 +1746,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i /* make sure we don't swamp the stripe cache if someone else * is trying to get access */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 0); spin_lock(&sh->lock); diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 34a837a1abf4f1d5beeef0dd0dec301eba984d87..b3c9d7327ac1d4228a2eecc810bf6e98df75d172 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -1331,9 +1331,7 @@ struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_ad { /* check if the ASIC is there */ if (dst_probe(state) < 0) { - if (state) - kfree(state); - + kfree(state); return NULL; } /* determine settings based on type */ @@ -1349,9 +1347,7 @@ struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_ad break; default: dprintk(verbose, DST_ERROR, 1, "unknown DST type. please report to the LinuxTV.org DVB mailinglist."); - if (state) - kfree(state); - + kfree(state); return NULL; } diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c index d4b97989e3ed058b93fc926206e110906eb14a7e..654d7dc879d9fbb7e7d7fd9acdf43620215270e4 100644 --- a/drivers/media/dvb/frontends/cx24110.c +++ b/drivers/media/dvb/frontends/cx24110.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "dvb_frontend.h" #include "cx24110.h" diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c index 794be520d5902fdad363d1a44486a76d9f5ecafc..645946a992d94b1dda65bf33e14561238ee6329f 100644 --- a/drivers/media/dvb/frontends/dvb_dummy_fe.c +++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c @@ -148,7 +148,7 @@ struct dvb_frontend* dvb_dummy_fe_qpsk_attach() return &state->frontend; error: - if (state) kfree(state); + kfree(state); return NULL; } @@ -171,7 +171,7 @@ struct dvb_frontend* dvb_dummy_fe_qam_attach() return &state->frontend; error: - if (state) kfree(state); + kfree(state); return NULL; } diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c index faaad1ae85594bbfa4a205c3638baa0c6399e12d..19b4bf7c21a752eed6fa9c390ba803826bb1e59c 100644 --- a/drivers/media/dvb/frontends/l64781.c +++ b/drivers/media/dvb/frontends/l64781.c @@ -559,7 +559,8 @@ struct dvb_frontend* l64781_attach(const struct l64781_config* config, return &state->frontend; error: - if (reg0x3e >= 0) l64781_writereg (state, 0x3e, reg0x3e); /* restore reg 0x3e */ + if (reg0x3e >= 0) + l64781_writereg (state, 0x3e, reg0x3e); /* restore reg 0x3e */ kfree(state); return NULL; } diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index 8dde72bd10461fb5997cf13e6748e73bfee43535..7852b83b82d44737413cd013ff657b8afc0cfc7c 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c @@ -731,8 +731,7 @@ struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, return &state->frontend; error: - if (state) - kfree(state); + kfree(state); dprintk("%s: ERROR\n",__FUNCTION__); return NULL; } diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c index e38454901dd12e31d281a9e2ec9d1210534ae43d..9c67f406d581a7d9a7fe7d964bd1786492ad8c9d 100644 --- a/drivers/media/dvb/frontends/mt312.c +++ b/drivers/media/dvb/frontends/mt312.c @@ -677,8 +677,7 @@ struct dvb_frontend* mt312_attach(const struct mt312_config* config, return &state->frontend; error: - if (state) - kfree(state); + kfree(state); return NULL; } diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c index 817b044c7fd1dd992898b6d680d62426d572729f..fc74c40d64777a500ae7748fde5e06bfdb11a7bd 100644 --- a/drivers/media/dvb/frontends/or51132.c +++ b/drivers/media/dvb/frontends/or51132.c @@ -577,8 +577,7 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config, return &state->frontend; error: - if (state) - kfree(state); + kfree(state); return NULL; } diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c index 87fd3a7bb392cfc9a4bb7b9fc0a01cc79c677f8c..0823ddaf70049a0daa625196da95b80662f49fe0 100644 --- a/drivers/media/video/arv.c +++ b/drivers/media/video/arv.c @@ -865,10 +865,8 @@ static int __init ar_init(void) out_irq: #endif - for (i = 0; i < MAX_AR_HEIGHT; i++) { - if (ar->frame[i]) - kfree(ar->frame[i]); - } + for (i = 0; i < MAX_AR_HEIGHT; i++) + kfree(ar->frame[i]); out_line_buff: #if USE_INT @@ -899,10 +897,8 @@ static void __exit ar_cleanup_module(void) #if USE_INT free_irq(M32R_IRQ_INT3, ar); #endif - for (i = 0; i < MAX_AR_HEIGHT; i++) { - if (ar->frame[i]) - kfree(ar->frame[i]); - } + for (i = 0; i < MAX_AR_HEIGHT; i++) + kfree(ar->frame[i]); #if USE_INT kfree(ar->line_buff); #endif diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index c062a017491e4bb08bf8c853d265b349ed464c59..d538a994ff04da1d68bcfe9ddc5023671c53d1a8 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -1951,8 +1951,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv, } down(&fh->cap.lock); - if (fh->ov.clips) - kfree(fh->ov.clips); + kfree(fh->ov.clips); fh->ov.clips = clips; fh->ov.nclips = n; @@ -2723,8 +2722,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, fh->ov.w.height = fb->fmt.height; btv->init.ov.w.width = fb->fmt.width; btv->init.ov.w.height = fb->fmt.height; - if (fh->ov.clips) - kfree(fh->ov.clips); + kfree(fh->ov.clips); fh->ov.clips = NULL; fh->ov.nclips = 0; diff --git a/drivers/media/video/indycam.c b/drivers/media/video/indycam.c index 26dd06ec89a2b6aa2b96e2b794cc7bd2e5ae5ac3..deeef125eb92eca9499fac5f06a7b72f7108a8fc 100644 --- a/drivers/media/video/indycam.c +++ b/drivers/media/video/indycam.c @@ -27,15 +27,15 @@ #include "indycam.h" -//#define INDYCAM_DEBUG - -#define INDYCAM_MODULE_VERSION "0.0.3" +#define INDYCAM_MODULE_VERSION "0.0.5" MODULE_DESCRIPTION("SGI IndyCam driver"); MODULE_VERSION(INDYCAM_MODULE_VERSION); MODULE_AUTHOR("Mikael Nousiainen "); MODULE_LICENSE("GPL"); +// #define INDYCAM_DEBUG + #ifdef INDYCAM_DEBUG #define dprintk(x...) printk("IndyCam: " x); #define indycam_regdump(client) indycam_regdump_debug(client) @@ -46,14 +46,14 @@ MODULE_LICENSE("GPL"); struct indycam { struct i2c_client *client; - int version; + u8 version; }; static struct i2c_driver i2c_driver_indycam; -static const unsigned char initseq[] = { +static const u8 initseq[] = { INDYCAM_CONTROL_AGCENA, /* INDYCAM_CONTROL */ - INDYCAM_SHUTTER_DEFAULT, /* INDYCAM_SHUTTER */ + INDYCAM_SHUTTER_60, /* INDYCAM_SHUTTER */ INDYCAM_GAIN_DEFAULT, /* INDYCAM_GAIN */ 0x00, /* INDYCAM_BRIGHTNESS (read-only) */ INDYCAM_RED_BALANCE_DEFAULT, /* INDYCAM_RED_BALANCE */ @@ -64,12 +64,11 @@ static const unsigned char initseq[] = { /* IndyCam register handling */ -static int indycam_read_reg(struct i2c_client *client, unsigned char reg, - unsigned char *value) +static int indycam_read_reg(struct i2c_client *client, u8 reg, u8 *value) { int ret; - if (reg == INDYCAM_RESET) { + if (reg == INDYCAM_REG_RESET) { dprintk("indycam_read_reg(): " "skipping write-only register %d\n", reg); *value = 0; @@ -77,24 +76,24 @@ static int indycam_read_reg(struct i2c_client *client, unsigned char reg, } ret = i2c_smbus_read_byte_data(client, reg); + if (ret < 0) { printk(KERN_ERR "IndyCam: indycam_read_reg(): read failed, " "register = 0x%02x\n", reg); return ret; } - *value = (unsigned char)ret; + *value = (u8)ret; return 0; } -static int indycam_write_reg(struct i2c_client *client, unsigned char reg, - unsigned char value) +static int indycam_write_reg(struct i2c_client *client, u8 reg, u8 value) { int err; - if ((reg == INDYCAM_BRIGHTNESS) - || (reg == INDYCAM_VERSION)) { + if ((reg == INDYCAM_REG_BRIGHTNESS) + || (reg == INDYCAM_REG_VERSION)) { dprintk("indycam_write_reg(): " "skipping read-only register %d\n", reg); return 0; @@ -102,6 +101,7 @@ static int indycam_write_reg(struct i2c_client *client, unsigned char reg, dprintk("Writing Reg %d = 0x%02x\n", reg, value); err = i2c_smbus_write_byte_data(client, reg, value); + if (err) { printk(KERN_ERR "IndyCam: indycam_write_reg(): write failed, " "register = 0x%02x, value = 0x%02x\n", reg, value); @@ -109,13 +109,12 @@ static int indycam_write_reg(struct i2c_client *client, unsigned char reg, return err; } -static int indycam_write_block(struct i2c_client *client, unsigned char reg, - unsigned char length, unsigned char *data) +static int indycam_write_block(struct i2c_client *client, u8 reg, + u8 length, u8 *data) { - unsigned char i; - int err; + int i, err; - for (i = reg; i < length; i++) { + for (i = 0; i < length; i++) { err = indycam_write_reg(client, reg + i, data[i]); if (err) return err; @@ -130,7 +129,7 @@ static int indycam_write_block(struct i2c_client *client, unsigned char reg, static void indycam_regdump_debug(struct i2c_client *client) { int i; - unsigned char val; + u8 val; for (i = 0; i < 9; i++) { indycam_read_reg(client, i, &val); @@ -139,76 +138,144 @@ static void indycam_regdump_debug(struct i2c_client *client) } #endif -static int indycam_get_controls(struct i2c_client *client, - struct indycam_control *ctrl) +static int indycam_get_control(struct i2c_client *client, + struct indycam_control *ctrl) { - unsigned char ctrl_reg; - - indycam_read_reg(client, INDYCAM_CONTROL, &ctrl_reg); - ctrl->agc = (ctrl_reg & INDYCAM_CONTROL_AGCENA) - ? INDYCAM_VALUE_ENABLED - : INDYCAM_VALUE_DISABLED; - ctrl->awb = (ctrl_reg & INDYCAM_CONTROL_AWBCTL) - ? INDYCAM_VALUE_ENABLED - : INDYCAM_VALUE_DISABLED; - indycam_read_reg(client, INDYCAM_SHUTTER, - (unsigned char *)&ctrl->shutter); - indycam_read_reg(client, INDYCAM_GAIN, - (unsigned char *)&ctrl->gain); - indycam_read_reg(client, INDYCAM_RED_BALANCE, - (unsigned char *)&ctrl->red_balance); - indycam_read_reg(client, INDYCAM_BLUE_BALANCE, - (unsigned char *)&ctrl->blue_balance); - indycam_read_reg(client, INDYCAM_RED_SATURATION, - (unsigned char *)&ctrl->red_saturation); - indycam_read_reg(client, INDYCAM_BLUE_SATURATION, - (unsigned char *)&ctrl->blue_saturation); - indycam_read_reg(client, INDYCAM_GAMMA, - (unsigned char *)&ctrl->gamma); + struct indycam *camera = i2c_get_clientdata(client); + u8 reg; + int ret = 0; + + switch (ctrl->type) { + case INDYCAM_CONTROL_AGC: + case INDYCAM_CONTROL_AWB: + ret = indycam_read_reg(client, INDYCAM_REG_CONTROL, ®); + if (ret) + return -EIO; + if (ctrl->type == INDYCAM_CONTROL_AGC) + ctrl->value = (reg & INDYCAM_CONTROL_AGCENA) + ? 1 : 0; + else + ctrl->value = (reg & INDYCAM_CONTROL_AWBCTL) + ? 1 : 0; + break; + case INDYCAM_CONTROL_SHUTTER: + ret = indycam_read_reg(client, INDYCAM_REG_SHUTTER, ®); + if (ret) + return -EIO; + ctrl->value = ((s32)reg == 0x00) ? 0xff : ((s32)reg - 1); + break; + case INDYCAM_CONTROL_GAIN: + ret = indycam_read_reg(client, INDYCAM_REG_GAIN, ®); + if (ret) + return -EIO; + ctrl->value = (s32)reg; + break; + case INDYCAM_CONTROL_RED_BALANCE: + ret = indycam_read_reg(client, INDYCAM_REG_RED_BALANCE, ®); + if (ret) + return -EIO; + ctrl->value = (s32)reg; + break; + case INDYCAM_CONTROL_BLUE_BALANCE: + ret = indycam_read_reg(client, INDYCAM_REG_BLUE_BALANCE, ®); + if (ret) + return -EIO; + ctrl->value = (s32)reg; + break; + case INDYCAM_CONTROL_RED_SATURATION: + ret = indycam_read_reg(client, + INDYCAM_REG_RED_SATURATION, ®); + if (ret) + return -EIO; + ctrl->value = (s32)reg; + break; + case INDYCAM_CONTROL_BLUE_SATURATION: + ret = indycam_read_reg(client, + INDYCAM_REG_BLUE_SATURATION, ®); + if (ret) + return -EIO; + ctrl->value = (s32)reg; + break; + case INDYCAM_CONTROL_GAMMA: + if (camera->version == CAMERA_VERSION_MOOSE) { + ret = indycam_read_reg(client, + INDYCAM_REG_GAMMA, ®); + if (ret) + return -EIO; + ctrl->value = (s32)reg; + } else { + ctrl->value = INDYCAM_GAMMA_DEFAULT; + } + break; + default: + ret = -EINVAL; + } - return 0; + return ret; } -static int indycam_set_controls(struct i2c_client *client, - struct indycam_control *ctrl) +static int indycam_set_control(struct i2c_client *client, + struct indycam_control *ctrl) { - unsigned char ctrl_reg; + struct indycam *camera = i2c_get_clientdata(client); + u8 reg; + int ret = 0; + + switch (ctrl->type) { + case INDYCAM_CONTROL_AGC: + case INDYCAM_CONTROL_AWB: + ret = indycam_read_reg(client, INDYCAM_REG_CONTROL, ®); + if (ret) + break; - indycam_read_reg(client, INDYCAM_CONTROL, &ctrl_reg); - if (ctrl->agc != INDYCAM_VALUE_UNCHANGED) { - if (ctrl->agc) - ctrl_reg |= INDYCAM_CONTROL_AGCENA; - else - ctrl_reg &= ~INDYCAM_CONTROL_AGCENA; - } - if (ctrl->awb != INDYCAM_VALUE_UNCHANGED) { - if (ctrl->awb) - ctrl_reg |= INDYCAM_CONTROL_AWBCTL; - else - ctrl_reg &= ~INDYCAM_CONTROL_AWBCTL; + if (ctrl->type == INDYCAM_CONTROL_AGC) { + if (ctrl->value) + reg |= INDYCAM_CONTROL_AGCENA; + else + reg &= ~INDYCAM_CONTROL_AGCENA; + } else { + if (ctrl->value) + reg |= INDYCAM_CONTROL_AWBCTL; + else + reg &= ~INDYCAM_CONTROL_AWBCTL; + } + + ret = indycam_write_reg(client, INDYCAM_REG_CONTROL, reg); + break; + case INDYCAM_CONTROL_SHUTTER: + reg = (ctrl->value == 0xff) ? 0x00 : (ctrl->value + 1); + ret = indycam_write_reg(client, INDYCAM_REG_SHUTTER, reg); + break; + case INDYCAM_CONTROL_GAIN: + ret = indycam_write_reg(client, INDYCAM_REG_GAIN, ctrl->value); + break; + case INDYCAM_CONTROL_RED_BALANCE: + ret = indycam_write_reg(client, INDYCAM_REG_RED_BALANCE, + ctrl->value); + break; + case INDYCAM_CONTROL_BLUE_BALANCE: + ret = indycam_write_reg(client, INDYCAM_REG_BLUE_BALANCE, + ctrl->value); + break; + case INDYCAM_CONTROL_RED_SATURATION: + ret = indycam_write_reg(client, INDYCAM_REG_RED_SATURATION, + ctrl->value); + break; + case INDYCAM_CONTROL_BLUE_SATURATION: + ret = indycam_write_reg(client, INDYCAM_REG_BLUE_SATURATION, + ctrl->value); + break; + case INDYCAM_CONTROL_GAMMA: + if (camera->version == CAMERA_VERSION_MOOSE) { + ret = indycam_write_reg(client, INDYCAM_REG_GAMMA, + ctrl->value); + } + break; + default: + ret = -EINVAL; } - indycam_write_reg(client, INDYCAM_CONTROL, ctrl_reg); - - if (ctrl->shutter >= 0) - indycam_write_reg(client, INDYCAM_SHUTTER, ctrl->shutter); - if (ctrl->gain >= 0) - indycam_write_reg(client, INDYCAM_GAIN, ctrl->gain); - if (ctrl->red_balance >= 0) - indycam_write_reg(client, INDYCAM_RED_BALANCE, - ctrl->red_balance); - if (ctrl->blue_balance >= 0) - indycam_write_reg(client, INDYCAM_BLUE_BALANCE, - ctrl->blue_balance); - if (ctrl->red_saturation >= 0) - indycam_write_reg(client, INDYCAM_RED_SATURATION, - ctrl->red_saturation); - if (ctrl->blue_saturation >= 0) - indycam_write_reg(client, INDYCAM_BLUE_SATURATION, - ctrl->blue_saturation); - if (ctrl->gamma >= 0) - indycam_write_reg(client, INDYCAM_GAMMA, ctrl->gamma); - return 0; + return ret; } /* I2C-interface */ @@ -247,7 +314,8 @@ static int indycam_attach(struct i2c_adapter *adap, int addr, int kind) if (err) goto out_free_camera; - camera->version = i2c_smbus_read_byte_data(client, INDYCAM_VERSION); + camera->version = i2c_smbus_read_byte_data(client, + INDYCAM_REG_VERSION); if (camera->version != CAMERA_VERSION_INDY && camera->version != CAMERA_VERSION_MOOSE) { err = -ENODEV; @@ -260,8 +328,7 @@ static int indycam_attach(struct i2c_adapter *adap, int addr, int kind) indycam_regdump(client); // initialize - err = indycam_write_block(client, 0, sizeof(initseq), - (unsigned char *)&initseq); + err = indycam_write_block(client, 0, sizeof(initseq), (u8 *)&initseq); if (err) { printk(KERN_ERR "IndyCam initalization failed\n"); err = -EIO; @@ -271,11 +338,10 @@ static int indycam_attach(struct i2c_adapter *adap, int addr, int kind) indycam_regdump(client); // white balance - err = indycam_write_reg(client, INDYCAM_CONTROL, + err = indycam_write_reg(client, INDYCAM_REG_CONTROL, INDYCAM_CONTROL_AGCENA | INDYCAM_CONTROL_AWBCTL); if (err) { - printk(KERN_ERR "IndyCam white balance " - "initialization failed\n"); + printk(KERN_ERR "IndyCam: White balancing camera failed\n"); err = -EIO; goto out_detach_client; } @@ -371,13 +437,11 @@ static int indycam_command(struct i2c_client *client, unsigned int cmd, /* TODO: convert values for indycam_set_controls() */ break; } - case DECODER_INDYCAM_GET_CONTROLS: { - struct indycam_control *ctrl = arg; - indycam_get_controls(client, ctrl); + case DECODER_INDYCAM_GET_CONTROL: { + return indycam_get_control(client, arg); } - case DECODER_INDYCAM_SET_CONTROLS: { - struct indycam_control *ctrl = arg; - indycam_set_controls(client, ctrl); + case DECODER_INDYCAM_SET_CONTROL: { + return indycam_set_control(client, arg); } default: return -EINVAL; @@ -388,12 +452,12 @@ static int indycam_command(struct i2c_client *client, unsigned int cmd, static struct i2c_driver i2c_driver_indycam = { .owner = THIS_MODULE, - .name = "indycam", - .id = I2C_DRIVERID_INDYCAM, - .flags = I2C_DF_NOTIFY, + .name = "indycam", + .id = I2C_DRIVERID_INDYCAM, + .flags = I2C_DF_NOTIFY, .attach_adapter = indycam_probe, - .detach_client = indycam_detach, - .command = indycam_command, + .detach_client = indycam_detach, + .command = indycam_command, }; static int __init indycam_init(void) diff --git a/drivers/media/video/indycam.h b/drivers/media/video/indycam.h index d9ddb6b79a03a0befd72af937718a19f0b6c0ce1..e6ee82063ed89214c58bc0e801cc318ad743fa6e 100644 --- a/drivers/media/video/indycam.h +++ b/drivers/media/video/indycam.h @@ -22,21 +22,21 @@ #define INDYCAM_VERSION_MINOR(x) ((x) & 0x0f) /* Register bus addresses */ -#define INDYCAM_CONTROL 0x00 -#define INDYCAM_SHUTTER 0x01 -#define INDYCAM_GAIN 0x02 -#define INDYCAM_BRIGHTNESS 0x03 /* read-only */ -#define INDYCAM_RED_BALANCE 0x04 -#define INDYCAM_BLUE_BALANCE 0x05 -#define INDYCAM_RED_SATURATION 0x06 -#define INDYCAM_BLUE_SATURATION 0x07 -#define INDYCAM_GAMMA 0x08 -#define INDYCAM_VERSION 0x0e /* read-only */ -#define INDYCAM_RESET 0x0f /* write-only */ - -#define INDYCAM_LED 0x46 -#define INDYCAM_ORIENTATION 0x47 -#define INDYCAM_BUTTON 0x48 +#define INDYCAM_REG_CONTROL 0x00 +#define INDYCAM_REG_SHUTTER 0x01 +#define INDYCAM_REG_GAIN 0x02 +#define INDYCAM_REG_BRIGHTNESS 0x03 /* read-only */ +#define INDYCAM_REG_RED_BALANCE 0x04 +#define INDYCAM_REG_BLUE_BALANCE 0x05 +#define INDYCAM_REG_RED_SATURATION 0x06 +#define INDYCAM_REG_BLUE_SATURATION 0x07 +#define INDYCAM_REG_GAMMA 0x08 +#define INDYCAM_REG_VERSION 0x0e /* read-only */ +#define INDYCAM_REG_RESET 0x0f /* write-only */ + +#define INDYCAM_REG_LED 0x46 +#define INDYCAM_REG_ORIENTATION 0x47 +#define INDYCAM_REG_BUTTON 0x48 /* Field definitions of registers */ #define INDYCAM_CONTROL_AGCENA (1<<0) /* automatic gain control */ @@ -59,13 +59,14 @@ #define INDYCAM_ORIENTATION_BOTTOM_TO_TOP 0x40 #define INDYCAM_BUTTON_RELEASED 0x10 +/* Values for controls */ #define INDYCAM_SHUTTER_MIN 0x00 #define INDYCAM_SHUTTER_MAX 0xff #define INDYCAM_GAIN_MIN 0x00 #define INDYCAM_GAIN_MAX 0xff -#define INDYCAM_RED_BALANCE_MIN 0x00 /* the effect is the opposite? */ -#define INDYCAM_RED_BALANCE_MAX 0xff -#define INDYCAM_BLUE_BALANCE_MIN 0x00 /* the effect is the opposite? */ +#define INDYCAM_RED_BALANCE_MIN 0x00 +#define INDYCAM_RED_BALANCE_MAX 0xff +#define INDYCAM_BLUE_BALANCE_MIN 0x00 #define INDYCAM_BLUE_BALANCE_MAX 0xff #define INDYCAM_RED_SATURATION_MIN 0x00 #define INDYCAM_RED_SATURATION_MAX 0xff @@ -74,34 +75,9 @@ #define INDYCAM_GAMMA_MIN 0x00 #define INDYCAM_GAMMA_MAX 0xff -/* Driver interface definitions */ - -#define INDYCAM_VALUE_ENABLED 1 -#define INDYCAM_VALUE_DISABLED 0 -#define INDYCAM_VALUE_UNCHANGED -1 - -/* When setting controls, a value of -1 leaves the control unchanged. */ -struct indycam_control { - int agc; /* boolean */ - int awb; /* boolean */ - int shutter; - int gain; - int red_balance; - int blue_balance; - int red_saturation; - int blue_saturation; - int gamma; -}; - -#define DECODER_INDYCAM_GET_CONTROLS _IOR('d', 193, struct indycam_control) -#define DECODER_INDYCAM_SET_CONTROLS _IOW('d', 194, struct indycam_control) - -/* Default values for controls */ - -#define INDYCAM_AGC_DEFAULT INDYCAM_VALUE_ENABLED -#define INDYCAM_AWB_DEFAULT INDYCAM_VALUE_ENABLED - -#define INDYCAM_SHUTTER_DEFAULT INDYCAM_SHUTTER_60 +#define INDYCAM_AGC_DEFAULT 1 +#define INDYCAM_AWB_DEFAULT 0 +#define INDYCAM_SHUTTER_DEFAULT 0xff #define INDYCAM_GAIN_DEFAULT 0x80 #define INDYCAM_RED_BALANCE_DEFAULT 0x18 #define INDYCAM_BLUE_BALANCE_DEFAULT 0xa4 @@ -109,4 +85,24 @@ struct indycam_control { #define INDYCAM_BLUE_SATURATION_DEFAULT 0xc0 #define INDYCAM_GAMMA_DEFAULT 0x80 +/* Driver interface definitions */ + +#define INDYCAM_CONTROL_AGC 0 /* boolean */ +#define INDYCAM_CONTROL_AWB 1 /* boolean */ +#define INDYCAM_CONTROL_SHUTTER 2 +#define INDYCAM_CONTROL_GAIN 3 +#define INDYCAM_CONTROL_RED_BALANCE 4 +#define INDYCAM_CONTROL_BLUE_BALANCE 5 +#define INDYCAM_CONTROL_RED_SATURATION 6 +#define INDYCAM_CONTROL_BLUE_SATURATION 7 +#define INDYCAM_CONTROL_GAMMA 8 + +struct indycam_control { + u8 type; + s32 value; +}; + +#define DECODER_INDYCAM_GET_CONTROL _IOR('d', 193, struct indycam_control) +#define DECODER_INDYCAM_SET_CONTROL _IOW('d', 194, struct indycam_control) + #endif diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c index 262890cb20a7daf55de5d25d6840db40a6eb9dc3..e75e7948fd9d84b32ea51642beadf9c676f6b113 100644 --- a/drivers/media/video/msp3400.c +++ b/drivers/media/video/msp3400.c @@ -741,8 +741,8 @@ static int msp34xx_sleep(struct msp3400c *msp, int timeout) set_current_state(TASK_INTERRUPTIBLE); schedule(); } else { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(msecs_to_jiffies(timeout)); + schedule_timeout_interruptible + (msecs_to_jiffies(timeout)); } } diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index badf2f9e3072bf8befeaba2278551ee463903e60..61a2d6b50eef29ad67948a5a04a324fcde367554 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -342,8 +342,8 @@ static int tvaudio_sleep(struct saa7134_dev *dev, int timeout) set_current_state(TASK_INTERRUPTIBLE); schedule(); } else { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(msecs_to_jiffies(timeout)); + schedule_timeout_interruptible + (msecs_to_jiffies(timeout)); } } remove_wait_queue(&dev->thread.wq, &wait); diff --git a/drivers/media/video/saa7191.c b/drivers/media/video/saa7191.c index 3ddbb62312be84acbc3a77b601159c8dfe8925a2..cbca896e8cfaa81dfcfaaa39fa665527a040b8ba 100644 --- a/drivers/media/video/saa7191.c +++ b/drivers/media/video/saa7191.c @@ -26,71 +26,95 @@ #include "saa7191.h" -#define SAA7191_MODULE_VERSION "0.0.3" +#define SAA7191_MODULE_VERSION "0.0.5" MODULE_DESCRIPTION("Philips SAA7191 video decoder driver"); MODULE_VERSION(SAA7191_MODULE_VERSION); MODULE_AUTHOR("Mikael Nousiainen "); MODULE_LICENSE("GPL"); +// #define SAA7191_DEBUG + +#ifdef SAA7191_DEBUG +#define dprintk(x...) printk("SAA7191: " x); +#else +#define dprintk(x...) +#endif + +#define SAA7191_SYNC_COUNT 30 +#define SAA7191_SYNC_DELAY 100 /* milliseconds */ + struct saa7191 { struct i2c_client *client; /* the register values are stored here as the actual * I2C-registers are write-only */ - unsigned char reg[25]; + u8 reg[25]; - unsigned char norm; - unsigned char input; + int input; + int norm; }; static struct i2c_driver i2c_driver_saa7191; -static const unsigned char initseq[] = { +static const u8 initseq[] = { 0, /* Subaddress */ - 0x50, /* SAA7191_REG_IDEL */ - 0x30, /* SAA7191_REG_HSYB */ - 0x00, /* SAA7191_REG_HSYS */ - 0xe8, /* SAA7191_REG_HCLB */ - 0xb6, /* SAA7191_REG_HCLS */ - 0xf4, /* SAA7191_REG_HPHI */ - 0x01, /* SAA7191_REG_LUMA - chrominance trap active (CVBS) */ - 0x00, /* SAA7191_REG_HUEC */ - 0xf8, /* SAA7191_REG_CKTQ */ - 0xf8, /* SAA7191_REG_CKTS */ - 0x90, /* SAA7191_REG_PLSE */ - 0x90, /* SAA7191_REG_SESE */ - 0x00, /* SAA7191_REG_GAIN */ - 0x0c, /* SAA7191_REG_STDC - not SECAM, slow time constant */ - 0x78, /* SAA7191_REG_IOCK - chrominance from CVBS, GPSW1 & 2 off */ - 0x99, /* SAA7191_REG_CTL3 - automatic field detection */ - 0x00, /* SAA7191_REG_CTL4 */ - 0x2c, /* SAA7191_REG_CHCV */ + + 0x50, /* (0x50) SAA7191_REG_IDEL */ + + /* 50 Hz signal timing */ + 0x30, /* (0x30) SAA7191_REG_HSYB */ + 0x00, /* (0x00) SAA7191_REG_HSYS */ + 0xe8, /* (0xe8) SAA7191_REG_HCLB */ + 0xb6, /* (0xb6) SAA7191_REG_HCLS */ + 0xf4, /* (0xf4) SAA7191_REG_HPHI */ + + /* control */ + SAA7191_LUMA_APER_1, /* (0x01) SAA7191_REG_LUMA - CVBS mode */ + 0x00, /* (0x00) SAA7191_REG_HUEC */ + 0xf8, /* (0xf8) SAA7191_REG_CKTQ */ + 0xf8, /* (0xf8) SAA7191_REG_CKTS */ + 0x90, /* (0x90) SAA7191_REG_PLSE */ + 0x90, /* (0x90) SAA7191_REG_SESE */ + 0x00, /* (0x00) SAA7191_REG_GAIN */ + SAA7191_STDC_NFEN | SAA7191_STDC_HRMV, /* (0x0c) SAA7191_REG_STDC + * - not SECAM, + * slow time constant */ + SAA7191_IOCK_OEDC | SAA7191_IOCK_OEHS | SAA7191_IOCK_OEVS + | SAA7191_IOCK_OEDY, /* (0x78) SAA7191_REG_IOCK + * - chroma from CVBS, GPSW1 & 2 off */ + SAA7191_CTL3_AUFD | SAA7191_CTL3_SCEN | SAA7191_CTL3_OFTS + | SAA7191_CTL3_YDEL0, /* (0x99) SAA7191_REG_CTL3 + * - automatic field detection */ + 0x00, /* (0x00) SAA7191_REG_CTL4 */ + 0x2c, /* (0x2c) SAA7191_REG_CHCV - PAL nominal value */ 0x00, /* unused */ 0x00, /* unused */ - 0x34, /* SAA7191_REG_HS6B */ - 0x0a, /* SAA7191_REG_HS6S */ - 0xf4, /* SAA7191_REG_HC6B */ - 0xce, /* SAA7191_REG_HC6S */ - 0xf4, /* SAA7191_REG_HP6I */ + + /* 60 Hz signal timing */ + 0x34, /* (0x34) SAA7191_REG_HS6B */ + 0x0a, /* (0x0a) SAA7191_REG_HS6S */ + 0xf4, /* (0xf4) SAA7191_REG_HC6B */ + 0xce, /* (0xce) SAA7191_REG_HC6S */ + 0xf4, /* (0xf4) SAA7191_REG_HP6I */ }; /* SAA7191 register handling */ -static unsigned char saa7191_read_reg(struct i2c_client *client, - unsigned char reg) +static u8 saa7191_read_reg(struct i2c_client *client, + u8 reg) { return ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg]; } static int saa7191_read_status(struct i2c_client *client, - unsigned char *value) + u8 *value) { int ret; ret = i2c_master_recv(client, value, 1); if (ret < 0) { - printk(KERN_ERR "SAA7191: saa7191_read_status(): read failed"); + printk(KERN_ERR "SAA7191: saa7191_read_status(): read failed\n"); return ret; } @@ -98,17 +122,16 @@ static int saa7191_read_status(struct i2c_client *client, } -static int saa7191_write_reg(struct i2c_client *client, unsigned char reg, - unsigned char value) +static int saa7191_write_reg(struct i2c_client *client, u8 reg, + u8 value) { - ((struct saa7191 *)i2c_get_clientdata(client))->reg[reg] = value; return i2c_smbus_write_byte_data(client, reg, value); } /* the first byte of data must be the first subaddress number (register) */ static int saa7191_write_block(struct i2c_client *client, - unsigned char length, unsigned char *data) + u8 length, u8 *data) { int i; int ret; @@ -121,7 +144,7 @@ static int saa7191_write_block(struct i2c_client *client, ret = i2c_master_send(client, data, length); if (ret < 0) { printk(KERN_ERR "SAA7191: saa7191_write_block(): " - "write failed"); + "write failed\n"); return ret; } @@ -132,8 +155,9 @@ static int saa7191_write_block(struct i2c_client *client, static int saa7191_set_input(struct i2c_client *client, int input) { - unsigned char luma = saa7191_read_reg(client, SAA7191_REG_LUMA); - unsigned char iock = saa7191_read_reg(client, SAA7191_REG_IOCK); + struct saa7191 *decoder = i2c_get_clientdata(client); + u8 luma = saa7191_read_reg(client, SAA7191_REG_LUMA); + u8 iock = saa7191_read_reg(client, SAA7191_REG_IOCK); int err; switch (input) { @@ -159,32 +183,20 @@ static int saa7191_set_input(struct i2c_client *client, int input) if (err) return -EIO; + decoder->input = input; + return 0; } static int saa7191_set_norm(struct i2c_client *client, int norm) { struct saa7191 *decoder = i2c_get_clientdata(client); - unsigned char stdc = saa7191_read_reg(client, SAA7191_REG_STDC); - unsigned char ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3); - unsigned char chcv = saa7191_read_reg(client, SAA7191_REG_CHCV); + u8 stdc = saa7191_read_reg(client, SAA7191_REG_STDC); + u8 ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3); + u8 chcv = saa7191_read_reg(client, SAA7191_REG_CHCV); int err; switch(norm) { - case SAA7191_NORM_AUTO: { - unsigned char status; - - // does status depend on current norm ? - if (saa7191_read_status(client, &status)) - return -EIO; - - stdc &= ~SAA7191_STDC_SECS; - ctl3 &= ~SAA7191_CTL3_FSEL; - ctl3 |= SAA7191_CTL3_AUFD; - chcv = (status & SAA7191_STATUS_FIDT) - ? SAA7191_CHCV_NTSC : SAA7191_CHCV_PAL; - break; - } case SAA7191_NORM_PAL: stdc &= ~SAA7191_STDC_SECS; ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL); @@ -217,60 +229,335 @@ static int saa7191_set_norm(struct i2c_client *client, int norm) decoder->norm = norm; + dprintk("ctl3: %02x stdc: %02x chcv: %02x\n", ctl3, + stdc, chcv); + dprintk("norm: %d\n", norm); + return 0; } -static int saa7191_get_controls(struct i2c_client *client, - struct saa7191_control *ctrl) +static int saa7191_wait_for_signal(struct i2c_client *client, u8 *status) { - unsigned char hue = saa7191_read_reg(client, SAA7191_REG_HUEC); - unsigned char stdc = saa7191_read_reg(client, SAA7191_REG_STDC); + int i = 0; - if (hue < 0x80) { - hue += 0x80; - } else { - hue -= 0x80; + dprintk("Checking for signal...\n"); + + for (i = 0; i < SAA7191_SYNC_COUNT; i++) { + if (saa7191_read_status(client, status)) + return -EIO; + + if (((*status) & SAA7191_STATUS_HLCK) == 0) { + dprintk("Signal found\n"); + return 0; + } + + msleep(SAA7191_SYNC_DELAY); } - ctrl->hue = hue; - ctrl->vtrc = (stdc & SAA7191_STDC_VTRC) - ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED; + dprintk("No signal\n"); - return 0; + return -EBUSY; } -static int saa7191_set_controls(struct i2c_client *client, - struct saa7191_control *ctrl) +static int saa7191_autodetect_norm_extended(struct i2c_client *client) { - int err; + u8 stdc = saa7191_read_reg(client, SAA7191_REG_STDC); + u8 ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3); + u8 status; + int err = 0; - if (ctrl->hue >= 0) { - unsigned char hue = ctrl->hue & 0xff; - if (hue < 0x80) { - hue += 0x80; - } else { - hue -= 0x80; + dprintk("SAA7191 extended signal auto-detection...\n"); + + stdc &= ~SAA7191_STDC_SECS; + ctl3 &= ~(SAA7191_CTL3_FSEL); + + err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc); + if (err) { + err = -EIO; + goto out; + } + err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3); + if (err) { + err = -EIO; + goto out; + } + + ctl3 |= SAA7191_CTL3_AUFD; + err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3); + if (err) { + err = -EIO; + goto out; + } + + msleep(SAA7191_SYNC_DELAY); + + err = saa7191_wait_for_signal(client, &status); + if (err) + goto out; + + if (status & SAA7191_STATUS_FIDT) { + /* 60Hz signal -> NTSC */ + dprintk("60Hz signal: NTSC\n"); + return saa7191_set_norm(client, SAA7191_NORM_NTSC); + } + + /* 50Hz signal */ + dprintk("50Hz signal: Trying PAL...\n"); + + /* try PAL first */ + err = saa7191_set_norm(client, SAA7191_NORM_PAL); + if (err) + goto out; + + msleep(SAA7191_SYNC_DELAY); + + err = saa7191_wait_for_signal(client, &status); + if (err) + goto out; + + /* not 50Hz ? */ + if (status & SAA7191_STATUS_FIDT) { + dprintk("No 50Hz signal\n"); + err = -EAGAIN; + goto out; + } + + if (status & SAA7191_STATUS_CODE) { + dprintk("PAL\n"); + return 0; + } + + dprintk("No color detected with PAL - Trying SECAM...\n"); + + /* no color detected ? -> try SECAM */ + err = saa7191_set_norm(client, + SAA7191_NORM_SECAM); + if (err) + goto out; + + msleep(SAA7191_SYNC_DELAY); + + err = saa7191_wait_for_signal(client, &status); + if (err) + goto out; + + /* not 50Hz ? */ + if (status & SAA7191_STATUS_FIDT) { + dprintk("No 50Hz signal\n"); + err = -EAGAIN; + goto out; + } + + if (status & SAA7191_STATUS_CODE) { + /* Color detected -> SECAM */ + dprintk("SECAM\n"); + return 0; + } + + dprintk("No color detected with SECAM - Going back to PAL.\n"); + + /* still no color detected ? + * -> set norm back to PAL */ + err = saa7191_set_norm(client, + SAA7191_NORM_PAL); + if (err) + goto out; + +out: + ctl3 = saa7191_read_reg(client, SAA7191_REG_CTL3); + if (ctl3 & SAA7191_CTL3_AUFD) { + ctl3 &= ~(SAA7191_CTL3_AUFD); + err = saa7191_write_reg(client, SAA7191_REG_CTL3, ctl3); + if (err) { + err = -EIO; } - err = saa7191_write_reg(client, SAA7191_REG_HUEC, hue); - if (err) - return -EIO; } - if (ctrl->vtrc >= 0) { - unsigned char stdc = - saa7191_read_reg(client, SAA7191_REG_STDC); - if (ctrl->vtrc) { - stdc |= SAA7191_STDC_VTRC; - } else { - stdc &= ~SAA7191_STDC_VTRC; + return err; +} + +static int saa7191_autodetect_norm(struct i2c_client *client) +{ + u8 status; + + dprintk("SAA7191 signal auto-detection...\n"); + + dprintk("Reading status...\n"); + + if (saa7191_read_status(client, &status)) + return -EIO; + + dprintk("Checking for signal...\n"); + + /* no signal ? */ + if (status & SAA7191_STATUS_HLCK) { + dprintk("No signal\n"); + return -EBUSY; + } + + dprintk("Signal found\n"); + + if (status & SAA7191_STATUS_FIDT) { + /* 60hz signal -> NTSC */ + dprintk("NTSC\n"); + return saa7191_set_norm(client, SAA7191_NORM_NTSC); + } else { + /* 50hz signal -> PAL */ + dprintk("PAL\n"); + return saa7191_set_norm(client, SAA7191_NORM_PAL); + } +} + +static int saa7191_get_control(struct i2c_client *client, + struct saa7191_control *ctrl) +{ + u8 reg; + int ret = 0; + + switch (ctrl->type) { + case SAA7191_CONTROL_BANDPASS: + case SAA7191_CONTROL_BANDPASS_WEIGHT: + case SAA7191_CONTROL_CORING: + reg = saa7191_read_reg(client, SAA7191_REG_LUMA); + switch (ctrl->type) { + case SAA7191_CONTROL_BANDPASS: + ctrl->value = ((s32)reg & SAA7191_LUMA_BPSS_MASK) + >> SAA7191_LUMA_BPSS_SHIFT; + break; + case SAA7191_CONTROL_BANDPASS_WEIGHT: + ctrl->value = ((s32)reg & SAA7191_LUMA_APER_MASK) + >> SAA7191_LUMA_APER_SHIFT; + break; + case SAA7191_CONTROL_CORING: + ctrl->value = ((s32)reg & SAA7191_LUMA_CORI_MASK) + >> SAA7191_LUMA_CORI_SHIFT; + break; } + break; + case SAA7191_CONTROL_FORCE_COLOUR: + case SAA7191_CONTROL_CHROMA_GAIN: + reg = saa7191_read_reg(client, SAA7191_REG_GAIN); + if (ctrl->type == SAA7191_CONTROL_FORCE_COLOUR) + ctrl->value = ((s32)reg & SAA7191_GAIN_COLO) ? 1 : 0; + else + ctrl->value = ((s32)reg & SAA7191_GAIN_LFIS_MASK) + >> SAA7191_GAIN_LFIS_SHIFT; + break; + case SAA7191_CONTROL_HUE: + reg = saa7191_read_reg(client, SAA7191_REG_HUEC); + if (reg < 0x80) + reg += 0x80; + else + reg -= 0x80; + ctrl->value = (s32)reg; + break; + case SAA7191_CONTROL_VTRC: + reg = saa7191_read_reg(client, SAA7191_REG_STDC); + ctrl->value = ((s32)reg & SAA7191_STDC_VTRC) ? 1 : 0; + break; + case SAA7191_CONTROL_LUMA_DELAY: + reg = saa7191_read_reg(client, SAA7191_REG_CTL3); + ctrl->value = ((s32)reg & SAA7191_CTL3_YDEL_MASK) + >> SAA7191_CTL3_YDEL_SHIFT; + if (ctrl->value >= 4) + ctrl->value -= 8; + break; + case SAA7191_CONTROL_VNR: + reg = saa7191_read_reg(client, SAA7191_REG_CTL4); + ctrl->value = ((s32)reg & SAA7191_CTL4_VNOI_MASK) + >> SAA7191_CTL4_VNOI_SHIFT; + break; + default: + ret = -EINVAL; + } - err = saa7191_write_reg(client, SAA7191_REG_STDC, stdc); - if (err) - return -EIO; + return ret; +} + +static int saa7191_set_control(struct i2c_client *client, + struct saa7191_control *ctrl) +{ + u8 reg; + int ret = 0; + + switch (ctrl->type) { + case SAA7191_CONTROL_BANDPASS: + case SAA7191_CONTROL_BANDPASS_WEIGHT: + case SAA7191_CONTROL_CORING: + reg = saa7191_read_reg(client, SAA7191_REG_LUMA); + switch (ctrl->type) { + case SAA7191_CONTROL_BANDPASS: + reg &= ~SAA7191_LUMA_BPSS_MASK; + reg |= (ctrl->value << SAA7191_LUMA_BPSS_SHIFT) + & SAA7191_LUMA_BPSS_MASK; + break; + case SAA7191_CONTROL_BANDPASS_WEIGHT: + reg &= ~SAA7191_LUMA_APER_MASK; + reg |= (ctrl->value << SAA7191_LUMA_APER_SHIFT) + & SAA7191_LUMA_APER_MASK; + break; + case SAA7191_CONTROL_CORING: + reg &= ~SAA7191_LUMA_CORI_MASK; + reg |= (ctrl->value << SAA7191_LUMA_CORI_SHIFT) + & SAA7191_LUMA_CORI_MASK; + break; + } + ret = saa7191_write_reg(client, SAA7191_REG_LUMA, reg); + break; + case SAA7191_CONTROL_FORCE_COLOUR: + case SAA7191_CONTROL_CHROMA_GAIN: + reg = saa7191_read_reg(client, SAA7191_REG_GAIN); + if (ctrl->type == SAA7191_CONTROL_FORCE_COLOUR) { + if (ctrl->value) + reg |= SAA7191_GAIN_COLO; + else + reg &= ~SAA7191_GAIN_COLO; + } else { + reg &= ~SAA7191_GAIN_LFIS_MASK; + reg |= (ctrl->value << SAA7191_GAIN_LFIS_SHIFT) + & SAA7191_GAIN_LFIS_MASK; + } + ret = saa7191_write_reg(client, SAA7191_REG_GAIN, reg); + break; + case SAA7191_CONTROL_HUE: + reg = ctrl->value & 0xff; + if (reg < 0x80) + reg += 0x80; + else + reg -= 0x80; + ret = saa7191_write_reg(client, SAA7191_REG_HUEC, reg); + break; + case SAA7191_CONTROL_VTRC: + reg = saa7191_read_reg(client, SAA7191_REG_STDC); + if (ctrl->value) + reg |= SAA7191_STDC_VTRC; + else + reg &= ~SAA7191_STDC_VTRC; + ret = saa7191_write_reg(client, SAA7191_REG_STDC, reg); + break; + case SAA7191_CONTROL_LUMA_DELAY: { + s32 value = ctrl->value; + if (value < 0) + value += 8; + reg = saa7191_read_reg(client, SAA7191_REG_CTL3); + reg &= ~SAA7191_CTL3_YDEL_MASK; + reg |= (value << SAA7191_CTL3_YDEL_SHIFT) + & SAA7191_CTL3_YDEL_MASK; + ret = saa7191_write_reg(client, SAA7191_REG_CTL3, reg); + break; + } + case SAA7191_CONTROL_VNR: + reg = saa7191_read_reg(client, SAA7191_REG_CTL4); + reg &= ~SAA7191_CTL4_VNOI_MASK; + reg |= (ctrl->value << SAA7191_CTL4_VNOI_SHIFT) + & SAA7191_CTL4_VNOI_MASK; + ret = saa7191_write_reg(client, SAA7191_REG_CTL4, reg); + break; + default: + ret = -EINVAL; } - return 0; + return ret; } /* I2C-interface */ @@ -309,11 +596,7 @@ static int saa7191_attach(struct i2c_adapter *adap, int addr, int kind) if (err) goto out_free_decoder; - decoder->input = SAA7191_INPUT_COMPOSITE; - decoder->norm = SAA7191_NORM_AUTO; - - err = saa7191_write_block(client, sizeof(initseq), - (unsigned char *)initseq); + err = saa7191_write_block(client, sizeof(initseq), (u8 *)initseq); if (err) { printk(KERN_ERR "SAA7191 initialization failed\n"); goto out_detach_client; @@ -321,6 +604,14 @@ static int saa7191_attach(struct i2c_adapter *adap, int addr, int kind) printk(KERN_INFO "SAA7191 initialized\n"); + decoder->input = SAA7191_INPUT_COMPOSITE; + decoder->norm = SAA7191_NORM_PAL; + + err = saa7191_autodetect_norm(client); + if (err && (err != -EBUSY)) { + printk(KERN_ERR "SAA7191: Signal auto-detection failed\n"); + } + return 0; out_detach_client: @@ -368,7 +659,7 @@ static int saa7191_command(struct i2c_client *client, unsigned int cmd, } case DECODER_GET_STATUS: { int *iarg = arg; - unsigned char status; + u8 status; int res = 0; if (saa7191_read_status(client, &status)) { @@ -404,7 +695,7 @@ static int saa7191_command(struct i2c_client *client, unsigned int cmd, switch (*iarg) { case VIDEO_MODE_AUTO: - return saa7191_set_norm(client, SAA7191_NORM_AUTO); + return saa7191_autodetect_norm(client); case VIDEO_MODE_PAL: return saa7191_set_norm(client, SAA7191_NORM_PAL); case VIDEO_MODE_NTSC: @@ -446,38 +737,48 @@ static int saa7191_command(struct i2c_client *client, unsigned int cmd, int err; val = (pic->hue >> 8) - 0x80; + err = saa7191_write_reg(client, SAA7191_REG_HUEC, val); if (err) return -EIO; + break; } case DECODER_SAA7191_GET_STATUS: { struct saa7191_status *status = arg; - unsigned char status_reg; + u8 status_reg; if (saa7191_read_status(client, &status_reg)) return -EIO; + status->signal = ((status_reg & SAA7191_STATUS_HLCK) == 0) - ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED; - status->ntsc = (status_reg & SAA7191_STATUS_FIDT) - ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED; - status->color = (status_reg & SAA7191_STATUS_CODE) - ? SAA7191_VALUE_ENABLED : SAA7191_VALUE_DISABLED; + ? 1 : 0; + status->signal_60hz = (status_reg & SAA7191_STATUS_FIDT) + ? 1 : 0; + status->color = (status_reg & SAA7191_STATUS_CODE) ? 1 : 0; status->input = decoder->input; status->norm = decoder->norm; + + break; } case DECODER_SAA7191_SET_NORM: { int *norm = arg; - return saa7191_set_norm(client, *norm); + + switch (*norm) { + case SAA7191_NORM_AUTO: + return saa7191_autodetect_norm(client); + case SAA7191_NORM_AUTO_EXT: + return saa7191_autodetect_norm_extended(client); + default: + return saa7191_set_norm(client, *norm); + } } - case DECODER_SAA7191_GET_CONTROLS: { - struct saa7191_control *ctrl = arg; - return saa7191_get_controls(client, ctrl); + case DECODER_SAA7191_GET_CONTROL: { + return saa7191_get_control(client, arg); } - case DECODER_SAA7191_SET_CONTROLS: { - struct saa7191_control *ctrl = arg; - return saa7191_set_controls(client, ctrl); + case DECODER_SAA7191_SET_CONTROL: { + return saa7191_set_control(client, arg); } default: return -EINVAL; @@ -488,12 +789,12 @@ static int saa7191_command(struct i2c_client *client, unsigned int cmd, static struct i2c_driver i2c_driver_saa7191 = { .owner = THIS_MODULE, - .name = "saa7191", - .id = I2C_DRIVERID_SAA7191, - .flags = I2C_DF_NOTIFY, + .name = "saa7191", + .id = I2C_DRIVERID_SAA7191, + .flags = I2C_DF_NOTIFY, .attach_adapter = saa7191_probe, - .detach_client = saa7191_detach, - .command = saa7191_command + .detach_client = saa7191_detach, + .command = saa7191_command }; static int saa7191_init(void) diff --git a/drivers/media/video/saa7191.h b/drivers/media/video/saa7191.h index 272045031435f1ab7ce0f0dac654f82892fe42b9..a2310da1940df4e7993c71102a92629aab5875b1 100644 --- a/drivers/media/video/saa7191.h +++ b/drivers/media/video/saa7191.h @@ -24,8 +24,8 @@ #define SAA7191_REG_HPHI 0x05 #define SAA7191_REG_LUMA 0x06 #define SAA7191_REG_HUEC 0x07 -#define SAA7191_REG_CKTQ 0x08 -#define SAA7191_REG_CKTS 0x09 +#define SAA7191_REG_CKTQ 0x08 /* bits 3-7 */ +#define SAA7191_REG_CKTS 0x09 /* bits 3-7 */ #define SAA7191_REG_PLSE 0x0a #define SAA7191_REG_SESE 0x0b #define SAA7191_REG_GAIN 0x0c @@ -43,30 +43,82 @@ /* Status Register definitions */ #define SAA7191_STATUS_CODE 0x01 /* color detected flag */ -#define SAA7191_STATUS_FIDT 0x20 /* format type NTSC/PAL */ -#define SAA7191_STATUS_HLCK 0x40 /* PLL unlocked/locked */ +#define SAA7191_STATUS_FIDT 0x20 /* signal type 50/60 Hz */ +#define SAA7191_STATUS_HLCK 0x40 /* PLL unlocked(1)/locked(0) */ #define SAA7191_STATUS_STTC 0x80 /* tv/vtr time constant */ /* Luminance Control Register definitions */ +/* input mode select bit: + * 0=CVBS (chrominance trap active), 1=S-Video (trap bypassed) */ #define SAA7191_LUMA_BYPS 0x80 - -/* Chroma Gain Control Settings Register definitions */ -/* 0=automatic colour-killer enabled, 1=forced colour on */ +/* pre-filter (only when chrominance trap is active) */ +#define SAA7191_LUMA_PREF 0x40 +/* aperture bandpass to select different characteristics with maximums + * (bits 4-5) */ +#define SAA7191_LUMA_BPSS_MASK 0x30 +#define SAA7191_LUMA_BPSS_SHIFT 4 +#define SAA7191_LUMA_BPSS_3 0x30 +#define SAA7191_LUMA_BPSS_2 0x20 +#define SAA7191_LUMA_BPSS_1 0x10 +#define SAA7191_LUMA_BPSS_0 0x00 +/* coring range for high frequency components according to 8-bit luminance + * (bits 2-3) + * 0=coring off, n= (+-)n LSB */ +#define SAA7191_LUMA_CORI_MASK 0x0c +#define SAA7191_LUMA_CORI_SHIFT 2 +#define SAA7191_LUMA_CORI_3 0x0c +#define SAA7191_LUMA_CORI_2 0x08 +#define SAA7191_LUMA_CORI_1 0x04 +#define SAA7191_LUMA_CORI_0 0x00 +/* aperture bandpass filter weights high frequency components of luminance + * signal (bits 0-1) + * 0=factor 0, 1=0.25, 2=0.5, 3=1 */ +#define SAA7191_LUMA_APER_MASK 0x03 +#define SAA7191_LUMA_APER_SHIFT 0 +#define SAA7191_LUMA_APER_3 0x03 +#define SAA7191_LUMA_APER_2 0x02 +#define SAA7191_LUMA_APER_1 0x01 +#define SAA7191_LUMA_APER_0 0x00 + +/* Chrominance Gain Control Settings Register definitions */ +/* colour on: 0=automatic colour-killer enabled, 1=forced colour on */ #define SAA7191_GAIN_COLO 0x80 +/* chrominance gain control (AGC filter) + * 0=loop filter time constant slow, 1=medium, 2=fast, 3=actual gain */ +#define SAA7191_GAIN_LFIS_MASK 0x60 +#define SAA7191_GAIN_LFIS_SHIFT 5 +#define SAA7191_GAIN_LFIS_3 0x60 +#define SAA7191_GAIN_LFIS_2 0x40 +#define SAA7191_GAIN_LFIS_1 0x20 +#define SAA7191_GAIN_LFIS_0 0x00 /* Standard/Mode Control Register definitions */ /* tv/vtr mode bit: 0=TV mode (slow time constant), * 1=VTR mode (fast time constant) */ #define SAA7191_STDC_VTRC 0x80 +/* SAA7191B-specific functions enable (RTCO, ODD and GPSW0 outputs) + * 0=outputs set to high-impedance (circuit equals SAA7191), 1=enabled */ +#define SAA7191_STDC_NFEN 0x08 +/* HREF generation: 0=like SAA7191, 1=HREF is 8xLLC2 clocks earlier */ +#define SAA7191_STDC_HRMV 0x04 +/* general purpose switch 0 + * (not used with VINO afaik) */ +#define SAA7191_STDC_GPSW0 0x02 /* SECAM mode bit: 0=other standards, 1=SECAM */ #define SAA7191_STDC_SECS 0x01 -/* the bit fields above must be or'd with this value */ -#define SAA7191_STDC_VALUE 0x0c /* I/O and Clock Control Register definitions */ /* horizontal clock PLL: 0=PLL closed, * 1=PLL circuit open and horizontal freq fixed */ #define SAA7191_IOCK_HPLL 0x80 +/* colour-difference output enable (outputs UV0-UV7) */ +#define SAA7191_IOCK_OEDC 0x40 +/* H-sync output enable */ +#define SAA7191_IOCK_OEHS 0x20 +/* V-sync output enable */ +#define SAA7191_IOCK_OEVS 0x10 +/* luminance output enable (outputs Y0-Y7) */ +#define SAA7191_IOCK_OEDY 0x08 /* S-VHS bit (chrominance from CVBS or from chrominance input): * 0=controlled by BYPS-bit, 1=from chrominance input */ #define SAA7191_IOCK_CHRS 0x04 @@ -83,11 +135,40 @@ /* field select: (if AUFD=0) * 0=50Hz (625 lines), 1=60Hz (525 lines) */ #define SAA7191_CTL3_FSEL 0x40 -/* the bit fields above must be or'd with this value */ -#define SAA7191_CTL3_VALUE 0x19 +/* SECAM cross-colour reduction enable */ +#define SAA7191_CTL3_SXCR 0x20 +/* sync and clamping pulse enable (HCL and HSY outputs) */ +#define SAA7191_CTL3_SCEN 0x10 +/* output format: 0=4:1:1, 1=4:2:2 (4:2:2 for VINO) */ +#define SAA7191_CTL3_OFTS 0x08 +/* luminance delay compensation + * 0=0*2/LLC, 1=+1*2/LLC, 2=+2*2/LLC, 3=+3*2/LLC, + * 4=-4*2/LLC, 5=-3*2/LLC, 6=-2*2/LLC, 7=-1*2/LLC + * step size = 2/LLC = 67.8ns for 50Hz, 81.5ns for 60Hz */ +#define SAA7191_CTL3_YDEL_MASK 0x07 +#define SAA7191_CTL3_YDEL_SHIFT 0 +#define SAA7191_CTL3_YDEL2 0x04 +#define SAA7191_CTL3_YDEL1 0x02 +#define SAA7191_CTL3_YDEL0 0x01 + +/* Miscellaneous Control #2 Register definitions */ +/* select HREF position + * 0=normal, HREF is matched to YUV output port, + * 1=HREF is matched to CVBS input port */ +#define SAA7191_CTL4_HRFS 0x04 +/* vertical noise reduction + * 0=normal, 1=searching window, 2=auto-deflection, 3=reduction bypassed */ +#define SAA7191_CTL4_VNOI_MASK 0x03 +#define SAA7191_CTL4_VNOI_SHIFT 0 +#define SAA7191_CTL4_VNOI_3 0x03 +#define SAA7191_CTL4_VNOI_2 0x02 +#define SAA7191_CTL4_VNOI_1 0x01 +#define SAA7191_CTL4_VNOI_0 0x00 /* Chrominance Gain Control Register definitions - * (nominal value for UV CCIR level) */ + * - for QAM-modulated input signals, effects output amplitude + * (SECAM gain fixed) + * (nominal values for UV CCIR level) */ #define SAA7191_CHCV_NTSC 0x2c #define SAA7191_CHCV_PAL 0x59 @@ -99,16 +180,13 @@ #define SAA7191_NORM_PAL 1 #define SAA7191_NORM_NTSC 2 #define SAA7191_NORM_SECAM 3 - -#define SAA7191_VALUE_ENABLED 1 -#define SAA7191_VALUE_DISABLED 0 -#define SAA7191_VALUE_UNCHANGED -1 +#define SAA7191_NORM_AUTO_EXT 4 /* extended auto-detection */ struct saa7191_status { - /* 0=no signal, 1=signal active*/ + /* 0=no signal, 1=signal detected */ int signal; /* 0=50hz (pal) signal, 1=60hz (ntsc) signal */ - int ntsc; + int signal_60hz; /* 0=no color detected, 1=color detected */ int color; @@ -118,22 +196,60 @@ struct saa7191_status { int norm; }; -#define SAA7191_HUE_MIN 0x00 -#define SAA7191_HUE_MAX 0xff -#define SAA7191_HUE_DEFAULT 0x80 +#define SAA7191_BANDPASS_MIN 0x00 +#define SAA7191_BANDPASS_MAX 0x03 +#define SAA7191_BANDPASS_DEFAULT 0x00 + +#define SAA7191_BANDPASS_WEIGHT_MIN 0x00 +#define SAA7191_BANDPASS_WEIGHT_MAX 0x03 +#define SAA7191_BANDPASS_WEIGHT_DEFAULT 0x01 + +#define SAA7191_CORING_MIN 0x00 +#define SAA7191_CORING_MAX 0x03 +#define SAA7191_CORING_DEFAULT 0x00 + +#define SAA7191_HUE_MIN 0x00 +#define SAA7191_HUE_MAX 0xff +#define SAA7191_HUE_DEFAULT 0x80 + +#define SAA7191_VTRC_MIN 0x00 +#define SAA7191_VTRC_MAX 0x01 +#define SAA7191_VTRC_DEFAULT 0x00 + +#define SAA7191_FORCE_COLOUR_MIN 0x00 +#define SAA7191_FORCE_COLOUR_MAX 0x01 +#define SAA7191_FORCE_COLOUR_DEFAULT 0x00 + +#define SAA7191_CHROMA_GAIN_MIN 0x00 +#define SAA7191_CHROMA_GAIN_MAX 0x03 +#define SAA7191_CHROMA_GAIN_DEFAULT 0x00 + +#define SAA7191_LUMA_DELAY_MIN -0x04 +#define SAA7191_LUMA_DELAY_MAX 0x03 +#define SAA7191_LUMA_DELAY_DEFAULT 0x01 + +#define SAA7191_VNR_MIN 0x00 +#define SAA7191_VNR_MAX 0x03 +#define SAA7191_VNR_DEFAULT 0x00 -#define SAA7191_VTRC_MIN 0x00 -#define SAA7191_VTRC_MAX 0x01 -#define SAA7191_VTRC_DEFAULT 0x00 +#define SAA7191_CONTROL_BANDPASS 0 +#define SAA7191_CONTROL_BANDPASS_WEIGHT 1 +#define SAA7191_CONTROL_CORING 2 +#define SAA7191_CONTROL_FORCE_COLOUR 3 /* boolean */ +#define SAA7191_CONTROL_CHROMA_GAIN 4 +#define SAA7191_CONTROL_HUE 5 +#define SAA7191_CONTROL_VTRC 6 /* boolean */ +#define SAA7191_CONTROL_LUMA_DELAY 7 +#define SAA7191_CONTROL_VNR 8 struct saa7191_control { - int hue; - int vtrc; + u8 type; + s32 value; }; #define DECODER_SAA7191_GET_STATUS _IOR('d', 195, struct saa7191_status) #define DECODER_SAA7191_SET_NORM _IOW('d', 196, int) -#define DECODER_SAA7191_GET_CONTROLS _IOR('d', 197, struct saa7191_control) -#define DECODER_SAA7191_SET_CONTROLS _IOW('d', 198, struct saa7191_control) +#define DECODER_SAA7191_GET_CONTROL _IOR('d', 197, struct saa7191_control) +#define DECODER_SAA7191_SET_CONTROL _IOW('d', 198, struct saa7191_control) #endif diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c index 59bb71381a1b19f18877348fee0561a8215efba3..d679ca23ded71aac49e7ea70f229e40137ddd300 100644 --- a/drivers/media/video/v4l1-compat.c +++ b/drivers/media/video/v4l1-compat.c @@ -1006,10 +1006,8 @@ v4l_compat_translate_ioctl(struct inode *inode, break; } - if (cap2) - kfree(cap2); - if (fmt2) - kfree(fmt2); + kfree(cap2); + kfree(fmt2); return err; } diff --git a/drivers/media/video/videocodec.c b/drivers/media/video/videocodec.c index c9d5f1a873cc094474033143a8c4937a4dbc7987..839db622040dcdcfe1ff344d7f8846b5c9a7ef53 100644 --- a/drivers/media/video/videocodec.c +++ b/drivers/media/video/videocodec.c @@ -353,8 +353,7 @@ videocodec_build_table (void) dprintk(3, "videocodec_build table: %d entries, %d bytes\n", i, size); - if (videocodec_buf) - kfree(videocodec_buf); + kfree(videocodec_buf); videocodec_buf = (char *) kmalloc(size, GFP_KERNEL); i = 0; @@ -471,8 +470,7 @@ videocodec_exit (void) { #ifdef CONFIG_PROC_FS remove_proc_entry("videocodecs", NULL); - if (videocodec_buf) - kfree(videocodec_buf); + kfree(videocodec_buf); #endif } diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 06df15f75de94d2fdf34268fd799737e99d7c5d1..83c49f9610d0b0bff75209c556eed46062f01d70 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -215,8 +215,7 @@ video_usercopy(struct inode *inode, struct file *file, } out: - if (mbuf) - kfree(mbuf); + kfree(mbuf); return err; } diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index ed4394e854abf94aae6057143c5597a7926994e5..71b28e9e085021e1fdae979e4edf7fe6b270a353 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -12,15 +12,11 @@ /* * TODO: - * - remove "hacks" from memory allocation code and implement nopage() + * - remove "mark pages reserved-hacks" from memory allocation code + * and implement nopage() * - check decimation, calculating and reporting image size when * using decimation - * - check vino_acquire_input(), vino_set_input() and channel - * ownership handling - * - report VINO error-interrupts via ioctls ? - * - implement picture controls (all implemented?) - * - use macros for boolean values (?) - * - implement user mode buffers and overlay (?) + * - implement read(), user mode buffers and overlay (?) */ #include @@ -60,18 +56,16 @@ * debug info. * Note that the debug output also slows down the driver significantly */ // #define VINO_DEBUG +// #define VINO_DEBUG_INT -#define VINO_MODULE_VERSION "0.0.3" -#define VINO_VERSION_CODE KERNEL_VERSION(0, 0, 3) +#define VINO_MODULE_VERSION "0.0.5" +#define VINO_VERSION_CODE KERNEL_VERSION(0, 0, 5) MODULE_DESCRIPTION("SGI VINO Video4Linux2 driver"); MODULE_VERSION(VINO_MODULE_VERSION); MODULE_AUTHOR("Mikael Nousiainen "); MODULE_LICENSE("GPL"); -#define mem_map_reserve(p) set_bit(PG_reserved, &((p)->flags)) -#define mem_map_unreserve(p) clear_bit(PG_reserved, &((p)->flags)) - #ifdef VINO_DEBUG #define dprintk(x...) printk("VINO: " x); #else @@ -91,15 +85,16 @@ MODULE_LICENSE("GPL"); #define VINO_MIN_HEIGHT 32 #define VINO_CLIPPING_START_ODD_D1 1 -#define VINO_CLIPPING_START_ODD_PAL 1 -#define VINO_CLIPPING_START_ODD_NTSC 1 +#define VINO_CLIPPING_START_ODD_PAL 15 +#define VINO_CLIPPING_START_ODD_NTSC 12 #define VINO_CLIPPING_START_EVEN_D1 2 -#define VINO_CLIPPING_START_EVEN_PAL 2 -#define VINO_CLIPPING_START_EVEN_NTSC 2 +#define VINO_CLIPPING_START_EVEN_PAL 15 +#define VINO_CLIPPING_START_EVEN_NTSC 12 #define VINO_INPUT_CHANNEL_COUNT 3 +/* the number is the index for vino_inputs */ #define VINO_INPUT_NONE -1 #define VINO_INPUT_COMPOSITE 0 #define VINO_INPUT_SVIDEO 1 @@ -107,15 +102,13 @@ MODULE_LICENSE("GPL"); #define VINO_PAGE_RATIO (PAGE_SIZE / VINO_PAGE_SIZE) -#define VINO_FIFO_THRESHOLD_DEFAULT 512 +#define VINO_FIFO_THRESHOLD_DEFAULT 16 -/*#define VINO_FRAMEBUFFER_SIZE (VINO_PAL_WIDTH * VINO_PAL_HEIGHT * 4 \ - + 2 * PAGE_SIZE)*/ #define VINO_FRAMEBUFFER_SIZE ((VINO_PAL_WIDTH \ * VINO_PAL_HEIGHT * 4 \ + 3 * PAGE_SIZE) & ~(PAGE_SIZE - 1)) -#define VINO_FRAMEBUFFER_MAX_COUNT 8 +#define VINO_FRAMEBUFFER_COUNT_MAX 8 #define VINO_FRAMEBUFFER_UNUSED 0 #define VINO_FRAMEBUFFER_IN_USE 1 @@ -131,24 +124,27 @@ MODULE_LICENSE("GPL"); #define VINO_DUMMY_DESC_COUNT 4 #define VINO_DESC_FETCH_DELAY 5 /* microseconds */ +#define VINO_MAX_FRAME_SKIP_COUNT 128 + /* the number is the index for vino_data_formats */ #define VINO_DATA_FMT_NONE -1 #define VINO_DATA_FMT_GREY 0 #define VINO_DATA_FMT_RGB332 1 #define VINO_DATA_FMT_RGB32 2 #define VINO_DATA_FMT_YUV 3 -//#define VINO_DATA_FMT_RGB24 4 #define VINO_DATA_FMT_COUNT 4 +/* the number is the index for vino_data_norms */ #define VINO_DATA_NORM_NONE -1 #define VINO_DATA_NORM_NTSC 0 #define VINO_DATA_NORM_PAL 1 #define VINO_DATA_NORM_SECAM 2 #define VINO_DATA_NORM_D1 3 -/* The following is a special entry that can be used to +/* The following are special entries that can be used to * autodetect the norm. */ -#define VINO_DATA_NORM_AUTO 0xff +#define VINO_DATA_NORM_AUTO 0xfe +#define VINO_DATA_NORM_AUTO_EXT 0xff #define VINO_DATA_NORM_COUNT 4 @@ -232,7 +228,7 @@ struct vino_framebuffer_fifo { unsigned int head; unsigned int tail; - unsigned int data[VINO_FRAMEBUFFER_MAX_COUNT]; + unsigned int data[VINO_FRAMEBUFFER_COUNT_MAX]; }; struct vino_framebuffer_queue { @@ -246,13 +242,20 @@ struct vino_framebuffer_queue { struct vino_framebuffer_fifo in; struct vino_framebuffer_fifo out; - struct vino_framebuffer *buffer[VINO_FRAMEBUFFER_MAX_COUNT]; + struct vino_framebuffer *buffer[VINO_FRAMEBUFFER_COUNT_MAX]; spinlock_t queue_lock; struct semaphore queue_sem; wait_queue_head_t frame_wait_queue; }; +struct vino_interrupt_data { + struct timeval timestamp; + unsigned int frame_counter; + unsigned int skip_count; + unsigned int skip; +}; + struct vino_channel_settings { unsigned int channel; @@ -285,6 +288,8 @@ struct vino_channel_settings { unsigned int users; + struct vino_interrupt_data int_data; + /* V4L support */ struct video_device *v4l_device; }; @@ -315,7 +320,7 @@ struct vino_settings { /* Module parameters */ /* - * Using vino_pixel_conversion the ARGB32-format pixels supplied + * Using vino_pixel_conversion the ABGR32-format pixels supplied * by the VINO chip can be converted to more common formats * like RGBA32 (or probably RGB24 in the future). This way we * can give out data that can be specified correctly with @@ -329,7 +334,9 @@ struct vino_settings { * Use non-zero value to enable conversion. */ static int vino_pixel_conversion = 0; + module_param_named(pixelconv, vino_pixel_conversion, int, 0); + MODULE_PARM_DESC(pixelconv, "enable pixel conversion (non-zero value enables)"); @@ -345,15 +352,22 @@ static const char *vino_bus_name = "GIO64 bus"; static const char *vino_v4l_device_name_a = "SGI VINO Channel A"; static const char *vino_v4l_device_name_b = "SGI VINO Channel B"; +static void vino_capture_tasklet(unsigned long channel); + +DECLARE_TASKLET(vino_tasklet_a, vino_capture_tasklet, VINO_CHANNEL_A); +DECLARE_TASKLET(vino_tasklet_b, vino_capture_tasklet, VINO_CHANNEL_B); + static const struct vino_input vino_inputs[] = { { .name = "Composite", - .std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, + .std = V4L2_STD_NTSC | V4L2_STD_PAL + | V4L2_STD_SECAM, },{ .name = "S-Video", - .std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, + .std = V4L2_STD_NTSC | V4L2_STD_PAL + | V4L2_STD_SECAM, },{ - .name = "D1 (IndyCam)", + .name = "D1/IndyCam", .std = V4L2_STD_NTSC, } }; @@ -376,15 +390,10 @@ static const struct vino_data_format vino_data_formats[] = { .colorspace = V4L2_COLORSPACE_SRGB, },{ .description = "YUV 4:2:2", - .bpp = 4, + .bpp = 2, .pixelformat = V4L2_PIX_FMT_YUYV, // XXX: swapped? .colorspace = V4L2_COLORSPACE_SMPTE170M, - }/*,{ - .description = "24-bit RGB", - .bpp = 3, - .pixelformat = V4L2_PIX_FMT_RGB24, - .colorspace = V4L2_COLORSPACE_SRGB, - }*/ + } }; static const struct vino_data_norm vino_data_norms[] = { @@ -397,18 +406,18 @@ static const struct vino_data_norm vino_data_norms[] = { .width = VINO_NTSC_WIDTH, .height = VINO_NTSC_HEIGHT, .odd = { - .top = VINO_CLIPPING_START_ODD_NTSC, - .left = 0, + .top = VINO_CLIPPING_START_ODD_NTSC, + .left = 0, .bottom = VINO_CLIPPING_START_ODD_NTSC + VINO_NTSC_HEIGHT / 2 - 1, - .right = VINO_NTSC_WIDTH, + .right = VINO_NTSC_WIDTH, }, .even = { - .top = VINO_CLIPPING_START_EVEN_NTSC, - .left = 0, + .top = VINO_CLIPPING_START_EVEN_NTSC, + .left = 0, .bottom = VINO_CLIPPING_START_EVEN_NTSC + VINO_NTSC_HEIGHT / 2 - 1, - .right = VINO_NTSC_WIDTH, + .right = VINO_NTSC_WIDTH, }, },{ .description = "PAL", @@ -419,18 +428,18 @@ static const struct vino_data_norm vino_data_norms[] = { .width = VINO_PAL_WIDTH, .height = VINO_PAL_HEIGHT, .odd = { - .top = VINO_CLIPPING_START_ODD_PAL, - .left = 0, + .top = VINO_CLIPPING_START_ODD_PAL, + .left = 0, .bottom = VINO_CLIPPING_START_ODD_PAL + VINO_PAL_HEIGHT / 2 - 1, - .right = VINO_PAL_WIDTH, + .right = VINO_PAL_WIDTH, }, .even = { - .top = VINO_CLIPPING_START_EVEN_PAL, - .left = 0, + .top = VINO_CLIPPING_START_EVEN_PAL, + .left = 0, .bottom = VINO_CLIPPING_START_EVEN_PAL + VINO_PAL_HEIGHT / 2 - 1, - .right = VINO_PAL_WIDTH, + .right = VINO_PAL_WIDTH, }, },{ .description = "SECAM", @@ -441,21 +450,21 @@ static const struct vino_data_norm vino_data_norms[] = { .width = VINO_PAL_WIDTH, .height = VINO_PAL_HEIGHT, .odd = { - .top = VINO_CLIPPING_START_ODD_PAL, - .left = 0, + .top = VINO_CLIPPING_START_ODD_PAL, + .left = 0, .bottom = VINO_CLIPPING_START_ODD_PAL + VINO_PAL_HEIGHT / 2 - 1, - .right = VINO_PAL_WIDTH, + .right = VINO_PAL_WIDTH, }, .even = { - .top = VINO_CLIPPING_START_EVEN_PAL, - .left = 0, + .top = VINO_CLIPPING_START_EVEN_PAL, + .left = 0, .bottom = VINO_CLIPPING_START_EVEN_PAL + VINO_PAL_HEIGHT / 2 - 1, - .right = VINO_PAL_WIDTH, + .right = VINO_PAL_WIDTH, }, },{ - .description = "NTSC (D1 input)", + .description = "NTSC/D1", .std = V4L2_STD_NTSC, .fps_min = 6, .fps_max = 30, @@ -463,18 +472,18 @@ static const struct vino_data_norm vino_data_norms[] = { .width = VINO_NTSC_WIDTH, .height = VINO_NTSC_HEIGHT, .odd = { - .top = VINO_CLIPPING_START_ODD_D1, - .left = 0, + .top = VINO_CLIPPING_START_ODD_D1, + .left = 0, .bottom = VINO_CLIPPING_START_ODD_D1 + VINO_NTSC_HEIGHT / 2 - 1, - .right = VINO_NTSC_WIDTH, + .right = VINO_NTSC_WIDTH, }, .even = { - .top = VINO_CLIPPING_START_EVEN_D1, - .left = 0, + .top = VINO_CLIPPING_START_EVEN_D1, + .left = 0, .bottom = VINO_CLIPPING_START_EVEN_D1 + VINO_NTSC_HEIGHT / 2 - 1, - .right = VINO_NTSC_WIDTH, + .right = VINO_NTSC_WIDTH, }, } }; @@ -491,7 +500,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = { .step = 1, .default_value = INDYCAM_AGC_DEFAULT, .flags = 0, - .reserved = { 0, 0 }, + .reserved = { INDYCAM_CONTROL_AGC, 0 }, },{ .id = V4L2_CID_AUTO_WHITE_BALANCE, .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -501,7 +510,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = { .step = 1, .default_value = INDYCAM_AWB_DEFAULT, .flags = 0, - .reserved = { 0, 0 }, + .reserved = { INDYCAM_CONTROL_AWB, 0 }, },{ .id = V4L2_CID_GAIN, .type = V4L2_CTRL_TYPE_INTEGER, @@ -511,7 +520,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = { .step = 1, .default_value = INDYCAM_GAIN_DEFAULT, .flags = 0, - .reserved = { 0, 0 }, + .reserved = { INDYCAM_CONTROL_GAIN, 0 }, },{ .id = V4L2_CID_PRIVATE_BASE, .type = V4L2_CTRL_TYPE_INTEGER, @@ -521,7 +530,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = { .step = 1, .default_value = INDYCAM_RED_SATURATION_DEFAULT, .flags = 0, - .reserved = { 0, 0 }, + .reserved = { INDYCAM_CONTROL_RED_SATURATION, 0 }, },{ .id = V4L2_CID_PRIVATE_BASE + 1, .type = V4L2_CTRL_TYPE_INTEGER, @@ -531,7 +540,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = { .step = 1, .default_value = INDYCAM_BLUE_SATURATION_DEFAULT, .flags = 0, - .reserved = { 0, 0 }, + .reserved = { INDYCAM_CONTROL_BLUE_SATURATION, 0 }, },{ .id = V4L2_CID_RED_BALANCE, .type = V4L2_CTRL_TYPE_INTEGER, @@ -541,7 +550,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = { .step = 1, .default_value = INDYCAM_RED_BALANCE_DEFAULT, .flags = 0, - .reserved = { 0, 0 }, + .reserved = { INDYCAM_CONTROL_RED_BALANCE, 0 }, },{ .id = V4L2_CID_BLUE_BALANCE, .type = V4L2_CTRL_TYPE_INTEGER, @@ -551,7 +560,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = { .step = 1, .default_value = INDYCAM_BLUE_BALANCE_DEFAULT, .flags = 0, - .reserved = { 0, 0 }, + .reserved = { INDYCAM_CONTROL_BLUE_BALANCE, 0 }, },{ .id = V4L2_CID_EXPOSURE, .type = V4L2_CTRL_TYPE_INTEGER, @@ -561,7 +570,7 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = { .step = 1, .default_value = INDYCAM_SHUTTER_DEFAULT, .flags = 0, - .reserved = { 0, 0 }, + .reserved = { INDYCAM_CONTROL_SHUTTER, 0 }, },{ .id = V4L2_CID_GAMMA, .type = V4L2_CTRL_TYPE_INTEGER, @@ -571,11 +580,11 @@ struct v4l2_queryctrl vino_indycam_v4l2_controls[] = { .step = 1, .default_value = INDYCAM_GAMMA_DEFAULT, .flags = 0, - .reserved = { 0, 0 }, + .reserved = { INDYCAM_CONTROL_GAMMA, 0 }, } }; -#define VINO_SAA7191_V4L2_CONTROL_COUNT 2 +#define VINO_SAA7191_V4L2_CONTROL_COUNT 9 struct v4l2_queryctrl vino_saa7191_v4l2_controls[] = { { @@ -587,9 +596,59 @@ struct v4l2_queryctrl vino_saa7191_v4l2_controls[] = { .step = 1, .default_value = SAA7191_HUE_DEFAULT, .flags = 0, - .reserved = { 0, 0 }, + .reserved = { SAA7191_CONTROL_HUE, 0 }, },{ .id = V4L2_CID_PRIVATE_BASE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Luminance Bandpass", + .minimum = SAA7191_BANDPASS_MIN, + .maximum = SAA7191_BANDPASS_MAX, + .step = 1, + .default_value = SAA7191_BANDPASS_DEFAULT, + .flags = 0, + .reserved = { SAA7191_CONTROL_BANDPASS, 0 }, + },{ + .id = V4L2_CID_PRIVATE_BASE + 1, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Luminance Bandpass Weight", + .minimum = SAA7191_BANDPASS_WEIGHT_MIN, + .maximum = SAA7191_BANDPASS_WEIGHT_MAX, + .step = 1, + .default_value = SAA7191_BANDPASS_WEIGHT_DEFAULT, + .flags = 0, + .reserved = { SAA7191_CONTROL_BANDPASS_WEIGHT, 0 }, + },{ + .id = V4L2_CID_PRIVATE_BASE + 2, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "HF Luminance Coring", + .minimum = SAA7191_CORING_MIN, + .maximum = SAA7191_CORING_MAX, + .step = 1, + .default_value = SAA7191_CORING_DEFAULT, + .flags = 0, + .reserved = { SAA7191_CONTROL_CORING, 0 }, + },{ + .id = V4L2_CID_PRIVATE_BASE + 3, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Force Colour", + .minimum = SAA7191_FORCE_COLOUR_MIN, + .maximum = SAA7191_FORCE_COLOUR_MAX, + .step = 1, + .default_value = SAA7191_FORCE_COLOUR_DEFAULT, + .flags = 0, + .reserved = { SAA7191_CONTROL_FORCE_COLOUR, 0 }, + },{ + .id = V4L2_CID_PRIVATE_BASE + 4, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Chrominance Gain Control", + .minimum = SAA7191_CHROMA_GAIN_MIN, + .maximum = SAA7191_CHROMA_GAIN_MAX, + .step = 1, + .default_value = SAA7191_CHROMA_GAIN_DEFAULT, + .flags = 0, + .reserved = { SAA7191_CONTROL_CHROMA_GAIN, 0 }, + },{ + .id = V4L2_CID_PRIVATE_BASE + 5, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "VTR Time Constant", .minimum = SAA7191_VTRC_MIN, @@ -597,7 +656,27 @@ struct v4l2_queryctrl vino_saa7191_v4l2_controls[] = { .step = 1, .default_value = SAA7191_VTRC_DEFAULT, .flags = 0, - .reserved = { 0, 0 }, + .reserved = { SAA7191_CONTROL_VTRC, 0 }, + },{ + .id = V4L2_CID_PRIVATE_BASE + 6, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Luminance Delay Compensation", + .minimum = SAA7191_LUMA_DELAY_MIN, + .maximum = SAA7191_LUMA_DELAY_MAX, + .step = 1, + .default_value = SAA7191_LUMA_DELAY_DEFAULT, + .flags = 0, + .reserved = { SAA7191_CONTROL_LUMA_DELAY, 0 }, + },{ + .id = V4L2_CID_PRIVATE_BASE + 7, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Vertical Noise Reduction", + .minimum = SAA7191_VNR_MIN, + .maximum = SAA7191_VNR_MAX, + .step = 1, + .default_value = SAA7191_VNR_DEFAULT, + .flags = 0, + .reserved = { SAA7191_CONTROL_VNR, 0 }, } }; @@ -639,9 +718,10 @@ static struct i2c_algo_sgi_data i2c_sgi_vino_data = */ static int i2c_vino_client_reg(struct i2c_client *client) { + unsigned long flags; int ret = 0; - spin_lock(&vino_drvdata->input_lock); + spin_lock_irqsave(&vino_drvdata->input_lock, flags); switch (client->driver->id) { case I2C_DRIVERID_SAA7191: if (vino_drvdata->decoder.driver) @@ -658,16 +738,17 @@ static int i2c_vino_client_reg(struct i2c_client *client) default: ret = -ENODEV; } - spin_unlock(&vino_drvdata->input_lock); + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); return ret; } static int i2c_vino_client_unreg(struct i2c_client *client) { + unsigned long flags; int ret = 0; - spin_lock(&vino_drvdata->input_lock); + spin_lock_irqsave(&vino_drvdata->input_lock, flags); if (client == vino_drvdata->decoder.driver) { if (vino_drvdata->decoder.owner != VINO_NO_CHANNEL) ret = -EBUSY; @@ -679,7 +760,7 @@ static int i2c_vino_client_unreg(struct i2c_client *client) else vino_drvdata->camera.driver = NULL; } - spin_unlock(&vino_drvdata->input_lock); + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); return ret; } @@ -727,7 +808,7 @@ static void vino_free_buffer_with_count(struct vino_framebuffer *fb, dprintk("vino_free_buffer_with_count(): count = %d\n", count); for (i = 0; i < count; i++) { - mem_map_unreserve(virt_to_page(fb->desc_table.virtual[i])); + ClearPageReserved(virt_to_page(fb->desc_table.virtual[i])); dma_unmap_single(NULL, fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i], PAGE_SIZE, DMA_FROM_DEVICE); @@ -805,7 +886,7 @@ static int vino_allocate_buffer(struct vino_framebuffer *fb, dma_data_addr + VINO_PAGE_SIZE * j; } - mem_map_reserve(virt_to_page(fb->desc_table.virtual[i])); + SetPageReserved(virt_to_page(fb->desc_table.virtual[i])); } /* page_count needs to be set anyway, because the descriptor table has @@ -892,7 +973,7 @@ static int vino_prepare_user_buffer(struct vino_framebuffer *fb, dma_data_addr + VINO_PAGE_SIZE * j; } - mem_map_reserve(virt_to_page(fb->desc_table.virtual[i])); + SetPageReserved(virt_to_page(fb->desc_table.virtual[i])); } /* page_count needs to be set anyway, because the descriptor table has @@ -933,7 +1014,7 @@ static void vino_sync_buffer(struct vino_framebuffer *fb) /* Framebuffer fifo functions (need to be locked externally) */ -static void vino_fifo_init(struct vino_framebuffer_fifo *f, +static inline void vino_fifo_init(struct vino_framebuffer_fifo *f, unsigned int length) { f->length = 0; @@ -941,16 +1022,18 @@ static void vino_fifo_init(struct vino_framebuffer_fifo *f, f->head = 0; f->tail = 0; - if (length > VINO_FRAMEBUFFER_MAX_COUNT) - length = VINO_FRAMEBUFFER_MAX_COUNT; + if (length > VINO_FRAMEBUFFER_COUNT_MAX) + length = VINO_FRAMEBUFFER_COUNT_MAX; f->length = length; } /* returns true/false */ -static int vino_fifo_has_id(struct vino_framebuffer_fifo *f, unsigned int id) +static inline int vino_fifo_has_id(struct vino_framebuffer_fifo *f, + unsigned int id) { unsigned int i; + for (i = f->head; i == (f->tail - 1); i = (i + 1) % f->length) { if (f->data[i] == id) return 1; @@ -959,13 +1042,15 @@ static int vino_fifo_has_id(struct vino_framebuffer_fifo *f, unsigned int id) return 0; } +#if 0 /* returns true/false */ -static int vino_fifo_full(struct vino_framebuffer_fifo *f) +static inline int vino_fifo_full(struct vino_framebuffer_fifo *f) { return (f->used == f->length); } +#endif -static unsigned int vino_fifo_get_used(struct vino_framebuffer_fifo *f) +static inline unsigned int vino_fifo_get_used(struct vino_framebuffer_fifo *f) { return f->used; } @@ -1076,8 +1161,8 @@ static int vino_queue_init(struct vino_framebuffer_queue *q, down(&q->queue_sem); - if (*length > VINO_FRAMEBUFFER_MAX_COUNT) - *length = VINO_FRAMEBUFFER_MAX_COUNT; + if (*length > VINO_FRAMEBUFFER_COUNT_MAX) + *length = VINO_FRAMEBUFFER_COUNT_MAX; q->length = 0; @@ -1313,6 +1398,7 @@ static int vino_queue_get_outgoing(struct vino_framebuffer_queue *q, return ret; } +#if 0 static int vino_queue_get_total(struct vino_framebuffer_queue *q, unsigned int *total) { @@ -1338,6 +1424,7 @@ static int vino_queue_get_total(struct vino_framebuffer_queue *q, return ret; } +#endif static struct vino_framebuffer *vino_queue_peek(struct vino_framebuffer_queue *q, @@ -1471,12 +1558,14 @@ static void vino_update_line_size(struct vino_channel_settings *vcs) dprintk("update_line_size(): before: w = %d, d = %d, " "line_size = %d\n", w, d, vcs->line_size); + /* line size must be multiple of 8 bytes */ lsize = (bpp * (w / d)) & ~7; w = (lsize / bpp) * d; vcs->clipping.right = vcs->clipping.left + w; vcs->line_size = lsize; + dprintk("update_line_size(): after: w = %d, d = %d, " "line_size = %d\n", w, d, vcs->line_size); } @@ -1532,7 +1621,7 @@ static void vino_set_clipping(struct vino_channel_settings *vcs, } /* execute with input_lock locked */ -static void vino_set_default_clipping(struct vino_channel_settings *vcs) +static inline void vino_set_default_clipping(struct vino_channel_settings *vcs) { vino_set_clipping(vcs, 0, 0, vino_data_norms[vcs->data_norm].width, vino_data_norms[vcs->data_norm].height); @@ -1556,8 +1645,7 @@ static void vino_set_scaling(struct vino_channel_settings *vcs, if (d < 1) { d = 1; - } - if (d > 8) { + } else if (d > 8) { d = 8; } @@ -1570,7 +1658,7 @@ static void vino_set_scaling(struct vino_channel_settings *vcs, } /* execute with input_lock locked */ -static void vino_reset_scaling(struct vino_channel_settings *vcs) +static inline void vino_set_default_scaling(struct vino_channel_settings *vcs) { vino_set_scaling(vcs, vcs->clipping.right - vcs->clipping.left, vcs->clipping.bottom - vcs->clipping.top); @@ -1649,7 +1737,8 @@ static void vino_set_framerate(struct vino_channel_settings *vcs, } /* execute with input_lock locked */ -static void vino_set_default_framerate(struct vino_channel_settings *vcs) +static inline void vino_set_default_framerate(struct + vino_channel_settings *vcs) { vino_set_framerate(vcs, vino_data_norms[vcs->data_norm].fps_max); } @@ -1687,6 +1776,9 @@ static int vino_dma_setup(struct vino_channel_settings *vcs, * should be more than enough time */ udelay(VINO_DESC_FETCH_DELAY); + dprintk("vino_dma_setup(): start desc = %08x, next 4 desc = %08x\n", + ch->start_desc_tbl, ch->next_4_desc); + /* set the alpha register */ ch->alpha = vcs->alpha; @@ -1700,9 +1792,6 @@ static int vino_dma_setup(struct vino_channel_settings *vcs, VINO_CLIP_EVEN(norm->even.top + vcs->clipping.bottom / 2 - 1) | VINO_CLIP_X(vcs->clipping.right); - /* FIXME: end-of-field bug workaround - VINO_CLIP_X(VINO_PAL_WIDTH); - */ /* set the size of actual content in the buffer (DECIMATION !) */ fb->data_size = ((vcs->clipping.right - vcs->clipping.left) / @@ -1802,7 +1891,7 @@ static int vino_dma_setup(struct vino_channel_settings *vcs, } /* (execute only with vino_lock locked) */ -static void vino_dma_start(struct vino_channel_settings *vcs) +static inline void vino_dma_start(struct vino_channel_settings *vcs) { u32 ctrl = vino->control; @@ -1813,12 +1902,14 @@ static void vino_dma_start(struct vino_channel_settings *vcs) } /* (execute only with vino_lock locked) */ -static void vino_dma_stop(struct vino_channel_settings *vcs) +static inline void vino_dma_stop(struct vino_channel_settings *vcs) { u32 ctrl = vino->control; ctrl &= (vcs->channel == VINO_CHANNEL_A) ? ~VINO_CTRL_A_DMA_ENBL : ~VINO_CTRL_B_DMA_ENBL; + ctrl &= (vcs->channel == VINO_CHANNEL_A) ? + ~VINO_CTRL_A_INT : ~VINO_CTRL_B_INT; vino->control = ctrl; dprintk("vino_dma_stop():\n"); } @@ -1902,7 +1993,7 @@ static int vino_capture_next(struct vino_channel_settings *vcs, int start) struct vino_framebuffer *fb; unsigned int incoming, id; int err = 0; - unsigned long flags, flags2; + unsigned long flags; dprintk("vino_capture_next():\n"); @@ -1943,10 +2034,6 @@ static int vino_capture_next(struct vino_channel_settings *vcs, int start) goto out; } - spin_lock_irqsave(&fb->state_lock, flags2); - fb->state = VINO_FRAMEBUFFER_UNUSED; - spin_unlock_irqrestore(&fb->state_lock, flags2); - if (start) { vcs->capturing = 1; } @@ -1964,7 +2051,7 @@ static int vino_capture_next(struct vino_channel_settings *vcs, int start) return err; } -static int vino_is_capturing(struct vino_channel_settings *vcs) +static inline int vino_is_capturing(struct vino_channel_settings *vcs) { int ret; unsigned long flags; @@ -2076,6 +2163,7 @@ static void vino_capture_stop(struct vino_channel_settings *vcs) dprintk("vino_capture_stop():\n"); spin_lock_irqsave(&vcs->capture_lock, flags); + /* unset capturing to stop queue processing */ vcs->capturing = 0; @@ -2121,6 +2209,7 @@ static void vino_capture_stop(struct vino_channel_settings *vcs) spin_unlock_irqrestore(&vcs->capture_lock, flags); } +#if 0 static int vino_capture_failed(struct vino_channel_settings *vcs) { struct vino_framebuffer *fb; @@ -2165,9 +2254,31 @@ static int vino_capture_failed(struct vino_channel_settings *vcs) return 0; } +#endif + +static void vino_skip_frame(struct vino_channel_settings *vcs) +{ + struct vino_framebuffer *fb; + unsigned long flags; + unsigned int id; + + spin_lock_irqsave(&vcs->capture_lock, flags); + fb = vino_queue_peek(&vcs->fb_queue, &id); + if (!fb) { + spin_unlock_irqrestore(&vcs->capture_lock, flags); + dprintk("vino_skip_frame(): vino_queue_peek() failed!\n"); + return; + } + spin_unlock_irqrestore(&vcs->capture_lock, flags); + + spin_lock_irqsave(&fb->state_lock, flags); + fb->state = VINO_FRAMEBUFFER_UNUSED; + spin_unlock_irqrestore(&fb->state_lock, flags); + + vino_capture_next(vcs, 0); +} -static void vino_frame_done(struct vino_channel_settings *vcs, - unsigned int fc) +static void vino_frame_done(struct vino_channel_settings *vcs) { struct vino_framebuffer *fb; unsigned long flags; @@ -2181,8 +2292,9 @@ static void vino_frame_done(struct vino_channel_settings *vcs, } spin_unlock_irqrestore(&vcs->capture_lock, flags); - fb->frame_counter = fc; - do_gettimeofday(&fb->timestamp); + fb->frame_counter = vcs->int_data.frame_counter; + memcpy(&fb->timestamp, &vcs->int_data.timestamp, + sizeof(struct timeval)); spin_lock_irqsave(&fb->state_lock, flags); if (fb->state == VINO_FRAMEBUFFER_IN_USE) @@ -2194,72 +2306,175 @@ static void vino_frame_done(struct vino_channel_settings *vcs, vino_capture_next(vcs, 0); } +static void vino_capture_tasklet(unsigned long channel) { + struct vino_channel_settings *vcs; + + vcs = (channel == VINO_CHANNEL_A) + ? &vino_drvdata->a : &vino_drvdata->b; + + if (vcs->int_data.skip) + vcs->int_data.skip_count++; + + if (vcs->int_data.skip && (vcs->int_data.skip_count + <= VINO_MAX_FRAME_SKIP_COUNT)) { + vino_skip_frame(vcs); + } else { + vcs->int_data.skip_count = 0; + vino_frame_done(vcs); + } +} + static irqreturn_t vino_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - u32 intr; + u32 ctrl, intr; unsigned int fc_a, fc_b; - int done_a = 0; - int done_b = 0; + int handled_a = 0, skip_a = 0, done_a = 0; + int handled_b = 0, skip_b = 0, done_b = 0; + +#ifdef VINO_DEBUG_INT + int loop = 0; + unsigned int line_count = vino->a.line_count, + page_index = vino->a.page_index, + field_counter = vino->a.field_counter, + start_desc_tbl = vino->a.start_desc_tbl, + next_4_desc = vino->a.next_4_desc; + unsigned int line_count_2, + page_index_2, + field_counter_2, + start_desc_tbl_2, + next_4_desc_2; +#endif spin_lock(&vino_drvdata->vino_lock); - intr = vino->intr_status; - fc_a = vino->a.field_counter / 2; - fc_b = vino->b.field_counter / 2; - - // TODO: handle error-interrupts in some special way ? - - if (intr & VINO_INTSTAT_A) { - if (intr & VINO_INTSTAT_A_EOF) { - vino_drvdata->a.field++; - if (vino_drvdata->a.field > 1) { + while ((intr = vino->intr_status)) { + fc_a = vino->a.field_counter >> 1; + fc_b = vino->b.field_counter >> 1; + + /* handle error-interrupts in some special way ? + * --> skips frames */ + if (intr & VINO_INTSTAT_A) { + if (intr & VINO_INTSTAT_A_EOF) { + vino_drvdata->a.field++; + if (vino_drvdata->a.field > 1) { + vino_dma_stop(&vino_drvdata->a); + vino_clear_interrupt(&vino_drvdata->a); + vino_drvdata->a.field = 0; + done_a = 1; + } else { + if (vino->a.page_index + != vino_drvdata->a.line_size) { + vino->a.line_count = 0; + vino->a.page_index = + vino_drvdata-> + a.line_size; + vino->a.next_4_desc = + vino->a.start_desc_tbl; + } + } + dprintk("channel A end-of-field " + "interrupt: %04x\n", intr); + } else { vino_dma_stop(&vino_drvdata->a); vino_clear_interrupt(&vino_drvdata->a); vino_drvdata->a.field = 0; - done_a = 1; + skip_a = 1; + dprintk("channel A error interrupt: %04x\n", + intr); } - dprintk("intr: channel A end-of-field interrupt: " - "%04x\n", intr); - } else { - vino_dma_stop(&vino_drvdata->a); - vino_clear_interrupt(&vino_drvdata->a); - done_a = 1; - dprintk("channel A error interrupt: %04x\n", intr); + +#ifdef VINO_DEBUG_INT + line_count_2 = vino->a.line_count; + page_index_2 = vino->a.page_index; + field_counter_2 = vino->a.field_counter; + start_desc_tbl_2 = vino->a.start_desc_tbl; + next_4_desc_2 = vino->a.next_4_desc; + + printk("intr = %04x, loop = %d, field = %d\n", + intr, loop, vino_drvdata->a.field); + printk("1- line count = %04d, page index = %04d, " + "start = %08x, next = %08x\n" + " fieldc = %d, framec = %d\n", + line_count, page_index, start_desc_tbl, + next_4_desc, field_counter, fc_a); + printk("12-line count = %04d, page index = %04d, " + " start = %08x, next = %08x\n", + line_count_2, page_index_2, start_desc_tbl_2, + next_4_desc_2); + + if (done_a) + printk("\n"); +#endif } - } - if (intr & VINO_INTSTAT_B) { - if (intr & VINO_INTSTAT_B_EOF) { - vino_drvdata->b.field++; - if (vino_drvdata->b.field > 1) { + + if (intr & VINO_INTSTAT_B) { + if (intr & VINO_INTSTAT_B_EOF) { + vino_drvdata->b.field++; + if (vino_drvdata->b.field > 1) { + vino_dma_stop(&vino_drvdata->b); + vino_clear_interrupt(&vino_drvdata->b); + vino_drvdata->b.field = 0; + done_b = 1; + } + dprintk("channel B end-of-field " + "interrupt: %04x\n", intr); + } else { vino_dma_stop(&vino_drvdata->b); vino_clear_interrupt(&vino_drvdata->b); vino_drvdata->b.field = 0; - done_b = 1; + skip_b = 1; + dprintk("channel B error interrupt: %04x\n", + intr); } - dprintk("intr: channel B end-of-field interrupt: " - "%04x\n", intr); - } else { - vino_dma_stop(&vino_drvdata->b); - vino_clear_interrupt(&vino_drvdata->b); - done_b = 1; - dprintk("channel B error interrupt: %04x\n", intr); } - } - /* always remember to clear interrupt status */ - vino->intr_status = ~intr; + /* Always remember to clear interrupt status. + * Disable VINO interrupts while we do this. */ + ctrl = vino->control; + vino->control = ctrl & ~(VINO_CTRL_A_INT | VINO_CTRL_B_INT); + vino->intr_status = ~intr; + vino->control = ctrl; - spin_unlock(&vino_drvdata->vino_lock); + spin_unlock(&vino_drvdata->vino_lock); - if (done_a) { - vino_frame_done(&vino_drvdata->a, fc_a); - dprintk("channel A frame done, interrupt: %d\n", intr); - } - if (done_b) { - vino_frame_done(&vino_drvdata->b, fc_b); - dprintk("channel B frame done, interrupt: %d\n", intr); + if ((!handled_a) && (done_a || skip_a)) { + if (!skip_a) { + do_gettimeofday(&vino_drvdata-> + a.int_data.timestamp); + vino_drvdata->a.int_data.frame_counter = fc_a; + } + vino_drvdata->a.int_data.skip = skip_a; + + dprintk("channel A %s, interrupt: %d\n", + skip_a ? "skipping frame" : "frame done", + intr); + tasklet_hi_schedule(&vino_tasklet_a); + handled_a = 1; + } + + if ((!handled_b) && (done_b || skip_b)) { + if (!skip_b) { + do_gettimeofday(&vino_drvdata-> + b.int_data.timestamp); + vino_drvdata->b.int_data.frame_counter = fc_b; + } + vino_drvdata->b.int_data.skip = skip_b; + + dprintk("channel B %s, interrupt: %d\n", + skip_b ? "skipping frame" : "frame done", + intr); + tasklet_hi_schedule(&vino_tasklet_b); + handled_b = 1; + } + +#ifdef VINO_DEBUG_INT + loop++; +#endif + spin_lock(&vino_drvdata->vino_lock); } + spin_unlock(&vino_drvdata->vino_lock); + return IRQ_HANDLED; } @@ -2279,11 +2494,13 @@ static int vino_get_saa7191_input(int input) } } -static int vino_get_saa7191_norm(int norm) +static int vino_get_saa7191_norm(unsigned int data_norm) { - switch (norm) { + switch (data_norm) { case VINO_DATA_NORM_AUTO: return SAA7191_NORM_AUTO; + case VINO_DATA_NORM_AUTO_EXT: + return SAA7191_NORM_AUTO_EXT; case VINO_DATA_NORM_PAL: return SAA7191_NORM_PAL; case VINO_DATA_NORM_NTSC: @@ -2297,6 +2514,57 @@ static int vino_get_saa7191_norm(int norm) } } +static int vino_get_from_saa7191_norm(int saa7191_norm) +{ + switch (saa7191_norm) { + case SAA7191_NORM_PAL: + return VINO_DATA_NORM_PAL; + case SAA7191_NORM_NTSC: + return VINO_DATA_NORM_NTSC; + case SAA7191_NORM_SECAM: + return VINO_DATA_NORM_SECAM; + default: + printk(KERN_ERR "VINO: vino_get_from_saa7191_norm(): " + "invalid norm!\n"); + return VINO_DATA_NORM_NONE; + } +} + +static int vino_saa7191_set_norm(unsigned int *data_norm) +{ + int saa7191_norm, new_data_norm; + int err = 0; + + saa7191_norm = vino_get_saa7191_norm(*data_norm); + + err = i2c_decoder_command(DECODER_SAA7191_SET_NORM, + &saa7191_norm); + if (err) + goto out; + + if ((*data_norm == VINO_DATA_NORM_AUTO) + || (*data_norm == VINO_DATA_NORM_AUTO_EXT)) { + struct saa7191_status status; + + err = i2c_decoder_command(DECODER_SAA7191_GET_STATUS, + &status); + if (err) + goto out; + + new_data_norm = + vino_get_from_saa7191_norm(status.norm); + if (new_data_norm == VINO_DATA_NORM_NONE) { + err = -EINVAL; + goto out; + } + + *data_norm = (unsigned int)new_data_norm; + } + +out: + return err; +} + /* execute with input_lock locked */ static int vino_is_input_owner(struct vino_channel_settings *vcs) { @@ -2313,11 +2581,12 @@ static int vino_is_input_owner(struct vino_channel_settings *vcs) static int vino_acquire_input(struct vino_channel_settings *vcs) { + unsigned long flags; int ret = 0; dprintk("vino_acquire_input():\n"); - spin_lock(&vino_drvdata->input_lock); + spin_lock_irqsave(&vino_drvdata->input_lock, flags); /* First try D1 and then SAA7191 */ if (vino_drvdata->camera.driver @@ -2332,23 +2601,48 @@ static int vino_acquire_input(struct vino_channel_settings *vcs) vcs->data_norm = VINO_DATA_NORM_D1; } else if (vino_drvdata->decoder.driver && (vino_drvdata->decoder.owner == VINO_NO_CHANNEL)) { + int input, data_norm; int saa7191_input; - int saa7191_norm; if (i2c_use_client(vino_drvdata->decoder.driver)) { ret = -ENODEV; goto out; } - vino_drvdata->decoder.owner = vcs->channel; - vcs->input = VINO_INPUT_COMPOSITE; - vcs->data_norm = VINO_DATA_NORM_PAL; + input = VINO_INPUT_COMPOSITE; + + saa7191_input = vino_get_saa7191_input(input); + ret = i2c_decoder_command(DECODER_SET_INPUT, + &saa7191_input); + if (ret) { + ret = -EINVAL; + goto out; + } + + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); - saa7191_input = vino_get_saa7191_input(vcs->input); - i2c_decoder_command(DECODER_SET_INPUT, &saa7191_input); + /* Don't hold spinlocks while auto-detecting norm + * as it may take a while... */ - saa7191_norm = vino_get_saa7191_norm(vcs->data_norm); - i2c_decoder_command(DECODER_SAA7191_SET_NORM, &saa7191_norm); + data_norm = VINO_DATA_NORM_AUTO_EXT; + + ret = vino_saa7191_set_norm(&data_norm); + if ((ret == -EBUSY) || (ret == -EAGAIN)) { + data_norm = VINO_DATA_NORM_PAL; + ret = vino_saa7191_set_norm(&data_norm); + } + + spin_lock_irqsave(&vino_drvdata->input_lock, flags); + + if (ret) { + ret = -EINVAL; + goto out; + } + + vino_drvdata->decoder.owner = vcs->channel; + + vcs->input = input; + vcs->data_norm = data_norm; } else { vcs->input = (vcs->channel == VINO_CHANNEL_A) ? vino_drvdata->b.input : vino_drvdata->a.input; @@ -2361,15 +2655,14 @@ static int vino_acquire_input(struct vino_channel_settings *vcs) goto out; } - if (vino_is_input_owner(vcs)) { - vino_set_default_clipping(vcs); - vino_set_default_framerate(vcs); - } + vino_set_default_clipping(vcs); + vino_set_default_scaling(vcs); + vino_set_default_framerate(vcs); dprintk("vino_acquire_input(): %s\n", vino_inputs[vcs->input].name); out: - spin_unlock(&vino_drvdata->input_lock); + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); return ret; } @@ -2378,16 +2671,17 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input) { struct vino_channel_settings *vcs2 = (vcs->channel == VINO_CHANNEL_A) ? &vino_drvdata->b : &vino_drvdata->a; + unsigned long flags; int ret = 0; dprintk("vino_set_input():\n"); - spin_lock(&vino_drvdata->input_lock); + spin_lock_irqsave(&vino_drvdata->input_lock, flags); if (vcs->input == input) goto out; - switch(input) { + switch (input) { case VINO_INPUT_COMPOSITE: case VINO_INPUT_SVIDEO: if (!vino_drvdata->decoder.driver) { @@ -2404,19 +2698,43 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input) } if (vino_drvdata->decoder.owner == vcs->channel) { + int data_norm; int saa7191_input; - int saa7191_norm; - vcs->input = input; - vcs->data_norm = VINO_DATA_NORM_PAL; + saa7191_input = vino_get_saa7191_input(input); + ret = i2c_decoder_command(DECODER_SET_INPUT, + &saa7191_input); + if (ret) { + vino_drvdata->decoder.owner = VINO_NO_CHANNEL; + ret = -EINVAL; + goto out; + } + + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); + + /* Don't hold spinlocks while auto-detecting norm + * as it may take a while... */ + + data_norm = VINO_DATA_NORM_AUTO_EXT; + + ret = vino_saa7191_set_norm(&data_norm); + if ((ret == -EBUSY) || (ret == -EAGAIN)) { + data_norm = VINO_DATA_NORM_PAL; + ret = vino_saa7191_set_norm(&data_norm); + } - saa7191_input = vino_get_saa7191_input(vcs->input); - i2c_decoder_command(DECODER_SET_INPUT, &saa7191_input); - saa7191_norm = vino_get_saa7191_norm(vcs->data_norm); - i2c_decoder_command(DECODER_SAA7191_SET_NORM, - &saa7191_norm); + spin_lock_irqsave(&vino_drvdata->input_lock, flags); + + if (ret) { + vino_drvdata->decoder.owner = VINO_NO_CHANNEL; + ret = -EINVAL; + goto out; + } + + vcs->input = input; + vcs->data_norm = data_norm; } else { - if (vcs2->input != input) { + if (input != vcs2->input) { ret = -EBUSY; goto out; } @@ -2471,12 +2789,13 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input) } vino_set_default_clipping(vcs); + vino_set_default_scaling(vcs); vino_set_default_framerate(vcs); dprintk("vino_set_input(): %s\n", vino_inputs[vcs->input].name); out: - spin_unlock(&vino_drvdata->input_lock); + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); return ret; } @@ -2485,10 +2804,11 @@ static void vino_release_input(struct vino_channel_settings *vcs) { struct vino_channel_settings *vcs2 = (vcs->channel == VINO_CHANNEL_A) ? &vino_drvdata->b : &vino_drvdata->a; + unsigned long flags; dprintk("vino_release_input():\n"); - spin_lock(&vino_drvdata->input_lock); + spin_lock_irqsave(&vino_drvdata->input_lock, flags); /* Release ownership of the channel * and if the other channel takes input from @@ -2511,34 +2831,61 @@ static void vino_release_input(struct vino_channel_settings *vcs) } vcs->input = VINO_INPUT_NONE; - spin_unlock(&vino_drvdata->input_lock); + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); } /* execute with input_lock locked */ static int vino_set_data_norm(struct vino_channel_settings *vcs, - unsigned int data_norm) + unsigned int data_norm, + unsigned long *flags) { - int saa7191_norm; + int err = 0; + + if (data_norm == vcs->data_norm) + return 0; switch (vcs->input) { case VINO_INPUT_D1: /* only one "norm" supported */ - if (data_norm != VINO_DATA_NORM_D1) + if ((data_norm != VINO_DATA_NORM_D1) + && (data_norm != VINO_DATA_NORM_AUTO) + && (data_norm != VINO_DATA_NORM_AUTO_EXT)) return -EINVAL; break; case VINO_INPUT_COMPOSITE: - case VINO_INPUT_SVIDEO: + case VINO_INPUT_SVIDEO: { + if ((data_norm != VINO_DATA_NORM_PAL) + && (data_norm != VINO_DATA_NORM_NTSC) + && (data_norm != VINO_DATA_NORM_SECAM) + && (data_norm != VINO_DATA_NORM_AUTO) + && (data_norm != VINO_DATA_NORM_AUTO_EXT)) + return -EINVAL; - saa7191_norm = vino_get_saa7191_norm(data_norm); + spin_unlock_irqrestore(&vino_drvdata->input_lock, *flags); + + /* Don't hold spinlocks while setting norm + * as it may take a while... */ + + err = vino_saa7191_set_norm(&data_norm); + + spin_lock_irqsave(&vino_drvdata->input_lock, *flags); + + if (err) + goto out; - i2c_decoder_command(DECODER_SAA7191_SET_NORM, &saa7191_norm); vcs->data_norm = data_norm; + + vino_set_default_clipping(vcs); + vino_set_default_scaling(vcs); + vino_set_default_framerate(vcs); break; + } default: return -EINVAL; } - return 0; +out: + return err; } /* V4L2 helper functions */ @@ -2558,8 +2905,9 @@ static int vino_find_data_format(__u32 pixelformat) static int vino_enum_data_norm(struct vino_channel_settings *vcs, __u32 index) { int data_norm = VINO_DATA_NORM_NONE; + unsigned long flags; - spin_lock(&vino_drvdata->input_lock); + spin_lock_irqsave(&vino_drvdata->input_lock, flags); switch(vcs->input) { case VINO_INPUT_COMPOSITE: case VINO_INPUT_SVIDEO: @@ -2577,7 +2925,7 @@ static int vino_enum_data_norm(struct vino_channel_settings *vcs, __u32 index) } break; } - spin_unlock(&vino_drvdata->input_lock); + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); return data_norm; } @@ -2585,8 +2933,9 @@ static int vino_enum_data_norm(struct vino_channel_settings *vcs, __u32 index) static int vino_enum_input(struct vino_channel_settings *vcs, __u32 index) { int input = VINO_INPUT_NONE; + unsigned long flags; - spin_lock(&vino_drvdata->input_lock); + spin_lock_irqsave(&vino_drvdata->input_lock, flags); if (vino_drvdata->decoder.driver && vino_drvdata->camera.driver) { switch (index) { case 0: @@ -2615,7 +2964,7 @@ static int vino_enum_input(struct vino_channel_settings *vcs, __u32 index) break; } } - spin_unlock(&vino_drvdata->input_lock); + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); return input; } @@ -2704,15 +3053,16 @@ static int vino_v4l2_enuminput(struct vino_channel_settings *vcs, } static int vino_v4l2_g_input(struct vino_channel_settings *vcs, - struct v4l2_input *i) + unsigned int *i) { __u32 index; int input; + unsigned long flags; - spin_lock(&vino_drvdata->input_lock); + spin_lock_irqsave(&vino_drvdata->input_lock, flags); input = vcs->input; index = vino_find_input_index(vcs); - spin_unlock(&vino_drvdata->input_lock); + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); dprintk("input = %d\n", input); @@ -2720,23 +3070,18 @@ static int vino_v4l2_g_input(struct vino_channel_settings *vcs, return -EINVAL; } - memset(i, 0, sizeof(struct v4l2_input)); - - i->index = index; - i->type = V4L2_INPUT_TYPE_CAMERA; - i->std = vino_inputs[input].std; - strcpy(i->name, vino_inputs[input].name); + *i = index; return 0; } static int vino_v4l2_s_input(struct vino_channel_settings *vcs, - struct v4l2_input *i) + unsigned int *i) { int input; - dprintk("requested input = %d\n", i->index); + dprintk("requested input = %d\n", *i); - input = vino_enum_input(vcs, i->index); + input = vino_enum_input(vcs, *i); if (input == VINO_INPUT_NONE) return -EINVAL; @@ -2747,7 +3092,9 @@ static int vino_v4l2_enumstd(struct vino_channel_settings *vcs, struct v4l2_standard *s) { int index = s->index; - int data_norm = vino_enum_data_norm(vcs, index); + int data_norm; + + data_norm = vino_enum_data_norm(vcs, index); dprintk("standard index = %d\n", index); if (data_norm == VINO_DATA_NORM_NONE) @@ -2771,13 +3118,55 @@ static int vino_v4l2_enumstd(struct vino_channel_settings *vcs, return 0; } +static int vino_v4l2_querystd(struct vino_channel_settings *vcs, + v4l2_std_id *std) +{ + unsigned long flags; + int err = 0; + + spin_lock_irqsave(&vino_drvdata->input_lock, flags); + + switch (vcs->input) { + case VINO_INPUT_D1: + *std = vino_inputs[vcs->input].std; + break; + case VINO_INPUT_COMPOSITE: + case VINO_INPUT_SVIDEO: { + struct saa7191_status status; + + i2c_decoder_command(DECODER_SAA7191_GET_STATUS, &status); + + if (status.signal) { + if (status.signal_60hz) { + *std = V4L2_STD_NTSC; + } else { + *std = V4L2_STD_PAL | V4L2_STD_SECAM; + } + } else { + *std = vino_inputs[vcs->input].std; + } + break; + } + default: + err = -EINVAL; + } + + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); + + return err; +} + static int vino_v4l2_g_std(struct vino_channel_settings *vcs, v4l2_std_id *std) { - spin_lock(&vino_drvdata->input_lock); - dprintk("current standard = %d\n", vcs->data_norm); + unsigned long flags; + + spin_lock_irqsave(&vino_drvdata->input_lock, flags); + *std = vino_data_norms[vcs->data_norm].std; - spin_unlock(&vino_drvdata->input_lock); + dprintk("current standard = %d\n", vcs->data_norm); + + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); return 0; } @@ -2785,13 +3174,18 @@ static int vino_v4l2_g_std(struct vino_channel_settings *vcs, static int vino_v4l2_s_std(struct vino_channel_settings *vcs, v4l2_std_id *std) { + unsigned long flags; int ret = 0; - spin_lock(&vino_drvdata->input_lock); + spin_lock_irqsave(&vino_drvdata->input_lock, flags); + + if (!vino_is_input_owner(vcs)) { + ret = -EBUSY; + goto out; + } /* check if the standard is valid for the current input */ - if (vino_is_input_owner(vcs) - && (vino_inputs[vcs->input].std & (*std))) { + if ((*std) & vino_inputs[vcs->input].std) { dprintk("standard accepted\n"); /* change the video norm for SAA7191 @@ -2800,24 +3194,33 @@ static int vino_v4l2_s_std(struct vino_channel_settings *vcs, if (vcs->input == VINO_INPUT_D1) goto out; - if ((*std) & V4L2_STD_PAL) { - vino_set_data_norm(vcs, VINO_DATA_NORM_PAL); - vcs->data_norm = VINO_DATA_NORM_PAL; + if (((*std) & V4L2_STD_PAL) + && ((*std) & V4L2_STD_NTSC) + && ((*std) & V4L2_STD_SECAM)) { + ret = vino_set_data_norm(vcs, VINO_DATA_NORM_AUTO_EXT, + &flags); + } else if ((*std) & V4L2_STD_PAL) { + ret = vino_set_data_norm(vcs, VINO_DATA_NORM_PAL, + &flags); } else if ((*std) & V4L2_STD_NTSC) { - vino_set_data_norm(vcs, VINO_DATA_NORM_NTSC); - vcs->data_norm = VINO_DATA_NORM_NTSC; + ret = vino_set_data_norm(vcs, VINO_DATA_NORM_NTSC, + &flags); } else if ((*std) & V4L2_STD_SECAM) { - vino_set_data_norm(vcs, VINO_DATA_NORM_SECAM); - vcs->data_norm = VINO_DATA_NORM_SECAM; + ret = vino_set_data_norm(vcs, VINO_DATA_NORM_SECAM, + &flags); } else { ret = -EINVAL; } + + if (ret) { + ret = -EINVAL; + } } else { ret = -EINVAL; } out: - spin_unlock(&vino_drvdata->input_lock); + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); return ret; } @@ -2855,6 +3258,7 @@ static int vino_v4l2_try_fmt(struct vino_channel_settings *vcs, struct v4l2_format *f) { struct vino_channel_settings tempvcs; + unsigned long flags; switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: { @@ -2863,13 +3267,13 @@ static int vino_v4l2_try_fmt(struct vino_channel_settings *vcs, dprintk("requested: w = %d, h = %d\n", pf->width, pf->height); - spin_lock(&vino_drvdata->input_lock); + spin_lock_irqsave(&vino_drvdata->input_lock, flags); memcpy(&tempvcs, vcs, sizeof(struct vino_channel_settings)); - spin_unlock(&vino_drvdata->input_lock); + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); tempvcs.data_format = vino_find_data_format(pf->pixelformat); if (tempvcs.data_format == VINO_DATA_FMT_NONE) { - tempvcs.data_format = VINO_DATA_FMT_RGB32; + tempvcs.data_format = VINO_DATA_FMT_GREY; pf->pixelformat = vino_data_formats[tempvcs.data_format]. pixelformat; @@ -2908,10 +3312,13 @@ static int vino_v4l2_try_fmt(struct vino_channel_settings *vcs, static int vino_v4l2_g_fmt(struct vino_channel_settings *vcs, struct v4l2_format *f) { + unsigned long flags; + switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: { struct v4l2_pix_format *pf = &f->fmt.pix; - spin_lock(&vino_drvdata->input_lock); + + spin_lock_irqsave(&vino_drvdata->input_lock, flags); pf->width = (vcs->clipping.right - vcs->clipping.left) / vcs->decimation; @@ -2930,7 +3337,7 @@ static int vino_v4l2_g_fmt(struct vino_channel_settings *vcs, pf->priv = 0; - spin_unlock(&vino_drvdata->input_lock); + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); break; } case V4L2_BUF_TYPE_VIDEO_OVERLAY: @@ -2945,20 +3352,18 @@ static int vino_v4l2_s_fmt(struct vino_channel_settings *vcs, struct v4l2_format *f) { int data_format; + unsigned long flags; switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: { struct v4l2_pix_format *pf = &f->fmt.pix; - spin_lock(&vino_drvdata->input_lock); - if (!vino_is_input_owner(vcs)) { - spin_unlock(&vino_drvdata->input_lock); - return -EINVAL; - } + spin_lock_irqsave(&vino_drvdata->input_lock, flags); data_format = vino_find_data_format(pf->pixelformat); + if (data_format == VINO_DATA_FMT_NONE) { - vcs->data_format = VINO_DATA_FMT_RGB32; + vcs->data_format = VINO_DATA_FMT_GREY; pf->pixelformat = vino_data_formats[vcs->data_format]. pixelformat; @@ -2985,7 +3390,7 @@ static int vino_v4l2_s_fmt(struct vino_channel_settings *vcs, pf->priv = 0; - spin_unlock(&vino_drvdata->input_lock); + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); break; } case V4L2_BUF_TYPE_VIDEO_OVERLAY: @@ -3000,12 +3405,15 @@ static int vino_v4l2_cropcap(struct vino_channel_settings *vcs, struct v4l2_cropcap *ccap) { const struct vino_data_norm *norm; + unsigned long flags; switch (ccap->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - spin_lock(&vino_drvdata->input_lock); + spin_lock_irqsave(&vino_drvdata->input_lock, flags); + norm = &vino_data_norms[vcs->data_norm]; - spin_unlock(&vino_drvdata->input_lock); + + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); ccap->bounds.left = 0; ccap->bounds.top = 0; @@ -3028,16 +3436,18 @@ static int vino_v4l2_cropcap(struct vino_channel_settings *vcs, static int vino_v4l2_g_crop(struct vino_channel_settings *vcs, struct v4l2_crop *c) { + unsigned long flags; + switch (c->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - spin_lock(&vino_drvdata->input_lock); + spin_lock_irqsave(&vino_drvdata->input_lock, flags); c->c.left = vcs->clipping.left; c->c.top = vcs->clipping.top; c->c.width = vcs->clipping.right - vcs->clipping.left; c->c.height = vcs->clipping.bottom - vcs->clipping.top; - spin_unlock(&vino_drvdata->input_lock); + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: default: @@ -3050,18 +3460,16 @@ static int vino_v4l2_g_crop(struct vino_channel_settings *vcs, static int vino_v4l2_s_crop(struct vino_channel_settings *vcs, struct v4l2_crop *c) { + unsigned long flags; + switch (c->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - spin_lock(&vino_drvdata->input_lock); + spin_lock_irqsave(&vino_drvdata->input_lock, flags); - if (!vino_is_input_owner(vcs)) { - spin_unlock(&vino_drvdata->input_lock); - return -EINVAL; - } vino_set_clipping(vcs, c->c.left, c->c.top, c->c.width, c->c.height); - spin_unlock(&vino_drvdata->input_lock); + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: default: @@ -3074,6 +3482,8 @@ static int vino_v4l2_s_crop(struct vino_channel_settings *vcs, static int vino_v4l2_g_parm(struct vino_channel_settings *vcs, struct v4l2_streamparm *sp) { + unsigned long flags; + switch (sp->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: { struct v4l2_captureparm *cp = &sp->parm.capture; @@ -3082,9 +3492,11 @@ static int vino_v4l2_g_parm(struct vino_channel_settings *vcs, cp->capability = V4L2_CAP_TIMEPERFRAME; cp->timeperframe.numerator = 1; - spin_lock(&vino_drvdata->input_lock); + spin_lock_irqsave(&vino_drvdata->input_lock, flags); + cp->timeperframe.denominator = vcs->fps; - spin_unlock(&vino_drvdata->input_lock); + + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); // TODO: cp->readbuffers = xxx; break; @@ -3100,15 +3512,13 @@ static int vino_v4l2_g_parm(struct vino_channel_settings *vcs, static int vino_v4l2_s_parm(struct vino_channel_settings *vcs, struct v4l2_streamparm *sp) { + unsigned long flags; + switch (sp->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: { struct v4l2_captureparm *cp = &sp->parm.capture; - spin_lock(&vino_drvdata->input_lock); - if (!vino_is_input_owner(vcs)) { - spin_unlock(&vino_drvdata->input_lock); - return -EINVAL; - } + spin_lock_irqsave(&vino_drvdata->input_lock, flags); if ((cp->timeperframe.numerator == 0) || (cp->timeperframe.denominator == 0)) { @@ -3118,7 +3528,8 @@ static int vino_v4l2_s_parm(struct vino_channel_settings *vcs, vino_set_framerate(vcs, cp->timeperframe.denominator / cp->timeperframe.numerator); } - spin_unlock(&vino_drvdata->input_lock); + + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); // TODO: set buffers according to cp->readbuffers break; @@ -3145,21 +3556,23 @@ static int vino_v4l2_reqbufs(struct vino_channel_settings *vcs, return -EINVAL; } - if (vino_is_capturing(vcs)) { - dprintk("busy, capturing\n"); - return -EBUSY; - } - dprintk("count = %d\n", rb->count); if (rb->count > 0) { + if (vino_is_capturing(vcs)) { + dprintk("busy, capturing\n"); + return -EBUSY; + } + if (vino_queue_has_mapped_buffers(&vcs->fb_queue)) { dprintk("busy, buffers still mapped\n"); return -EBUSY; } else { + vcs->streaming = 0; vino_queue_free(&vcs->fb_queue); vino_queue_init(&vcs->fb_queue, &rb->count); } } else { + vcs->streaming = 0; vino_capture_stop(vcs); vino_queue_free(&vcs->fb_queue); } @@ -3302,12 +3715,12 @@ static int vino_v4l2_dqbuf(struct vino_channel_settings *vcs, err = vino_queue_get_incoming(&vcs->fb_queue, &incoming); if (err) { dprintk("vino_queue_get_incoming() failed\n"); - return -EIO; + return -EINVAL; } err = vino_queue_get_outgoing(&vcs->fb_queue, &outgoing); if (err) { dprintk("vino_queue_get_outgoing() failed\n"); - return -EIO; + return -EINVAL; } dprintk("incoming = %d, outgoing = %d\n", incoming, outgoing); @@ -3327,8 +3740,10 @@ static int vino_v4l2_dqbuf(struct vino_channel_settings *vcs, if (err) { err = vino_wait_for_frame(vcs); if (err) { - /* interrupted */ - vino_capture_failed(vcs); + /* interrupted or + * no frames captured because + * of frame skipping */ + // vino_capture_failed(vcs); return -EIO; } } @@ -3341,10 +3756,12 @@ static int vino_v4l2_dqbuf(struct vino_channel_settings *vcs, } err = vino_check_buffer(vcs, fb); + + vino_v4l2_get_buffer_status(vcs, fb, b); + if (err) return -EIO; - vino_v4l2_get_buffer_status(vcs, fb, b); break; } case V4L2_BUF_TYPE_VIDEO_OVERLAY: @@ -3401,8 +3818,8 @@ static int vino_v4l2_streamoff(struct vino_channel_settings *vcs) if (!vcs->streaming) return 0; - vino_capture_stop(vcs); vcs->streaming = 0; + vino_capture_stop(vcs); return 0; } @@ -3410,10 +3827,11 @@ static int vino_v4l2_streamoff(struct vino_channel_settings *vcs) static int vino_v4l2_queryctrl(struct vino_channel_settings *vcs, struct v4l2_queryctrl *queryctrl) { + unsigned long flags; int i; int err = 0; - spin_lock(&vino_drvdata->input_lock); + spin_lock_irqsave(&vino_drvdata->input_lock, flags); switch (vcs->input) { case VINO_INPUT_D1: @@ -3423,6 +3841,7 @@ static int vino_v4l2_queryctrl(struct vino_channel_settings *vcs, memcpy(queryctrl, &vino_indycam_v4l2_controls[i], sizeof(struct v4l2_queryctrl)); + queryctrl->reserved[0] = 0; goto found; } } @@ -3437,6 +3856,7 @@ static int vino_v4l2_queryctrl(struct vino_channel_settings *vcs, memcpy(queryctrl, &vino_saa7191_v4l2_controls[i], sizeof(struct v4l2_queryctrl)); + queryctrl->reserved[0] = 0; goto found; } } @@ -3448,7 +3868,7 @@ static int vino_v4l2_queryctrl(struct vino_channel_settings *vcs, } found: - spin_unlock(&vino_drvdata->input_lock); + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); return err; } @@ -3456,70 +3876,72 @@ static int vino_v4l2_queryctrl(struct vino_channel_settings *vcs, static int vino_v4l2_g_ctrl(struct vino_channel_settings *vcs, struct v4l2_control *control) { - struct indycam_control indycam_ctrl; - struct saa7191_control saa7191_ctrl; + unsigned long flags; + int i; int err = 0; - spin_lock(&vino_drvdata->input_lock); + spin_lock_irqsave(&vino_drvdata->input_lock, flags); switch (vcs->input) { - case VINO_INPUT_D1: - i2c_camera_command(DECODER_INDYCAM_GET_CONTROLS, - &indycam_ctrl); + case VINO_INPUT_D1: { + struct indycam_control indycam_ctrl; - switch(control->id) { - case V4L2_CID_AUTOGAIN: - control->value = indycam_ctrl.agc; - break; - case V4L2_CID_AUTO_WHITE_BALANCE: - control->value = indycam_ctrl.awb; - break; - case V4L2_CID_GAIN: - control->value = indycam_ctrl.gain; - break; - case V4L2_CID_PRIVATE_BASE: - control->value = indycam_ctrl.red_saturation; - break; - case V4L2_CID_PRIVATE_BASE + 1: - control->value = indycam_ctrl.blue_saturation; - break; - case V4L2_CID_RED_BALANCE: - control->value = indycam_ctrl.red_balance; - break; - case V4L2_CID_BLUE_BALANCE: - control->value = indycam_ctrl.blue_balance; - break; - case V4L2_CID_EXPOSURE: - control->value = indycam_ctrl.shutter; - break; - case V4L2_CID_GAMMA: - control->value = indycam_ctrl.gamma; - break; - default: + for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) { + if (vino_indycam_v4l2_controls[i].id == + control->id) { + goto found1; + } + } + + err = -EINVAL; + goto out; + +found1: + indycam_ctrl.type = vino_indycam_v4l2_controls[i].reserved[0]; + + err = i2c_camera_command(DECODER_INDYCAM_GET_CONTROL, + &indycam_ctrl); + if (err) { err = -EINVAL; + goto out; } + + control->value = indycam_ctrl.value; break; + } case VINO_INPUT_COMPOSITE: - case VINO_INPUT_SVIDEO: - i2c_decoder_command(DECODER_SAA7191_GET_CONTROLS, - &saa7191_ctrl); + case VINO_INPUT_SVIDEO: { + struct saa7191_control saa7191_ctrl; - switch(control->id) { - case V4L2_CID_HUE: - control->value = saa7191_ctrl.hue; - break; - case V4L2_CID_PRIVATE_BASE: - control->value = saa7191_ctrl.vtrc; - break; - default: + for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) { + if (vino_saa7191_v4l2_controls[i].id == + control->id) { + goto found2; + } + } + + err = -EINVAL; + goto out; + +found2: + saa7191_ctrl.type = vino_saa7191_v4l2_controls[i].reserved[0]; + + err = i2c_decoder_command(DECODER_SAA7191_GET_CONTROL, + &saa7191_ctrl); + if (err) { err = -EINVAL; + goto out; } + + control->value = saa7191_ctrl.value; break; + } default: err = -EINVAL; } - spin_unlock(&vino_drvdata->input_lock); +out: + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); return err; } @@ -3527,15 +3949,21 @@ static int vino_v4l2_g_ctrl(struct vino_channel_settings *vcs, static int vino_v4l2_s_ctrl(struct vino_channel_settings *vcs, struct v4l2_control *control) { - struct indycam_control indycam_ctrl; - struct saa7191_control saa7191_ctrl; + unsigned long flags; int i; int err = 0; - spin_lock(&vino_drvdata->input_lock); + spin_lock_irqsave(&vino_drvdata->input_lock, flags); + + if (!vino_is_input_owner(vcs)) { + err = -EBUSY; + goto out; + } switch (vcs->input) { - case VINO_INPUT_D1: + case VINO_INPUT_D1: { + struct indycam_control indycam_ctrl; + for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) { if (vino_indycam_v4l2_controls[i].id == control->id) { @@ -3544,65 +3972,31 @@ static int vino_v4l2_s_ctrl(struct vino_channel_settings *vcs, && (control->value <= vino_indycam_v4l2_controls[i]. maximum)) { - goto ok1; + goto found1; } else { err = -ERANGE; - goto error; + goto out; } } } + err = -EINVAL; - goto error; + goto out; -ok1: - indycam_ctrl.agc = INDYCAM_VALUE_UNCHANGED; - indycam_ctrl.awb = INDYCAM_VALUE_UNCHANGED; - indycam_ctrl.shutter = INDYCAM_VALUE_UNCHANGED; - indycam_ctrl.gain = INDYCAM_VALUE_UNCHANGED; - indycam_ctrl.red_balance = INDYCAM_VALUE_UNCHANGED; - indycam_ctrl.blue_balance = INDYCAM_VALUE_UNCHANGED; - indycam_ctrl.red_saturation = INDYCAM_VALUE_UNCHANGED; - indycam_ctrl.blue_saturation = INDYCAM_VALUE_UNCHANGED; - indycam_ctrl.gamma = INDYCAM_VALUE_UNCHANGED; - - switch(control->id) { - case V4L2_CID_AUTOGAIN: - indycam_ctrl.agc = control->value; - break; - case V4L2_CID_AUTO_WHITE_BALANCE: - indycam_ctrl.awb = control->value; - break; - case V4L2_CID_GAIN: - indycam_ctrl.gain = control->value; - break; - case V4L2_CID_PRIVATE_BASE: - indycam_ctrl.red_saturation = control->value; - break; - case V4L2_CID_PRIVATE_BASE + 1: - indycam_ctrl.blue_saturation = control->value; - break; - case V4L2_CID_RED_BALANCE: - indycam_ctrl.red_balance = control->value; - break; - case V4L2_CID_BLUE_BALANCE: - indycam_ctrl.blue_balance = control->value; - break; - case V4L2_CID_EXPOSURE: - indycam_ctrl.shutter = control->value; - break; - case V4L2_CID_GAMMA: - indycam_ctrl.gamma = control->value; - break; - default: - err = -EINVAL; - } +found1: + indycam_ctrl.type = vino_indycam_v4l2_controls[i].reserved[0]; + indycam_ctrl.value = control->value; - if (!err) - i2c_camera_command(DECODER_INDYCAM_SET_CONTROLS, - &indycam_ctrl); + err = i2c_camera_command(DECODER_INDYCAM_SET_CONTROL, + &indycam_ctrl); + if (err) + err = -EINVAL; break; + } case VINO_INPUT_COMPOSITE: - case VINO_INPUT_SVIDEO: + case VINO_INPUT_SVIDEO: { + struct saa7191_control saa7191_ctrl; + for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) { if (vino_saa7191_v4l2_controls[i].id == control->id) { @@ -3611,41 +4005,32 @@ static int vino_v4l2_s_ctrl(struct vino_channel_settings *vcs, && (control->value <= vino_saa7191_v4l2_controls[i]. maximum)) { - goto ok2; + goto found2; } else { err = -ERANGE; - goto error; + goto out; } } } err = -EINVAL; - goto error; - -ok2: - saa7191_ctrl.hue = SAA7191_VALUE_UNCHANGED; - saa7191_ctrl.vtrc = SAA7191_VALUE_UNCHANGED; + goto out; - switch(control->id) { - case V4L2_CID_HUE: - saa7191_ctrl.hue = control->value; - break; - case V4L2_CID_PRIVATE_BASE: - saa7191_ctrl.vtrc = control->value; - break; - default: - err = -EINVAL; - } +found2: + saa7191_ctrl.type = vino_saa7191_v4l2_controls[i].reserved[0]; + saa7191_ctrl.value = control->value; - if (!err) - i2c_decoder_command(DECODER_SAA7191_SET_CONTROLS, - &saa7191_ctrl); + err = i2c_decoder_command(DECODER_SAA7191_SET_CONTROL, + &saa7191_ctrl); + if (err) + err = -EINVAL; break; + } default: err = -EINVAL; } -error: - spin_unlock(&vino_drvdata->input_lock); +out: + spin_unlock_irqrestore(&vino_drvdata->input_lock, flags); return err; } @@ -3865,9 +4250,9 @@ static unsigned int vino_poll(struct file *file, poll_table *pt) over: dprintk("poll(): data %savailable\n", (outgoing > 0) ? "" : "not "); - if (outgoing > 0) { + + if (outgoing > 0) ret = POLLIN | POLLRDNORM; - } error: @@ -3880,6 +4265,7 @@ static int vino_do_ioctl(struct inode *inode, struct file *file, struct video_device *dev = video_devdata(file); struct vino_channel_settings *vcs = video_get_drvdata(dev); +#ifdef VINO_DEBUG switch (_IOC_TYPE(cmd)) { case 'v': dprintk("ioctl(): V4L1 unsupported (0x%08x)\n", cmd); @@ -3891,9 +4277,9 @@ static int vino_do_ioctl(struct inode *inode, struct file *file, default: dprintk("ioctl(): unsupported command 0x%08x\n", cmd); } +#endif switch (cmd) { - /* TODO: V4L1 interface (use compatibility layer?) */ /* V4L2 interface */ case VIDIOC_QUERYCAP: { vino_v4l2_querycap(arg); @@ -3911,6 +4297,9 @@ static int vino_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_ENUMSTD: { return vino_v4l2_enumstd(vcs, arg); } + case VIDIOC_QUERYSTD: { + return vino_v4l2_querystd(vcs, arg); + } case VIDIOC_G_STD: { return vino_v4l2_g_std(vcs, arg); } @@ -4100,8 +4489,7 @@ static int vino_probe(void) return -ENODEV; } - printk(KERN_INFO "VINO with chip ID %ld, revision %ld found\n", - VINO_ID_VALUE(rev_id), VINO_REV_NUM(rev_id)); + printk(KERN_INFO "VINO revision %ld found\n", VINO_REV_NUM(rev_id)); return 0; } diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c index eed2acea17791305a94965ab63020b7f9d41459f..39a0d238900e63f26c34992944b73a441e66b8f4 100644 --- a/drivers/media/video/zoran_card.c +++ b/drivers/media/video/zoran_card.c @@ -1057,10 +1057,8 @@ zr36057_init (struct zoran *zr) KERN_ERR "%s: zr36057_init() - kmalloc (STAT_COM) failed\n", ZR_DEVNAME(zr)); - if (vdev) - kfree(vdev); - if (mem) - kfree((void *)mem); + kfree(vdev); + kfree((void *)mem); return -ENOMEM; } memset((void *) mem, 0, mem_needed); @@ -1105,15 +1103,15 @@ zoran_release (struct zoran *zr) /* unregister videocodec bus */ if (zr->codec) { struct videocodec_master *master = zr->codec->master_data; + videocodec_detach(zr->codec); - if (master) - kfree(master); + kfree(master); } if (zr->vfe) { struct videocodec_master *master = zr->vfe->master_data; + videocodec_detach(zr->vfe); - if (master) - kfree(master); + kfree(master); } /* unregister i2c bus */ diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c index 53adeb70f2cafb2f7a551ff5e121782f306df329..07bde9acd672cbac58f1973f0b4a3a1697d32907 100644 --- a/drivers/media/video/zoran_driver.c +++ b/drivers/media/video/zoran_driver.c @@ -996,8 +996,6 @@ zoran_jpg_queue_frame (struct file *file, return -EINVAL; } - spin_lock_irqsave(&zr->spinlock, flags); - if (fh->jpg_buffers.active == ZORAN_FREE) { if (zr->jpg_buffers.active == ZORAN_FREE) { zr->jpg_buffers = fh->jpg_buffers; @@ -1016,6 +1014,8 @@ zoran_jpg_queue_frame (struct file *file, zr36057_enable_jpg(zr, mode); } + spin_lock_irqsave(&zr->spinlock, flags); + if (!res) { switch (zr->jpg_buffers.buffer[num].state) { case BUZ_STATE_DONE: diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index ed3c891e388f9ee3c73184dc0b445202bb208ab8..014085d8ec85cfd370fb15b4add8f59e0015931b 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c @@ -511,7 +511,7 @@ mpt_lan_close(struct net_device *dev) { struct mpt_lan_priv *priv = netdev_priv(dev); MPT_ADAPTER *mpt_dev = priv->mpt_dev; - unsigned int timeout; + unsigned long timeout; int i; dlprintk((KERN_INFO MYNAM ": mpt_lan_close called\n")); @@ -526,11 +526,9 @@ mpt_lan_close(struct net_device *dev) mpt_lan_reset(dev); - timeout = 2 * HZ; - while (atomic_read(&priv->buckets_out) && --timeout) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + timeout = jiffies + 2 * HZ; + while (atomic_read(&priv->buckets_out) && time_before(jiffies, timeout)) + schedule_timeout_interruptible(1); for (i = 0; i < priv->max_buckets_out; i++) { if (priv->RcvCtl[i].skb != NULL) { diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 5cb07eb224d71be05a3c39f6db4fb474ec4bf6a7..4330ed0cedaaaafbc2a435b73c1b42b4aadc43d9 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -1013,10 +1013,8 @@ mptscsih_remove(struct pci_dev *pdev) spin_lock_irqsave(&dvtaskQ_lock, flags); if (dvtaskQ_active) { spin_unlock_irqrestore(&dvtaskQ_lock, flags); - while(dvtaskQ_active && --count) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + while(dvtaskQ_active && --count) + schedule_timeout_interruptible(1); } else { spin_unlock_irqrestore(&dvtaskQ_lock, flags); } diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c index b675b4ebbebdff558521b181d81b4eb2ab59b7c7..9c339a2505b006ed630d315436563733c7831393 100644 --- a/drivers/message/i2o/exec-osm.c +++ b/drivers/message/i2o/exec-osm.c @@ -33,6 +33,7 @@ #include #include #include +#include /* wait_event_interruptible_timeout() needs this */ #include /* HZ */ #include "core.h" diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c index 61b837de4b6a134756e5af4eb0892b9a8c318685..4eb53258842eaef0ad01f68dd3cceee28b96223b 100644 --- a/drivers/message/i2o/iop.c +++ b/drivers/message/i2o/iop.c @@ -93,8 +93,7 @@ u32 i2o_msg_get_wait(struct i2o_controller *c, c->name); return I2O_QUEUE_EMPTY; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } return m; @@ -485,8 +484,7 @@ static int i2o_iop_init_outbound_queue(struct i2o_controller *c) osm_warn("%s: Timeout Initializing\n", c->name); return -ETIMEDOUT; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } m = c->out_queue.phys; @@ -548,8 +546,7 @@ static int i2o_iop_reset(struct i2o_controller *c) if (time_after(jiffies, timeout)) break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } switch (*status) { @@ -577,8 +574,7 @@ static int i2o_iop_reset(struct i2o_controller *c) rc = -ETIMEDOUT; goto exit; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_RESET); } @@ -989,8 +985,7 @@ int i2o_status_get(struct i2o_controller *c) return -ETIMEDOUT; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } #ifdef DEBUG diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c index c75d713c01e4a9c9680410b2de2c75fabdf6802d..55ba23075c90ed688ad2ee88c9608a1fefcda77a 100644 --- a/drivers/mfd/mcp-core.c +++ b/drivers/mfd/mcp-core.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index ceae379a4d4c56227541582affc855785fc248c5..da528390acf87293292237abddf2bf5cf66b600c 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1263,7 +1263,7 @@ EXPORT_SYMBOL(mmc_suspend_host); */ int mmc_resume_host(struct mmc_host *host) { - mmc_detect_change(host, 0); + mmc_rescan(host); return 0; } diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 4ff67e7363d95436de496a044ce2e076bddefb7a..e954b8354fef74f3e7f8d6a9dabdfef7814a9c95 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -1602,8 +1602,7 @@ static void __devexit wbsd_release_dma(struct wbsd_host* host) if (host->dma_addr) dma_unmap_single(host->mmc->dev, host->dma_addr, WBSD_DMA_SIZE, DMA_BIDIRECTIONAL); - if (host->dma_buffer) - kfree(host->dma_buffer); + kfree(host->dma_buffer); if (host->dma >= 0) free_dma(host->dma); diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 027054dea032bea6b909000b94228e218d64c190..f6b775e63ac8f07499767ae828f52cad418a067c 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -1,4 +1,4 @@ -# $Id: Kconfig,v 1.7 2004/11/22 11:33:56 ijc Exp $ +# $Id: Kconfig,v 1.11 2005/11/07 11:14:19 gleixner Exp $ menu "Memory Technology Devices (MTD)" @@ -10,7 +10,7 @@ config MTD will provide the generic support for MTD drivers to register themselves with the kernel and for potential users of MTD devices to enumerate the devices which are present and obtain a handle on - them. It will also allow you to select individual drivers for + them. It will also allow you to select individual drivers for particular hardware and users of MTD devices. If unsure, say N. config MTD_DEBUG @@ -61,11 +61,11 @@ config MTD_REDBOOT_PARTS If you need code which can detect and parse this table, and register MTD 'partitions' corresponding to each image in the table, enable - this option. + this option. You will still need the parsing functions to be called by the driver - for your particular device. It won't happen automatically. The - SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for + for your particular device. It won't happen automatically. The + SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for example. config MTD_REDBOOT_DIRECTORY_BLOCK @@ -81,10 +81,10 @@ config MTD_REDBOOT_DIRECTORY_BLOCK partition table. A zero or positive value gives an absolete erase block number. A negative value specifies a number of sectors before the end of the device. - + For example "2" means block number 2, "-1" means the last block and "-2" means the penultimate block. - + config MTD_REDBOOT_PARTS_UNALLOCATED bool " Include unallocated flash regions" depends on MTD_REDBOOT_PARTS @@ -105,11 +105,11 @@ config MTD_CMDLINE_PARTS ---help--- Allow generic configuration of the MTD paritition tables via the kernel command line. Multiple flash resources are supported for hardware where - different kinds of flash memory are available. + different kinds of flash memory are available. You will still need the parsing functions to be called by the driver - for your particular device. It won't happen automatically. The - SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for + for your particular device. It won't happen automatically. The + SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for example. The format for the command line is as follows: @@ -118,12 +118,12 @@ config MTD_CMDLINE_PARTS := :[,] := [@offset][][ro] := unique id used in mapping driver/device - := standard linux memsize OR "-" to denote all + := standard linux memsize OR "-" to denote all remaining space := (NAME) - Due to the way Linux handles the command line, no spaces are - allowed in the partition definition, including mtd id's and partition + Due to the way Linux handles the command line, no spaces are + allowed in the partition definition, including mtd id's and partition names. Examples: @@ -240,7 +240,7 @@ config INFTL tristate "INFTL (Inverse NAND Flash Translation Layer) support" depends on MTD ---help--- - This provides support for the Inverse NAND Flash Translation + This provides support for the Inverse NAND Flash Translation Layer which is used on M-Systems' newer DiskOnChip devices. It uses a kind of pseudo-file system on a flash device to emulate a block device with 512-byte sectors, on top of which you put @@ -253,6 +253,16 @@ config INFTL permitted to copy, modify and distribute the code as you wish. Just not use it. +config RFD_FTL + tristate "Resident Flash Disk (Flash Translation Layer) support" + depends on MTD + ---help--- + This provides support for the flash translation layer known + as the Resident Flash Disk (RFD), as used by the Embedded BIOS + of General Software. There is a blurb at: + + http://www.gensw.com/pages/prod/bios/rfd.htm + source "drivers/mtd/chips/Kconfig" source "drivers/mtd/maps/Kconfig" @@ -261,5 +271,7 @@ source "drivers/mtd/devices/Kconfig" source "drivers/mtd/nand/Kconfig" +source "drivers/mtd/onenand/Kconfig" + endmenu diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index e4ad588327f705aa4aa09fa7e5d82e369f299876..fc9374407c2bc7c6f5e57dd015e0d74e97b3fa8a 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -1,7 +1,7 @@ # # Makefile for the memory technology device drivers. # -# $Id: Makefile.common,v 1.5 2004/08/10 20:51:49 dwmw2 Exp $ +# $Id: Makefile.common,v 1.7 2005/07/11 10:39:27 gleixner Exp $ # Core functionality. mtd-y := mtdcore.o @@ -20,8 +20,9 @@ obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o mtd_blkdevs.o obj-$(CONFIG_FTL) += ftl.o mtd_blkdevs.o obj-$(CONFIG_NFTL) += nftl.o mtd_blkdevs.o obj-$(CONFIG_INFTL) += inftl.o mtd_blkdevs.o +obj-$(CONFIG_RFD_FTL) += rfd_ftl.o mtd_blkdevs.o nftl-objs := nftlcore.o nftlmount.o inftl-objs := inftlcore.o inftlmount.o -obj-y += chips/ maps/ devices/ nand/ +obj-y += chips/ maps/ devices/ nand/ onenand/ diff --git a/drivers/mtd/afs.c b/drivers/mtd/afs.c index 7363e101eb0f0958a8294831047ed191e18c0b93..6a45be04564b7cd6b92b4b7afab76696d50feb23 100644 --- a/drivers/mtd/afs.c +++ b/drivers/mtd/afs.c @@ -1,27 +1,27 @@ /*====================================================================== drivers/mtd/afs.c: ARM Flash Layout/Partitioning - + Copyright (C) 2000 ARM Limited - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - This is access code for flashes using ARM's flash partitioning + + This is access code for flashes using ARM's flash partitioning standards. - $Id: afs.c,v 1.13 2004/02/27 22:09:59 rmk Exp $ + $Id: afs.c,v 1.15 2005/11/07 11:14:19 gleixner Exp $ ======================================================================*/ @@ -163,7 +163,7 @@ afs_read_iis(struct mtd_info *mtd, struct image_info_struct *iis, u_int ptr) return ret; } -static int parse_afs_partitions(struct mtd_info *mtd, +static int parse_afs_partitions(struct mtd_info *mtd, struct mtd_partition **pparts, unsigned long origin) { diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig index df95d2158b167cef5946395e25778c323db6db13..eafa23f5cbd66e615c4b0f5025433f85267a35ff 100644 --- a/drivers/mtd/chips/Kconfig +++ b/drivers/mtd/chips/Kconfig @@ -1,5 +1,5 @@ # drivers/mtd/chips/Kconfig -# $Id: Kconfig,v 1.15 2005/06/06 23:04:35 tpoynor Exp $ +# $Id: Kconfig,v 1.18 2005/11/07 11:14:22 gleixner Exp $ menu "RAM/ROM/Flash chip drivers" depends on MTD!=n @@ -39,7 +39,7 @@ config MTD_CFI_ADV_OPTIONS If you need to specify a specific endianness for access to flash chips, or if you wish to reduce the size of the kernel by including support for only specific arrangements of flash chips, say 'Y'. This - option does not directly affect the code, but will enable other + option does not directly affect the code, but will enable other configuration options which allow you to do so. If unsure, say 'N'. @@ -56,7 +56,7 @@ config MTD_CFI_NOSWAP data bits when writing the 'magic' commands to the chips. Saying 'NO', which is the default when CONFIG_MTD_CFI_ADV_OPTIONS isn't enabled, means that the CPU will not do any swapping; the chips - are expected to be wired to the CPU in 'host-endian' form. + are expected to be wired to the CPU in 'host-endian' form. Specific arrangements are possible with the BIG_ENDIAN_BYTE and LITTLE_ENDIAN_BYTE, if the bytes are reversed. @@ -79,10 +79,10 @@ config MTD_CFI_GEOMETRY bool "Specific CFI Flash geometry selection" depends on MTD_CFI_ADV_OPTIONS help - This option does not affect the code directly, but will enable + This option does not affect the code directly, but will enable some other configuration options which would allow you to reduce - the size of the kernel by including support for only certain - arrangements of CFI chips. If unsure, say 'N' and all options + the size of the kernel by including support for only certain + arrangements of CFI chips. If unsure, say 'N' and all options which are supported by the current code will be enabled. config MTD_MAP_BANK_WIDTH_1 @@ -197,7 +197,7 @@ config MTD_CFI_AMDSTD help The Common Flash Interface defines a number of different command sets which a CFI-compliant chip may claim to implement. This code - provides support for one of those command sets, used on chips + provides support for one of those command sets, used on chips including the AMD Am29LV320. config MTD_CFI_AMDSTD_RETRY @@ -237,14 +237,14 @@ config MTD_RAM tristate "Support for RAM chips in bus mapping" depends on MTD help - This option enables basic support for RAM chips accessed through + This option enables basic support for RAM chips accessed through a bus mapping driver. config MTD_ROM tristate "Support for ROM chips in bus mapping" depends on MTD help - This option enables basic support for ROM chips accessed through + This option enables basic support for ROM chips accessed through a bus mapping driver. config MTD_ABSENT @@ -275,7 +275,7 @@ config MTD_AMDSTD depends on MTD && MTD_OBSOLETE_CHIPS help This option enables support for flash chips using AMD-compatible - commands, including some which are not CFI-compatible and hence + commands, including some which are not CFI-compatible and hence cannot be used with the CONFIG_MTD_CFI_AMDSTD option. It also works on AMD compatible chips that do conform to CFI. @@ -285,7 +285,7 @@ config MTD_SHARP depends on MTD && MTD_OBSOLETE_CHIPS help This option enables support for flash chips using Sharp-compatible - commands, including some which are not CFI-compatible and hence + commands, including some which are not CFI-compatible and hence cannot be used with the CONFIG_MTD_CFI_INTELxxx options. config MTD_JEDEC diff --git a/drivers/mtd/chips/Makefile b/drivers/mtd/chips/Makefile index 6830489828c604bac1a4c975217869da22d0d2d5..8afe3092c4e38ba73214c3f255006c3bced97a3a 100644 --- a/drivers/mtd/chips/Makefile +++ b/drivers/mtd/chips/Makefile @@ -1,7 +1,7 @@ # # linux/drivers/chips/Makefile # -# $Id: Makefile.common,v 1.4 2004/07/12 16:07:30 dwmw2 Exp $ +# $Id: Makefile.common,v 1.5 2005/11/07 11:14:22 gleixner Exp $ # *** BIG UGLY NOTE *** # @@ -11,7 +11,7 @@ # the CFI command set drivers are linked before gen_probe.o obj-$(CONFIG_MTD) += chipreg.o -obj-$(CONFIG_MTD_AMDSTD) += amd_flash.o +obj-$(CONFIG_MTD_AMDSTD) += amd_flash.o obj-$(CONFIG_MTD_CFI) += cfi_probe.o obj-$(CONFIG_MTD_CFI_UTIL) += cfi_util.o obj-$(CONFIG_MTD_CFI_STAA) += cfi_cmdset_0020.o diff --git a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c index 2dafeba3f3d5afb9ce165794e86286da7b064e77..fdb91b6f1d979254e63b0256f7fbdf54fc3e1ac7 100644 --- a/drivers/mtd/chips/amd_flash.c +++ b/drivers/mtd/chips/amd_flash.c @@ -3,7 +3,7 @@ * * Author: Jonas Holmberg * - * $Id: amd_flash.c,v 1.27 2005/02/04 07:43:09 jonashg Exp $ + * $Id: amd_flash.c,v 1.28 2005/11/07 11:14:22 gleixner Exp $ * * Copyright (c) 2001 Axis Communications AB * @@ -93,9 +93,9 @@ #define D6_MASK 0x40 struct amd_flash_private { - int device_type; - int interleave; - int numchips; + int device_type; + int interleave; + int numchips; unsigned long chipshift; // const char *im_name; struct flchip chips[0]; @@ -253,7 +253,7 @@ static int amd_flash_do_unlock(struct mtd_info *mtd, loff_t ofs, size_t len, int i; int retval = 0; int lock_status; - + map = mtd->priv; /* Pass the whole chip through sector by sector and check for each @@ -273,7 +273,7 @@ static int amd_flash_do_unlock(struct mtd_info *mtd, loff_t ofs, size_t len, unlock_sector(map, eraseoffset, is_unlock); lock_status = is_sector_locked(map, eraseoffset); - + if (is_unlock && lock_status) { printk("Cannot unlock sector at address %x length %xx\n", eraseoffset, merip->erasesize); @@ -305,7 +305,7 @@ static int amd_flash_lock(struct mtd_info *mtd, loff_t ofs, size_t len) /* * Reads JEDEC manufacturer ID and device ID and returns the index of the first * matching table entry (-1 if not found or alias for already found chip). - */ + */ static int probe_new_chip(struct mtd_info *mtd, __u32 base, struct flchip *chips, struct amd_flash_private *private, @@ -636,7 +636,7 @@ static struct mtd_info *amd_flash_probe(struct map_info *map) { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, { .offset = 0x1F0000, .erasesize = 0x02000, .numblocks = 8 } } - } + } }; struct mtd_info *mtd; @@ -701,7 +701,7 @@ static struct mtd_info *amd_flash_probe(struct map_info *map) mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions, GFP_KERNEL); - if (!mtd->eraseregions) { + if (!mtd->eraseregions) { printk(KERN_WARNING "%s: Failed to allocate " "memory for MTD erase region info\n", map->name); kfree(mtd); @@ -739,12 +739,12 @@ static struct mtd_info *amd_flash_probe(struct map_info *map) mtd->type = MTD_NORFLASH; mtd->flags = MTD_CAP_NORFLASH; mtd->name = map->name; - mtd->erase = amd_flash_erase; - mtd->read = amd_flash_read; - mtd->write = amd_flash_write; - mtd->sync = amd_flash_sync; - mtd->suspend = amd_flash_suspend; - mtd->resume = amd_flash_resume; + mtd->erase = amd_flash_erase; + mtd->read = amd_flash_read; + mtd->write = amd_flash_write; + mtd->sync = amd_flash_sync; + mtd->suspend = amd_flash_suspend; + mtd->resume = amd_flash_resume; mtd->lock = amd_flash_lock; mtd->unlock = amd_flash_unlock; @@ -789,7 +789,7 @@ static inline int read_one_chip(struct map_info *map, struct flchip *chip, map->name, chip->state); set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - + spin_unlock_bh(chip->mutex); schedule(); @@ -802,7 +802,7 @@ static inline int read_one_chip(struct map_info *map, struct flchip *chip, timeo = jiffies + HZ; goto retry; - } + } adr += chip->start; @@ -889,7 +889,7 @@ static int write_one_word(struct map_info *map, struct flchip *chip, map->name, chip->state); set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - + spin_unlock_bh(chip->mutex); schedule(); @@ -901,7 +901,7 @@ static int write_one_word(struct map_info *map, struct flchip *chip, timeo = jiffies + HZ; goto retry; - } + } chip->state = FL_WRITING; @@ -911,7 +911,7 @@ static int write_one_word(struct map_info *map, struct flchip *chip, wide_write(map, datum, adr); times_left = 500000; - while (times_left-- && flash_is_busy(map, adr, private->interleave)) { + while (times_left-- && flash_is_busy(map, adr, private->interleave)) { if (need_resched()) { spin_unlock_bh(chip->mutex); schedule(); @@ -989,7 +989,7 @@ static int amd_flash_write(struct mtd_info *mtd, loff_t to , size_t len, if (ret) { return ret; } - + ofs += n; buf += n; (*retlen) += n; @@ -1002,7 +1002,7 @@ static int amd_flash_write(struct mtd_info *mtd, loff_t to , size_t len, } } } - + /* We are now aligned, write as much as possible. */ while(len >= map->buswidth) { __u32 datum; @@ -1063,7 +1063,7 @@ static int amd_flash_write(struct mtd_info *mtd, loff_t to , size_t len, if (ret) { return ret; } - + (*retlen) += n; } @@ -1085,7 +1085,7 @@ static inline int erase_one_block(struct map_info *map, struct flchip *chip, if (chip->state != FL_READY){ set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - + spin_unlock_bh(chip->mutex); schedule(); @@ -1098,7 +1098,7 @@ static inline int erase_one_block(struct map_info *map, struct flchip *chip, timeo = jiffies + HZ; goto retry; - } + } chip->state = FL_ERASING; @@ -1106,30 +1106,30 @@ static inline int erase_one_block(struct map_info *map, struct flchip *chip, ENABLE_VPP(map); send_cmd(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA); send_cmd_to_addr(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA_2, adr); - + timeo = jiffies + (HZ * 20); spin_unlock_bh(chip->mutex); msleep(1000); spin_lock_bh(chip->mutex); - + while (flash_is_busy(map, adr, private->interleave)) { if (chip->state != FL_ERASING) { /* Someone's suspended the erase. Sleep */ set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - + spin_unlock_bh(chip->mutex); printk(KERN_INFO "%s: erase suspended. Sleeping\n", map->name); schedule(); remove_wait_queue(&chip->wq, &wait); - + if (signal_pending(current)) { return -EINTR; } - + timeo = jiffies + (HZ*2); /* FIXME */ spin_lock_bh(chip->mutex); continue; @@ -1145,7 +1145,7 @@ static inline int erase_one_block(struct map_info *map, struct flchip *chip, return -EIO; } - + /* Latency issues. Drop the lock, wait a while and retry */ spin_unlock_bh(chip->mutex); @@ -1153,7 +1153,7 @@ static inline int erase_one_block(struct map_info *map, struct flchip *chip, schedule(); else udelay(1); - + spin_lock_bh(chip->mutex); } @@ -1180,7 +1180,7 @@ static inline int erase_one_block(struct map_info *map, struct flchip *chip, return -EIO; } } - + DISABLE_VPP(map); chip->state = FL_READY; wake_up(&chip->wq); @@ -1246,7 +1246,7 @@ static int amd_flash_erase(struct mtd_info *mtd, struct erase_info *instr) * with the erase region at that address. */ - while ((i < mtd->numeraseregions) && + while ((i < mtd->numeraseregions) && ((instr->addr + instr->len) >= regions[i].offset)) { i++; } @@ -1293,10 +1293,10 @@ static int amd_flash_erase(struct mtd_info *mtd, struct erase_info *instr) } } } - + instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); - + return 0; } @@ -1324,7 +1324,7 @@ static void amd_flash_sync(struct mtd_info *mtd) case FL_JEDEC_QUERY: chip->oldstate = chip->state; chip->state = FL_SYNCING; - /* No need to wake_up() on this state change - + /* No need to wake_up() on this state change - * as the whole point is that nobody can do anything * with the chip now anyway. */ @@ -1335,13 +1335,13 @@ static void amd_flash_sync(struct mtd_info *mtd) default: /* Not an idle state */ add_wait_queue(&chip->wq, &wait); - + spin_unlock_bh(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); - + goto retry; } } @@ -1351,7 +1351,7 @@ static void amd_flash_sync(struct mtd_info *mtd) chip = &private->chips[i]; spin_lock_bh(chip->mutex); - + if (chip->state == FL_SYNCING) { chip->state = chip->oldstate; wake_up(&chip->wq); diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 0cfcd88468e0ed3c2db5da780bc3d7e428c3ab3c..143f01a4c1705343a2406c53f1aff0f71b4feb28 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -4,9 +4,9 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.178 2005/05/19 17:05:43 nico Exp $ + * $Id: cfi_cmdset_0001.c,v 1.185 2005/11/07 11:14:22 gleixner Exp $ + * * - * * 10/10/2000 Nicolas Pitre * - completely revamped method functions so they are aware and * independent of the flash geometry (buswidth, interleave, etc.) @@ -51,6 +51,7 @@ static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); +static int cfi_intelext_writev(struct mtd_info *, const struct kvec *, unsigned long, loff_t, size_t *); static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *); static void cfi_intelext_sync (struct mtd_info *); static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len); @@ -105,6 +106,7 @@ static struct mtd_chip_driver cfi_intelext_chipdrv = { static void cfi_tell_features(struct cfi_pri_intelext *extp) { int i; + printk(" Extended Query version %c.%c\n", extp->MajorVersion, extp->MinorVersion); printk(" Feature/Command Support: %4.4X\n", extp->FeatureSupport); printk(" - Chip Erase: %s\n", extp->FeatureSupport&1?"supported":"unsupported"); printk(" - Suspend Erase: %s\n", extp->FeatureSupport&2?"supported":"unsupported"); @@ -116,36 +118,43 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp) printk(" - Page-mode read: %s\n", extp->FeatureSupport&128?"supported":"unsupported"); printk(" - Synchronous read: %s\n", extp->FeatureSupport&256?"supported":"unsupported"); printk(" - Simultaneous operations: %s\n", extp->FeatureSupport&512?"supported":"unsupported"); - for (i=10; i<32; i++) { - if (extp->FeatureSupport & (1<FeatureSupport&1024?"supported":"unsupported"); + for (i=11; i<32; i++) { + if (extp->FeatureSupport & (1<SuspendCmdSupport); printk(" - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported"); for (i=1; i<8; i++) { if (extp->SuspendCmdSupport & (1<BlkStatusRegMask); printk(" - Lock Bit Active: %s\n", extp->BlkStatusRegMask&1?"yes":"no"); - printk(" - Valid Bit Active: %s\n", extp->BlkStatusRegMask&2?"yes":"no"); - for (i=2; i<16; i++) { + printk(" - Lock-Down Bit Active: %s\n", extp->BlkStatusRegMask&2?"yes":"no"); + for (i=2; i<3; i++) { if (extp->BlkStatusRegMask & (1<BlkStatusRegMask&16?"yes":"no"); + printk(" - EFA Lock-Down Bit: %s\n", extp->BlkStatusRegMask&32?"yes":"no"); + for (i=6; i<16; i++) { + if (extp->BlkStatusRegMask & (1<VccOptimal >> 4, extp->VccOptimal & 0xf); if (extp->VppOptimal) - printk(" Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", + printk(" Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", extp->VppOptimal >> 4, extp->VppOptimal & 0xf); } #endif #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE -/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ +/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ static void fixup_intel_strataflash(struct mtd_info *mtd, void* param) { struct map_info *map = mtd->priv; @@ -176,7 +185,7 @@ static void fixup_st_m28w320ct(struct mtd_info *mtd, void* param) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; - + cfi->cfiq->BufWriteTimeoutTyp = 0; /* Not supported */ cfi->cfiq->BufWriteTimeoutMax = 0; /* Not supported */ } @@ -185,7 +194,7 @@ static void fixup_st_m28w320cb(struct mtd_info *mtd, void* param) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; - + /* Note this is done after the region info is endian swapped */ cfi->cfiq->EraseRegionInfo[1] = (cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e; @@ -207,12 +216,13 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) if (cfi->cfiq->BufWriteTimeoutTyp) { printk(KERN_INFO "Using buffer write method\n" ); mtd->write = cfi_intelext_write_buffers; + mtd->writev = cfi_intelext_writev; } } static struct cfi_fixup cfi_fixup_table[] = { #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE - { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, + { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, #endif #ifdef CMDSET0001_DISABLE_WRITE_SUSPEND { CFI_MFR_ANY, CFI_ID_ANY, fixup_no_write_suspend, NULL }, @@ -252,12 +262,21 @@ read_pri_intelext(struct map_info *map, __u16 adr) if (!extp) return NULL; + if (extp->MajorVersion != '1' || + (extp->MinorVersion < '0' || extp->MinorVersion > '4')) { + printk(KERN_ERR " Unknown Intel/Sharp Extended Query " + "version %c.%c.\n", extp->MajorVersion, + extp->MinorVersion); + kfree(extp); + return NULL; + } + /* Do some byteswapping if necessary */ extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport); extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask); extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr); - if (extp->MajorVersion == '1' && extp->MinorVersion == '3') { + if (extp->MajorVersion == '1' && extp->MinorVersion >= '3') { unsigned int extra_size = 0; int nb_parts, i; @@ -266,7 +285,10 @@ read_pri_intelext(struct map_info *map, __u16 adr) sizeof(struct cfi_intelext_otpinfo); /* Burst Read info */ - extra_size += 6; + extra_size += 2; + if (extp_size < sizeof(*extp) + extra_size) + goto need_more; + extra_size += extp->extra[extra_size-1]; /* Number of hardware-partitions */ extra_size += 1; @@ -274,6 +296,10 @@ read_pri_intelext(struct map_info *map, __u16 adr) goto need_more; nb_parts = extp->extra[extra_size - 1]; + /* skip the sizeof(partregion) field in CFI 1.4 */ + if (extp->MinorVersion >= '4') + extra_size += 2; + for (i = 0; i < nb_parts; i++) { struct cfi_intelext_regioninfo *rinfo; rinfo = (struct cfi_intelext_regioninfo *)&extp->extra[extra_size]; @@ -285,6 +311,9 @@ read_pri_intelext(struct map_info *map, __u16 adr) * sizeof(struct cfi_intelext_blockinfo); } + if (extp->MinorVersion >= '4') + extra_size += sizeof(struct cfi_intelext_programming_regioninfo); + if (extp_size < sizeof(*extp) + extra_size) { need_more: extp_size = sizeof(*extp) + extra_size; @@ -298,7 +327,7 @@ read_pri_intelext(struct map_info *map, __u16 adr) goto again; } } - + return extp; } @@ -339,7 +368,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) mtd->reboot_notifier.notifier_call = cfi_intelext_reboot; if (cfi->cfi_mode == CFI_MODE_CFI) { - /* + /* * It's a real CFI chip, not one for which the probe * routine faked a CFI structure. So we read the feature * table from it. @@ -354,14 +383,14 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) } /* Install our own private info structure */ - cfi->cmdset_priv = extp; + cfi->cmdset_priv = extp; cfi_fixup(mtd, cfi_fixup_table); #ifdef DEBUG_CFI_FEATURES /* Tell the user about it in lots of lovely detail */ cfi_tell_features(extp); -#endif +#endif if(extp->SuspendCmdSupport & 1) { printk(KERN_NOTICE "cfi_cmdset_0001: Erase suspend on write enabled\n"); @@ -379,10 +408,10 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) cfi->chips[i].buffer_write_time = 1<cfiq->BufWriteTimeoutTyp; cfi->chips[i].erase_time = 1<cfiq->BlockEraseTimeoutTyp; cfi->chips[i].ref_point_counter = 0; - } + } map->fldrv = &cfi_intelext_chipdrv; - + return cfi_intelext_setup(mtd); } @@ -399,13 +428,13 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd) mtd->size = devsize * cfi->numchips; mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; - mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) + mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions, GFP_KERNEL); - if (!mtd->eraseregions) { + if (!mtd->eraseregions) { printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n"); goto setup_err; } - + for (i=0; icfiq->NumEraseRegions; i++) { unsigned long ernum, ersize; ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave; @@ -429,7 +458,7 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd) } for (i=0; inumeraseregions;i++){ - printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n", + printk(KERN_DEBUG "erase region %d: offset=0x%x,size=0x%x,blocks=%d\n", i,mtd->eraseregions[i].offset, mtd->eraseregions[i].erasesize, mtd->eraseregions[i].numblocks); @@ -455,8 +484,7 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd) setup_err: if(mtd) { - if(mtd->eraseregions) - kfree(mtd->eraseregions); + kfree(mtd->eraseregions); kfree(mtd); } kfree(cfi->cmdset_priv); @@ -481,7 +509,7 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, * arrangement at this point. This can be rearranged in the future * if someone feels motivated enough. --nico */ - if (extp && extp->MajorVersion == '1' && extp->MinorVersion == '3' + if (extp && extp->MajorVersion == '1' && extp->MinorVersion >= '3' && extp->FeatureSupport & (1 << 9)) { struct cfi_private *newcfi; struct flchip *chip; @@ -493,12 +521,16 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, sizeof(struct cfi_intelext_otpinfo); /* Burst Read info */ - offs += 6; + offs += extp->extra[offs+1]+2; /* Number of partition regions */ numregions = extp->extra[offs]; offs += 1; + /* skip the sizeof(partregion) field in CFI 1.4 */ + if (extp->MinorVersion >= '4') + offs += 2; + /* Number of hardware partitions */ numparts = 0; for (i = 0; i < numregions; i++) { @@ -510,6 +542,20 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, sizeof(struct cfi_intelext_blockinfo); } + /* Programming Region info */ + if (extp->MinorVersion >= '4') { + struct cfi_intelext_programming_regioninfo *prinfo; + prinfo = (struct cfi_intelext_programming_regioninfo *)&extp->extra[offs]; + MTD_PROGREGION_SIZE(mtd) = cfi->interleave << prinfo->ProgRegShift; + MTD_PROGREGION_CTRLMODE_VALID(mtd) = cfi->interleave * prinfo->ControlValid; + MTD_PROGREGION_CTRLMODE_INVALID(mtd) = cfi->interleave * prinfo->ControlInvalid; + mtd->flags |= MTD_PROGRAM_REGIONS; + printk(KERN_DEBUG "%s: program region size/ctrl_valid/ctrl_inval = %d/%d/%d\n", + map->name, MTD_PROGREGION_SIZE(mtd), + MTD_PROGREGION_CTRLMODE_VALID(mtd), + MTD_PROGREGION_CTRLMODE_INVALID(mtd)); + } + /* * All functions below currently rely on all chips having * the same geometry so we'll just assume that all hardware @@ -654,8 +700,8 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr break; if (time_after(jiffies, timeo)) { - printk(KERN_ERR "Waiting for chip to be ready timed out. Status %lx\n", - status.x[0]); + printk(KERN_ERR "%s: Waiting for chip to be ready timed out. Status %lx\n", + map->name, status.x[0]); return -EIO; } spin_unlock(chip->mutex); @@ -664,7 +710,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr /* Someone else might have been playing with it. */ goto retry; } - + case FL_READY: case FL_CFI_QUERY: case FL_JEDEC_QUERY: @@ -702,8 +748,8 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr map_write(map, CMD(0x70), adr); chip->state = FL_ERASING; chip->oldstate = FL_READY; - printk(KERN_ERR "Chip not ready after erase " - "suspended: status = 0x%lx\n", status.x[0]); + printk(KERN_ERR "%s: Chip not ready after erase " + "suspended: status = 0x%lx\n", map->name, status.x[0]); return -EIO; } @@ -783,14 +829,14 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad switch(chip->oldstate) { case FL_ERASING: chip->state = chip->oldstate; - /* What if one interleaved chip has finished and the + /* What if one interleaved chip has finished and the other hasn't? The old code would leave the finished - one in READY mode. That's bad, and caused -EROFS + one in READY mode. That's bad, and caused -EROFS errors to be returned from do_erase_oneblock because that's the only bit it checked for at the time. - As the state machine appears to explicitly allow + As the state machine appears to explicitly allow sending the 0x70 (Read Status) command to an erasing - chip and expecting it to be ignored, that's what we + chip and expecting it to be ignored, that's what we do. */ map_write(map, CMD(0xd0), adr); map_write(map, CMD(0x70), adr); @@ -810,7 +856,7 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad DISABLE_VPP(map); break; default: - printk(KERN_ERR "put_chip() called with oldstate %d!!\n", chip->oldstate); + printk(KERN_ERR "%s: put_chip() called with oldstate %d!!\n", map->name, chip->oldstate); } wake_up(&chip->wq); } @@ -1026,8 +1072,8 @@ static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t a adr += chip->start; - /* Ensure cmd read/writes are aligned. */ - cmd_addr = adr & ~(map_bankwidth(map)-1); + /* Ensure cmd read/writes are aligned. */ + cmd_addr = adr & ~(map_bankwidth(map)-1); spin_lock(chip->mutex); @@ -1055,7 +1101,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si if (!map->virt || (from + len > mtd->size)) return -EINVAL; - + *mtdbuf = (void *)map->virt + from; *retlen = 0; @@ -1082,7 +1128,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si *retlen += thislen; len -= thislen; - + ofs = 0; chipnum++; } @@ -1121,7 +1167,7 @@ static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t fro if(chip->ref_point_counter == 0) chip->state = FL_READY; } else - printk(KERN_ERR "Warning: unpoint called on non pointed region\n"); /* Should this give an error? */ + printk(KERN_ERR "%s: Warning: unpoint called on non pointed region\n", map->name); /* Should this give an error? */ put_chip(map, chip, chip->start); spin_unlock(chip->mutex); @@ -1140,8 +1186,8 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof adr += chip->start; - /* Ensure cmd read/writes are aligned. */ - cmd_addr = adr & ~(map_bankwidth(map)-1); + /* Ensure cmd read/writes are aligned. */ + cmd_addr = adr & ~(map_bankwidth(map)-1); spin_lock(chip->mutex); ret = get_chip(map, chip, cmd_addr, FL_READY); @@ -1196,7 +1242,7 @@ static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, siz *retlen += thislen; len -= thislen; buf += thislen; - + ofs = 0; chipnum++; } @@ -1213,12 +1259,17 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, adr += chip->start; - /* Let's determine this according to the interleave only once */ + /* Let's determine those according to the interleave only once */ status_OK = CMD(0x80); switch (mode) { - case FL_WRITING: write_cmd = CMD(0x40); break; - case FL_OTP_WRITE: write_cmd = CMD(0xc0); break; - default: return -EINVAL; + case FL_WRITING: + write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0x40) : CMD(0x41); + break; + case FL_OTP_WRITE: + write_cmd = CMD(0xc0); + break; + default: + return -EINVAL; } spin_lock(chip->mutex); @@ -1259,12 +1310,13 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, status = map_read(map, adr); if (map_word_andequal(map, status, status_OK, status_OK)) break; - + /* OK Still waiting */ if (time_after(jiffies, timeo)) { + map_write(map, CMD(0x70), adr); chip->state = FL_STATUS; xip_enable(map, chip, adr); - printk(KERN_ERR "waiting for chip to be ready timed out in word write\n"); + printk(KERN_ERR "%s: word write error (status timeout)\n", map->name); ret = -EIO; goto out; } @@ -1276,27 +1328,39 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, if (!z) { chip->word_write_time--; if (!chip->word_write_time) - chip->word_write_time++; + chip->word_write_time = 1; } - if (z > 1) + if (z > 1) chip->word_write_time++; /* Done and happy. */ chip->state = FL_STATUS; - /* check for lock bit */ - if (map_word_bitsset(map, status, CMD(0x02))) { - /* clear status */ + /* check for errors */ + if (map_word_bitsset(map, status, CMD(0x1a))) { + unsigned long chipstatus = MERGESTATUS(status); + + /* reset status */ map_write(map, CMD(0x50), adr); - /* put back into read status register mode */ map_write(map, CMD(0x70), adr); - ret = -EROFS; + xip_enable(map, chip, adr); + + if (chipstatus & 0x02) { + ret = -EROFS; + } else if (chipstatus & 0x08) { + printk(KERN_ERR "%s: word write error (bad VPP)\n", map->name); + ret = -EIO; + } else { + printk(KERN_ERR "%s: word write error (status 0x%lx)\n", map->name, chipstatus); + ret = -EINVAL; + } + + goto out; } xip_enable(map, chip, adr); out: put_chip(map, chip, adr); spin_unlock(chip->mutex); - return ret; } @@ -1329,7 +1393,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le ret = do_write_oneword(map, &cfi->chips[chipnum], bus_ofs, datum, FL_WRITING); - if (ret) + if (ret) return ret; len -= n; @@ -1338,13 +1402,13 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le (*retlen) += n; if (ofs >> cfi->chipshift) { - chipnum ++; + chipnum ++; ofs = 0; if (chipnum == cfi->numchips) return 0; } } - + while(len >= map_bankwidth(map)) { map_word datum = map_word_load(map, buf); @@ -1359,7 +1423,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le len -= map_bankwidth(map); if (ofs >> cfi->chipshift) { - chipnum ++; + chipnum ++; ofs = 0; if (chipnum == cfi->numchips) return 0; @@ -1374,9 +1438,9 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le ret = do_write_oneword(map, &cfi->chips[chipnum], ofs, datum, FL_WRITING); - if (ret) + if (ret) return ret; - + (*retlen) += len; } @@ -1384,20 +1448,24 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le } -static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, - unsigned long adr, const u_char *buf, int len) +static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, + unsigned long adr, const struct kvec **pvec, + unsigned long *pvec_seek, int len) { struct cfi_private *cfi = map->fldrv_priv; - map_word status, status_OK; + map_word status, status_OK, write_cmd, datum; unsigned long cmd_adr, timeo; - int wbufsize, z, ret=0, bytes, words; + int wbufsize, z, ret=0, word_gap, words; + const struct kvec *vec; + unsigned long vec_seek; wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; adr += chip->start; cmd_adr = adr & ~(wbufsize-1); - + /* Let's determine this according to the interleave only once */ status_OK = CMD(0x80); + write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0xe8) : CMD(0xe9); spin_lock(chip->mutex); ret = get_chip(map, chip, cmd_adr, FL_WRITING); @@ -1411,7 +1479,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, xip_disable(map, chip, cmd_adr); /* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set - [...], the device will not accept any more Write to Buffer commands". + [...], the device will not accept any more Write to Buffer commands". So we must check here and reset those bits if they're set. Otherwise we're just pissing in the wind */ if (chip->state != FL_STATUS) @@ -1429,7 +1497,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, z = 0; for (;;) { - map_write(map, CMD(0xe8), cmd_adr); + map_write(map, write_cmd, cmd_adr); status = map_read(map, cmd_adr); if (map_word_andequal(map, status, status_OK, status_OK)) @@ -1447,41 +1515,66 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, map_write(map, CMD(0x50), cmd_adr); map_write(map, CMD(0x70), cmd_adr); xip_enable(map, chip, cmd_adr); - printk(KERN_ERR "Chip not ready for buffer write. status = %lx, Xstatus = %lx\n", - status.x[0], Xstatus.x[0]); + printk(KERN_ERR "%s: Chip not ready for buffer write. status = %lx, Xstatus = %lx\n", + map->name, status.x[0], Xstatus.x[0]); ret = -EIO; goto out; } } + /* Figure out the number of words to write */ + word_gap = (-adr & (map_bankwidth(map)-1)); + words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map); + if (!word_gap) { + words--; + } else { + word_gap = map_bankwidth(map) - word_gap; + adr -= word_gap; + datum = map_word_ff(map); + } + /* Write length of data to come */ - bytes = len & (map_bankwidth(map)-1); - words = len / map_bankwidth(map); - map_write(map, CMD(words - !bytes), cmd_adr ); + map_write(map, CMD(words), cmd_adr ); /* Write data */ - z = 0; - while(z < words * map_bankwidth(map)) { - map_word datum = map_word_load(map, buf); - map_write(map, datum, adr+z); + vec = *pvec; + vec_seek = *pvec_seek; + do { + int n = map_bankwidth(map) - word_gap; + if (n > vec->iov_len - vec_seek) + n = vec->iov_len - vec_seek; + if (n > len) + n = len; - z += map_bankwidth(map); - buf += map_bankwidth(map); - } + if (!word_gap && len < map_bankwidth(map)) + datum = map_word_ff(map); - if (bytes) { - map_word datum; + datum = map_word_load_partial(map, datum, + vec->iov_base + vec_seek, + word_gap, n); - datum = map_word_ff(map); - datum = map_word_load_partial(map, datum, buf, 0, bytes); - map_write(map, datum, adr+z); - } + len -= n; + word_gap += n; + if (!len || word_gap == map_bankwidth(map)) { + map_write(map, datum, adr); + adr += map_bankwidth(map); + word_gap = 0; + } + + vec_seek += n; + if (vec_seek == vec->iov_len) { + vec++; + vec_seek = 0; + } + } while (len); + *pvec = vec; + *pvec_seek = vec_seek; /* GO GO GO */ map_write(map, CMD(0xd0), cmd_adr); chip->state = FL_WRITING; - INVALIDATE_CACHE_UDELAY(map, chip, + INVALIDATE_CACHE_UDELAY(map, chip, cmd_adr, len, chip->buffer_write_time); @@ -1507,13 +1600,14 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, /* OK Still waiting */ if (time_after(jiffies, timeo)) { + map_write(map, CMD(0x70), cmd_adr); chip->state = FL_STATUS; xip_enable(map, chip, cmd_adr); - printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n"); + printk(KERN_ERR "%s: buffer write error (status timeout)\n", map->name); ret = -EIO; goto out; } - + /* Latency issues. Drop the lock, wait a while and retry */ z++; UDELAY(map, chip, cmd_adr, 1); @@ -1521,21 +1615,34 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, if (!z) { chip->buffer_write_time--; if (!chip->buffer_write_time) - chip->buffer_write_time++; + chip->buffer_write_time = 1; } - if (z > 1) + if (z > 1) chip->buffer_write_time++; /* Done and happy. */ chip->state = FL_STATUS; - /* check for lock bit */ - if (map_word_bitsset(map, status, CMD(0x02))) { - /* clear status */ + /* check for errors */ + if (map_word_bitsset(map, status, CMD(0x1a))) { + unsigned long chipstatus = MERGESTATUS(status); + + /* reset status */ map_write(map, CMD(0x50), cmd_adr); - /* put back into read status register mode */ - map_write(map, CMD(0x70), adr); - ret = -EROFS; + map_write(map, CMD(0x70), cmd_adr); + xip_enable(map, chip, cmd_adr); + + if (chipstatus & 0x02) { + ret = -EROFS; + } else if (chipstatus & 0x08) { + printk(KERN_ERR "%s: buffer write error (bad VPP)\n", map->name); + ret = -EIO; + } else { + printk(KERN_ERR "%s: buffer write error (status 0x%lx)\n", map->name, chipstatus); + ret = -EINVAL; + } + + goto out; } xip_enable(map, chip, cmd_adr); @@ -1544,70 +1651,65 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, return ret; } -static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to, - size_t len, size_t *retlen, const u_char *buf) +static int cfi_intelext_writev (struct mtd_info *mtd, const struct kvec *vecs, + unsigned long count, loff_t to, size_t *retlen) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; int ret = 0; int chipnum; - unsigned long ofs; + unsigned long ofs, vec_seek, i; + size_t len = 0; + + for (i = 0; i < count; i++) + len += vecs[i].iov_len; *retlen = 0; if (!len) return 0; chipnum = to >> cfi->chipshift; - ofs = to - (chipnum << cfi->chipshift); - - /* If it's not bus-aligned, do the first word write */ - if (ofs & (map_bankwidth(map)-1)) { - size_t local_len = (-ofs)&(map_bankwidth(map)-1); - if (local_len > len) - local_len = len; - ret = cfi_intelext_write_words(mtd, to, local_len, - retlen, buf); - if (ret) - return ret; - ofs += local_len; - buf += local_len; - len -= local_len; - - if (ofs >> cfi->chipshift) { - chipnum ++; - ofs = 0; - if (chipnum == cfi->numchips) - return 0; - } - } + ofs = to - (chipnum << cfi->chipshift); + vec_seek = 0; - while(len) { + do { /* We must not cross write block boundaries */ int size = wbufsize - (ofs & (wbufsize-1)); if (size > len) size = len; - ret = do_write_buffer(map, &cfi->chips[chipnum], - ofs, buf, size); + ret = do_write_buffer(map, &cfi->chips[chipnum], + ofs, &vecs, &vec_seek, size); if (ret) return ret; ofs += size; - buf += size; (*retlen) += size; len -= size; if (ofs >> cfi->chipshift) { - chipnum ++; + chipnum ++; ofs = 0; if (chipnum == cfi->numchips) return 0; } - } + } while (len); + return 0; } +static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to, + size_t len, size_t *retlen, const u_char *buf) +{ + struct kvec vec; + + vec.iov_base = (void *) buf; + vec.iov_len = len; + + return cfi_intelext_writev(mtd, &vec, 1, to, retlen); +} + static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk) { @@ -1673,23 +1775,17 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, status = map_read(map, adr); if (map_word_andequal(map, status, status_OK, status_OK)) break; - + /* OK Still waiting */ if (time_after(jiffies, timeo)) { - map_word Xstatus; map_write(map, CMD(0x70), adr); chip->state = FL_STATUS; - Xstatus = map_read(map, adr); - /* Clear status bits */ - map_write(map, CMD(0x50), adr); - map_write(map, CMD(0x70), adr); xip_enable(map, chip, adr); - printk(KERN_ERR "waiting for erase at %08lx to complete timed out. status = %lx, Xstatus = %lx.\n", - adr, status.x[0], Xstatus.x[0]); + printk(KERN_ERR "%s: block erase error: (status timeout)\n", map->name); ret = -EIO; goto out; } - + /* Latency issues. Drop the lock, wait a while and retry */ UDELAY(map, chip, adr, 1000000/HZ); } @@ -1699,43 +1795,40 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, chip->state = FL_STATUS; status = map_read(map, adr); - /* check for lock bit */ + /* check for errors */ if (map_word_bitsset(map, status, CMD(0x3a))) { - unsigned long chipstatus; + unsigned long chipstatus = MERGESTATUS(status); /* Reset the error bits */ map_write(map, CMD(0x50), adr); map_write(map, CMD(0x70), adr); xip_enable(map, chip, adr); - chipstatus = MERGESTATUS(status); - if ((chipstatus & 0x30) == 0x30) { - printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%lx\n", chipstatus); - ret = -EIO; + printk(KERN_ERR "%s: block erase error: (bad command sequence, status 0x%lx)\n", map->name, chipstatus); + ret = -EINVAL; } else if (chipstatus & 0x02) { /* Protection bit set */ ret = -EROFS; } else if (chipstatus & 0x8) { /* Voltage */ - printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%lx\n", chipstatus); + printk(KERN_ERR "%s: block erase error: (bad VPP)\n", map->name); ret = -EIO; - } else if (chipstatus & 0x20) { - if (retries--) { - printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus); - timeo = jiffies + HZ; - put_chip(map, chip, adr); - spin_unlock(chip->mutex); - goto retry; - } - printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%lx\n", adr, chipstatus); + } else if (chipstatus & 0x20 && retries--) { + printk(KERN_DEBUG "block erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus); + timeo = jiffies + HZ; + put_chip(map, chip, adr); + spin_unlock(chip->mutex); + goto retry; + } else { + printk(KERN_ERR "%s: block erase failed at 0x%08lx (status 0x%lx)\n", map->name, adr, chipstatus); ret = -EIO; } - } else { - xip_enable(map, chip, adr); - ret = 0; + + goto out; } + xip_enable(map, chip, adr); out: put_chip(map, chip, adr); spin_unlock(chip->mutex); return ret; @@ -1755,7 +1848,7 @@ int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); - + return 0; } @@ -1776,7 +1869,7 @@ static void cfi_intelext_sync (struct mtd_info *mtd) if (!ret) { chip->oldstate = chip->state; chip->state = FL_SYNCING; - /* No need to wake_up() on this state change - + /* No need to wake_up() on this state change - * as the whole point is that nobody can do anything * with the chip now anyway. */ @@ -1790,7 +1883,7 @@ static void cfi_intelext_sync (struct mtd_info *mtd) chip = &cfi->chips[i]; spin_lock(chip->mutex); - + if (chip->state == FL_SYNCING) { chip->state = chip->oldstate; chip->oldstate = FL_READY; @@ -1847,7 +1940,7 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip ENABLE_VPP(map); xip_disable(map, chip, adr); - + map_write(map, CMD(0x60), adr); if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) { map_write(map, CMD(0x01), adr); @@ -1875,25 +1968,22 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip status = map_read(map, adr); if (map_word_andequal(map, status, status_OK, status_OK)) break; - + /* OK Still waiting */ if (time_after(jiffies, timeo)) { - map_word Xstatus; map_write(map, CMD(0x70), adr); chip->state = FL_STATUS; - Xstatus = map_read(map, adr); xip_enable(map, chip, adr); - printk(KERN_ERR "waiting for unlock to complete timed out. status = %lx, Xstatus = %lx.\n", - status.x[0], Xstatus.x[0]); + printk(KERN_ERR "%s: block unlock error: (status timeout)\n", map->name); put_chip(map, chip, adr); spin_unlock(chip->mutex); return -EIO; } - + /* Latency issues. Drop the lock, wait a while and retry */ UDELAY(map, chip, adr, 1); } - + /* Done and happy. */ chip->state = FL_STATUS; xip_enable(map, chip, adr); @@ -1913,9 +2003,9 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len) ofs, len, 0); #endif - ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, + ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, ofs, len, DO_XXLOCK_ONEBLOCK_LOCK); - + #ifdef DEBUG_LOCK_BITS printk(KERN_DEBUG "%s: lock status after, ret=%d\n", __FUNCTION__, ret); @@ -1939,20 +2029,20 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, ofs, len, DO_XXLOCK_ONEBLOCK_UNLOCK); - + #ifdef DEBUG_LOCK_BITS printk(KERN_DEBUG "%s: lock status after, ret=%d\n", __FUNCTION__, ret); - cfi_varsize_frob(mtd, do_printlockstatus_oneblock, + cfi_varsize_frob(mtd, do_printlockstatus_oneblock, ofs, len, 0); #endif - + return ret; } #ifdef CONFIG_MTD_OTP -typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip, +typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip, u_long data_offset, u_char *buf, u_int size, u_long prot_offset, u_int groupno, u_int groupsize); @@ -2003,7 +2093,7 @@ do_otp_write(struct map_info *map, struct flchip *chip, u_long offset, datum = map_word_load_partial(map, datum, buf, gap, n); ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE); - if (ret) + if (ret) return ret; offset += n; @@ -2196,7 +2286,7 @@ static int cfi_intelext_lock_user_prot_reg(struct mtd_info *mtd, NULL, do_otp_lock, 1); } -static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd, +static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf, size_t len) { size_t retlen; @@ -2239,7 +2329,7 @@ static int cfi_intelext_suspend(struct mtd_info *mtd) if (chip->oldstate == FL_READY) { chip->oldstate = chip->state; chip->state = FL_PM_SUSPENDED; - /* No need to wake_up() on this state change - + /* No need to wake_up() on this state change - * as the whole point is that nobody can do anything * with the chip now anyway. */ @@ -2267,9 +2357,9 @@ static int cfi_intelext_suspend(struct mtd_info *mtd) if (ret) { for (i--; i >=0; i--) { chip = &cfi->chips[i]; - + spin_lock(chip->mutex); - + if (chip->state == FL_PM_SUSPENDED) { /* No need to force it into a known state here, because we're returning failure, and it didn't @@ -2280,8 +2370,8 @@ static int cfi_intelext_suspend(struct mtd_info *mtd) } spin_unlock(chip->mutex); } - } - + } + return ret; } @@ -2293,11 +2383,11 @@ static void cfi_intelext_resume(struct mtd_info *mtd) struct flchip *chip; for (i=0; inumchips; i++) { - + chip = &cfi->chips[i]; spin_lock(chip->mutex); - + /* Go to known state. Chip may have been power cycled */ if (chip->state == FL_PM_SUSPENDED) { map_write(map, CMD(0xFF), cfi->chips[i].start); @@ -2319,7 +2409,7 @@ static int cfi_intelext_reset(struct mtd_info *mtd) struct flchip *chip = &cfi->chips[i]; /* force the completion of any ongoing operation - and switch to array mode so any bootloader in + and switch to array mode so any bootloader in flash is accessible for soft reboot. */ spin_lock(chip->mutex); ret = get_chip(map, chip, chip->start, FL_SYNCING); @@ -2356,20 +2446,23 @@ static void cfi_intelext_destroy(struct mtd_info *mtd) kfree(mtd->eraseregions); } -static char im_name_1[]="cfi_cmdset_0001"; -static char im_name_3[]="cfi_cmdset_0003"; +static char im_name_0001[] = "cfi_cmdset_0001"; +static char im_name_0003[] = "cfi_cmdset_0003"; +static char im_name_0200[] = "cfi_cmdset_0200"; static int __init cfi_intelext_init(void) { - inter_module_register(im_name_1, THIS_MODULE, &cfi_cmdset_0001); - inter_module_register(im_name_3, THIS_MODULE, &cfi_cmdset_0001); + inter_module_register(im_name_0001, THIS_MODULE, &cfi_cmdset_0001); + inter_module_register(im_name_0003, THIS_MODULE, &cfi_cmdset_0001); + inter_module_register(im_name_0200, THIS_MODULE, &cfi_cmdset_0001); return 0; } static void __exit cfi_intelext_exit(void) { - inter_module_unregister(im_name_1); - inter_module_unregister(im_name_3); + inter_module_unregister(im_name_0001); + inter_module_unregister(im_name_0003); + inter_module_unregister(im_name_0200); } module_init(cfi_intelext_init); diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 8505f118f2dbfcd8d7275c3cb1af5292eaaaca0d..aed10bd5c3c3869cb52732d764004753a30aa319 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -10,14 +10,14 @@ * * 4_by_16 work by Carolyn J. Smith * - * XIP support hooks by Vitaly Wool (based on code for Intel flash + * XIP support hooks by Vitaly Wool (based on code for Intel flash * by Nicolas Pitre) - * + * * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com * * This code is GPL * - * $Id: cfi_cmdset_0002.c,v 1.118 2005/07/04 22:34:29 gleixner Exp $ + * $Id: cfi_cmdset_0002.c,v 1.122 2005/11/07 11:14:22 gleixner Exp $ * */ @@ -93,7 +93,7 @@ static void cfi_tell_features(struct cfi_pri_amdstd *extp) }; printk(" Silicon revision: %d\n", extp->SiliconRevision >> 1); - printk(" Address sensitive unlock: %s\n", + printk(" Address sensitive unlock: %s\n", (extp->SiliconRevision & 1) ? "Not required" : "Required"); if (extp->EraseSuspend < ARRAY_SIZE(erase_suspend)) @@ -118,9 +118,9 @@ static void cfi_tell_features(struct cfi_pri_amdstd *extp) else printk(" Page mode: %d word page\n", extp->PageMode << 2); - printk(" Vpp Supply Minimum Program/Erase Voltage: %d.%d V\n", + printk(" Vpp Supply Minimum Program/Erase Voltage: %d.%d V\n", extp->VppMin >> 4, extp->VppMin & 0xf); - printk(" Vpp Supply Maximum Program/Erase Voltage: %d.%d V\n", + printk(" Vpp Supply Maximum Program/Erase Voltage: %d.%d V\n", extp->VppMax >> 4, extp->VppMax & 0xf); if (extp->TopBottom < ARRAY_SIZE(top_bottom)) @@ -177,7 +177,7 @@ static void fixup_use_erase_chip(struct mtd_info *mtd, void *param) ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0)) { mtd->erase = cfi_amdstd_erase_chip; } - + } static struct cfi_fixup cfi_fixup_table[] = { @@ -239,7 +239,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) if (cfi->cfi_mode==CFI_MODE_CFI){ unsigned char bootloc; - /* + /* * It's a real CFI chip, not one for which the probe * routine faked a CFI structure. So we read the feature * table from it. @@ -253,8 +253,18 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) return NULL; } + if (extp->MajorVersion != '1' || + (extp->MinorVersion < '0' || extp->MinorVersion > '4')) { + printk(KERN_ERR " Unknown Amd/Fujitsu Extended Query " + "version %c.%c.\n", extp->MajorVersion, + extp->MinorVersion); + kfree(extp); + kfree(mtd); + return NULL; + } + /* Install our own private info structure */ - cfi->cmdset_priv = extp; + cfi->cmdset_priv = extp; /* Apply cfi device specific fixups */ cfi_fixup(mtd, cfi_fixup_table); @@ -262,7 +272,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) #ifdef DEBUG_CFI_FEATURES /* Tell the user about it in lots of lovely detail */ cfi_tell_features(extp); -#endif +#endif bootloc = extp->TopBottom; if ((bootloc != 2) && (bootloc != 3)) { @@ -273,11 +283,11 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) if (bootloc == 3 && cfi->cfiq->NumEraseRegions > 1) { printk(KERN_WARNING "%s: Swapping erase regions for broken CFI table.\n", map->name); - + for (i=0; icfiq->NumEraseRegions / 2; i++) { int j = (cfi->cfiq->NumEraseRegions-1)-i; __u32 swap; - + swap = cfi->cfiq->EraseRegionInfo[i]; cfi->cfiq->EraseRegionInfo[i] = cfi->cfiq->EraseRegionInfo[j]; cfi->cfiq->EraseRegionInfo[j] = swap; @@ -288,11 +298,11 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) cfi->addr_unlock2 = 0x2aa; /* Modify the unlock address if we are in compatibility mode */ if ( /* x16 in x8 mode */ - ((cfi->device_type == CFI_DEVICETYPE_X8) && + ((cfi->device_type == CFI_DEVICETYPE_X8) && (cfi->cfiq->InterfaceDesc == 2)) || /* x32 in x16 mode */ ((cfi->device_type == CFI_DEVICETYPE_X16) && - (cfi->cfiq->InterfaceDesc == 4))) + (cfi->cfiq->InterfaceDesc == 4))) { cfi->addr_unlock1 = 0xaaa; cfi->addr_unlock2 = 0x555; @@ -310,10 +320,10 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) cfi->chips[i].word_write_time = 1<cfiq->WordWriteTimeoutTyp; cfi->chips[i].buffer_write_time = 1<cfiq->BufWriteTimeoutTyp; cfi->chips[i].erase_time = 1<cfiq->BlockEraseTimeoutTyp; - } - + } + map->fldrv = &cfi_amdstd_chipdrv; - + return cfi_amdstd_setup(mtd); } @@ -326,24 +336,24 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd) unsigned long offset = 0; int i,j; - printk(KERN_NOTICE "number of %s chips: %d\n", + printk(KERN_NOTICE "number of %s chips: %d\n", (cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips); - /* Select the correct geometry setup */ + /* Select the correct geometry setup */ mtd->size = devsize * cfi->numchips; mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions, GFP_KERNEL); - if (!mtd->eraseregions) { + if (!mtd->eraseregions) { printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n"); goto setup_err; } - + for (i=0; icfiq->NumEraseRegions; i++) { unsigned long ernum, ersize; ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave; ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1; - + if (mtd->erasesize < ersize) { mtd->erasesize = ersize; } @@ -378,8 +388,7 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd) setup_err: if(mtd) { - if(mtd->eraseregions) - kfree(mtd->eraseregions); + kfree(mtd->eraseregions); kfree(mtd); } kfree(cfi->cmdset_priv); @@ -430,7 +439,7 @@ static int __xipram chip_good(struct map_info *map, unsigned long addr, map_word oldd = map_read(map, addr); curd = map_read(map, addr); - return map_word_equal(map, oldd, curd) && + return map_word_equal(map, oldd, curd) && map_word_equal(map, curd, expected); } @@ -462,7 +471,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr /* Someone else might have been playing with it. */ goto retry; } - + case FL_READY: case FL_CFI_QUERY: case FL_JEDEC_QUERY: @@ -505,7 +514,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__); return -EIO; } - + spin_unlock(chip->mutex); cfi_udelay(1); spin_lock(chip->mutex); @@ -608,7 +617,7 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip, * When a delay is required for the flash operation to complete, the * xip_udelay() function is polling for both the given timeout and pending * (but still masked) hardware interrupts. Whenever there is an interrupt - * pending then the flash erase operation is suspended, array mode restored + * pending then the flash erase operation is suspended, array mode restored * and interrupts unmasked. Task scheduling might also happen at that * point. The CPU eventually returns from the interrupt or the call to * schedule() and the suspended flash operation is resumed for the remaining @@ -632,9 +641,9 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, ((chip->state == FL_ERASING && (extp->EraseSuspend & 2))) && (cfi_interleave_is_1(cfi) || chip->oldstate == FL_READY)) { /* - * Let's suspend the erase operation when supported. - * Note that we currently don't try to suspend - * interleaved chips if there is already another + * Let's suspend the erase operation when supported. + * Note that we currently don't try to suspend + * interleaved chips if there is already another * operation suspended (imagine what happens * when one chip was already done with the current * operation while another chip suspended it, then @@ -770,8 +779,8 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof adr += chip->start; - /* Ensure cmd read/writes are aligned. */ - cmd_addr = adr & ~(map_bankwidth(map)-1); + /* Ensure cmd read/writes are aligned. */ + cmd_addr = adr & ~(map_bankwidth(map)-1); spin_lock(chip->mutex); ret = get_chip(map, chip, cmd_addr, FL_READY); @@ -851,7 +860,7 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi #endif set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - + spin_unlock(chip->mutex); schedule(); @@ -863,7 +872,7 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi timeo = jiffies + HZ; goto retry; - } + } adr += chip->start; @@ -872,14 +881,14 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); - + map_copy_from(map, buf, adr, len); cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); - + wake_up(&chip->wq); spin_unlock(chip->mutex); @@ -988,7 +997,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, chip->word_write_time); /* See comment above for timeout value. */ - timeo = jiffies + uWriteTimeout; + timeo = jiffies + uWriteTimeout; for (;;) { if (chip->state != FL_WRITING) { /* Someone's suspended the write. Sleep */ @@ -1004,16 +1013,16 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, continue; } - if (chip_ready(map, adr)) - break; - - if (time_after(jiffies, timeo)) { + if (time_after(jiffies, timeo) && !chip_ready(map, adr)){ xip_enable(map, chip, adr); printk(KERN_WARNING "MTD %s(): software timeout\n", __func__); xip_disable(map, chip, adr); - break; + break; } + if (chip_ready(map, adr)) + break; + /* Latency issues. Drop the lock, wait a while and retry */ UDELAY(map, chip, adr, 1); } @@ -1023,7 +1032,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, map_write( map, CMD(0xF0), chip->start ); /* FIXME - should have reset delay before continuing */ - if (++retry_cnt <= MAX_WORD_RETRIES) + if (++retry_cnt <= MAX_WORD_RETRIES) goto retry; ret = -EIO; @@ -1091,27 +1100,27 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, /* Number of bytes to copy from buffer */ n = min_t(int, len, map_bankwidth(map)-i); - + tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n); - ret = do_write_oneword(map, &cfi->chips[chipnum], + ret = do_write_oneword(map, &cfi->chips[chipnum], bus_ofs, tmp_buf); - if (ret) + if (ret) return ret; - + ofs += n; buf += n; (*retlen) += n; len -= n; if (ofs >> cfi->chipshift) { - chipnum ++; + chipnum ++; ofs = 0; if (chipnum == cfi->numchips) return 0; } } - + /* We are now aligned, write as much as possible */ while(len >= map_bankwidth(map)) { map_word datum; @@ -1129,7 +1138,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, len -= map_bankwidth(map); if (ofs >> cfi->chipshift) { - chipnum ++; + chipnum ++; ofs = 0; if (chipnum == cfi->numchips) return 0; @@ -1167,12 +1176,12 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, spin_unlock(cfi->chips[chipnum].mutex); tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len); - - ret = do_write_oneword(map, &cfi->chips[chipnum], + + ret = do_write_oneword(map, &cfi->chips[chipnum], ofs, tmp_buf); - if (ret) + if (ret) return ret; - + (*retlen) += len; } @@ -1184,7 +1193,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, * FIXME: interleaved mode not tested, and probably not supported! */ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, - unsigned long adr, const u_char *buf, + unsigned long adr, const u_char *buf, int len) { struct cfi_private *cfi = map->fldrv_priv; @@ -1214,7 +1223,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, XIP_INVAL_CACHED_RANGE(map, adr, len); ENABLE_VPP(map); xip_disable(map, chip, cmd_adr); - + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); //cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); @@ -1248,8 +1257,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, adr, map_bankwidth(map), chip->word_write_time); - timeo = jiffies + uWriteTimeout; - + timeo = jiffies + uWriteTimeout; + for (;;) { if (chip->state != FL_WRITING) { /* Someone's suspended the write. Sleep */ @@ -1265,13 +1274,13 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, continue; } + if (time_after(jiffies, timeo) && !chip_ready(map, adr)) + break; + if (chip_ready(map, adr)) { xip_enable(map, chip, adr); goto op_done; } - - if( time_after(jiffies, timeo)) - break; /* Latency issues. Drop the lock, wait a while and retry */ UDELAY(map, chip, adr, 1); @@ -1343,7 +1352,7 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len, if (size % map_bankwidth(map)) size -= size % map_bankwidth(map); - ret = do_write_buffer(map, &cfi->chips[chipnum], + ret = do_write_buffer(map, &cfi->chips[chipnum], ofs, buf, size); if (ret) return ret; @@ -1354,7 +1363,7 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len, len -= size; if (ofs >> cfi->chipshift) { - chipnum ++; + chipnum ++; ofs = 0; if (chipnum == cfi->numchips) return 0; @@ -1571,7 +1580,7 @@ int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); - + return 0; } @@ -1594,7 +1603,7 @@ static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr) instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); - + return 0; } @@ -1621,7 +1630,7 @@ static void cfi_amdstd_sync (struct mtd_info *mtd) case FL_JEDEC_QUERY: chip->oldstate = chip->state; chip->state = FL_SYNCING; - /* No need to wake_up() on this state change - + /* No need to wake_up() on this state change - * as the whole point is that nobody can do anything * with the chip now anyway. */ @@ -1632,13 +1641,13 @@ static void cfi_amdstd_sync (struct mtd_info *mtd) default: /* Not an idle state */ add_wait_queue(&chip->wq, &wait); - + spin_unlock(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); - + goto retry; } } @@ -1649,7 +1658,7 @@ static void cfi_amdstd_sync (struct mtd_info *mtd) chip = &cfi->chips[i]; spin_lock(chip->mutex); - + if (chip->state == FL_SYNCING) { chip->state = chip->oldstate; wake_up(&chip->wq); @@ -1679,7 +1688,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd) case FL_JEDEC_QUERY: chip->oldstate = chip->state; chip->state = FL_PM_SUSPENDED; - /* No need to wake_up() on this state change - + /* No need to wake_up() on this state change - * as the whole point is that nobody can do anything * with the chip now anyway. */ @@ -1700,7 +1709,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd) chip = &cfi->chips[i]; spin_lock(chip->mutex); - + if (chip->state == FL_PM_SUSPENDED) { chip->state = chip->oldstate; wake_up(&chip->wq); @@ -1708,7 +1717,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd) spin_unlock(chip->mutex); } } - + return ret; } @@ -1721,11 +1730,11 @@ static void cfi_amdstd_resume(struct mtd_info *mtd) struct flchip *chip; for (i=0; inumchips; i++) { - + chip = &cfi->chips[i]; spin_lock(chip->mutex); - + if (chip->state == FL_PM_SUSPENDED) { chip->state = FL_READY; map_write(map, CMD(0xF0), chip->start); @@ -1742,6 +1751,7 @@ static void cfi_amdstd_destroy(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; + kfree(cfi->cmdset_priv); kfree(cfi->cfiq); kfree(cfi); diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index c894f880157831f1d1c3524aa77d9a462d77dd60..c4a19d2dc67f6aabdc88977311dbd4ba2fa109ce 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c @@ -4,8 +4,8 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0020.c,v 1.19 2005/07/13 15:52:45 dwmw2 Exp $ - * + * $Id: cfi_cmdset_0020.c,v 1.22 2005/11/07 11:14:22 gleixner Exp $ + * * 10/10/2000 Nicolas Pitre * - completely revamped method functions so they are aware and * independent of the flash geometry (buswidth, interleave, etc.) @@ -81,17 +81,17 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp) printk(" - Page-mode read: %s\n", extp->FeatureSupport&128?"supported":"unsupported"); printk(" - Synchronous read: %s\n", extp->FeatureSupport&256?"supported":"unsupported"); for (i=9; i<32; i++) { - if (extp->FeatureSupport & (1<FeatureSupport & (1<SuspendCmdSupport); printk(" - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported"); for (i=1; i<8; i++) { if (extp->SuspendCmdSupport & (1<BlkStatusRegMask); printk(" - Lock Bit Active: %s\n", extp->BlkStatusRegMask&1?"yes":"no"); printk(" - Valid Bit Active: %s\n", extp->BlkStatusRegMask&2?"yes":"no"); @@ -99,11 +99,11 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp) if (extp->BlkStatusRegMask & (1<VccOptimal >> 8, extp->VccOptimal & 0xf); if (extp->VppOptimal) - printk(" Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", + printk(" Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", extp->VppOptimal >> 8, extp->VppOptimal & 0xf); } #endif @@ -121,7 +121,7 @@ struct mtd_info *cfi_cmdset_0020(struct map_info *map, int primary) int i; if (cfi->cfi_mode) { - /* + /* * It's a real CFI chip, not one for which the probe * routine faked a CFI structure. So we read the feature * table from it. @@ -133,24 +133,33 @@ struct mtd_info *cfi_cmdset_0020(struct map_info *map, int primary) if (!extp) return NULL; + if (extp->MajorVersion != '1' || + (extp->MinorVersion < '0' || extp->MinorVersion > '3')) { + printk(KERN_ERR " Unknown ST Microelectronics" + " Extended Query version %c.%c.\n", + extp->MajorVersion, extp->MinorVersion); + kfree(extp); + return NULL; + } + /* Do some byteswapping if necessary */ extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport); extp->BlkStatusRegMask = cfi32_to_cpu(extp->BlkStatusRegMask); - + #ifdef DEBUG_CFI_FEATURES /* Tell the user about it in lots of lovely detail */ cfi_tell_features(extp); -#endif +#endif /* Install our own private info structure */ cfi->cmdset_priv = extp; - } + } for (i=0; i< cfi->numchips; i++) { cfi->chips[i].word_write_time = 128; cfi->chips[i].buffer_write_time = 128; cfi->chips[i].erase_time = 1024; - } + } return cfi_staa_setup(map); } @@ -178,15 +187,15 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map) mtd->size = devsize * cfi->numchips; mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; - mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) + mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions, GFP_KERNEL); - if (!mtd->eraseregions) { + if (!mtd->eraseregions) { printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n"); kfree(cfi->cmdset_priv); kfree(mtd); return NULL; } - + for (i=0; icfiq->NumEraseRegions; i++) { unsigned long ernum, ersize; ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave; @@ -219,7 +228,7 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map) mtd->eraseregions[i].numblocks); } - /* Also select the correct geometry setup too */ + /* Also select the correct geometry setup too */ mtd->erase = cfi_staa_erase_varsize; mtd->read = cfi_staa_read; mtd->write = cfi_staa_write_buffers; @@ -250,8 +259,8 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof adr += chip->start; - /* Ensure cmd read/writes are aligned. */ - cmd_addr = adr & ~(map_bankwidth(map)-1); + /* Ensure cmd read/writes are aligned. */ + cmd_addr = adr & ~(map_bankwidth(map)-1); /* Let's determine this according to the interleave only once */ status_OK = CMD(0x80); @@ -267,7 +276,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof case FL_ERASING: if (!(((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2)) goto sleep; /* We don't support erase suspend */ - + map_write (map, CMD(0xb0), cmd_addr); /* If the flash has finished erasing, then 'erase suspend' * appears to make some (28F320) flash devices switch to @@ -282,7 +291,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof status = map_read(map, cmd_addr); if (map_word_andequal(map, status, status_OK, status_OK)) break; - + if (time_after(jiffies, timeo)) { /* Urgh */ map_write(map, CMD(0xd0), cmd_addr); @@ -294,17 +303,17 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof "suspended: status = 0x%lx\n", status.x[0]); return -EIO; } - + spin_unlock_bh(chip->mutex); cfi_udelay(1); spin_lock_bh(chip->mutex); } - + suspended = 1; map_write(map, CMD(0xff), cmd_addr); chip->state = FL_READY; break; - + #if 0 case FL_WRITING: /* Not quite yet */ @@ -325,7 +334,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof chip->state = FL_READY; break; } - + /* Urgh. Chip not yet ready to talk to us. */ if (time_after(jiffies, timeo)) { spin_unlock_bh(chip->mutex); @@ -355,17 +364,17 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof if (suspended) { chip->state = chip->oldstate; - /* What if one interleaved chip has finished and the + /* What if one interleaved chip has finished and the other hasn't? The old code would leave the finished - one in READY mode. That's bad, and caused -EROFS + one in READY mode. That's bad, and caused -EROFS errors to be returned from do_erase_oneblock because that's the only bit it checked for at the time. - As the state machine appears to explicitly allow + As the state machine appears to explicitly allow sending the 0x70 (Read Status) command to an erasing - chip and expecting it to be ignored, that's what we + chip and expecting it to be ignored, that's what we do. */ map_write(map, CMD(0xd0), cmd_addr); - map_write(map, CMD(0x70), cmd_addr); + map_write(map, CMD(0x70), cmd_addr); } wake_up(&chip->wq); @@ -405,14 +414,14 @@ static int cfi_staa_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen += thislen; len -= thislen; buf += thislen; - + ofs = 0; chipnum++; } return ret; } -static inline int do_write_buffer(struct map_info *map, struct flchip *chip, +static inline int do_write_buffer(struct map_info *map, struct flchip *chip, unsigned long adr, const u_char *buf, int len) { struct cfi_private *cfi = map->fldrv_priv; @@ -420,7 +429,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, unsigned long cmd_adr, timeo; DECLARE_WAITQUEUE(wait, current); int wbufsize, z; - + /* M58LW064A requires bus alignment for buffer wriets -- saw */ if (adr & (map_bankwidth(map)-1)) return -EINVAL; @@ -428,10 +437,10 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; adr += chip->start; cmd_adr = adr & ~(wbufsize-1); - + /* Let's determine this according to the interleave only once */ status_OK = CMD(0x80); - + timeo = jiffies + HZ; retry: @@ -439,7 +448,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, printk("%s: chip->state[%d]\n", __FUNCTION__, chip->state); #endif spin_lock_bh(chip->mutex); - + /* Check that the chip's ready to talk to us. * Later, we can actually think about interrupting it * if it's in FL_ERASING state. @@ -448,7 +457,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, switch (chip->state) { case FL_READY: break; - + case FL_CFI_QUERY: case FL_JEDEC_QUERY: map_write(map, CMD(0x70), cmd_adr); @@ -513,7 +522,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, /* Write length of data to come */ map_write(map, CMD(len/map_bankwidth(map)-1), cmd_adr ); - + /* Write data */ for (z = 0; z < len; z += map_bankwidth(map), buf += map_bankwidth(map)) { @@ -560,7 +569,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n"); return -EIO; } - + /* Latency issues. Drop the lock, wait a while and retry */ spin_unlock_bh(chip->mutex); cfi_udelay(1); @@ -572,9 +581,9 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, if (!chip->buffer_write_time) chip->buffer_write_time++; } - if (z > 1) + if (z > 1) chip->buffer_write_time++; - + /* Done and happy. */ DISABLE_VPP(map); chip->state = FL_STATUS; @@ -598,7 +607,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, return 0; } -static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to, +static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { struct map_info *map = mtd->priv; @@ -620,7 +629,7 @@ static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to, printk("%s: chipnum[%x] wbufsize[%x]\n", __FUNCTION__, chipnum, wbufsize); printk("%s: ofs[%x] len[%x]\n", __FUNCTION__, ofs, len); #endif - + /* Write buffer is worth it only if more than one word to write... */ while (len > 0) { /* We must not cross write block boundaries */ @@ -629,7 +638,7 @@ static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to, if (size > len) size = len; - ret = do_write_buffer(map, &cfi->chips[chipnum], + ret = do_write_buffer(map, &cfi->chips[chipnum], ofs, buf, size); if (ret) return ret; @@ -640,13 +649,13 @@ static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to, len -= size; if (ofs >> cfi->chipshift) { - chipnum ++; + chipnum ++; ofs = 0; if (chipnum == cfi->numchips) return 0; } } - + return 0; } @@ -756,7 +765,7 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u status = map_read(map, adr); if (map_word_andequal(map, status, status_OK, status_OK)) break; - + /* Urgh. Chip not yet ready to talk to us. */ if (time_after(jiffies, timeo)) { spin_unlock_bh(chip->mutex); @@ -789,7 +798,7 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u map_write(map, CMD(0x20), adr); map_write(map, CMD(0xD0), adr); chip->state = FL_ERASING; - + spin_unlock_bh(chip->mutex); msleep(1000); spin_lock_bh(chip->mutex); @@ -814,7 +823,7 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u status = map_read(map, adr); if (map_word_andequal(map, status, status_OK, status_OK)) break; - + /* OK Still waiting */ if (time_after(jiffies, timeo)) { map_write(map, CMD(0x70), adr); @@ -824,13 +833,13 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u spin_unlock_bh(chip->mutex); return -EIO; } - + /* Latency issues. Drop the lock, wait a while and retry */ spin_unlock_bh(chip->mutex); cfi_udelay(1); spin_lock_bh(chip->mutex); } - + DISABLE_VPP(map); ret = 0; @@ -855,7 +864,7 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u /* Reset the error bits */ map_write(map, CMD(0x50), adr); map_write(map, CMD(0x70), adr); - + if ((chipstatus & 0x30) == 0x30) { printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", chipstatus); ret = -EIO; @@ -904,17 +913,17 @@ int cfi_staa_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) i = 0; - /* Skip all erase regions which are ended before the start of + /* Skip all erase regions which are ended before the start of the requested erase. Actually, to save on the calculations, we skip to the first erase region which starts after the start of the requested erase, and then go back one. */ - + while (i < mtd->numeraseregions && instr->addr >= regions[i].offset) i++; i--; - /* OK, now i is pointing at the erase region in which this + /* OK, now i is pointing at the erase region in which this erase request starts. Check the start of the requested erase range is aligned with the erase size which is in effect here. @@ -937,7 +946,7 @@ int cfi_staa_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) the address actually falls */ i--; - + if ((instr->addr + instr->len) & (regions[i].erasesize-1)) return -EINVAL; @@ -949,7 +958,7 @@ int cfi_staa_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) while(len) { ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr); - + if (ret) return ret; @@ -962,15 +971,15 @@ int cfi_staa_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) if (adr >> cfi->chipshift) { adr = 0; chipnum++; - + if (chipnum >= cfi->numchips) break; } } - + instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); - + return 0; } @@ -996,7 +1005,7 @@ static void cfi_staa_sync (struct mtd_info *mtd) case FL_JEDEC_QUERY: chip->oldstate = chip->state; chip->state = FL_SYNCING; - /* No need to wake_up() on this state change - + /* No need to wake_up() on this state change - * as the whole point is that nobody can do anything * with the chip now anyway. */ @@ -1007,11 +1016,11 @@ static void cfi_staa_sync (struct mtd_info *mtd) default: /* Not an idle state */ add_wait_queue(&chip->wq, &wait); - + spin_unlock_bh(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); - + goto retry; } } @@ -1022,7 +1031,7 @@ static void cfi_staa_sync (struct mtd_info *mtd) chip = &cfi->chips[i]; spin_lock_bh(chip->mutex); - + if (chip->state == FL_SYNCING) { chip->state = chip->oldstate; wake_up(&chip->wq); @@ -1057,9 +1066,9 @@ static inline int do_lock_oneblock(struct map_info *map, struct flchip *chip, un case FL_STATUS: status = map_read(map, adr); - if (map_word_andequal(map, status, status_OK, status_OK)) + if (map_word_andequal(map, status, status_OK, status_OK)) break; - + /* Urgh. Chip not yet ready to talk to us. */ if (time_after(jiffies, timeo)) { spin_unlock_bh(chip->mutex); @@ -1088,7 +1097,7 @@ static inline int do_lock_oneblock(struct map_info *map, struct flchip *chip, un map_write(map, CMD(0x60), adr); map_write(map, CMD(0x01), adr); chip->state = FL_LOCKING; - + spin_unlock_bh(chip->mutex); msleep(1000); spin_lock_bh(chip->mutex); @@ -1102,7 +1111,7 @@ static inline int do_lock_oneblock(struct map_info *map, struct flchip *chip, un status = map_read(map, adr); if (map_word_andequal(map, status, status_OK, status_OK)) break; - + /* OK Still waiting */ if (time_after(jiffies, timeo)) { map_write(map, CMD(0x70), adr); @@ -1112,13 +1121,13 @@ static inline int do_lock_oneblock(struct map_info *map, struct flchip *chip, un spin_unlock_bh(chip->mutex); return -EIO; } - + /* Latency issues. Drop the lock, wait a while and retry */ spin_unlock_bh(chip->mutex); cfi_udelay(1); spin_lock_bh(chip->mutex); } - + /* Done and happy. */ chip->state = FL_STATUS; DISABLE_VPP(map); @@ -1162,8 +1171,8 @@ static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len) cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); printk("after lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor))); cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); -#endif - +#endif + if (ret) return ret; @@ -1173,7 +1182,7 @@ static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len) if (adr >> cfi->chipshift) { adr = 0; chipnum++; - + if (chipnum >= cfi->numchips) break; } @@ -1208,7 +1217,7 @@ static inline int do_unlock_oneblock(struct map_info *map, struct flchip *chip, status = map_read(map, adr); if (map_word_andequal(map, status, status_OK, status_OK)) break; - + /* Urgh. Chip not yet ready to talk to us. */ if (time_after(jiffies, timeo)) { spin_unlock_bh(chip->mutex); @@ -1237,7 +1246,7 @@ static inline int do_unlock_oneblock(struct map_info *map, struct flchip *chip, map_write(map, CMD(0x60), adr); map_write(map, CMD(0xD0), adr); chip->state = FL_UNLOCKING; - + spin_unlock_bh(chip->mutex); msleep(1000); spin_lock_bh(chip->mutex); @@ -1251,7 +1260,7 @@ static inline int do_unlock_oneblock(struct map_info *map, struct flchip *chip, status = map_read(map, adr); if (map_word_andequal(map, status, status_OK, status_OK)) break; - + /* OK Still waiting */ if (time_after(jiffies, timeo)) { map_write(map, CMD(0x70), adr); @@ -1261,13 +1270,13 @@ static inline int do_unlock_oneblock(struct map_info *map, struct flchip *chip, spin_unlock_bh(chip->mutex); return -EIO; } - + /* Latency issues. Drop the unlock, wait a while and retry */ spin_unlock_bh(chip->mutex); cfi_udelay(1); spin_lock_bh(chip->mutex); } - + /* Done and happy. */ chip->state = FL_STATUS; DISABLE_VPP(map); @@ -1292,7 +1301,7 @@ static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) { unsigned long temp_adr = adr; unsigned long temp_len = len; - + cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); while (temp_len) { printk("before unlock %x: block status register is %x\n",temp_adr,cfi_read_query(map, temp_adr+(2*ofs_factor))); @@ -1310,7 +1319,7 @@ static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) printk("after unlock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor))); cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); #endif - + return ret; } @@ -1334,7 +1343,7 @@ static int cfi_staa_suspend(struct mtd_info *mtd) case FL_JEDEC_QUERY: chip->oldstate = chip->state; chip->state = FL_PM_SUSPENDED; - /* No need to wake_up() on this state change - + /* No need to wake_up() on this state change - * as the whole point is that nobody can do anything * with the chip now anyway. */ @@ -1353,9 +1362,9 @@ static int cfi_staa_suspend(struct mtd_info *mtd) if (ret) { for (i--; i >=0; i--) { chip = &cfi->chips[i]; - + spin_lock_bh(chip->mutex); - + if (chip->state == FL_PM_SUSPENDED) { /* No need to force it into a known state here, because we're returning failure, and it didn't @@ -1365,8 +1374,8 @@ static int cfi_staa_suspend(struct mtd_info *mtd) } spin_unlock_bh(chip->mutex); } - } - + } + return ret; } @@ -1378,11 +1387,11 @@ static void cfi_staa_resume(struct mtd_info *mtd) struct flchip *chip; for (i=0; inumchips; i++) { - + chip = &cfi->chips[i]; spin_lock_bh(chip->mutex); - + /* Go to known state. Chip may have been power cycled */ if (chip->state == FL_PM_SUSPENDED) { map_write(map, CMD(0xFF), 0); diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c index cf750038ce6af9645df83ff320a35200c6598168..90eb30e06b7c9322fd4e71b81a794976d5f95c4a 100644 --- a/drivers/mtd/chips/cfi_probe.c +++ b/drivers/mtd/chips/cfi_probe.c @@ -1,7 +1,7 @@ -/* +/* Common Flash Interface probe code. (C) 2000 Red Hat. GPL'd. - $Id: cfi_probe.c,v 1.83 2004/11/16 18:19:02 nico Exp $ + $Id: cfi_probe.c,v 1.84 2005/11/07 11:14:23 gleixner Exp $ */ #include @@ -20,7 +20,7 @@ #include #include -//#define DEBUG_CFI +//#define DEBUG_CFI #ifdef DEBUG_CFI static void print_cfi_ident(struct cfi_ident *); @@ -103,7 +103,7 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, unsigned long *chip_map, struct cfi_private *cfi) { int i; - + if ((base + 0) >= map->size) { printk(KERN_NOTICE "Probe at base[0x00](0x%08lx) past the end of the map(0x%08lx)\n", @@ -128,7 +128,7 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, } if (!cfi->numchips) { - /* This is the first time we're called. Set up the CFI + /* This is the first time we're called. Set up the CFI stuff accordingly and return */ return cfi_chip_setup(map, cfi); } @@ -138,13 +138,13 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, unsigned long start; if(!test_bit(i, chip_map)) { /* Skip location; no valid chip at this address */ - continue; + continue; } start = i << cfi->chipshift; /* This chip should be in read mode if it's one we've already touched. */ if (qry_present(map, start, cfi)) { - /* Eep. This chip also had the QRY marker. + /* Eep. This chip also had the QRY marker. * Is it an alias for the new one? */ cfi_send_gen_cmd(0xF0, 0, start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL); @@ -156,13 +156,13 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, map->name, base, start); return 0; } - /* Yes, it's actually got QRY for data. Most + /* Yes, it's actually got QRY for data. Most * unfortunate. Stick the new chip in read mode * too and if it's the same, assume it's an alias. */ /* FIXME: Use other modes to do a proper check */ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL); - + if (qry_present(map, base, cfi)) { xip_allowed(base, map); printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", @@ -171,12 +171,12 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, } } } - + /* OK, if we got to here, then none of the previous chips appear to be aliases for the current one. */ set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */ cfi->numchips++; - + /* Put it back into Read Mode */ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); @@ -185,11 +185,11 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n", map->name, cfi->interleave, cfi->device_type*8, base, map->bankwidth*8); - + return 1; } -static int __xipram cfi_chip_setup(struct map_info *map, +static int __xipram cfi_chip_setup(struct map_info *map, struct cfi_private *cfi) { int ofs_factor = cfi->interleave*cfi->device_type; @@ -209,11 +209,11 @@ static int __xipram cfi_chip_setup(struct map_info *map, printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name); return 0; } - - memset(cfi->cfiq,0,sizeof(struct cfi_ident)); - + + memset(cfi->cfiq,0,sizeof(struct cfi_ident)); + cfi->cfi_mode = CFI_MODE_CFI; - + /* Read the CFI info structure */ xip_disable_qry(base, map, cfi); for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++) @@ -231,7 +231,7 @@ static int __xipram cfi_chip_setup(struct map_info *map, cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL); cfi->mfr = cfi_read_query(map, base); - cfi->id = cfi_read_query(map, base + ofs_factor); + cfi->id = cfi_read_query(map, base + ofs_factor); /* Put it back into Read Mode */ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); @@ -255,10 +255,10 @@ static int __xipram cfi_chip_setup(struct map_info *map, for (i=0; icfiq->NumEraseRegions; i++) { cfi->cfiq->EraseRegionInfo[i] = le32_to_cpu(cfi->cfiq->EraseRegionInfo[i]); - -#ifdef DEBUG_CFI + +#ifdef DEBUG_CFI printk(" Erase Region #%d: BlockSize 0x%4.4X bytes, %d blocks\n", - i, (cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff, + i, (cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff, (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1); #endif } @@ -271,33 +271,33 @@ static int __xipram cfi_chip_setup(struct map_info *map, } #ifdef DEBUG_CFI -static char *vendorname(__u16 vendor) +static char *vendorname(__u16 vendor) { switch (vendor) { case P_ID_NONE: return "None"; - + case P_ID_INTEL_EXT: return "Intel/Sharp Extended"; - + case P_ID_AMD_STD: return "AMD/Fujitsu Standard"; - + case P_ID_INTEL_STD: return "Intel/Sharp Standard"; - + case P_ID_AMD_EXT: return "AMD/Fujitsu Extended"; case P_ID_WINBOND: return "Winbond Standard"; - + case P_ID_ST_ADV: return "ST Advanced"; case P_ID_MITSUBISHI_STD: return "Mitsubishi Standard"; - + case P_ID_MITSUBISHI_EXT: return "Mitsubishi Extended"; @@ -306,13 +306,13 @@ static char *vendorname(__u16 vendor) case P_ID_INTEL_PERFORMANCE: return "Intel Performance Code"; - + case P_ID_INTEL_DATA: return "Intel Data"; - + case P_ID_RESERVED: return "Not Allowed / Reserved for Future Use"; - + default: return "Unknown"; } @@ -325,21 +325,21 @@ static void print_cfi_ident(struct cfi_ident *cfip) if (cfip->qry[0] != 'Q' || cfip->qry[1] != 'R' || cfip->qry[2] != 'Y') { printk("Invalid CFI ident structure.\n"); return; - } -#endif + } +#endif printk("Primary Vendor Command Set: %4.4X (%s)\n", cfip->P_ID, vendorname(cfip->P_ID)); if (cfip->P_ADR) printk("Primary Algorithm Table at %4.4X\n", cfip->P_ADR); else printk("No Primary Algorithm Table\n"); - + printk("Alternative Vendor Command Set: %4.4X (%s)\n", cfip->A_ID, vendorname(cfip->A_ID)); if (cfip->A_ADR) printk("Alternate Algorithm Table at %4.4X\n", cfip->A_ADR); else printk("No Alternate Algorithm Table\n"); - - + + printk("Vcc Minimum: %2d.%d V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf); printk("Vcc Maximum: %2d.%d V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf); if (cfip->VppMin) { @@ -348,61 +348,61 @@ static void print_cfi_ident(struct cfi_ident *cfip) } else printk("No Vpp line\n"); - + printk("Typical byte/word write timeout: %d µs\n", 1<WordWriteTimeoutTyp); printk("Maximum byte/word write timeout: %d µs\n", (1<WordWriteTimeoutMax) * (1<WordWriteTimeoutTyp)); - + if (cfip->BufWriteTimeoutTyp || cfip->BufWriteTimeoutMax) { printk("Typical full buffer write timeout: %d µs\n", 1<BufWriteTimeoutTyp); printk("Maximum full buffer write timeout: %d µs\n", (1<BufWriteTimeoutMax) * (1<BufWriteTimeoutTyp)); } else printk("Full buffer write not supported\n"); - + printk("Typical block erase timeout: %d ms\n", 1<BlockEraseTimeoutTyp); printk("Maximum block erase timeout: %d ms\n", (1<BlockEraseTimeoutMax) * (1<BlockEraseTimeoutTyp)); if (cfip->ChipEraseTimeoutTyp || cfip->ChipEraseTimeoutMax) { - printk("Typical chip erase timeout: %d ms\n", 1<ChipEraseTimeoutTyp); + printk("Typical chip erase timeout: %d ms\n", 1<ChipEraseTimeoutTyp); printk("Maximum chip erase timeout: %d ms\n", (1<ChipEraseTimeoutMax) * (1<ChipEraseTimeoutTyp)); } else printk("Chip erase not supported\n"); - + printk("Device size: 0x%X bytes (%d MiB)\n", 1 << cfip->DevSize, 1<< (cfip->DevSize - 20)); printk("Flash Device Interface description: 0x%4.4X\n", cfip->InterfaceDesc); switch(cfip->InterfaceDesc) { case 0: printk(" - x8-only asynchronous interface\n"); break; - + case 1: printk(" - x16-only asynchronous interface\n"); break; - + case 2: printk(" - supports x8 and x16 via BYTE# with asynchronous interface\n"); break; - + case 3: printk(" - x32-only asynchronous interface\n"); break; - + case 4: printk(" - supports x16 and x32 via Word# with asynchronous interface\n"); break; - + case 65535: printk(" - Not Allowed / Reserved\n"); break; - + default: printk(" - Unknown\n"); break; } - + printk("Max. bytes in buffer write: 0x%x\n", 1<< cfip->MaxBufWriteSize); printk("Number of Erase Block Regions: %d\n", cfip->NumEraseRegions); - + } #endif /* DEBUG_CFI */ diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c index 2b2ede2bfccaeca3f9e0e47f2869d501b1633abf..d8e7a026ba5ae945a83da21485f4a34dac71ef2d 100644 --- a/drivers/mtd/chips/cfi_util.c +++ b/drivers/mtd/chips/cfi_util.c @@ -7,7 +7,7 @@ * * This code is covered by the GPL. * - * $Id: cfi_util.c,v 1.8 2004/12/14 19:55:56 nico Exp $ + * $Id: cfi_util.c,v 1.10 2005/11/07 11:14:23 gleixner Exp $ * */ @@ -56,7 +56,7 @@ __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* n /* Read in the Extended Query Table */ for (i=0; iMajorVersion != '1' || - (extp->MinorVersion < '0' || extp->MinorVersion > '3')) { - printk(KERN_WARNING " Unknown %s Extended Query " - "version %c.%c.\n", name, extp->MajorVersion, - extp->MinorVersion); - kfree(extp); - extp = NULL; - } - out: return extp; } @@ -122,17 +113,17 @@ int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob, i = 0; - /* Skip all erase regions which are ended before the start of + /* Skip all erase regions which are ended before the start of the requested erase. Actually, to save on the calculations, we skip to the first erase region which starts after the start of the requested erase, and then go back one. */ - + while (i < mtd->numeraseregions && ofs >= regions[i].offset) i++; i--; - /* OK, now i is pointing at the erase region in which this + /* OK, now i is pointing at the erase region in which this erase request starts. Check the start of the requested erase range is aligned with the erase size which is in effect here. @@ -155,7 +146,7 @@ int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob, the address actually falls */ i--; - + if ((ofs + len) & (regions[i].erasesize-1)) return -EINVAL; @@ -168,7 +159,7 @@ int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob, int size = regions[i].erasesize; ret = (*frob)(map, &cfi->chips[chipnum], adr, size, thunk); - + if (ret) return ret; @@ -182,7 +173,7 @@ int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob, if (adr >> cfi->chipshift) { adr = 0; chipnum++; - + if (chipnum >= cfi->numchips) break; } diff --git a/drivers/mtd/chips/chipreg.c b/drivers/mtd/chips/chipreg.c index d7d739a108ae5367788f6825b93925f4034e07f4..c2127840a183007b57976d9a611ab96789656c36 100644 --- a/drivers/mtd/chips/chipreg.c +++ b/drivers/mtd/chips/chipreg.c @@ -41,7 +41,7 @@ static struct mtd_chip_driver *get_mtd_chip_driver (const char *name) list_for_each(pos, &chip_drvs_list) { this = list_entry(pos, typeof(*this), list); - + if (!strcmp(this->name, name)) { ret = this; break; @@ -73,7 +73,7 @@ struct mtd_info *do_map_probe(const char *name, struct map_info *map) ret = drv->probe(map); - /* We decrease the use count here. It may have been a + /* We decrease the use count here. It may have been a probe-only module, which is no longer required from this point, having given us a handle on (and increased the use count of) the actual driver code. @@ -82,7 +82,7 @@ struct mtd_info *do_map_probe(const char *name, struct map_info *map) if (ret) return ret; - + return NULL; } /* diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h index e1a5b76596c577a2b2325071cc8988755772449e..77303ce5dcf1699d3097a76a25935d884f515fb3 100644 --- a/drivers/mtd/chips/fwh_lock.h +++ b/drivers/mtd/chips/fwh_lock.h @@ -25,7 +25,7 @@ struct fwh_xxlock_thunk { * so this code has not been tested with interleaved chips, * and will likely fail in that context. */ -static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, +static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk) { struct cfi_private *cfi = map->fldrv_priv; @@ -44,7 +44,7 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, * - on 64k boundariesand * - bit 1 set high * - block lock registers are 4MiB lower - overflow subtract (danger) - * + * * The address manipulation is first done on the logical address * which is 0 at the start of the chip, and then the offset of * the individual chip is addted to it. Any other order a weird @@ -93,7 +93,7 @@ static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len) ret = cfi_varsize_frob(mtd, fwh_xxlock_oneblock, ofs, len, (void *)&FWH_XXLOCK_ONEBLOCK_UNLOCK); - + return ret; } diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c index dc065b22f79ece4ee37440038c965766cfcaa8d4..41bd59d20d85f38229e1b9056e9e87d4598474c2 100644 --- a/drivers/mtd/chips/gen_probe.c +++ b/drivers/mtd/chips/gen_probe.c @@ -2,7 +2,7 @@ * Routines common to all CFI-type probes. * (C) 2001-2003 Red Hat, Inc. * GPL'd - * $Id: gen_probe.c,v 1.22 2005/01/24 23:49:50 rmk Exp $ + * $Id: gen_probe.c,v 1.24 2005/11/07 11:14:23 gleixner Exp $ */ #include @@ -26,7 +26,7 @@ struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp) /* First probe the map to see if we have CFI stuff there. */ cfi = genprobe_ident_chips(map, cp); - + if (!cfi) return NULL; @@ -36,12 +36,12 @@ struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp) mtd = check_cmd_set(map, 1); /* First the primary cmdset */ if (!mtd) mtd = check_cmd_set(map, 0); /* Then the secondary */ - + if (mtd) return mtd; printk(KERN_WARNING"gen_probe: No supported Vendor Command Set found\n"); - + kfree(cfi->cfiq); kfree(cfi); map->fldrv_priv = NULL; @@ -60,14 +60,14 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi memset(&cfi, 0, sizeof(cfi)); - /* Call the probetype-specific code with all permutations of + /* Call the probetype-specific code with all permutations of interleave and device type, etc. */ if (!genprobe_new_chip(map, cp, &cfi)) { /* The probe didn't like it */ printk(KERN_DEBUG "%s: Found no %s device at location zero\n", cp->name, map->name); return NULL; - } + } #if 0 /* Let the CFI probe routine do this sanity check. The Intel and AMD probe routines won't ever return a broken CFI structure anyway, @@ -92,13 +92,13 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi } else { BUG(); } - + cfi.numchips = 1; - /* - * Allocate memory for bitmap of valid chips. - * Align bitmap storage size to full byte. - */ + /* + * Allocate memory for bitmap of valid chips. + * Align bitmap storage size to full byte. + */ max_chips = map->size >> cfi.chipshift; mapsize = (max_chips / 8) + ((max_chips % 8) ? 1 : 0); chip_map = kmalloc(mapsize, GFP_KERNEL); @@ -122,7 +122,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi } /* - * Now allocate the space for the structures we need to return to + * Now allocate the space for the structures we need to return to * our caller, and copy the appropriate data into them. */ @@ -154,7 +154,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi return retcfi; } - + static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp, struct cfi_private *cfi) { @@ -189,7 +189,7 @@ extern cfi_cmdset_fn_t cfi_cmdset_0001; extern cfi_cmdset_fn_t cfi_cmdset_0002; extern cfi_cmdset_fn_t cfi_cmdset_0020; -static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, +static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, int primary) { struct cfi_private *cfi = map->fldrv_priv; @@ -199,7 +199,7 @@ static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, cfi_cmdset_fn_t *probe_function; sprintf(probename, "cfi_cmdset_%4.4X", type); - + probe_function = inter_module_get_request(probename, probename); if (probe_function) { @@ -221,7 +221,7 @@ static struct mtd_info *check_cmd_set(struct map_info *map, int primary) { struct cfi_private *cfi = map->fldrv_priv; __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID; - + if (type == P_ID_NONE || type == P_ID_RESERVED) return NULL; @@ -235,6 +235,7 @@ static struct mtd_info *check_cmd_set(struct map_info *map, int primary) #ifdef CONFIG_MTD_CFI_INTELEXT case 0x0001: case 0x0003: + case 0x0200: return cfi_cmdset_0001(map, primary); #endif #ifdef CONFIG_MTD_CFI_AMDSTD diff --git a/drivers/mtd/chips/jedec.c b/drivers/mtd/chips/jedec.c index 4f6778f3ee3e2a9d9714389805a56b6311111e3c..c40b48dabed362c00a5bc2c001a75d2131a6b05c 100644 --- a/drivers/mtd/chips/jedec.c +++ b/drivers/mtd/chips/jedec.c @@ -1,6 +1,6 @@ /* JEDEC Flash Interface. - * This is an older type of interface for self programming flash. It is + * This is an older type of interface for self programming flash. It is * commonly use in older AMD chips and is obsolete compared with CFI. * It is called JEDEC because the JEDEC association distributes the ID codes * for the chips. @@ -88,9 +88,9 @@ static const struct JEDECTable JEDEC_table[] = { static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id); static void jedec_sync(struct mtd_info *mtd) {}; -static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len, +static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); -static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len, +static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); static struct mtd_info *jedec_probe(struct map_info *map); @@ -122,7 +122,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) memset(MTD, 0, sizeof(struct mtd_info) + sizeof(struct jedec_private)); priv = (struct jedec_private *)&MTD[1]; - + my_bank_size = map->size; if (map->size/my_bank_size > MAX_JEDEC_CHIPS) @@ -131,13 +131,13 @@ static struct mtd_info *jedec_probe(struct map_info *map) kfree(MTD); return NULL; } - + for (Base = 0; Base < map->size; Base += my_bank_size) { // Perhaps zero could designate all tests? if (map->buswidth == 0) map->buswidth = 1; - + if (map->buswidth == 1){ if (jedec_probe8(map,Base,priv) == 0) { printk("did recognize jedec chip\n"); @@ -150,7 +150,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) if (map->buswidth == 4) jedec_probe32(map,Base,priv); } - + // Get the biggest sector size SectorSize = 0; for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) @@ -160,7 +160,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) if (priv->chips[I].sectorsize > SectorSize) SectorSize = priv->chips[I].sectorsize; } - + // Quickly ensure that the other sector sizes are factors of the largest for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) { @@ -169,9 +169,9 @@ static struct mtd_info *jedec_probe(struct map_info *map) printk("mtd: Failed. Device has incompatible mixed sector sizes\n"); kfree(MTD); return NULL; - } + } } - + /* Generate a part name that includes the number of different chips and other configuration information */ count = 1; @@ -181,13 +181,13 @@ static struct mtd_info *jedec_probe(struct map_info *map) for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) { const struct JEDECTable *JEDEC; - + if (priv->chips[I+1].jedec == priv->chips[I].jedec) { count++; continue; } - + // Locate the chip in the jedec table JEDEC = jedec_idtoinf(priv->chips[I].jedec >> 8,priv->chips[I].jedec); if (JEDEC == 0) @@ -196,11 +196,11 @@ static struct mtd_info *jedec_probe(struct map_info *map) kfree(MTD); return NULL; } - + if (Uniq != 0) strcat(Part,","); Uniq++; - + if (count != 1) sprintf(Part+strlen(Part),"%x*[%s]",count,JEDEC->name); else @@ -208,7 +208,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) if (strlen(Part) > sizeof(Part)*2/3) break; count = 1; - } + } /* Determine if the chips are organized in a linear fashion, or if there are empty banks. Note, the last bank does not count here, only the @@ -233,7 +233,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) { if (priv->bank_fill[I] != my_bank_size) priv->is_banked = 1; - + /* This even could be eliminated, but new de-optimized read/write functions have to be written */ printk("priv->bank_fill[%d] is %lx, priv->bank_fill[0] is %lx\n",I,priv->bank_fill[I],priv->bank_fill[0]); @@ -242,7 +242,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) printk("mtd: Failed. Cannot handle unsymmetric banking\n"); kfree(MTD); return NULL; - } + } } } } @@ -250,7 +250,7 @@ static struct mtd_info *jedec_probe(struct map_info *map) strcat(Part,", banked"); // printk("Part: '%s'\n",Part); - + memset(MTD,0,sizeof(*MTD)); // strlcpy(MTD->name,Part,sizeof(MTD->name)); MTD->name = map->name; @@ -291,7 +291,7 @@ static int checkparity(u_char C) /* Take an array of JEDEC numbers that represent interleved flash chips and process them. Check to make sure they are good JEDEC numbers, look - them up and then add them to the chip list */ + them up and then add them to the chip list */ static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, unsigned long base,struct jedec_private *priv) { @@ -306,16 +306,16 @@ static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, if (checkparity(Mfg[I]) == 0 || checkparity(Id[I]) == 0) return 0; } - + // Finally, just make sure all the chip sizes are the same JEDEC = jedec_idtoinf(Mfg[0],Id[0]); - + if (JEDEC == 0) { printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]); return 0; } - + Size = JEDEC->size; SectorSize = JEDEC->sectorsize; for (I = 0; I != Count; I++) @@ -331,7 +331,7 @@ static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, { printk("mtd: Failed. Interleved flash does not have matching characteristics\n"); return 0; - } + } } // Load the Chips @@ -345,13 +345,13 @@ static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, { printk("mtd: Device has too many chips. Increase MAX_JEDEC_CHIPS\n"); return 0; - } - + } + // Add them to the table for (J = 0; J != Count; J++) { unsigned long Bank; - + JEDEC = jedec_idtoinf(Mfg[J],Id[J]); priv->chips[I].jedec = (Mfg[J] << 8) | Id[J]; priv->chips[I].size = JEDEC->size; @@ -364,17 +364,17 @@ static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count, // log2 n :| priv->chips[I].addrshift = 0; for (Bank = Count; Bank != 1; Bank >>= 1, priv->chips[I].addrshift++); - + // Determine how filled this bank is. Bank = base & (~(my_bank_size-1)); - if (priv->bank_fill[Bank/my_bank_size] < base + + if (priv->bank_fill[Bank/my_bank_size] < base + (JEDEC->size << priv->chips[I].addrshift) - Bank) priv->bank_fill[Bank/my_bank_size] = base + (JEDEC->size << priv->chips[I].addrshift) - Bank; I++; } priv->size += priv->chips[I-1].size*Count; - + return priv->chips[I-1].size; } @@ -392,7 +392,7 @@ static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id) // Look for flash using an 8 bit bus interface static int jedec_probe8(struct map_info *map,unsigned long base, struct jedec_private *priv) -{ +{ #define flread(x) map_read8(map,base+x) #define flwrite(v,x) map_write8(map,v,base+x) @@ -410,20 +410,20 @@ static int jedec_probe8(struct map_info *map,unsigned long base, OldVal = flread(base); for (I = 0; OldVal != flread(base) && I < 10000; I++) OldVal = flread(base); - + // Reset the chip - flwrite(Reset,0x555); - + flwrite(Reset,0x555); + // Send the sequence flwrite(AutoSel1,0x555); flwrite(AutoSel2,0x2AA); flwrite(AutoSel3,0x555); - + // Get the JEDEC numbers Mfg[0] = flread(0); Id[0] = flread(1); // printk("Mfg is %x, Id is %x\n",Mfg[0],Id[0]); - + Size = handle_jedecs(map,Mfg,Id,1,base,priv); // printk("handle_jedecs Size is %x\n",(unsigned int)Size); if (Size == 0) @@ -431,13 +431,13 @@ static int jedec_probe8(struct map_info *map,unsigned long base, flwrite(Reset,0x555); return 0; } - + // Reset. flwrite(Reset,0x555); - + return 1; - + #undef flread #undef flwrite } @@ -470,17 +470,17 @@ static int jedec_probe32(struct map_info *map,unsigned long base, OldVal = flread(base); for (I = 0; OldVal != flread(base) && I < 10000; I++) OldVal = flread(base); - + // Reset the chip - flwrite(Reset,0x555); - + flwrite(Reset,0x555); + // Send the sequence flwrite(AutoSel1,0x555); flwrite(AutoSel2,0x2AA); flwrite(AutoSel3,0x555); - + // Test #1, JEDEC numbers are readable from 0x??00/0x??01 - if (flread(0) != flread(0x100) || + if (flread(0) != flread(0x100) || flread(1) != flread(0x101)) { flwrite(Reset,0x555); @@ -494,14 +494,14 @@ static int jedec_probe32(struct map_info *map,unsigned long base, OldVal = flread(1); for (I = 0; I != 4; I++) Id[I] = (OldVal >> (I*8)); - + Size = handle_jedecs(map,Mfg,Id,4,base,priv); if (Size == 0) { flwrite(Reset,0x555); return 0; } - + /* Check if there is address wrap around within a single bank, if this returns JEDEC numbers then we assume that it is wrap around. Notice we call this routine with the JEDEC return still enabled, if two or @@ -519,27 +519,27 @@ static int jedec_probe32(struct map_info *map,unsigned long base, // Reset. flwrite(0xF0F0F0F0,0x555); - + return 1; - + #undef flread #undef flwrite } /* Linear read. */ -static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len, +static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct map_info *map = mtd->priv; - + map_copy_from(map, buf, from, len); *retlen = len; - return 0; + return 0; } /* Banked read. Take special care to jump past the holes in the bank mapping. This version assumes symetry in the holes.. */ -static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len, +static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct map_info *map = mtd->priv; @@ -555,17 +555,17 @@ static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len, if (priv->bank_fill[0] - offset < len) get = priv->bank_fill[0] - offset; - bank /= priv->bank_fill[0]; + bank /= priv->bank_fill[0]; map_copy_from(map,buf + *retlen,bank*my_bank_size + offset,get); - + len -= get; *retlen += get; from += get; - } - return 0; + } + return 0; } -/* Pass the flags value that the flash return before it re-entered read +/* Pass the flags value that the flash return before it re-entered read mode. */ static void jedec_flash_failed(unsigned char code) { @@ -579,17 +579,17 @@ static void jedec_flash_failed(unsigned char code) printk("mtd: Programming didn't take\n"); } -/* This uses the erasure function described in the AMD Flash Handbook, +/* This uses the erasure function described in the AMD Flash Handbook, it will work for flashes with a fixed sector size only. Flashes with a selection of sector sizes (ie the AMD Am29F800B) will need a different - routine. This routine tries to parallize erasing multiple chips/sectors + routine. This routine tries to parallize erasing multiple chips/sectors where possible */ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) { // Does IO to the currently selected chip #define flread(x) map_read8(map,chip->base+((x)<addrshift)) #define flwrite(v,x) map_write8(map,v,chip->base+((x)<addrshift)) - + unsigned long Time = 0; unsigned long NoTime = 0; unsigned long start = instr->addr, len = instr->len; @@ -603,7 +603,7 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) (len % mtd->erasesize) != 0 || (len/mtd->erasesize) == 0) return -EINVAL; - + jedec_flash_chip_scan(priv,start,len); // Start the erase sequence on each chip @@ -611,16 +611,16 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) { unsigned long off; struct jedec_flash_chip *chip = priv->chips + I; - + if (chip->length == 0) continue; - + if (chip->start + chip->length > chip->size) { printk("DIE\n"); return -EIO; - } - + } + flwrite(0xF0,chip->start + 0x555); flwrite(0xAA,chip->start + 0x555); flwrite(0x55,chip->start + 0x2AA); @@ -628,8 +628,8 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) flwrite(0xAA,chip->start + 0x555); flwrite(0x55,chip->start + 0x2AA); - /* Once we start selecting the erase sectors the delay between each - command must not exceed 50us or it will immediately start erasing + /* Once we start selecting the erase sectors the delay between each + command must not exceed 50us or it will immediately start erasing and ignore the other sectors */ for (off = 0; off < len; off += chip->sectorsize) { @@ -641,19 +641,19 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) { printk("mtd: Ack! We timed out the erase timer!\n"); return -EIO; - } + } } - } + } /* We could split this into a timer routine and return early, performing background erasure.. Maybe later if the need warrents */ /* Poll the flash for erasure completion, specs say this can take as long - as 480 seconds to do all the sectors (for a 2 meg flash). + as 480 seconds to do all the sectors (for a 2 meg flash). Erasure time is dependent on chip age, temp and wear.. */ - + /* This being a generic routine assumes a 32 bit bus. It does read32s - and bundles interleved chips into the same grouping. This will work + and bundles interleved chips into the same grouping. This will work for all bus widths */ Time = 0; NoTime = 0; @@ -664,20 +664,20 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) unsigned todo[4] = {0,0,0,0}; unsigned todo_left = 0; unsigned J; - + if (chip->length == 0) continue; - /* Find all chips in this data line, realistically this is all + /* Find all chips in this data line, realistically this is all or nothing up to the interleve count */ for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++) { - if ((priv->chips[J].base & (~((1<addrshift)-1))) == + if ((priv->chips[J].base & (~((1<addrshift)-1))) == (chip->base & (~((1<addrshift)-1)))) { todo_left++; todo[priv->chips[J].base & ((1<addrshift)-1)] = 1; - } + } } /* printk("todo: %x %x %x %x\n",(short)todo[0],(short)todo[1], @@ -687,7 +687,7 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) { __u32 Last[4]; unsigned long Count = 0; - + /* During erase bit 7 is held low and bit 6 toggles, we watch this, should it stop toggling or go high then the erase is completed, or this is not really flash ;> */ @@ -718,23 +718,23 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) __u8 Byte3 = (Last[(Count-3)%4] >> (J*8)) & 0xFF; if (todo[J] == 0) continue; - + if ((Byte1 & (1 << 7)) == 0 && Byte1 != Byte2) { // printk("Check %x %x %x\n",(short)J,(short)Byte1,(short)Byte2); continue; } - + if (Byte1 == Byte2) { jedec_flash_failed(Byte3); return -EIO; } - + todo[J] = 0; todo_left--; } - + /* if (NoTime == 0) Time += HZ/10 - schedule_timeout(HZ/10);*/ NoTime = 0; @@ -751,7 +751,7 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) break; } Count++; - + /* // Count time, max of 15s per sector (according to AMD) if (Time > 15*len/mtd->erasesize*HZ) { @@ -759,38 +759,38 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) return -EIO; } */ } - + // Skip to the next chip if we used chip erase if (chip->length == chip->size) off = chip->size; else off += chip->sectorsize; - + if (off >= chip->length) break; NoTime = 1; } - + for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++) { if ((priv->chips[J].base & (~((1<addrshift)-1))) == (chip->base & (~((1<addrshift)-1)))) priv->chips[J].length = 0; - } + } } - + //printk("done\n"); instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; - + #undef flread #undef flwrite } /* This is the simple flash writing function. It writes to every byte, in sequence. It takes care of how to properly address the flash if - the flash is interleved. It can only be used if all the chips in the + the flash is interleved. It can only be used if all the chips in the array are identical!*/ static int flash_write(struct mtd_info *mtd, loff_t start, size_t len, size_t *retlen, const u_char *buf) @@ -800,25 +800,25 @@ static int flash_write(struct mtd_info *mtd, loff_t start, size_t len, of addrshift (interleave index) and then adds the control register index. */ #define flread(x) map_read8(map,base+(off&((1<addrshift)-1))+((x)<addrshift)) #define flwrite(v,x) map_write8(map,v,base+(off&((1<addrshift)-1))+((x)<addrshift)) - + struct map_info *map = mtd->priv; struct jedec_private *priv = map->fldrv_priv; unsigned long base; unsigned long off; size_t save_len = len; - + if (start + len > mtd->size) return -EIO; - + //printk("Here"); - + //printk("flash_write: start is %x, len is %x\n",start,(unsigned long)len); while (len != 0) { struct jedec_flash_chip *chip = priv->chips; unsigned long bank; unsigned long boffset; - + // Compute the base of the flash. off = ((unsigned long)start) % (chip->size << chip->addrshift); base = start - off; @@ -828,10 +828,10 @@ static int flash_write(struct mtd_info *mtd, loff_t start, size_t len, boffset = base & (priv->bank_fill[0]-1); bank = (bank/priv->bank_fill[0])*my_bank_size; base = bank + boffset; - + // printk("Flasing %X %X %X\n",base,chip->size,len); // printk("off is %x, compare with %x\n",off,chip->size << chip->addrshift); - + // Loop over this page for (; off != (chip->size << chip->addrshift) && len != 0; start++, len--, off++,buf++) { @@ -845,7 +845,7 @@ static int flash_write(struct mtd_info *mtd, loff_t start, size_t len, } if (((~oldbyte) & *buf) != 0) printk("mtd: warn: Trying to set a 0 to a 1\n"); - + // Write flwrite(0xAA,0x555); flwrite(0x55,0x2AA); @@ -854,10 +854,10 @@ static int flash_write(struct mtd_info *mtd, loff_t start, size_t len, Last[0] = map_read8(map,base + off); Last[1] = map_read8(map,base + off); Last[2] = map_read8(map,base + off); - + /* Wait for the flash to finish the operation. We store the last 4 status bytes that have been retrieved so we can determine why - it failed. The toggle bits keep toggling when there is a + it failed. The toggle bits keep toggling when there is a failure */ for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] && Count < 10000; Count++) @@ -866,7 +866,7 @@ static int flash_write(struct mtd_info *mtd, loff_t start, size_t len, { jedec_flash_failed(Last[(Count - 3) % 4]); return -EIO; - } + } } } *retlen = save_len; @@ -885,24 +885,24 @@ static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start // Zero the records for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) priv->chips[I].start = priv->chips[I].length = 0; - + // Intersect the region with each chip for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) { struct jedec_flash_chip *chip = priv->chips + I; unsigned long ByteStart; unsigned long ChipEndByte = chip->offset + (chip->size << chip->addrshift); - + // End is before this chip or the start is after it if (start+len < chip->offset || ChipEndByte - (1 << chip->addrshift) < start) continue; - + if (start < chip->offset) { ByteStart = chip->offset; chip->start = 0; - } + } else { chip->start = (start - chip->offset + (1 << chip->addrshift)-1) >> chip->addrshift; diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index 30da428eb7b99e0c9a265928d8d4303654a21264..edb306c03c0a14b8f1e9b0f50382f05a08e5d4d2 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -1,7 +1,7 @@ -/* +/* Common Flash Interface probe code. (C) 2000 Red Hat. GPL'd. - $Id: jedec_probe.c,v 1.63 2005/02/14 16:30:32 bjd Exp $ + $Id: jedec_probe.c,v 1.66 2005/11/07 11:14:23 gleixner Exp $ See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5) for the standard this probe goes back to. @@ -1719,7 +1719,7 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, static struct mtd_info *jedec_probe(struct map_info *map); -static inline u32 jedec_read_mfr(struct map_info *map, __u32 base, +static inline u32 jedec_read_mfr(struct map_info *map, __u32 base, struct cfi_private *cfi) { map_word result; @@ -1730,7 +1730,7 @@ static inline u32 jedec_read_mfr(struct map_info *map, __u32 base, return result.x[0] & mask; } -static inline u32 jedec_read_id(struct map_info *map, __u32 base, +static inline u32 jedec_read_id(struct map_info *map, __u32 base, struct cfi_private *cfi) { map_word result; @@ -1741,7 +1741,7 @@ static inline u32 jedec_read_id(struct map_info *map, __u32 base, return result.x[0] & mask; } -static inline void jedec_reset(u32 base, struct map_info *map, +static inline void jedec_reset(u32 base, struct map_info *map, struct cfi_private *cfi) { /* Reset */ @@ -1765,7 +1765,7 @@ static inline void jedec_reset(u32 base, struct map_info *map, * so ensure we're in read mode. Send both the Intel and the AMD command * for this. Intel uses 0xff for this, AMD uses 0xff for NOP, so * this should be safe. - */ + */ cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); /* FIXME - should have reset delay before continuing */ } @@ -1807,14 +1807,14 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index) printk("Found: %s\n",jedec_table[index].name); num_erase_regions = jedec_table[index].NumEraseRegions; - + p_cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL); if (!p_cfi->cfiq) { //xx printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name); return 0; } - memset(p_cfi->cfiq,0,sizeof(struct cfi_ident)); + memset(p_cfi->cfiq,0,sizeof(struct cfi_ident)); p_cfi->cfiq->P_ID = jedec_table[index].CmdSet; p_cfi->cfiq->NumEraseRegions = jedec_table[index].NumEraseRegions; @@ -1969,7 +1969,7 @@ static inline int jedec_match( __u32 base, cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL); /* FIXME - should have a delay before continuing */ - match_done: + match_done: return rc; } @@ -1998,23 +1998,23 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, "Probe at base(0x%08x) past the end of the map(0x%08lx)\n", base, map->size -1); return 0; - + } /* Ensure the unlock addresses we try stay inside the map */ probe_offset1 = cfi_build_cmd_addr( - cfi->addr_unlock1, - cfi_interleave(cfi), + cfi->addr_unlock1, + cfi_interleave(cfi), cfi->device_type); probe_offset2 = cfi_build_cmd_addr( - cfi->addr_unlock1, - cfi_interleave(cfi), + cfi->addr_unlock1, + cfi_interleave(cfi), cfi->device_type); if ( ((base + probe_offset1 + map_bankwidth(map)) >= map->size) || ((base + probe_offset2 + map_bankwidth(map)) >= map->size)) { goto retry; } - + /* Reset */ jedec_reset(base, map, cfi); @@ -2027,13 +2027,13 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, /* FIXME - should have a delay before continuing */ if (!cfi->numchips) { - /* This is the first time we're called. Set up the CFI + /* This is the first time we're called. Set up the CFI stuff accordingly and return */ - + cfi->mfr = jedec_read_mfr(map, base, cfi); cfi->id = jedec_read_id(map, base, cfi); DEBUG(MTD_DEBUG_LEVEL3, - "Search for id:(%02x %02x) interleave(%d) type(%d)\n", + "Search for id:(%02x %02x) interleave(%d) type(%d)\n", cfi->mfr, cfi->id, cfi_interleave(cfi), cfi->device_type); for (i=0; i> cfi->chipshift); i++) { unsigned long start; @@ -2083,7 +2083,7 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, map->name, base, start); return 0; } - + /* Yes, it's actually got the device IDs as data. Most * unfortunate. Stick the new chip in read mode * too and if it's the same, assume it's an alias. */ @@ -2097,20 +2097,20 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, } } } - + /* OK, if we got to here, then none of the previous chips appear to be aliases for the current one. */ set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */ cfi->numchips++; - + ok_out: /* Put it back into Read Mode */ jedec_reset(base, map, cfi); printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n", - map->name, cfi_interleave(cfi), cfi->device_type*8, base, + map->name, cfi_interleave(cfi), cfi->device_type*8, base, map->bankwidth*8); - + return 1; } diff --git a/drivers/mtd/chips/map_absent.c b/drivers/mtd/chips/map_absent.c index c6c83833cc32311ccb14fda47cbf685480f05a20..a611de9b15159349116d78d28fdb2968b29f2c62 100644 --- a/drivers/mtd/chips/map_absent.c +++ b/drivers/mtd/chips/map_absent.c @@ -1,11 +1,11 @@ /* * Common code to handle absent "placeholder" devices * Copyright 2001 Resilience Corporation - * $Id: map_absent.c,v 1.5 2004/11/16 18:29:00 dwmw2 Exp $ + * $Id: map_absent.c,v 1.6 2005/11/07 11:14:23 gleixner Exp $ * * This map driver is used to allocate "placeholder" MTD - * devices on systems that have socketed/removable media. - * Use of this driver as a fallback preserves the expected + * devices on systems that have socketed/removable media. + * Use of this driver as a fallback preserves the expected * registration of MTD device nodes regardless of probe outcome. * A usage example is as follows: * @@ -80,7 +80,7 @@ static int map_absent_read(struct mtd_info *mtd, loff_t from, size_t len, size_t static int map_absent_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { *retlen = 0; - return -ENODEV; + return -ENODEV; } static int map_absent_erase(struct mtd_info *mtd, struct erase_info *instr) diff --git a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c index c3cf0f63bc93639ad151a35b8867e554452548a7..2d26bdef82d5c9fe4fe64ad4406719edcb5b12c0 100644 --- a/drivers/mtd/chips/sharp.c +++ b/drivers/mtd/chips/sharp.c @@ -4,7 +4,7 @@ * Copyright 2000,2001 David A. Schleef * 2000,2001 Lineo, Inc. * - * $Id: sharp.c,v 1.14 2004/08/09 13:19:43 dwmw2 Exp $ + * $Id: sharp.c,v 1.16 2005/11/07 11:14:23 gleixner Exp $ * * Devices supported: * LH28F016SCT Symmetrical block flash memory, 2Mx8 @@ -31,6 +31,7 @@ #include #include #include +#include #define CMD_RESET 0xffffffff #define CMD_READ_ID 0x90909090 @@ -214,7 +215,7 @@ static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd) /* This function returns with the chip->mutex lock held. */ static int sharp_wait(struct map_info *map, struct flchip *chip) { - __u16 status; + int status, i; unsigned long timeo = jiffies + HZ; DECLARE_WAITQUEUE(wait, current); int adr = 0; @@ -227,13 +228,11 @@ static int sharp_wait(struct map_info *map, struct flchip *chip) map_write32(map,CMD_READ_STATUS,adr); chip->state = FL_STATUS; case FL_STATUS: - status = map_read32(map,adr); -//printk("status=%08x\n",status); - - udelay(100); - if((status & SR_READY)!=SR_READY){ -//printk(".status=%08x\n",status); - udelay(100); + for(i=0;i<100;i++){ + status = map_read32(map,adr); + if((status & SR_READY)==SR_READY) + break; + udelay(1); } break; default: @@ -460,12 +459,12 @@ static int sharp_do_wait_for_ready(struct map_info *map, struct flchip *chip, remove_wait_queue(&chip->wq, &wait); //spin_lock_bh(chip->mutex); - + if (signal_pending(current)){ ret = -EINTR; goto out; } - + } ret = -ETIME; out: @@ -564,7 +563,7 @@ static int sharp_suspend(struct mtd_info *mtd) static void sharp_resume(struct mtd_info *mtd) { printk("sharp_resume()\n"); - + } static void sharp_destroy(struct mtd_info *mtd) diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index ef24837019d3e4e8f4961035a62d1198beb039fb..6b8bb2e4dcfde7ca5dbf8cb6bd1f4abc13c78c6f 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c @@ -1,24 +1,24 @@ /* - * $Id: cmdlinepart.c,v 1.18 2005/06/07 15:04:26 joern Exp $ + * $Id: cmdlinepart.c,v 1.19 2005/11/07 11:14:19 gleixner Exp $ * * Read flash partition table from command line * * Copyright 2002 SYSGO Real-Time Solutions GmbH * * The format for the command line is as follows: - * + * * mtdparts=[; := :[,] * := [@offset][][ro] * := unique name used in mapping driver/device (mtd->name) * := standard linux memsize OR "-" to denote all remaining space * := '(' NAME ')' - * + * * Examples: - * + * * 1 NOR Flash, with 1 single writable partition: * edb7312-nor:- - * + * * 1 NOR Flash with 2 partitions, 1 NAND with one * edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home) */ @@ -60,17 +60,17 @@ static int cmdline_parsed = 0; /* * Parse one partition definition for an MTD. Since there can be many - * comma separated partition definitions, this function calls itself + * comma separated partition definitions, this function calls itself * recursively until no more partition definitions are found. Nice side * effect: the memory to keep the mtd_partition structs and the names * is allocated upon the last definition being found. At that point the * syntax has been verified ok. */ -static struct mtd_partition * newpart(char *s, +static struct mtd_partition * newpart(char *s, char **retptr, int *num_parts, - int this_part, - unsigned char **extra_mem_ptr, + int this_part, + unsigned char **extra_mem_ptr, int extra_mem_size) { struct mtd_partition *parts; @@ -102,7 +102,7 @@ static struct mtd_partition * newpart(char *s, mask_flags = 0; /* this is going to be a regular partition */ delim = 0; /* check for offset */ - if (*s == '@') + if (*s == '@') { s++; offset = memparse(s, &s); @@ -112,7 +112,7 @@ static struct mtd_partition * newpart(char *s, { delim = ')'; } - + if (delim) { char *p; @@ -131,12 +131,12 @@ static struct mtd_partition * newpart(char *s, name = NULL; name_len = 13; /* Partition_000 */ } - + /* record name length for memory allocation later */ extra_mem_size += name_len + 1; /* test for options */ - if (strncmp(s, "ro", 2) == 0) + if (strncmp(s, "ro", 2) == 0) { mask_flags |= MTD_WRITEABLE; s += 2; @@ -151,7 +151,7 @@ static struct mtd_partition * newpart(char *s, return NULL; } /* more partitions follow, parse them */ - if ((parts = newpart(s + 1, &s, num_parts, + if ((parts = newpart(s + 1, &s, num_parts, this_part + 1, &extra_mem, extra_mem_size)) == 0) return NULL; } @@ -187,7 +187,7 @@ static struct mtd_partition * newpart(char *s, extra_mem += name_len + 1; dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n", - this_part, + this_part, parts[this_part].name, parts[this_part].offset, parts[this_part].size, @@ -204,8 +204,8 @@ static struct mtd_partition * newpart(char *s, return parts; } -/* - * Parse the command line. +/* + * Parse the command line. */ static int mtdpart_setup_real(char *s) { @@ -230,7 +230,7 @@ static int mtdpart_setup_real(char *s) dbg(("parsing <%s>\n", p+1)); - /* + /* * parse one mtd. have it reserve memory for the * struct cmdline_mtd_partition and the mtd-id string. */ @@ -239,7 +239,7 @@ static int mtdpart_setup_real(char *s) &num_parts, /* out: number of parts */ 0, /* first partition */ (unsigned char**)&this_mtd, /* out: extra mem */ - mtd_id_len + 1 + sizeof(*this_mtd) + + mtd_id_len + 1 + sizeof(*this_mtd) + sizeof(void*)-1 /*alignment*/); if(!parts) { @@ -254,21 +254,21 @@ static int mtdpart_setup_real(char *s) } /* align this_mtd */ - this_mtd = (struct cmdline_mtd_partition *) + this_mtd = (struct cmdline_mtd_partition *) ALIGN((unsigned long)this_mtd, sizeof(void*)); - /* enter results */ + /* enter results */ this_mtd->parts = parts; this_mtd->num_parts = num_parts; this_mtd->mtd_id = (char*)(this_mtd + 1); strlcpy(this_mtd->mtd_id, mtd_id, mtd_id_len + 1); /* link into chain */ - this_mtd->next = partitions; + this_mtd->next = partitions; partitions = this_mtd; - dbg(("mtdid=<%s> num_parts=<%d>\n", + dbg(("mtdid=<%s> num_parts=<%d>\n", this_mtd->mtd_id, this_mtd->num_parts)); - + /* EOS - we're done */ if (*s == 0) @@ -292,7 +292,7 @@ static int mtdpart_setup_real(char *s) * information. It returns partitions for the requested mtd device, or * the first one in the chain if a NULL mtd_id is passed in. */ -static int parse_cmdline_partitions(struct mtd_info *master, +static int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, unsigned long origin) { @@ -322,7 +322,7 @@ static int parse_cmdline_partitions(struct mtd_info *master, part->parts[i].size = master->size - offset; if (offset + part->parts[i].size > master->size) { - printk(KERN_WARNING ERRP + printk(KERN_WARNING ERRP "%s: partitioning exceeds flash size, truncating\n", part->mtd_id); part->parts[i].size = master->size - offset; @@ -338,8 +338,8 @@ static int parse_cmdline_partitions(struct mtd_info *master, } -/* - * This is the handler for our kernel parameter, called from +/* + * This is the handler for our kernel parameter, called from * main.c::checksetup(). Note that we can not yet kmalloc() anything, * so we only save the commandline for later processing. * diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index c4a56a4ac5e20dfe1df3960ea800d851ff1333c6..9a2aa4033c6a6e37ea60ade60a4f67c70613ccc5 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -1,5 +1,5 @@ # drivers/mtd/maps/Kconfig -# $Id: Kconfig,v 1.15 2004/12/22 17:51:15 joern Exp $ +# $Id: Kconfig,v 1.18 2005/11/07 11:14:24 gleixner Exp $ menu "Self-contained MTD device drivers" depends on MTD!=n @@ -110,7 +110,7 @@ config MTDRAM_ABS_POS If you have system RAM accessible by the CPU but not used by Linux in normal operation, you can give the physical address at which the available RAM starts, and the MTDRAM driver will use it instead of - allocating space from Linux's available memory. Otherwise, leave + allocating space from Linux's available memory. Otherwise, leave this set to zero. Most people will want to leave this as zero. config MTD_BLKMTD @@ -165,7 +165,7 @@ config MTD_DOC2001 select MTD_DOCPROBE select MTD_NAND_IDS ---help--- - This provides an alternative MTD device driver for the M-Systems + This provides an alternative MTD device driver for the M-Systems DiskOnChip Millennium devices. Use this if you have problems with the combined DiskOnChip 2000 and Millennium driver above. To get the DiskOnChip probe code to load and use this driver instead of @@ -192,7 +192,7 @@ config MTD_DOC2001PLUS If you use this device, you probably also want to enable the INFTL 'Inverse NAND Flash Translation Layer' option below, which is used - to emulate a block device by using a kind of file system on the + to emulate a block device by using a kind of file system on the flash chips. NOTE: This driver will soon be replaced by the new DiskOnChip driver diff --git a/drivers/mtd/devices/blkmtd.c b/drivers/mtd/devices/blkmtd.c index 662e807801ed046e71a99ad8b50f781bc14f1fee..f9db52f6bf00f40156ece013ffd6f37e60769aee 100644 --- a/drivers/mtd/devices/blkmtd.c +++ b/drivers/mtd/devices/blkmtd.c @@ -1,5 +1,5 @@ /* - * $Id: blkmtd.c,v 1.24 2004/11/16 18:29:01 dwmw2 Exp $ + * $Id: blkmtd.c,v 1.27 2005/11/07 11:14:24 gleixner Exp $ * * blkmtd.c - use a block device as a fake MTD * @@ -39,7 +39,7 @@ /* Default erase size in K, always make it a multiple of PAGE_SIZE */ #define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10) /* 128KiB */ -#define VERSION "$Revision: 1.24 $" +#define VERSION "$Revision: 1.27 $" /* Info for the block device */ struct blkmtd_dev { @@ -117,7 +117,7 @@ static int bi_write_complete(struct bio *bio, unsigned int bytes_done, int error unlock_page(page); page_cache_release(page); } while (bvec >= bio->bi_io_vec); - + complete((struct completion*)bio->bi_private); return 0; } @@ -135,7 +135,7 @@ static int blkmtd_readpage(struct blkmtd_dev *dev, struct page *page) unlock_page(page); return 0; } - + ClearPageUptodate(page); ClearPageError(page); @@ -539,11 +539,8 @@ static void free_device(struct blkmtd_dev *dev) { DEBUG(2, "blkmtd: free_device() dev = %p\n", dev); if(dev) { - if(dev->mtd_info.eraseregions) - kfree(dev->mtd_info.eraseregions); - if(dev->mtd_info.name) - kfree(dev->mtd_info.name); - + kfree(dev->mtd_info.eraseregions); + kfree(dev->mtd_info.name); if(dev->blkdev) { invalidate_inode_pages(dev->blkdev->bd_inode->i_mapping); close_bdev_excl(dev->blkdev); @@ -710,7 +707,7 @@ static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size dev->mtd_info.erasesize >> 10, readonly ? "(read-only)" : ""); } - + return dev; devinit_err: diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 4a7a805e7564c4d359f9049daf1ebc54a284c39b..0aaa0ced9aba0acd7d5105d16a4fe90b4323be73 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -1,5 +1,5 @@ /* - * $Id: block2mtd.c,v 1.28 2005/03/19 22:40:44 gleixner Exp $ + * $Id: block2mtd.c,v 1.29 2005/11/07 11:14:24 gleixner Exp $ * * block2mtd.c - create an mtd from a block device * @@ -19,7 +19,7 @@ #include #include -#define VERSION "$Revision: 1.28 $" +#define VERSION "$Revision: 1.29 $" #define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args) @@ -111,7 +111,7 @@ static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len) return PTR_ERR(page); max = (u_long*)page_address(page) + PAGE_SIZE; - for (p=(u_long*)page_address(page); p PAGE_SIZE) + if ((offset+len) > PAGE_SIZE) cpylen = PAGE_SIZE - offset; // multiple pages else cpylen = len; // this page diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c index 5fc532895a24eb37b7b859ea8e767e8f50812071..be5e88b3888daf727404fa12c5cb22bb77b01b40 100644 --- a/drivers/mtd/devices/doc2000.c +++ b/drivers/mtd/devices/doc2000.c @@ -4,7 +4,7 @@ * (c) 1999 Machine Vision Holdings, Inc. * (c) 1999, 2000 David Woodhouse * - * $Id: doc2000.c,v 1.66 2005/01/05 18:05:12 dwmw2 Exp $ + * $Id: doc2000.c,v 1.67 2005/11/07 11:14:24 gleixner Exp $ */ #include @@ -58,7 +58,7 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); -static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, +static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, @@ -76,14 +76,14 @@ static void DoC_Delay(struct DiskOnChip *doc, unsigned short cycles) { volatile char dummy; int i; - + for (i = 0; i < cycles; i++) { if (DoC_is_Millennium(doc)) dummy = ReadDOC(doc->virtadr, NOP); else dummy = ReadDOC(doc->virtadr, DOCStatus); } - + } /* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */ @@ -220,8 +220,8 @@ static int DoC_Address(struct DiskOnChip *doc, int numbytes, unsigned long ofs, WriteDOC(ofs & 0xff, docptr, WritePipeTerm); DoC_Delay(doc, 2); /* Needed for some slow flash chips. mf. */ - - /* FIXME: The SlowIO's for millennium could be replaced by + + /* FIXME: The SlowIO's for millennium could be replaced by a single WritePipeTerm here. mf. */ /* Lower the ALE line */ @@ -377,9 +377,9 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) if (mfr == 0xff || mfr == 0) return 0; - /* Check it's the same as the first chip we identified. + /* Check it's the same as the first chip we identified. * M-Systems say that any given DiskOnChip device should only - * contain _one_ type of flash part, although that's not a + * contain _one_ type of flash part, although that's not a * hardware restriction. */ if (doc->mfr) { if (doc->mfr == mfr && doc->id == id) @@ -397,7 +397,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { if (nand_manuf_ids[j].id == mfr) break; - } + } printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, " "Chip ID: %2.2X (%s:%s)\n", mfr, id, @@ -405,7 +405,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) if (!doc->mfr) { doc->mfr = mfr; doc->id = id; - doc->chipshift = + doc->chipshift = ffs((nand_flash_ids[i].chipsize << 20)) - 1; doc->page256 = (nand_flash_ids[i].pagesize == 256) ? 1 : 0; doc->pageadrlen = doc->chipshift > 25 ? 3 : 2; @@ -467,7 +467,7 @@ static void DoC_ScanChips(struct DiskOnChip *this, int maxchips) ret = 0; - /* Fill out the chip array with {floor, chipno} for each + /* Fill out the chip array with {floor, chipno} for each * detected chip in the device. */ for (floor = 0; floor < MAX_FLOORS; floor++) { for (chip = 0; chip < numchips[floor]; chip++) { @@ -757,12 +757,12 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], eccbuf[4], eccbuf[5]); #endif - + /* disable the ECC engine */ WriteDOC(DOC_ECC_DIS, docptr , ECCConf); } - /* according to 11.4.1, we need to wait for the busy line + /* according to 11.4.1, we need to wait for the busy line * drop if we read to the end of the page. */ if(0 == ((from + len) & 0x1ff)) { @@ -941,7 +941,7 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, /* Let the caller know we completed it */ *retlen += len; - + if (eccbuf) { unsigned char x[8]; size_t dummy; @@ -950,10 +950,10 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, /* Write the ECC data to flash */ for (di=0; di<6; di++) x[di] = eccbuf[di]; - + x[6]=0x55; x[7]=0x55; - + ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x); if (ret) { up(&this->lock); @@ -970,7 +970,7 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, return 0; } -static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, +static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel) { @@ -1022,7 +1022,7 @@ static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, break; to += thislen; - } + } up(&writev_buf_sem); *retlen = totretlen; @@ -1080,7 +1080,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, /* Reading the full OOB data drops us off of the end of the page, * causing the flash device to go into busy mode, so we need * to wait until ready 11.4.1 and Toshiba TC58256FT docs */ - + ret = DoC_WaitReady(this); up(&this->lock); @@ -1190,7 +1190,7 @@ static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len, return 0; } - + static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t * retlen, const u_char * buf) { @@ -1222,7 +1222,7 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *instr) } instr->state = MTD_ERASING; - + /* FIXME: Do this in the background. Use timers or schedule_task() */ while(len) { mychip = &this->chips[ofs >> this->chipshift]; diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c index 1e704915ef0880d6c8325bacd64f1c8977bea3df..fcb28a6fd89f8dc011698b828b0c046b23aeb382 100644 --- a/drivers/mtd/devices/doc2001.c +++ b/drivers/mtd/devices/doc2001.c @@ -4,7 +4,7 @@ * (c) 1999 Machine Vision Holdings, Inc. * (c) 1999, 2000 David Woodhouse * - * $Id: doc2001.c,v 1.48 2005/01/05 18:05:12 dwmw2 Exp $ + * $Id: doc2001.c,v 1.49 2005/11/07 11:14:24 gleixner Exp $ */ #include @@ -196,10 +196,10 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) DoC_Command(doc->virtadr, NAND_CMD_RESET, CDSN_CTRL_WP); DoC_WaitReady(doc->virtadr); - /* Read the NAND chip ID: 1. Send ReadID command */ + /* Read the NAND chip ID: 1. Send ReadID command */ DoC_Command(doc->virtadr, NAND_CMD_READID, CDSN_CTRL_WP); - /* Read the NAND chip ID: 2. Send address byte zero */ + /* Read the NAND chip ID: 2. Send address byte zero */ DoC_Address(doc->virtadr, 1, 0x00, CDSN_CTRL_WP, 0x00); /* Read the manufacturer and device id codes of the flash device through @@ -223,7 +223,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { if (nand_manuf_ids[j].id == mfr) break; - } + } printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, " "Chip ID: %2.2X (%s:%s)\n", mfr, id, nand_manuf_ids[j].name, nand_flash_ids[i].name); @@ -275,7 +275,7 @@ static void DoC_ScanChips(struct DiskOnChip *this) return; } - /* Fill out the chip array with {floor, chipno} for each + /* Fill out the chip array with {floor, chipno} for each * detected chip in the device. */ for (floor = 0, ret = 0; floor < MAX_FLOORS_MIL; floor++) { for (chip = 0 ; chip < numchips[floor] ; chip++) { @@ -309,7 +309,7 @@ static int DoCMil_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2) tmp2 = ReadDOC(doc2->virtadr, AliasResolution); if (tmp1 != tmp2) return 0; - + WriteDOC((tmp1+1) % 0xff, doc1->virtadr, AliasResolution); tmp2 = ReadDOC(doc2->virtadr, AliasResolution); if (tmp2 == (tmp1+1) % 0xff) @@ -425,7 +425,7 @@ static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, return -EINVAL; /* Don't allow a single read to cross a 512-byte block boundary */ - if (from + len > ((from | 0x1ff) + 1)) + if (from + len > ((from | 0x1ff) + 1)) len = ((from | 0x1ff) + 1) - from; /* Find the chip which is to be used and select it */ @@ -552,7 +552,7 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, #if 0 /* Don't allow a single write to cross a 512-byte block boundary */ - if (to + len > ( (to | 0x1ff) + 1)) + if (to + len > ( (to | 0x1ff) + 1)) len = ((to | 0x1ff) + 1) - to; #else /* Don't allow writes which aren't exactly one block */ @@ -632,7 +632,7 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, /* write the block status BLOCK_USED (0x5555) at the end of ECC data FIXME: this is only a hack for programming the IPL area for LinuxBIOS - and should be replace with proper codes in user space utilities */ + and should be replace with proper codes in user space utilities */ WriteDOC(0x55, docptr, Mil_CDSN_IO); WriteDOC(0x55, docptr, Mil_CDSN_IO + 1); @@ -802,7 +802,7 @@ int doc_erase (struct mtd_info *mtd, struct erase_info *instr) void __iomem *docptr = this->virtadr; struct Nand *mychip = &this->chips[ofs >> this->chipshift]; - if (len != mtd->erasesize) + if (len != mtd->erasesize) printk(KERN_WARNING "Erase not right size (%x != %x)n", len, mtd->erasesize); @@ -870,9 +870,9 @@ static void __exit cleanup_doc2001(void) while ((mtd=docmillist)) { this = mtd->priv; docmillist = this->nextdoc; - + del_mtd_device(mtd); - + iounmap(this->virtadr); kfree(this->chips); kfree(mtd); diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c index ed47bafb2ce2f9380d4e2bf9f516022e0735936d..0595cc7324b257d7f95a147c618df5af9f6bf73f 100644 --- a/drivers/mtd/devices/doc2001plus.c +++ b/drivers/mtd/devices/doc2001plus.c @@ -6,7 +6,7 @@ * (c) 1999 Machine Vision Holdings, Inc. * (c) 1999, 2000 David Woodhouse * - * $Id: doc2001plus.c,v 1.13 2005/01/05 18:05:12 dwmw2 Exp $ + * $Id: doc2001plus.c,v 1.14 2005/11/07 11:14:24 gleixner Exp $ * * Released under GPL */ @@ -293,10 +293,10 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) DoC_Command(docptr, NAND_CMD_RESET, 0); DoC_WaitReady(docptr); - /* Read the NAND chip ID: 1. Send ReadID command */ + /* Read the NAND chip ID: 1. Send ReadID command */ DoC_Command(docptr, NAND_CMD_READID, 0); - /* Read the NAND chip ID: 2. Send address byte zero */ + /* Read the NAND chip ID: 2. Send address byte zero */ DoC_Address(doc, 1, 0x00, 0, 0x00); WriteDOC(0, docptr, Mplus_FlashControl); @@ -365,7 +365,7 @@ static void DoC_ScanChips(struct DiskOnChip *this) this->interleave = 1; /* Check the ASIC agrees */ - if ( (this->interleave << 2) != + if ( (this->interleave << 2) != (ReadDOC(this->virtadr, Mplus_Configuration) & 4)) { u_char conf = ReadDOC(this->virtadr, Mplus_Configuration); printk(KERN_NOTICE "Setting DiskOnChip Millennium Plus interleave to %s\n", @@ -398,7 +398,7 @@ static void DoC_ScanChips(struct DiskOnChip *this) return; } - /* Fill out the chip array with {floor, chipno} for each + /* Fill out the chip array with {floor, chipno} for each * detected chip in the device. */ for (floor = 0, ret = 0; floor < MAX_FLOORS_MPLUS; floor++) { for (chip = 0 ; chip < numchips[floor] ; chip++) { @@ -432,7 +432,7 @@ static int DoCMilPlus_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2) tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution); if (tmp1 != tmp2) return 0; - + WriteDOC((tmp1+1) % 0xff, doc1->virtadr, Mplus_AliasResolution); tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution); if (tmp2 == (tmp1+1) % 0xff) @@ -624,7 +624,7 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, return -EINVAL; /* Don't allow a single read to cross a 512-byte block boundary */ - if (from + len > ((from | 0x1ff) + 1)) + if (from + len > ((from | 0x1ff) + 1)) len = ((from | 0x1ff) + 1) - from; DoC_CheckASIC(docptr); @@ -1066,7 +1066,7 @@ int doc_erase(struct mtd_info *mtd, struct erase_info *instr) DoC_CheckASIC(docptr); - if (len != mtd->erasesize) + if (len != mtd->erasesize) printk(KERN_WARNING "MTD: Erase not right size (%x != %x)n", len, mtd->erasesize); @@ -1136,9 +1136,9 @@ static void __exit cleanup_doc2001plus(void) while ((mtd=docmilpluslist)) { this = mtd->priv; docmilpluslist = this->nextdoc; - + del_mtd_device(mtd); - + iounmap(this->virtadr); kfree(this->chips); kfree(mtd); diff --git a/drivers/mtd/devices/docecc.c b/drivers/mtd/devices/docecc.c index 24f670b5a4f34e4b36751fe66479ada3d78843f6..cd3db72bef96ae92cfd9a69ee688d20d5759bc33 100644 --- a/drivers/mtd/devices/docecc.c +++ b/drivers/mtd/devices/docecc.c @@ -4,10 +4,10 @@ * GNU GPL License. The rest is simply to convert the disk on chip * syndrom into a standard syndom. * - * Author: Fabrice Bellard (fabrice.bellard@netgem.com) + * Author: Fabrice Bellard (fabrice.bellard@netgem.com) * Copyright (C) 2000 Netgem S.A. * - * $Id: docecc.c,v 1.5 2003/05/21 15:15:06 dwmw2 Exp $ + * $Id: docecc.c,v 1.7 2005/11/07 11:14:25 gleixner Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -122,7 +122,7 @@ for(ci=(n)-1;ci >=0;ci--)\ a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1) we consider the integer "i" whose binary representation with a(0) being LSB and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry - "index_of[i]". Now, @^index_of[i] is that element whose polynomial + "index_of[i]". Now, @^index_of[i] is that element whose polynomial representation is (a(0),a(1),a(2),...,a(m-1)). NOTE: The element alpha_to[2^m-1] = 0 always signifying that the @@ -130,7 +130,7 @@ for(ci=(n)-1;ci >=0;ci--)\ Similarily, the element index_of[0] = A0 always signifying that the power of alpha which has the polynomial representation (0,0,...,0) is "infinity". - + */ static void @@ -176,7 +176,7 @@ generate_gf(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1]) * are written back. NOTE! This array must be at least NN-KK elements long. * The corrected data are written in eras_val[]. They must be xor with the data * to retrieve the correct data : data[erase_pos[i]] ^= erase_val[i] . - * + * * First "no_eras" erasures are declared by the calling program. Then, the * maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2). * If the number of channel errors is not greater than "t_after_eras" the @@ -189,7 +189,7 @@ generate_gf(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1]) * */ static int eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], - gf bb[NN - KK + 1], gf eras_val[NN-KK], int eras_pos[NN-KK], + gf bb[NN - KK + 1], gf eras_val[NN-KK], int eras_pos[NN-KK], int no_eras) { int deg_lambda, el, deg_omega; @@ -212,7 +212,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], count = 0; goto finish; } - + for(i=1;i<=NN-KK;i++){ s[i] = bb[0]; } @@ -220,7 +220,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], if(bb[j] == 0) continue; tmp = Index_of[bb[j]]; - + for(i=1;i<=NN-KK;i++) s[i] ^= Alpha_to[modnn(tmp + (B0+i-1)*PRIM*j)]; } @@ -234,7 +234,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], tmp = modnn(tmp + 2 * KK * (B0+i-1)*PRIM); s[i] = tmp; } - + CLEAR(&lambda[1],NN-KK); lambda[0] = 1; @@ -252,7 +252,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], #if DEBUG_ECC >= 1 /* Test code that verifies the erasure locator polynomial just constructed Needed only for decoder debugging. */ - + /* find roots of the erasure location polynomial */ for(i=1;i<=no_eras;i++) reg[i] = Index_of[lambda[i]]; @@ -286,7 +286,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], } for(i=0;i= 0; i -=2) { if(lambda[i+1] != A0) @@ -436,11 +436,11 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], /* The sector bytes are packed into NB_DATA MM bits words */ #define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / MM) -/* +/* * Correct the errors in 'sector[]' by using 'ecc1[]' which is the * content of the feedback shift register applyied to the sector and * the ECC. Return the number of errors corrected (and correct them in - * sector), or -1 if error + * sector), or -1 if error */ int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6]) { @@ -454,7 +454,7 @@ int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6]) Alpha_to = kmalloc((NN + 1) * sizeof(dtype), GFP_KERNEL); if (!Alpha_to) return -1; - + Index_of = kmalloc((NN + 1) * sizeof(dtype), GFP_KERNEL); if (!Index_of) { kfree(Alpha_to); @@ -470,7 +470,7 @@ int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6]) bb[2] = ((ecc1[2] & 0xf0) >> 4) | ((ecc1[3] & 0x3f) << 4); bb[3] = ((ecc1[3] & 0xc0) >> 6) | ((ecc1[0] & 0xff) << 2); - nb_errors = eras_dec_rs(Alpha_to, Index_of, bb, + nb_errors = eras_dec_rs(Alpha_to, Index_of, bb, error_val, error_pos, 0); if (nb_errors <= 0) goto the_end; @@ -489,7 +489,7 @@ int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6]) can be modified since pos is even */ index = (pos >> 3) ^ 1; bitpos = pos & 7; - if ((index >= 0 && index < SECTOR_SIZE) || + if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) { val = error_val[i] >> (2 + bitpos); parity ^= val; @@ -500,7 +500,7 @@ int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6]) bitpos = (bitpos + 10) & 7; if (bitpos == 0) bitpos = 8; - if ((index >= 0 && index < SECTOR_SIZE) || + if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) { val = error_val[i] << (8 - bitpos); parity ^= val; @@ -509,7 +509,7 @@ int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6]) } } } - + /* use parity to test extra errors */ if ((parity & 0xff) != 0) nb_errors = -1; diff --git a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c index 197d67045e1e754e60424fcd2dd180d206336618..13178b9dd00aa1db3a72a3a9a87100efff547029 100644 --- a/drivers/mtd/devices/docprobe.c +++ b/drivers/mtd/devices/docprobe.c @@ -4,22 +4,22 @@ /* (C) 1999 Machine Vision Holdings, Inc. */ /* (C) 1999-2003 David Woodhouse */ -/* $Id: docprobe.c,v 1.44 2005/01/05 12:40:36 dwmw2 Exp $ */ +/* $Id: docprobe.c,v 1.46 2005/11/07 11:14:25 gleixner Exp $ */ /* DOC_PASSIVE_PROBE: - In order to ensure that the BIOS checksum is correct at boot time, and - hence that the onboard BIOS extension gets executed, the DiskOnChip - goes into reset mode when it is read sequentially: all registers - return 0xff until the chip is woken up again by writing to the - DOCControl register. - - Unfortunately, this means that the probe for the DiskOnChip is unsafe, - because one of the first things it does is write to where it thinks - the DOCControl register should be - which may well be shared memory - for another device. I've had machines which lock up when this is - attempted. Hence the possibility to do a passive probe, which will fail + In order to ensure that the BIOS checksum is correct at boot time, and + hence that the onboard BIOS extension gets executed, the DiskOnChip + goes into reset mode when it is read sequentially: all registers + return 0xff until the chip is woken up again by writing to the + DOCControl register. + + Unfortunately, this means that the probe for the DiskOnChip is unsafe, + because one of the first things it does is write to where it thinks + the DOCControl register should be - which may well be shared memory + for another device. I've had machines which lock up when this is + attempted. Hence the possibility to do a passive probe, which will fail to detect a chip in reset mode, but is at least guaranteed not to lock the machine. @@ -33,9 +33,9 @@ The old Millennium-only driver has been retained just in case there are problems with the new code. If the combined driver doesn't work - for you, you can try the old one by undefining DOC_SINGLE_DRIVER + for you, you can try the old one by undefining DOC_SINGLE_DRIVER below and also enabling it in your configuration. If this fixes the - problems, please send a report to the MTD mailing list at + problems, please send a report to the MTD mailing list at . */ #define DOC_SINGLE_DRIVER @@ -68,16 +68,16 @@ MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe static unsigned long __initdata doc_locations[] = { #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__) #ifdef CONFIG_MTD_DOCPROBE_HIGH - 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, + 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, 0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000, - 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, - 0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, + 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, + 0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, 0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000, #else /* CONFIG_MTD_DOCPROBE_HIGH */ - 0xc8000, 0xca000, 0xcc000, 0xce000, + 0xc8000, 0xca000, 0xcc000, 0xce000, 0xd0000, 0xd2000, 0xd4000, 0xd6000, - 0xd8000, 0xda000, 0xdc000, 0xde000, - 0xe0000, 0xe2000, 0xe4000, 0xe6000, + 0xd8000, 0xda000, 0xdc000, 0xde000, + 0xe0000, 0xe2000, 0xe4000, 0xe6000, 0xe8000, 0xea000, 0xec000, 0xee000, #endif /* CONFIG_MTD_DOCPROBE_HIGH */ #elif defined(__PPC__) @@ -111,35 +111,35 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr return 0; #endif /* CONFIG_MTD_DOCPROBE_55AA */ -#ifndef DOC_PASSIVE_PROBE +#ifndef DOC_PASSIVE_PROBE /* It's not possible to cleanly detect the DiskOnChip - the * bootup procedure will put the device into reset mode, and * it's not possible to talk to it without actually writing * to the DOCControl register. So we store the current contents * of the DOCControl register's location, in case we later decide * that it's not a DiskOnChip, and want to put it back how we - * found it. + * found it. */ tmp2 = ReadDOC(window, DOCControl); - + /* Reset the DiskOnChip ASIC */ - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, window, DOCControl); - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, window, DOCControl); - + /* Enable the DiskOnChip ASIC */ - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, window, DOCControl); - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, window, DOCControl); -#endif /* !DOC_PASSIVE_PROBE */ +#endif /* !DOC_PASSIVE_PROBE */ /* We need to read the ChipID register four times. For some newer DiskOnChip 2000 units, the first three reads will return the DiskOnChip Millennium ident. Don't ask. */ ChipID = ReadDOC(window, ChipID); - + switch (ChipID) { case DOC_ChipID_Doc2k: /* Check the TOGGLE bit in the ECC register */ @@ -149,7 +149,7 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr if (tmp != tmpb && tmp == tmpc) return ChipID; break; - + case DOC_ChipID_DocMil: /* Check for the new 2000 with Millennium ASIC */ ReadDOC(window, ChipID); @@ -164,7 +164,7 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr if (tmp != tmpb && tmp == tmpc) return ChipID; break; - + case DOC_ChipID_DocMilPlus16: case DOC_ChipID_DocMilPlus32: case 0: @@ -179,7 +179,7 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr DOC_MODE_BDECT; WriteDOC(tmp, window, Mplus_DOCControl); WriteDOC(~tmp, window, Mplus_CtrlConfirm); - + mdelay(1); /* Enable the DiskOnChip ASIC */ tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | @@ -187,7 +187,7 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr WriteDOC(tmp, window, Mplus_DOCControl); WriteDOC(~tmp, window, Mplus_CtrlConfirm); mdelay(1); -#endif /* !DOC_PASSIVE_PROBE */ +#endif /* !DOC_PASSIVE_PROBE */ ChipID = ReadDOC(window, ChipID); @@ -227,7 +227,7 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr WriteDOC(tmp2, window, DOCControl); #endif return 0; -} +} static int docfound; @@ -244,10 +244,10 @@ static void __init DoC_Probe(unsigned long physadr) void (*initroutine)(struct mtd_info *) = NULL; docptr = ioremap(physadr, DOC_IOREMAP_LEN); - + if (!docptr) return; - + if ((ChipID = doccheck(docptr, physadr))) { if (ChipID == DOC_ChipID_Doc2kTSOP) { /* Remove this at your own peril. The hardware driver works but nothing prevents you from erasing bad blocks */ @@ -263,9 +263,9 @@ static void __init DoC_Probe(unsigned long physadr) iounmap(docptr); return; } - + this = (struct DiskOnChip *)(&mtd[1]); - + memset((char *)mtd,0, sizeof(struct mtd_info)); memset((char *)this, 0, sizeof(struct DiskOnChip)); @@ -281,13 +281,13 @@ static void __init DoC_Probe(unsigned long physadr) im_funcname = "DoC2k_init"; im_modname = "doc2000"; break; - + case DOC_ChipID_Doc2k: name="2000"; im_funcname = "DoC2k_init"; im_modname = "doc2000"; break; - + case DOC_ChipID_DocMil: name="Millennium"; #ifdef DOC_SINGLE_DRIVER @@ -331,7 +331,7 @@ static void __init DoC_Probe(unsigned long physadr) static int __init init_doc(void) { int i; - + if (doc_config_location) { printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location); DoC_Probe(doc_config_location); diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c index df987a53ed9cf918c5c8d318e0dc8b1267f2a96e..1e876fcb04084ca43ff366803973fad01ee9b833 100644 --- a/drivers/mtd/devices/lart.c +++ b/drivers/mtd/devices/lart.c @@ -2,7 +2,7 @@ /* * MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART. * - * $Id: lart.c,v 1.7 2004/08/09 13:19:44 dwmw2 Exp $ + * $Id: lart.c,v 1.9 2005/11/07 11:14:25 gleixner Exp $ * * Author: Abraham vd Merwe * @@ -122,7 +122,7 @@ static char module_name[] = "lart"; /* * The data line mapping on LART is as follows: - * + * * U2 CPU | U3 CPU * ------------------- * 0 20 | 0 12 @@ -181,7 +181,7 @@ static char module_name[] = "lart"; (((x) & 0x00004000) >> 13) \ ) -/* +/* * The address line mapping on LART is as follows: * * U3 CPU | U2 CPU @@ -204,7 +204,7 @@ static char module_name[] = "lart"; * 12 15 | 12 15 * 13 14 | 13 14 * 14 16 | 14 16 - * + * * MAIN BLOCK BOUNDARY * * 15 17 | 15 18 diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 765c0179c8df9097e476982c57131edea2399647..e8685ee6c1e425f202b8ca2b91ea6de05dc8c8ae 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -1,5 +1,5 @@ /** - * $Id: phram.c,v 1.14 2005/03/07 21:43:38 joern Exp $ + * $Id: phram.c,v 1.16 2005/11/07 11:14:25 gleixner Exp $ * * Copyright (c) ???? Jochen Schäuble * Copyright (c) 2003-2004 Jörn Engel @@ -41,10 +41,10 @@ static int phram_erase(struct mtd_info *mtd, struct erase_info *instr) if (instr->addr + instr->len > mtd->size) return -EINVAL; - + memset(start + instr->addr, 0xff, instr->len); - /* This'll catch a few races. Free the thing before returning :) + /* This'll catch a few races. Free the thing before returning :) * I don't feel at all ashamed. This kind of thing is possible anyway * with flash, but unlikely. */ @@ -63,7 +63,7 @@ static int phram_point(struct mtd_info *mtd, loff_t from, size_t len, if (from + len > mtd->size) return -EINVAL; - + *mtdbuf = start + from; *retlen = len; return 0; @@ -84,7 +84,7 @@ static int phram_read(struct mtd_info *mtd, loff_t from, size_t len, if (len > mtd->size - from) len = mtd->size - from; - + memcpy(buf, start + from, len); *retlen = len; @@ -101,7 +101,7 @@ static int phram_write(struct mtd_info *mtd, loff_t to, size_t len, if (len > mtd->size - to) len = mtd->size - to; - + memcpy(start + to, buf, len); *retlen = len; @@ -159,7 +159,7 @@ static int register_device(char *name, unsigned long start, unsigned long len) } list_add_tail(&new->list, &phram_list); - return 0; + return 0; out2: iounmap(new->mtd.priv); diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c index 5b3defadf884d264b6920648feb2a83a65d576d9..de48b35f5609e96957b2a7ec0e71de2572ca0236 100644 --- a/drivers/mtd/devices/pmc551.c +++ b/drivers/mtd/devices/pmc551.c @@ -1,5 +1,5 @@ /* - * $Id: pmc551.c,v 1.30 2005/01/05 18:05:13 dwmw2 Exp $ + * $Id: pmc551.c,v 1.32 2005/11/07 11:14:25 gleixner Exp $ * * PMC551 PCI Mezzanine Ram Device * @@ -27,7 +27,7 @@ * it as high speed swap or for a high speed disk device of some * sort. Which becomes very useful on diskless systems in the * embedded market I might add. - * + * * Notes: * Due to what I assume is more buggy SROM, the 64M PMC551 I * have available claims that all 4 of it's DRAM banks have 64M @@ -63,10 +63,10 @@ * Minyard set up the card to utilize a 1M sliding apature. * * Corey Minyard - * * Modified driver to utilize a sliding aperture instead of + * * Modified driver to utilize a sliding aperture instead of * mapping all memory into kernel space which turned out to * be very wasteful. - * * Located a bug in the SROM's initialization sequence that + * * Located a bug in the SROM's initialization sequence that * made the memory unusable, added a fix to code to touch up * the DRAM some. * @@ -390,7 +390,7 @@ static u32 fixup_pmc551 (struct pci_dev *dev) bcmd |= (0x40|0x20); pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd); - /* + /* * Take care and turn off the memory on the device while we * tweak the configurations */ @@ -408,7 +408,7 @@ static u32 fixup_pmc551 (struct pci_dev *dev) * Grab old BAR0 config so that we can figure out memory size * This is another bit of kludge going on. The reason for the * redundancy is I am hoping to retain the original configuration - * previously assigned to the card by the BIOS or some previous + * previously assigned to the card by the BIOS or some previous * fixup routine in the kernel. So we read the old config into cfg, * then write all 1's to the memory space, read back the result into * "size", and then write back all the old config. @@ -480,7 +480,7 @@ static u32 fixup_pmc551 (struct pci_dev *dev) } while ( (PCI_COMMAND_IO) & cmd ); /* - * Turn on auto refresh + * Turn on auto refresh * The loop is taken directly from Ramix's example code. I assume that * this must be held high for some duration of time, but I can find no * documentation refrencing the reasons why. @@ -615,7 +615,7 @@ static u32 fixup_pmc551 (struct pci_dev *dev) pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd ); printk( KERN_DEBUG "pmc551: EEPROM is under %s control\n" "pmc551: System Control Register is %slocked to PCI access\n" - "pmc551: System Control Register is %slocked to EEPROM access\n", + "pmc551: System Control Register is %slocked to EEPROM access\n", (bcmd&0x1)?"software":"hardware", (bcmd&0x20)?"":"un", (bcmd&0x40)?"":"un"); #endif @@ -744,7 +744,7 @@ static int __init init_pmc551(void) priv->start = ioremap(((PCI_Device->resource[0].start) & PCI_BASE_ADDRESS_MEM_MASK), priv->asize); - + if (!priv->start) { printk(KERN_NOTICE "pmc551: Unable to map IO space\n"); kfree(mtd->priv); @@ -765,7 +765,7 @@ static int __init init_pmc551(void) priv->curr_map0 ); #ifdef CONFIG_MTD_PMC551_DEBUG - printk( KERN_DEBUG "pmc551: aperture set to %d\n", + printk( KERN_DEBUG "pmc551: aperture set to %d\n", (priv->base_map0 & 0xF0)>>4 ); #endif @@ -823,13 +823,13 @@ static void __exit cleanup_pmc551(void) while((mtd=pmc551list)) { priv = mtd->priv; pmc551list = priv->nextpmc551; - + if(priv->start) { printk (KERN_DEBUG "pmc551: unmapping %dM starting at 0x%p\n", priv->asize>>20, priv->start); iounmap (priv->start); } - + kfree (mtd->priv); del_mtd_device (mtd); kfree (mtd); diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index 84fa91392a8c7180b5113a15a290e76f49f4a50a..6faee6c6958c2a7bc709b53df6cf61ff6c507369 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c @@ -1,6 +1,6 @@ /*====================================================================== - $Id: slram.c,v 1.34 2005/01/06 21:16:42 jwboyer Exp $ + $Id: slram.c,v 1.36 2005/11/07 11:14:25 gleixner Exp $ This driver provides a method to access memory not used by the kernel itself (i.e. if the kernel commandline mem=xxx is used). To actually @@ -18,14 +18,14 @@ : start of the memory region, decimal or hex (0xabcdef) : end of the memory region. It's possible to use +0x1234 to specify the offset instead of the absolute address - + NOTE: With slram it's only possible to map a contigous memory region. Therfore if there's a device mapped somewhere in the region specified slram will fail to load (see kernel log if modprobe fails). - - + Jochen Schaeuble ======================================================================*/ @@ -89,10 +89,10 @@ static int slram_erase(struct mtd_info *mtd, struct erase_info *instr) if (instr->addr + instr->len > mtd->size) { return(-EINVAL); } - + memset(priv->start + instr->addr, 0xff, instr->len); - /* This'll catch a few races. Free the thing before returning :) + /* This'll catch a few races. Free the thing before returning :) * I don't feel at all ashamed. This kind of thing is possible anyway * with flash, but unlikely. */ @@ -170,12 +170,12 @@ static int register_device(char *name, unsigned long start, unsigned long length } (*curmtd)->mtdinfo = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); (*curmtd)->next = NULL; - + if ((*curmtd)->mtdinfo) { memset((char *)(*curmtd)->mtdinfo, 0, sizeof(struct mtd_info)); (*curmtd)->mtdinfo->priv = kmalloc(sizeof(slram_priv_t), GFP_KERNEL); - + if (!(*curmtd)->mtdinfo->priv) { kfree((*curmtd)->mtdinfo); (*curmtd)->mtdinfo = NULL; @@ -188,7 +188,7 @@ static int register_device(char *name, unsigned long start, unsigned long length E("slram: Cannot allocate new MTD device.\n"); return(-ENOMEM); } - + if (!(((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start = ioremap(start, length))) { E("slram: ioremap failed\n"); @@ -223,7 +223,7 @@ static int register_device(char *name, unsigned long start, unsigned long length T("slram: Mapped from 0x%p to 0x%p\n", ((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start, ((slram_priv_t *)(*curmtd)->mtdinfo->priv)->end); - return(0); + return(0); } static void unregister_devices(void) @@ -256,7 +256,7 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength) char *buffer; unsigned long devstart; unsigned long devlength; - + if ((!devname) || (!szstart) || (!szlength)) { unregister_devices(); return(-EINVAL); @@ -264,7 +264,7 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength) devstart = simple_strtoul(szstart, &buffer, 0); devstart = handle_unit(devstart, buffer); - + if (*(szlength) != '+') { devlength = simple_strtoul(szlength, &buffer, 0); devlength = handle_unit(devlength, buffer) - devstart; @@ -278,7 +278,7 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength) E("slram: Illegal start / length parameter.\n"); return(-EINVAL); } - + if ((devstart = register_device(devname, devstart, devlength))){ unregister_devices(); return((int)devstart); @@ -335,7 +335,7 @@ static int init_slram(void) } #else int count; - + for (count = 0; (map[count]) && (count < SLRAM_MAX_DEVICES_PARAMS); count++) { } @@ -350,10 +350,10 @@ static int init_slram(void) if (parse_cmdline(devname, map[i * 3 + 1], map[i * 3 + 2])!=0) { return(-EINVAL); } - + } #endif /* !MODULE */ - + return(0); } diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index d32c1b3a8ce34422bd7c476b80299beef40ebb67..de7e231d6d180deb3528caeb62593555ba09f363 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -1,5 +1,5 @@ /* This version ported to the Linux-MTD system by dwmw2@infradead.org - * $Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $ + * $Id: ftl.c,v 1.58 2005/11/07 11:14:19 gleixner Exp $ * * Fixes: Arnaldo Carvalho de Melo * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups @@ -53,7 +53,7 @@ Use of the FTL format for non-PCMCIA applications may be an infringement of these patents. For additional information, contact M-Systems (http://www.m-sys.com) directly. - + ======================================================================*/ #include #include @@ -160,7 +160,7 @@ static void ftl_erase_callback(struct erase_info *done); Scan_header() checks to see if a memory region contains an FTL partition. build_maps() reads all the erase unit headers, builds the erase unit map, and then builds the virtual page map. - + ======================================================================*/ static int scan_header(partition_t *part) @@ -176,10 +176,10 @@ static int scan_header(partition_t *part) (offset + sizeof(header)) < max_offset; offset += part->mbd.mtd->erasesize ? : 0x2000) { - err = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret, + err = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret, (unsigned char *)&header); - - if (err) + + if (err) return err; if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break; @@ -232,10 +232,10 @@ static int build_maps(partition_t *part) for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) { offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN)) << part->header.EraseUnitSize); - ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval, + ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval, (unsigned char *)&header); - - if (ret) + + if (ret) goto out_XferInfo; ret = -1; @@ -274,7 +274,7 @@ static int build_maps(partition_t *part) "don't add up!\n"); goto out_XferInfo; } - + /* Set up virtual page map */ blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize; part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t)); @@ -296,12 +296,12 @@ static int build_maps(partition_t *part) part->EUNInfo[i].Free = 0; part->EUNInfo[i].Deleted = 0; offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset); - - ret = part->mbd.mtd->read(part->mbd.mtd, offset, - part->BlocksPerUnit * sizeof(u_int32_t), &retval, + + ret = part->mbd.mtd->read(part->mbd.mtd, offset, + part->BlocksPerUnit * sizeof(u_int32_t), &retval, (unsigned char *)part->bam_cache); - - if (ret) + + if (ret) goto out_bam_cache; for (j = 0; j < part->BlocksPerUnit; j++) { @@ -316,7 +316,7 @@ static int build_maps(partition_t *part) part->EUNInfo[i].Deleted++; } } - + ret = 0; goto out; @@ -336,7 +336,7 @@ static int build_maps(partition_t *part) Erase_xfer() schedules an asynchronous erase operation for a transfer unit. - + ======================================================================*/ static int erase_xfer(partition_t *part, @@ -351,10 +351,10 @@ static int erase_xfer(partition_t *part, xfer->state = XFER_ERASING; /* Is there a free erase slot? Always in MTD. */ - - + + erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL); - if (!erase) + if (!erase) return -ENOMEM; erase->mtd = part->mbd.mtd; @@ -362,7 +362,7 @@ static int erase_xfer(partition_t *part, erase->addr = xfer->Offset; erase->len = 1 << part->header.EraseUnitSize; erase->priv = (u_long)part; - + ret = part->mbd.mtd->erase(part->mbd.mtd, erase); if (!ret) @@ -377,7 +377,7 @@ static int erase_xfer(partition_t *part, Prepare_xfer() takes a freshly erased transfer unit and gives it an appropriate header. - + ======================================================================*/ static void ftl_erase_callback(struct erase_info *erase) @@ -385,7 +385,7 @@ static void ftl_erase_callback(struct erase_info *erase) partition_t *part; struct xfer_info_t *xfer; int i; - + /* Look up the transfer unit */ part = (partition_t *)(erase->priv); @@ -422,7 +422,7 @@ static int prepare_xfer(partition_t *part, int i) xfer = &part->XferInfo[i]; xfer->state = XFER_FAILED; - + DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset); /* Write the transfer unit header */ @@ -446,7 +446,7 @@ static int prepare_xfer(partition_t *part, int i) for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) { - ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t), + ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t), &retlen, (u_char *)&ctl); if (ret) @@ -454,7 +454,7 @@ static int prepare_xfer(partition_t *part, int i) } xfer->state = XFER_PREPARED; return 0; - + } /* prepare_xfer */ /*====================================================================== @@ -466,7 +466,7 @@ static int prepare_xfer(partition_t *part, int i) All data blocks are copied to the corresponding blocks in the target unit, so the virtual block map does not need to be updated. - + ======================================================================*/ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, @@ -486,14 +486,14 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, xfer = &part->XferInfo[xferunit]; DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n", eun->Offset, xfer->Offset); - - + + /* Read current BAM */ if (part->bam_index != srcunit) { offset = eun->Offset + le32_to_cpu(part->header.BAMOffset); - ret = part->mbd.mtd->read(part->mbd.mtd, offset, + ret = part->mbd.mtd->read(part->mbd.mtd, offset, part->BlocksPerUnit * sizeof(u_int32_t), &retlen, (u_char *) (part->bam_cache)); @@ -501,11 +501,11 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, part->bam_index = 0xffff; if (ret) { - printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n"); + printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n"); return ret; } } - + /* Write the LogicalEUN for the transfer unit */ xfer->state = XFER_UNKNOWN; offset = xfer->Offset + 20; /* Bad! */ @@ -513,12 +513,12 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t), &retlen, (u_char *) &unit); - + if (ret) { printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n"); return ret; } - + /* Copy all data blocks from source unit to transfer unit */ src = eun->Offset; dest = xfer->Offset; @@ -558,15 +558,15 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, } /* Write the BAM to the transfer unit */ - ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset), - part->BlocksPerUnit * sizeof(int32_t), &retlen, + ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset), + part->BlocksPerUnit * sizeof(int32_t), &retlen, (u_char *)part->bam_cache); if (ret) { printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n"); return ret; } - + /* All clear? Then update the LogicalEUN again */ ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t), &retlen, (u_char *)&srcunitswap); @@ -574,9 +574,9 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, if (ret) { printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n"); return ret; - } - - + } + + /* Update the maps and usage stats*/ i = xfer->EraseCount; xfer->EraseCount = eun->EraseCount; @@ -588,10 +588,10 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, part->FreeTotal += free; eun->Free = free; eun->Deleted = 0; - + /* Now, the cache should be valid for the new block */ part->bam_index = srcunit; - + return 0; } /* copy_erase_unit */ @@ -608,7 +608,7 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, oldest data unit instead. This means that we generally postpone the next reclaimation as long as possible, but shuffle static stuff around a bit for wear leveling. - + ======================================================================*/ static int reclaim_block(partition_t *part) @@ -666,7 +666,7 @@ static int reclaim_block(partition_t *part) else DEBUG(1, "ftl_cs: reclaim failed: no " "suitable transfer units!\n"); - + return -EIO; } } @@ -715,7 +715,7 @@ static int reclaim_block(partition_t *part) returns the block index -- the erase unit is just the currently cached unit. If there are no free blocks, it returns 0 -- this is never a valid data block because it contains the header. - + ======================================================================*/ #ifdef PSYCHO_DEBUG @@ -737,7 +737,7 @@ static u_int32_t find_free(partition_t *part) u_int32_t blk; size_t retlen; int ret; - + /* Find an erase unit with some free space */ stop = (part->bam_index == 0xffff) ? 0 : part->bam_index; eun = stop; @@ -749,17 +749,17 @@ static u_int32_t find_free(partition_t *part) if (part->EUNInfo[eun].Free == 0) return 0; - + /* Is this unit's BAM cached? */ if (eun != part->bam_index) { /* Invalidate cache */ part->bam_index = 0xffff; - ret = part->mbd.mtd->read(part->mbd.mtd, + ret = part->mbd.mtd->read(part->mbd.mtd, part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset), part->BlocksPerUnit * sizeof(u_int32_t), &retlen, (u_char *) (part->bam_cache)); - + if (ret) { printk(KERN_WARNING"ftl: Error reading BAM in find_free\n"); return 0; @@ -781,14 +781,14 @@ static u_int32_t find_free(partition_t *part) } DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun); return blk; - + } /* find_free */ /*====================================================================== Read a series of sectors from an FTL partition. - + ======================================================================*/ static int ftl_read(partition_t *part, caddr_t buffer, @@ -798,7 +798,7 @@ static int ftl_read(partition_t *part, caddr_t buffer, u_long i; int ret; size_t offset, retlen; - + DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n", part, sector, nblocks); if (!(part->state & FTL_FORMATTED)) { @@ -834,7 +834,7 @@ static int ftl_read(partition_t *part, caddr_t buffer, /*====================================================================== Write a series of sectors to an FTL partition - + ======================================================================*/ static int set_bam_entry(partition_t *part, u_int32_t log_addr, @@ -855,7 +855,7 @@ static int set_bam_entry(partition_t *part, u_int32_t log_addr, blk = (log_addr % bsize) / SECTOR_SIZE; offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) + le32_to_cpu(part->header.BAMOffset)); - + #ifdef PSYCHO_DEBUG ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t), &retlen, (u_char *)&old_addr); @@ -925,7 +925,7 @@ static int ftl_write(partition_t *part, caddr_t buffer, if (ret) return ret; } - + bsize = 1 << part->header.EraseUnitSize; virt_addr = sector * SECTOR_SIZE | BLOCK_DATA; @@ -949,12 +949,12 @@ static int ftl_write(partition_t *part, caddr_t buffer, log_addr = part->bam_index * bsize + blk * SECTOR_SIZE; part->EUNInfo[part->bam_index].Free--; part->FreeTotal--; - if (set_bam_entry(part, log_addr, 0xfffffffe)) + if (set_bam_entry(part, log_addr, 0xfffffffe)) return -EIO; part->EUNInfo[part->bam_index].Deleted++; offset = (part->EUNInfo[part->bam_index].Offset + blk * SECTOR_SIZE); - ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, + ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, buffer); if (ret) { @@ -964,7 +964,7 @@ static int ftl_write(partition_t *part, caddr_t buffer, offset); return -EIO; } - + /* Only delete the old entry when the new entry is ready */ old_addr = part->VirtualBlockMap[sector+i]; if (old_addr != 0xffffffff) { @@ -979,7 +979,7 @@ static int ftl_write(partition_t *part, caddr_t buffer, return -EIO; part->VirtualBlockMap[sector+i] = log_addr; part->EUNInfo[part->bam_index].Deleted--; - + buffer += SECTOR_SIZE; virt_addr += SECTOR_SIZE; } @@ -1034,20 +1034,20 @@ static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) partition_t *partition; partition = kmalloc(sizeof(partition_t), GFP_KERNEL); - + if (!partition) { printk(KERN_WARNING "No memory to scan for FTL on %s\n", mtd->name); return; - } + } memset(partition, 0, sizeof(partition_t)); partition->mbd.mtd = mtd; - if ((scan_header(partition) == 0) && + if ((scan_header(partition) == 0) && (build_maps(partition) == 0)) { - + partition->state = FTL_FORMATTED; #ifdef PCMCIA_DEBUG printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n", @@ -1086,7 +1086,7 @@ struct mtd_blktrans_ops ftl_tr = { int init_ftl(void) { - DEBUG(0, "$Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $\n"); + DEBUG(0, "$Id: ftl.c,v 1.58 2005/11/07 11:14:19 gleixner Exp $\n"); return register_mtd_blktrans(&ftl_tr); } diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index 39eb53f6551f0d96943539ce0ce0a41aba1dc22f..8a544890173d3c857c953eb149c68b14b145ba90 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -1,4 +1,4 @@ -/* +/* * inftlcore.c -- Linux driver for Inverse Flash Translation Layer (INFTL) * * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) @@ -7,7 +7,7 @@ * (c) 1999 Machine Vision Holdings, Inc. * Author: David Woodhouse * - * $Id: inftlcore.c,v 1.18 2004/11/16 18:28:59 dwmw2 Exp $ + * $Id: inftlcore.c,v 1.19 2005/11/07 11:14:20 gleixner Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -113,23 +113,21 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) if (inftl->mbd.size != inftl->heads * inftl->cylinders * inftl->sectors) { /* - Oh no we don't have + Oh no we don't have mbd.size == heads * cylinders * sectors */ printk(KERN_WARNING "INFTL: cannot calculate a geometry to " "match size of 0x%lx.\n", inftl->mbd.size); printk(KERN_WARNING "INFTL: using C:%d H:%d S:%d " "(== 0x%lx sects)\n", - inftl->cylinders, inftl->heads , inftl->sectors, + inftl->cylinders, inftl->heads , inftl->sectors, (long)inftl->cylinders * (long)inftl->heads * (long)inftl->sectors ); } if (add_mtd_blktrans_dev(&inftl->mbd)) { - if (inftl->PUtable) - kfree(inftl->PUtable); - if (inftl->VUtable) - kfree(inftl->VUtable); + kfree(inftl->PUtable); + kfree(inftl->VUtable); kfree(inftl); return; } @@ -147,10 +145,8 @@ static void inftl_remove_dev(struct mtd_blktrans_dev *dev) del_mtd_blktrans_dev(dev); - if (inftl->PUtable) - kfree(inftl->PUtable); - if (inftl->VUtable) - kfree(inftl->VUtable); + kfree(inftl->PUtable); + kfree(inftl->VUtable); kfree(inftl); } @@ -223,7 +219,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned "Virtual Unit Chain %d!\n", thisVUC); return BLOCK_NIL; } - + /* * Scan to find the Erase Unit which holds the actual data for each * 512-byte block within the Chain. @@ -264,7 +260,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned "Unit Chain 0x%x\n", thisVUC); return BLOCK_NIL; } - + thisEUN = inftl->PUtable[thisEUN]; } @@ -295,15 +291,15 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned */ if (BlockMap[block] == BLOCK_NIL) continue; - + ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize * BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE, - &retlen, movebuf); + &retlen, movebuf); if (ret < 0) { ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize * BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE, &retlen, movebuf); - if (ret != -EIO) + if (ret != -EIO) DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went " "away on retry?\n"); } @@ -355,7 +351,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned static u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock) { /* - * This is the part that needs some cleverness applied. + * This is the part that needs some cleverness applied. * For now, I'm doing the minimum applicable to actually * get the thing to work. * Wear-levelling and other clever stuff needs to be implemented @@ -414,7 +410,7 @@ static int nrbits(unsigned int val, int bitcount) } /* - * INFTL_findwriteunit: Return the unit number into which we can write + * INFTL_findwriteunit: Return the unit number into which we can write * for this block. Make it available if it isn't already. */ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) @@ -463,10 +459,10 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) * Invalid block. Don't use it any more. * Must implement. */ - break; + break; } - - if (!silly--) { + + if (!silly--) { printk(KERN_WARNING "INFTL: infinite loop in " "Virtual Unit Chain 0x%x\n", thisVUC); return 0xffff; @@ -482,7 +478,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) /* - * OK. We didn't find one in the existing chain, or there + * OK. We didn't find one in the existing chain, or there * is no existing chain. Allocate a new one. */ writeEUN = INFTL_findfreeblock(inftl, 0); @@ -506,8 +502,8 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) if (writeEUN == BLOCK_NIL) { /* * Ouch. This should never happen - we should - * always be able to make some room somehow. - * If we get here, we've allocated more storage + * always be able to make some room somehow. + * If we get here, we've allocated more storage * space than actual media, or our makefreeblock * routine is missing something. */ @@ -518,7 +514,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) INFTL_dumpVUchains(inftl); #endif return BLOCK_NIL; - } + } } /* @@ -543,7 +539,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) parity |= (nrbits(prev_block, 16) & 0x1) ? 0x2 : 0; parity |= (nrbits(anac, 8) & 0x1) ? 0x4 : 0; parity |= (nrbits(nacs, 8) & 0x1) ? 0x8 : 0; - + oob.u.a.virtualUnitNo = cpu_to_le16(thisVUC); oob.u.a.prevUnitNo = cpu_to_le16(prev_block); oob.u.a.ANAC = anac; @@ -562,7 +558,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) oob.u.b.parityPerField = parity; oob.u.b.discarded = 0xaa; - MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize + + MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize + SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u); inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC]; @@ -602,7 +598,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) "Virtual Unit Chain %d!\n", thisVUC); return; } - + /* * Scan through the Erase Units to determine whether any data is in * each of the 512-byte blocks within the Chain. @@ -642,7 +638,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) "Unit Chain 0x%x\n", thisVUC); return; } - + thisEUN = inftl->PUtable[thisEUN]; } @@ -758,7 +754,7 @@ static int INFTL_deleteblock(struct INFTLrecord *inftl, unsigned block) return 0; } -static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, +static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, char *buffer) { struct INFTLrecord *inftl = (void *)mbd; @@ -893,7 +889,7 @@ extern char inftlmountrev[]; static int __init init_inftl(void) { - printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.18 $, " + printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.19 $, " "inftlmount.c %s\n", inftlmountrev); return register_mtd_blktrans(&inftl_tr); diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index b5dda47395a71db2f3db02601e9722a73fc98edc..43fdc943388241bcceeacd66b410ec15612699d2 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -1,14 +1,14 @@ -/* +/* * inftlmount.c -- INFTL mount code with extensive checks. * * Author: Greg Ungerer (gerg@snapgear.com) * (C) Copyright 2002-2003, Greg Ungerer (gerg@snapgear.com) * * Based heavily on the nftlmount.c code which is: - * Author: Fabrice Bellard (fabrice.bellard@netgem.com) + * Author: Fabrice Bellard (fabrice.bellard@netgem.com) * Copyright (C) 2000 Netgem S.A. * - * $Id: inftlmount.c,v 1.16 2004/11/22 13:50:53 kalev Exp $ + * $Id: inftlmount.c,v 1.18 2005/11/07 11:14:20 gleixner Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -41,7 +41,7 @@ #include #include -char inftlmountrev[]="$Revision: 1.16 $"; +char inftlmountrev[]="$Revision: 1.18 $"; /* * find_boot_record: Find the INFTL Media Header and its Spare copy which @@ -273,7 +273,7 @@ static int find_boot_record(struct INFTLrecord *inftl) inftl->nb_boot_blocks); return -1; } - + inftl->mbd.size = inftl->numvunits * (inftl->EraseSize / SECTORSIZE); @@ -302,7 +302,7 @@ static int find_boot_record(struct INFTLrecord *inftl) inftl->nb_blocks * sizeof(u16)); return -ENOMEM; } - + /* Mark the blocks before INFTL MediaHeader as reserved */ for (i = 0; i < inftl->nb_boot_blocks; i++) inftl->PUtable[i] = BLOCK_RESERVED; @@ -380,7 +380,7 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address, * * Return: 0 when succeed, -1 on error. * - * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? + * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? */ int INFTL_formatblock(struct INFTLrecord *inftl, int block) { @@ -563,7 +563,7 @@ int INFTL_mount(struct INFTLrecord *s) /* Search for INFTL MediaHeader and Spare INFTL Media Header */ if (find_boot_record(s) < 0) { printk(KERN_WARNING "INFTL: could not find valid boot record?\n"); - return -1; + return -ENXIO; } /* Init the logical to physical table */ @@ -574,6 +574,12 @@ int INFTL_mount(struct INFTLrecord *s) /* Temporary buffer to store ANAC numbers. */ ANACtable = kmalloc(s->nb_blocks * sizeof(u8), GFP_KERNEL); + if (!ANACtable) { + printk(KERN_WARNING "INFTL: allocation of ANACtable " + "failed (%zd bytes)\n", + s->nb_blocks * sizeof(u8)); + return -ENOMEM; + } memset(ANACtable, 0, s->nb_blocks); /* @@ -595,7 +601,7 @@ int INFTL_mount(struct INFTLrecord *s) for (chain_length = 0; ; chain_length++) { - if ((chain_length == 0) && + if ((chain_length == 0) && (s->PUtable[block] != BLOCK_NOTEXPLORED)) { /* Nothing to do here, onto next block */ break; @@ -742,7 +748,7 @@ int INFTL_mount(struct INFTLrecord *s) "in virtual chain %d\n", s->PUtable[block], logical_block); s->PUtable[block] = BLOCK_NIL; - + } if (ANACtable[block] != ANAC) { /* diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 44781a83b2e78b79b953d21f60bbf4fe12294466..48638c8097a56b9204bcec9dad9019121b681d40 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -1,5 +1,5 @@ # drivers/mtd/maps/Kconfig -# $Id: Kconfig,v 1.55 2005/07/02 01:53:24 tpoynor Exp $ +# $Id: Kconfig,v 1.61 2005/11/07 11:14:26 gleixner Exp $ menu "Mapping drivers for chip access" depends on MTD!=n @@ -64,9 +64,9 @@ config MTD_SUN_UFLASH tristate "Sun Microsystems userflash support" depends on (SPARC32 || SPARC64) && MTD_CFI help - This provides a 'mapping' driver which supports the way in - which user-programmable flash chips are connected on various - Sun Microsystems boardsets. This driver will require CFI support + This provides a 'mapping' driver which supports the way in + which user-programmable flash chips are connected on various + Sun Microsystems boardsets. This driver will require CFI support in the kernel, so if you did not enable CFI previously, do that now. config MTD_PNC2000 @@ -89,22 +89,22 @@ config MTD_NETSC520 depends on X86 && MTD_CFI && MTD_PARTITIONS help This enables access routines for the flash chips on the AMD NetSc520 - demonstration board. If you have one of these boards and would like + demonstration board. If you have one of these boards and would like to use the flash chips on it, say 'Y'. config MTD_TS5500 tristate "JEDEC Flash device mapped on Technologic Systems TS-5500" - depends on X86 && MTD_JEDECPROBE && MTD_PARTITIONS + depends on ELAN + select MTD_PARTITIONS + select MTD_JEDECPROBE + select MTD_CFI_AMDSTD help This provides a driver for the on-board flash of the Technologic - System's TS-5500 board. The flash is split into 3 partitions + System's TS-5500 board. The 2MB flash is split into 3 partitions which are accessed as separate MTD devices. - mtd0 and mtd2 are the two BIOS drives. Unfortunately the BIOS - uses a proprietary flash translation layer from General Software, - which is not supported (the drives cannot be mounted). You can - create your own file system (jffs for example), but the BIOS - won't be able to boot from it. + mtd0 and mtd2 are the two BIOS drives, which use the resident + flash disk (RFD) flash translation layer. mtd1 allows you to reprogram your BIOS. BE VERY CAREFUL. @@ -212,11 +212,18 @@ config MTD_NETtel Support for flash chips on NETtel/SecureEdge/SnapGear boards. config MTD_ALCHEMY - tristate ' AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support' - depends on MIPS && SOC_AU1X00 + tristate ' AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support' + depends on SOC_AU1X00 help Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards +config MTD_MTX1 + tristate "4G Systems MTX-1 Flash device" + depends on MIPS && MIPS_MTX1 + help + Flash memory access on 4G Systems MTX-1 Board. If you have one of + these boards and would like to use the flash chips on it, say 'Y'. + config MTD_DILNETPC tristate "CFI Flash device mapped on DIL/Net PC" depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT @@ -244,14 +251,14 @@ config MTD_L440GX config MTD_SBC8240 tristate "Flash device on SBC8240" - depends on PPC32 && MTD_JEDECPROBE && 6xx && 8260 + depends on MTD_JEDECPROBE && 8260 help Flash access on the SBC8240 board from Wind River. See config MTD_TQM8XXL tristate "CFI Flash device mapped on TQM8XXL" - depends on MTD_CFI && PPC32 && 8xx && TQM8xxL + depends on MTD_CFI && TQM8xxL help The TQM8xxL PowerPC board has up to two banks of CFI-compliant chips, currently uses AMD one. This 'mapping' driver supports @@ -261,7 +268,7 @@ config MTD_TQM8XXL config MTD_RPXLITE tristate "CFI Flash device mapped on RPX Lite or CLLF" - depends on MTD_CFI && PPC32 && 8xx && (RPXCLASSIC || RPXLITE) + depends on MTD_CFI && (RPXCLASSIC || RPXLITE) help The RPXLite PowerPC board has CFI-compliant chips mapped in a strange sparse mapping. This 'mapping' driver supports that @@ -271,7 +278,7 @@ config MTD_RPXLITE config MTD_MBX860 tristate "System flash on MBX860 board" - depends on MTD_CFI && PPC32 && 8xx && MBX + depends on MTD_CFI && MBX help This enables access routines for the flash chips on the Motorola MBX860 board. If you have one of these boards and would like @@ -279,7 +286,7 @@ config MTD_MBX860 config MTD_DBOX2 tristate "CFI Flash device mapped on D-Box2" - depends on PPC32 && 8xx && DBOX2 && MTD_CFI_INTELSTD && MTD_CFI_INTELEXT && MTD_CFI_AMDSTD + depends on DBOX2 && MTD_CFI_INTELSTD && MTD_CFI_INTELEXT && MTD_CFI_AMDSTD help This enables access routines for the flash chips on the Nokia/Sagem D-Box 2 board. If you have one of these boards and would like to use @@ -287,14 +294,14 @@ config MTD_DBOX2 config MTD_CFI_FLAGADM tristate "CFI Flash device mapping on FlagaDM" - depends on PPC32 && 8xx && MTD_CFI + depends on 8xx && MTD_CFI help Mapping for the Flaga digital module. If you don't have one, ignore this setting. config MTD_BEECH tristate "CFI Flash device mapped on IBM 405LP Beech" - depends on MTD_CFI && PPC32 && 40x && BEECH + depends on MTD_CFI && BEECH help This enables access routines for the flash chips on the IBM 405LP Beech board. If you have one of these boards and would like @@ -302,7 +309,7 @@ config MTD_BEECH config MTD_ARCTIC tristate "CFI Flash device mapped on IBM 405LP Arctic" - depends on MTD_CFI && PPC32 && 40x && ARCTIC2 + depends on MTD_CFI && ARCTIC2 help This enables access routines for the flash chips on the IBM 405LP Arctic board. If you have one of these boards and would like to @@ -310,7 +317,7 @@ config MTD_ARCTIC config MTD_WALNUT tristate "Flash device mapped on IBM 405GP Walnut" - depends on MTD_JEDECPROBE && PPC32 && 40x && WALNUT + depends on MTD_JEDECPROBE && WALNUT help This enables access routines for the flash chips on the IBM 405GP Walnut board. If you have one of these boards and would like to @@ -318,7 +325,7 @@ config MTD_WALNUT config MTD_EBONY tristate "Flash devices mapped on IBM 440GP Ebony" - depends on MTD_JEDECPROBE && PPC32 && 44x && EBONY + depends on MTD_JEDECPROBE && EBONY help This enables access routines for the flash chips on the IBM 440GP Ebony board. If you have one of these boards and would like to @@ -326,7 +333,7 @@ config MTD_EBONY config MTD_OCOTEA tristate "Flash devices mapped on IBM 440GX Ocotea" - depends on MTD_CFI && PPC32 && 44x && OCOTEA + depends on MTD_CFI && OCOTEA help This enables access routines for the flash chips on the IBM 440GX Ocotea board. If you have one of these boards and would like to @@ -334,12 +341,20 @@ config MTD_OCOTEA config MTD_REDWOOD tristate "CFI Flash devices mapped on IBM Redwood" - depends on MTD_CFI && PPC32 && 4xx && 40x && ( REDWOOD_4 || REDWOOD_5 || REDWOOD_6 ) + depends on MTD_CFI && ( REDWOOD_4 || REDWOOD_5 || REDWOOD_6 ) help This enables access routines for the flash chips on the IBM Redwood board. If you have one of these boards and would like to use the flash chips on it, say 'Y'. +config MTD_TQM834x + tristate "Flash device mapped on TQ Components TQM834x Boards" + depends on MTD_CFI && TQM834x + help + This enables access routines for the flash chips on the + TQ Components TQM834x boards. If you have one of these boards + and would like to use the flash chips on it, say 'Y'. + config MTD_CSTM_MIPS_IXX tristate "Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board" depends on MIPS && MTD_CFI && MTD_JEDECPROBE && MTD_PARTITIONS @@ -362,8 +377,8 @@ config MTD_CSTM_MIPS_IXX_START default "0x8000000" help This is the physical memory location that the MTD driver will - use for the flash chips on your particular target board. - Refer to the memory map which should hopefully be in the + use for the flash chips on your particular target board. + Refer to the memory map which should hopefully be in the documentation for your board. config MTD_CSTM_MIPS_IXX_LEN @@ -371,7 +386,7 @@ config MTD_CSTM_MIPS_IXX_LEN depends on MTD_CSTM_MIPS_IXX default "0x4000000" help - This is the total length that the MTD driver will use for the + This is the total length that the MTD driver will use for the flash chips on your particular board. Refer to the memory map which should hopefully be in the documentation for your board. @@ -405,14 +420,14 @@ config MTD_ARM_INTEGRATOR config MTD_CDB89712 tristate "Cirrus CDB89712 evaluation board mappings" - depends on ARM && MTD_CFI && ARCH_CDB89712 + depends on MTD_CFI && ARCH_CDB89712 help This enables access to the flash or ROM chips on the CDB89712 board. If you have such a board, say 'Y'. config MTD_SA1100 tristate "CFI Flash device mapped on StrongARM SA11x0" - depends on ARM && MTD_CFI && ARCH_SA1100 && MTD_PARTITIONS + depends on MTD_CFI && ARCH_SA1100 && MTD_PARTITIONS help This enables access to the flash chips on most platforms based on the SA1100 and SA1110, including the Assabet and the Compaq iPAQ. @@ -420,13 +435,13 @@ config MTD_SA1100 config MTD_IPAQ tristate "CFI Flash device mapped on Compaq/HP iPAQ" - depends on ARM && IPAQ_HANDHELD && MTD_CFI + depends on IPAQ_HANDHELD && MTD_CFI help This provides a driver for the on-board flash of the iPAQ. config MTD_DC21285 tristate "CFI Flash device mapped on DC21285 Footbridge" - depends on ARM && MTD_CFI && ARCH_FOOTBRIDGE && MTD_COMPLEX_MAPPINGS + depends on MTD_CFI && ARCH_FOOTBRIDGE && MTD_COMPLEX_MAPPINGS help This provides a driver for the flash accessed using Intel's 21285 bridge used with Intel's StrongARM processors. More info at @@ -434,33 +449,33 @@ config MTD_DC21285 config MTD_IQ80310 tristate "CFI Flash device mapped on the XScale IQ80310 board" - depends on ARM && MTD_CFI && ARCH_IQ80310 + depends on MTD_CFI && ARCH_IQ80310 help This enables access routines for the flash chips on the Intel XScale - IQ80310 evaluation board. If you have one of these boards and would + IQ80310 evaluation board. If you have one of these boards and would like to use the flash chips on it, say 'Y'. config MTD_IXP4XX tristate "CFI Flash device mapped on Intel IXP4xx based systems" - depends on ARM && MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP4XX + depends on MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP4XX help - This enables MTD access to flash devices on platforms based + This enables MTD access to flash devices on platforms based on Intel's IXP4xx family of network processors such as the IXDP425 and Coyote. If you have an IXP4xx based board and would like to use the flash chips on it, say 'Y'. config MTD_IXP2000 tristate "CFI Flash device mapped on Intel IXP2000 based systems" - depends on ARM && MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP2000 + depends on MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP2000 help - This enables MTD access to flash devices on platforms based + This enables MTD access to flash devices on platforms based on Intel's IXP2000 family of network processors such as the IXDP425 and Coyote. If you have an IXP2000 based board and would like to use the flash chips on it, say 'Y'. config MTD_EPXA10DB tristate "CFI Flash device mapped on Epxa10db" - depends on ARM && MTD_CFI && MTD_PARTITIONS && ARCH_CAMELOT + depends on MTD_CFI && MTD_PARTITIONS && ARCH_CAMELOT help This enables support for the flash devices on the Altera Excalibur XA10 Development Board. If you are building a kernel @@ -468,21 +483,21 @@ config MTD_EPXA10DB config MTD_FORTUNET tristate "CFI Flash device mapped on the FortuNet board" - depends on ARM && MTD_CFI && MTD_PARTITIONS && SA1100_FORTUNET + depends on MTD_CFI && MTD_PARTITIONS && SA1100_FORTUNET help This enables access to the Flash on the FortuNet board. If you have such a board, say 'Y'. config MTD_AUTCPU12 tristate "NV-RAM mapping AUTCPU12 board" - depends on ARM && ARCH_AUTCPU12 + depends on ARCH_AUTCPU12 help This enables access to the NV-RAM on autronix autcpu12 board. If you have such a board, say 'Y'. config MTD_EDB7312 tristate "CFI Flash device mapped on EDB7312" - depends on ARM && MTD_CFI + depends on ARCH_EDB7312 && MTD_CFI help This enables access to the CFI Flash on the Cogent EDB7312 board. If you have such a board, say 'Y' here. @@ -496,7 +511,7 @@ config MTD_IMPA7 config MTD_CEIVA tristate "JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame" - depends on ARM && MTD_JEDECPROBE && ARCH_CEIVA + depends on MTD_JEDECPROBE && ARCH_CEIVA help This enables access to the flash chips on the Ceiva/Polaroid PhotoMax Digital Picture Frame. @@ -504,25 +519,31 @@ config MTD_CEIVA config MTD_NOR_TOTO tristate "NOR Flash device on TOTO board" - depends on ARM && ARCH_OMAP && OMAP_TOTO + depends on ARCH_OMAP && OMAP_TOTO help This enables access to the NOR flash on the Texas Instruments TOTO board. config MTD_H720X tristate "Hynix evaluation board mappings" - depends on ARM && MTD_CFI && ( ARCH_H7201 || ARCH_H7202 ) + depends on MTD_CFI && ( ARCH_H7201 || ARCH_H7202 ) help This enables access to the flash chips on the Hynix evaluation boards. If you have such a board, say 'Y'. config MTD_MPC1211 tristate "CFI Flash device mapped on Interface MPC-1211" - depends on SUPERH && SH_MPC1211 && MTD_CFI + depends on SH_MPC1211 && MTD_CFI help This enables access to the flash chips on the Interface MPC-1211(CTP/PCI/MPC-SH02). If you have such a board, say 'Y'. +config MTD_PQ2FADS + tristate "JEDEC flash SIMM mapped on PQ2FADS and 8272ADS boards" + depends on (ADS8272 || PQ2FADS) && MTD_PARTITIONS && MTD_JEDECPROBE && MTD_PHYSMAP && MTD_CFI_GEOMETRY && MTD_CFI_INTELEXT + help + This enables access to flash SIMM on PQ2FADS-like boards + config MTD_OMAP_NOR tristate "TI OMAP board mappings" depends on MTD_CFI && ARCH_OMAP diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 7bcbc49e329f24c94ec7d1ee714c29e8ecab1a5f..7d9e940a1dcd7e5ddc20621bcae3ece4f5f0739e 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -1,7 +1,7 @@ # # linux/drivers/maps/Makefile # -# $Id: Makefile.common,v 1.30 2005/07/02 01:53:24 tpoynor Exp $ +# $Id: Makefile.common,v 1.34 2005/11/07 11:14:26 gleixner Exp $ ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y) obj-$(CONFIG_MTD) += map_funcs.o @@ -26,7 +26,7 @@ obj-$(CONFIG_MTD_MAINSTONE) += mainstone-flash.o obj-$(CONFIG_MTD_MBX860) += mbx860.o obj-$(CONFIG_MTD_CEIVA) += ceiva.o obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o -obj-$(CONFIG_MTD_PHYSMAP) += physmap.o +obj-$(CONFIG_MTD_PHYSMAP) += physmap.o obj-$(CONFIG_MTD_PNC2000) += pnc2000.o obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o @@ -70,3 +70,6 @@ obj-$(CONFIG_MTD_DMV182) += dmv182.o obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o +obj-$(CONFIG_MTD_PQ2FADS) += pq2fads.o +obj-$(CONFIG_MTD_MTX1) += mtx-1_flash.o +obj-$(CONFIG_MTD_TQM834x) += tqm834x.o diff --git a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c index 27fd2a3c3b600721264419a81110c440b665d25b..a57791a6ce402a754e32f6dec0b40523ffe11eda 100644 --- a/drivers/mtd/maps/alchemy-flash.c +++ b/drivers/mtd/maps/alchemy-flash.c @@ -1,10 +1,10 @@ /* * Flash memory access on AMD Alchemy evaluation boards - * - * $Id: alchemy-flash.c,v 1.1 2005/02/27 21:50:21 ppopov Exp $ + * + * $Id: alchemy-flash.c,v 1.2 2005/11/07 11:14:26 gleixner Exp $ * * (C) 2003, 2004 Pete Popov - * + * */ #include @@ -22,7 +22,7 @@ #ifdef DEBUG_RW #define DBG(x...) printk(x) #else -#define DBG(x...) +#define DBG(x...) #endif #ifdef CONFIG_MIPS_PB1000 @@ -136,7 +136,7 @@ int __init alchemy_mtd_init(void) int nb_parts = 0; unsigned long window_addr; unsigned long window_size; - + /* Default flash buswidth */ alchemy_map.bankwidth = BOARD_FLASH_WIDTH; @@ -161,7 +161,7 @@ int __init alchemy_mtd_init(void) * Now let's probe for the actual flash. Do it here since * specific machine settings might have been set above. */ - printk(KERN_NOTICE BOARD_MAP_NAME ": probing %d-bit flash bus\n", + printk(KERN_NOTICE BOARD_MAP_NAME ": probing %d-bit flash bus\n", alchemy_map.bankwidth*8); alchemy_map.virt = ioremap(window_addr, window_size); mymtd = do_map_probe("cfi_probe", &alchemy_map); diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c index e8a900a77685e4bb024a3c510a2b3e5dc3d11c1b..c350878d4592978ffece3fe1b1e97cb4caae5187 100644 --- a/drivers/mtd/maps/amd76xrom.c +++ b/drivers/mtd/maps/amd76xrom.c @@ -2,7 +2,7 @@ * amd76xrom.c * * Normal mappings of chips in physical memory - * $Id: amd76xrom.c,v 1.20 2005/03/18 14:04:35 gleixner Exp $ + * $Id: amd76xrom.c,v 1.21 2005/11/07 11:14:26 gleixner Exp $ */ #include @@ -70,7 +70,7 @@ static void amd76xrom_cleanup(struct amd76xrom_window *window) list_del(&map->list); kfree(map); } - if (window->rsrc.parent) + if (window->rsrc.parent) release_resource(&window->rsrc); if (window->virt) { @@ -107,7 +107,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, window->phys = 0xffff0000; /* 64KiB */ } window->size = 0xffffffffUL - window->phys + 1UL; - + /* * Try to reserve the window mem region. If this fails then * it is likely due to a fragment of the window being @@ -138,7 +138,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, /* Enable writes through the rom window */ pci_read_config_byte(pdev, 0x40, &byte); pci_write_config_byte(pdev, 0x40, byte | 1); - + /* FIXME handle registers 0x80 - 0x8C the bios region locks */ /* For write accesses caches are useless */ @@ -186,7 +186,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, MOD_NAME, map->map.phys); /* There is no generic VPP support */ - for(map->map.bankwidth = 32; map->map.bankwidth; + for(map->map.bankwidth = 32; map->map.bankwidth; map->map.bankwidth >>= 1) { char **probe_type; @@ -239,7 +239,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, for(i = 0; i < cfi->numchips; i++) { cfi->chips[i].start += offset; } - + /* Now that the mtd devices is complete claim and export it */ map->mtd->owner = THIS_MODULE; if (add_mtd_device(map->mtd)) { @@ -259,9 +259,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, out: /* Free any left over map structures */ - if (map) { - kfree(map); - } + kfree(map); /* See if I have any map structures */ if (list_empty(&window->maps)) { amd76xrom_cleanup(window); @@ -279,9 +277,9 @@ static void __devexit amd76xrom_remove_one (struct pci_dev *pdev) } static struct pci_device_id amd76xrom_pci_tbl[] = { - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, + { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440, + { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_AMD, 0x7468 }, /* amd8111 support */ { 0, } diff --git a/drivers/mtd/maps/arctic-mtd.c b/drivers/mtd/maps/arctic-mtd.c index 777276fd0e151ff04f068a066d628f57b1050855..d95ae582fbe9a4cc275919153fac944e56e4b664 100644 --- a/drivers/mtd/maps/arctic-mtd.c +++ b/drivers/mtd/maps/arctic-mtd.c @@ -1,7 +1,7 @@ /* - * $Id: arctic-mtd.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $ - * - * drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for + * $Id: arctic-mtd.c,v 1.14 2005/11/07 11:14:26 gleixner Exp $ + * + * drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for * IBM 405LP Arctic boards. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/mtd/maps/autcpu12-nvram.c b/drivers/mtd/maps/autcpu12-nvram.c index cf362ccc3c8ed57c029dd8dbd8aaadbb69a5a451..7ed3424dd959bb2aa3ce42af93a4dc25ad74f25f 100644 --- a/drivers/mtd/maps/autcpu12-nvram.c +++ b/drivers/mtd/maps/autcpu12-nvram.c @@ -1,8 +1,8 @@ /* - * NV-RAM memory access on autcpu12 + * NV-RAM memory access on autcpu12 * (C) 2002 Thomas Gleixner (gleixner@autronix.de) * - * $Id: autcpu12-nvram.c,v 1.8 2004/11/04 13:24:14 gleixner Exp $ + * $Id: autcpu12-nvram.c,v 1.9 2005/11/07 11:14:26 gleixner Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -55,10 +55,10 @@ static int __init init_autcpu12_sram (void) } simple_map_init(&autcpu_sram_map); - /* - * Check for 32K/128K - * read ofs 0 - * read ofs 0x10000 + /* + * Check for 32K/128K + * read ofs 0 + * read ofs 0x10000 * Write complement to ofs 0x100000 * Read and check result on ofs 0x0 * Restore contents @@ -66,7 +66,7 @@ static int __init init_autcpu12_sram (void) save0 = map_read32(&autcpu12_sram_map,0); save1 = map_read32(&autcpu12_sram_map,0x10000); map_write32(&autcpu12_sram_map,~save0,0x10000); - /* if we find this pattern on 0x0, we have 32K size + /* if we find this pattern on 0x0, we have 32K size * restore contents and exit */ if ( map_read32(&autcpu12_sram_map,0) != save0) { @@ -89,7 +89,7 @@ static int __init init_autcpu12_sram (void) sram_mtd->owner = THIS_MODULE; sram_mtd->erasesize = 16; - + if (add_mtd_device(sram_mtd)) { printk("NV-RAM device addition failed\n"); err = -ENOMEM; @@ -97,7 +97,7 @@ static int __init init_autcpu12_sram (void) } printk("NV-RAM device size %ldKiB registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K); - + return 0; out_probe: diff --git a/drivers/mtd/maps/bast-flash.c b/drivers/mtd/maps/bast-flash.c index bfe994e59265d57772da814b0b08eab199e2e793..b7858eb935347acb767d2961de8896027b4b1674 100644 --- a/drivers/mtd/maps/bast-flash.c +++ b/drivers/mtd/maps/bast-flash.c @@ -9,7 +9,7 @@ * 20-Sep-2004 BJD Initial version * 17-Jan-2005 BJD Add whole device if no partitions found * - * $Id: bast-flash.c,v 1.2 2005/01/18 11:13:47 bjd Exp $ + * $Id: bast-flash.c,v 1.5 2005/11/07 11:14:26 gleixner Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -75,7 +75,7 @@ static void bast_flash_setrw(int to) local_irq_save(flags); val = __raw_readb(BAST_VA_CTRL3); - + if (to) val |= BAST_CPLD_CTRL3_ROMWEN; else @@ -93,7 +93,7 @@ static int bast_flash_remove(struct device *dev) dev_set_drvdata(dev, NULL); - if (info == NULL) + if (info == NULL) return 0; if (info->map.virt != NULL) @@ -104,14 +104,13 @@ static int bast_flash_remove(struct device *dev) map_destroy(info->mtd); } - if (info->partitions) - kfree(info->partitions); + kfree(info->partitions); if (info->area) { release_resource(info->area); kfree(info->area); } - + kfree(info); return 0; @@ -138,15 +137,15 @@ static int bast_flash_probe(struct device *dev) info->map.phys = res->start; info->map.size = res->end - res->start + 1; - info->map.name = dev->bus_id; + info->map.name = dev->bus_id; info->map.bankwidth = 2; - + if (info->map.size > AREA_MAXSIZE) info->map.size = AREA_MAXSIZE; pr_debug("%s: area %08lx, size %ld\n", __FUNCTION__, info->map.phys, info->map.size); - + info->area = request_mem_region(res->start, info->map.size, pdev->name); if (info->area == NULL) { @@ -163,7 +162,7 @@ static int bast_flash_probe(struct device *dev) err = -EIO; goto exit_error; } - + simple_map_init(&info->map); /* enable the write to the flash area */ @@ -188,7 +187,7 @@ static int bast_flash_probe(struct device *dev) err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0); if (err > 0) { err = add_mtd_partitions(info->mtd, info->partitions, err); - if (err) + if (err) printk(KERN_ERR PFX "cannot add/parse partitions\n"); } else { err = add_mtd_device(info->mtd); @@ -206,6 +205,7 @@ static int bast_flash_probe(struct device *dev) static struct device_driver bast_flash_driver = { .name = "bast-nor", + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = bast_flash_probe, .remove = bast_flash_remove, diff --git a/drivers/mtd/maps/beech-mtd.c b/drivers/mtd/maps/beech-mtd.c index 5e79c9d5da2b3a4537bbb516c2c59127dc7b12c3..5df7361d14079e2d8aae78ea02b76ac59555d038 100644 --- a/drivers/mtd/maps/beech-mtd.c +++ b/drivers/mtd/maps/beech-mtd.c @@ -1,7 +1,7 @@ /* - * $Id: beech-mtd.c,v 1.10 2004/11/04 13:24:14 gleixner Exp $ - * - * drivers/mtd/maps/beech-mtd.c MTD mappings and partition tables for + * $Id: beech-mtd.c,v 1.11 2005/11/07 11:14:26 gleixner Exp $ + * + * drivers/mtd/maps/beech-mtd.c MTD mappings and partition tables for * IBM 405LP Beech boards. * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/mtd/maps/cdb89712.c b/drivers/mtd/maps/cdb89712.c index ab15dac2f9360168ab3893499c3ef8ca0f1a103a..9f17bb6c5a9d388714c8822ea412230d918b6b38 100644 --- a/drivers/mtd/maps/cdb89712.c +++ b/drivers/mtd/maps/cdb89712.c @@ -1,7 +1,7 @@ /* * Flash on Cirrus CDB89712 * - * $Id: cdb89712.c,v 1.10 2004/11/04 13:24:14 gleixner Exp $ + * $Id: cdb89712.c,v 1.11 2005/11/07 11:14:26 gleixner Exp $ */ #include @@ -37,13 +37,13 @@ struct resource cdb89712_flash_resource = { static int __init init_cdb89712_flash (void) { int err; - + if (request_resource (&ioport_resource, &cdb89712_flash_resource)) { printk(KERN_NOTICE "Failed to reserve Cdb89712 FLASH space\n"); err = -EBUSY; goto out; } - + cdb89712_flash_map.virt = ioremap(FLASH_START, FLASH_SIZE); if (!cdb89712_flash_map.virt) { printk(KERN_NOTICE "Failed to ioremap Cdb89712 FLASH space\n"); @@ -64,13 +64,13 @@ static int __init init_cdb89712_flash (void) } flash_mtd->owner = THIS_MODULE; - + if (add_mtd_device(flash_mtd)) { printk("FLASH device addition failed\n"); err = -ENOMEM; goto out_probe; } - + return 0; out_probe: @@ -107,13 +107,13 @@ struct resource cdb89712_sram_resource = { static int __init init_cdb89712_sram (void) { int err; - + if (request_resource (&ioport_resource, &cdb89712_sram_resource)) { printk(KERN_NOTICE "Failed to reserve Cdb89712 SRAM space\n"); err = -EBUSY; goto out; } - + cdb89712_sram_map.virt = ioremap(SRAM_START, SRAM_SIZE); if (!cdb89712_sram_map.virt) { printk(KERN_NOTICE "Failed to ioremap Cdb89712 SRAM space\n"); @@ -130,13 +130,13 @@ static int __init init_cdb89712_sram (void) sram_mtd->owner = THIS_MODULE; sram_mtd->erasesize = 16; - + if (add_mtd_device(sram_mtd)) { printk("SRAM device addition failed\n"); err = -ENOMEM; goto out_probe; } - + return 0; out_probe: @@ -175,13 +175,13 @@ struct resource cdb89712_bootrom_resource = { static int __init init_cdb89712_bootrom (void) { int err; - + if (request_resource (&ioport_resource, &cdb89712_bootrom_resource)) { printk(KERN_NOTICE "Failed to reserve Cdb89712 BOOTROM space\n"); err = -EBUSY; goto out; } - + cdb89712_bootrom_map.virt = ioremap(BOOTROM_START, BOOTROM_SIZE); if (!cdb89712_bootrom_map.virt) { printk(KERN_NOTICE "Failed to ioremap Cdb89712 BootROM space\n"); @@ -198,13 +198,13 @@ static int __init init_cdb89712_bootrom (void) bootrom_mtd->owner = THIS_MODULE; bootrom_mtd->erasesize = 0x10000; - + if (add_mtd_device(bootrom_mtd)) { printk("BootROM device addition failed\n"); err = -ENOMEM; goto out_probe; } - + return 0; out_probe: @@ -225,16 +225,16 @@ static int __init init_cdb89712_bootrom (void) static int __init init_cdb89712_maps(void) { - printk(KERN_INFO "Cirrus CDB89712 MTD mappings:\n Flash 0x%x at 0x%x\n SRAM 0x%x at 0x%x\n BootROM 0x%x at 0x%x\n", + printk(KERN_INFO "Cirrus CDB89712 MTD mappings:\n Flash 0x%x at 0x%x\n SRAM 0x%x at 0x%x\n BootROM 0x%x at 0x%x\n", FLASH_SIZE, FLASH_START, SRAM_SIZE, SRAM_START, BOOTROM_SIZE, BOOTROM_START); init_cdb89712_flash(); init_cdb89712_sram(); init_cdb89712_bootrom(); - + return 0; } - + static void __exit cleanup_cdb89712_maps(void) { @@ -244,7 +244,7 @@ static void __exit cleanup_cdb89712_maps(void) iounmap((void *)cdb89712_sram_map.virt); release_resource (&cdb89712_sram_resource); } - + if (flash_mtd) { del_mtd_device(flash_mtd); map_destroy(flash_mtd); diff --git a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c index c68b31dc7e6d4979c363a8ac1e32bb0abba09f5b..5a95ab370a970cf6150d857de460a02bfeba29df 100644 --- a/drivers/mtd/maps/ceiva.c +++ b/drivers/mtd/maps/ceiva.c @@ -313,8 +313,7 @@ static void __init clps_locate_partitions(struct mtd_info *mtd) static void __exit clps_destroy_partitions(void) { - if (parsed_parts) - kfree(parsed_parts); + kfree(parsed_parts); } static struct mtd_info *mymtd; diff --git a/drivers/mtd/maps/cfi_flagadm.c b/drivers/mtd/maps/cfi_flagadm.c index f72e4f894b321efeb2a457d59c8be45733abc28f..6a8c0415bde87b6c7432f5307d84e8a301f0990e 100644 --- a/drivers/mtd/maps/cfi_flagadm.c +++ b/drivers/mtd/maps/cfi_flagadm.c @@ -1,8 +1,8 @@ /* * Copyright © 2001 Flaga hf. Medical Devices, Kári Davíðsson * - * $Id: cfi_flagadm.c,v 1.14 2004/11/04 13:24:14 gleixner Exp $ - * + * $Id: cfi_flagadm.c,v 1.15 2005/11/07 11:14:26 gleixner Exp $ + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your @@ -42,7 +42,7 @@ */ #define FLASH_PHYS_ADDR 0x40000000 -#define FLASH_SIZE 0x400000 +#define FLASH_SIZE 0x400000 #define FLASH_PARTITION0_ADDR 0x00000000 #define FLASH_PARTITION0_SIZE 0x00020000 @@ -79,7 +79,7 @@ struct mtd_partition flagadm_parts[] = { .offset = FLASH_PARTITION2_ADDR, .size = FLASH_PARTITION2_SIZE }, - { + { .name = "Persistant storage", .offset = FLASH_PARTITION3_ADDR, .size = FLASH_PARTITION3_SIZE @@ -91,10 +91,10 @@ struct mtd_partition flagadm_parts[] = { static struct mtd_info *mymtd; int __init init_flagadm(void) -{ +{ printk(KERN_NOTICE "FlagaDM flash device: %x at %x\n", FLASH_SIZE, FLASH_PHYS_ADDR); - + flagadm_map.phys = FLASH_PHYS_ADDR; flagadm_map.virt = ioremap(FLASH_PHYS_ADDR, FLASH_SIZE); diff --git a/drivers/mtd/maps/cstm_mips_ixx.c b/drivers/mtd/maps/cstm_mips_ixx.c index ae9252fbf1760461f05217aa3d33adca8dba78b7..a370953c1513a2a6c1a24a9f551d7300ea52b47b 100644 --- a/drivers/mtd/maps/cstm_mips_ixx.c +++ b/drivers/mtd/maps/cstm_mips_ixx.c @@ -1,10 +1,10 @@ /* - * $Id: cstm_mips_ixx.c,v 1.12 2004/11/04 13:24:14 gleixner Exp $ + * $Id: cstm_mips_ixx.c,v 1.14 2005/11/07 11:14:26 gleixner Exp $ * * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions. * Config with both CFI and JEDEC device support. * - * Basically physmap.c with the addition of partitions and + * Basically physmap.c with the addition of partitions and * an array of mapping info to accomodate more than one flash type per board. * * Copyright 2000 MontaVista Software Inc. @@ -69,7 +69,7 @@ void cstm_mips_ixx_set_vpp(struct map_info *map,int vpp) __u16 data; __u8 data1; static u8 first = 1; - + // Set GPIO port B pin3 to high data = *(__u16 *)(CC_GPBCR); data = (data & 0xff0f) | 0x0040; @@ -85,7 +85,7 @@ void cstm_mips_ixx_set_vpp(struct map_info *map,int vpp) } else { if (!--vpp_count) { __u16 data; - + // Set GPIO port B pin3 to high data = *(__u16 *)(CC_GPBCR); data = (data & 0xff3f) | 0x0040; @@ -109,8 +109,8 @@ struct cstm_mips_ixx_info { }; #if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) -#define PHYSMAP_NUMBER 1 // number of board desc structs needed, one per contiguous flash type -const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] = +#define PHYSMAP_NUMBER 1 // number of board desc structs needed, one per contiguous flash type +const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] = { { // 28F128J3A in 2x16 configuration "big flash", // name @@ -131,10 +131,10 @@ static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP }, }; #else /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */ -#define PHYSMAP_NUMBER 1 // number of board desc structs needed, one per contiguous flash type -const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] = +#define PHYSMAP_NUMBER 1 // number of board desc structs needed, one per contiguous flash type +const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] = { - { + { "MTD flash", // name CONFIG_MTD_CSTM_MIPS_IXX_START, // window_addr CONFIG_MTD_CSTM_MIPS_IXX_LEN, // window_size @@ -144,7 +144,7 @@ const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] = }; static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = { -{ +{ { .name = "main partition", .size = CONFIG_MTD_CSTM_MIPS_IXX_LEN, @@ -165,7 +165,7 @@ int __init init_cstm_mips_ixx(void) /* Initialize mapping */ for (i=0;iowner = THIS_MODULE; /* Create MTD devices for each partition. */ add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS); - + return 0; } diff --git a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c index e5b74169fde621167b96aa47cb127f7b098296a8..701620b6baede850569e5516a1d2683a86323d6f 100644 --- a/drivers/mtd/maps/dc21285.c +++ b/drivers/mtd/maps/dc21285.c @@ -4,8 +4,8 @@ * (C) 2000 Nicolas Pitre * * This code is GPL - * - * $Id: dc21285.c,v 1.22 2004/11/01 13:39:21 rmk Exp $ + * + * $Id: dc21285.c,v 1.24 2005/11/07 11:14:26 gleixner Exp $ */ #include #include @@ -27,9 +27,9 @@ static struct mtd_info *dc21285_mtd; #ifdef CONFIG_ARCH_NETWINDER -/* +/* * This is really ugly, but it seams to be the only - * realiable way to do it, as the cpld state machine + * realiable way to do it, as the cpld state machine * is unpredictible. So we have a 25us penalty per * write access. */ @@ -150,7 +150,7 @@ static struct map_info dc21285_map = { static struct mtd_partition *dc21285_parts; static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; #endif - + static int __init init_dc21285(void) { @@ -160,20 +160,20 @@ static int __init init_dc21285(void) /* Determine bankwidth */ switch (*CSR_SA110_CNTL & (3<<14)) { - case SA110_CNTL_ROMWIDTH_8: + case SA110_CNTL_ROMWIDTH_8: dc21285_map.bankwidth = 1; dc21285_map.read = dc21285_read8; dc21285_map.write = dc21285_write8; dc21285_map.copy_to = dc21285_copy_to_8; break; - case SA110_CNTL_ROMWIDTH_16: - dc21285_map.bankwidth = 2; + case SA110_CNTL_ROMWIDTH_16: + dc21285_map.bankwidth = 2; dc21285_map.read = dc21285_read16; dc21285_map.write = dc21285_write16; dc21285_map.copy_to = dc21285_copy_to_16; break; - case SA110_CNTL_ROMWIDTH_32: - dc21285_map.bankwidth = 4; + case SA110_CNTL_ROMWIDTH_32: + dc21285_map.bankwidth = 4; dc21285_map.read = dc21285_read32; dc21285_map.write = dc21285_write32; dc21285_map.copy_to = dc21285_copy_to_32; @@ -201,20 +201,20 @@ static int __init init_dc21285(void) if (!dc21285_mtd) { iounmap(dc21285_map.virt); return -ENXIO; - } - + } + dc21285_mtd->owner = THIS_MODULE; #ifdef CONFIG_MTD_PARTITIONS nrparts = parse_mtd_partitions(dc21285_mtd, probes, &dc21285_parts, 0); if (nrparts > 0) add_mtd_partitions(dc21285_mtd, dc21285_parts, nrparts); - else -#endif + else +#endif add_mtd_device(dc21285_mtd); - + if(machine_is_ebsa285()) { - /* + /* * Flash timing is determined with bits 19-16 of the * CSR_SA110_CNTL. The value is the number of wait cycles, or * 0 for 16 cycles (the default). Cycles are 20 ns. @@ -227,7 +227,7 @@ static int __init init_dc21285(void) /* tristate time */ *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24)); } - + return 0; } diff --git a/drivers/mtd/maps/dilnetpc.c b/drivers/mtd/maps/dilnetpc.c index f99519692cb7815d369577c0c54ede59e7332f1f..b51c757817d819c3cc4352ed773df591a905222d 100644 --- a/drivers/mtd/maps/dilnetpc.c +++ b/drivers/mtd/maps/dilnetpc.c @@ -14,7 +14,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: dilnetpc.c,v 1.17 2004/11/28 09:40:39 dwmw2 Exp $ + * $Id: dilnetpc.c,v 1.20 2005/11/07 11:14:26 gleixner Exp $ * * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems * featuring the AMD Elan SC410 processor. There are two variants of this @@ -272,13 +272,13 @@ static struct map_info dnpc_map = { static struct mtd_partition partition_info[]= { - { - .name = "ADNP boot", - .offset = 0, + { + .name = "ADNP boot", + .offset = 0, .size = 0xf0000, }, - { - .name = "ADNP system BIOS", + { + .name = "ADNP system BIOS", .offset = MTDPART_OFS_NXTBLK, .size = 0x10000, #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED @@ -291,7 +291,7 @@ static struct mtd_partition partition_info[]= .size = 0x2f0000, }, { - .name = "ADNP system BIOS entry", + .name = "ADNP system BIOS entry", .offset = MTDPART_OFS_NXTBLK, .size = MTDPART_SIZ_FULL, #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED @@ -325,9 +325,9 @@ static struct mtd_info *merged_mtd; static struct mtd_partition higlvl_partition_info[]= { - { - .name = "ADNP boot block", - .offset = 0, + { + .name = "ADNP boot block", + .offset = 0, .size = CONFIG_MTD_DILNETPC_BOOTSIZE, }, { @@ -335,8 +335,8 @@ static struct mtd_partition higlvl_partition_info[]= .offset = MTDPART_OFS_NXTBLK, .size = ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000, }, - { - .name = "ADNP system BIOS + BIOS Entry", + { + .name = "ADNP system BIOS + BIOS Entry", .offset = MTDPART_OFS_NXTBLK, .size = MTDPART_SIZ_FULL, #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED @@ -371,7 +371,7 @@ static int __init init_dnpc(void) /* ** determine hardware (DNP/ADNP/invalid) - */ + */ if((is_dnp = dnp_adnp_probe()) < 0) return -ENXIO; @@ -397,13 +397,13 @@ static int __init init_dnpc(void) ++dnpc_map.name; for(i = 0; i < NUM_PARTITIONS; i++) ++partition_info[i].name; - higlvl_partition_info[1].size = DNP_WINDOW_SIZE - + higlvl_partition_info[1].size = DNP_WINDOW_SIZE - CONFIG_MTD_DILNETPC_BOOTSIZE - 0x20000; for(i = 0; i < NUM_HIGHLVL_PARTITIONS; i++) ++higlvl_partition_info[i].name; } - printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n", + printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n", is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.phys); dnpc_map.virt = ioremap_nocache(dnpc_map.phys, dnpc_map.size); @@ -436,7 +436,7 @@ static int __init init_dnpc(void) iounmap(dnpc_map.virt); return -ENXIO; } - + mymtd->owner = THIS_MODULE; /* diff --git a/drivers/mtd/maps/dmv182.c b/drivers/mtd/maps/dmv182.c index b9bc63503e268c6f0c308215ca5e9119d24fa70c..b993ac01a9a5f8b10b6048e1e9ab75454cf3cddf 100644 --- a/drivers/mtd/maps/dmv182.c +++ b/drivers/mtd/maps/dmv182.c @@ -1,10 +1,10 @@ /* * drivers/mtd/maps/svme182.c - * + * * Flash map driver for the Dy4 SVME182 board - * - * $Id: dmv182.c,v 1.5 2004/11/04 13:24:14 gleixner Exp $ + * + * $Id: dmv182.c,v 1.6 2005/11/07 11:14:26 gleixner Exp $ * * Copyright 2003-2004, TimeSys Corporation * @@ -104,7 +104,7 @@ static int __init init_svme182(void) partitions = svme182_partitions; svme182_map.virt = ioremap(FLASH_BASE_ADDR, svme182_map.size); - + if (svme182_map.virt == 0) { printk("Failed to ioremap FLASH memory area.\n"); return -EIO; diff --git a/drivers/mtd/maps/ebony.c b/drivers/mtd/maps/ebony.c index b9d9cf4854b62e5f17abdc9b0f5597a5b1ea19f0..c0daf58357cacaba92fcf0550bac25d84e286eaf 100644 --- a/drivers/mtd/maps/ebony.c +++ b/drivers/mtd/maps/ebony.c @@ -1,6 +1,6 @@ /* - * $Id: ebony.c,v 1.15 2004/12/09 18:39:54 holindho Exp $ - * + * $Id: ebony.c,v 1.16 2005/11/07 11:14:26 gleixner Exp $ + * * Mapping for Ebony user flash * * Matt Porter @@ -85,7 +85,7 @@ int __init init_ebony(void) small_flash_base = EBONY_SMALL_FLASH_LOW2; else small_flash_base = EBONY_SMALL_FLASH_LOW1; - + if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) && !EBONY_ONBRD_FLASH_EN(fpga0_reg)) large_flash_base = EBONY_LARGE_FLASH_LOW; diff --git a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c index 8b0da394f3fa5224274fa30896711925cc8ad5aa..b48a3473ffc16103f65947f471e5d35169118966 100644 --- a/drivers/mtd/maps/edb7312.c +++ b/drivers/mtd/maps/edb7312.c @@ -1,10 +1,10 @@ /* - * $Id: edb7312.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $ + * $Id: edb7312.c,v 1.14 2005/11/07 11:14:27 gleixner Exp $ * * Handle mapping of the NOR flash on Cogent EDB7312 boards * * Copyright 2002 SYSGO Real-Time Solutions GmbH - * + * * 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. @@ -46,7 +46,7 @@ struct map_info edb7312nor_map = { #ifdef CONFIG_MTD_PARTITIONS /* - * MTD partitioning stuff + * MTD partitioning stuff */ static struct mtd_partition static_partitions[3] = { @@ -80,7 +80,7 @@ int __init init_edb7312nor(void) const char **type; const char *part_type = 0; - printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", + printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", WINDOW_SIZE, WINDOW_ADDR); edb7312nor_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); @@ -88,7 +88,7 @@ int __init init_edb7312nor(void) printk(MSG_PREFIX "failed to ioremap\n"); return -EIO; } - + simple_map_init(&edb7312nor_map); mymtd = 0; diff --git a/drivers/mtd/maps/epxa10db-flash.c b/drivers/mtd/maps/epxa10db-flash.c index 1df6188926b3aa81e99b402bdaa265d4fa666d16..265b079fe93466d91f0a966524e155cc3d5fff32 100644 --- a/drivers/mtd/maps/epxa10db-flash.c +++ b/drivers/mtd/maps/epxa10db-flash.c @@ -5,7 +5,7 @@ * Copyright (C) 2001 Altera Corporation * Copyright (C) 2001 Red Hat, Inc. * - * $Id: epxa10db-flash.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $ + * $Id: epxa10db-flash.c,v 1.15 2005/11/07 11:14:27 gleixner Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -62,7 +62,7 @@ static const char *probes[] = { "RedBoot", "afs", NULL }; static int __init epxa_mtd_init(void) { int i; - + printk(KERN_NOTICE "%s flash device: 0x%x at 0x%x\n", BOARD_NAME, FLASH_SIZE, FLASH_START); epxa_map.virt = ioremap(FLASH_START, FLASH_SIZE); @@ -126,8 +126,8 @@ static void __exit epxa_mtd_cleanup(void) } -/* - * This will do for now, once we decide which bootldr we're finally +/* + * This will do for now, once we decide which bootldr we're finally * going to use then we'll remove this function and do it properly * * Partions are currently (as offsets from base of flash): @@ -140,7 +140,7 @@ static int __init epxa_default_partitions(struct mtd_info *master, struct mtd_pa struct mtd_partition *parts; int ret, i; int npartitions = 0; - char *names; + char *names; const char *name = "jffs"; printk("Using default partitions for %s\n",BOARD_NAME); @@ -152,7 +152,7 @@ static int __init epxa_default_partitions(struct mtd_info *master, struct mtd_pa goto out; } i=0; - names = (char *)&parts[npartitions]; + names = (char *)&parts[npartitions]; parts[i].name = names; names += strlen(name) + 1; strcpy(parts[i].name, name); diff --git a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c index 00f7bbe5479e47d74aa5570e6d85d103d26f750d..c6bf4e1219ef116c9a5e6cb488fa8ece0d47315c 100644 --- a/drivers/mtd/maps/fortunet.c +++ b/drivers/mtd/maps/fortunet.c @@ -1,6 +1,6 @@ /* fortunet.c memory map * - * $Id: fortunet.c,v 1.9 2004/11/04 13:24:14 gleixner Exp $ + * $Id: fortunet.c,v 1.11 2005/11/07 11:14:27 gleixner Exp $ */ #include @@ -212,7 +212,7 @@ int __init init_fortunet(void) map_regions[ix].map_info.phys = map_regions[ix].window_addr_physical, - map_regions[ix].map_info.virt = + map_regions[ix].map_info.virt = ioremap_nocache( map_regions[ix].window_addr_physical, map_regions[ix].map_info.size); diff --git a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c index c73828171d9b303566962a21b0c541c7d29daf58..3190948211011b16211950cba7e7dab9c4b89251 100644 --- a/drivers/mtd/maps/h720x-flash.c +++ b/drivers/mtd/maps/h720x-flash.c @@ -1,11 +1,11 @@ /* - * Flash memory access on Hynix GMS30C7201/HMS30C7202 based + * Flash memory access on Hynix GMS30C7201/HMS30C7202 based * evaluation boards - * - * $Id: h720x-flash.c,v 1.11 2004/11/04 13:24:14 gleixner Exp $ + * + * $Id: h720x-flash.c,v 1.12 2005/11/07 11:14:27 gleixner Exp $ * * (C) 2002 Jungjun Kim - * 2003 Thomas Gleixner + * 2003 Thomas Gleixner */ #include @@ -72,7 +72,7 @@ int __init h720x_mtd_init(void) { char *part_type = NULL; - + h720x_map.virt = ioremap(FLASH_PHYS, FLASH_SIZE); if (!h720x_map.virt) { @@ -91,7 +91,7 @@ int __init h720x_mtd_init(void) h720x_map.bankwidth = 2; mymtd = do_map_probe("cfi_probe", &h720x_map); } - + if (mymtd) { mymtd->owner = THIS_MODULE; @@ -124,11 +124,11 @@ static void __exit h720x_mtd_cleanup(void) del_mtd_partitions(mymtd); map_destroy(mymtd); } - + /* Free partition info, if commandline partition was used */ if (mtd_parts && (mtd_parts != h720x_partitions)) kfree (mtd_parts); - + if (h720x_map.virt) { iounmap((void *)h720x_map.virt); h720x_map.virt = 0; diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c index e505207cd4892918b27c59a3ccc2f00afc0c3c59..ea5073781b3a38265053e2710606d5ef26464854 100644 --- a/drivers/mtd/maps/ichxrom.c +++ b/drivers/mtd/maps/ichxrom.c @@ -2,7 +2,7 @@ * ichxrom.c * * Normal mappings of chips in physical memory - * $Id: ichxrom.c,v 1.18 2005/07/07 10:26:20 dwmw2 Exp $ + * $Id: ichxrom.c,v 1.19 2005/11/07 11:14:27 gleixner Exp $ */ #include @@ -101,7 +101,7 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev, * you can only really attach a FWH to an ICHX there * a number of simplifications you can make. * - * Also you can page firmware hubs if an 8MB window isn't enough + * Also you can page firmware hubs if an 8MB window isn't enough * but don't currently handle that case either. */ window->pdev = pdev; @@ -144,7 +144,7 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev, window->phys = 0xfff00000; } else if ((byte & 0x80) == 0x80) { - window->phys = 0xfff80000; + window->phys = 0xfff80000; } if (window->phys == 0) { @@ -233,7 +233,7 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev, * in a factory setting. So in-place programming * needs to use a different method. */ - for(map->map.bankwidth = 32; map->map.bankwidth; + for(map->map.bankwidth = 32; map->map.bankwidth; map->map.bankwidth >>= 1) { char **probe_type; @@ -286,7 +286,7 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev, for(i = 0; i < cfi->numchips; i++) { cfi->chips[i].start += offset; } - + /* Now that the mtd devices is complete claim and export it */ map->mtd->owner = THIS_MODULE; if (add_mtd_device(map->mtd)) { @@ -306,9 +306,8 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev, out: /* Free any left over map structures */ - if (map) { - kfree(map); - } + kfree(map); + /* See if I have any map structures */ if (list_empty(&window->maps)) { ichxrom_cleanup(window); @@ -325,11 +324,11 @@ static void __devexit ichxrom_remove_one (struct pci_dev *pdev) } static struct pci_device_id ichxrom_pci_tbl[] __devinitdata = { - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, PCI_ANY_ID, PCI_ANY_ID, }, diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c index cb39172c81d23fbe2803937badce1dd37ebcc221..ba7f40311a7e359352156b2d9e51738b6cd7e55c 100644 --- a/drivers/mtd/maps/impa7.c +++ b/drivers/mtd/maps/impa7.c @@ -1,10 +1,10 @@ /* - * $Id: impa7.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $ + * $Id: impa7.c,v 1.14 2005/11/07 11:14:27 gleixner Exp $ * * Handle mapping of the NOR flash on implementa A7 boards * * Copyright 2002 SYSGO Real-Time Solutions GmbH - * + * * 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. @@ -55,7 +55,7 @@ static struct map_info impa7_map[NUM_FLASHBANKS] = { #ifdef CONFIG_MTD_PARTITIONS /* - * MTD partitioning stuff + * MTD partitioning stuff */ static struct mtd_partition static_partitions[] = { @@ -108,9 +108,9 @@ int __init init_impa7(void) impa7_mtd[i]->owner = THIS_MODULE; devicesfound++; #ifdef CONFIG_MTD_PARTITIONS - mtd_parts_nb[i] = parse_mtd_partitions(impa7_mtd[i], + mtd_parts_nb[i] = parse_mtd_partitions(impa7_mtd[i], probes, - &mtd_parts[i], + &mtd_parts[i], 0); if (mtd_parts_nb[i] > 0) { part_type = "command line"; @@ -121,16 +121,16 @@ int __init init_impa7(void) } printk(KERN_NOTICE MSG_PREFIX - "using %s partition definition\n", + "using %s partition definition\n", part_type); - add_mtd_partitions(impa7_mtd[i], + add_mtd_partitions(impa7_mtd[i], mtd_parts[i], mtd_parts_nb[i]); #else add_mtd_device(impa7_mtd[i]); #endif } - else + else iounmap((void *)impa7_map[i].virt); } return devicesfound == 0 ? -ENXIO : 0; diff --git a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c index d14a0185b8f419f97d14595caee88803c64769d9..fe738fd8d6f89f068910a82cd636a4bb431eb4c9 100644 --- a/drivers/mtd/maps/integrator-flash.c +++ b/drivers/mtd/maps/integrator-flash.c @@ -1,28 +1,28 @@ /*====================================================================== drivers/mtd/maps/integrator-flash.c: ARM Integrator flash map driver - + Copyright (C) 2000 ARM Limited Copyright (C) 2003 Deep Blue Solutions Ltd. - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - This is access code for flashes using ARM's flash partitioning + + This is access code for flashes using ARM's flash partitioning standards. - $Id: integrator-flash.c,v 1.18 2004/11/01 13:26:15 rmk Exp $ + $Id: integrator-flash.c,v 1.20 2005/11/07 11:14:27 gleixner Exp $ ======================================================================*/ @@ -148,8 +148,7 @@ static int armflash_probe(struct device *_dev) del_mtd_partitions(info->mtd); map_destroy(info->mtd); } - if (info->parts) - kfree(info->parts); + kfree(info->parts); no_device: iounmap(base); @@ -176,8 +175,7 @@ static int armflash_remove(struct device *_dev) del_mtd_partitions(info->mtd); map_destroy(info->mtd); } - if (info->parts) - kfree(info->parts); + kfree(info->parts); iounmap(info->map.virt); release_resource(info->res); diff --git a/drivers/mtd/maps/ipaq-flash.c b/drivers/mtd/maps/ipaq-flash.c index 712401810841bf1f1d5358b12108ddffac8affbf..35097c9bbf50c5bb560fe5fce3b039a3a4c4eba3 100644 --- a/drivers/mtd/maps/ipaq-flash.c +++ b/drivers/mtd/maps/ipaq-flash.c @@ -1,11 +1,11 @@ /* * Flash memory access on iPAQ Handhelds (either SA1100 or PXA250 based) - * + * * (C) 2000 Nicolas Pitre * (C) 2002 Hewlett-Packard Company * (C) 2003 Christian Pellegrin , : concatenation of multiple flashes - * - * $Id: ipaq-flash.c,v 1.3 2004/11/04 13:24:15 gleixner Exp $ + * + * $Id: ipaq-flash.c,v 1.5 2005/11/07 11:14:27 gleixner Exp $ */ #include @@ -107,7 +107,7 @@ static struct mtd_partition h3xxx_partitions[] = { #ifndef CONFIG_LAB mask_flags: MTD_WRITEABLE, /* force read-only */ #endif - }, + }, { name: "H3XXX root jffs2", #ifndef CONFIG_LAB @@ -148,7 +148,7 @@ static DEFINE_SPINLOCK(ipaq_vpp_lock); static void h3xxx_set_vpp(struct map_info *map, int vpp) { static int nest = 0; - + spin_lock(&ipaq_vpp_lock); if (vpp) nest++; @@ -191,7 +191,7 @@ static unsigned long cs_phys[] = { SA1100_CS3_PHYS, SA1100_CS4_PHYS, SA1100_CS5_PHYS, -#else +#else PXA_CS0_PHYS, PXA_CS1_PHYS, PXA_CS2_PHYS, @@ -216,7 +216,7 @@ int __init ipaq_mtd_init(void) /* Default flash bankwidth */ // ipaq_map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4; - + if (machine_is_h1900()) { /* For our intents, the h1900 is not a real iPAQ, so we special-case it. */ @@ -229,7 +229,7 @@ int __init ipaq_mtd_init(void) else for(i=0; isize); - + /* do we really need this debugging? --joshua 20030703 */ // printk("my_sub_mtd[%d]=%p\n", i, my_sub_mtd[i]); my_sub_mtd[i]->owner = THIS_MODULE; @@ -333,11 +333,11 @@ int __init ipaq_mtd_init(void) #else mymtd = my_sub_mtd[0]; - /* + /* *In the very near future, command line partition parsing * will use the device name as 'mtd-id' instead of a value * passed to the parse_cmdline_partitions() routine. Since - * the bootldr says 'ipaq', make sure it continues to work. + * the bootldr says 'ipaq', make sure it continues to work. */ mymtd->name = "ipaq"; @@ -385,7 +385,7 @@ int __init ipaq_mtd_init(void) */ i = parse_mtd_partitions(mymtd, part_probes, &parsed_parts, 0); - + if (i > 0) { nb_parts = parsed_nr_parts = i; parts = parsed_parts; @@ -423,16 +423,15 @@ static void __exit ipaq_mtd_cleanup(void) #endif map_destroy(mymtd); #ifdef CONFIG_MTD_CONCAT - for(i=0; i @@ -46,8 +46,8 @@ struct ixp2000_flash_info { }; static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long ofs) -{ - unsigned long (*set_bank)(unsigned long) = +{ + unsigned long (*set_bank)(unsigned long) = (unsigned long(*)(unsigned long))map->map_priv_2; return (set_bank ? set_bank(ofs) : ofs); @@ -55,8 +55,8 @@ static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long #ifdef __ARMEB__ /* - * Rev A0 and A1 of IXP2400 silicon have a broken addressing unit which - * causes the lower address bits to be XORed with 0x11 on 8 bit accesses + * Rev A0 and A1 of IXP2400 silicon have a broken addressing unit which + * causes the lower address bits to be XORed with 0x11 on 8 bit accesses * and XORed with 0x10 on 16 bit accesses. See the spec update, erratum 44. */ static int erratum44_workaround = 0; @@ -90,7 +90,7 @@ static void ixp2000_flash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) { from = flash_bank_setup(map, from); - while(len--) + while(len--) *(__u8 *) to++ = *(__u8 *)(map->map_priv_1 + from++); } @@ -129,8 +129,7 @@ static int ixp2000_flash_remove(struct device *_dev) if (info->map.map_priv_1) iounmap((void *) info->map.map_priv_1); - if (info->partitions) { - kfree(info->partitions); } + kfree(info->partitions); if (info->res) { release_resource(info->res); @@ -149,11 +148,11 @@ static int ixp2000_flash_probe(struct device *_dev) static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; struct platform_device *dev = to_platform_device(_dev); struct ixp2000_flash_data *ixp_data = dev->dev.platform_data; - struct flash_platform_data *plat; + struct flash_platform_data *plat; struct ixp2000_flash_info *info; unsigned long window_size; int err = -1; - + if (!ixp_data) return -ENODEV; @@ -162,7 +161,7 @@ static int ixp2000_flash_probe(struct device *_dev) return -ENODEV; window_size = dev->resource->end - dev->resource->start + 1; - dev_info(_dev, "Probe of IXP2000 flash(%d banks x %dMiB)\n", + dev_info(_dev, "Probe of IXP2000 flash(%d banks x %dMiB)\n", ixp_data->nr_banks, ((u32)window_size >> 20)); if (plat->width != 1) { @@ -175,7 +174,7 @@ static int ixp2000_flash_probe(struct device *_dev) if(!info) { err = -ENOMEM; goto Error; - } + } memzero(info, sizeof(struct ixp2000_flash_info)); dev_set_drvdata(&dev->dev, info); @@ -185,7 +184,7 @@ static int ixp2000_flash_probe(struct device *_dev) * not attempt to do a direct access on us. */ info->map.phys = NO_XIP; - + info->nr_banks = ixp_data->nr_banks; info->map.size = ixp_data->nr_banks * window_size; info->map.bankwidth = 1; @@ -193,7 +192,7 @@ static int ixp2000_flash_probe(struct device *_dev) /* * map_priv_2 is used to store a ptr to to the bank_setup routine */ - info->map.map_priv_2 = (void __iomem *) ixp_data->bank_setup; + info->map.map_priv_2 = (unsigned long) ixp_data->bank_setup; info->map.name = dev->dev.bus_id; info->map.read = ixp2000_flash_read8; @@ -201,8 +200,8 @@ static int ixp2000_flash_probe(struct device *_dev) info->map.copy_from = ixp2000_flash_copy_from; info->map.copy_to = ixp2000_flash_copy_to; - info->res = request_mem_region(dev->resource->start, - dev->resource->end - dev->resource->start + 1, + info->res = request_mem_region(dev->resource->start, + dev->resource->end - dev->resource->start + 1, dev->dev.bus_id); if (!info->res) { dev_err(_dev, "Could not reserve memory region\n"); @@ -210,7 +209,7 @@ static int ixp2000_flash_probe(struct device *_dev) goto Error; } - info->map.map_priv_1 = ioremap(dev->resource->start, + info->map.map_priv_1 = (unsigned long) ioremap(dev->resource->start, dev->resource->end - dev->resource->start + 1); if (!info->map.map_priv_1) { dev_err(_dev, "Failed to ioremap flash region\n"); diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c index 733a9297a56263eda2c49bfe7db2545f86ed78d6..56b3a355bf7b83f934a77eeca368b2cdfa25d96c 100644 --- a/drivers/mtd/maps/ixp4xx.c +++ b/drivers/mtd/maps/ixp4xx.c @@ -1,5 +1,5 @@ /* - * $Id: ixp4xx.c,v 1.7 2004/11/04 13:24:15 gleixner Exp $ + * $Id: ixp4xx.c,v 1.12 2005/11/07 11:14:27 gleixner Exp $ * * drivers/mtd/maps/ixp4xx.c * @@ -45,7 +45,7 @@ static map_word ixp4xx_read16(struct map_info *map, unsigned long ofs) { map_word val; - val.x[0] = *(__u16 *) (map->map_priv_1 + ofs); + val.x[0] = le16_to_cpu(readw(map->virt + ofs)); return val; } @@ -59,35 +59,35 @@ static void ixp4xx_copy_from(struct map_info *map, void *to, { int i; u8 *dest = (u8 *) to; - u16 *src = (u16 *) (map->map_priv_1 + from); + void __iomem *src = map->virt + from; u16 data; for (i = 0; i < (len / 2); i++) { - data = src[i]; + data = le16_to_cpu(readw(src + 2*i)); dest[i * 2] = BYTE0(data); dest[i * 2 + 1] = BYTE1(data); } if (len & 1) - dest[len - 1] = BYTE0(src[i]); + dest[len - 1] = BYTE0(le16_to_cpu(readw(src + 2*i))); } -/* +/* * Unaligned writes are ignored, causing the 8-bit * probe to fail and proceed to the 16-bit probe (which succeeds). */ static void ixp4xx_probe_write16(struct map_info *map, map_word d, unsigned long adr) { if (!(adr & 1)) - *(__u16 *) (map->map_priv_1 + adr) = d.x[0]; + writew(cpu_to_le16(d.x[0]), map->virt + adr); } -/* +/* * Fast write16 function without the probing check above */ static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr) { - *(__u16 *) (map->map_priv_1 + adr) = d.x[0]; + writew(cpu_to_le16(d.x[0]), map->virt + adr); } struct ixp4xx_flash_info { @@ -104,28 +104,20 @@ static int ixp4xx_flash_remove(struct device *_dev) struct platform_device *dev = to_platform_device(_dev); struct flash_platform_data *plat = dev->dev.platform_data; struct ixp4xx_flash_info *info = dev_get_drvdata(&dev->dev); - map_word d; dev_set_drvdata(&dev->dev, NULL); if(!info) return 0; - /* - * This is required for a soft reboot to work. - */ - d.x[0] = 0xff; - ixp4xx_write16(&info->map, d, 0x55 * 0x2); - if (info->mtd) { del_mtd_partitions(info->mtd); map_destroy(info->mtd); } - if (info->map.map_priv_1) - iounmap((void *) info->map.map_priv_1); + if (info->map.virt) + iounmap(info->map.virt); - if (info->partitions) - kfree(info->partitions); + kfree(info->partitions); if (info->res) { release_resource(info->res); @@ -135,9 +127,6 @@ static int ixp4xx_flash_remove(struct device *_dev) if (plat->exit) plat->exit(); - /* Disable flash write */ - *IXP4XX_EXP_CS0 &= ~IXP4XX_FLASH_WRITABLE; - return 0; } @@ -161,17 +150,11 @@ static int ixp4xx_flash_probe(struct device *_dev) if(!info) { err = -ENOMEM; goto Error; - } + } memzero(info, sizeof(struct ixp4xx_flash_info)); dev_set_drvdata(&dev->dev, info); - /* - * Enable flash write - * TODO: Move this out to board specific code - */ - *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE; - /* * Tell the MTD layer we're not 1:1 mapped so that it does * not attempt to do a direct access on us. @@ -190,8 +173,8 @@ static int ixp4xx_flash_probe(struct device *_dev) info->map.write = ixp4xx_probe_write16, info->map.copy_from = ixp4xx_copy_from, - info->res = request_mem_region(dev->resource->start, - dev->resource->end - dev->resource->start + 1, + info->res = request_mem_region(dev->resource->start, + dev->resource->end - dev->resource->start + 1, "IXP4XXFlash"); if (!info->res) { printk(KERN_ERR "IXP4XXFlash: Could not reserve memory region\n"); @@ -199,9 +182,9 @@ static int ixp4xx_flash_probe(struct device *_dev) goto Error; } - info->map.map_priv_1 = ioremap(dev->resource->start, - dev->resource->end - dev->resource->start + 1); - if (!info->map.map_priv_1) { + info->map.virt = ioremap(dev->resource->start, + dev->resource->end - dev->resource->start + 1); + if (!info->map.virt) { printk(KERN_ERR "IXP4XXFlash: Failed to ioremap region\n"); err = -EIO; goto Error; @@ -214,7 +197,7 @@ static int ixp4xx_flash_probe(struct device *_dev) goto Error; } info->mtd->owner = THIS_MODULE; - + /* Use the fast version */ info->map.write = ixp4xx_write16, @@ -259,4 +242,3 @@ module_exit(ixp4xx_flash_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("MTD map driver for Intel IXP4xx systems"); MODULE_AUTHOR("Deepak Saxena"); - diff --git a/drivers/mtd/maps/l440gx.c b/drivers/mtd/maps/l440gx.c index b08668212ab7401a0640e15f9fab420431d93499..851bf957605205c66ed3a7fe0d0777e83b44e4f6 100644 --- a/drivers/mtd/maps/l440gx.c +++ b/drivers/mtd/maps/l440gx.c @@ -1,5 +1,5 @@ /* - * $Id: l440gx.c,v 1.17 2004/11/28 09:40:39 dwmw2 Exp $ + * $Id: l440gx.c,v 1.18 2005/11/07 11:14:27 gleixner Exp $ * * BIOS Flash chip on Intel 440GX board. * @@ -49,7 +49,7 @@ static struct map_info l440gx_map = { .bankwidth = BUSWIDTH, .phys = WINDOW_ADDR, #if 0 - /* FIXME verify that this is the + /* FIXME verify that this is the * appripriate code for vpp enable/disable */ .set_vpp = l440gx_set_vpp @@ -62,10 +62,10 @@ static int __init init_l440gx(void) struct resource *pm_iobase; __u16 word; - dev = pci_find_device(PCI_VENDOR_ID_INTEL, + dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, NULL); - pm_dev = pci_find_device(PCI_VENDOR_ID_INTEL, + pm_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL); if (!dev || !pm_dev) { @@ -82,10 +82,10 @@ static int __init init_l440gx(void) simple_map_init(&l440gx_map); printk(KERN_NOTICE "window_addr = 0x%08lx\n", (unsigned long)l440gx_map.virt); - /* Setup the pm iobase resource + /* Setup the pm iobase resource * This code should move into some kind of generic bridge * driver but for the moment I'm content with getting the - * allocation correct. + * allocation correct. */ pm_iobase = &pm_dev->resource[PIIXE_IOBASE_RESOURCE]; if (!(pm_iobase->flags & IORESOURCE_IO)) { @@ -110,7 +110,7 @@ static int __init init_l440gx(void) /* Set the iobase */ iobase = pm_iobase->start; pci_write_config_dword(pm_dev, 0x40, iobase | 1); - + /* Set XBCS# */ pci_read_config_word(dev, 0x4e, &word); @@ -122,7 +122,7 @@ static int __init init_l440gx(void) /* Enable the gate on the WE line */ outb(inb(TRIBUF_PORT) & ~1, TRIBUF_PORT); - + printk(KERN_NOTICE "Enabled WE line to L440GX BIOS flash chip.\n"); mymtd = do_map_probe("jedec_probe", &l440gx_map); @@ -145,7 +145,7 @@ static void __exit cleanup_l440gx(void) { del_mtd_device(mymtd); map_destroy(mymtd); - + iounmap(l440gx_map.virt); } diff --git a/drivers/mtd/maps/lubbock-flash.c b/drivers/mtd/maps/lubbock-flash.c index 2337e0c4675061419bb9ddc6f64c4f7ff9f40378..1aa0447c5e66a2430ec9dd42bf5b86fba8549f16 100644 --- a/drivers/mtd/maps/lubbock-flash.c +++ b/drivers/mtd/maps/lubbock-flash.c @@ -1,11 +1,11 @@ /* - * $Id: lubbock-flash.c,v 1.19 2004/11/04 13:24:15 gleixner Exp $ + * $Id: lubbock-flash.c,v 1.21 2005/11/07 11:14:27 gleixner Exp $ * * Map driver for the Lubbock developer platform. * * Author: Nicolas Pitre * Copyright: (C) 2001 MontaVista Software Inc. - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. @@ -76,7 +76,7 @@ static int __init init_lubbock(void) int flashboot = (LUB_CONF_SWITCHES & 1); int ret = 0, i; - lubbock_maps[0].bankwidth = lubbock_maps[1].bankwidth = + lubbock_maps[0].bankwidth = lubbock_maps[1].bankwidth = (BOOT_DEF & 1) ? 2 : 4; /* Compensate for the nROMBT switch which swaps the flash banks */ @@ -100,11 +100,11 @@ static int __init init_lubbock(void) simple_map_init(&lubbock_maps[i]); printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit bankwidth)\n", - lubbock_maps[i].name, lubbock_maps[i].phys, + lubbock_maps[i].name, lubbock_maps[i].phys, lubbock_maps[i].bankwidth * 8); mymtds[i] = do_map_probe("cfi_probe", &lubbock_maps[i]); - + if (!mymtds[i]) { iounmap((void *)lubbock_maps[i].virt); if (lubbock_maps[i].cached) @@ -124,7 +124,7 @@ static int __init init_lubbock(void) if (!mymtds[0] && !mymtds[1]) return ret; - + for (i = 0; i < 2; i++) { if (!mymtds[i]) { printk(KERN_WARNING "%s is absent. Skipping\n", lubbock_maps[i].name); @@ -151,15 +151,14 @@ static void __exit cleanup_lubbock(void) if (nr_parsed_parts[i] || !i) del_mtd_partitions(mymtds[i]); else - del_mtd_device(mymtds[i]); + del_mtd_device(mymtds[i]); map_destroy(mymtds[i]); iounmap((void *)lubbock_maps[i].virt); if (lubbock_maps[i].cached) iounmap(lubbock_maps[i].cached); - if (parsed_parts[i]) - kfree(parsed_parts[i]); + kfree(parsed_parts[i]); } } diff --git a/drivers/mtd/maps/mainstone-flash.c b/drivers/mtd/maps/mainstone-flash.c index da0f8a692628a253f7a95831d8d44cb9664683d6..eaa4bbb868a32855adef0adcb9e7f4ca7d492f2d 100644 --- a/drivers/mtd/maps/mainstone-flash.c +++ b/drivers/mtd/maps/mainstone-flash.c @@ -5,7 +5,7 @@ * * Author: Nicolas Pitre * Copyright: (C) 2001 MontaVista Software Inc. - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. @@ -91,27 +91,27 @@ static int __init init_mainstone(void) mainstone_maps[i].virt = ioremap(mainstone_maps[i].phys, WINDOW_SIZE); if (!mainstone_maps[i].virt) { - printk(KERN_WARNING "Failed to ioremap %s\n", + printk(KERN_WARNING "Failed to ioremap %s\n", mainstone_maps[i].name); if (!ret) ret = -ENOMEM; continue; } - mainstone_maps[i].cached = + mainstone_maps[i].cached = ioremap_cached(mainstone_maps[i].phys, WINDOW_SIZE); if (!mainstone_maps[i].cached) printk(KERN_WARNING "Failed to ioremap cached %s\n", mainstone_maps[i].name); simple_map_init(&mainstone_maps[i]); - printk(KERN_NOTICE + printk(KERN_NOTICE "Probing %s at physical address 0x%08lx" " (%d-bit bankwidth)\n", - mainstone_maps[i].name, mainstone_maps[i].phys, + mainstone_maps[i].name, mainstone_maps[i].phys, mainstone_maps[i].bankwidth * 8); mymtds[i] = do_map_probe("cfi_probe", &mainstone_maps[i]); - + if (!mymtds[i]) { iounmap((void *)mainstone_maps[i].virt); if (mainstone_maps[i].cached) @@ -131,21 +131,21 @@ static int __init init_mainstone(void) if (!mymtds[0] && !mymtds[1]) return ret; - + for (i = 0; i < 2; i++) { if (!mymtds[i]) { - printk(KERN_WARNING "%s is absent. Skipping\n", + printk(KERN_WARNING "%s is absent. Skipping\n", mainstone_maps[i].name); } else if (nr_parsed_parts[i]) { - add_mtd_partitions(mymtds[i], parsed_parts[i], + add_mtd_partitions(mymtds[i], parsed_parts[i], nr_parsed_parts[i]); } else if (!i) { printk("Using static partitions on %s\n", mainstone_maps[i].name); - add_mtd_partitions(mymtds[i], mainstone_partitions, + add_mtd_partitions(mymtds[i], mainstone_partitions, ARRAY_SIZE(mainstone_partitions)); } else { - printk("Registering %s as whole device\n", + printk("Registering %s as whole device\n", mainstone_maps[i].name); add_mtd_device(mymtds[i]); } diff --git a/drivers/mtd/maps/mbx860.c b/drivers/mtd/maps/mbx860.c index c5c6901a476318d63d86c14d06e9d5f92d081026..06b1187278468bb4e0392b8a70edc1b32842c3f3 100644 --- a/drivers/mtd/maps/mbx860.c +++ b/drivers/mtd/maps/mbx860.c @@ -1,11 +1,11 @@ /* - * $Id: mbx860.c,v 1.8 2004/11/04 13:24:15 gleixner Exp $ + * $Id: mbx860.c,v 1.9 2005/11/07 11:14:27 gleixner Exp $ * * Handle mapping of the flash on MBX860 boards * * Author: Anton Todorov * Copyright: (C) 2001 Emness Technology - * + * * 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. @@ -46,7 +46,7 @@ static struct mtd_partition partition_info[]={ { .name = "MBX flash APPLICATION partition", .offset = (BOOT_PARTITION_SIZE_KiB+KERNEL_PARTITION_SIZE_KiB)*1024 } }; - + static struct mtd_info *mymtd; diff --git a/drivers/mtd/maps/mtx-1_flash.c b/drivers/mtd/maps/mtx-1_flash.c new file mode 100644 index 0000000000000000000000000000000000000000..d1e66e186746bf4116476ae2a8fb17b95660600c --- /dev/null +++ b/drivers/mtd/maps/mtx-1_flash.c @@ -0,0 +1,96 @@ +/* + * Flash memory access on 4G Systems MTX-1 boards + * + * $Id: mtx-1_flash.c,v 1.2 2005/11/07 11:14:27 gleixner Exp $ + * + * (C) 2005 Bruno Randolf + * (C) 2005 Jörn Engel + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +static struct map_info mtx1_map = { + .name = "MTX-1 flash", + .bankwidth = 4, + .size = 0x2000000, + .phys = 0x1E000000, +}; + +static struct mtd_partition mtx1_partitions[] = { + { + .name = "filesystem", + .size = 0x01C00000, + .offset = 0, + },{ + .name = "yamon", + .size = 0x00100000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE, + },{ + .name = "kernel", + .size = 0x002c0000, + .offset = MTDPART_OFS_APPEND, + },{ + .name = "yamon env", + .size = 0x00040000, + .offset = MTDPART_OFS_APPEND, + } +}; + +static struct mtd_info *mtx1_mtd; + +int __init mtx1_mtd_init(void) +{ + int ret = -ENXIO; + + simple_map_init(&mtx1_map); + + mtx1_map.virt = ioremap(mtx1_map.phys, mtx1_map.size); + if (!mtx1_map.virt) + return -EIO; + + mtx1_mtd = do_map_probe("cfi_probe", &mtx1_map); + if (!mtx1_mtd) + goto err; + + mtx1_mtd->owner = THIS_MODULE; + + ret = add_mtd_partitions(mtx1_mtd, mtx1_partitions, + ARRAY_SIZE(mtx1_partitions)); + if (ret) + goto err; + + return 0; + +err: + iounmap(mtx1_map.virt); + return ret; +} + +static void __exit mtx1_mtd_cleanup(void) +{ + if (mtx1_mtd) { + del_mtd_partitions(mtx1_mtd); + map_destroy(mtx1_mtd); + } + if (mtx1_map.virt) + iounmap(mtx1_map.virt); +} + +module_init(mtx1_mtd_init); +module_exit(mtx1_mtd_cleanup); + +MODULE_AUTHOR("Bruno Randolf "); +MODULE_DESCRIPTION("MTX-1 flash map"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/maps/netsc520.c b/drivers/mtd/maps/netsc520.c index ab7e6358d281b35edccb08006062964f0d53723a..33060a31572217b6feb25ba8d288323fbc492555 100644 --- a/drivers/mtd/maps/netsc520.c +++ b/drivers/mtd/maps/netsc520.c @@ -3,7 +3,7 @@ * Copyright (C) 2001 Mark Langsdorf (mark.langsdorf@amd.com) * based on sc520cdp.c by Sysgo Real-Time Solutions GmbH * - * $Id: netsc520.c,v 1.13 2004/11/28 09:40:40 dwmw2 Exp $ + * $Id: netsc520.c,v 1.14 2005/11/07 11:14:27 gleixner Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -38,7 +38,7 @@ ** The single, 16 megabyte flash bank is divided into four virtual ** partitions. The first partition is 768 KiB and is intended to ** store the kernel image loaded by the bootstrap loader. The second -** partition is 256 KiB and holds the BIOS image. The third +** partition is 256 KiB and holds the BIOS image. The third ** partition is 14.5 MiB and is intended for the flash file system ** image. The last partition is 512 KiB and contains another copy ** of the BIOS image and the reset vector. @@ -51,28 +51,28 @@ ** recoverable afterwards. */ -/* partition_info gives details on the logical partitions that the split the +/* partition_info gives details on the logical partitions that the split the * single flash device into. If the size if zero we use up to the end of the * device. */ static struct mtd_partition partition_info[]={ - { - .name = "NetSc520 boot kernel", - .offset = 0, + { + .name = "NetSc520 boot kernel", + .offset = 0, .size = 0xc0000 }, - { - .name = "NetSc520 Low BIOS", - .offset = 0xc0000, + { + .name = "NetSc520 Low BIOS", + .offset = 0xc0000, .size = 0x40000 }, - { - .name = "NetSc520 file system", - .offset = 0x100000, + { + .name = "NetSc520 file system", + .offset = 0x100000, .size = 0xe80000 }, - { - .name = "NetSc520 High BIOS", - .offset = 0xf80000, + { + .name = "NetSc520 High BIOS", + .offset = 0xf80000, .size = 0x80000 }, }; @@ -114,7 +114,7 @@ static int __init init_netsc520(void) iounmap(netsc520_map.virt); return -ENXIO; } - + mymtd->owner = THIS_MODULE; add_mtd_partitions( mymtd, partition_info, NUM_PARTITIONS ); return 0; diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c index 61be5a4148c9abdae5d56e02b99fe709a9862eb2..f00ee7e54dba7dbdaa17a30d3e2ff013d3f3eb6d 100644 --- a/drivers/mtd/maps/nettel.c +++ b/drivers/mtd/maps/nettel.c @@ -6,7 +6,7 @@ * (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com) * (C) Copyright 2001-2002, SnapGear (www.snapgear.com) * - * $Id: nettel.c,v 1.10 2005/01/05 17:11:29 dwmw2 Exp $ + * $Id: nettel.c,v 1.11 2005/11/07 11:14:27 gleixner Exp $ */ /****************************************************************************/ @@ -143,7 +143,7 @@ static int nettel_reboot_notifier(struct notifier_block *nb, unsigned long val, { struct cfi_private *cfi = nettel_intel_map.fldrv_priv; unsigned long b; - + /* Make sure all FLASH chips are put back into read mode */ for (b = 0; (b < nettel_intel_partitions[3].size); b += 0x100000) { cfi_send_gen_cmd(0xff, 0x55, b, &nettel_intel_map, cfi, @@ -199,7 +199,7 @@ int nettel_eraseconfig(void) schedule(); /* Wait for erase to finish. */ remove_wait_queue(&wait_q, &wait); - + put_mtd_device(mtd); } @@ -430,7 +430,7 @@ int __init nettel_init(void) nettel_intel_partitions[1].size = (intel0size + intel1size) - (1024*1024 + intel_mtd->erasesize); nettel_intel_partitions[3].size = intel0size + intel1size; - nettel_intel_partitions[4].offset = + nettel_intel_partitions[4].offset = (intel0size + intel1size) - intel_mtd->erasesize; nettel_intel_partitions[4].size = intel_mtd->erasesize; nettel_intel_partitions[5].offset = diff --git a/drivers/mtd/maps/ocelot.c b/drivers/mtd/maps/ocelot.c index 82c3070678c5111b4abb69a212dee60f43046ec1..6977963d789708c1e060e0990843b1a4e602eb52 100644 --- a/drivers/mtd/maps/ocelot.c +++ b/drivers/mtd/maps/ocelot.c @@ -1,5 +1,5 @@ /* - * $Id: ocelot.c,v 1.16 2005/01/05 18:05:13 dwmw2 Exp $ + * $Id: ocelot.c,v 1.17 2005/11/07 11:14:27 gleixner Exp $ * * Flash on Momenco Ocelot */ @@ -31,7 +31,7 @@ static void ocelot_ram_write(struct mtd_info *mtd, loff_t to, size_t len, size_t struct map_info *map = mtd->priv; size_t done = 0; - /* If we use memcpy, it does word-wide writes. Even though we told the + /* If we use memcpy, it does word-wide writes. Even though we told the GT64120A that it's an 8-bit wide region, word-wide writes don't work. We end up just writing the first byte of the four to all four bytes. So we have this loop instead */ @@ -68,7 +68,7 @@ static int __init init_ocelot_maps(void) int nr_parts; unsigned char brd_status; - printk(KERN_INFO "Momenco Ocelot MTD mappings: Flash 0x%x at 0x%x, NVRAM 0x%x at 0x%x\n", + printk(KERN_INFO "Momenco Ocelot MTD mappings: Flash 0x%x at 0x%x, NVRAM 0x%x at 0x%x\n", FLASH_WINDOW_SIZE, FLASH_WINDOW_ADDR, NVRAM_WINDOW_SIZE, NVRAM_WINDOW_ADDR); /* First check whether the flash jumper is present */ @@ -138,8 +138,8 @@ static int __init init_ocelot_maps(void) add_mtd_device(flash_mtd); return 0; - - fail3: + + fail3: iounmap((void *)ocelot_flash_map.virt); if (ocelot_flash_map.cached) iounmap((void *)ocelot_flash_map.cached); diff --git a/drivers/mtd/maps/octagon-5066.c b/drivers/mtd/maps/octagon-5066.c index e5ff83de420ee9ecb808de973db51133471185a1..a6642db3d325e19e6418ce0675fdd0f596e1f522 100644 --- a/drivers/mtd/maps/octagon-5066.c +++ b/drivers/mtd/maps/octagon-5066.c @@ -1,12 +1,12 @@ -// $Id: octagon-5066.c,v 1.26 2004/07/12 22:38:29 dwmw2 Exp $ +// $Id: octagon-5066.c,v 1.28 2005/11/07 11:14:27 gleixner Exp $ /* ###################################################################### - Octagon 5066 MTD Driver. - + Octagon 5066 MTD Driver. + The Octagon 5066 is a SBC based on AMD's 586-WB running at 133 MHZ. It comes with a builtin AMD 29F016 flash chip and a socketed EEPROM that is replacable by flash. Both units are mapped through a multiplexer - into a 32k memory window at 0xe8000. The control register for the + into a 32k memory window at 0xe8000. The control register for the multiplexing unit is located at IO 0x208 with a bit map of 0-5 Page Selection in 32k increments 6-7 Device selection: @@ -14,14 +14,14 @@ 01 SSD 0 (Socket) 10 SSD 1 (Flash chip) 11 undefined - + On each SSD, the first 128k is reserved for use by the bios - (actually it IS the bios..) This only matters if you are booting off the + (actually it IS the bios..) This only matters if you are booting off the flash, you must not put a file system starting there. - + The driver tries to do a detection algorithm to guess what sort of devices are plugged into the sockets. - + ##################################################################### */ #include @@ -56,7 +56,7 @@ static void __oct5066_page(struct map_info *map, __u8 byte) static inline void oct5066_page(struct map_info *map, unsigned long ofs) { __u8 byte = map->map_priv_1 | (ofs >> WINDOW_SHIFT); - + if (page_n_dev != byte) __oct5066_page(map, byte); } @@ -78,7 +78,7 @@ static void oct5066_copy_from(struct map_info *map, void *to, unsigned long from unsigned long thislen = len; if (len > (WINDOW_LENGTH - (from & WINDOW_MASK))) thislen = WINDOW_LENGTH-(from & WINDOW_MASK); - + spin_lock(&oct5066_spin); oct5066_page(map, from); memcpy_fromio(to, iomapadr + from, thislen); @@ -103,7 +103,7 @@ static void oct5066_copy_to(struct map_info *map, unsigned long to, const void * unsigned long thislen = len; if (len > (WINDOW_LENGTH - (to & WINDOW_MASK))) thislen = WINDOW_LENGTH-(to & WINDOW_MASK); - + spin_lock(&oct5066_spin); oct5066_page(map, to); memcpy_toio(iomapadr + to, from, thislen); @@ -144,7 +144,7 @@ static struct mtd_info *oct5066_mtd[2] = {NULL, NULL}; // OctProbe - Sense if this is an octagon card // --------------------------------------------------------------------- /* Perform a simple validity test, we map the window select SSD0 and - change pages while monitoring the window. A change in the window, + change pages while monitoring the window. A change in the window, controlled by the PAGE_IO port is a functioning 5066 board. This will fail if the thing in the socket is set to a uniform value. */ static int __init OctProbe(void) @@ -161,13 +161,13 @@ static int __init OctProbe(void) Values[I%10] = readl(iomapadr); if (I > 0 && Values[I%10] == Values[0]) return -EAGAIN; - } + } else { // Make sure we get the same values on the second pass if (Values[I%10] != readl(iomapadr)) return -EAGAIN; - } + } } return 0; } @@ -207,11 +207,11 @@ int __init init_oct5066(void) ret = -EAGAIN; goto out_unmap; } - + // Print out our little header.. printk("Octagon 5066 SSD IO:0x%x MEM:0x%x-0x%x\n",PAGE_IO,WINDOW_START, WINDOW_START+WINDOW_LENGTH); - + for (i=0; i<2; i++) { oct5066_mtd[i] = do_map_probe("cfi_probe", &oct5066_map[i]); if (!oct5066_mtd[i]) @@ -225,11 +225,11 @@ int __init init_oct5066(void) add_mtd_device(oct5066_mtd[i]); } } - + if (!oct5066_mtd[0] && !oct5066_mtd[1]) { cleanup_oct5066(); return -ENXIO; - } + } return 0; diff --git a/drivers/mtd/maps/omap-toto-flash.c b/drivers/mtd/maps/omap-toto-flash.c index da36e8dddd17e9833d222d108bb20fdabb53a4e3..dc37652700570e3c6899fb881f1269fc17e8d270 100644 --- a/drivers/mtd/maps/omap-toto-flash.c +++ b/drivers/mtd/maps/omap-toto-flash.c @@ -5,7 +5,7 @@ * * (C) 2002 MontVista Software, Inc. * - * $Id: omap-toto-flash.c,v 1.3 2004/09/16 23:27:13 gleixner Exp $ + * $Id: omap-toto-flash.c,v 1.5 2005/11/07 11:14:27 gleixner Exp $ */ #include @@ -38,7 +38,7 @@ static struct map_info omap_toto_map_flash = { .virt = (void __iomem *)OMAP_TOTO_FLASH_BASE, }; - + static struct mtd_partition toto_flash_partitions[] = { { .name = "BootLoader", @@ -54,21 +54,21 @@ static struct mtd_partition toto_flash_partitions[] = { .name = "EnvArea", /* bottom 64KiB for env vars */ .size = MTDPART_SIZ_FULL, .offset = MTDPART_OFS_APPEND, - } + } }; static struct mtd_partition *parsed_parts; static struct mtd_info *flash_mtd; - -static int __init init_flash (void) + +static int __init init_flash (void) { struct mtd_partition *parts; int nb_parts = 0; int parsed_nr_parts = 0; const char *part_type; - + /* * Static partition definition selection */ @@ -89,7 +89,7 @@ static int __init init_flash (void) flash_mtd = do_map_probe("jedec_probe", &omap_toto_map_flash); if (!flash_mtd) return -ENXIO; - + if (parsed_nr_parts > 0) { parts = parsed_parts; nb_parts = parsed_nr_parts; @@ -108,8 +108,8 @@ static int __init init_flash (void) } return 0; } - -int __init omap_toto_mtd_init(void) + +int __init omap_toto_mtd_init(void) { int status; @@ -119,13 +119,12 @@ int __init omap_toto_mtd_init(void) return status; } -static void __exit omap_toto_mtd_cleanup(void) +static void __exit omap_toto_mtd_cleanup(void) { if (flash_mtd) { del_mtd_partitions(flash_mtd); map_destroy(flash_mtd); - if (parsed_parts) - kfree(parsed_parts); + kfree(parsed_parts); } } diff --git a/drivers/mtd/maps/omap_nor.c b/drivers/mtd/maps/omap_nor.c index 7f370bb794fefae45e192df190d657e7bcd13110..fd3b4a5fc2072653a6f2c919d5c9984004a87a04 100644 --- a/drivers/mtd/maps/omap_nor.c +++ b/drivers/mtd/maps/omap_nor.c @@ -3,7 +3,7 @@ * * Copyright (C) 2001-2002 MontaVista Software Inc. * Copyright (C) 2003-2004 Texas Instruments - * Copyright (C) 2004 Nokia Corporation + * Copyright (C) 2004 Nokia Corporation * * Assembled using driver code copyright the companies above * and written by David Brownell, Jian Zhang , diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c index d9c64e99ee32a7ae466499f0b053df0908dcefd6..8b3570b090954bd27f8034d69620d0dc9baf2fd3 100644 --- a/drivers/mtd/maps/pci.c +++ b/drivers/mtd/maps/pci.c @@ -7,8 +7,8 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * $Id: pci.c,v 1.10 2005/03/18 14:04:35 gleixner Exp $ - * + * $Id: pci.c,v 1.13 2005/11/07 11:14:27 gleixner Exp $ + * * Generic PCI memory map driver. We support the following boards: * - Intel IQ80310 ATU. * - Intel EBSA285 (blank rom programming mode). Tested working 27/09/2001 @@ -38,7 +38,7 @@ struct map_pci_info { void (*exit)(struct pci_dev *dev, struct map_pci_info *map); unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs); struct pci_dev *dev; -}; +}; static map_word mtd_pci_read8(struct map_info *_map, unsigned long ofs) { diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index ff7c50d101802333bf7a9b452ab60212a103cf57..af24216a06264bcbd58631c701be6e431dda3f9b 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -1,5 +1,5 @@ /* - * $Id: pcmciamtd.c,v 1.51 2004/07/12 22:38:29 dwmw2 Exp $ + * $Id: pcmciamtd.c,v 1.55 2005/11/07 11:14:28 gleixner Exp $ * * pcmciamtd.c - MTD driver for PCMCIA flash memory cards * @@ -48,7 +48,7 @@ static const int debug = 0; #define DRIVER_DESC "PCMCIA Flash memory card driver" -#define DRIVER_VERSION "$Revision: 1.51 $" +#define DRIVER_VERSION "$Revision: 1.55 $" /* Size of the PCMCIA address space: 26 bits = 64 MB */ #define MAX_PCMCIA_ADDR 0x4000000 @@ -176,7 +176,7 @@ static void pcmcia_copy_from_remap(struct map_info *map, void *to, unsigned long if(toread > len) toread = len; - + addr = remap_window(map, from); if(!addr) return; @@ -386,7 +386,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ cs_error(link->handle, ParseTuple, rc); break; } - + switch(tuple.TupleCode) { case CISTPL_FORMAT: { cistpl_format_t *t = &parse.format; @@ -394,9 +394,9 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ DEBUG(2, "Format type: %u, Error Detection: %u, offset = %u, length =%u", t->type, t->edc, t->offset, t->length); break; - + } - + case CISTPL_DEVICE: { cistpl_device_t *t = &parse.device; int i; @@ -410,7 +410,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ } break; } - + case CISTPL_VERS_1: { cistpl_vers_1_t *t = &parse.version_1; int i; @@ -425,7 +425,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ DEBUG(2, "Found name: %s", dev->mtd_name); break; } - + case CISTPL_JEDEC_C: { cistpl_jedec_t *t = &parse.jedec; int i; @@ -434,7 +434,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ } break; } - + case CISTPL_DEVICE_GEO: { cistpl_device_geo_t *t = &parse.device_geo; int i; @@ -449,11 +449,11 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ } break; } - + default: DEBUG(2, "Unknown tuple code %d", tuple.TupleCode); } - + rc = pcmcia_get_next_tuple(link->handle, &tuple); } if(!dev->pcmcia_map.size) @@ -470,7 +470,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ if(bankwidth) { dev->pcmcia_map.bankwidth = bankwidth; DEBUG(2, "bankwidth forced to %d", bankwidth); - } + } dev->pcmcia_map.name = dev->mtd_name; if(!dev->mtd_name[0]) { @@ -568,7 +568,7 @@ static void pcmciamtd_config(dev_link_t *link) return; } DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10); - + /* Get write protect status */ CS_CHECK(GetStatus, pcmcia_get_status(link->handle, &status)); DEBUG(2, "status value: 0x%x window handle = 0x%8.8lx", @@ -624,11 +624,11 @@ static void pcmciamtd_config(dev_link_t *link) mtd = do_map_probe(probes[i], &dev->pcmcia_map); if(mtd) break; - + DEBUG(1, "FAILED: %s", probes[i]); } } - + if(!mtd) { DEBUG(1, "Cant find an MTD"); pcmciamtd_release(link); diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index b853670bfb81d6b4ffc6d58d5aa62a2d00c5669d..9ee760f97bc6ae58da80183fe3de17cdc77e80d4 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c @@ -1,5 +1,5 @@ /* - * $Id: physmap.c,v 1.37 2004/11/28 09:40:40 dwmw2 Exp $ + * $Id: physmap.c,v 1.38 2005/11/07 11:14:28 gleixner Exp $ * * Normal mappings of chips in physical memory * @@ -69,7 +69,7 @@ static int __init init_physmap(void) mymtd->owner = THIS_MODULE; #ifdef CONFIG_MTD_PARTITIONS - mtd_parts_nb = parse_mtd_partitions(mymtd, part_probes, + mtd_parts_nb = parse_mtd_partitions(mymtd, part_probes, &mtd_parts, 0); if (mtd_parts_nb > 0) @@ -78,9 +78,9 @@ static int __init init_physmap(void) return 0; } - if (num_physmap_partitions != 0) + if (num_physmap_partitions != 0) { - printk(KERN_NOTICE + printk(KERN_NOTICE "Using physmap partition definition\n"); add_mtd_partitions (mymtd, physmap_partitions, num_physmap_partitions); return 0; diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 104576b5be3480cf238f1f4c3ac0a6c9bbfeca8f..a02eed94a231ecbf39686d2db1733b65a3fdfd4c 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c @@ -6,7 +6,7 @@ * * Generic platfrom device based RAM map * - * $Id: plat-ram.c,v 1.3 2005/03/19 22:41:27 gleixner Exp $ + * $Id: plat-ram.c,v 1.7 2005/11/07 11:14:28 gleixner Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -91,7 +91,7 @@ static int platram_remove(struct device *dev) dev_dbg(dev, "removing device\n"); - if (info == NULL) + if (info == NULL) return 0; if (info->mtd) { @@ -118,7 +118,7 @@ static int platram_remove(struct device *dev) if (info->map.virt != NULL) iounmap(info->map.virt); - + kfree(info); return 0; @@ -139,7 +139,7 @@ static int platram_probe(struct device *dev) int err = 0; dev_dbg(dev, "probe entered\n"); - + if (dev->platform_data == NULL) { dev_err(dev, "no platform data supplied\n"); err = -ENOENT; @@ -177,7 +177,7 @@ static int platram_probe(struct device *dev) info->map.phys = res->start; info->map.size = (res->end - res->start) + 1; - info->map.name = pdata->mapname != NULL ? pdata->mapname : pd->name; + info->map.name = pdata->mapname != NULL ? pdata->mapname : (char *)pd->name; info->map.bankwidth = pdata->bankwidth; /* register our usage of the memory area */ @@ -240,7 +240,7 @@ static int platram_probe(struct device *dev) dev_err(dev, "add_mtd_device() failed\n"); err = -ENOMEM; } - + dev_info(dev, "registered mtd device\n"); return err; @@ -254,6 +254,7 @@ static int platram_probe(struct device *dev) static struct device_driver platram_driver = { .name = "mtd-ram", + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = platram_probe, .remove = platram_remove, diff --git a/drivers/mtd/maps/pnc2000.c b/drivers/mtd/maps/pnc2000.c index a0f43dad898507877d026d82754e2d92634b8f94..d7e16c2d5c4441efd0bf8bf129a1050dfb514d42 100644 --- a/drivers/mtd/maps/pnc2000.c +++ b/drivers/mtd/maps/pnc2000.c @@ -5,7 +5,7 @@ * * This code is GPL * - * $Id: pnc2000.c,v 1.17 2004/11/16 18:29:02 dwmw2 Exp $ + * $Id: pnc2000.c,v 1.18 2005/11/07 11:14:28 gleixner Exp $ */ #include @@ -21,7 +21,7 @@ #define WINDOW_ADDR 0xbf000000 #define WINDOW_SIZE 0x00400000 -/* +/* * MAP DRIVER STUFF */ @@ -36,7 +36,7 @@ static struct map_info pnc_map = { /* - * MTD 'PARTITIONING' STUFF + * MTD 'PARTITIONING' STUFF */ static struct mtd_partition pnc_partitions[3] = { { @@ -56,7 +56,7 @@ static struct mtd_partition pnc_partitions[3] = { } }; -/* +/* * This is the master MTD device for which all the others are just * auto-relocating aliases. */ diff --git a/drivers/mtd/maps/pq2fads.c b/drivers/mtd/maps/pq2fads.c new file mode 100644 index 0000000000000000000000000000000000000000..fb78d87cc130ddd30e58b2fe8cc2271b9962df53 --- /dev/null +++ b/drivers/mtd/maps/pq2fads.c @@ -0,0 +1,88 @@ +/* + * drivers/mtd/maps/pq2fads.c + * + * Mapping for the flash SIMM on 8272ADS and PQ2FADS board + * + * Author: Vitaly Bordug + * + * 2005 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + NOTE: bank width and interleave relative to the installed flash + should have been chosen within MTD_CFI_GEOMETRY options. + */ +#define PQ2FADS_BANK_WIDTH 4 + +static struct mtd_partition pq2fads_partitions[] = { + { +#ifdef CONFIG_ADS8272 + .name = "HRCW", + .size = 0x40000, + .offset = 0, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "User FS", + .size = 0x5c0000, + .offset = 0x40000, +#else + .name = "User FS", + .size = 0x600000, + .offset = 0, +#endif + }, { + .name = "uImage", + .size = 0x100000, + .offset = 0x600000, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "bootloader", + .size = 0x40000, + .offset = 0x700000, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "bootloader env", + .size = 0x40000, + .offset = 0x740000, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + } +}; + + +/* pointer to MPC885ADS board info data */ +extern unsigned char __res[]; + +static int __init init_pq2fads_mtd(void) +{ + bd_t *bd = (bd_t *)__res; + physmap_configure(bd->bi_flashstart, bd->bi_flashsize, PQ2FADS_BANK_WIDTH, NULL); + + physmap_set_partitions(pq2fads_partitions, + sizeof (pq2fads_partitions) / + sizeof (pq2fads_partitions[0])); + return 0; +} + +static void __exit cleanup_pq2fads_mtd(void) +{ +} + +module_init(init_pq2fads_mtd); +module_exit(cleanup_pq2fads_mtd); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MTD map and partitions for MPC8272ADS boards"); diff --git a/drivers/mtd/maps/redwood.c b/drivers/mtd/maps/redwood.c index edd01ee4f90be1232c16c4a524fea994994fb2a7..5b76ed8861859d7ce47305de56b35ec991f4a11a 100644 --- a/drivers/mtd/maps/redwood.c +++ b/drivers/mtd/maps/redwood.c @@ -1,5 +1,5 @@ /* - * $Id: redwood.c,v 1.10 2004/11/04 13:24:15 gleixner Exp $ + * $Id: redwood.c,v 1.11 2005/11/07 11:14:28 gleixner Exp $ * * drivers/mtd/maps/redwood.c * @@ -79,7 +79,7 @@ static struct mtd_partition redwood_flash_partitions[] = { #define RW_PART0_OF 0 #define RW_PART0_SZ 0x400000 /* 4 MiB data */ -#define RW_PART1_OF RW_PART0_OF + RW_PART0_SZ +#define RW_PART1_OF RW_PART0_OF + RW_PART0_SZ #define RW_PART1_SZ 0x10000 /* 64K VPD */ #define RW_PART2_OF RW_PART1_OF + RW_PART1_SZ #define RW_PART2_SZ 0x400000 - (0x10000 + 0x20000) diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index c8d0da19d897e461a18efaace5076bfc12111d59..9e8bb1782be00318ab3eb58264ccf087e3761c8d 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -1,9 +1,9 @@ /* * Flash memory access on SA11x0 based devices - * + * * (C) 2000 Nicolas Pitre - * - * $Id: sa1100-flash.c,v 1.47 2004/11/01 13:44:36 rmk Exp $ + * + * $Id: sa1100-flash.c,v 1.51 2005/11/07 11:14:28 gleixner Exp $ */ #include #include @@ -241,8 +241,7 @@ static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *pla #endif } - if (info->parts) - kfree(info->parts); + kfree(info->parts); for (i = info->num_subdev - 1; i >= 0; i--) sa1100_destroy_subdev(&info->subdev[i]); diff --git a/drivers/mtd/maps/sbc8240.c b/drivers/mtd/maps/sbc8240.c index da684d3384e923a37ec9e819c9ecc1e5e3a40840..225cdd9ba5b2f2d84054686d826e8cfff028b75b 100644 --- a/drivers/mtd/maps/sbc8240.c +++ b/drivers/mtd/maps/sbc8240.c @@ -5,7 +5,7 @@ * * This code is GPLed * - * $Id: sbc8240.c,v 1.4 2004/07/12 22:38:29 dwmw2 Exp $ + * $Id: sbc8240.c,v 1.5 2005/11/07 11:14:28 gleixner Exp $ * */ @@ -205,7 +205,7 @@ int __init init_sbc8240_mtd (void) } else { printk (KERN_NOTICE MSG_PREFIX "Using %s partition definition\n", sbc8240_part_banks[i].mtd_part->name); - add_mtd_partitions (sbc8240_mtd[i], + add_mtd_partitions (sbc8240_mtd[i], sbc8240_part_banks[i].mtd_part, sbc8240_part_banks[i].nums); } diff --git a/drivers/mtd/maps/sbc_gxx.c b/drivers/mtd/maps/sbc_gxx.c index 65add28bde14ce40d562aa2df5a6edb7a235dca9..7cc4041d096d6eaf5fb9e351760a95e1f1d2382c 100644 --- a/drivers/mtd/maps/sbc_gxx.c +++ b/drivers/mtd/maps/sbc_gxx.c @@ -1,35 +1,35 @@ /* sbc_gxx.c -- MTD map driver for Arcom Control Systems SBC-MediaGX, SBC-GXm and SBC-GX1 series boards. - + Copyright (C) 2001 Arcom Control System Ltd - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - $Id: sbc_gxx.c,v 1.33 2004/11/28 09:40:40 dwmw2 Exp $ + $Id: sbc_gxx.c,v 1.35 2005/11/07 11:14:28 gleixner Exp $ -The SBC-MediaGX / SBC-GXx has up to 16 MiB of -Intel StrataFlash (28F320/28F640) in x8 mode. +The SBC-MediaGX / SBC-GXx has up to 16 MiB of +Intel StrataFlash (28F320/28F640) in x8 mode. This driver uses the CFI probe and Intel Extended Command Set drivers. The flash is accessed as follows: 16 KiB memory window at 0xdc000-0xdffff - + Two IO address locations for paging - + 0x258 bit 0-7: address bit 14-21 0x259 @@ -37,7 +37,7 @@ The flash is accessed as follows: bit 7: 0 - reset/powered down 1 - device enabled -The single flash device is divided into 3 partition which appear as +The single flash device is divided into 3 partition which appear as separate MTD devices. 25/04/2001 AJL (Arcom) Modified signon strings and partition sizes @@ -87,17 +87,17 @@ static volatile int page_in_window = -1; // Current page in window. static void __iomem *iomapadr; static DEFINE_SPINLOCK(sbc_gxx_spin); -/* partition_info gives details on the logical partitions that the split the +/* partition_info gives details on the logical partitions that the split the * single flash device into. If the size if zero we use up to the end of the * device. */ static struct mtd_partition partition_info[]={ - { .name = "SBC-GXx flash boot partition", - .offset = 0, + { .name = "SBC-GXx flash boot partition", + .offset = 0, .size = BOOT_PARTITION_SIZE_KiB*1024 }, - { .name = "SBC-GXx flash data partition", - .offset = BOOT_PARTITION_SIZE_KiB*1024, + { .name = "SBC-GXx flash data partition", + .offset = BOOT_PARTITION_SIZE_KiB*1024, .size = (DATA_PARTITION_SIZE_KiB)*1024 }, - { .name = "SBC-GXx flash application partition", + { .name = "SBC-GXx flash application partition", .offset = (BOOT_PARTITION_SIZE_KiB+DATA_PARTITION_SIZE_KiB)*1024 } }; @@ -130,7 +130,7 @@ static void sbc_gxx_copy_from(struct map_info *map, void *to, unsigned long from unsigned long thislen = len; if (len > (WINDOW_LENGTH - (from & WINDOW_MASK))) thislen = WINDOW_LENGTH-(from & WINDOW_MASK); - + spin_lock(&sbc_gxx_spin); sbc_gxx_page(map, from); memcpy_fromio(to, iomapadr + (from & WINDOW_MASK), thislen); @@ -150,12 +150,12 @@ static void sbc_gxx_write8(struct map_info *map, map_word d, unsigned long adr) } static void sbc_gxx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ +{ while(len) { unsigned long thislen = len; if (len > (WINDOW_LENGTH - (to & WINDOW_MASK))) thislen = WINDOW_LENGTH-(to & WINDOW_MASK); - + spin_lock(&sbc_gxx_spin); sbc_gxx_page(map, to); memcpy_toio(iomapadr + (to & WINDOW_MASK), from, thislen); @@ -201,7 +201,7 @@ static int __init init_sbc_gxx(void) sbc_gxx_map.name ); return -EIO; } - + if (!request_region( PAGE_IO, PAGE_IO_SIZE, "SBC-GXx flash")) { printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n", sbc_gxx_map.name, @@ -209,8 +209,8 @@ static int __init init_sbc_gxx(void) iounmap(iomapadr); return -EAGAIN; } - - + + printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n", sbc_gxx_map.name, PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1, @@ -222,7 +222,7 @@ static int __init init_sbc_gxx(void) cleanup_sbc_gxx(); return -ENXIO; } - + all_mtd->owner = THIS_MODULE; /* Create MTD devices for each partition. */ diff --git a/drivers/mtd/maps/sc520cdp.c b/drivers/mtd/maps/sc520cdp.c index a06ed21e7ed1b85f9799a08f87b821947f261c42..6fb9f3c57aabe1fc9fc443675d0bd82c5dd741ff 100644 --- a/drivers/mtd/maps/sc520cdp.c +++ b/drivers/mtd/maps/sc520cdp.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: sc520cdp.c,v 1.21 2004/12/13 10:27:08 dedekind Exp $ + * $Id: sc520cdp.c,v 1.22 2005/11/07 11:14:28 gleixner Exp $ * * * The SC520CDP is an evaluation board for the Elan SC520 processor available @@ -231,7 +231,7 @@ static void sc520cdp_setup_par(void) static int __init init_sc520cdp(void) { int i, devices_found = 0; - + #ifdef REPROGRAM_PAR /* reprogram PAR registers so flash appears at the desired addresses */ sc520cdp_setup_par(); @@ -278,7 +278,7 @@ static int __init init_sc520cdp(void) static void __exit cleanup_sc520cdp(void) { int i; - + if (merged_mtd) { del_mtd_device(merged_mtd); mtd_concat_destroy(merged_mtd); diff --git a/drivers/mtd/maps/scx200_docflash.c b/drivers/mtd/maps/scx200_docflash.c index 0ece3786d6ea5a179ebda4b43a8fbe0396653e73..2c91dff8bb60c881e015d9e8e6d53b6bba3c669c 100644 --- a/drivers/mtd/maps/scx200_docflash.c +++ b/drivers/mtd/maps/scx200_docflash.c @@ -1,8 +1,8 @@ -/* linux/drivers/mtd/maps/scx200_docflash.c +/* linux/drivers/mtd/maps/scx200_docflash.c Copyright (c) 2001,2002 Christer Weinigel - $Id: scx200_docflash.c,v 1.10 2004/11/28 09:40:40 dwmw2 Exp $ + $Id: scx200_docflash.c,v 1.12 2005/11/07 11:14:28 gleixner Exp $ National Semiconductor SCx200 flash mapped with DOCCS */ @@ -49,23 +49,23 @@ static struct mtd_info *mymtd; #ifdef CONFIG_MTD_PARTITIONS static struct mtd_partition partition_info[] = { - { - .name = "DOCCS Boot kernel", - .offset = 0, + { + .name = "DOCCS Boot kernel", + .offset = 0, .size = 0xc0000 }, - { - .name = "DOCCS Low BIOS", - .offset = 0xc0000, + { + .name = "DOCCS Low BIOS", + .offset = 0xc0000, .size = 0x40000 }, - { - .name = "DOCCS File system", - .offset = 0x100000, + { + .name = "DOCCS File system", + .offset = 0x100000, .size = ~0 /* calculate from flash size */ }, - { - .name = "DOCCS High BIOS", + { + .name = "DOCCS High BIOS", .offset = ~0, /* calculate from flash size */ .size = 0x80000 }, @@ -88,7 +88,7 @@ static int __init init_scx200_docflash(void) printk(KERN_DEBUG NAME ": NatSemi SCx200 DOCCS Flash Driver\n"); - if ((bridge = pci_find_device(PCI_VENDOR_ID_NS, + if ((bridge = pci_find_device(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE, NULL)) == NULL) return -ENODEV; @@ -134,28 +134,28 @@ static int __init init_scx200_docflash(void) printk(KERN_ERR NAME ": invalid size for flash mapping\n"); return -EINVAL; } - + if (width != 8 && width != 16) { printk(KERN_ERR NAME ": invalid bus width for flash mapping\n"); return -EINVAL; } - - if (allocate_resource(&iomem_resource, &docmem, + + if (allocate_resource(&iomem_resource, &docmem, size, - 0xc0000000, 0xffffffff, + 0xc0000000, 0xffffffff, size, NULL, NULL)) { printk(KERN_ERR NAME ": unable to allocate memory for flash mapping\n"); return -ENOMEM; } - + ctrl = 0x07000000 | ((size-1) >> 13); printk(KERN_INFO "DOCCS BASE=0x%08lx, CTRL=0x%08lx\n", (long)docmem.start, (long)ctrl); - + pci_write_config_dword(bridge, SCx200_DOCCS_BASE, docmem.start); pci_write_config_dword(bridge, SCx200_DOCCS_CTRL, ctrl); pmr = inl(scx200_cb_base + SCx200_PMR); - + if (width == 8) { pmr &= ~(1<<6); } else { @@ -163,8 +163,8 @@ static int __init init_scx200_docflash(void) } outl(pmr, scx200_cb_base + SCx200_PMR); } - - printk(KERN_INFO NAME ": DOCCS mapped at 0x%lx-0x%lx, width %d\n", + + printk(KERN_INFO NAME ": DOCCS mapped at 0x%lx-0x%lx, width %d\n", docmem.start, docmem.end, width); scx200_docflash_map.size = size; diff --git a/drivers/mtd/maps/sharpsl-flash.c b/drivers/mtd/maps/sharpsl-flash.c index b7f093fbf9b05396dc1f54a6c14bb3b0c501268e..999f4bb3d845ce475322c88db98f774036dbcbfb 100644 --- a/drivers/mtd/maps/sharpsl-flash.c +++ b/drivers/mtd/maps/sharpsl-flash.c @@ -1,10 +1,10 @@ /* * sharpsl-flash.c - * + * * Copyright (C) 2001 Lineo Japan, Inc. * Copyright (C) 2002 SHARP * - * $Id: sharpsl-flash.c,v 1.5 2005/03/21 08:42:11 rpurdie Exp $ + * $Id: sharpsl-flash.c,v 1.7 2005/11/07 11:14:28 gleixner Exp $ * * based on rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp * Handle mapping of the flash on the RPX Lite and CLLF boards @@ -57,7 +57,7 @@ int __init init_sharpsl(void) int nb_parts = 0; char *part_type = "static"; - printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n", + printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR); sharpsl_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); if (!sharpsl_map.virt) { @@ -75,7 +75,7 @@ int __init init_sharpsl(void) mymtd->owner = THIS_MODULE; - if (machine_is_corgi() || machine_is_shepherd() || machine_is_husky() + if (machine_is_corgi() || machine_is_shepherd() || machine_is_husky() || machine_is_poodle()) { sharpsl_partitions[0].size=0x006d0000; sharpsl_partitions[0].offset=0x00120000; @@ -87,10 +87,10 @@ int __init init_sharpsl(void) sharpsl_partitions[0].offset=0x00140000; } else { map_destroy(mymtd); - iounmap(sharpsl_map.virt); + iounmap(sharpsl_map.virt); return -ENODEV; } - + parts = sharpsl_partitions; nb_parts = NB_OF(sharpsl_partitions); diff --git a/drivers/mtd/maps/solutionengine.c b/drivers/mtd/maps/solutionengine.c index 8ce5d897645c71b450f6cc1b2120f2921fa1dad2..c53c2c369c9d5dcc2df5aec29b26c48c3e6157ee 100644 --- a/drivers/mtd/maps/solutionengine.c +++ b/drivers/mtd/maps/solutionengine.c @@ -1,5 +1,5 @@ /* - * $Id: solutionengine.c,v 1.14 2004/09/16 23:27:14 gleixner Exp $ + * $Id: solutionengine.c,v 1.15 2005/11/07 11:14:28 gleixner Exp $ * * Flash and EPROM on Hitachi Solution Engine and similar boards. * @@ -67,7 +67,7 @@ static int __init init_soleng_maps(void) soleng_eprom_map.virt = (void __iomem *)P1SEGADDR(0x01000000); simple_map_init(&soleng_eprom_map); simple_map_init(&soleng_flash_map); - + printk(KERN_NOTICE "Probing for flash chips at 0x00000000:\n"); flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map); if (!flash_mtd) { diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index 29091d10030a091651c935f6126221d1de92ff8e..0758cb1d01056568dfda74d55297f7e9a6daa791 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c @@ -1,4 +1,4 @@ -/* $Id: sun_uflash.c,v 1.11 2004/11/04 13:24:15 gleixner Exp $ +/* $Id: sun_uflash.c,v 1.13 2005/11/07 11:14:28 gleixner Exp $ * * sun_uflash - Driver implementation for user-programmable flash * present on many Sun Microsystems SME boardsets. @@ -63,7 +63,7 @@ int uflash_devinit(struct linux_ebus_device* edev) iTmp = prom_getproperty( edev->prom_node, "reg", (void *)regs, sizeof(regs)); if ((iTmp % sizeof(regs[0])) != 0) { - printk("%s: Strange reg property size %d\n", + printk("%s: Strange reg property size %d\n", UFLASH_DEVNAME, iTmp); return -ENODEV; } @@ -75,7 +75,7 @@ int uflash_devinit(struct linux_ebus_device* edev) * can work on supporting it. */ printk("%s: unsupported device at 0x%lx (%d regs): " \ - "email ebrower@usa.net\n", + "email ebrower@usa.net\n", UFLASH_DEVNAME, edev->resource[0].start, nregs); return -ENODEV; } @@ -84,7 +84,7 @@ int uflash_devinit(struct linux_ebus_device* edev) printk("%s: unable to kmalloc new device\n", UFLASH_DEVNAME); return(-ENOMEM); } - + /* copy defaults and tweak parameters */ memcpy(&pdev->map, &uflash_map_templ, sizeof(uflash_map_templ)); pdev->map.size = regs[0].reg_size; @@ -155,7 +155,7 @@ static void __exit uflash_cleanup(void) list_for_each(udevlist, &device_list) { udev = list_entry(udevlist, struct uflash_dev, list); - DEBUG(2, "%s: removing device %s\n", + DEBUG(2, "%s: removing device %s\n", UFLASH_DEVNAME, udev->name); if(0 != udev->mtd) { @@ -166,11 +166,9 @@ static void __exit uflash_cleanup(void) iounmap(udev->map.virt); udev->map.virt = NULL; } - if(0 != udev->name) { - kfree(udev->name); - } + kfree(udev->name); kfree(udev); - } + } } module_init(uflash_init); diff --git a/drivers/mtd/maps/tqm834x.c b/drivers/mtd/maps/tqm834x.c new file mode 100644 index 0000000000000000000000000000000000000000..c7ae9a515c1aa1a1d3161933db1e4cae904a9c07 --- /dev/null +++ b/drivers/mtd/maps/tqm834x.c @@ -0,0 +1,291 @@ +/* + * drivers/mtd/maps/tqm834x.c + * + * MTD mapping driver for TQM834x boards + * + * Copyright 2005 Wolfgang Denk, DENX Software Engineering, . + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define FLASH_BANK_MAX 2 + +extern unsigned char __res[]; + +/* trivial struct to describe partition information */ +struct mtd_part_def +{ + int nums; + unsigned char *type; + struct mtd_partition* mtd_part; +}; + +static struct mtd_info* mtd_banks[FLASH_BANK_MAX]; +static struct map_info* map_banks[FLASH_BANK_MAX]; +static struct mtd_part_def part_banks[FLASH_BANK_MAX]; + +static unsigned long num_banks; +static unsigned long start_scan_addr; + +#ifdef CONFIG_MTD_PARTITIONS +/* + * The following defines the partition layout of TQM834x boards. + * + * See include/linux/mtd/partitions.h for definition of the + * mtd_partition structure. + * + * Assume minimal initial size of 4 MiB per bank, will be updated + * later in init_tqm834x_mtd() routine. + */ + +/* Partition definition for the first flash bank which is always present. */ +static struct mtd_partition tqm834x_partitions_bank1[] = { + { + .name = "u-boot", /* u-boot firmware */ + .offset = 0x00000000, + .size = 0x00040000, /* 256 KiB */ + /*mask_flags: MTD_WRITEABLE, * force read-only */ + }, + { + .name = "env", /* u-boot environment */ + .offset = 0x00040000, + .size = 0x00020000, /* 128 KiB */ + /*mask_flags: MTD_WRITEABLE, * force read-only */ + }, + { + .name = "kernel", /* linux kernel image */ + .offset = 0x00060000, + .size = 0x00100000, /* 1 MiB */ + /*mask_flags: MTD_WRITEABLE, * force read-only */ + }, + { + .name = "initrd", /* ramdisk image */ + .offset = 0x00160000, + .size = 0x00200000, /* 2 MiB */ + }, + { + .name = "user", /* user data */ + .offset = 0x00360000, + .size = 0x000a0000, /* remaining space */ + /* NOTE: this parttion size is re-calcated in */ + /* init_tqm834x_mtd() to cover actual remaining space. */ + }, +}; + +/* Partition definition for the second flash bank which may be present on some + * TQM834x boards. + */ +static struct mtd_partition tqm834x_partitions_bank2[] = { + { + .name = "jffs2", /* jffs2 filesystem */ + .offset = 0x00000000, + .size = 0x00400000, /* whole device */ + /* NOTE: this parttion size is re-calcated in */ + /* init_tqm834x_mtd() to cover actual device size. */ + }, +}; + +#endif /* CONFIG_MTD_PARTITIONS */ + +static int __init init_tqm834x_mtd(void) +{ + int idx = 0, ret = 0; + unsigned long flash_addr, flash_size, mtd_size = 0; + + /* pointer to TQM834x board info data */ + bd_t *bd = (bd_t *)__res; +#ifdef CONFIG_MTD_CMDLINE_PARTS + int n; + char mtdid[4]; + const char *part_probes[] = { "cmdlinepart", NULL }; +#endif + + flash_addr = bd->bi_flashstart; + flash_size = bd->bi_flashsize; + + /* request maximum flash size address space */ + start_scan_addr = (unsigned long)ioremap(flash_addr, flash_size); + if (!start_scan_addr) { + printk("%s: Failed to ioremap address: 0x%lx\n", + __FUNCTION__, flash_addr); + return -EIO; + } + + for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { + if (mtd_size >= flash_size) + break; + + pr_debug("%s: chip probing count %d\n", __FUNCTION__, idx); + + map_banks[idx] = + (struct map_info *)kmalloc(sizeof(struct map_info), + GFP_KERNEL); + if (map_banks[idx] == NULL) { + ret = -ENOMEM; + goto error_mem; + } + memset((void *)map_banks[idx], 0, sizeof(struct map_info)); + map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL); + if (map_banks[idx]->name == NULL) { + ret = -ENOMEM; + goto error_mem; + } + memset((void *)map_banks[idx]->name, 0, 16); + + sprintf(map_banks[idx]->name, "TQM834x-%d", idx); + map_banks[idx]->size = flash_size; + map_banks[idx]->bankwidth = 4; + + simple_map_init(map_banks[idx]); + + map_banks[idx]->virt = (void __iomem *) + (start_scan_addr + ((idx > 0) ? + (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0)); + map_banks[idx]->phys = + flash_addr + ((idx > 0) ? + (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0); + + /* start to probe flash chips */ + mtd_banks[idx] = do_map_probe("cfi_probe", map_banks[idx]); + if (mtd_banks[idx]) { + mtd_banks[idx]->owner = THIS_MODULE; + mtd_size += mtd_banks[idx]->size; + num_banks++; + pr_debug("%s: bank %ld, name: %s, size: %d bytes \n", + __FUNCTION__, num_banks, + mtd_banks[idx]->name, mtd_banks[idx]->size); + } + } + + /* no supported flash chips found */ + if (!num_banks) { + printk("TQM834x: No supported flash chips found!\n"); + ret = -ENXIO; + goto error_mem; + } + +#ifdef CONFIG_MTD_PARTITIONS + /* + * Select static partition definitions + */ + n = ARRAY_SIZE(tqm834x_partitions_bank1); + part_banks[0].mtd_part = tqm834x_partitions_bank1; + part_banks[0].type = "static image bank1"; + part_banks[0].nums = n; + + /* update last partition size to cover actual remaining space */ + tqm834x_partitions_bank1[n - 1].size = + mtd_banks[0]->size - + tqm834x_partitions_bank1[n - 1].offset; + + /* check if we have second bank? */ + if (num_banks == 2) { + n = ARRAY_SIZE(tqm834x_partitions_bank2); + part_banks[1].mtd_part = tqm834x_partitions_bank2; + part_banks[1].type = "static image bank2"; + part_banks[1].nums = n; + + /* update last partition size to cover actual remaining space */ + tqm834x_partitions_bank2[n - 1].size = + mtd_banks[1]->size - + tqm834x_partitions_bank2[n - 1].offset; + } + + for(idx = 0; idx < num_banks ; idx++) { +#ifdef CONFIG_MTD_CMDLINE_PARTS + sprintf(mtdid, "%d", idx); + n = parse_mtd_partitions(mtd_banks[idx], + part_probes, + &part_banks[idx].mtd_part, + 0); + pr_debug("%s: %d command line partitions on bank %s\n", + __FUNCTION__, n, mtdid); + if (n > 0) { + part_banks[idx].type = "command line"; + part_banks[idx].nums = n; + } +#endif /* CONFIG_MTD_CMDLINE_PARTS */ + if (part_banks[idx].nums == 0) { + printk(KERN_NOTICE + "TQM834x flash bank %d: no partition info " + "available, registering whole device\n", idx); + add_mtd_device(mtd_banks[idx]); + } else { + printk(KERN_NOTICE + "TQM834x flash bank %d: Using %s partition " + "definition\n", idx, part_banks[idx].type); + add_mtd_partitions(mtd_banks[idx], + part_banks[idx].mtd_part, + part_banks[idx].nums); + } + } +#else /* ! CONFIG_MTD_PARTITIONS */ + printk(KERN_NOTICE "TQM834x flash: registering %d flash banks " + "at once\n", num_banks); + + for(idx = 0 ; idx < num_banks ; idx++) + add_mtd_device(mtd_banks[idx]); + +#endif /* CONFIG_MTD_PARTITIONS */ + + return 0; +error_mem: + for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { + if (map_banks[idx] != NULL) { + if (map_banks[idx]->name != NULL) { + kfree(map_banks[idx]->name); + map_banks[idx]->name = NULL; + } + kfree(map_banks[idx]); + map_banks[idx] = NULL; + } + } + + iounmap((void *)start_scan_addr); + + return ret; +} + +static void __exit cleanup_tqm834x_mtd(void) +{ + unsigned int idx = 0; + for(idx = 0 ; idx < num_banks ; idx++) { + /* destroy mtd_info previously allocated */ + if (mtd_banks[idx]) { + del_mtd_partitions(mtd_banks[idx]); + map_destroy(mtd_banks[idx]); + } + + /* release map_info not used anymore */ + kfree(map_banks[idx]->name); + kfree(map_banks[idx]); + } + + if (start_scan_addr) { + iounmap((void *)start_scan_addr); + start_scan_addr = 0; + } +} + +module_init(init_tqm834x_mtd); +module_exit(cleanup_tqm834x_mtd); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Wolfgang Denk "); +MODULE_DESCRIPTION("MTD map driver for TQM834x boards"); diff --git a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c index 4e28b977f224120db3c5dc5d278c3593081accfb..a43517053e7cfe4819a51f0c1974ffc767ef8251 100644 --- a/drivers/mtd/maps/tqm8xxl.c +++ b/drivers/mtd/maps/tqm8xxl.c @@ -1,15 +1,15 @@ /* - * Handle mapping of the flash memory access routines + * Handle mapping of the flash memory access routines * on TQM8xxL based devices. * - * $Id: tqm8xxl.c,v 1.13 2004/10/20 22:21:53 dwmw2 Exp $ + * $Id: tqm8xxl.c,v 1.15 2005/11/07 11:14:28 gleixner Exp $ * * based on rpxlite.c * * Copyright(C) 2001 Kirk Lee * * This code is GPLed - * + * */ /* @@ -19,7 +19,7 @@ * 2MiB 512Kx16 2MiB 0 * 4MiB 1Mx16 4MiB 0 * 8MiB 1Mx16 4MiB 4MiB - * Thus, we choose CONFIG_MTD_CFI_I2 & CONFIG_MTD_CFI_B4 at + * Thus, we choose CONFIG_MTD_CFI_I2 & CONFIG_MTD_CFI_B4 at * kernel configuration. */ #include @@ -58,9 +58,9 @@ static void __iomem *start_scan_addr; * Here are partition information for all known TQM8xxL series devices. * See include/linux/mtd/partitions.h for definition of the mtd_partition * structure. - * + * * The *_max_flash_size is the maximum possible mapped flash size which - * is not necessarily the actual flash size. It must correspond to the + * is not necessarily the actual flash size. It must correspond to the * value specified in the mapping definition defined by the * "struct map_desc *_io_desc" for the corresponding machine. */ @@ -132,9 +132,9 @@ int __init init_tqm_mtd(void) for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { if(mtd_size >= flash_size) break; - + printk(KERN_INFO "%s: chip probing count %d\n", __FUNCTION__, idx); - + map_banks[idx] = (struct map_info *)kmalloc(sizeof(struct map_info), GFP_KERNEL); if(map_banks[idx] == NULL) { ret = -ENOMEM; @@ -180,7 +180,7 @@ int __init init_tqm_mtd(void) mtd_size += mtd_banks[idx]->size; num_banks++; - printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks, + printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks, mtd_banks[idx]->name, mtd_banks[idx]->size); } } @@ -211,7 +211,7 @@ int __init init_tqm_mtd(void) } else { printk(KERN_NOTICE "TQM flash%d: Using %s partition definition\n", idx, part_banks[idx].type); - add_mtd_partitions(mtd_banks[idx], part_banks[idx].mtd_part, + add_mtd_partitions(mtd_banks[idx], part_banks[idx].mtd_part, part_banks[idx].nums); } } @@ -224,10 +224,8 @@ int __init init_tqm_mtd(void) error_mem: for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { if(map_banks[idx] != NULL) { - if(map_banks[idx]->name != NULL) { - kfree(map_banks[idx]->name); - map_banks[idx]->name = NULL; - } + kfree(map_banks[idx]->name); + map_banks[idx]->name = NULL; kfree(map_banks[idx]); map_banks[idx] = NULL; } diff --git a/drivers/mtd/maps/ts5500_flash.c b/drivers/mtd/maps/ts5500_flash.c index 3ebd90f5650331e730ea7d9bdf8b71e470ed7ae3..4b372bcb17f1c0b6dbd5ec3312aa59edbb97f7dd 100644 --- a/drivers/mtd/maps/ts5500_flash.c +++ b/drivers/mtd/maps/ts5500_flash.c @@ -19,26 +19,22 @@ * * Note: * - In order for detection to work, jumper 3 must be set. - * - Drive A and B use a proprietary FTL from General Software which isn't - * supported as of yet so standard drives can't be mounted; you can create - * your own (e.g. jffs) file system. - * - If you have created your own jffs file system and the bios overwrites + * - Drive A and B use the resident flash disk (RFD) flash translation layer. + * - If you have created your own jffs file system and the bios overwrites * it during boot, try disabling Drive A: and B: in the boot order. * - * $Id: ts5500_flash.c,v 1.2 2004/11/28 09:40:40 dwmw2 Exp $ + * $Id: ts5500_flash.c,v 1.5 2005/11/07 11:14:28 gleixner Exp $ */ #include +#include #include -#include #include -#include -#include #include - -#ifdef CONFIG_MTD_PARTITIONS +#include #include -#endif +#include + #define WINDOW_ADDR 0x09400000 #define WINDOW_SIZE 0x00200000 @@ -50,7 +46,6 @@ static struct map_info ts5500_map = { .phys = WINDOW_ADDR }; -#ifdef CONFIG_MTD_PARTITIONS static struct mtd_partition ts5500_partitions[] = { { .name = "Drive A", @@ -71,8 +66,6 @@ static struct mtd_partition ts5500_partitions[] = { #define NUM_PARTITIONS (sizeof(ts5500_partitions)/sizeof(struct mtd_partition)) -#endif - static struct mtd_info *mymtd; static int __init init_ts5500_map(void) @@ -81,48 +74,39 @@ static int __init init_ts5500_map(void) ts5500_map.virt = ioremap_nocache(ts5500_map.phys, ts5500_map.size); - if(!ts5500_map.virt) { + if (!ts5500_map.virt) { printk(KERN_ERR "Failed to ioremap_nocache\n"); rc = -EIO; - goto err_out_ioremap; + goto err2; } simple_map_init(&ts5500_map); mymtd = do_map_probe("jedec_probe", &ts5500_map); - if(!mymtd) + if (!mymtd) mymtd = do_map_probe("map_rom", &ts5500_map); - if(!mymtd) { + if (!mymtd) { rc = -ENXIO; - goto err_out_map; + goto err1; } mymtd->owner = THIS_MODULE; -#ifdef CONFIG_MTD_PARTITIONS add_mtd_partitions(mymtd, ts5500_partitions, NUM_PARTITIONS); -#else - add_mtd_device(mymtd); -#endif return 0; -err_out_map: +err1: map_destroy(mymtd); -err_out_ioremap: iounmap(ts5500_map.virt); - +err2: return rc; } static void __exit cleanup_ts5500_map(void) { if (mymtd) { -#ifdef CONFIG_MTD_PARTITIONS del_mtd_partitions(mymtd); -#else - del_mtd_device(mymtd); -#endif map_destroy(mymtd); } diff --git a/drivers/mtd/maps/tsunami_flash.c b/drivers/mtd/maps/tsunami_flash.c index 170d71239e5ed5d4b776244857b7f3e7ab081a5a..9e21e6c02f80df8af03aec9fdd9f0d8cd6cfd062 100644 --- a/drivers/mtd/maps/tsunami_flash.c +++ b/drivers/mtd/maps/tsunami_flash.c @@ -2,7 +2,7 @@ * tsunami_flash.c * * flash chip on alpha ds10... - * $Id: tsunami_flash.c,v 1.9 2004/07/14 09:52:55 dwmw2 Exp $ + * $Id: tsunami_flash.c,v 1.10 2005/11/07 11:14:29 gleixner Exp $ */ #include #include @@ -41,7 +41,7 @@ static void tsunami_flash_copy_from( } static void tsunami_flash_copy_to( - struct map_info *map, unsigned long offset, + struct map_info *map, unsigned long offset, const void *addr, ssize_t len) { const unsigned char *src; @@ -90,7 +90,7 @@ static int __init init_tsunami_flash(void) char **type; tsunami_tig_writeb(FLASH_ENABLE_BYTE, FLASH_ENABLE_PORT); - + tsunami_flash_mtd = 0; type = rom_probe_types; for(; !tsunami_flash_mtd && *type; type++) { diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c index cc372136e852750f87f42dd3d69c0d917d074908..79d92808b766fea1f006faedb5fb0d914d712238 100644 --- a/drivers/mtd/maps/uclinux.c +++ b/drivers/mtd/maps/uclinux.c @@ -5,7 +5,7 @@ * * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) * - * $Id: uclinux.c,v 1.10 2005/01/05 18:05:13 dwmw2 Exp $ + * $Id: uclinux.c,v 1.12 2005/11/07 11:14:29 gleixner Exp $ */ /****************************************************************************/ @@ -82,7 +82,7 @@ int __init uclinux_mtd_init(void) iounmap(mapp->virt); return(-ENXIO); } - + mtd->owner = THIS_MODULE; mtd->point = uclinux_point; mtd->priv = mapp; diff --git a/drivers/mtd/maps/vmax301.c b/drivers/mtd/maps/vmax301.c index c8c74110ed1b561b7fde5b32fefb4fbb131417cb..e0063941c0df3090e71363c8325ef263d8d40ba8 100644 --- a/drivers/mtd/maps/vmax301.c +++ b/drivers/mtd/maps/vmax301.c @@ -1,19 +1,19 @@ -// $Id: vmax301.c,v 1.30 2004/07/12 22:38:29 dwmw2 Exp $ +// $Id: vmax301.c,v 1.32 2005/11/07 11:14:29 gleixner Exp $ /* ###################################################################### Tempustech VMAX SBC301 MTD Driver. - + The VMAx 301 is a SBC based on . It comes with three builtin AMD 29F016B flash chips and a socket for SRAM or - more flash. Each unit has it's own 8k mapping into a settable region + more flash. Each unit has it's own 8k mapping into a settable region (0xD8000). There are two 8k mappings for each MTD, the first is always set to the lower 8k of the device the second is paged. Writing a 16 bit page value to anywhere in the first 8k will cause the second 8k to page around. - To boot the device a bios extension must be installed into the first 8k - of flash that is smart enough to copy itself down, page in the rest of + To boot the device a bios extension must be installed into the first 8k + of flash that is smart enough to copy itself down, page in the rest of itself and begin executing. - + ##################################################################### */ #include @@ -35,7 +35,7 @@ /* Actually we could use two spinlocks, but we'd have to have more private space in the struct map_info. We lose a little performance like this, but we'd probably lose more by having - the extra indirection from having one of the map->map_priv + the extra indirection from having one of the map->map_priv fields pointing to yet another private struct. */ static DEFINE_SPINLOCK(vmax301_spin); @@ -98,7 +98,7 @@ static void vmax301_copy_to(struct map_info *map, unsigned long to, const void * spin_lock(&vmax301_spin); vmax301_page(map, to); memcpy_toio(map->map_priv_2 + to, from, thislen); - spin_unlock(&vmax301_spin); + spin_unlock(&vmax301_spin); to += thislen; from += thislen; len -= thislen; @@ -137,7 +137,7 @@ static struct mtd_info *vmax_mtd[2] = {NULL, NULL}; static void __exit cleanup_vmax301(void) { int i; - + for (i=0; i<2; i++) { if (vmax_mtd[i]) { del_mtd_device(vmax_mtd[i]); @@ -161,13 +161,13 @@ int __init init_vmax301(void) return -EIO; } /* Put the address in the map's private data area. - We store the actual MTD IO address rather than the + We store the actual MTD IO address rather than the address of the first half, because it's used more - often. + often. */ vmax_map[0].map_priv_2 = iomapadr + WINDOW_START; vmax_map[1].map_priv_2 = iomapadr + (3*WINDOW_START); - + for (i=0; i<2; i++) { vmax_mtd[i] = do_map_probe("cfi_probe", &vmax_map[i]); if (!vmax_mtd[i]) diff --git a/drivers/mtd/maps/walnut.c b/drivers/mtd/maps/walnut.c index d6137b1b567025c667a6f4f37361baca533f07bb..5c17bca3a37e0d52e981b65ec638e59d75524b06 100644 --- a/drivers/mtd/maps/walnut.c +++ b/drivers/mtd/maps/walnut.c @@ -1,12 +1,12 @@ /* - * $Id: walnut.c,v 1.2 2004/12/10 12:07:42 holindho Exp $ - * + * $Id: walnut.c,v 1.3 2005/11/07 11:14:29 gleixner Exp $ + * * Mapping for Walnut flash * (used ebony.c as a "framework") - * + * * Heikki Lindholm - * - * + * + * * 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 @@ -48,7 +48,7 @@ static struct mtd_partition walnut_partitions[] = { .name = "OpenBIOS", .offset = 0x0, .size = WALNUT_FLASH_SIZE, - /*.mask_flags = MTD_WRITEABLE, */ /* force read-only */ + /*.mask_flags = MTD_WRITEABLE, */ /* force read-only */ } }; @@ -72,11 +72,11 @@ int __init init_walnut(void) printk("The on-board flash is disabled (U79 sw 5)!"); return -EIO; } - if (WALNUT_FLASH_SRAM_SEL(fpga_brds1)) + if (WALNUT_FLASH_SRAM_SEL(fpga_brds1)) flash_base = WALNUT_FLASH_LOW; else flash_base = WALNUT_FLASH_HIGH; - + walnut_map.phys = flash_base; walnut_map.virt = (void __iomem *)ioremap(flash_base, walnut_map.size); diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c index 82b887b05707127785d38a33e7d715394beae914..60c197ec455b87cf40b6ee20303fdb0fe3046610 100644 --- a/drivers/mtd/maps/wr_sbc82xx_flash.c +++ b/drivers/mtd/maps/wr_sbc82xx_flash.c @@ -1,5 +1,5 @@ /* - * $Id: wr_sbc82xx_flash.c,v 1.7 2004/11/04 13:24:15 gleixner Exp $ + * $Id: wr_sbc82xx_flash.c,v 1.8 2005/11/07 11:14:29 gleixner Exp $ * * Map for flash chips on Wind River PowerQUICC II SBC82xx board. * @@ -163,10 +163,10 @@ static void __exit cleanup_sbc82xx_flash(void) del_mtd_partitions(sbcmtd[i]); else del_mtd_device(sbcmtd[i]); - + kfree(sbcmtd_parts[i]); map_destroy(sbcmtd[i]); - + iounmap((void *)sbc82xx_flash_map[i].virt); sbc82xx_flash_map[i].virt = 0; } diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index f8d2185819e7e2e17348b0c3fd8b0c2b41208d44..339cb1218eaa0b9d7e7431f069ec89a354051873 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -1,5 +1,5 @@ /* - * $Id: mtd_blkdevs.c,v 1.24 2004/11/16 18:28:59 dwmw2 Exp $ + * $Id: mtd_blkdevs.c,v 1.27 2005/11/07 11:14:20 gleixner Exp $ * * (C) 2003 David Woodhouse * @@ -21,7 +21,6 @@ #include #include #include -#include static LIST_HEAD(blktrans_majors); @@ -86,7 +85,7 @@ static int mtd_blktrans_thread(void *arg) daemonize("%sd", tr->name); /* daemonize() doesn't do this for us since some kernel threads - actually want to deal with signals. We can't just call + actually want to deal with signals. We can't just call exit_sighand() since that'll cause an oops when we finally do exit. */ spin_lock_irq(¤t->sighand->siglock); @@ -95,7 +94,7 @@ static int mtd_blktrans_thread(void *arg) spin_unlock_irq(¤t->sighand->siglock); spin_lock_irq(rq->queue_lock); - + while (!tr->blkcore_priv->exiting) { struct request *req; struct mtd_blktrans_dev *dev; @@ -158,7 +157,7 @@ static int blktrans_open(struct inode *i, struct file *f) if (!try_module_get(tr->owner)) goto out_tr; - /* FIXME: Locking. A hot pluggable device can go away + /* FIXME: Locking. A hot pluggable device can go away (del_mtd_device can be called for it) without its module being unloaded. */ dev->mtd->usecount++; @@ -196,7 +195,7 @@ static int blktrans_release(struct inode *i, struct file *f) } -static int blktrans_ioctl(struct inode *inode, struct file *file, +static int blktrans_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct mtd_blktrans_dev *dev = inode->i_bdev->bd_disk->private_data; @@ -265,7 +264,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) /* Required number was free */ list_add_tail(&new->list, &d->list); goto added; - } + } last_devnum = d->devnum; } if (new->devnum == -1) @@ -289,11 +288,19 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) gd->major = tr->major; gd->first_minor = (new->devnum) << tr->part_bits; gd->fops = &mtd_blktrans_ops; - - snprintf(gd->disk_name, sizeof(gd->disk_name), - "%s%c", tr->name, (tr->part_bits?'a':'0') + new->devnum); - snprintf(gd->devfs_name, sizeof(gd->devfs_name), - "%s/%c", tr->name, (tr->part_bits?'a':'0') + new->devnum); + + if (tr->part_bits) + if (new->devnum < 26) + snprintf(gd->disk_name, sizeof(gd->disk_name), + "%s%c", tr->name, 'a' + new->devnum); + else + snprintf(gd->disk_name, sizeof(gd->disk_name), + "%s%c%c", tr->name, + 'a' - 1 + new->devnum / 26, + 'a' + new->devnum % 26); + else + snprintf(gd->disk_name, sizeof(gd->disk_name), + "%s%d", tr->name, new->devnum); /* 2.5 has capacity in units of 512 bytes while still having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */ @@ -307,7 +314,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) set_disk_ro(gd, 1); add_disk(gd); - + return 0; } @@ -322,7 +329,7 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) del_gendisk(old->blkcore_priv); put_disk(old->blkcore_priv); - + return 0; } @@ -361,12 +368,12 @@ static struct mtd_notifier blktrans_notifier = { .add = blktrans_notify_add, .remove = blktrans_notify_remove, }; - + int register_mtd_blktrans(struct mtd_blktrans_ops *tr) { int ret, i; - /* Register the notifier if/when the first device type is + /* Register the notifier if/when the first device type is registered, to prevent the link/init ordering from fucking us over. */ if (!blktrans_notifier.list.next) @@ -409,9 +416,7 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) kfree(tr->blkcore_priv); up(&mtd_table_mutex); return ret; - } - - devfs_mk_dir(tr->name); + } INIT_LIST_HEAD(&tr->devs); list_add(&tr->list, &blktrans_majors); @@ -445,7 +450,6 @@ int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr) tr->remove_dev(dev); } - devfs_remove(tr->name); blk_cleanup_queue(tr->blkcore_priv->rq); unregister_blkdev(tr->major, tr->name); diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index 400dd9c89883bb1462c85ae48646738abb8fb72b..e84756644fd1e1f5559a87406a6d71877c369bb8 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -1,21 +1,22 @@ -/* +/* * Direct MTD block device access * - * $Id: mtdblock.c,v 1.66 2004/11/25 13:52:52 joern Exp $ + * $Id: mtdblock.c,v 1.68 2005/11/07 11:14:20 gleixner Exp $ * * (C) 2000-2003 Nicolas Pitre * (C) 1999-2003 David Woodhouse */ #include -#include -#include -#include #include #include +#include +#include +#include #include +#include #include -#include /* TASK_* */ + #include #include @@ -31,7 +32,7 @@ static struct mtdblk_dev { /* * Cache stuff... - * + * * Since typical flash erasable sectors are much larger than what Linux's * buffer cache can handle, we must implement read-modify-write on flash * sectors for each block write requests. To avoid over-erasing flash sectors @@ -45,7 +46,7 @@ static void erase_callback(struct erase_info *done) wake_up(wait_q); } -static int erase_write (struct mtd_info *mtd, unsigned long pos, +static int erase_write (struct mtd_info *mtd, unsigned long pos, int len, const char *buf) { struct erase_info erase; @@ -103,18 +104,18 @@ static int write_cached_data (struct mtdblk_dev *mtdblk) return 0; DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: writing cached data for \"%s\" " - "at 0x%lx, size 0x%x\n", mtd->name, + "at 0x%lx, size 0x%x\n", mtd->name, mtdblk->cache_offset, mtdblk->cache_size); - - ret = erase_write (mtd, mtdblk->cache_offset, + + ret = erase_write (mtd, mtdblk->cache_offset, mtdblk->cache_size, mtdblk->cache_data); if (ret) return ret; /* * Here we could argubly set the cache state to STATE_CLEAN. - * However this could lead to inconsistency since we will not - * be notified if this content is altered on the flash by other + * However this could lead to inconsistency since we will not + * be notified if this content is altered on the flash by other * means. Let's declare it empty and leave buffering tasks to * the buffer cache instead. */ @@ -123,7 +124,7 @@ static int write_cached_data (struct mtdblk_dev *mtdblk) } -static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, +static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, int len, const char *buf) { struct mtd_info *mtd = mtdblk->mtd; @@ -133,7 +134,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n", mtd->name, pos, len); - + if (!sect_size) return MTD_WRITE (mtd, pos, len, &retlen, buf); @@ -141,11 +142,11 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, unsigned long sect_start = (pos/sect_size)*sect_size; unsigned int offset = pos - sect_start; unsigned int size = sect_size - offset; - if( size > len ) + if( size > len ) size = len; if (size == sect_size) { - /* + /* * We are covering a whole sector. Thus there is no * need to bother with the cache while it may still be * useful for other partial writes. @@ -159,7 +160,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, if (mtdblk->cache_state == STATE_DIRTY && mtdblk->cache_offset != sect_start) { ret = write_cached_data(mtdblk); - if (ret) + if (ret) return ret; } @@ -192,7 +193,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, } -static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, +static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, int len, char *buf) { struct mtd_info *mtd = mtdblk->mtd; @@ -200,9 +201,9 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, size_t retlen; int ret; - DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n", + DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n", mtd->name, pos, len); - + if (!sect_size) return MTD_READ (mtd, pos, len, &retlen, buf); @@ -210,7 +211,7 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, unsigned long sect_start = (pos/sect_size)*sect_size; unsigned int offset = pos - sect_start; unsigned int size = sect_size - offset; - if (size > len) + if (size > len) size = len; /* @@ -268,12 +269,12 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd) int dev = mbd->devnum; DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n"); - + if (mtdblks[dev]) { mtdblks[dev]->count++; return 0; } - + /* OK, it's not open. Create cache info for it */ mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL); if (!mtdblk) @@ -292,7 +293,7 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd) } mtdblks[dev] = mtdblk; - + DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); return 0; @@ -320,7 +321,7 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd) DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); return 0; -} +} static int mtdblock_flush(struct mtd_blktrans_dev *dev) { diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 16df1e4fb0e94d2efec9542e6114f0593c3ad3bf..6f044584bdc6ac3b38c4a20949bfcbabb5f292ae 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -1,22 +1,23 @@ /* - * $Id: mtdchar.c,v 1.73 2005/07/04 17:36:41 gleixner Exp $ + * $Id: mtdchar.c,v 1.76 2005/11/07 11:14:20 gleixner Exp $ * * Character-device access to raw MTD devices. * */ #include +#include +#include +#include #include #include +#include +#include + #include #include -#include -#include -#include -#include /* TASK_* */ -#include -#include +#include static struct class *mtd_class; @@ -27,7 +28,7 @@ static void mtd_notify_add(struct mtd_info* mtd) class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), NULL, "mtd%d", mtd->index); - + class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), NULL, "mtd%dro", mtd->index); @@ -70,26 +71,23 @@ static loff_t mtd_lseek (struct file *file, loff_t offset, int orig) switch (orig) { case 0: /* SEEK_SET */ - file->f_pos = offset; break; case 1: /* SEEK_CUR */ - file->f_pos += offset; + offset += file->f_pos; break; case 2: /* SEEK_END */ - file->f_pos =mtd->size + offset; + offset += mtd->size; break; default: return -EINVAL; } - if (file->f_pos < 0) - file->f_pos = 0; - else if (file->f_pos >= mtd->size) - file->f_pos = mtd->size - 1; + if (offset >= 0 && offset < mtd->size) + return file->f_pos = offset; - return file->f_pos; + return -EINVAL; } @@ -110,23 +108,23 @@ static int mtd_open(struct inode *inode, struct file *file) return -EACCES; mtd = get_mtd_device(NULL, devnum); - + if (!mtd) return -ENODEV; - + if (MTD_ABSENT == mtd->type) { put_mtd_device(mtd); return -ENODEV; } file->private_data = mtd; - + /* You can't open it RW if it's not a writeable device */ if ((file->f_mode & 2) && !(mtd->flags & MTD_WRITEABLE)) { put_mtd_device(mtd); return -EACCES; } - + return 0; } /* mtd_open */ @@ -139,10 +137,10 @@ static int mtd_close(struct inode *inode, struct file *file) DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n"); mtd = TO_MTD(file); - + if (mtd->sync) mtd->sync(mtd); - + put_mtd_device(mtd); return 0; @@ -161,7 +159,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t int ret=0; int len; char *kbuf; - + DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n"); if (*ppos + count > mtd->size) @@ -169,11 +167,11 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t if (!count) return 0; - + /* FIXME: Use kiovec in 2.5 to lock down the user's buffers and pass them directly to the MTD functions */ while (count) { - if (count > MAX_KMALLOC_SIZE) + if (count > MAX_KMALLOC_SIZE) len = MAX_KMALLOC_SIZE; else len = count; @@ -181,7 +179,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t kbuf=kmalloc(len,GFP_KERNEL); if (!kbuf) return -ENOMEM; - + switch (MTD_MODE(file)) { case MTD_MODE_OTP_FACT: ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf); @@ -194,7 +192,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t } /* Nand returns -EBADMSG on ecc errors, but it returns * the data. For our userspace tools it is important - * to dump areas with ecc errors ! + * to dump areas with ecc errors ! * Userspace software which accesses NAND this way * must be aware of the fact that it deals with NAND */ @@ -216,7 +214,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t kfree(kbuf); return ret; } - + kfree(kbuf); } @@ -233,10 +231,10 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count int len; DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n"); - + if (*ppos == mtd->size) return -ENOSPC; - + if (*ppos + count > mtd->size) count = mtd->size - *ppos; @@ -244,7 +242,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count return 0; while (count) { - if (count > MAX_KMALLOC_SIZE) + if (count > MAX_KMALLOC_SIZE) len = MAX_KMALLOC_SIZE; else len = count; @@ -259,7 +257,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count kfree(kbuf); return -EFAULT; } - + switch (MTD_MODE(file)) { case MTD_MODE_OTP_FACT: ret = -EROFS; @@ -284,7 +282,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count kfree(kbuf); return ret; } - + kfree(kbuf); } @@ -308,7 +306,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, void __user *argp = (void __user *)arg; int ret = 0; u_long size; - + DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n"); size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; @@ -320,7 +318,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, if (!access_ok(VERIFY_WRITE, argp, size)) return -EFAULT; } - + switch (cmd) { case MEMGETREGIONCOUNT: if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int))) @@ -372,11 +370,11 @@ static int mtd_ioctl(struct inode *inode, struct file *file, erase->mtd = mtd; erase->callback = mtdchar_erase_callback; erase->priv = (unsigned long)&waitq; - + /* FIXME: Allow INTERRUPTIBLE. Which means not having the wait_queue head on the stack. - + If the wq_head is on the stack, and we leave because we got interrupted, then the wq_head is no longer there when the @@ -404,13 +402,13 @@ static int mtd_ioctl(struct inode *inode, struct file *file, struct mtd_oob_buf buf; void *databuf; ssize_t retlen; - + if(!(file->f_mode & 2)) return -EPERM; if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) return -EFAULT; - + if (buf.length > 0x4096) return -EINVAL; @@ -426,7 +424,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, databuf = kmalloc(buf.length, GFP_KERNEL); if (!databuf) return -ENOMEM; - + if (copy_from_user(databuf, buf.ptr, buf.length)) { kfree(databuf); return -EFAULT; @@ -450,7 +448,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) return -EFAULT; - + if (buf.length > 0x4096) return -EINVAL; @@ -466,14 +464,14 @@ static int mtd_ioctl(struct inode *inode, struct file *file, databuf = kmalloc(buf.length, GFP_KERNEL); if (!databuf) return -ENOMEM; - + ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf); if (put_user(retlen, (uint32_t __user *)argp)) ret = -EFAULT; else if (retlen && copy_to_user(buf.ptr, databuf, retlen)) ret = -EFAULT; - + kfree(databuf); break; } @@ -523,7 +521,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, case MEMGETBADBLOCK: { loff_t offs; - + if (copy_from_user(&offs, argp, sizeof(loff_t))) return -EFAULT; if (!mtd->block_isbad) diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index f3e65af33a9c86d6338847ddb2b4c16ed5229774..b1bf8c411de78e6c7685d7cd8928e642dd1afeb5 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -7,14 +7,15 @@ * * This code is GPL * - * $Id: mtdconcat.c,v 1.9 2004/06/30 15:17:41 dbrown Exp $ + * $Id: mtdconcat.c,v 1.11 2005/11/07 11:14:20 gleixner Exp $ */ -#include -#include #include +#include #include -#include /* TASK_* */ +#include +#include + #include #include @@ -43,7 +44,7 @@ struct mtd_concat { */ #define CONCAT(x) ((struct mtd_concat *)(x)) -/* +/* * MTD methods which look up the relevant subdevice, translate the * effective address and pass through to the subdevice. */ @@ -877,7 +878,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c return &concat->mtd; } -/* +/* * This function destroys an MTD object obtained from concat_mtd_devs() */ diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index dc86df18e94b72768ce0d7beaaf06e629c9217a0..dade02ab0687aeee729a3e1c80339b5e27fbdf87 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -1,5 +1,5 @@ /* - * $Id: mtdcore.c,v 1.45 2005/02/18 14:34:50 dedekind Exp $ + * $Id: mtdcore.c,v 1.47 2005/11/07 11:14:20 gleixner Exp $ * * Core registration and callback routines for MTD * drivers and users. @@ -25,7 +25,7 @@ #include -/* These are exported solely for the purpose of mtd_blkdevs.c. You +/* These are exported solely for the purpose of mtd_blkdevs.c. You should not use them for _anything_ else */ DECLARE_MUTEX(mtd_table_mutex); struct mtd_info *mtd_table[MAX_MTD_DEVICES]; @@ -66,7 +66,7 @@ int add_mtd_device(struct mtd_info *mtd) struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list); not->add(mtd); } - + up(&mtd_table_mutex); /* We _know_ we aren't being removed, because our caller is still holding us here. So none @@ -75,7 +75,7 @@ int add_mtd_device(struct mtd_info *mtd) __module_get(THIS_MODULE); return 0; } - + up(&mtd_table_mutex); return 1; } @@ -93,13 +93,13 @@ int add_mtd_device(struct mtd_info *mtd) int del_mtd_device (struct mtd_info *mtd) { int ret; - + down(&mtd_table_mutex); if (mtd_table[mtd->index] != mtd) { ret = -ENODEV; } else if (mtd->usecount) { - printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n", + printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n", mtd->index, mtd->name, mtd->usecount); ret = -EBUSY; } else { @@ -140,7 +140,7 @@ void register_mtd_user (struct mtd_notifier *new) list_add(&new->list, &mtd_notifiers); __module_get(THIS_MODULE); - + for (i=0; i< MAX_MTD_DEVICES; i++) if (mtd_table[i]) new->add(mtd_table[i]); @@ -169,7 +169,7 @@ int unregister_mtd_user (struct mtd_notifier *old) for (i=0; i< MAX_MTD_DEVICES; i++) if (mtd_table[i]) old->remove(mtd_table[i]); - + list_del(&old->list); up(&mtd_table_mutex); return 0; @@ -187,7 +187,7 @@ int unregister_mtd_user (struct mtd_notifier *old) * both, return the num'th driver only if its address matches. Return NULL * if not. */ - + struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) { struct mtd_info *ret = NULL; @@ -296,39 +296,6 @@ EXPORT_SYMBOL(unregister_mtd_user); EXPORT_SYMBOL(default_mtd_writev); EXPORT_SYMBOL(default_mtd_readv); -/*====================================================================*/ -/* Power management code */ - -#ifdef CONFIG_PM - -#include - -static struct pm_dev *mtd_pm_dev = NULL; - -static int mtd_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) -{ - int ret = 0, i; - - if (down_trylock(&mtd_table_mutex)) - return -EAGAIN; - if (rqst == PM_SUSPEND) { - for (i = 0; ret == 0 && i < MAX_MTD_DEVICES; i++) { - if (mtd_table[i] && mtd_table[i]->suspend) - ret = mtd_table[i]->suspend(mtd_table[i]); - } - } else i = MAX_MTD_DEVICES-1; - - if (rqst == PM_RESUME || ret) { - for ( ; i >= 0; i--) { - if (mtd_table[i] && mtd_table[i]->resume) - mtd_table[i]->resume(mtd_table[i]); - } - } - up(&mtd_table_mutex); - return ret; -} -#endif - /*====================================================================*/ /* Support for /proc/mtd */ @@ -388,22 +355,11 @@ static int __init init_mtd(void) if ((proc_mtd = create_proc_entry( "mtd", 0, NULL ))) proc_mtd->read_proc = mtd_read_proc; #endif - -#ifdef CONFIG_PM - mtd_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, mtd_pm_callback); -#endif return 0; } static void __exit cleanup_mtd(void) { -#ifdef CONFIG_PM - if (mtd_pm_dev) { - pm_unregister(mtd_pm_dev); - mtd_pm_dev = NULL; - } -#endif - #ifdef CONFIG_PROC_FS if (proc_mtd) remove_proc_entry( "mtd", NULL); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index b92e6bfffaf2afa78cf3aad8fe38d7248509200c..99395911d26f73577999a62b3808e4456529bb92 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -5,11 +5,11 @@ * * This code is GPL * - * $Id: mtdpart.c,v 1.53 2005/02/08 17:11:13 nico Exp $ + * $Id: mtdpart.c,v 1.55 2005/11/07 11:14:20 gleixner Exp $ * * 02-21-2002 Thomas Gleixner * added support for read_oob, write_oob - */ + */ #include #include @@ -41,13 +41,13 @@ struct mtd_part { */ #define PART(x) ((struct mtd_part *)(x)) - -/* + +/* * MTD methods which simply translate the effective address and pass through * to the _real_ device. */ -static int part_read (struct mtd_info *mtd, loff_t from, size_t len, +static int part_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct mtd_part *part = PART(mtd); @@ -55,15 +55,15 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len, len = 0; else if (from + len > mtd->size) len = mtd->size - from; - if (part->master->read_ecc == NULL) - return part->master->read (part->master, from + part->offset, + if (part->master->read_ecc == NULL) + return part->master->read (part->master, from + part->offset, len, retlen, buf); else - return part->master->read_ecc (part->master, from + part->offset, + return part->master->read_ecc (part->master, from + part->offset, len, retlen, buf, NULL, &mtd->oobinfo); } -static int part_point (struct mtd_info *mtd, loff_t from, size_t len, +static int part_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **buf) { struct mtd_part *part = PART(mtd); @@ -71,7 +71,7 @@ static int part_point (struct mtd_info *mtd, loff_t from, size_t len, len = 0; else if (from + len > mtd->size) len = mtd->size - from; - return part->master->point (part->master, from + part->offset, + return part->master->point (part->master, from + part->offset, len, retlen, buf); } static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) @@ -82,7 +82,7 @@ static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_ } -static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, +static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel) { struct mtd_part *part = PART(mtd); @@ -92,11 +92,11 @@ static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, len = 0; else if (from + len > mtd->size) len = mtd->size - from; - return part->master->read_ecc (part->master, from + part->offset, + return part->master->read_ecc (part->master, from + part->offset, len, retlen, buf, eccbuf, oobsel); } -static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, +static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct mtd_part *part = PART(mtd); @@ -104,15 +104,15 @@ static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, len = 0; else if (from + len > mtd->size) len = mtd->size - from; - return part->master->read_oob (part->master, from + part->offset, + return part->master->read_oob (part->master, from + part->offset, len, retlen, buf); } -static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, +static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct mtd_part *part = PART(mtd); - return part->master->read_user_prot_reg (part->master, from, + return part->master->read_user_prot_reg (part->master, from, len, retlen, buf); } @@ -123,11 +123,11 @@ static int part_get_user_prot_info (struct mtd_info *mtd, return part->master->get_user_prot_info (part->master, buf, len); } -static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, +static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct mtd_part *part = PART(mtd); - return part->master->read_fact_prot_reg (part->master, from, + return part->master->read_fact_prot_reg (part->master, from, len, retlen, buf); } @@ -148,13 +148,13 @@ static int part_write (struct mtd_info *mtd, loff_t to, size_t len, len = 0; else if (to + len > mtd->size) len = mtd->size - to; - if (part->master->write_ecc == NULL) - return part->master->write (part->master, to + part->offset, + if (part->master->write_ecc == NULL) + return part->master->write (part->master, to + part->offset, len, retlen, buf); else - return part->master->write_ecc (part->master, to + part->offset, + return part->master->write_ecc (part->master, to + part->offset, len, retlen, buf, NULL, &mtd->oobinfo); - + } static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, @@ -170,7 +170,7 @@ static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, len = 0; else if (to + len > mtd->size) len = mtd->size - to; - return part->master->write_ecc (part->master, to + part->offset, + return part->master->write_ecc (part->master, to + part->offset, len, retlen, buf, eccbuf, oobsel); } @@ -184,19 +184,19 @@ static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len, len = 0; else if (to + len > mtd->size) len = mtd->size - to; - return part->master->write_oob (part->master, to + part->offset, + return part->master->write_oob (part->master, to + part->offset, len, retlen, buf); } -static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, +static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct mtd_part *part = PART(mtd); - return part->master->write_user_prot_reg (part->master, from, + return part->master->write_user_prot_reg (part->master, from, len, retlen, buf); } -static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len) +static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len) { struct mtd_part *part = PART(mtd); return part->master->lock_user_prot_reg (part->master, from, len); @@ -208,7 +208,7 @@ static int part_writev (struct mtd_info *mtd, const struct kvec *vecs, struct mtd_part *part = PART(mtd); if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; - if (part->master->writev_ecc == NULL) + if (part->master->writev_ecc == NULL) return part->master->writev (part->master, vecs, count, to + part->offset, retlen); else @@ -221,12 +221,12 @@ static int part_readv (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, size_t *retlen) { struct mtd_part *part = PART(mtd); - if (part->master->readv_ecc == NULL) + if (part->master->readv_ecc == NULL) return part->master->readv (part->master, vecs, count, from + part->offset, retlen); else return part->master->readv_ecc (part->master, vecs, count, - from + part->offset, retlen, + from + part->offset, retlen, NULL, &mtd->oobinfo); } @@ -252,7 +252,7 @@ static int part_readv_ecc (struct mtd_info *mtd, struct kvec *vecs, if (oobsel == NULL) oobsel = &mtd->oobinfo; return part->master->readv_ecc (part->master, vecs, count, - from + part->offset, retlen, + from + part->offset, retlen, eccbuf, oobsel); } @@ -286,7 +286,7 @@ EXPORT_SYMBOL_GPL(mtd_erase_callback); static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len) { struct mtd_part *part = PART(mtd); - if ((len + ofs) > mtd->size) + if ((len + ofs) > mtd->size) return -EINVAL; return part->master->lock(part->master, ofs + part->offset, len); } @@ -294,7 +294,7 @@ static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len) static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len) { struct mtd_part *part = PART(mtd); - if ((len + ofs) > mtd->size) + if ((len + ofs) > mtd->size) return -EINVAL; return part->master->unlock(part->master, ofs + part->offset, len); } @@ -337,8 +337,8 @@ static int part_block_markbad (struct mtd_info *mtd, loff_t ofs) return part->master->block_markbad(part->master, ofs); } -/* - * This function unregisters and destroy all slave MTD objects which are +/* + * This function unregisters and destroy all slave MTD objects which are * attached to the given master MTD object. */ @@ -371,7 +371,7 @@ int del_mtd_partitions(struct mtd_info *master) * (Q: should we register the master MTD object as well?) */ -int add_mtd_partitions(struct mtd_info *master, +int add_mtd_partitions(struct mtd_info *master, const struct mtd_partition *parts, int nbparts) { @@ -414,7 +414,7 @@ int add_mtd_partitions(struct mtd_info *master, slave->mtd.point = part_point; slave->mtd.unpoint = part_unpoint; } - + if (master->read_ecc) slave->mtd.read_ecc = part_read_ecc; if (master->write_ecc) @@ -465,9 +465,10 @@ int add_mtd_partitions(struct mtd_info *master, if (slave->offset == MTDPART_OFS_APPEND) slave->offset = cur_offset; if (slave->offset == MTDPART_OFS_NXTBLK) { - u_int32_t emask = master->erasesize-1; - slave->offset = (cur_offset + emask) & ~emask; - if (slave->offset != cur_offset) { + slave->offset = cur_offset; + if ((cur_offset % master->erasesize) != 0) { + /* Round up to next erasesize */ + slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize; printk(KERN_NOTICE "Moving partition %d: " "0x%08x -> 0x%08x\n", i, cur_offset, slave->offset); @@ -476,8 +477,8 @@ int add_mtd_partitions(struct mtd_info *master, if (slave->mtd.size == MTDPART_SIZ_FULL) slave->mtd.size = master->size - slave->offset; cur_offset = slave->offset + slave->mtd.size; - - printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset, + + printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset, slave->offset + slave->mtd.size, slave->mtd.name); /* let's do some sanity checks */ @@ -497,7 +498,7 @@ int add_mtd_partitions(struct mtd_info *master, /* Deal with variable erase size stuff */ int i; struct mtd_erase_region_info *regions = master->eraseregions; - + /* Find the first erase regions which is part of this partition. */ for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++) ; @@ -512,7 +513,7 @@ int add_mtd_partitions(struct mtd_info *master, slave->mtd.erasesize = master->erasesize; } - if ((slave->mtd.flags & MTD_WRITEABLE) && + if ((slave->mtd.flags & MTD_WRITEABLE) && (slave->offset % slave->mtd.erasesize)) { /* Doesn't start on a boundary of major erase size */ /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */ @@ -520,14 +521,14 @@ int add_mtd_partitions(struct mtd_info *master, printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n", parts[i].name); } - if ((slave->mtd.flags & MTD_WRITEABLE) && + if ((slave->mtd.flags & MTD_WRITEABLE) && (slave->mtd.size % slave->mtd.erasesize)) { slave->mtd.flags &= ~MTD_WRITEABLE; printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", parts[i].name); } - /* copy oobinfo from master */ + /* copy oobinfo from master */ memcpy(&slave->mtd.oobinfo, &master->oobinfo, sizeof(slave->mtd.oobinfo)); if(parts[i].mtdp) @@ -588,12 +589,12 @@ int deregister_mtd_parser(struct mtd_part_parser *p) return 0; } -int parse_mtd_partitions(struct mtd_info *master, const char **types, +int parse_mtd_partitions(struct mtd_info *master, const char **types, struct mtd_partition **pparts, unsigned long origin) { struct mtd_part_parser *parser; int ret = 0; - + for ( ; ret <= 0 && *types; types++) { parser = get_partition_parser(*types); #ifdef CONFIG_KMOD @@ -607,7 +608,7 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types, } ret = (*parser->parse_fn)(master, pparts, origin); if (ret > 0) { - printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n", + printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n", ret, parser->name, master->name); } put_partition_parser(parser); diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 36d34e5e5a5ac21530593130d499aa5d0d0ec153..1fc4c134d9391f685eb1880ca90082d96cd30725 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -1,5 +1,5 @@ # drivers/mtd/nand/Kconfig -# $Id: Kconfig,v 1.31 2005/06/20 12:03:21 bjd Exp $ +# $Id: Kconfig,v 1.35 2005/11/07 11:14:30 gleixner Exp $ menu "NAND Flash Device Drivers" depends on MTD!=n @@ -25,33 +25,33 @@ config MTD_NAND_VERIFY_WRITE config MTD_NAND_AUTCPU12 tristate "SmartMediaCard on autronix autcpu12 board" - depends on ARM && MTD_NAND && ARCH_AUTCPU12 + depends on MTD_NAND && ARCH_AUTCPU12 help - This enables the driver for the autronix autcpu12 board to + This enables the driver for the autronix autcpu12 board to access the SmartMediaCard. config MTD_NAND_EDB7312 tristate "Support for Cirrus Logic EBD7312 evaluation board" - depends on ARM && MTD_NAND && ARCH_EDB7312 + depends on MTD_NAND && ARCH_EDB7312 help - This enables the driver for the Cirrus Logic EBD7312 evaluation + This enables the driver for the Cirrus Logic EBD7312 evaluation board to access the onboard NAND Flash. config MTD_NAND_H1900 tristate "iPAQ H1900 flash" - depends on ARM && MTD_NAND && ARCH_PXA && MTD_PARTITIONS + depends on MTD_NAND && ARCH_PXA && MTD_PARTITIONS help This enables the driver for the iPAQ h1900 flash. config MTD_NAND_SPIA tristate "NAND Flash device on SPIA board" - depends on ARM && ARCH_P720T && MTD_NAND + depends on ARCH_P720T && MTD_NAND help If you had to ask, you don't have one. Say 'N'. config MTD_NAND_TOTO tristate "NAND Flash device on TOTO board" - depends on ARM && ARCH_OMAP && MTD_NAND + depends on ARCH_OMAP && MTD_NAND help Support for NAND flash on Texas Instruments Toto platform. @@ -59,8 +59,8 @@ config MTD_NAND_IDS tristate config MTD_NAND_AU1550 - tristate "Au1550 NAND support" - depends on SOC_AU1550 && MTD_NAND + tristate "Au1550/1200 NAND support" + depends on (SOC_AU1200 || SOC_AU1550) && MTD_NAND help This enables the driver for the NAND flash controller on the AMD/Alchemy 1550 SOC. @@ -71,7 +71,7 @@ config MTD_NAND_RTC_FROM4 select REED_SOLOMON select REED_SOLOMON_DEC8 help - This enables the driver for the Renesas Technology AG-AND + This enables the driver for the Renesas Technology AG-AND flash interface board (FROM_BOARD4) config MTD_NAND_PPCHAMELEONEVB @@ -88,7 +88,7 @@ config MTD_NAND_S3C2410 SoCs No board specfic support is done by this driver, each board - must advertise a platform_device for the driver to attach. + must advertise a platform_device for the driver to attach. config MTD_NAND_S3C2410_DEBUG bool "S3C2410 NAND driver debug" @@ -181,7 +181,7 @@ config MTD_NAND_DISKONCHIP_BBTWRITE config MTD_NAND_SHARPSL bool "Support for NAND Flash on Sharp SL Series (C7xx + others)" - depends on MTD_NAND && ARCH_PXA + depends on MTD_NAND && ARCH_PXA config MTD_NAND_NANDSIM bool "Support for NAND Flash Simulator" diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 4c7719ce3f4835abc09a55a45cbb0c5473caf569..3cafcdf28aedec5049949f21a25f19f53ed454e2 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -3,7 +3,7 @@ * * Copyright (C) 2004 Embedded Edge, LLC * - * $Id: au1550nd.c,v 1.11 2004/11/04 12:53:10 gleixner Exp $ + * $Id: au1550nd.c,v 1.13 2005/11/07 11:14:30 gleixner Exp $ * * 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 @@ -21,20 +21,14 @@ /* fixme: this is ugly */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0) -#include -#ifdef CONFIG_MIPS_PB1550 -#include -#endif -#ifdef CONFIG_MIPS_DB1550 -#include -#endif +#include #else #include #ifdef CONFIG_MIPS_PB1550 -#include +#include #endif #ifdef CONFIG_MIPS_DB1550 -#include +#include #endif #endif @@ -45,39 +39,22 @@ static struct mtd_info *au1550_mtd = NULL; static void __iomem *p_nand; static int nand_width = 1; /* default x8*/ -#define NAND_CS 1 - /* * Define partitions for flash device */ const static struct mtd_partition partition_info[] = { -#ifdef CONFIG_MIPS_PB1550 -#define NUM_PARTITIONS 2 - { - .name = "Pb1550 NAND FS 0", + { + .name = "NAND FS 0", .offset = 0, - .size = 8*1024*1024 + .size = 8*1024*1024 }, - { - .name = "Pb1550 NAND FS 1", + { + .name = "NAND FS 1", .offset = MTDPART_OFS_APPEND, - .size = MTDPART_SIZ_FULL + .size = MTDPART_SIZ_FULL } -#endif -#ifdef CONFIG_MIPS_DB1550 -#define NUM_PARTITIONS 2 - { - .name = "Db1550 NAND FS 0", - .offset = 0, - .size = 8*1024*1024 - }, - { - .name = "Db1550 NAND FS 1", - .offset = MTDPART_OFS_APPEND, - .size = MTDPART_SIZ_FULL - } -#endif }; +#define NB_OF(x) (sizeof(x)/sizeof(x[0])) /** @@ -112,7 +89,7 @@ static void au_write_byte(struct mtd_info *mtd, u_char byte) * au_read_byte16 - read one byte endianess aware from the chip * @mtd: MTD device structure * - * read function for 16bit buswith with + * read function for 16bit buswith with * endianess conversion */ static u_char au_read_byte16(struct mtd_info *mtd) @@ -142,7 +119,7 @@ static void au_write_byte16(struct mtd_info *mtd, u_char byte) * au_read_word - read one word from the chip * @mtd: MTD device structure * - * read function for 16bit buswith without + * read function for 16bit buswith without * endianess conversion */ static u16 au_read_word(struct mtd_info *mtd) @@ -158,7 +135,7 @@ static u16 au_read_word(struct mtd_info *mtd) * @mtd: MTD device structure * @word: data word to write * - * write function for 16bit buswith without + * write function for 16bit buswith without * endianess conversion */ static void au_write_word(struct mtd_info *mtd, u16 word) @@ -188,7 +165,7 @@ static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len) } /** - * au_read_buf - read chip data into buffer + * au_read_buf - read chip data into buffer * @mtd: MTD device structure * @buf: buffer to store date * @len: number of bytes to read @@ -202,12 +179,12 @@ static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len) for (i=0; iIO_ADDR_R); - au_sync(); + au_sync(); } } /** - * au_verify_buf - Verify chip data against buffer + * au_verify_buf - Verify chip data against buffer * @mtd: MTD device structure * @buf: buffer containing the data to compare * @len: number of bytes to compare @@ -242,16 +219,16 @@ static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) struct nand_chip *this = mtd->priv; u16 *p = (u16 *) buf; len >>= 1; - + for (i=0; iIO_ADDR_W); au_sync(); } - + } /** - * au_read_buf16 - read chip data into buffer + * au_read_buf16 - read chip data into buffer * @mtd: MTD device structure * @buf: buffer to store date * @len: number of bytes to read @@ -272,7 +249,7 @@ static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len) } /** - * au_verify_buf16 - Verify chip data against buffer + * au_verify_buf16 - Verify chip data against buffer * @mtd: MTD device structure * @buf: buffer containing the data to compare * @len: number of bytes to compare @@ -305,26 +282,26 @@ static void au1550_hwcontrol(struct mtd_info *mtd, int cmd) case NAND_CTL_CLRCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; break; case NAND_CTL_SETALE: this->IO_ADDR_W = p_nand + MEM_STNAND_ADDR; break; - case NAND_CTL_CLRALE: - this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; - /* FIXME: Nobody knows why this is neccecary, + case NAND_CTL_CLRALE: + this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; + /* FIXME: Nobody knows why this is neccecary, * but it works only that way */ - udelay(1); + udelay(1); break; - case NAND_CTL_SETNCE: + case NAND_CTL_SETNCE: /* assert (force assert) chip enable */ au_writel((1<<(4+NAND_CS)) , MEM_STNDCTL); break; break; - case NAND_CTL_CLRNCE: + case NAND_CTL_CLRNCE: /* deassert chip enable */ au_writel(0, MEM_STNDCTL); break; break; } this->IO_ADDR_R = this->IO_ADDR_W; - + /* Drain the writebuffer */ au_sync(); } @@ -339,14 +316,16 @@ int au1550_device_ready(struct mtd_info *mtd) /* * Main initialization routine */ -int __init au1550_init (void) +int __init au1xxx_nand_init (void) { struct nand_chip *this; u16 boot_swapboot = 0; /* default value */ int retval; + u32 mem_staddr; + u32 nand_phys; /* Allocate memory for MTD device structure and private data */ - au1550_mtd = kmalloc (sizeof(struct mtd_info) + + au1550_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL); if (!au1550_mtd) { printk ("Unable to allocate NAND MTD dev structure.\n"); @@ -364,14 +343,17 @@ int __init au1550_init (void) au1550_mtd->priv = this; - /* MEM_STNDCTL: disable ints, disable nand boot */ - au_writel(0, MEM_STNDCTL); + /* disable interrupts */ + au_writel(au_readl(MEM_STNDCTL) & ~(1<<8), MEM_STNDCTL); + + /* disable NAND boot */ + au_writel(au_readl(MEM_STNDCTL) & ~(1<<0), MEM_STNDCTL); #ifdef CONFIG_MIPS_PB1550 /* set gpio206 high */ au_writel(au_readl(GPIO2_DIR) & ~(1<<6), GPIO2_DIR); - boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) | + boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) | ((bcsr->status >> 6) & 0x1); switch (boot_swapboot) { case 0: @@ -397,25 +379,66 @@ int __init au1550_init (void) } #endif - /* Configure RCE1 - should be done by YAMON */ - au_writel(0x5 | (nand_width << 22), 0xB4001010); /* MEM_STCFG1 */ - au_writel(NAND_TIMING, 0xB4001014); /* MEM_STTIME1 */ - au_sync(); + /* Configure chip-select; normally done by boot code, e.g. YAMON */ +#ifdef NAND_STCFG + if (NAND_CS == 0) { + au_writel(NAND_STCFG, MEM_STCFG0); + au_writel(NAND_STTIME, MEM_STTIME0); + au_writel(NAND_STADDR, MEM_STADDR0); + } + if (NAND_CS == 1) { + au_writel(NAND_STCFG, MEM_STCFG1); + au_writel(NAND_STTIME, MEM_STTIME1); + au_writel(NAND_STADDR, MEM_STADDR1); + } + if (NAND_CS == 2) { + au_writel(NAND_STCFG, MEM_STCFG2); + au_writel(NAND_STTIME, MEM_STTIME2); + au_writel(NAND_STADDR, MEM_STADDR2); + } + if (NAND_CS == 3) { + au_writel(NAND_STCFG, MEM_STCFG3); + au_writel(NAND_STTIME, MEM_STTIME3); + au_writel(NAND_STADDR, MEM_STADDR3); + } +#endif - /* setup and enable chip select, MEM_STADDR1 */ - /* we really need to decode offsets only up till 0x20 */ - au_writel((1<<28) | (NAND_PHYS_ADDR>>4) | - (((NAND_PHYS_ADDR + 0x1000)-1) & (0x3fff<<18)>>18), - MEM_STADDR1); - au_sync(); + /* Locate NAND chip-select in order to determine NAND phys address */ + mem_staddr = 0x00000000; + if (((au_readl(MEM_STCFG0) & 0x7) == 0x5) && (NAND_CS == 0)) + mem_staddr = au_readl(MEM_STADDR0); + else if (((au_readl(MEM_STCFG1) & 0x7) == 0x5) && (NAND_CS == 1)) + mem_staddr = au_readl(MEM_STADDR1); + else if (((au_readl(MEM_STCFG2) & 0x7) == 0x5) && (NAND_CS == 2)) + mem_staddr = au_readl(MEM_STADDR2); + else if (((au_readl(MEM_STCFG3) & 0x7) == 0x5) && (NAND_CS == 3)) + mem_staddr = au_readl(MEM_STADDR3); + + if (mem_staddr == 0x00000000) { + printk("Au1xxx NAND: ERROR WITH NAND CHIP-SELECT\n"); + kfree(au1550_mtd); + return 1; + } + nand_phys = (mem_staddr << 4) & 0xFFFC0000; + + p_nand = (void __iomem *)ioremap(nand_phys, 0x1000); + + /* make controller and MTD agree */ + if (NAND_CS == 0) + nand_width = au_readl(MEM_STCFG0) & (1<<22); + if (NAND_CS == 1) + nand_width = au_readl(MEM_STCFG1) & (1<<22); + if (NAND_CS == 2) + nand_width = au_readl(MEM_STCFG2) & (1<<22); + if (NAND_CS == 3) + nand_width = au_readl(MEM_STCFG3) & (1<<22); - p_nand = ioremap(NAND_PHYS_ADDR, 0x1000); /* Set address of hardware control function */ this->hwcontrol = au1550_hwcontrol; this->dev_ready = au1550_device_ready; /* 30 us command delay time */ - this->chip_delay = 30; + this->chip_delay = 30; this->eccmode = NAND_ECC_SOFT; this->options = NAND_NO_AUTOINCR; @@ -438,19 +461,19 @@ int __init au1550_init (void) } /* Register the partitions */ - add_mtd_partitions(au1550_mtd, partition_info, NUM_PARTITIONS); + add_mtd_partitions(au1550_mtd, partition_info, NB_OF(partition_info)); return 0; outio: iounmap ((void *)p_nand); - + outmem: kfree (au1550_mtd); return retval; } -module_init(au1550_init); +module_init(au1xxx_nand_init); /* * Clean up routine diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c index 4afa8ced05ade9a51128d6d6746f2765ccee6459..056dfc17a075acb69600320ec3975e2f17cbfd17 100644 --- a/drivers/mtd/nand/autcpu12.c +++ b/drivers/mtd/nand/autcpu12.c @@ -5,8 +5,8 @@ * * Derived from drivers/mtd/spia.c * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) - * - * $Id: autcpu12.c,v 1.22 2004/11/04 12:53:10 gleixner Exp $ + * + * $Id: autcpu12.c,v 1.23 2005/11/07 11:14:30 gleixner Exp $ * * 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 @@ -14,7 +14,7 @@ * * Overview: * This is a device driver for the NAND flash device found on the - * autronix autcpu12 board, which is a SmartMediaCard. It supports + * autronix autcpu12 board, which is a SmartMediaCard. It supports * 16MiB, 32MiB and 64MiB cards. * * @@ -93,7 +93,7 @@ static struct mtd_partition partition_info128k[] = { #define NUM_PARTITIONS32K 2 #define NUM_PARTITIONS64K 2 #define NUM_PARTITIONS128K 2 -/* +/* * hardware specific access to control-lines */ static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd) @@ -163,7 +163,7 @@ int __init autcpu12_init (void) this->hwcontrol = autcpu12_hwcontrol; this->dev_ready = autcpu12_device_ready; /* 20 us command delay time */ - this->chip_delay = 20; + this->chip_delay = 20; this->eccmode = NAND_ECC_SOFT; /* Enable the following for a flash based bad block table */ @@ -171,21 +171,21 @@ int __init autcpu12_init (void) this->options = NAND_USE_FLASH_BBT; */ this->options = NAND_USE_FLASH_BBT; - + /* Scan to find existance of the device */ if (nand_scan (autcpu12_mtd, 1)) { err = -ENXIO; goto out_ior; } - + /* Register the partitions */ switch(autcpu12_mtd->size){ case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break; case SZ_32M: add_mtd_partitions(autcpu12_mtd, partition_info32k, NUM_PARTITIONS32K); break; - case SZ_64M: add_mtd_partitions(autcpu12_mtd, partition_info64k, NUM_PARTITIONS64K); break; - case SZ_128M: add_mtd_partitions(autcpu12_mtd, partition_info128k, NUM_PARTITIONS128K); break; + case SZ_64M: add_mtd_partitions(autcpu12_mtd, partition_info64k, NUM_PARTITIONS64K); break; + case SZ_128M: add_mtd_partitions(autcpu12_mtd, partition_info128k, NUM_PARTITIONS128K); break; default: { - printk ("Unsupported SmartMedia device\n"); + printk ("Unsupported SmartMedia device\n"); err = -ENXIO; goto out_ior; } @@ -213,7 +213,7 @@ static void __exit autcpu12_cleanup (void) /* unmap physical adress */ iounmap((void *)autcpu12_fio_base); - + /* Free the MTD device structure */ kfree (autcpu12_mtd); } diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index fdb5d4ad3d526d0953629e26b5c433b07e5231ac..21d4e8f4b7af4c9ffa2c0f851cec1136f2d5b94e 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -1,4 +1,4 @@ -/* +/* * drivers/mtd/nand/diskonchip.c * * (C) 2003 Red Hat, Inc. @@ -8,15 +8,15 @@ * Author: David Woodhouse * Additional Diskonchip 2000 and Millennium support by Dan Brown * Diskonchip Millennium Plus support by Kalev Lember - * + * * Error correction code lifted from the old docecc code - * Author: Fabrice Bellard (fabrice.bellard@netgem.com) + * Author: Fabrice Bellard (fabrice.bellard@netgem.com) * Copyright (C) 2000 Netgem S.A. * converted to the generic Reed-Solomon library by Thomas Gleixner - * + * * Interface to generic NAND code for M-Systems DiskOnChip devices * - * $Id: diskonchip.c,v 1.54 2005/04/07 14:22:55 dbrown Exp $ + * $Id: diskonchip.c,v 1.55 2005/11/07 11:14:30 gleixner Exp $ */ #include @@ -42,16 +42,16 @@ static unsigned long __initdata doc_locations[] = { #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__) #ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH - 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, + 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, 0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000, - 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, - 0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, + 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, + 0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, 0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000, #else /* CONFIG_MTD_DOCPROBE_HIGH */ - 0xc8000, 0xca000, 0xcc000, 0xce000, + 0xc8000, 0xca000, 0xcc000, 0xce000, 0xd0000, 0xd2000, 0xd4000, 0xd6000, - 0xd8000, 0xda000, 0xdc000, 0xde000, - 0xe0000, 0xe2000, 0xe4000, 0xe6000, + 0xd8000, 0xda000, 0xdc000, 0xde000, + 0xe0000, 0xe2000, 0xe4000, 0xe6000, 0xe8000, 0xea000, 0xec000, 0xee000, #endif /* CONFIG_MTD_DOCPROBE_HIGH */ #elif defined(__PPC__) @@ -138,7 +138,7 @@ MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe /* the Reed Solomon control structure */ static struct rs_control *rs_decoder; -/* +/* * The HW decoder in the DoC ASIC's provides us a error syndrome, * which we must convert to a standard syndrom usable by the generic * Reed-Solomon library code. @@ -163,8 +163,8 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) /* Initialize the syndrom buffer */ for (i = 0; i < NROOTS; i++) s[i] = ds[0]; - /* - * Evaluate + /* + * Evaluate * s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0] * where x = alpha^(FCR + i) */ @@ -188,7 +188,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) if (nerr < 0) return nerr; - /* + /* * Correct the errors. The bitpositions are a bit of magic, * but they are given by the design of the de/encoder circuit * in the DoC ASIC's. @@ -205,7 +205,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) can be modified since pos is even */ index = (pos >> 3) ^ 1; bitpos = pos & 7; - if ((index >= 0 && index < SECTOR_SIZE) || + if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) { val = (uint8_t) (errval[i] >> (2 + bitpos)); parity ^= val; @@ -216,7 +216,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) bitpos = (bitpos + 10) & 7; if (bitpos == 0) bitpos = 8; - if ((index >= 0 && index < SECTOR_SIZE) || + if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) { val = (uint8_t)(errval[i] << (8 - bitpos)); parity ^= val; @@ -233,7 +233,7 @@ static void DoC_Delay(struct doc_priv *doc, unsigned short cycles) { volatile char dummy; int i; - + for (i = 0; i < cycles; i++) { if (DoC_is_Millennium(doc)) dummy = ReadDOC(doc->virtadr, NOP); @@ -242,7 +242,7 @@ static void DoC_Delay(struct doc_priv *doc, unsigned short cycles) else dummy = ReadDOC(doc->virtadr, DOCStatus); } - + } #define CDSN_CTRL_FR_B_MASK (CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1) @@ -327,7 +327,7 @@ static u_char doc2000_read_byte(struct mtd_info *mtd) return ret; } -static void doc2000_writebuf(struct mtd_info *mtd, +static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *this = mtd->priv; @@ -343,7 +343,7 @@ static void doc2000_writebuf(struct mtd_info *mtd, if (debug) printk("\n"); } -static void doc2000_readbuf(struct mtd_info *mtd, +static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len) { struct nand_chip *this = mtd->priv; @@ -358,7 +358,7 @@ static void doc2000_readbuf(struct mtd_info *mtd, } } -static void doc2000_readbuf_dword(struct mtd_info *mtd, +static void doc2000_readbuf_dword(struct mtd_info *mtd, u_char *buf, int len) { struct nand_chip *this = mtd->priv; @@ -379,7 +379,7 @@ static void doc2000_readbuf_dword(struct mtd_info *mtd, } } -static int doc2000_verifybuf(struct mtd_info *mtd, +static int doc2000_verifybuf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *this = mtd->priv; @@ -406,12 +406,12 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) doc200x_hwcontrol(mtd, NAND_CTL_SETALE); this->write_byte(mtd, 0); doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); - + /* We cant' use dev_ready here, but at least we wait for the - * command to complete + * command to complete */ udelay(50); - + ret = this->read_byte(mtd) << 8; ret |= this->read_byte(mtd); @@ -438,7 +438,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) this->read_buf = &doc2000_readbuf_dword; } } - + return ret; } @@ -469,7 +469,7 @@ static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this, int state) struct doc_priv *doc = this->priv; int status; - + DoC_WaitReady(doc); this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); DoC_WaitReady(doc); @@ -503,7 +503,7 @@ static u_char doc2001_read_byte(struct mtd_info *mtd) return ReadDOC(docptr, LastDataRead); } -static void doc2001_writebuf(struct mtd_info *mtd, +static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *this = mtd->priv; @@ -517,7 +517,7 @@ static void doc2001_writebuf(struct mtd_info *mtd, WriteDOC(0x00, docptr, WritePipeTerm); } -static void doc2001_readbuf(struct mtd_info *mtd, +static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len) { struct nand_chip *this = mtd->priv; @@ -535,7 +535,7 @@ static void doc2001_readbuf(struct mtd_info *mtd, buf[i] = ReadDOC(docptr, LastDataRead); } -static int doc2001_verifybuf(struct mtd_info *mtd, +static int doc2001_verifybuf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *this = mtd->priv; @@ -570,7 +570,7 @@ static u_char doc2001plus_read_byte(struct mtd_info *mtd) return ret; } -static void doc2001plus_writebuf(struct mtd_info *mtd, +static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *this = mtd->priv; @@ -587,7 +587,7 @@ static void doc2001plus_writebuf(struct mtd_info *mtd, if (debug) printk("\n"); } -static void doc2001plus_readbuf(struct mtd_info *mtd, +static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len) { struct nand_chip *this = mtd->priv; @@ -617,7 +617,7 @@ static void doc2001plus_readbuf(struct mtd_info *mtd, if (debug) printk("\n"); } -static int doc2001plus_verifybuf(struct mtd_info *mtd, +static int doc2001plus_verifybuf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *this = mtd->priv; @@ -797,7 +797,7 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col WriteDOC(0, docptr, Mplus_FlashControl); } - /* + /* * program and erase have their own busy handlers * status and sequential in needs no delay */ @@ -822,7 +822,7 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col /* This applies to read commands */ default: - /* + /* * If we don't have access to the busy pin, we apply the given * command delay */ @@ -945,7 +945,7 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, for (i = 0; i < 6; i++) { if (DoC_is_MillenniumPlus(doc)) ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i); - else + else ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i); if (ecc_code[i] != empty_write_ecc[i]) emptymatch = 0; @@ -982,7 +982,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ void __iomem *docptr = doc->virtadr; volatile u_char dummy; int emptymatch = 1; - + /* flush the pipeline */ if (DoC_is_2000(doc)) { dummy = ReadDOC(docptr, 2k_ECCStatus); @@ -997,7 +997,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ dummy = ReadDOC(docptr, ECCConf); dummy = ReadDOC(docptr, ECCConf); } - + /* Error occured ? */ if (dummy & 0x80) { for (i = 0; i < 6; i++) { @@ -1035,7 +1035,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ if (!emptymatch) ret = doc_ecc_decode (rs_decoder, dat, calc_ecc); if (ret > 0) printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret); - } + } if (DoC_is_MillenniumPlus(doc)) WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); else @@ -1046,7 +1046,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ } return ret; } - + //u_char mydatabuf[528]; /* The strange out-of-order .oobfree list below is a (possibly unneeded) @@ -1065,7 +1065,7 @@ static struct nand_oobinfo doc200x_oobinfo = { .eccpos = {0, 1, 2, 3, 4, 5}, .oobfree = { {8, 8}, {6, 2} } }; - + /* Find the (I)NFTL Media Header, and optionally also the mirror media header. On sucessful return, buf will contain a copy of the media header for further processing. id is the string to scan for, and will presumably be @@ -1251,7 +1251,7 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits); mh->FormatFlags = le32_to_cpu(mh->FormatFlags); mh->PercentUsed = le32_to_cpu(mh->PercentUsed); - + printk(KERN_INFO " bootRecordID = %s\n" " NoOfBootImageBlocks = %d\n" " NoOfBinaryPartitions = %d\n" @@ -1468,7 +1468,7 @@ static inline int __init doc2001_init(struct mtd_info *mtd) ReadDOC(doc->virtadr, ChipID); if (ReadDOC(doc->virtadr, ChipID) != DOC_ChipID_DocMil) { /* It's not a Millennium; it's one of the newer - DiskOnChip 2000 units with a similar ASIC. + DiskOnChip 2000 units with a similar ASIC. Treat it like a Millennium, except that it can have multiple chips. */ doc2000_count_chips(mtd); @@ -1530,20 +1530,20 @@ static inline int __init doc_probe(unsigned long physadr) * to the DOCControl register. So we store the current contents * of the DOCControl register's location, in case we later decide * that it's not a DiskOnChip, and want to put it back how we - * found it. + * found it. */ save_control = ReadDOC(virtadr, DOCControl); /* Reset the DiskOnChip ASIC */ - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl); - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl); /* Enable the DiskOnChip ASIC */ - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl); - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl); ChipID = ReadDOC(virtadr, ChipID); @@ -1738,7 +1738,7 @@ static int __init init_nanddoc(void) int i, ret = 0; /* We could create the decoder on demand, if memory is a concern. - * This way we have it handy, if an error happens + * This way we have it handy, if an error happens * * Symbolsize is 10 (bits) * Primitve polynomial is x^10+x^3+1 diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c index 5549681ccdce12b7597e34d125bbd8a524e168ef..9b1fd2f387faf59444378adc5b966ff948673477 100644 --- a/drivers/mtd/nand/edb7312.c +++ b/drivers/mtd/nand/edb7312.c @@ -6,7 +6,7 @@ * Derived from drivers/mtd/nand/autcpu12.c * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) * - * $Id: edb7312.c,v 1.11 2004/11/04 12:53:10 gleixner Exp $ + * $Id: edb7312.c,v 1.12 2005/11/07 11:14:30 gleixner Exp $ * * 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 @@ -71,27 +71,27 @@ static struct mtd_partition partition_info[] = { #endif -/* +/* * hardware specific access to control-lines */ -static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd) +static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd) { switch(cmd) { - - case NAND_CTL_SETCLE: - clps_writeb(clps_readb(ep7312_pxdr) | 0x10, ep7312_pxdr); + + case NAND_CTL_SETCLE: + clps_writeb(clps_readb(ep7312_pxdr) | 0x10, ep7312_pxdr); break; - case NAND_CTL_CLRCLE: + case NAND_CTL_CLRCLE: clps_writeb(clps_readb(ep7312_pxdr) & ~0x10, ep7312_pxdr); break; - + case NAND_CTL_SETALE: clps_writeb(clps_readb(ep7312_pxdr) | 0x20, ep7312_pxdr); break; case NAND_CTL_CLRALE: clps_writeb(clps_readb(ep7312_pxdr) & ~0x20, ep7312_pxdr); break; - + case NAND_CTL_SETNCE: clps_writeb((clps_readb(ep7312_pxdr) | 0x80) & ~0x40, ep7312_pxdr); break; @@ -122,16 +122,16 @@ static int __init ep7312_init (void) int mtd_parts_nb = 0; struct mtd_partition *mtd_parts = 0; void __iomem * ep7312_fio_base; - + /* Allocate memory for MTD device structure and private data */ - ep7312_mtd = kmalloc(sizeof(struct mtd_info) + + ep7312_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); if (!ep7312_mtd) { printk("Unable to allocate EDB7312 NAND MTD device structure.\n"); return -ENOMEM; } - + /* map physical adress */ ep7312_fio_base = ioremap(ep7312_fio_pbase, SZ_1K); if(!ep7312_fio_base) { @@ -139,23 +139,23 @@ static int __init ep7312_init (void) kfree(ep7312_mtd); return -EIO; } - + /* Get pointer to private data */ this = (struct nand_chip *) (&ep7312_mtd[1]); - + /* Initialize structures */ memset((char *) ep7312_mtd, 0, sizeof(struct mtd_info)); memset((char *) this, 0, sizeof(struct nand_chip)); - + /* Link the private data with the MTD structure */ ep7312_mtd->priv = this; - + /* * Set GPIO Port B control register so that the pins are configured * to be outputs for controlling the NAND flash. */ clps_writeb(0xf0, ep7312_pxddr); - + /* insert callbacks */ this->IO_ADDR_R = ep7312_fio_base; this->IO_ADDR_W = ep7312_fio_base; @@ -163,14 +163,14 @@ static int __init ep7312_init (void) this->dev_ready = ep7312_device_ready; /* 15 us command delay time */ this->chip_delay = 15; - + /* Scan to find existence of the device */ if (nand_scan (ep7312_mtd, 1)) { iounmap((void *)ep7312_fio_base); kfree (ep7312_mtd); return -ENXIO; } - + #ifdef CONFIG_MTD_PARTITIONS ep7312_mtd->name = "edb7312-nand"; mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes, @@ -185,11 +185,11 @@ static int __init ep7312_init (void) mtd_parts_nb = NUM_PARTITIONS; part_type = "static"; } - + /* Register the partitions */ printk(KERN_NOTICE "Using %s partition definition\n", part_type); add_mtd_partitions(ep7312_mtd, mtd_parts, mtd_parts_nb); - + /* Return happy */ return 0; } @@ -201,13 +201,13 @@ module_init(ep7312_init); static void __exit ep7312_cleanup (void) { struct nand_chip *this = (struct nand_chip *) &ep7312_mtd[1]; - + /* Release resources, unregister device */ nand_release (ap7312_mtd); - + /* Free internal data buffer */ kfree (this->data_buf); - + /* Free the MTD device structure */ kfree (ep7312_mtd); } diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c index 3825a7a0900ced0707182f1e39c4547e85a7ea05..041e4b3358fbce2d953ef14d77e4c5e9e609e048 100644 --- a/drivers/mtd/nand/h1910.c +++ b/drivers/mtd/nand/h1910.c @@ -7,7 +7,7 @@ * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) * - * $Id: h1910.c,v 1.5 2004/11/04 12:53:10 gleixner Exp $ + * $Id: h1910.c,v 1.6 2005/11/07 11:14:30 gleixner Exp $ * * 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 @@ -54,24 +54,24 @@ static struct mtd_partition partition_info[] = { #endif -/* +/* * hardware specific access to control-lines */ -static void h1910_hwcontrol(struct mtd_info *mtd, int cmd) +static void h1910_hwcontrol(struct mtd_info *mtd, int cmd) { struct nand_chip* this = (struct nand_chip *) (mtd->priv); - + switch(cmd) { - - case NAND_CTL_SETCLE: + + case NAND_CTL_SETCLE: this->IO_ADDR_R |= (1 << 2); this->IO_ADDR_W |= (1 << 2); break; - case NAND_CTL_CLRCLE: + case NAND_CTL_CLRCLE: this->IO_ADDR_R &= ~(1 << 2); this->IO_ADDR_W &= ~(1 << 2); break; - + case NAND_CTL_SETALE: this->IO_ADDR_R |= (1 << 3); this->IO_ADDR_W |= (1 << 3); @@ -80,7 +80,7 @@ static void h1910_hwcontrol(struct mtd_info *mtd, int cmd) this->IO_ADDR_R &= ~(1 << 3); this->IO_ADDR_W &= ~(1 << 3); break; - + case NAND_CTL_SETNCE: break; case NAND_CTL_CLRNCE: @@ -108,18 +108,18 @@ static int __init h1910_init (void) int mtd_parts_nb = 0; struct mtd_partition *mtd_parts = 0; void __iomem *nandaddr; - + if (!machine_is_h1900()) return -ENODEV; - + nandaddr = __ioremap(0x08000000, 0x1000, 0, 1); if (!nandaddr) { printk("Failed to ioremap nand flash.\n"); return -ENOMEM; } - + /* Allocate memory for MTD device structure and private data */ - h1910_nand_mtd = kmalloc(sizeof(struct mtd_info) + + h1910_nand_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); if (!h1910_nand_mtd) { @@ -127,22 +127,22 @@ static int __init h1910_init (void) iounmap ((void *) nandaddr); return -ENOMEM; } - + /* Get pointer to private data */ this = (struct nand_chip *) (&h1910_nand_mtd[1]); - + /* Initialize structures */ memset((char *) h1910_nand_mtd, 0, sizeof(struct mtd_info)); memset((char *) this, 0, sizeof(struct nand_chip)); - + /* Link the private data with the MTD structure */ h1910_nand_mtd->priv = this; - + /* * Enable VPEN */ GPSR(37) = GPIO_bit(37); - + /* insert callbacks */ this->IO_ADDR_R = nandaddr; this->IO_ADDR_W = nandaddr; @@ -152,7 +152,7 @@ static int __init h1910_init (void) this->chip_delay = 50; this->eccmode = NAND_ECC_SOFT; this->options = NAND_NO_AUTOINCR; - + /* Scan to find existence of the device */ if (nand_scan (h1910_nand_mtd, 1)) { printk(KERN_NOTICE "No NAND device - returning -ENXIO\n"); @@ -160,9 +160,9 @@ static int __init h1910_init (void) iounmap ((void *) nandaddr); return -ENXIO; } - + #ifdef CONFIG_MTD_CMDLINE_PARTS - mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts, + mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts, "h1910-nand"); if (mtd_parts_nb > 0) part_type = "command line"; @@ -175,11 +175,11 @@ static int __init h1910_init (void) mtd_parts_nb = NUM_PARTITIONS; part_type = "static"; } - + /* Register the partitions */ printk(KERN_NOTICE "Using %s partition definition\n", part_type); add_mtd_partitions(h1910_nand_mtd, mtd_parts, mtd_parts_nb); - + /* Return happy */ return 0; } @@ -191,7 +191,7 @@ module_init(h1910_init); static void __exit h1910_cleanup (void) { struct nand_chip *this = (struct nand_chip *) &h1910_nand_mtd[1]; - + /* Release resources, unregister device */ nand_release (h1910_nand_mtd); diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 04e54318bc6a603f2c44b32e3b2f8b5b260a64dc..5d222460b42a87acd20c18f23183c67ad9f109e4 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -5,14 +5,14 @@ * This is the generic MTD driver for NAND flash devices. It should be * capable of working with almost all NAND chips currently available. * Basic support for AG-AND chips is provided. - * + * * Additional technical information is available on * http://www.linux-mtd.infradead.org/tech/nand.html - * + * * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * 2002 Thomas Gleixner (tglx@linutronix.de) * - * 02-08-2004 tglx: support for strange chips, which cannot auto increment + * 02-08-2004 tglx: support for strange chips, which cannot auto increment * pages on read / read_oob * * 03-17-2004 tglx: Check ready before auto increment check. Simon Bayes @@ -21,7 +21,7 @@ * Make reads over block boundaries work too * * 04-14-2004 tglx: first working version for 2k page size chips - * + * * 05-19-2004 tglx: Basic support for Renesas AG-AND chips * * 09-24-2004 tglx: add support for hardware controllers (e.g. ECC) shared @@ -30,25 +30,27 @@ * * 12-05-2004 dmarlin: add workaround for Renesas AG-AND chips "disturb" issue. * Basically, any block not rewritten may lose data when surrounding blocks - * are rewritten many times. JFFS2 ensures this doesn't happen for blocks + * are rewritten many times. JFFS2 ensures this doesn't happen for blocks * it uses, but the Bad Block Table(s) may not be rewritten. To ensure they * do not lose data, force them to be rewritten when some of the surrounding - * blocks are erased. Rather than tracking a specific nearby block (which - * could itself go bad), use a page address 'mask' to select several blocks + * blocks are erased. Rather than tracking a specific nearby block (which + * could itself go bad), use a page address 'mask' to select several blocks * in the same area, and rewrite the BBT when any of them are erased. * - * 01-03-2005 dmarlin: added support for the device recovery command sequence for Renesas + * 01-03-2005 dmarlin: added support for the device recovery command sequence for Renesas * AG-AND chips. If there was a sudden loss of power during an erase operation, * a "device recovery" operation must be performed when power is restored * to ensure correct operation. * - * 01-20-2005 dmarlin: added support for optional hardware specific callback routine to + * 01-20-2005 dmarlin: added support for optional hardware specific callback routine to * perform extra error status checks on erase and write failures. This required * adding a wrapper function for nand_read_ecc. * + * 08-20-2005 vwool: suspend/resume added + * * Credits: - * David Woodhouse for adding multichip support - * + * David Woodhouse for adding multichip support + * * Aleph One Ltd. and Toby Churchill Ltd. for supporting the * rework for 2K page size chips * @@ -59,7 +61,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.147 2005/07/15 07:18:06 gleixner Exp $ + * $Id: nand_base.c,v 1.150 2005/09/15 13:58:48 vwool Exp $ * * 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 @@ -103,8 +105,8 @@ static struct nand_oobinfo nand_oob_64 = { .useecc = MTD_NANDECC_AUTOPLACE, .eccbytes = 24, .eccpos = { - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}, .oobfree = { {2, 38} } }; @@ -147,19 +149,19 @@ static void nand_sync (struct mtd_info *mtd); static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel, int mode); #ifdef CONFIG_MTD_NAND_VERIFY_WRITE -static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, +static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode); #else #define nand_verify_pages(...) (0) #endif - -static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state); + +static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state); /** * nand_release_device - [GENERIC] release chip * @mtd: MTD device structure - * - * Deselect, release chip lock and wake up anyone waiting on the device + * + * Deselect, release chip lock and wake up anyone waiting on the device */ static void nand_release_device (struct mtd_info *mtd) { @@ -213,7 +215,7 @@ static void nand_write_byte(struct mtd_info *mtd, u_char byte) * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip * @mtd: MTD device structure * - * Default read function for 16bit buswith with + * Default read function for 16bit buswith with * endianess conversion */ static u_char nand_read_byte16(struct mtd_info *mtd) @@ -240,7 +242,7 @@ static void nand_write_byte16(struct mtd_info *mtd, u_char byte) * nand_read_word - [DEFAULT] read one word from the chip * @mtd: MTD device structure * - * Default read function for 16bit buswith without + * Default read function for 16bit buswith without * endianess conversion */ static u16 nand_read_word(struct mtd_info *mtd) @@ -254,7 +256,7 @@ static u16 nand_read_word(struct mtd_info *mtd) * @mtd: MTD device structure * @word: data word to write * - * Default write function for 16bit buswith without + * Default write function for 16bit buswith without * endianess conversion */ static void nand_write_word(struct mtd_info *mtd, u16 word) @@ -275,7 +277,7 @@ static void nand_select_chip(struct mtd_info *mtd, int chip) struct nand_chip *this = mtd->priv; switch(chip) { case -1: - this->hwcontrol(mtd, NAND_CTL_CLRNCE); + this->hwcontrol(mtd, NAND_CTL_CLRNCE); break; case 0: this->hwcontrol(mtd, NAND_CTL_SETNCE); @@ -304,7 +306,7 @@ static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) } /** - * nand_read_buf - [DEFAULT] read chip data into buffer + * nand_read_buf - [DEFAULT] read chip data into buffer * @mtd: MTD device structure * @buf: buffer to store date * @len: number of bytes to read @@ -321,7 +323,7 @@ static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) } /** - * nand_verify_buf - [DEFAULT] Verify chip data against buffer + * nand_verify_buf - [DEFAULT] Verify chip data against buffer * @mtd: MTD device structure * @buf: buffer containing the data to compare * @len: number of bytes to compare @@ -354,14 +356,14 @@ static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) struct nand_chip *this = mtd->priv; u16 *p = (u16 *) buf; len >>= 1; - + for (i=0; iIO_ADDR_W); - + } /** - * nand_read_buf16 - [DEFAULT] read chip data into buffer + * nand_read_buf16 - [DEFAULT] read chip data into buffer * @mtd: MTD device structure * @buf: buffer to store date * @len: number of bytes to read @@ -380,7 +382,7 @@ static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len) } /** - * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer + * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer * @mtd: MTD device structure * @buf: buffer containing the data to compare * @len: number of bytes to compare @@ -407,7 +409,7 @@ static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len) * @ofs: offset from device start * @getchip: 0, if the chip is already selected * - * Check, if the block is bad. + * Check, if the block is bad. */ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) { @@ -424,14 +426,14 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) /* Select the NAND device */ this->select_chip(mtd, chipnr); - } else - page = (int) ofs; + } else + page = (int) ofs; if (this->options & NAND_BUSWIDTH_16) { this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page & this->pagemask); bad = cpu_to_le16(this->read_word(mtd)); if (this->badblockpos & 0x1) - bad >>= 1; + bad >>= 8; if ((bad & 0xFF) != 0xff) res = 1; } else { @@ -439,12 +441,12 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) if (this->read_byte(mtd) != 0xff) res = 1; } - + if (getchip) { /* Deselect and wake up anyone waiting on the device */ nand_release_device(mtd); - } - + } + return res; } @@ -462,7 +464,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) u_char buf[2] = {0, 0}; size_t retlen; int block; - + /* Get block number */ block = ((int) ofs) >> this->bbt_erase_shift; if (this->bbt) @@ -471,25 +473,25 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) /* Do we have a flash based bad block table ? */ if (this->options & NAND_USE_FLASH_BBT) return nand_update_bbt (mtd, ofs); - + /* We write two bytes, so we dont have to mess with 16 bit access */ ofs += mtd->oobsize + (this->badblockpos & ~0x01); return nand_write_oob (mtd, ofs , 2, &retlen, buf); } -/** +/** * nand_check_wp - [GENERIC] check if the chip is write protected * @mtd: MTD device structure - * Check, if the device is write protected + * Check, if the device is write protected * - * The function expects, that the device is already selected + * The function expects, that the device is already selected */ static int nand_check_wp (struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; /* Check the WP bit */ this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); - return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; + return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; } /** @@ -505,15 +507,15 @@ static int nand_check_wp (struct mtd_info *mtd) static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt) { struct nand_chip *this = mtd->priv; - + if (!this->bbt) return this->block_bad(mtd, ofs, getchip); - + /* Return info from the table */ return nand_isbad_bbt (mtd, ofs, allowbbt); } -/* +/* * Wait for the ready pin, after a command * The timeout is catched later. */ @@ -527,7 +529,7 @@ static void nand_wait_ready(struct mtd_info *mtd) if (this->dev_ready(mtd)) return; touch_softlockup_watchdog(); - } while (time_before(jiffies, timeo)); + } while (time_before(jiffies, timeo)); } /** @@ -590,13 +592,13 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in /* Latch in address */ this->hwcontrol(mtd, NAND_CTL_CLRALE); } - - /* - * program and erase have their own busy handlers + + /* + * program and erase have their own busy handlers * status and sequential in needs no delay */ switch (command) { - + case NAND_CMD_PAGEPROG: case NAND_CMD_ERASE1: case NAND_CMD_ERASE2: @@ -605,7 +607,7 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in return; case NAND_CMD_RESET: - if (this->dev_ready) + if (this->dev_ready) break; udelay(this->chip_delay); this->hwcontrol(mtd, NAND_CTL_SETCLE); @@ -614,16 +616,16 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in while ( !(this->read_byte(mtd) & NAND_STATUS_READY)); return; - /* This applies to read commands */ + /* This applies to read commands */ default: - /* + /* * If we don't have access to the busy pin, we apply the given * command delay */ if (!this->dev_ready) { udelay (this->chip_delay); return; - } + } } /* Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ @@ -653,8 +655,8 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, column += mtd->oobblock; command = NAND_CMD_READ0; } - - + + /* Begin command latch cycle */ this->hwcontrol(mtd, NAND_CTL_SETCLE); /* Write out the command to the device. */ @@ -672,7 +674,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, column >>= 1; this->write_byte(mtd, column & 0xff); this->write_byte(mtd, column >> 8); - } + } if (page_addr != -1) { this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); @@ -683,13 +685,13 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, /* Latch in address */ this->hwcontrol(mtd, NAND_CTL_CLRALE); } - - /* - * program and erase have their own busy handlers + + /* + * program and erase have their own busy handlers * status, sequential in, and deplete1 need no delay */ switch (command) { - + case NAND_CMD_CACHEDPROG: case NAND_CMD_PAGEPROG: case NAND_CMD_ERASE1: @@ -699,7 +701,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, case NAND_CMD_DEPLETE1: return; - /* + /* * read error status commands require only a short delay */ case NAND_CMD_STATUS_ERROR: @@ -711,7 +713,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, return; case NAND_CMD_RESET: - if (this->dev_ready) + if (this->dev_ready) break; udelay(this->chip_delay); this->hwcontrol(mtd, NAND_CTL_SETCLE); @@ -728,17 +730,17 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, /* End command latch cycle */ this->hwcontrol(mtd, NAND_CTL_CLRCLE); /* Fall through into ready check */ - - /* This applies to read commands */ + + /* This applies to read commands */ default: - /* + /* * If we don't have access to the busy pin, we apply the given * command delay */ if (!this->dev_ready) { udelay (this->chip_delay); return; - } + } } /* Apply this short delay always to ensure that we do wait tWB in @@ -752,11 +754,11 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, * nand_get_device - [GENERIC] Get chip for selected access * @this: the nand chip descriptor * @mtd: MTD device structure - * @new_state: the state which is requested + * @new_state: the state which is requested * * Get the device and lock it for exclusive access */ -static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state) +static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state) { struct nand_chip *active; spinlock_t *lock; @@ -779,7 +781,11 @@ static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int n if (active == this && this->state == FL_READY) { this->state = new_state; spin_unlock(lock); - return; + return 0; + } + if (new_state == FL_PM_SUSPENDED) { + spin_unlock(lock); + return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN; } set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(wq, &wait); @@ -796,7 +802,7 @@ static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int n * @state: state to select the max. timeout value * * Wait for command done. This applies to erase and program only - * Erase can take up to 400ms and program up to 20ms according to + * Erase can take up to 400ms and program up to 20ms according to * general NAND and SmartMedia specs * */ @@ -805,7 +811,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) unsigned long timeo = jiffies; int status; - + if (state == FL_ERASING) timeo += (HZ * 400) / 1000; else @@ -817,17 +823,17 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) if ((state == FL_ERASING) && (this->options & NAND_IS_AND)) this->cmdfunc (mtd, NAND_CMD_STATUS_MULTI, -1, -1); - else + else this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); - while (time_before(jiffies, timeo)) { + while (time_before(jiffies, timeo)) { /* Check, if we were interrupted */ if (this->state != state) return 0; if (this->dev_ready) { if (this->dev_ready(mtd)) - break; + break; } else { if (this->read_byte(mtd) & NAND_STATUS_READY) break; @@ -853,7 +859,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) * * Cached programming is not supported yet. */ -static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, +static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel, int cached) { int i, status; @@ -862,10 +868,10 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa int *oob_config = oobsel->eccpos; int datidx = 0, eccidx = 0, eccsteps = this->eccsteps; int eccbytes = 0; - + /* FIXME: Enable cached programming */ cached = 0; - + /* Send command to begin auto page programming */ this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page); @@ -876,7 +882,7 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n"); this->write_buf(mtd, this->data_poi, mtd->oobblock); break; - + /* Software ecc 3/256, write all */ case NAND_ECC_SOFT: for (; eccsteps; eccsteps--) { @@ -905,11 +911,11 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa } break; } - + /* Write out OOB data */ if (this->options & NAND_HWECC_SYNDROME) this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes); - else + else this->write_buf(mtd, oob_buf, mtd->oobsize); /* Send command to actually program the data */ @@ -934,7 +940,7 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa /* wait until cache is ready*/ // status = this->waitfunc (mtd, this, FL_CACHEDRPG); } - return 0; + return 0; } #ifdef CONFIG_MTD_NAND_VERIFY_WRITE @@ -950,19 +956,19 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa * @oobmode: 1 = full buffer verify, 0 = ecc only * * The NAND device assumes that it is always writing to a cleanly erased page. - * Hence, it performs its internal write verification only on bits that + * Hence, it performs its internal write verification only on bits that * transitioned from 1 to 0. The device does NOT verify the whole page on a - * byte by byte basis. It is possible that the page was not completely erased - * or the page is becoming unusable due to wear. The read with ECC would catch - * the error later when the ECC page check fails, but we would rather catch + * byte by byte basis. It is possible that the page was not completely erased + * or the page is becoming unusable due to wear. The read with ECC would catch + * the error later when the ECC page check fails, but we would rather catch * it early in the page write stage. Better to write no data than invalid data. */ -static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, +static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode) { int i, j, datidx = 0, oobofs = 0, res = -EIO; int eccsteps = this->eccsteps; - int hweccbytes; + int hweccbytes; u_char oobdata[64]; hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0; @@ -1002,7 +1008,7 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) { int ecccnt = oobsel->eccbytes; - + for (i = 0; i < ecccnt; i++) { int idx = oobsel->eccpos[i]; if (oobdata[idx] != oob_buf[oobofs + idx] ) { @@ -1012,20 +1018,20 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int goto out; } } - } + } } oobofs += mtd->oobsize - hweccbytes * eccsteps; page++; numpages--; - /* Apply delay or wait for ready/busy pin + /* Apply delay or wait for ready/busy pin * Do this before the AUTOINCR check, so no problems * arise if a chip which does auto increment * is marked as NOAUTOINCR by the board driver. * Do this also before returning, so the chip is * ready for the next command. */ - if (!this->dev_ready) + if (!this->dev_ready) udelay (this->chip_delay); else nand_wait_ready(mtd); @@ -1033,17 +1039,17 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int /* All done, return happy */ if (!numpages) return 0; - - - /* Check, if the chip supports auto page increment */ + + + /* Check, if the chip supports auto page increment */ if (!NAND_CANAUTOINCR(this)) this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); } - /* + /* * Terminate the read command. We come here in case of an error * So we must issue a reset command. */ -out: +out: this->cmdfunc (mtd, NAND_CMD_RESET, -1, -1); return res; } @@ -1105,7 +1111,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, * NAND read with ECC */ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, - size_t * retlen, u_char * buf, u_char * oob_buf, + size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel, int flags) { @@ -1139,7 +1145,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, /* Autoplace of oob data ? Use the default placement scheme */ if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) oobsel = this->autooob; - + eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; oob_config = oobsel->eccpos; @@ -1157,28 +1163,28 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, end = mtd->oobblock; ecc = this->eccsize; eccbytes = this->eccbytes; - + if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME)) compareecc = 0; oobreadlen = mtd->oobsize; - if (this->options & NAND_HWECC_SYNDROME) + if (this->options & NAND_HWECC_SYNDROME) oobreadlen -= oobsel->eccbytes; /* Loop until all data read */ while (read < len) { - + int aligned = (!col && (len - read) >= end); - /* + /* * If the read is not page aligned, we have to read into data buffer * due to ecc, else we read into return buffer direct */ if (aligned) data_poi = &buf[read]; - else + else data_poi = this->data_buf; - - /* Check, if we have this page in the buffer + + /* Check, if we have this page in the buffer * * FIXME: Make it work when we must provide oob data too, * check the usage of data_buf oob field @@ -1194,7 +1200,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, if (sndcmd) { this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); sndcmd = 0; - } + } /* get oob area, if we have no oob buffer from fs-driver */ if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE || @@ -1202,7 +1208,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, oob_data = &this->data_buf[end]; eccsteps = this->eccsteps; - + switch (eccmode) { case NAND_ECC_NONE: { /* No ECC, Read in a page */ static unsigned long lastwhinge = 0; @@ -1213,12 +1219,12 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, this->read_buf(mtd, data_poi, end); break; } - + case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */ this->read_buf(mtd, data_poi, end); - for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) + for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); - break; + break; default: for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=eccbytes, datidx += ecc) { @@ -1237,15 +1243,15 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, * does the error correction on the fly */ ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]); if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " + DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); ecc_failed++; } } else { this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); - } + } } - break; + break; } /* read oobdata */ @@ -1253,8 +1259,8 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, /* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */ if (!compareecc) - goto readoob; - + goto readoob; + /* Pick the ECC bytes out of the oob data */ for (j = 0; j < oobsel->eccbytes; j++) ecc_code[j] = oob_data[oob_config[j]]; @@ -1262,24 +1268,24 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, /* correct data, if neccecary */ for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) { ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]); - + /* Get next chunk of ecc bytes */ j += eccbytes; - - /* Check, if we have a fs supplied oob-buffer, + + /* Check, if we have a fs supplied oob-buffer, * This is the legacy mode. Used by YAFFS1 * Should go away some day */ - if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) { + if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) { int *p = (int *)(&oob_data[mtd->oobsize]); p[i] = ecc_status; } - - if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { + + if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); ecc_failed++; } - } + } readoob: /* check, if we have a fs supplied oob-buffer */ @@ -1305,25 +1311,25 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, } readdata: /* Partial page read, transfer data into fs buffer */ - if (!aligned) { + if (!aligned) { for (j = col; j < end && read < len; j++) buf[read++] = data_poi[j]; - this->pagebuf = realpage; - } else + this->pagebuf = realpage; + } else read += mtd->oobblock; - /* Apply delay or wait for ready/busy pin + /* Apply delay or wait for ready/busy pin * Do this before the AUTOINCR check, so no problems * arise if a chip which does auto increment * is marked as NOAUTOINCR by the board driver. */ - if (!this->dev_ready) + if (!this->dev_ready) udelay (this->chip_delay); else nand_wait_ready(mtd); - + if (read == len) - break; + break; /* For subsequent reads align to page boundary. */ col = 0; @@ -1337,11 +1343,11 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, this->select_chip(mtd, -1); this->select_chip(mtd, chipnr); } - /* Check, if the chip supports auto page increment - * or if we have hit a block boundary. - */ + /* Check, if the chip supports auto page increment + * or if we have hit a block boundary. + */ if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) - sndcmd = 1; + sndcmd = 1; } /* Deselect and wake up anyone waiting on the device */ @@ -1378,7 +1384,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t /* Shift to get page */ page = (int)(from >> this->page_shift); chipnr = (int)(from >> this->chip_shift); - + /* Mask to get column */ col = from & (mtd->oobsize - 1); @@ -1400,7 +1406,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t /* Send the read command */ this->cmdfunc (mtd, NAND_CMD_READOOB, col, page & this->pagemask); - /* + /* * Read the data, if we read more than one page * oob data, let the device transfer the data ! */ @@ -1422,20 +1428,20 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t this->select_chip(mtd, -1); this->select_chip(mtd, chipnr); } - - /* Apply delay or wait for ready/busy pin + + /* Apply delay or wait for ready/busy pin * Do this before the AUTOINCR check, so no problems * arise if a chip which does auto increment * is marked as NOAUTOINCR by the board driver. */ - if (!this->dev_ready) + if (!this->dev_ready) udelay (this->chip_delay); else nand_wait_ready(mtd); - /* Check, if the chip supports auto page increment - * or if we have hit a block boundary. - */ + /* Check, if the chip supports auto page increment + * or if we have hit a block boundary. + */ if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) { /* For subsequent page reads set offset to 0 */ this->cmdfunc (mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask); @@ -1481,27 +1487,27 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, nand_get_device (this, mtd , FL_READING); this->select_chip (mtd, chip); - + /* Add requested oob length */ len += ooblen; - + while (len) { if (sndcmd) this->cmdfunc (mtd, NAND_CMD_READ0, 0, page & this->pagemask); - sndcmd = 0; + sndcmd = 0; this->read_buf (mtd, &buf[cnt], pagesize); len -= pagesize; cnt += pagesize; page++; - - if (!this->dev_ready) + + if (!this->dev_ready) udelay (this->chip_delay); else nand_wait_ready(mtd); - - /* Check, if the chip supports auto page increment */ + + /* Check, if the chip supports auto page increment */ if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) sndcmd = 1; } @@ -1512,8 +1518,8 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, } -/** - * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer +/** + * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer * @mtd: MTD device structure * @fsbuf: buffer given by fs driver * @oobsel: out of band selection structre @@ -1542,20 +1548,20 @@ static u_char * nand_prepare_oobbuf (struct mtd_info *mtd, u_char *fsbuf, struct int i, len, ofs; /* Zero copy fs supplied buffer */ - if (fsbuf && !autoplace) + if (fsbuf && !autoplace) return fsbuf; /* Check, if the buffer must be filled with ff again */ - if (this->oobdirty) { - memset (this->oob_buf, 0xff, + if (this->oobdirty) { + memset (this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift)); this->oobdirty = 0; - } - + } + /* If we have no autoplacement or no fs buffer use the internal one */ if (!autoplace || !fsbuf) return this->oob_buf; - + /* Walk through the pages and place the data */ this->oobdirty = 1; ofs = 0; @@ -1589,7 +1595,7 @@ static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * ret { return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL)); } - + /** * nand_write_ecc - [MTD Interface] NAND write with ECC * @mtd: MTD device structure @@ -1622,7 +1628,7 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, return -EINVAL; } - /* reject writes, which are not page aligned */ + /* reject writes, which are not page aligned */ if (NOTALIGNED (to) || NOTALIGNED(len)) { printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); return -EINVAL; @@ -1641,14 +1647,14 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, goto out; /* if oobsel is NULL, use chip defaults */ - if (oobsel == NULL) - oobsel = &mtd->oobinfo; - + if (oobsel == NULL) + oobsel = &mtd->oobinfo; + /* Autoplace of oob data ? Use the default placement scheme */ if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { oobsel = this->autooob; autoplace = 1; - } + } if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) autoplace = 1; @@ -1656,9 +1662,9 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, totalpages = len >> this->page_shift; page = (int) (to >> this->page_shift); /* Invalidate the page cache, if we write to the cached page */ - if (page <= this->pagebuf && this->pagebuf < (page + totalpages)) + if (page <= this->pagebuf && this->pagebuf < (page + totalpages)) this->pagebuf = -1; - + /* Set it relative to chip */ page &= this->pagemask; startpage = page; @@ -1680,14 +1686,14 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, if (ret) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret); goto out; - } + } /* Next oob page */ oob += mtd->oobsize; /* Update written bytes count */ written += mtd->oobblock; - if (written == len) + if (written == len) goto cmp; - + /* Increment page address */ page++; @@ -1698,13 +1704,13 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, if (!(page & (ppblock - 1))){ int ofs; this->data_poi = bufstart; - ret = nand_verify_pages (mtd, this, startpage, + ret = nand_verify_pages (mtd, this, startpage, page - startpage, oobbuf, oobsel, chipnr, (eccbuf != NULL)); if (ret) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); goto out; - } + } *retlen = written; ofs = autoplace ? mtd->oobavail : mtd->oobsize; @@ -1714,8 +1720,9 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, numpages = min (totalpages, ppblock); page &= this->pagemask; startpage = page; - oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, + oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, autoplace, numpages); + oob = 0; /* Check, if we cross a chip boundary */ if (!page) { chipnr++; @@ -1731,7 +1738,7 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, oobbuf, oobsel, chipnr, (eccbuf != NULL)); if (!ret) *retlen = written; - else + else DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); out: @@ -1791,7 +1798,7 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * /* Check, if it is write protected */ if (nand_check_wp(mtd)) goto out; - + /* Invalidate the page cache, if we write to the cached page */ if (page == this->pagebuf) this->pagebuf = -1; @@ -1854,10 +1861,10 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * * * NAND write with kvec. This just calls the ecc function */ -static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, +static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t * retlen) { - return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, NULL)); + return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, NULL)); } /** @@ -1872,7 +1879,7 @@ static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned * * NAND write with iovec with ecc */ -static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, +static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel) { int i, page, len, total_len, ret = -EIO, written = 0, chipnr; @@ -1898,7 +1905,7 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig return -EINVAL; } - /* reject writes, which are not page aligned */ + /* reject writes, which are not page aligned */ if (NOTALIGNED (to) || NOTALIGNED(total_len)) { printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); return -EINVAL; @@ -1917,21 +1924,21 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig goto out; /* if oobsel is NULL, use chip defaults */ - if (oobsel == NULL) - oobsel = &mtd->oobinfo; + if (oobsel == NULL) + oobsel = &mtd->oobinfo; /* Autoplace of oob data ? Use the default placement scheme */ if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { oobsel = this->autooob; autoplace = 1; - } + } if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) autoplace = 1; /* Setup start page */ page = (int) (to >> this->page_shift); /* Invalidate the page cache, if we write to the cached page */ - if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift)) + if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift)) this->pagebuf = -1; startpage = page & this->pagemask; @@ -1955,10 +1962,10 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig oob = 0; for (i = 1; i <= numpages; i++) { /* Write one page. If this is the last page to write - * then use the real pageprogram command, else select + * then use the real pageprogram command, else select * cached programming if supported by the chip. */ - ret = nand_write_page (mtd, this, page & this->pagemask, + ret = nand_write_page (mtd, this, page & this->pagemask, &oobbuf[oob], oobsel, i != numpages); if (ret) goto out; @@ -1974,12 +1981,12 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig count--; } } else { - /* We must use the internal buffer, read data out of each + /* We must use the internal buffer, read data out of each * tuple until we have a full page to write */ int cnt = 0; while (cnt < mtd->oobblock) { - if (vecs->iov_base != NULL && vecs->iov_len) + if (vecs->iov_base != NULL && vecs->iov_len) this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++]; /* Check, if we have to switch to the next tuple */ if (len >= (int) vecs->iov_len) { @@ -1988,10 +1995,10 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig count--; } } - this->pagebuf = page; - this->data_poi = this->data_buf; + this->pagebuf = page; + this->data_poi = this->data_buf; bufstart = this->data_poi; - numpages = 1; + numpages = 1; oobbuf = nand_prepare_oobbuf (mtd, NULL, oobsel, autoplace, numpages); ret = nand_write_page (mtd, this, page & this->pagemask, oobbuf, oobsel, 0); @@ -2004,7 +2011,7 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig ret = nand_verify_pages (mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0); if (ret) goto out; - + written += mtd->oobblock * numpages; /* All done ? */ if (!count) @@ -2072,7 +2079,7 @@ static int nand_erase (struct mtd_info *mtd, struct erase_info *instr) { return nand_erase_nand (mtd, instr, 0); } - + #define BBT_PAGE_MASK 0xffffff3f /** * nand_erase_intern - [NAND Interface] erase block(s) @@ -2154,14 +2161,14 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb instr->state = MTD_ERASE_FAILED; goto erase_exit; } - - /* Invalidate the page cache, if we erase the block which contains + + /* Invalidate the page cache, if we erase the block which contains the current cached page */ if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block)) this->pagebuf = -1; this->erase_cmd (mtd, page & this->pagemask); - + status = this->waitfunc (mtd, this, FL_ERASING); /* See if operation failed and additional status checks are available */ @@ -2179,12 +2186,12 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */ if (this->options & BBT_AUTO_REFRESH) { - if (((page & BBT_PAGE_MASK) == bbt_masked_page) && + if (((page & BBT_PAGE_MASK) == bbt_masked_page) && (page != this->bbt_td->pages[chipnr])) { rewrite_bbt[chipnr] = (page << this->page_shift); } } - + /* Increment page address and decrement length */ len -= (1 << this->phys_erase_shift); page += pages_per_block; @@ -2195,7 +2202,7 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb this->select_chip(mtd, -1); this->select_chip(mtd, chipnr); - /* if BBT requires refresh and BBT-PERCHIP, + /* if BBT requires refresh and BBT-PERCHIP, * set the BBT page mask to see if this BBT should be rewritten */ if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) { bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK; @@ -2220,7 +2227,7 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb for (chipnr = 0; chipnr < this->numchips; chipnr++) { if (rewrite_bbt[chipnr]) { /* update the BBT for chip */ - DEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n", + DEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n", chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]); nand_update_bbt (mtd, rewrite_bbt[chipnr]); } @@ -2258,9 +2265,9 @@ static void nand_sync (struct mtd_info *mtd) static int nand_block_isbad (struct mtd_info *mtd, loff_t ofs) { /* Check for invalid offset */ - if (ofs > mtd->size) + if (ofs > mtd->size) return -EINVAL; - + return nand_block_checkbad (mtd, ofs, 1, 0); } @@ -2284,6 +2291,34 @@ static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs) return this->block_markbad(mtd, ofs); } +/** + * nand_suspend - [MTD Interface] Suspend the NAND flash + * @mtd: MTD device structure + */ +static int nand_suspend(struct mtd_info *mtd) +{ + struct nand_chip *this = mtd->priv; + + return nand_get_device (this, mtd, FL_PM_SUSPENDED); +} + +/** + * nand_resume - [MTD Interface] Resume the NAND flash + * @mtd: MTD device structure + */ +static void nand_resume(struct mtd_info *mtd) +{ + struct nand_chip *this = mtd->priv; + + if (this->state == FL_PM_SUSPENDED) + nand_release_device(mtd); + else + printk(KERN_ERR "resume() called for the chip which is not " + "in suspended state\n"); + +} + + /** * nand_scan - [NAND Interface] Scan for the NAND device * @mtd: MTD device structure @@ -2351,13 +2386,13 @@ int nand_scan (struct mtd_info *mtd, int maxchips) /* Print and store flash device information */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { - - if (nand_dev_id != nand_flash_ids[i].id) + + if (nand_dev_id != nand_flash_ids[i].id) continue; if (!mtd->name) mtd->name = nand_flash_ids[i].name; this->chipsize = nand_flash_ids[i].chipsize << 20; - + /* New devices have all the information in additional id bytes */ if (!nand_flash_ids[i].pagesize) { int extid; @@ -2369,14 +2404,14 @@ int nand_scan (struct mtd_info *mtd, int maxchips) mtd->oobblock = 1024 << (extid & 0x3); extid >>= 2; /* Calc oobsize */ - mtd->oobsize = (8 << (extid & 0x03)) * (mtd->oobblock / 512); + mtd->oobsize = (8 << (extid & 0x01)) * (mtd->oobblock >> 9); extid >>= 2; /* Calc blocksize. Blocksize is multiples of 64KiB */ mtd->erasesize = (64 * 1024) << (extid & 0x03); extid >>= 2; /* Get buswidth information */ busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; - + } else { /* Old devices have this data hardcoded in the * device id table */ @@ -2396,23 +2431,23 @@ int nand_scan (struct mtd_info *mtd, int maxchips) * this correct ! */ if (busw != (this->options & NAND_BUSWIDTH_16)) { printk (KERN_INFO "NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, nand_manuf_ids[maf_id].name , mtd->name); - printk (KERN_WARNING - "NAND bus width %d instead %d bit\n", + printk (KERN_WARNING + "NAND bus width %d instead %d bit\n", (this->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8); this->select_chip(mtd, -1); - return 1; + return 1; } - - /* Calculate the address shift from the page size */ + + /* Calculate the address shift from the page size */ this->page_shift = ffs(mtd->oobblock) - 1; this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1; this->chip_shift = ffs(this->chipsize) - 1; /* Set the bad block position */ - this->badblockpos = mtd->oobblock > 512 ? + this->badblockpos = mtd->oobblock > 512 ? NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; /* Get chip options, preserve non chip based options */ @@ -2422,10 +2457,10 @@ int nand_scan (struct mtd_info *mtd, int maxchips) this->options |= NAND_NO_AUTOINCR; /* Check if this is a not a samsung device. Do not clear the options * for chips which are not having an extended id. - */ + */ if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize) this->options &= ~NAND_SAMSUNG_LP_OPTIONS; - + /* Check for AND chips with 4 page planes */ if (this->options & NAND_4PAGE_ARRAY) this->erase_cmd = multi_erase_cmd; @@ -2435,9 +2470,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips) /* Do not replace user supplied command function ! */ if (mtd->oobblock > 512 && this->cmdfunc == nand_command) this->cmdfunc = nand_command_lp; - + printk (KERN_INFO "NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, nand_manuf_ids[maf_id].name , nand_flash_ids[i].name); break; } @@ -2461,7 +2496,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) } if (i > 1) printk(KERN_INFO "%d NAND chips detected\n", i); - + /* Allocate buffers, if neccecary */ if (!this->oob_buf) { size_t len; @@ -2473,7 +2508,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) } this->options |= NAND_OOBBUF_ALLOC; } - + if (!this->data_buf) { size_t len; len = mtd->oobblock + mtd->oobsize; @@ -2500,7 +2535,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) if (!this->autooob) { /* Select the appropriate default oob placement scheme for * placement agnostic filesystems */ - switch (mtd->oobsize) { + switch (mtd->oobsize) { case 8: this->autooob = &nand_oob_8; break; @@ -2516,19 +2551,19 @@ int nand_scan (struct mtd_info *mtd, int maxchips) BUG(); } } - + /* The number of bytes available for the filesystem to place fs dependend * oob data */ mtd->oobavail = 0; for (i = 0; this->autooob->oobfree[i][1]; i++) mtd->oobavail += this->autooob->oobfree[i][1]; - /* + /* * check ECC mode, default to software * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize - * fallback to software ECC + * fallback to software ECC */ - this->eccsize = 256; /* set default eccsize */ + this->eccsize = 256; /* set default eccsize */ this->eccbytes = 3; switch (this->eccmode) { @@ -2543,56 +2578,56 @@ int nand_scan (struct mtd_info *mtd, int maxchips) this->eccsize = 2048; break; - case NAND_ECC_HW3_512: - case NAND_ECC_HW6_512: - case NAND_ECC_HW8_512: + case NAND_ECC_HW3_512: + case NAND_ECC_HW6_512: + case NAND_ECC_HW8_512: if (mtd->oobblock == 256) { printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n"); this->eccmode = NAND_ECC_SOFT; this->calculate_ecc = nand_calculate_ecc; this->correct_data = nand_correct_data; - } else + } else this->eccsize = 512; /* set eccsize to 512 */ break; - + case NAND_ECC_HW3_256: break; - - case NAND_ECC_NONE: + + case NAND_ECC_NONE: printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n"); this->eccmode = NAND_ECC_NONE; break; - case NAND_ECC_SOFT: + case NAND_ECC_SOFT: this->calculate_ecc = nand_calculate_ecc; this->correct_data = nand_correct_data; break; default: printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode); - BUG(); - } + BUG(); + } - /* Check hardware ecc function availability and adjust number of ecc bytes per + /* Check hardware ecc function availability and adjust number of ecc bytes per * calculation step */ switch (this->eccmode) { case NAND_ECC_HW12_2048: this->eccbytes += 4; - case NAND_ECC_HW8_512: + case NAND_ECC_HW8_512: this->eccbytes += 2; - case NAND_ECC_HW6_512: + case NAND_ECC_HW6_512: this->eccbytes += 3; - case NAND_ECC_HW3_512: + case NAND_ECC_HW3_512: case NAND_ECC_HW3_256: if (this->calculate_ecc && this->correct_data && this->enable_hwecc) break; printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n"); - BUG(); + BUG(); } - + mtd->eccsize = this->eccsize; - + /* Set the number of read / write steps for one page to ensure ECC generation */ switch (this->eccmode) { case NAND_ECC_HW12_2048: @@ -2604,15 +2639,15 @@ int nand_scan (struct mtd_info *mtd, int maxchips) this->eccsteps = mtd->oobblock / 512; break; case NAND_ECC_HW3_256: - case NAND_ECC_SOFT: + case NAND_ECC_SOFT: this->eccsteps = mtd->oobblock / 256; break; - - case NAND_ECC_NONE: + + case NAND_ECC_NONE: this->eccsteps = 1; break; } - + /* Initialize state, waitqueue and spinlock */ this->state = FL_READY; init_waitqueue_head (&this->wq); @@ -2643,8 +2678,8 @@ int nand_scan (struct mtd_info *mtd, int maxchips) mtd->sync = nand_sync; mtd->lock = NULL; mtd->unlock = NULL; - mtd->suspend = NULL; - mtd->resume = NULL; + mtd->suspend = nand_suspend; + mtd->resume = nand_resume; mtd->block_isbad = nand_block_isbad; mtd->block_markbad = nand_block_markbad; @@ -2652,7 +2687,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo)); mtd->owner = THIS_MODULE; - + /* Check, if we should skip the bad block table scan */ if (this->options & NAND_SKIP_BBTSCAN) return 0; @@ -2662,7 +2697,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) } /** - * nand_release - [NAND Interface] Free resources held by the NAND device + * nand_release - [NAND Interface] Free resources held by the NAND device * @mtd: MTD device structure */ void nand_release (struct mtd_info *mtd) @@ -2676,9 +2711,8 @@ void nand_release (struct mtd_info *mtd) /* Deregister the device */ del_mtd_device (mtd); - /* Free bad block table memory, if allocated */ - if (this->bbt) - kfree (this->bbt); + /* Free bad block table memory */ + kfree (this->bbt); /* Buffer allocated by nand_scan ? */ if (this->options & NAND_OOBBUF_ALLOC) kfree (this->oob_buf); diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 7535ef53685e8aaa13c8409d88187fd1a354be96..ca286999fe08ab3b39e89f6f2963bc708b440569 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -3,10 +3,10 @@ * * Overview: * Bad block table support for the NAND driver - * + * * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) * - * $Id: nand_bbt.c,v 1.35 2005/07/15 13:53:47 gleixner Exp $ + * $Id: nand_bbt.c,v 1.36 2005/11/07 11:14:30 gleixner Exp $ * * 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 @@ -14,23 +14,23 @@ * * Description: * - * When nand_scan_bbt is called, then it tries to find the bad block table - * depending on the options in the bbt descriptor(s). If a bbt is found - * then the contents are read and the memory based bbt is created. If a + * When nand_scan_bbt is called, then it tries to find the bad block table + * depending on the options in the bbt descriptor(s). If a bbt is found + * then the contents are read and the memory based bbt is created. If a * mirrored bbt is selected then the mirror is searched too and the - * versions are compared. If the mirror has a greater version number + * versions are compared. If the mirror has a greater version number * than the mirror bbt is used to build the memory based bbt. * If the tables are not versioned, then we "or" the bad block information. - * If one of the bbt's is out of date or does not exist it is (re)created. - * If no bbt exists at all then the device is scanned for factory marked - * good / bad blocks and the bad block tables are created. + * If one of the bbt's is out of date or does not exist it is (re)created. + * If no bbt exists at all then the device is scanned for factory marked + * good / bad blocks and the bad block tables are created. * - * For manufacturer created bbts like the one found on M-SYS DOC devices + * For manufacturer created bbts like the one found on M-SYS DOC devices * the bbt is searched and read but never created * - * The autogenerated bad block table is located in the last good blocks - * of the device. The table is mirrored, so it can be updated eventually. - * The table is marked in the oob area with an ident pattern and a version + * The autogenerated bad block table is located in the last good blocks + * of the device. The table is mirrored, so it can be updated eventually. + * The table is marked in the oob area with an ident pattern and a version * number which indicates which of both tables is more up to date. * * The table uses 2 bits per block @@ -43,13 +43,13 @@ * 01b: block is marked bad due to wear * 10b: block is reserved (to protect the bbt area) * 11b: block is factory marked bad - * + * * Multichip devices like DOC store the bad block info per floor. * * Following assumptions are made: * - bbts start at a page boundary, if autolocated on a block boundary * - the space neccecary for a bbt in FLASH does not exceed a block boundary - * + * */ #include @@ -62,7 +62,7 @@ #include -/** +/** * check_pattern - [GENERIC] check if a pattern is in the buffer * @buf: the buffer to search * @len: the length of buffer to search @@ -86,9 +86,9 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des if (p[i] != 0xff) return -1; } - } + } p += end; - + /* Compare the pattern */ for (i = 0; i < td->len; i++) { if (p[i] != td->pattern[i]) @@ -106,13 +106,13 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des return 0; } -/** +/** * check_short_pattern - [GENERIC] check if a pattern is in the buffer * @buf: the buffer to search * @td: search pattern descriptor * * Check for a pattern at the given place. Used to search bad block - * tables and good / bad block identifiers. Same as check_pattern, but + * tables and good / bad block identifiers. Same as check_pattern, but * no optional empty check * */ @@ -142,7 +142,7 @@ static int check_short_pattern (uint8_t *buf, struct nand_bbt_descr *td) * Read the bad block table starting from page. * */ -static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, +static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, int bits, int offs, int reserved_block_code) { int res, i, j, act = 0; @@ -153,7 +153,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, totlen = (num * bits) >> 3; from = ((loff_t)page) << this->page_shift; - + while (totlen) { len = min (totlen, (size_t) (1 << this->bbt_erase_shift)); res = mtd->read_ecc (mtd, from, len, &retlen, buf, NULL, this->autooob); @@ -163,7 +163,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, return res; } printk (KERN_WARNING "nand_bbt: ECC error while reading bad block table\n"); - } + } /* Analyse data */ for (i = 0; i < len; i++) { @@ -183,12 +183,12 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, * message to MTD_DEBUG_LEVEL0 */ printk (KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n", ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); - /* Factory marked bad or worn out ? */ + /* Factory marked bad or worn out ? */ if (tmp == 0) this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); else this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06); - } + } } totlen -= len; from += len; @@ -200,7 +200,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page * @mtd: MTD device structure * @buf: temporary buffer - * @td: descriptor for the bad block table + * @td: descriptor for the bad block table * @chip: read the table for a specific chip, -1 read all chips. * Applies only if NAND_BBT_PERCHIP option is set * @@ -235,7 +235,7 @@ static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page * @mtd: MTD device structure * @buf: temporary buffer - * @td: descriptor for the bad block table + * @td: descriptor for the bad block table * @md: descriptor for the bad block table mirror * * Read the bad block table(s) for all chips starting at a given page @@ -247,16 +247,16 @@ static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_de { struct nand_chip *this = mtd->priv; - /* Read the primary version, if available */ + /* Read the primary version, if available */ if (td->options & NAND_BBT_VERSION) { - nand_read_raw (mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); + nand_read_raw (mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); td->version[0] = buf[mtd->oobblock + td->veroffs]; printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]); } - /* Read the mirror version, if available */ + /* Read the mirror version, if available */ if (md && (md->options & NAND_BBT_VERSION)) { - nand_read_raw (mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); + nand_read_raw (mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); md->version[0] = buf[mtd->oobblock + md->veroffs]; printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]); } @@ -290,7 +290,7 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr else { if (bd->options & NAND_BBT_SCAN2NDPAGE) len = 2; - else + else len = 1; } @@ -322,10 +322,10 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr numblocks += startblock; from = startblock << (this->bbt_erase_shift - 1); } - + for (i = startblock; i < numblocks;) { int ret; - + if (bd->options & NAND_BBT_SCANEMPTY) if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen))) return ret; @@ -333,8 +333,8 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr for (j = 0; j < len; j++) { if (!(bd->options & NAND_BBT_SCANEMPTY)) { size_t retlen; - - /* Read the full oob until read_oob is fixed to + + /* Read the full oob until read_oob is fixed to * handle single byte reads for 16 bit buswidth */ ret = mtd->read_oob(mtd, from + j * mtd->oobblock, mtd->oobsize, &retlen, buf); @@ -343,14 +343,14 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr if (check_short_pattern (buf, bd)) { this->bbt[i >> 3] |= 0x03 << (i & 0x6); - printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", + printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", i >> 1, (unsigned int) from); break; } } else { if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { this->bbt[i >> 3] |= 0x03 << (i & 0x6); - printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", + printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", i >> 1, (unsigned int) from); break; } @@ -369,15 +369,15 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr * @td: descriptor for the bad block table * * Read the bad block table by searching for a given ident pattern. - * Search is preformed either from the beginning up or from the end of + * Search is preformed either from the beginning up or from the end of * the device downwards. The search starts always at the start of a * block. - * If the option NAND_BBT_PERCHIP is given, each chip is searched + * If the option NAND_BBT_PERCHIP is given, each chip is searched * for a bbt, which contains the bad block information of this chip. * This is neccecary to provide support for certain DOC devices. * - * The bbt ident pattern resides in the oob area of the first page - * in a block. + * The bbt ident pattern resides in the oob area of the first page + * in a block. */ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) { @@ -392,10 +392,10 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr startblock = (mtd->size >> this->bbt_erase_shift) -1; dir = -1; } else { - startblock = 0; + startblock = 0; dir = 1; - } - + } + /* Do we have a bbt per chip ? */ if (td->options & NAND_BBT_PERCHIP) { chips = this->numchips; @@ -405,19 +405,19 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr chips = 1; bbtblocks = mtd->size >> this->bbt_erase_shift; } - + /* Number of bits for each erase block in the bbt */ bits = td->options & NAND_BBT_NRBITS_MSK; - + for (i = 0; i < chips; i++) { /* Reset version information */ - td->version[i] = 0; + td->version[i] = 0; td->pages[i] = -1; /* Scan the maximum number of blocks */ for (block = 0; block < td->maxblocks; block++) { int actblock = startblock + dir * block; /* Read first page */ - nand_read_raw (mtd, buf, actblock << this->bbt_erase_shift, mtd->oobblock, mtd->oobsize); + nand_read_raw (mtd, buf, actblock << this->bbt_erase_shift, mtd->oobblock, mtd->oobsize); if (!check_pattern(buf, scanlen, mtd->oobblock, td)) { td->pages[i] = actblock << (this->bbt_erase_shift - this->page_shift); if (td->options & NAND_BBT_VERSION) { @@ -435,46 +435,46 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr else printk (KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], td->version[i]); } - return 0; + return 0; } /** * search_read_bbts - [GENERIC] scan the device for bad block table(s) * @mtd: MTD device structure * @buf: temporary buffer - * @td: descriptor for the bad block table + * @td: descriptor for the bad block table * @md: descriptor for the bad block table mirror * * Search and read the bad block table(s) */ -static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf, +static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) { /* Search the primary table */ search_bbt (mtd, buf, td); - + /* Search the mirror table */ if (md) search_bbt (mtd, buf, md); - + /* Force result check */ - return 1; + return 1; } - -/** + +/** * write_bbt - [GENERIC] (Re)write the bad block table * * @mtd: MTD device structure * @buf: temporary buffer - * @td: descriptor for the bad block table + * @td: descriptor for the bad block table * @md: descriptor for the bad block table mirror * @chipsel: selector for a specific chip, -1 for all * * (Re)write the bad block table * */ -static int write_bbt (struct mtd_info *mtd, uint8_t *buf, +static int write_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel) { struct nand_chip *this = mtd->priv; @@ -493,7 +493,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, /* Write bad block table per chip rather than per device ? */ if (td->options & NAND_BBT_PERCHIP) { numblocks = (int) (this->chipsize >> this->bbt_erase_shift); - /* Full device write or specific chip ? */ + /* Full device write or specific chip ? */ if (chipsel == -1) { nrchips = this->numchips; } else { @@ -503,19 +503,19 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, } else { numblocks = (int) (mtd->size >> this->bbt_erase_shift); nrchips = 1; - } - + } + /* Loop through the chips */ for (; chip < nrchips; chip++) { - - /* There was already a version of the table, reuse the page - * This applies for absolute placement too, as we have the + + /* There was already a version of the table, reuse the page + * This applies for absolute placement too, as we have the * page nr. in td->pages. */ if (td->pages[chip] != -1) { page = td->pages[chip]; goto write; - } + } /* Automatic placement of the bad block table */ /* Search direction top -> down ? */ @@ -525,7 +525,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, } else { startblock = chip * numblocks; dir = 1; - } + } for (i = 0; i < td->maxblocks; i++) { int block = startblock + dir * i; @@ -542,7 +542,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, } printk (KERN_ERR "No space left to write bad block table\n"); return -ENOSPC; -write: +write: /* Set up shift count and masks for the flash table */ bits = td->options & NAND_BBT_NRBITS_MSK; @@ -553,14 +553,14 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; msk[2] = ~rcode; msk[3] = 0xff; break; default: return -EINVAL; } - + bbtoffs = chip * (numblocks >> 2); - + to = ((loff_t) page) << this->page_shift; memcpy (&oobinfo, this->autooob, sizeof(oobinfo)); oobinfo.useecc = MTD_NANDECC_PLACEONLY; - + /* Must we save the block contents ? */ if (td->options & NAND_BBT_SAVECONTENT) { /* Make it block aligned */ @@ -599,7 +599,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, buf[len + td->veroffs] = td->version[chip]; } } - + /* walk through the memory table */ for (i = 0; i < numblocks; ) { uint8_t dat; @@ -611,7 +611,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, dat >>= 2; } } - + memset (&einfo, 0, sizeof (einfo)); einfo.mtd = mtd; einfo.addr = (unsigned long) to; @@ -621,18 +621,18 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, printk (KERN_WARNING "nand_bbt: Error during block erase: %d\n", res); return res; } - + res = mtd->write_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo); if (res < 0) { printk (KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res); return res; } - printk (KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n", + printk (KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n", (unsigned int) to, td->version[chip]); - + /* Mark it as used */ td->pages[chip] = page; - } + } return 0; } @@ -641,7 +641,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, * @mtd: MTD device structure * @bd: descriptor for the good/bad block search pattern * - * The function creates a memory based bbt by scanning the device + * The function creates a memory based bbt by scanning the device * for manufacturer / software marked good / bad blocks */ static inline int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) @@ -673,11 +673,11 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des struct nand_bbt_descr *rd, *rd2; /* Do we have a bbt per chip ? */ - if (td->options & NAND_BBT_PERCHIP) + if (td->options & NAND_BBT_PERCHIP) chips = this->numchips; - else + else chips = 1; - + for (i = 0; i < chips; i++) { writeops = 0; rd = NULL; @@ -692,7 +692,7 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des } if (td->pages[i] == -1) { - rd = md; + rd = md; td->version[i] = md->version[i]; writeops = 1; goto writecheck; @@ -710,7 +710,7 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des if (!(td->options & NAND_BBT_VERSION)) rd2 = md; goto writecheck; - } + } if (((int8_t) (td->version[i] - md->version[i])) > 0) { rd = td; @@ -735,15 +735,15 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des create: /* Create the bad block table by scanning the device ? */ if (!(td->options & NAND_BBT_CREATE)) - continue; - + continue; + /* Create the table in memory by scanning the chip(s) */ create_bbt (mtd, buf, bd, chipsel); - + td->version[i] = 1; if (md) - md->version[i] = 1; -writecheck: + md->version[i] = 1; +writecheck: /* read back first ? */ if (rd) read_abs_bbt (mtd, buf, rd, chipsel); @@ -757,7 +757,7 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des if (res < 0) return res; } - + /* Write the mirror bad block table to the device ? */ if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { res = write_bbt (mtd, buf, md, td, chipsel); @@ -765,11 +765,11 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des return res; } } - return 0; + return 0; } /** - * mark_bbt_regions - [GENERIC] mark the bad block table regions + * mark_bbt_regions - [GENERIC] mark the bad block table regions * @mtd: MTD device structure * @td: bad block table descriptor * @@ -790,14 +790,14 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td) } else { chips = 1; nrblocks = (int)(mtd->size >> this->bbt_erase_shift); - } - + } + for (i = 0; i < chips; i++) { if ((td->options & NAND_BBT_ABSPAGE) || !(td->options & NAND_BBT_WRITE)) { if (td->pages[i] == -1) continue; block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift); - block <<= 1; + block <<= 1; oldval = this->bbt[(block >> 3)]; newval = oldval | (0x2 << (block & 0x06)); this->bbt[(block >> 3)] = newval; @@ -808,16 +808,16 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td) update = 0; if (td->options & NAND_BBT_LASTBLOCK) block = ((i + 1) * nrblocks) - td->maxblocks; - else + else block = i * nrblocks; - block <<= 1; + block <<= 1; for (j = 0; j < td->maxblocks; j++) { oldval = this->bbt[(block >> 3)]; newval = oldval | (0x2 << (block & 0x06)); this->bbt[(block >> 3)] = newval; if (oldval != newval) update = 1; block += 2; - } + } /* If we want reserved blocks to be recorded to flash, and some new ones have been marked, then we need to update the stored bbts. This should only happen once. */ @@ -831,7 +831,7 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td) * @mtd: MTD device structure * @bd: descriptor for the good/bad block search pattern * - * The function checks, if a bad block table(s) is/are already + * The function checks, if a bad block table(s) is/are already * available. If not it scans the device for manufacturer * marked good / bad blocks and writes the bad block table(s) to * the selected place. @@ -880,30 +880,30 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) this->bbt = NULL; return -ENOMEM; } - + /* Is the bbt at a given page ? */ if (td->options & NAND_BBT_ABSPAGE) { res = read_abs_bbts (mtd, buf, td, md); - } else { + } else { /* Search the bad block table using a pattern in oob */ res = search_read_bbts (mtd, buf, td, md); - } + } - if (res) + if (res) res = check_create (mtd, buf, bd); - + /* Prevent the bbt regions from erasing / writing */ mark_bbt_region (mtd, td); if (md) mark_bbt_region (mtd, md); - + kfree (buf); return res; } /** - * nand_update_bbt - [NAND Interface] update bad block table(s) + * nand_update_bbt - [NAND Interface] update bad block table(s) * @mtd: MTD device structure * @offs: the offset of the newly marked block * @@ -930,7 +930,7 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs) printk (KERN_ERR "nand_update_bbt: Out of memory\n"); return -ENOMEM; } - + writeops = md != NULL ? 0x03 : 0x01; /* Do we have a bbt per chip ? */ @@ -944,7 +944,7 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs) td->version[chip]++; if (md) - md->version[chip]++; + md->version[chip]++; /* Write the bad block table to the device ? */ if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { @@ -957,12 +957,12 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs) res = write_bbt (mtd, buf, md, td, chipsel); } -out: +out: kfree (buf); return res; } -/* Define some generic bad / good block scan pattern which are used +/* Define some generic bad / good block scan pattern which are used * while scanning a device for factory marked good / bad blocks. */ static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; @@ -1009,7 +1009,7 @@ static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' }; static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; static struct nand_bbt_descr bbt_main_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, .offs = 8, .len = 4, @@ -1019,7 +1019,7 @@ static struct nand_bbt_descr bbt_main_descr = { }; static struct nand_bbt_descr bbt_mirror_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, .offs = 8, .len = 4, @@ -1029,7 +1029,7 @@ static struct nand_bbt_descr bbt_mirror_descr = { }; /** - * nand_default_bbt - [NAND Interface] Select a default bad block table for the device + * nand_default_bbt - [NAND Interface] Select a default bad block table for the device * @mtd: MTD device structure * * This function selects the default bad block table @@ -1039,29 +1039,29 @@ static struct nand_bbt_descr bbt_mirror_descr = { int nand_default_bbt (struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; - - /* Default for AG-AND. We must use a flash based + + /* Default for AG-AND. We must use a flash based * bad block table as the devices have factory marked * _good_ blocks. Erasing those blocks leads to loss * of the good / bad information, so we _must_ store - * this information in a good / bad table during + * this information in a good / bad table during * startup */ if (this->options & NAND_IS_AND) { /* Use the default pattern descriptors */ - if (!this->bbt_td) { + if (!this->bbt_td) { this->bbt_td = &bbt_main_descr; this->bbt_md = &bbt_mirror_descr; - } + } this->options |= NAND_USE_FLASH_BBT; return nand_scan_bbt (mtd, &agand_flashbased); } - - + + /* Is a flash based bad block table requested ? */ if (this->options & NAND_USE_FLASH_BBT) { - /* Use the default pattern descriptors */ - if (!this->bbt_td) { + /* Use the default pattern descriptors */ + if (!this->bbt_td) { this->bbt_td = &bbt_main_descr; this->bbt_md = &bbt_mirror_descr; } @@ -1081,7 +1081,7 @@ int nand_default_bbt (struct mtd_info *mtd) } /** - * nand_isbad_bbt - [NAND Interface] Check if a block is bad + * nand_isbad_bbt - [NAND Interface] Check if a block is bad * @mtd: MTD device structure * @offs: offset in the device * @allowbbt: allow access to bad block table region @@ -1092,12 +1092,12 @@ int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt) struct nand_chip *this = mtd->priv; int block; uint8_t res; - + /* Get block number * 2 */ block = (int) (offs >> (this->bbt_erase_shift - 1)); res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; - DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", + DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", (unsigned int)offs, block >> 1, res); switch ((int)res) { diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index 2e341b75437ae2e15fb7b3dc54bb8b578bf5a308..40ac909150a3db5701c572fe536b9e1e6a5c766b 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c @@ -7,22 +7,22 @@ * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com) * Toshiba America Electronics Components, Inc. * - * $Id: nand_ecc.c,v 1.14 2004/06/16 15:34:37 gleixner Exp $ + * $Id: nand_ecc.c,v 1.15 2005/11/07 11:14:30 gleixner Exp $ * * This file is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 or (at your option) any * later version. - * + * * This file is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. - * + * * You should have received a copy of the GNU General Public License along * with this file; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * + * * As a special exception, if other files instantiate templates or use * macros or inline functions from these files, or you compile these * files and link them with other works to produce a work based on these @@ -30,7 +30,7 @@ * covered by the GNU General Public License. However the source code for * these files must still be made available in accordance with section (3) * of the GNU General Public License. - * + * * This exception does not invalidate any other reasons why a work based on * this file might be covered by the GNU General Public License. */ @@ -67,7 +67,7 @@ static const u_char nand_ecc_precalc_table[] = { * nand_trans_result - [GENERIC] create non-inverted ECC * @reg2: line parity reg 2 * @reg3: line parity reg 3 - * @ecc_code: ecc + * @ecc_code: ecc * * Creates non-inverted ECC code from line parity */ @@ -75,11 +75,11 @@ static void nand_trans_result(u_char reg2, u_char reg3, u_char *ecc_code) { u_char a, b, i, tmp1, tmp2; - + /* Initialize variables */ a = b = 0x80; tmp1 = tmp2 = 0; - + /* Calculate first ECC byte */ for (i = 0; i < 4; i++) { if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ @@ -90,7 +90,7 @@ static void nand_trans_result(u_char reg2, u_char reg3, b >>= 1; a >>= 1; } - + /* Calculate second ECC byte */ b = 0x80; for (i = 0; i < 4; i++) { @@ -102,7 +102,7 @@ static void nand_trans_result(u_char reg2, u_char reg3, b >>= 1; a >>= 1; } - + /* Store two of the ECC bytes */ ecc_code[0] = tmp1; ecc_code[1] = tmp2; @@ -118,28 +118,28 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code { u_char idx, reg1, reg2, reg3; int j; - + /* Initialize variables */ reg1 = reg2 = reg3 = 0; ecc_code[0] = ecc_code[1] = ecc_code[2] = 0; - - /* Build up column parity */ + + /* Build up column parity */ for(j = 0; j < 256; j++) { - + /* Get CP0 - CP5 from table */ idx = nand_ecc_precalc_table[dat[j]]; reg1 ^= (idx & 0x3f); - + /* All bit XOR = 1 ? */ if (idx & 0x40) { reg3 ^= (u_char) j; reg2 ^= ~((u_char) j); } } - + /* Create non-inverted ECC code from line parity */ nand_trans_result(reg2, reg3, ecc_code); - + /* Calculate final ECC code */ ecc_code[0] = ~ecc_code[0]; ecc_code[1] = ~ecc_code[1]; @@ -159,12 +159,12 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) { u_char a, b, c, d1, d2, d3, add, bit, i; - - /* Do error detection */ + + /* Do error detection */ d1 = calc_ecc[0] ^ read_ecc[0]; d2 = calc_ecc[1] ^ read_ecc[1]; d3 = calc_ecc[2] ^ read_ecc[2]; - + if ((d1 | d2 | d3) == 0) { /* No errors */ return 0; @@ -173,7 +173,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_cha a = (d1 ^ (d1 >> 1)) & 0x55; b = (d2 ^ (d2 >> 1)) & 0x55; c = (d3 ^ (d3 >> 1)) & 0x54; - + /* Found and will correct single bit error in the data */ if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { c = 0x80; @@ -237,7 +237,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_cha } } } - + /* Should never happen */ return -1; } diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index efe246961b69fe1d1ee7b490a0108cdd24e95e1c..dbc7e55a4247a215cf1097c1ea289be0d51bd357 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -3,7 +3,7 @@ * * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) * - * $Id: nand_ids.c,v 1.14 2005/06/23 09:38:50 gleixner Exp $ + * $Id: nand_ids.c,v 1.16 2005/11/07 11:14:31 gleixner Exp $ * * 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 @@ -14,14 +14,14 @@ #include /* * Chip ID list -* +* * Name. ID code, pagesize, chipsize in MegaByte, eraseblock size, * options -* +* * Pagesize; 0, 256, 512 * 0 get this information from the extended chip ID + 256 256 Byte page size -* 512 512 Byte page size +* 512 512 Byte page size */ struct nand_flash_dev nand_flash_ids[] = { {"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0}, @@ -34,27 +34,27 @@ struct nand_flash_dev nand_flash_ids[] = { {"NAND 4MiB 3,3V 8-bit", 0xe3, 512, 4, 0x2000, 0}, {"NAND 4MiB 3,3V 8-bit", 0xe5, 512, 4, 0x2000, 0}, {"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 0x2000, 0}, - + {"NAND 8MiB 1,8V 8-bit", 0x39, 512, 8, 0x2000, 0}, {"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0}, {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16}, {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16}, - + {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0}, {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0}, {"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16}, {"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16}, - + {"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, 0}, {"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, 0}, {"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16}, {"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16}, - + {"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, 0}, {"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0}, {"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16}, {"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16}, - + {"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0}, {"NAND 128MiB 1,8V 8-bit", 0x39, 512, 128, 0x4000, 0}, {"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0}, @@ -62,7 +62,7 @@ struct nand_flash_dev nand_flash_ids[] = { {"NAND 128MiB 1,8V 16-bit", 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16}, {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16}, {"NAND 128MiB 3,3V 16-bit", 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16}, - + {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0}, /* These are the new chips with large page size. The pagesize @@ -73,7 +73,7 @@ struct nand_flash_dev nand_flash_ids[] = { {"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, {"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, {"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, - + /* 1 Gigabit */ {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, @@ -85,13 +85,13 @@ struct nand_flash_dev nand_flash_ids[] = { {"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, {"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, {"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, - + /* 4 Gigabit */ {"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, {"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, {"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, {"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, - + /* 8 Gigabit */ {"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, {"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, @@ -104,11 +104,11 @@ struct nand_flash_dev nand_flash_ids[] = { {"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, - /* Renesas AND 1 Gigabit. Those chips do not support extended id and have a strange page/block layout ! + /* Renesas AND 1 Gigabit. Those chips do not support extended id and have a strange page/block layout ! * The chosen minimum erasesize is 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page planes * 1 block = 2 pages, but due to plane arrangement the blocks 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7 * Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go - * There are more speed improvements for reads and writes possible, but not implemented now + * There are more speed improvements for reads and writes possible, but not implemented now */ {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH}, diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 754b6ed7ce140b5470f5c8533ac45b0aedf4030a..de4500395300065d99e3489e4d445947c64b1fed 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -3,7 +3,7 @@ * * Author: Artem B. Bityuckiy , * - * Copyright (C) 2004 Nokia Corporation + * Copyright (C) 2004 Nokia Corporation * * Note: NS means "NAND Simulator". * Note: Input means input TO flash chip, output means output FROM chip. @@ -126,7 +126,7 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero"); /* The largest possible page size */ #define NS_LARGEST_PAGE_SIZE 2048 - + /* The prefix for simulator output */ #define NS_OUTPUT_PREFIX "[nandsim]" @@ -145,7 +145,7 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero"); do { if (do_delays) udelay(us); } while(0) #define NS_MDELAY(us) \ do { if (do_delays) mdelay(us); } while(0) - + /* Is the nandsim structure initialized ? */ #define NS_IS_INITIALIZED(ns) ((ns)->geom.totsz != 0) @@ -153,12 +153,12 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero"); #define NS_STATUS_OK(ns) (NAND_STATUS_READY | (NAND_STATUS_WP * ((ns)->lines.wp == 0))) /* Operation failed completion status */ -#define NS_STATUS_FAILED(ns) (NAND_STATUS_FAIL | NS_STATUS_OK(ns)) +#define NS_STATUS_FAILED(ns) (NAND_STATUS_FAIL | NS_STATUS_OK(ns)) /* Calculate the page offset in flash RAM image by (row, column) address */ #define NS_RAW_OFFSET(ns) \ (((ns)->regs.row << (ns)->geom.pgshift) + ((ns)->regs.row * (ns)->geom.oobsz) + (ns)->regs.column) - + /* Calculate the OOB offset in flash RAM image by (row, column) address */ #define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz) @@ -223,15 +223,15 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero"); /* Remove action bits ftom state */ #define NS_STATE(x) ((x) & ~ACTION_MASK) - -/* + +/* * Maximum previous states which need to be saved. Currently saving is * only needed for page programm operation with preceeded read command * (which is only valid for 512-byte pages). */ #define NS_MAX_PREVSTATES 1 -/* +/* * The structure which describes all the internal simulator data. */ struct nandsim { @@ -242,7 +242,7 @@ struct nandsim { uint32_t options; /* chip's characteristic bits */ uint32_t state; /* current chip state */ uint32_t nxstate; /* next expected state */ - + uint32_t *op; /* current operation, NULL operations isn't known yet */ uint32_t pstates[NS_MAX_PREVSTATES]; /* previous states */ uint16_t npstates; /* number of previous states saved */ @@ -413,7 +413,7 @@ init_nandsim(struct mtd_info *mtd) ns->geom.secaddrbytes = 3; } } - + /* Detect how many ID bytes the NAND chip outputs */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { if (second_id_byte != nand_flash_ids[i].id) @@ -444,7 +444,7 @@ init_nandsim(struct mtd_info *mtd) #ifdef CONFIG_NS_ABS_POS ns->mem.byte = ioremap(CONFIG_NS_ABS_POS, ns->geom.totszoob); if (!ns->mem.byte) { - NS_ERR("init_nandsim: failed to map the NAND flash image at address %p\n", + NS_ERR("init_nandsim: failed to map the NAND flash image at address %p\n", (void *)CONFIG_NS_ABS_POS); return -ENOMEM; } @@ -567,7 +567,7 @@ static int check_command(int cmd) { switch (cmd) { - + case NAND_CMD_READ0: case NAND_CMD_READSTART: case NAND_CMD_PAGEPROG: @@ -580,7 +580,7 @@ check_command(int cmd) case NAND_CMD_RESET: case NAND_CMD_READ1: return 0; - + case NAND_CMD_STATUS_MULTI: default: return 1; @@ -631,7 +631,7 @@ static inline void accept_addr_byte(struct nandsim *ns, u_char bt) { uint byte = (uint)bt; - + if (ns->regs.count < (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) ns->regs.column |= (byte << 8 * ns->regs.count); else { @@ -642,11 +642,11 @@ accept_addr_byte(struct nandsim *ns, u_char bt) return; } - + /* * Switch to STATE_READY state. */ -static inline void +static inline void switch_to_ready_state(struct nandsim *ns, u_char status) { NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY)); @@ -675,7 +675,7 @@ switch_to_ready_state(struct nandsim *ns, u_char status) * (for example program from the second half and read from the * second half operations both begin with the READ1 command). In this * case the ns->pstates[] array contains previous states. - * + * * Thus, the function tries to find operation containing the following * states (if the 'flag' parameter is 0): * ns->pstates[0], ... ns->pstates[ns->npstates], ns->state @@ -683,7 +683,7 @@ switch_to_ready_state(struct nandsim *ns, u_char status) * If (one and only one) matching operation is found, it is accepted ( * ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is * zeroed). - * + * * If there are several maches, the current state is pushed to the * ns->pstates. * @@ -692,7 +692,7 @@ switch_to_ready_state(struct nandsim *ns, u_char status) * In such situation the function is called with 'flag' != 0, and the * operation is searched using the following pattern: * ns->pstates[0], ... ns->pstates[ns->npstates],
- * + * * It is supposed that this pattern must either match one operation on * none. There can't be ambiguity in that case. * @@ -711,15 +711,15 @@ find_operation(struct nandsim *ns, uint32_t flag) { int opsfound = 0; int i, j, idx = 0; - + for (i = 0; i < NS_OPER_NUM; i++) { int found = 1; - + if (!(ns->options & ops[i].reqopts)) /* Ignore operations we can't perform */ continue; - + if (flag) { if (!(ops[i].states[ns->npstates] & STATE_ADDR_MASK)) continue; @@ -728,7 +728,7 @@ find_operation(struct nandsim *ns, uint32_t flag) continue; } - for (j = 0; j < ns->npstates; j++) + for (j = 0; j < ns->npstates; j++) if (NS_STATE(ops[i].states[j]) != NS_STATE(ns->pstates[j]) && (ns->options & ops[idx].reqopts)) { found = 0; @@ -745,7 +745,7 @@ find_operation(struct nandsim *ns, uint32_t flag) /* Exact match */ ns->op = &ops[idx].states[0]; if (flag) { - /* + /* * In this case the find_operation function was * called when address has just began input. But it isn't * yet fully input and the current state must @@ -763,7 +763,7 @@ find_operation(struct nandsim *ns, uint32_t flag) idx, get_state_name(ns->state), get_state_name(ns->nxstate)); return 0; } - + if (opsfound == 0) { /* Nothing was found. Try to ignore previous commands (if any) and search again */ if (ns->npstates != 0) { @@ -777,13 +777,13 @@ find_operation(struct nandsim *ns, uint32_t flag) switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); return -2; } - + if (flag) { /* This shouldn't happen */ NS_DBG("find_operation: BUG, operation must be known if address is input\n"); return -2; } - + NS_DBG("find_operation: there is still ambiguity\n"); ns->pstates[ns->npstates++] = ns->state; @@ -803,7 +803,7 @@ do_state_action(struct nandsim *ns, uint32_t action) int busdiv = ns->busw == 8 ? 1 : 2; action &= ACTION_MASK; - + /* Check that page address input is correct */ if (action != ACTION_SECERASE && ns->regs.row >= ns->geom.pgnum) { NS_WARN("do_state_action: wrong page number (%#x)\n", ns->regs.row); @@ -827,14 +827,14 @@ do_state_action(struct nandsim *ns, uint32_t action) NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n", num, NS_RAW_OFFSET(ns) + ns->regs.off); - + if (ns->regs.off == 0) NS_LOG("read page %d\n", ns->regs.row); else if (ns->regs.off < ns->geom.pgsz) NS_LOG("read page %d (second half)\n", ns->regs.row); else NS_LOG("read OOB of page %d\n", ns->regs.row); - + NS_UDELAY(access_delay); NS_UDELAY(input_cycle * ns->geom.pgsz / 1000 / busdiv); @@ -844,30 +844,30 @@ do_state_action(struct nandsim *ns, uint32_t action) /* * Erase sector. */ - + if (ns->lines.wp) { NS_ERR("do_state_action: device is write-protected, ignore sector erase\n"); return -1; } - + if (ns->regs.row >= ns->geom.pgnum - ns->geom.pgsec || (ns->regs.row & ~(ns->geom.secsz - 1))) { NS_ERR("do_state_action: wrong sector address (%#x)\n", ns->regs.row); return -1; } - + ns->regs.row = (ns->regs.row << 8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column; ns->regs.column = 0; - + NS_DBG("do_state_action: erase sector at address %#x, off = %d\n", ns->regs.row, NS_RAW_OFFSET(ns)); NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift)); memset(ns->mem.byte + NS_RAW_OFFSET(ns), 0xFF, ns->geom.secszoob); - + NS_MDELAY(erase_delay); - + break; case ACTION_PRGPAGE: @@ -893,12 +893,12 @@ do_state_action(struct nandsim *ns, uint32_t action) NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n", num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off); NS_LOG("programm page %d\n", ns->regs.row); - + NS_UDELAY(programm_delay); NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv); - + break; - + case ACTION_ZEROOFF: NS_DBG("do_state_action: set internal offset to 0\n"); ns->regs.off = 0; @@ -918,7 +918,7 @@ do_state_action(struct nandsim *ns, uint32_t action) NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz); ns->regs.off = ns->geom.pgsz; break; - + default: NS_DBG("do_state_action: BUG! unknown action\n"); } @@ -937,7 +937,7 @@ switch_state(struct nandsim *ns) * The current operation have already been identified. * Just follow the states chain. */ - + ns->stateidx += 1; ns->state = ns->nxstate; ns->nxstate = ns->op[ns->stateidx + 1]; @@ -951,14 +951,14 @@ switch_state(struct nandsim *ns) switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); return; } - + } else { /* * We don't yet know which operation we perform. * Try to identify it. */ - /* + /* * The only event causing the switch_state function to * be called with yet unknown operation is new command. */ @@ -987,7 +987,7 @@ switch_state(struct nandsim *ns) */ u_char status = NS_STATUS_OK(ns); - + /* In case of data states, see if all bytes were input/output */ if ((ns->state & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK)) && ns->regs.count != ns->regs.num) { @@ -995,17 +995,17 @@ switch_state(struct nandsim *ns) ns->regs.num - ns->regs.count); status = NS_STATUS_FAILED(ns); } - + NS_DBG("switch_state: operation complete, switch to STATE_READY state\n"); switch_to_ready_state(ns, status); return; } else if (ns->nxstate & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK)) { - /* + /* * If the next state is data input/output, switch to it now */ - + ns->state = ns->nxstate; ns->nxstate = ns->op[++ns->stateidx + 1]; ns->regs.num = ns->regs.count = 0; @@ -1023,16 +1023,16 @@ switch_state(struct nandsim *ns) case STATE_DATAOUT: ns->regs.num = ns->geom.pgszoob - ns->regs.off - ns->regs.column; break; - + case STATE_DATAOUT_ID: ns->regs.num = ns->geom.idbytes; break; - + case STATE_DATAOUT_STATUS: case STATE_DATAOUT_STATUS_M: ns->regs.count = ns->regs.num = 0; break; - + default: NS_ERR("switch_state: BUG! unknown data state\n"); } @@ -1044,16 +1044,16 @@ switch_state(struct nandsim *ns) */ ns->regs.count = 0; - + switch (NS_STATE(ns->nxstate)) { case STATE_ADDR_PAGE: ns->regs.num = ns->geom.pgaddrbytes; - + break; case STATE_ADDR_SEC: ns->regs.num = ns->geom.secaddrbytes; break; - + case STATE_ADDR_ZERO: ns->regs.num = 1; break; @@ -1062,7 +1062,7 @@ switch_state(struct nandsim *ns) NS_ERR("switch_state: BUG! unknown address state\n"); } } else { - /* + /* * Just reset internal counters. */ @@ -1184,7 +1184,7 @@ ns_nand_read_byte(struct mtd_info *mtd) default: BUG(); } - + if (ns->regs.count == ns->regs.num) { NS_DBG("read_byte: all bytes were read\n"); @@ -1201,9 +1201,9 @@ ns_nand_read_byte(struct mtd_info *mtd) } else if (NS_STATE(ns->nxstate) == STATE_READY) switch_state(ns); - + } - + return outb; } @@ -1211,7 +1211,7 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte) { struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; - + /* Sanity and correctness checks */ if (!ns->lines.ce) { NS_ERR("write_byte: chip is disabled, ignore write\n"); @@ -1221,7 +1221,7 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte) NS_ERR("write_byte: ALE and CLE pins are high simultaneously, ignore write\n"); return; } - + if (ns->lines.cle == 1) { /* * The byte written is a command. @@ -1233,7 +1233,7 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte) return; } - /* + /* * Chip might still be in STATE_DATAOUT * (if OPT_AUTOINCR feature is supported), STATE_DATAOUT_STATUS or * STATE_DATAOUT_STATUS_M state. If so, switch state. @@ -1254,13 +1254,13 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte) "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate)); switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); } - + /* Check that the command byte is correct */ if (check_command(byte)) { NS_ERR("write_byte: unknown command %#x\n", (uint)byte); return; } - + NS_DBG("command byte corresponding to %s state accepted\n", get_state_name(get_state_by_command(byte))); ns->regs.command = byte; @@ -1277,12 +1277,12 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte) if (find_operation(ns, 1) < 0) return; - + if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) { switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); return; } - + ns->regs.count = 0; switch (NS_STATE(ns->nxstate)) { case STATE_ADDR_PAGE: @@ -1306,7 +1306,7 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte) switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); return; } - + /* Check if this is expected byte */ if (ns->regs.count == ns->regs.num) { NS_ERR("write_byte: no more address bytes expected\n"); @@ -1325,12 +1325,12 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte) NS_DBG("address (%#x, %#x) is accepted\n", ns->regs.row, ns->regs.column); switch_state(ns); } - + } else { /* * The byte written is an input data. */ - + /* Check that chip is expecting data input */ if (!(ns->state & STATE_DATAIN_MASK)) { NS_ERR("write_byte: data input (%#x) isn't expected, state is %s, " @@ -1372,7 +1372,7 @@ ns_nand_read_word(struct mtd_info *mtd) struct nand_chip *chip = (struct nand_chip *)mtd->priv; NS_DBG("read_word\n"); - + return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8); } @@ -1380,14 +1380,14 @@ static void ns_nand_write_word(struct mtd_info *mtd, uint16_t word) { struct nand_chip *chip = (struct nand_chip *)mtd->priv; - + NS_DBG("write_word\n"); - + chip->write_byte(mtd, word & 0xFF); chip->write_byte(mtd, word >> 8); } -static void +static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) { struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; @@ -1409,13 +1409,13 @@ ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) memcpy(ns->buf.byte + ns->regs.count, buf, len); ns->regs.count += len; - + if (ns->regs.count == ns->regs.num) { NS_DBG("write_buf: %d bytes were written\n", ns->regs.count); } } -static void +static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) { struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; @@ -1453,7 +1453,7 @@ ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) memcpy(buf, ns->buf.byte + ns->regs.count, len); ns->regs.count += len; - + if (ns->regs.count == ns->regs.num) { if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) { ns->regs.count = 0; @@ -1465,11 +1465,11 @@ ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) else if (NS_STATE(ns->nxstate) == STATE_READY) switch_state(ns); } - + return; } -static int +static int ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) { ns_nand_read_buf(mtd, (u_char *)&ns_verify_buf[0], len); @@ -1496,7 +1496,7 @@ int __init ns_init_module(void) NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width); return -EINVAL; } - + /* Allocate and initialize mtd_info, nand_chip and nandsim structures */ nsmtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip) + sizeof(struct nandsim), GFP_KERNEL); @@ -1509,7 +1509,7 @@ int __init ns_init_module(void) chip = (struct nand_chip *)(nsmtd + 1); nsmtd->priv = (void *)chip; nand = (struct nandsim *)(chip + 1); - chip->priv = (void *)nand; + chip->priv = (void *)nand; /* * Register simulator's callbacks. @@ -1526,9 +1526,9 @@ int __init ns_init_module(void) chip->eccmode = NAND_ECC_SOFT; chip->options |= NAND_SKIP_BBTSCAN; - /* + /* * Perform minimum nandsim structure initialization to handle - * the initial ID read command correctly + * the initial ID read command correctly */ if (third_id_byte != 0xFF || fourth_id_byte != 0xFF) nand->geom.idbytes = 4; @@ -1557,7 +1557,7 @@ int __init ns_init_module(void) NS_ERR("scan_bbt: can't initialize the nandsim structure\n"); goto error; } - + if ((retval = nand_default_bbt(nsmtd)) != 0) { free_nandsim(nand); goto error; diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c index e510a83d7bdbc24768185fd2668e93ddf16e6a5a..91a95f34a6eed2c6763ec849cadcb490e6a0e21d 100644 --- a/drivers/mtd/nand/ppchameleonevb.c +++ b/drivers/mtd/nand/ppchameleonevb.c @@ -6,7 +6,7 @@ * Derived from drivers/mtd/nand/edb7312.c * * - * $Id: ppchameleonevb.c,v 1.6 2004/11/05 16:07:16 kalev Exp $ + * $Id: ppchameleonevb.c,v 1.7 2005/11/07 11:14:31 gleixner Exp $ * * 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 @@ -338,7 +338,7 @@ static int __init ppchameleonevb_init (void) out_be32((volatile unsigned*)GPIO0_TSRH, in_be32((volatile unsigned*)GPIO0_TSRH) & 0xFFFFFFF0); out_be32((volatile unsigned*)GPIO0_TSRL, in_be32((volatile unsigned*)GPIO0_TSRL) & 0x3FFFFFFF); /* enable output driver */ - out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN | + out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN | NAND_EVB_CLE_GPIO_PIN | NAND_EVB_ALE_GPIO_PIN); #ifdef USE_READY_BUSY_PIN /* three-state select */ @@ -402,7 +402,7 @@ static void __exit ppchameleonevb_cleanup (void) /* Release resources, unregister device(s) */ nand_release (ppchameleon_mtd); nand_release (ppchameleonevb_mtd); - + /* Release iomaps */ this = (struct nand_chip *) &ppchameleon_mtd[1]; iounmap((void *) this->IO_ADDR_R; diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index 031051cbde7637589a224f14f618485fcb688040..3a5841c9d950edd00f05b21767fa15bf23edec03 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c @@ -2,11 +2,11 @@ * drivers/mtd/nand/rtc_from4.c * * Copyright (C) 2004 Red Hat, Inc. - * + * * Derived from drivers/mtd/nand/spia.c * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * - * $Id: rtc_from4.c,v 1.9 2005/01/24 20:40:11 dmarlin Exp $ + * $Id: rtc_from4.c,v 1.10 2005/11/07 11:14:31 gleixner Exp $ * * 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 @@ -14,8 +14,8 @@ * * Overview: * This is a device driver for the AG-AND flash device found on the - * Renesas Technology Corp. Flash ROM 4-slot interface board (FROM_BOARD4), - * which utilizes the Renesas HN29V1G91T-30 part. + * Renesas Technology Corp. Flash ROM 4-slot interface board (FROM_BOARD4), + * which utilizes the Renesas HN29V1G91T-30 part. * This chip is a 1 GBibit (128MiB x 8 bits) AG-AND flash device. */ @@ -105,9 +105,9 @@ const static struct mtd_partition partition_info[] = { }; #define NUM_PARTITIONS 1 -/* +/* * hardware specific flash bbt decriptors - * Note: this is to allow debugging by disabling + * Note: this is to allow debugging by disabling * NAND_BBT_CREATE and/or NAND_BBT_WRITE * */ @@ -141,7 +141,7 @@ static struct nand_bbt_descr rtc_from4_bbt_mirror_descr = { /* the Reed Solomon control structure */ static struct rs_control *rs_decoder; -/* +/* * hardware specific Out Of Band information */ static struct nand_oobinfo rtc_from4_nand_oobinfo = { @@ -200,38 +200,38 @@ static uint8_t revbits[256] = { -/* +/* * rtc_from4_hwcontrol - hardware specific access to control-lines * @mtd: MTD device structure * @cmd: hardware control command * - * Address lines (A5 and A4) are used to control Command and Address Latch + * Address lines (A5 and A4) are used to control Command and Address Latch * Enable on this board, so set the read/write address appropriately. * - * Chip Enable is also controlled by the Chip Select (CS5) and + * Chip Enable is also controlled by the Chip Select (CS5) and * Address lines (A24-A22), so no action is required here. * */ static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd) { struct nand_chip* this = (struct nand_chip *) (mtd->priv); - + switch(cmd) { - - case NAND_CTL_SETCLE: + + case NAND_CTL_SETCLE: this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_CLE); break; - case NAND_CTL_CLRCLE: + case NAND_CTL_CLRCLE: this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_CLE); break; - + case NAND_CTL_SETALE: this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_ALE); break; case NAND_CTL_CLRALE: this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_ALE); break; - + case NAND_CTL_SETNCE: break; case NAND_CTL_CLRNCE: @@ -296,7 +296,7 @@ static int rtc_from4_nand_device_ready(struct mtd_info *mtd) * @mtd: MTD device structure * @chip: Chip to select (0 == slot 3, 1 == slot 4) * - * If there was a sudden loss of power during an erase operation, a + * If there was a sudden loss of power during an erase operation, a * "device recovery" operation must be performed when power is restored * to ensure correct operation. This routine performs the required steps * for the requested chip. @@ -312,7 +312,7 @@ static void deplete(struct mtd_info *mtd, int chip) while (!this->dev_ready(mtd)); this->select_chip(mtd, chip); - + /* Send the commands for device recovery, phase 1 */ this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0000); this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1); @@ -330,7 +330,7 @@ static void deplete(struct mtd_info *mtd, int chip) * @mtd: MTD device structure * @mode: I/O mode; read or write * - * enable hardware ECC for data read or write + * enable hardware ECC for data read or write * */ static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode) @@ -340,7 +340,7 @@ static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode) switch (mode) { case NAND_ECC_READ : - status = RTC_FROM4_RS_ECC_CTL_CLR + status = RTC_FROM4_RS_ECC_CTL_CLR | RTC_FROM4_RS_ECC_CTL_FD_E; *rs_ecc_ctl = status; @@ -353,8 +353,8 @@ static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode) break; case NAND_ECC_WRITE : - status = RTC_FROM4_RS_ECC_CTL_CLR - | RTC_FROM4_RS_ECC_CTL_GEN + status = RTC_FROM4_RS_ECC_CTL_CLR + | RTC_FROM4_RS_ECC_CTL_GEN | RTC_FROM4_RS_ECC_CTL_FD_E; *rs_ecc_ctl = status; @@ -411,7 +411,7 @@ static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_c static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2) { int i, j, res; - unsigned short status; + unsigned short status; uint16_t par[6], syn[6]; uint8_t ecc[8]; volatile unsigned short *rs_ecc; @@ -430,7 +430,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha } /* convert into 6 10bit syndrome fields */ - par[5] = rs_decoder->index_of[(((uint16_t)ecc[0] >> 0) & 0x0ff) | + par[5] = rs_decoder->index_of[(((uint16_t)ecc[0] >> 0) & 0x0ff) | (((uint16_t)ecc[1] << 8) & 0x300)]; par[4] = rs_decoder->index_of[(((uint16_t)ecc[1] >> 2) & 0x03f) | (((uint16_t)ecc[2] << 6) & 0x3c0)]; @@ -456,7 +456,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha /* Let the library code do its magic.*/ res = decode_rs8(rs_decoder, (uint8_t *)buf, par, 512, syn, 0, NULL, 0xff, NULL); if (res > 0) { - DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " + DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " "ECC corrected %d errors on read\n", res); } return res; @@ -470,9 +470,9 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha * @state: state or the operation * @status: status code returned from read status * @page: startpage inside the chip, must be called with (page & this->pagemask) - * - * Perform additional error status checks on erase and write failures - * to determine if errors are correctable. For this device, correctable + * + * Perform additional error status checks on erase and write failures + * to determine if errors are correctable. For this device, correctable * 1-bit errors on erase and write are considered acceptable. * * note: see pages 34..37 of data sheet for details. @@ -633,7 +633,7 @@ int __init rtc_from4_init (void) #ifdef RTC_FROM4_HWECC /* We could create the decoder on demand, if memory is a concern. - * This way we have it handy, if an error happens + * This way we have it handy, if an error happens * * Symbolsize is 10 (bits) * Primitve polynomial is x^10+x^3+1 diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 2df5e47d1f5ce2ec7c16a9ab6018d7e4be6c1eff..97e9b7892d29dfce8f5eab6f724b85f9740940ed 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -17,8 +17,9 @@ * 02-May-2005 BJD Reduced hwcontrol decode * 20-Jun-2005 BJD Updated s3c2440 support, fixed timing bug * 08-Jul-2005 BJD Fix OOPS when no platform data supplied + * 20-Oct-2005 BJD Fix timing calculation bug * - * $Id: s3c2410.c,v 1.14 2005/07/06 20:05:06 bjd Exp $ + * $Id: s3c2410.c,v 1.20 2005/11/07 11:14:31 gleixner Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -136,13 +137,13 @@ static struct s3c2410_platform_nand *to_nand_plat(struct device *dev) /* timing calculations */ -#define NS_IN_KHZ 10000000 +#define NS_IN_KHZ 1000000 static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max) { int result; - result = (wanted * NS_IN_KHZ) / clk; + result = (wanted * clk) / NS_IN_KHZ; result++; pr_debug("result %d from %ld, %d\n", result, clk, wanted); @@ -159,20 +160,22 @@ static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max) return result; } -#define to_ns(ticks,clk) (((clk) * (ticks)) / NS_IN_KHZ) +#define to_ns(ticks,clk) (((ticks) * NS_IN_KHZ) / (unsigned int)(clk)) /* controller setup */ -static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, +static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, struct device *dev) { struct s3c2410_platform_nand *plat = to_nand_plat(dev); - unsigned int tacls, twrph0, twrph1; unsigned long clkrate = clk_get_rate(info->clk); + int tacls, twrph0, twrph1; unsigned long cfg; /* calculate the timing information for the controller */ + clkrate /= 1000; /* turn clock into kHz for ease of use */ + if (plat != NULL) { tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 4); twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8); @@ -183,16 +186,16 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, twrph0 = 8; twrph1 = 8; } - + if (tacls < 0 || twrph0 < 0 || twrph1 < 0) { printk(KERN_ERR PFX "cannot get timings suitable for board\n"); return -EINVAL; } - printk(KERN_INFO PFX "timing: Tacls %ldns, Twrph0 %ldns, Twrph1 %ldns\n", - to_ns(tacls, clkrate), - to_ns(twrph0, clkrate), - to_ns(twrph1, clkrate)); + printk(KERN_INFO PFX "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n", + tacls, to_ns(tacls, clkrate), + twrph0, to_ns(twrph0, clkrate), + twrph1, to_ns(twrph1, clkrate)); if (!info->is_s3c2440) { cfg = S3C2410_NFCONF_EN; @@ -216,7 +219,7 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) { struct s3c2410_nand_info *info; - struct s3c2410_nand_mtd *nmtd; + struct s3c2410_nand_mtd *nmtd; struct nand_chip *this = mtd->priv; void __iomem *reg; unsigned long cur; @@ -249,7 +252,7 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) writel(cur, reg); } -/* command and control functions +/* command and control functions * * Note, these all use tglx's method of changing the IO_ADDR_W field * to make the code simpler, and use the nand layer's code to issue the @@ -321,7 +324,7 @@ static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd) static int s3c2410_nand_devready(struct mtd_info *mtd) { struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); - + if (info->is_s3c2440) return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY; return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY; @@ -342,7 +345,7 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, if (read_ecc[0] == calc_ecc[0] && read_ecc[1] == calc_ecc[1] && - read_ecc[2] == calc_ecc[2]) + read_ecc[2] == calc_ecc[2]) return 0; /* we curently have no method for correcting the error */ @@ -433,14 +436,14 @@ static int s3c2410_nand_remove(struct device *dev) dev_set_drvdata(dev, NULL); - if (info == NULL) + if (info == NULL) return 0; /* first thing we need to do is release all our mtds * and their partitions, then go through freeing the - * resources used + * resources used */ - + if (info->mtds != NULL) { struct s3c2410_nand_mtd *ptr = info->mtds; int mtdno; @@ -504,7 +507,7 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, /* s3c2410_nand_init_chip * - * init a single instance of an chip + * init a single instance of an chip */ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, @@ -576,7 +579,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) info = kmalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) { - printk(KERN_ERR PFX "no memory for flash info\n"); + dev_err(dev, "no memory for flash info\n"); err = -ENOMEM; goto exit_error; } @@ -591,7 +594,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) info->clk = clk_get(dev, "nand"); if (IS_ERR(info->clk)) { - printk(KERN_ERR PFX "failed to get clock"); + dev_err(dev, "failed to get clock"); err = -ENOENT; goto exit_error; } @@ -608,7 +611,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) info->area = request_mem_region(res->start, size, pdev->name); if (info->area == NULL) { - printk(KERN_ERR PFX "cannot reserve register region\n"); + dev_err(dev, "cannot reserve register region\n"); err = -ENOENT; goto exit_error; } @@ -619,12 +622,12 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) info->is_s3c2440 = is_s3c2440; if (info->regs == NULL) { - printk(KERN_ERR PFX "cannot reserve register region\n"); + dev_err(dev, "cannot reserve register region\n"); err = -EIO; goto exit_error; - } + } - printk(KERN_INFO PFX "mapped registers at %p\n", info->regs); + dev_dbg(dev, "mapped registers at %p\n", info->regs); /* initialise the hardware */ @@ -642,7 +645,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) size = nr_sets * sizeof(*info->mtds); info->mtds = kmalloc(size, GFP_KERNEL); if (info->mtds == NULL) { - printk(KERN_ERR PFX "failed to allocate mtd storage\n"); + dev_err(dev, "failed to allocate mtd storage\n"); err = -ENOMEM; goto exit_error; } @@ -656,7 +659,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) for (setno = 0; setno < nr_sets; setno++, nmtd++) { pr_debug("initialising set %d (%p, info %p)\n", setno, nmtd, info); - + s3c2410_nand_init_chip(info, nmtd, sets); nmtd->scan_res = nand_scan(&nmtd->mtd, @@ -669,7 +672,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440) if (sets != NULL) sets++; } - + pr_debug("initialised ok\n"); return 0; @@ -695,6 +698,7 @@ static int s3c2440_nand_probe(struct device *dev) static struct device_driver s3c2410_nand_driver = { .name = "s3c2410-nand", + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = s3c2410_nand_probe, .remove = s3c2410_nand_remove, @@ -702,6 +706,7 @@ static struct device_driver s3c2410_nand_driver = { static struct device_driver s3c2440_nand_driver = { .name = "s3c2440-nand", + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = s3c2440_nand_probe, .remove = s3c2410_nand_remove, diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 88b5b5b40b43aa07fed88f2b56edfb1b1b9cdab2..1924a4f137c79eed315673de214224d225e78e70 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -3,7 +3,7 @@ * * Copyright (C) 2004 Richard Purdie * - * $Id: sharpsl.c,v 1.4 2005/01/23 11:09:19 rpurdie Exp $ + * $Id: sharpsl.c,v 1.7 2005/11/07 11:14:31 gleixner Exp $ * * Based on Sharp's NAND driver sharp_sl.c * @@ -76,14 +76,14 @@ static struct mtd_partition sharpsl_nand_default_partition_info[] = { }, }; -/* +/* * hardware specific access to control-lines */ static void sharpsl_nand_hwcontrol(struct mtd_info* mtd, int cmd) { switch (cmd) { - case NAND_CTL_SETCLE: + case NAND_CTL_SETCLE: writeb(readb(FLASHCTL) | FLCLE, FLASHCTL); break; case NAND_CTL_CLRCLE: @@ -97,10 +97,10 @@ sharpsl_nand_hwcontrol(struct mtd_info* mtd, int cmd) writeb(readb(FLASHCTL) & ~FLALE, FLASHCTL); break; - case NAND_CTL_SETNCE: + case NAND_CTL_SETNCE: writeb(readb(FLASHCTL) & ~(FLCE0|FLCE1), FLASHCTL); break; - case NAND_CTL_CLRNCE: + case NAND_CTL_CLRNCE: writeb(readb(FLASHCTL) | (FLCE0|FLCE1), FLASHCTL); break; } @@ -115,6 +115,23 @@ static struct nand_bbt_descr sharpsl_bbt = { .pattern = scan_ff_pattern }; +static struct nand_bbt_descr sharpsl_akita_bbt = { + .options = 0, + .offs = 4, + .len = 1, + .pattern = scan_ff_pattern +}; + +static struct nand_oobinfo akita_oobinfo = { + .useecc = MTD_NANDECC_AUTOPLACE, + .eccbytes = 24, + .eccpos = { + 0x5, 0x1, 0x2, 0x3, 0x6, 0x7, 0x15, 0x11, + 0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23, + 0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37}, + .oobfree = { {0x08, 0x09} } +}; + static int sharpsl_nand_dev_ready(struct mtd_info* mtd) { @@ -160,7 +177,7 @@ sharpsl_nand_init(void) printk ("Unable to allocate SharpSL NAND MTD device structure.\n"); return -ENOMEM; } - + /* map physical adress */ sharpsl_io_base = ioremap(sharpsl_phys_base, 0x1000); if(!sharpsl_io_base){ @@ -168,7 +185,7 @@ sharpsl_nand_init(void) kfree(sharpsl_mtd); return -EIO; } - + /* Get pointer to private data */ this = (struct nand_chip *) (&sharpsl_mtd[1]); @@ -194,10 +211,14 @@ sharpsl_nand_init(void) this->chip_delay = 15; /* set eccmode using hardware ECC */ this->eccmode = NAND_ECC_HW3_256; + this->badblock_pattern = &sharpsl_bbt; + if (machine_is_akita() || machine_is_borzoi()) { + this->badblock_pattern = &sharpsl_akita_bbt; + this->autooob = &akita_oobinfo; + } this->enable_hwecc = sharpsl_nand_enable_hwecc; this->calculate_ecc = sharpsl_nand_calculate_ecc; this->correct_data = nand_correct_data; - this->badblock_pattern = &sharpsl_bbt; /* Scan to find existence of the device */ err=nand_scan(sharpsl_mtd,1); @@ -211,7 +232,7 @@ sharpsl_nand_init(void) sharpsl_mtd->name = "sharpsl-nand"; nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes, &sharpsl_partition_info, 0); - + if (nr_partitions <= 0) { nr_partitions = DEFAULT_NUM_PARTITIONS; sharpsl_partition_info = sharpsl_nand_default_partition_info; @@ -230,7 +251,7 @@ sharpsl_nand_init(void) } } - if (machine_is_husky() || machine_is_borzoi()) { + if (machine_is_husky() || machine_is_borzoi() || machine_is_akita()) { /* Need to use small eraseblock size for backward compatibility */ sharpsl_mtd->flags |= MTD_NO_VIRTBLOCKS; } diff --git a/drivers/mtd/nand/spia.c b/drivers/mtd/nand/spia.c index b777c412b75835e7ebbb08bef2e7e681d031ebcc..32541cbb0103284669c6fc91c62aa58501132e2f 100644 --- a/drivers/mtd/nand/spia.c +++ b/drivers/mtd/nand/spia.c @@ -8,7 +8,7 @@ * to controllines (due to change in nand.c) * page_cache added * - * $Id: spia.c,v 1.24 2004/11/04 12:53:10 gleixner Exp $ + * $Id: spia.c,v 1.25 2005/11/07 11:14:31 gleixner Exp $ * * 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 @@ -82,7 +82,7 @@ const static struct mtd_partition partition_info[] = { #define NUM_PARTITIONS 2 -/* +/* * hardware specific access to control-lines */ static void spia_hwcontrol(struct mtd_info *mtd, int cmd){ @@ -137,7 +137,7 @@ int __init spia_init (void) /* Set address of hardware control function */ this->hwcontrol = spia_hwcontrol; /* 15 us command delay time */ - this->chip_delay = 15; + this->chip_delay = 15; /* Scan to find existence of the device */ if (nand_scan (spia_mtd, 1)) { diff --git a/drivers/mtd/nand/toto.c b/drivers/mtd/nand/toto.c index 52c808fb5fa93165038f59a4c399136899134789..7609c43cb3ec759baf4b24d5728b34d9dbe64a03 100644 --- a/drivers/mtd/nand/toto.c +++ b/drivers/mtd/nand/toto.c @@ -15,7 +15,7 @@ * This is a device driver for the NAND flash device found on the * TI fido board. It supports 32MiB and 64MiB cards * - * $Id: toto.c,v 1.4 2004/10/05 13:50:20 gleixner Exp $ + * $Id: toto.c,v 1.5 2005/11/07 11:14:31 gleixner Exp $ */ #include @@ -57,7 +57,7 @@ static unsigned long toto_io_base = OMAP_FLASH_1_BASE; #endif #define T_NAND_CTL_SETNCE(iob) gpiosetout(NAND_NCE, 0) #define T_NAND_CTL_CLRNCE(iob) gpiosetout(NAND_NCE, NAND_NCE) - + /* * Define partitions for flash devices */ @@ -91,7 +91,7 @@ static struct mtd_partition partition_info32M[] = { #define NUM_PARTITIONS32M 3 #define NUM_PARTITIONS64M 4 -/* +/* * hardware specific access to control-lines */ @@ -146,7 +146,7 @@ int __init toto_init (void) this->hwcontrol = toto_hwcontrol; this->dev_ready = NULL; /* 25 us command delay time */ - this->chip_delay = 30; + this->chip_delay = 30; this->eccmode = NAND_ECC_SOFT; /* Scan to find existance of the device */ @@ -157,10 +157,10 @@ int __init toto_init (void) /* Register the partitions */ switch(toto_mtd->size){ - case SZ_64M: add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M); break; - case SZ_32M: add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M); break; + case SZ_64M: add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M); break; + case SZ_32M: add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M); break; default: { - printk (KERN_WARNING "Unsupported Nand device\n"); + printk (KERN_WARNING "Unsupported Nand device\n"); err = -ENXIO; goto out_buf; } @@ -170,9 +170,9 @@ int __init toto_init (void) archflashwp(0,0); /* open up flash for writing */ goto out; - + out_buf: - kfree (this->data_buf); + kfree (this->data_buf); out_mtd: kfree (toto_mtd); out: @@ -194,7 +194,7 @@ static void __exit toto_cleanup (void) /* stop flash writes */ archflashwp(0,1); - + /* release gpios to system */ gpiorelease(NAND_MASK); } diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index b2014043634fc5eb842516ad1b75ebe0ed682f7b..d7cd5fa16ba445e8d854760de615e7ec15821949 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -1,7 +1,7 @@ /* Linux driver for NAND Flash Translation Layer */ /* (c) 1999 Machine Vision Holdings, Inc. */ /* Author: David Woodhouse */ -/* $Id: nftlcore.c,v 1.97 2004/11/16 18:28:59 dwmw2 Exp $ */ +/* $Id: nftlcore.c,v 1.98 2005/11/07 11:14:21 gleixner Exp $ */ /* The contents of this file are distributed under the GNU General @@ -101,23 +101,21 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) { /* - Oh no we don't have + Oh no we don't have mbd.size == heads * cylinders * sectors */ printk(KERN_WARNING "NFTL: cannot calculate a geometry to " "match size of 0x%lx.\n", nftl->mbd.size); printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d " "(== 0x%lx sects)\n", - nftl->cylinders, nftl->heads , nftl->sectors, + nftl->cylinders, nftl->heads , nftl->sectors, (long)nftl->cylinders * (long)nftl->heads * (long)nftl->sectors ); } if (add_mtd_blktrans_dev(&nftl->mbd)) { - if (nftl->ReplUnitTable) - kfree(nftl->ReplUnitTable); - if (nftl->EUNtable) - kfree(nftl->EUNtable); + kfree(nftl->ReplUnitTable); + kfree(nftl->EUNtable); kfree(nftl); return; } @@ -133,10 +131,8 @@ static void nftl_remove_dev(struct mtd_blktrans_dev *dev) DEBUG(MTD_DEBUG_LEVEL1, "NFTL: remove_dev (i=%d)\n", dev->devnum); del_mtd_blktrans_dev(dev); - if (nftl->ReplUnitTable) - kfree(nftl->ReplUnitTable); - if (nftl->EUNtable) - kfree(nftl->EUNtable); + kfree(nftl->ReplUnitTable); + kfree(nftl->EUNtable); kfree(nftl); } @@ -178,7 +174,7 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate ) if (!silly--) { printk("Argh! No free blocks found! LastFreeEUN = %d, " - "FirstEUN = %d\n", nftl->LastFreeEUN, + "FirstEUN = %d\n", nftl->LastFreeEUN, le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN)); return 0xffff; } @@ -210,7 +206,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p "Virtual Unit Chain %d!\n", thisVUC); return BLOCK_NIL; } - + /* Scan to find the Erase Unit which holds the actual data for each 512-byte block within the Chain. */ @@ -227,7 +223,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p if (block == 2) { foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1; if (foldmark == FOLD_MARK_IN_PROGRESS) { - DEBUG(MTD_DEBUG_LEVEL1, + DEBUG(MTD_DEBUG_LEVEL1, "Write Inhibited on EUN %d\n", thisEUN); inplace = 0; } else { @@ -249,7 +245,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p if (!BlockFreeFound[block]) BlockMap[block] = thisEUN; else - printk(KERN_WARNING + printk(KERN_WARNING "SECTOR_USED found after SECTOR_FREE " "in Virtual Unit Chain %d for block %d\n", thisVUC, block); @@ -258,7 +254,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p if (!BlockFreeFound[block]) BlockMap[block] = BLOCK_NIL; else - printk(KERN_WARNING + printk(KERN_WARNING "SECTOR_DELETED found after SECTOR_FREE " "in Virtual Unit Chain %d for block %d\n", thisVUC, block); @@ -277,14 +273,14 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p thisVUC); return BLOCK_NIL; } - + thisEUN = nftl->ReplUnitTable[thisEUN]; } if (inplace) { /* We're being asked to be a fold-in-place. Check that all blocks which actually have data associated - with them (i.e. BlockMap[block] != BLOCK_NIL) are + with them (i.e. BlockMap[block] != BLOCK_NIL) are either already present or SECTOR_FREE in the target block. If not, we're going to have to fold out-of-place anyway. @@ -297,7 +293,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p "block %d was %x lastEUN, " "and is in EUN %d (%s) %d\n", thisVUC, block, BlockLastState[block], - BlockMap[block], + BlockMap[block], BlockMap[block]== targetEUN ? "==" : "!=", targetEUN); inplace = 0; @@ -314,17 +310,17 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p inplace = 0; } } - + if (!inplace) { DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. " "Trying out-of-place\n", thisVUC); /* We need to find a targetEUN to fold into. */ targetEUN = NFTL_findfreeblock(nftl, 1); if (targetEUN == BLOCK_NIL) { - /* Ouch. Now we're screwed. We need to do a + /* Ouch. Now we're screwed. We need to do a fold-in-place of another chain to make room for this one. We need a better way of selecting - which chain to fold, because makefreeblock will + which chain to fold, because makefreeblock will only ask us to fold the same one again. */ printk(KERN_WARNING @@ -338,7 +334,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p chain by selecting the longer one */ oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS); oob.u.c.unused = 0xffffffff; - MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8, + MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8, 8, &retlen, (char *)&oob.u); } @@ -361,14 +357,14 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p happen in case of media errors or deleted blocks) */ if (BlockMap[block] == BLOCK_NIL) continue; - + ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), - 512, &retlen, movebuf); + 512, &retlen, movebuf); if (ret < 0) { ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), 512, &retlen, - movebuf); - if (ret != -EIO) + movebuf); + if (ret != -EIO) printk("Error went away on retry.\n"); } memset(&oob, 0xff, sizeof(struct nftl_oob)); @@ -376,18 +372,18 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512), 512, &retlen, movebuf, (char *)&oob, &nftl->oobinfo); } - + /* add the header so that it is now a valid chain */ oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC); oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff; - - MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 8, + + MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 8, 8, &retlen, (char *)&oob.u); /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */ - /* At this point, we have two different chains for this Virtual Unit, and no way to tell + /* At this point, we have two different chains for this Virtual Unit, and no way to tell them apart. If we crash now, we get confused. However, both contain the same data, so we shouldn't actually lose data in this case. It's just that when we load up on a medium which has duplicate chains, we need to free one of the chains because it's not necessary any more. @@ -395,7 +391,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p thisEUN = nftl->EUNtable[thisVUC]; DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n"); - /* For each block in the old chain (except the targetEUN of course), + /* For each block in the old chain (except the targetEUN of course), free it and make it available for future use */ while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) { unsigned int EUNtmp; @@ -413,7 +409,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p } thisEUN = EUNtmp; } - + /* Make this the new start of chain for thisVUC */ nftl->ReplUnitTable[targetEUN] = BLOCK_NIL; nftl->EUNtable[thisVUC] = targetEUN; @@ -423,7 +419,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock) { - /* This is the part that needs some cleverness applied. + /* This is the part that needs some cleverness applied. For now, I'm doing the minimum applicable to actually get the thing to work. Wear-levelling and other clever stuff needs to be implemented @@ -470,7 +466,7 @@ static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock) return NFTL_foldchain (nftl, LongestChain, pendingblock); } -/* NFTL_findwriteunit: Return the unit number into which we can write +/* NFTL_findwriteunit: Return the unit number into which we can write for this block. Make it available if it isn't already */ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) @@ -488,7 +484,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) a free space for the block in question. */ - /* This condition catches the 0x[7f]fff cases, as well as + /* This condition catches the 0x[7f]fff cases, as well as being a sanity check for past-end-of-media access */ lastEUN = BLOCK_NIL; @@ -503,7 +499,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) MTD_READOOB(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs, 8, &retlen, (char *)&bci); - + DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n", block , writeEUN, le16_to_cpu(bci.Status)); @@ -518,10 +514,10 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) break; default: // Invalid block. Don't use it any more. Must implement. - break; + break; } - - if (!silly--) { + + if (!silly--) { printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n", thisVUC); @@ -532,7 +528,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) writeEUN = nftl->ReplUnitTable[writeEUN]; } - /* OK. We didn't find one in the existing chain, or there + /* OK. We didn't find one in the existing chain, or there is no existing chain. */ /* Try to find an already-free block */ @@ -546,12 +542,12 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) /* First remember the start of this chain */ //u16 startEUN = nftl->EUNtable[thisVUC]; - + //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC); writeEUN = NFTL_makefreeblock(nftl, 0xffff); if (writeEUN == BLOCK_NIL) { - /* OK, we accept that the above comment is + /* OK, we accept that the above comment is lying - there may have been free blocks last time we called NFTL_findfreeblock(), but they are reserved for when we're @@ -562,21 +558,21 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) } if (writeEUN == BLOCK_NIL) { /* Ouch. This should never happen - we should - always be able to make some room somehow. - If we get here, we've allocated more storage + always be able to make some room somehow. + If we get here, we've allocated more storage space than actual media, or our makefreeblock routine is missing something. */ printk(KERN_WARNING "Cannot make free space.\n"); return BLOCK_NIL; - } + } //printk("Restarting scan\n"); lastEUN = BLOCK_NIL; continue; } /* We've found a free block. Insert it into the chain. */ - + if (lastEUN != BLOCK_NIL) { thisVUC |= 0x8000; /* It's a replacement block */ } else { @@ -749,7 +745,7 @@ extern char nftlmountrev[]; static int __init init_nftl(void) { - printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.97 $, nftlmount.c %s\n", nftlmountrev); + printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.98 $, nftlmount.c %s\n", nftlmountrev); return register_mtd_blktrans(&nftl_tr); } diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index 84afd9029f53e58591533f41dcad4cc48d543bc0..3b104ebb219ad9cbe816575ecd25d9f23b7844b3 100644 --- a/drivers/mtd/nftlmount.c +++ b/drivers/mtd/nftlmount.c @@ -1,10 +1,10 @@ -/* +/* * NFTL mount code with extensive checks * - * Author: Fabrice Bellard (fabrice.bellard@netgem.com) + * Author: Fabrice Bellard (fabrice.bellard@netgem.com) * Copyright (C) 2000 Netgem S.A. * - * $Id: nftlmount.c,v 1.40 2004/11/22 14:38:29 kalev Exp $ + * $Id: nftlmount.c,v 1.41 2005/11/07 11:14:21 gleixner Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,7 +31,7 @@ #define SECTORSIZE 512 -char nftlmountrev[]="$Revision: 1.40 $"; +char nftlmountrev[]="$Revision: 1.41 $"; /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the * various device information of the NFTL partition and Bad Unit Table. Update @@ -47,7 +47,7 @@ static int find_boot_record(struct NFTLrecord *nftl) struct NFTLMediaHeader *mh = &nftl->MediaHdr; unsigned int i; - /* Assume logical EraseSize == physical erasesize for starting the scan. + /* Assume logical EraseSize == physical erasesize for starting the scan. We'll sort it out later if we find a MediaHeader which says otherwise */ /* Actually, we won't. The new DiskOnChip driver has already scanned the MediaHeader and adjusted the virtual erasesize it presents in @@ -83,9 +83,9 @@ static int find_boot_record(struct NFTLrecord *nftl) if (retlen < 6 || memcmp(buf, "ANAND", 6)) { /* ANAND\0 not found. Continue */ #if 0 - printk(KERN_DEBUG "ANAND header not found at 0x%x in mtd%d\n", + printk(KERN_DEBUG "ANAND header not found at 0x%x in mtd%d\n", block * nftl->EraseSize, nftl->mbd.mtd->index); -#endif +#endif continue; } @@ -103,7 +103,7 @@ static int find_boot_record(struct NFTLrecord *nftl) */ if (le16_to_cpu(h1.EraseMark | h1.EraseMark1) != ERASE_MARK) { printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but erase mark not present (0x%04x,0x%04x instead)\n", - block * nftl->EraseSize, nftl->mbd.mtd->index, + block * nftl->EraseSize, nftl->mbd.mtd->index, le16_to_cpu(h1.EraseMark), le16_to_cpu(h1.EraseMark1)); continue; } @@ -175,7 +175,7 @@ device is already correct. nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN); if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) { printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n"); - printk(KERN_NOTICE "nb_boot_blocks (%d) + 2 > nb_blocks (%d)\n", + printk(KERN_NOTICE "nb_boot_blocks (%d) + 2 > nb_blocks (%d)\n", nftl->nb_boot_blocks, nftl->nb_blocks); return -1; } @@ -187,7 +187,7 @@ device is already correct. nftl->numvunits, nftl->nb_blocks, nftl->nb_boot_blocks); return -1; } - + nftl->mbd.size = nftl->numvunits * (nftl->EraseSize / SECTORSIZE); /* If we're not using the last sectors in the device for some reason, @@ -210,12 +210,12 @@ device is already correct. printk(KERN_NOTICE "NFTL: allocation of ReplUnitTable failed\n"); return -ENOMEM; } - + /* mark the bios blocks (blocks before NFTL MediaHeader) as reserved */ for (i = 0; i < nftl->nb_boot_blocks; i++) nftl->ReplUnitTable[i] = BLOCK_RESERVED; /* mark all remaining blocks as potentially containing data */ - for (; i < nftl->nb_blocks; i++) { + for (; i < nftl->nb_blocks; i++) { nftl->ReplUnitTable[i] = BLOCK_NOTEXPLORED; } @@ -245,12 +245,12 @@ The new DiskOnChip driver already scanned the bad block table. Just query it. if (nftl->mbd.mtd->block_isbad(nftl->mbd.mtd, i * nftl->EraseSize)) nftl->ReplUnitTable[i] = BLOCK_RESERVED; } - + nftl->MediaUnit = block; boot_record_count++; - + } /* foreach (block) */ - + return boot_record_count?0:-1; } @@ -265,7 +265,7 @@ static int memcmpb(void *a, int c, int n) } /* check_free_sector: check if a free sector is actually FREE, i.e. All 0xff in data and oob area */ -static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len, +static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len, int check_oob) { int i; @@ -293,7 +293,7 @@ static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int * * Return: 0 when succeed, -1 on error. * - * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? + * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? */ int NFTL_formatblock(struct NFTLrecord *nftl, int block) { @@ -385,7 +385,7 @@ static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_b /* verify that the sector is really free. If not, mark as ignore */ if (memcmpb(&bci, 0xff, 8) != 0 || - check_free_sectors(nftl, block * nftl->EraseSize + i * SECTORSIZE, + check_free_sectors(nftl, block * nftl->EraseSize + i * SECTORSIZE, SECTORSIZE, 0) != 0) { printk("Incorrect free sector %d in block %d: " "marking it as ignored\n", @@ -486,7 +486,7 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block) size_t retlen; /* check erase mark. */ - if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, + if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0) return -1; @@ -501,7 +501,7 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block) h1.EraseMark = cpu_to_le16(ERASE_MARK); h1.EraseMark1 = cpu_to_le16(ERASE_MARK); h1.WearInfo = cpu_to_le32(0); - if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, + if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0) return -1; } else { @@ -582,9 +582,9 @@ int NFTL_mount(struct NFTLrecord *s) for (;;) { /* read the block header. If error, we format the chain */ - if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8, 8, + if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8, 8, &retlen, (char *)&h0) < 0 || - MTD_READOOB(s->mbd.mtd, block * s->EraseSize + SECTORSIZE + 8, 8, + MTD_READOOB(s->mbd.mtd, block * s->EraseSize + SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0) { s->ReplUnitTable[block] = BLOCK_NIL; do_format_chain = 1; @@ -639,7 +639,7 @@ int NFTL_mount(struct NFTLrecord *s) first_logical_block = logical_block; } else { if (logical_block != first_logical_block) { - printk("Block %d: incorrect logical block: %d expected: %d\n", + printk("Block %d: incorrect logical block: %d expected: %d\n", block, logical_block, first_logical_block); /* the chain is incorrect : we must format it, but we need to read it completly */ @@ -668,7 +668,7 @@ int NFTL_mount(struct NFTLrecord *s) s->ReplUnitTable[block] = BLOCK_NIL; break; } else if (rep_block >= s->nb_blocks) { - printk("Block %d: referencing invalid block %d\n", + printk("Block %d: referencing invalid block %d\n", block, rep_block); do_format_chain = 1; s->ReplUnitTable[block] = BLOCK_NIL; @@ -688,7 +688,7 @@ int NFTL_mount(struct NFTLrecord *s) s->ReplUnitTable[block] = rep_block; s->EUNtable[first_logical_block] = BLOCK_NIL; } else { - printk("Block %d: referencing block %d already in another chain\n", + printk("Block %d: referencing block %d already in another chain\n", block, rep_block); /* XXX: should handle correctly fold in progress chains */ do_format_chain = 1; @@ -710,7 +710,7 @@ int NFTL_mount(struct NFTLrecord *s) } else { unsigned int first_block1, chain_to_format, chain_length1; int fold_mark; - + /* valid chain : get foldmark */ fold_mark = get_fold_mark(s, first_block); if (fold_mark == 0) { @@ -729,9 +729,9 @@ int NFTL_mount(struct NFTLrecord *s) if (first_block1 != BLOCK_NIL) { /* XXX: what to do if same length ? */ chain_length1 = calc_chain_length(s, first_block1); - printk("Two chains at blocks %d (len=%d) and %d (len=%d)\n", + printk("Two chains at blocks %d (len=%d) and %d (len=%d)\n", first_block1, chain_length1, first_block, chain_length); - + if (chain_length >= chain_length1) { chain_to_format = first_block1; s->EUNtable[first_logical_block] = first_block; diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..126ff6bf63d5c8b8cfc733b13f5656f758a40cd7 --- /dev/null +++ b/drivers/mtd/onenand/Kconfig @@ -0,0 +1,38 @@ +# +# linux/drivers/mtd/onenand/Kconfig +# + +menu "OneNAND Flash Device Drivers" + depends on MTD != n + +config MTD_ONENAND + tristate "OneNAND Device Support" + depends on MTD + help + This enables support for accessing all type of OneNAND flash + devices. For further information see + . + +config MTD_ONENAND_VERIFY_WRITE + bool "Verify OneNAND page writes" + depends on MTD_ONENAND + help + This adds an extra check when data is written to the flash. The + OneNAND flash device internally checks only bits transitioning + from 1 to 0. There is a rare possibility that even though the + device thinks the write was successful, a bit could have been + flipped accidentaly due to device wear or something else. + +config MTD_ONENAND_GENERIC + tristate "OneNAND Flash device via platform device driver" + depends on MTD_ONENAND && ARM + help + Support for OneNAND flash via platform device driver. + +config MTD_ONENAND_SYNC_READ + bool "OneNAND Sync. Burst Read Support" + depends on ARCH_OMAP + help + This enables support for Sync. Burst Read. + +endmenu diff --git a/drivers/mtd/onenand/Makefile b/drivers/mtd/onenand/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..269cfe46734503b9f423eeec46fb696f0e7bf1e5 --- /dev/null +++ b/drivers/mtd/onenand/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for the OneNAND MTD +# + +# Core functionality. +obj-$(CONFIG_MTD_ONENAND) += onenand.o + +# Board specific. +obj-$(CONFIG_MTD_ONENAND_GENERIC) += generic.o + +onenand-objs = onenand_base.o onenand_bbt.o diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c new file mode 100644 index 0000000000000000000000000000000000000000..48cce431f89f3ebe498fc8673ee69606c5017848 --- /dev/null +++ b/drivers/mtd/onenand/generic.c @@ -0,0 +1,147 @@ +/* + * linux/drivers/mtd/onenand/generic.c + * + * Copyright (c) 2005 Samsung Electronics + * Kyungmin Park + * + * 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. + * + * Overview: + * This is a device driver for the OneNAND flash for generic boards. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DRIVER_NAME "onenand" + + +#ifdef CONFIG_MTD_PARTITIONS +static const char *part_probes[] = { "cmdlinepart", NULL, }; +#endif + +struct onenand_info { + struct mtd_info mtd; + struct mtd_partition *parts; + struct onenand_chip onenand; +}; + +static int __devinit generic_onenand_probe(struct device *dev) +{ + struct onenand_info *info; + struct platform_device *pdev = to_platform_device(dev); + struct onenand_platform_data *pdata = pdev->dev.platform_data; + struct resource *res = pdev->resource; + unsigned long size = res->end - res->start + 1; + int err; + + info = kmalloc(sizeof(struct onenand_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + memset(info, 0, sizeof(struct onenand_info)); + + if (!request_mem_region(res->start, size, dev->driver->name)) { + err = -EBUSY; + goto out_free_info; + } + + info->onenand.base = ioremap(res->start, size); + if (!info->onenand.base) { + err = -ENOMEM; + goto out_release_mem_region; + } + + info->onenand.mmcontrol = pdata->mmcontrol; + + info->mtd.name = pdev->dev.bus_id; + info->mtd.priv = &info->onenand; + info->mtd.owner = THIS_MODULE; + + if (onenand_scan(&info->mtd, 1)) { + err = -ENXIO; + goto out_iounmap; + } + +#ifdef CONFIG_MTD_PARTITIONS + err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0); + if (err > 0) + add_mtd_partitions(&info->mtd, info->parts, err); + else if (err < 0 && pdata->parts) + add_mtd_partitions(&info->mtd, pdata->parts, pdata->nr_parts); + else +#endif + err = add_mtd_device(&info->mtd); + + dev_set_drvdata(&pdev->dev, info); + + return 0; + +out_iounmap: + iounmap(info->onenand.base); +out_release_mem_region: + release_mem_region(res->start, size); +out_free_info: + kfree(info); + + return err; +} + +static int __devexit generic_onenand_remove(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct onenand_info *info = dev_get_drvdata(&pdev->dev); + struct resource *res = pdev->resource; + unsigned long size = res->end - res->start + 1; + + dev_set_drvdata(&pdev->dev, NULL); + + if (info) { + if (info->parts) + del_mtd_partitions(&info->mtd); + else + del_mtd_device(&info->mtd); + + onenand_release(&info->mtd); + release_mem_region(res->start, size); + iounmap(info->onenand.base); + kfree(info); + } + + return 0; +} + +static struct device_driver generic_onenand_driver = { + .name = DRIVER_NAME, + .bus = &platform_bus_type, + .probe = generic_onenand_probe, + .remove = __devexit_p(generic_onenand_remove), +}; + +MODULE_ALIAS(DRIVER_NAME); + +static int __init generic_onenand_init(void) +{ + return driver_register(&generic_onenand_driver); +} + +static void __exit generic_onenand_exit(void) +{ + driver_unregister(&generic_onenand_driver); +} + +module_init(generic_onenand_init); +module_exit(generic_onenand_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kyungmin Park "); +MODULE_DESCRIPTION("Glue layer for OneNAND flash on generic boards"); diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c new file mode 100644 index 0000000000000000000000000000000000000000..cc38fa0d45c6910747d77734226aa568f72b761f --- /dev/null +++ b/drivers/mtd/onenand/onenand_base.c @@ -0,0 +1,1588 @@ +/* + * linux/drivers/mtd/onenand/onenand_base.c + * + * Copyright (C) 2005 Samsung Electronics + * Kyungmin Park + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include + +/** + * onenand_oob_64 - oob info for large (2KB) page + */ +static struct nand_oobinfo onenand_oob_64 = { + .useecc = MTD_NANDECC_AUTOPLACE, + .eccbytes = 20, + .eccpos = { + 8, 9, 10, 11, 12, + 24, 25, 26, 27, 28, + 40, 41, 42, 43, 44, + 56, 57, 58, 59, 60, + }, + .oobfree = { + {2, 3}, {14, 2}, {18, 3}, {30, 2}, + {24, 3}, {46, 2}, {40, 3}, {62, 2} } +}; + +/** + * onenand_oob_32 - oob info for middle (1KB) page + */ +static struct nand_oobinfo onenand_oob_32 = { + .useecc = MTD_NANDECC_AUTOPLACE, + .eccbytes = 10, + .eccpos = { + 8, 9, 10, 11, 12, + 24, 25, 26, 27, 28, + }, + .oobfree = { {2, 3}, {14, 2}, {18, 3}, {30, 2} } +}; + +static const unsigned char ffchars[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 16 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 32 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 48 */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 64 */ +}; + +/** + * onenand_readw - [OneNAND Interface] Read OneNAND register + * @param addr address to read + * + * Read OneNAND register + */ +static unsigned short onenand_readw(void __iomem *addr) +{ + return readw(addr); +} + +/** + * onenand_writew - [OneNAND Interface] Write OneNAND register with value + * @param value value to write + * @param addr address to write + * + * Write OneNAND register with value + */ +static void onenand_writew(unsigned short value, void __iomem *addr) +{ + writew(value, addr); +} + +/** + * onenand_block_address - [DEFAULT] Get block address + * @param this onenand chip data structure + * @param block the block + * @return translated block address if DDP, otherwise same + * + * Setup Start Address 1 Register (F100h) + */ +static int onenand_block_address(struct onenand_chip *this, int block) +{ + if (this->device_id & ONENAND_DEVICE_IS_DDP) { + /* Device Flash Core select, NAND Flash Block Address */ + int dfs = 0; + + if (block & this->density_mask) + dfs = 1; + + return (dfs << ONENAND_DDP_SHIFT) | + (block & (this->density_mask - 1)); + } + + return block; +} + +/** + * onenand_bufferram_address - [DEFAULT] Get bufferram address + * @param this onenand chip data structure + * @param block the block + * @return set DBS value if DDP, otherwise 0 + * + * Setup Start Address 2 Register (F101h) for DDP + */ +static int onenand_bufferram_address(struct onenand_chip *this, int block) +{ + if (this->device_id & ONENAND_DEVICE_IS_DDP) { + /* Device BufferRAM Select */ + int dbs = 0; + + if (block & this->density_mask) + dbs = 1; + + return (dbs << ONENAND_DDP_SHIFT); + } + + return 0; +} + +/** + * onenand_page_address - [DEFAULT] Get page address + * @param page the page address + * @param sector the sector address + * @return combined page and sector address + * + * Setup Start Address 8 Register (F107h) + */ +static int onenand_page_address(int page, int sector) +{ + /* Flash Page Address, Flash Sector Address */ + int fpa, fsa; + + fpa = page & ONENAND_FPA_MASK; + fsa = sector & ONENAND_FSA_MASK; + + return ((fpa << ONENAND_FPA_SHIFT) | fsa); +} + +/** + * onenand_buffer_address - [DEFAULT] Get buffer address + * @param dataram1 DataRAM index + * @param sectors the sector address + * @param count the number of sectors + * @return the start buffer value + * + * Setup Start Buffer Register (F200h) + */ +static int onenand_buffer_address(int dataram1, int sectors, int count) +{ + int bsa, bsc; + + /* BufferRAM Sector Address */ + bsa = sectors & ONENAND_BSA_MASK; + + if (dataram1) + bsa |= ONENAND_BSA_DATARAM1; /* DataRAM1 */ + else + bsa |= ONENAND_BSA_DATARAM0; /* DataRAM0 */ + + /* BufferRAM Sector Count */ + bsc = count & ONENAND_BSC_MASK; + + return ((bsa << ONENAND_BSA_SHIFT) | bsc); +} + +/** + * onenand_command - [DEFAULT] Send command to OneNAND device + * @param mtd MTD device structure + * @param cmd the command to be sent + * @param addr offset to read from or write to + * @param len number of bytes to read or write + * + * Send command to OneNAND device. This function is used for middle/large page + * devices (1KB/2KB Bytes per page) + */ +static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t len) +{ + struct onenand_chip *this = mtd->priv; + int value, readcmd = 0; + int block, page; + /* Now we use page size operation */ + int sectors = 4, count = 4; + + /* Address translation */ + switch (cmd) { + case ONENAND_CMD_UNLOCK: + case ONENAND_CMD_LOCK: + case ONENAND_CMD_LOCK_TIGHT: + block = -1; + page = -1; + break; + + case ONENAND_CMD_ERASE: + case ONENAND_CMD_BUFFERRAM: + block = (int) (addr >> this->erase_shift); + page = -1; + break; + + default: + block = (int) (addr >> this->erase_shift); + page = (int) (addr >> this->page_shift); + page &= this->page_mask; + break; + } + + /* NOTE: The setting order of the registers is very important! */ + if (cmd == ONENAND_CMD_BUFFERRAM) { + /* Select DataRAM for DDP */ + value = onenand_bufferram_address(this, block); + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); + + /* Switch to the next data buffer */ + ONENAND_SET_NEXT_BUFFERRAM(this); + + return 0; + } + + if (block != -1) { + /* Write 'DFS, FBA' of Flash */ + value = onenand_block_address(this, block); + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); + } + + if (page != -1) { + int dataram; + + switch (cmd) { + case ONENAND_CMD_READ: + case ONENAND_CMD_READOOB: + dataram = ONENAND_SET_NEXT_BUFFERRAM(this); + readcmd = 1; + break; + + default: + dataram = ONENAND_CURRENT_BUFFERRAM(this); + break; + } + + /* Write 'FPA, FSA' of Flash */ + value = onenand_page_address(page, sectors); + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS8); + + /* Write 'BSA, BSC' of DataRAM */ + value = onenand_buffer_address(dataram, sectors, count); + this->write_word(value, this->base + ONENAND_REG_START_BUFFER); + + if (readcmd) { + /* Select DataRAM for DDP */ + value = onenand_bufferram_address(this, block); + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); + } + } + + /* Interrupt clear */ + this->write_word(ONENAND_INT_CLEAR, this->base + ONENAND_REG_INTERRUPT); + + /* Write command */ + this->write_word(cmd, this->base + ONENAND_REG_COMMAND); + + return 0; +} + +/** + * onenand_wait - [DEFAULT] wait until the command is done + * @param mtd MTD device structure + * @param state state to select the max. timeout value + * + * Wait for command done. This applies to all OneNAND command + * Read can take up to 30us, erase up to 2ms and program up to 350us + * according to general OneNAND specs + */ +static int onenand_wait(struct mtd_info *mtd, int state) +{ + struct onenand_chip * this = mtd->priv; + unsigned long timeout; + unsigned int flags = ONENAND_INT_MASTER; + unsigned int interrupt = 0; + unsigned int ctrl, ecc; + + /* The 20 msec is enough */ + timeout = jiffies + msecs_to_jiffies(20); + while (time_before(jiffies, timeout)) { + interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); + + if (interrupt & flags) + break; + + if (state != FL_READING) + cond_resched(); + } + /* To get correct interrupt status in timeout case */ + interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); + + ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); + + if (ctrl & ONENAND_CTRL_ERROR) { + /* It maybe occur at initial bad block */ + DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: controller error = 0x%04x\n", ctrl); + /* Clear other interrupt bits for preventing ECC error */ + interrupt &= ONENAND_INT_MASTER; + } + + if (ctrl & ONENAND_CTRL_LOCK) { + DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: it's locked error = 0x%04x\n", ctrl); + return -EACCES; + } + + if (interrupt & ONENAND_INT_READ) { + ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); + if (ecc & ONENAND_ECC_2BIT_ALL) { + DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: ECC error = 0x%04x\n", ecc); + return -EBADMSG; + } + } + + return 0; +} + +/** + * onenand_bufferram_offset - [DEFAULT] BufferRAM offset + * @param mtd MTD data structure + * @param area BufferRAM area + * @return offset given area + * + * Return BufferRAM offset given area + */ +static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area) +{ + struct onenand_chip *this = mtd->priv; + + if (ONENAND_CURRENT_BUFFERRAM(this)) { + if (area == ONENAND_DATARAM) + return mtd->oobblock; + if (area == ONENAND_SPARERAM) + return mtd->oobsize; + } + + return 0; +} + +/** + * onenand_read_bufferram - [OneNAND Interface] Read the bufferram area + * @param mtd MTD data structure + * @param area BufferRAM area + * @param buffer the databuffer to put/get data + * @param offset offset to read from or write to + * @param count number of bytes to read/write + * + * Read the BufferRAM area + */ +static int onenand_read_bufferram(struct mtd_info *mtd, int area, + unsigned char *buffer, int offset, size_t count) +{ + struct onenand_chip *this = mtd->priv; + void __iomem *bufferram; + + bufferram = this->base + area; + + bufferram += onenand_bufferram_offset(mtd, area); + + memcpy(buffer, bufferram + offset, count); + + return 0; +} + +/** + * onenand_sync_read_bufferram - [OneNAND Interface] Read the bufferram area with Sync. Burst mode + * @param mtd MTD data structure + * @param area BufferRAM area + * @param buffer the databuffer to put/get data + * @param offset offset to read from or write to + * @param count number of bytes to read/write + * + * Read the BufferRAM area with Sync. Burst Mode + */ +static int onenand_sync_read_bufferram(struct mtd_info *mtd, int area, + unsigned char *buffer, int offset, size_t count) +{ + struct onenand_chip *this = mtd->priv; + void __iomem *bufferram; + + bufferram = this->base + area; + + bufferram += onenand_bufferram_offset(mtd, area); + + this->mmcontrol(mtd, ONENAND_SYS_CFG1_SYNC_READ); + + memcpy(buffer, bufferram + offset, count); + + this->mmcontrol(mtd, 0); + + return 0; +} + +/** + * onenand_write_bufferram - [OneNAND Interface] Write the bufferram area + * @param mtd MTD data structure + * @param area BufferRAM area + * @param buffer the databuffer to put/get data + * @param offset offset to read from or write to + * @param count number of bytes to read/write + * + * Write the BufferRAM area + */ +static int onenand_write_bufferram(struct mtd_info *mtd, int area, + const unsigned char *buffer, int offset, size_t count) +{ + struct onenand_chip *this = mtd->priv; + void __iomem *bufferram; + + bufferram = this->base + area; + + bufferram += onenand_bufferram_offset(mtd, area); + + memcpy(bufferram + offset, buffer, count); + + return 0; +} + +/** + * onenand_check_bufferram - [GENERIC] Check BufferRAM information + * @param mtd MTD data structure + * @param addr address to check + * @return 1 if there are valid data, otherwise 0 + * + * Check bufferram if there is data we required + */ +static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr) +{ + struct onenand_chip *this = mtd->priv; + int block, page; + int i; + + block = (int) (addr >> this->erase_shift); + page = (int) (addr >> this->page_shift); + page &= this->page_mask; + + i = ONENAND_CURRENT_BUFFERRAM(this); + + /* Is there valid data? */ + if (this->bufferram[i].block == block && + this->bufferram[i].page == page && + this->bufferram[i].valid) + return 1; + + return 0; +} + +/** + * onenand_update_bufferram - [GENERIC] Update BufferRAM information + * @param mtd MTD data structure + * @param addr address to update + * @param valid valid flag + * + * Update BufferRAM information + */ +static int onenand_update_bufferram(struct mtd_info *mtd, loff_t addr, + int valid) +{ + struct onenand_chip *this = mtd->priv; + int block, page; + int i; + + block = (int) (addr >> this->erase_shift); + page = (int) (addr >> this->page_shift); + page &= this->page_mask; + + /* Invalidate BufferRAM */ + for (i = 0; i < MAX_BUFFERRAM; i++) { + if (this->bufferram[i].block == block && + this->bufferram[i].page == page) + this->bufferram[i].valid = 0; + } + + /* Update BufferRAM */ + i = ONENAND_CURRENT_BUFFERRAM(this); + this->bufferram[i].block = block; + this->bufferram[i].page = page; + this->bufferram[i].valid = valid; + + return 0; +} + +/** + * onenand_get_device - [GENERIC] Get chip for selected access + * @param mtd MTD device structure + * @param new_state the state which is requested + * + * Get the device and lock it for exclusive access + */ +static int onenand_get_device(struct mtd_info *mtd, int new_state) +{ + struct onenand_chip *this = mtd->priv; + DECLARE_WAITQUEUE(wait, current); + + /* + * Grab the lock and see if the device is available + */ + while (1) { + spin_lock(&this->chip_lock); + if (this->state == FL_READY) { + this->state = new_state; + spin_unlock(&this->chip_lock); + break; + } + if (new_state == FL_PM_SUSPENDED) { + spin_unlock(&this->chip_lock); + return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN; + } + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&this->wq, &wait); + spin_unlock(&this->chip_lock); + schedule(); + remove_wait_queue(&this->wq, &wait); + } + + return 0; +} + +/** + * onenand_release_device - [GENERIC] release chip + * @param mtd MTD device structure + * + * Deselect, release chip lock and wake up anyone waiting on the device + */ +static void onenand_release_device(struct mtd_info *mtd) +{ + struct onenand_chip *this = mtd->priv; + + /* Release the chip */ + spin_lock(&this->chip_lock); + this->state = FL_READY; + wake_up(&this->wq); + spin_unlock(&this->chip_lock); +} + +/** + * onenand_read_ecc - [MTD Interface] Read data with ECC + * @param mtd MTD device structure + * @param from offset to read from + * @param len number of bytes to read + * @param retlen pointer to variable to store the number of read bytes + * @param buf the databuffer to put data + * @param oob_buf filesystem supplied oob data buffer + * @param oobsel oob selection structure + * + * OneNAND read with ECC + */ +static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf, + u_char *oob_buf, struct nand_oobinfo *oobsel) +{ + struct onenand_chip *this = mtd->priv; + int read = 0, column; + int thislen; + int ret = 0; + + DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); + + /* Do not allow reads past end of device */ + if ((from + len) > mtd->size) { + DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: Attempt read beyond end of device\n"); + *retlen = 0; + return -EINVAL; + } + + /* Grab the lock and see if the device is available */ + onenand_get_device(mtd, FL_READING); + + /* TODO handling oob */ + + while (read < len) { + thislen = min_t(int, mtd->oobblock, len - read); + + column = from & (mtd->oobblock - 1); + if (column + thislen > mtd->oobblock) + thislen = mtd->oobblock - column; + + if (!onenand_check_bufferram(mtd, from)) { + this->command(mtd, ONENAND_CMD_READ, from, mtd->oobblock); + + ret = this->wait(mtd, FL_READING); + /* First copy data and check return value for ECC handling */ + onenand_update_bufferram(mtd, from, 1); + } + + this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); + + read += thislen; + + if (read == len) + break; + + if (ret) { + DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: read failed = %d\n", ret); + goto out; + } + + from += thislen; + buf += thislen; + } + +out: + /* Deselect and wake up anyone waiting on the device */ + onenand_release_device(mtd); + + /* + * Return success, if no ECC failures, else -EBADMSG + * fs driver will take care of that, because + * retlen == desired len and result == -EBADMSG + */ + *retlen = read; + return ret; +} + +/** + * onenand_read - [MTD Interface] MTD compability function for onenand_read_ecc + * @param mtd MTD device structure + * @param from offset to read from + * @param len number of bytes to read + * @param retlen pointer to variable to store the number of read bytes + * @param buf the databuffer to put data + * + * This function simply calls onenand_read_ecc with oob buffer and oobsel = NULL +*/ +static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + return onenand_read_ecc(mtd, from, len, retlen, buf, NULL, NULL); +} + +/** + * onenand_read_oob - [MTD Interface] OneNAND read out-of-band + * @param mtd MTD device structure + * @param from offset to read from + * @param len number of bytes to read + * @param retlen pointer to variable to store the number of read bytes + * @param buf the databuffer to put data + * + * OneNAND read out-of-band data from the spare area + */ +static int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct onenand_chip *this = mtd->priv; + int read = 0, thislen, column; + int ret = 0; + + DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); + + /* Initialize return length value */ + *retlen = 0; + + /* Do not allow reads past end of device */ + if (unlikely((from + len) > mtd->size)) { + DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: Attempt read beyond end of device\n"); + return -EINVAL; + } + + /* Grab the lock and see if the device is available */ + onenand_get_device(mtd, FL_READING); + + column = from & (mtd->oobsize - 1); + + while (read < len) { + thislen = mtd->oobsize - column; + thislen = min_t(int, thislen, len); + + this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize); + + onenand_update_bufferram(mtd, from, 0); + + ret = this->wait(mtd, FL_READING); + /* First copy data and check return value for ECC handling */ + + this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); + + read += thislen; + + if (read == len) + break; + + if (ret) { + DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: read failed = %d\n", ret); + goto out; + } + + buf += thislen; + + /* Read more? */ + if (read < len) { + /* Page size */ + from += mtd->oobblock; + column = 0; + } + } + +out: + /* Deselect and wake up anyone waiting on the device */ + onenand_release_device(mtd); + + *retlen = read; + return ret; +} + +#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE +/** + * onenand_verify_page - [GENERIC] verify the chip contents after a write + * @param mtd MTD device structure + * @param buf the databuffer to verify + * + * Check DataRAM area directly + */ +static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr) +{ + struct onenand_chip *this = mtd->priv; + void __iomem *dataram0, *dataram1; + int ret = 0; + + this->command(mtd, ONENAND_CMD_READ, addr, mtd->oobblock); + + ret = this->wait(mtd, FL_READING); + if (ret) + return ret; + + onenand_update_bufferram(mtd, addr, 1); + + /* Check, if the two dataram areas are same */ + dataram0 = this->base + ONENAND_DATARAM; + dataram1 = dataram0 + mtd->oobblock; + + if (memcmp(dataram0, dataram1, mtd->oobblock)) + return -EBADMSG; + + return 0; +} +#else +#define onenand_verify_page(...) (0) +#endif + +#define NOTALIGNED(x) ((x & (mtd->oobblock - 1)) != 0) + +/** + * onenand_write_ecc - [MTD Interface] OneNAND write with ECC + * @param mtd MTD device structure + * @param to offset to write to + * @param len number of bytes to write + * @param retlen pointer to variable to store the number of written bytes + * @param buf the data to write + * @param eccbuf filesystem supplied oob data buffer + * @param oobsel oob selection structure + * + * OneNAND write with ECC + */ +static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf, + u_char *eccbuf, struct nand_oobinfo *oobsel) +{ + struct onenand_chip *this = mtd->priv; + int written = 0; + int ret = 0; + + DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); + + /* Initialize retlen, in case of early exit */ + *retlen = 0; + + /* Do not allow writes past end of device */ + if (unlikely((to + len) > mtd->size)) { + DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt write to past end of device\n"); + return -EINVAL; + } + + /* Reject writes, which are not page aligned */ + if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { + DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt to write not page aligned data\n"); + return -EINVAL; + } + + /* Grab the lock and see if the device is available */ + onenand_get_device(mtd, FL_WRITING); + + /* Loop until all data write */ + while (written < len) { + int thislen = min_t(int, mtd->oobblock, len - written); + + this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobblock); + + this->write_bufferram(mtd, ONENAND_DATARAM, buf, 0, thislen); + this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); + + this->command(mtd, ONENAND_CMD_PROG, to, mtd->oobblock); + + onenand_update_bufferram(mtd, to, 1); + + ret = this->wait(mtd, FL_WRITING); + if (ret) { + DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: write filaed %d\n", ret); + goto out; + } + + written += thislen; + + /* Only check verify write turn on */ + ret = onenand_verify_page(mtd, (u_char *) buf, to); + if (ret) { + DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: verify failed %d\n", ret); + goto out; + } + + if (written == len) + break; + + to += thislen; + buf += thislen; + } + +out: + /* Deselect and wake up anyone waiting on the device */ + onenand_release_device(mtd); + + *retlen = written; + + return ret; +} + +/** + * onenand_write - [MTD Interface] compability function for onenand_write_ecc + * @param mtd MTD device structure + * @param to offset to write to + * @param len number of bytes to write + * @param retlen pointer to variable to store the number of written bytes + * @param buf the data to write + * + * This function simply calls onenand_write_ecc + * with oob buffer and oobsel = NULL + */ +static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + return onenand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL); +} + +/** + * onenand_write_oob - [MTD Interface] OneNAND write out-of-band + * @param mtd MTD device structure + * @param to offset to write to + * @param len number of bytes to write + * @param retlen pointer to variable to store the number of written bytes + * @param buf the data to write + * + * OneNAND write out-of-band + */ +static int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct onenand_chip *this = mtd->priv; + int column, status; + int written = 0; + + DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); + + /* Initialize retlen, in case of early exit */ + *retlen = 0; + + /* Do not allow writes past end of device */ + if (unlikely((to + len) > mtd->size)) { + DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: Attempt write to past end of device\n"); + return -EINVAL; + } + + /* Grab the lock and see if the device is available */ + onenand_get_device(mtd, FL_WRITING); + + /* Loop until all data write */ + while (written < len) { + int thislen = min_t(int, mtd->oobsize, len - written); + + column = to & (mtd->oobsize - 1); + + this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize); + + this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); + this->write_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); + + this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); + + onenand_update_bufferram(mtd, to, 0); + + status = this->wait(mtd, FL_WRITING); + if (status) + goto out; + + written += thislen; + + if (written == len) + break; + + to += thislen; + buf += thislen; + } + +out: + /* Deselect and wake up anyone waiting on the device */ + onenand_release_device(mtd); + + *retlen = written; + + return 0; +} + +/** + * onenand_writev_ecc - [MTD Interface] write with iovec with ecc + * @param mtd MTD device structure + * @param vecs the iovectors to write + * @param count number of vectors + * @param to offset to write to + * @param retlen pointer to variable to store the number of written bytes + * @param eccbuf filesystem supplied oob data buffer + * @param oobsel oob selection structure + * + * OneNAND write with iovec with ecc + */ +static int onenand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, + unsigned long count, loff_t to, size_t *retlen, + u_char *eccbuf, struct nand_oobinfo *oobsel) +{ + struct onenand_chip *this = mtd->priv; + unsigned char buffer[MAX_ONENAND_PAGESIZE], *pbuf; + size_t total_len, len; + int i, written = 0; + int ret = 0; + + /* Preset written len for early exit */ + *retlen = 0; + + /* Calculate total length of data */ + total_len = 0; + for (i = 0; i < count; i++) + total_len += vecs[i].iov_len; + + DEBUG(MTD_DEBUG_LEVEL3, "onenand_writev_ecc: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count); + + /* Do not allow write past end of the device */ + if (unlikely((to + total_len) > mtd->size)) { + DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: Attempted write past end of device\n"); + return -EINVAL; + } + + /* Reject writes, which are not page aligned */ + if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(total_len))) { + DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: Attempt to write not page aligned data\n"); + return -EINVAL; + } + + /* Grab the lock and see if the device is available */ + onenand_get_device(mtd, FL_WRITING); + + /* TODO handling oob */ + + /* Loop until all keve's data has been written */ + len = 0; + while (count) { + pbuf = buffer; + /* + * If the given tuple is >= pagesize then + * write it out from the iov + */ + if ((vecs->iov_len - len) >= mtd->oobblock) { + pbuf = vecs->iov_base + len; + + len += mtd->oobblock; + + /* Check, if we have to switch to the next tuple */ + if (len >= (int) vecs->iov_len) { + vecs++; + len = 0; + count--; + } + } else { + int cnt = 0, thislen; + while (cnt < mtd->oobblock) { + thislen = min_t(int, mtd->oobblock - cnt, vecs->iov_len - len); + memcpy(buffer + cnt, vecs->iov_base + len, thislen); + cnt += thislen; + len += thislen; + + /* Check, if we have to switch to the next tuple */ + if (len >= (int) vecs->iov_len) { + vecs++; + len = 0; + count--; + } + } + } + + this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobblock); + + this->write_bufferram(mtd, ONENAND_DATARAM, pbuf, 0, mtd->oobblock); + this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); + + this->command(mtd, ONENAND_CMD_PROG, to, mtd->oobblock); + + onenand_update_bufferram(mtd, to, 1); + + ret = this->wait(mtd, FL_WRITING); + if (ret) { + DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: write failed %d\n", ret); + goto out; + } + + + /* Only check verify write turn on */ + ret = onenand_verify_page(mtd, (u_char *) pbuf, to); + if (ret) { + DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: verify failed %d\n", ret); + goto out; + } + + written += mtd->oobblock; + + to += mtd->oobblock; + } + +out: + /* Deselect and wakt up anyone waiting on the device */ + onenand_release_device(mtd); + + *retlen = written; + + return 0; +} + +/** + * onenand_writev - [MTD Interface] compabilty function for onenand_writev_ecc + * @param mtd MTD device structure + * @param vecs the iovectors to write + * @param count number of vectors + * @param to offset to write to + * @param retlen pointer to variable to store the number of written bytes + * + * OneNAND write with kvec. This just calls the ecc function + */ +static int onenand_writev(struct mtd_info *mtd, const struct kvec *vecs, + unsigned long count, loff_t to, size_t *retlen) +{ + return onenand_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL); +} + +/** + * onenand_block_checkbad - [GENERIC] Check if a block is marked bad + * @param mtd MTD device structure + * @param ofs offset from device start + * @param getchip 0, if the chip is already selected + * @param allowbbt 1, if its allowed to access the bbt area + * + * Check, if the block is bad. Either by reading the bad block table or + * calling of the scan function. + */ +static int onenand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt) +{ + struct onenand_chip *this = mtd->priv; + struct bbm_info *bbm = this->bbm; + + /* Return info from the table */ + return bbm->isbad_bbt(mtd, ofs, allowbbt); +} + +/** + * onenand_erase - [MTD Interface] erase block(s) + * @param mtd MTD device structure + * @param instr erase instruction + * + * Erase one ore more blocks + */ +static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + struct onenand_chip *this = mtd->priv; + unsigned int block_size; + loff_t addr; + int len; + int ret = 0; + + DEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len); + + block_size = (1 << this->erase_shift); + + /* Start address must align on block boundary */ + if (unlikely(instr->addr & (block_size - 1))) { + DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Unaligned address\n"); + return -EINVAL; + } + + /* Length must align on block boundary */ + if (unlikely(instr->len & (block_size - 1))) { + DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Length not block aligned\n"); + return -EINVAL; + } + + /* Do not allow erase past end of device */ + if (unlikely((instr->len + instr->addr) > mtd->size)) { + DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Erase past end of device\n"); + return -EINVAL; + } + + instr->fail_addr = 0xffffffff; + + /* Grab the lock and see if the device is available */ + onenand_get_device(mtd, FL_ERASING); + + /* Loop throught the pages */ + len = instr->len; + addr = instr->addr; + + instr->state = MTD_ERASING; + + while (len) { + + /* Check if we have a bad block, we do not erase bad blocks */ + if (onenand_block_checkbad(mtd, addr, 0, 0)) { + printk (KERN_WARNING "onenand_erase: attempt to erase a bad block at addr 0x%08x\n", (unsigned int) addr); + instr->state = MTD_ERASE_FAILED; + goto erase_exit; + } + + this->command(mtd, ONENAND_CMD_ERASE, addr, block_size); + + ret = this->wait(mtd, FL_ERASING); + /* Check, if it is write protected */ + if (ret) { + if (ret == -EPERM) + DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Device is write protected!!!\n"); + else + DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Failed erase, block %d\n", (unsigned) (addr >> this->erase_shift)); + instr->state = MTD_ERASE_FAILED; + instr->fail_addr = addr; + goto erase_exit; + } + + len -= block_size; + addr += block_size; + } + + instr->state = MTD_ERASE_DONE; + +erase_exit: + + ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; + /* Do call back function */ + if (!ret) + mtd_erase_callback(instr); + + /* Deselect and wake up anyone waiting on the device */ + onenand_release_device(mtd); + + return ret; +} + +/** + * onenand_sync - [MTD Interface] sync + * @param mtd MTD device structure + * + * Sync is actually a wait for chip ready function + */ +static void onenand_sync(struct mtd_info *mtd) +{ + DEBUG(MTD_DEBUG_LEVEL3, "onenand_sync: called\n"); + + /* Grab the lock and see if the device is available */ + onenand_get_device(mtd, FL_SYNCING); + + /* Release it and go back */ + onenand_release_device(mtd); +} + + +/** + * onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad + * @param mtd MTD device structure + * @param ofs offset relative to mtd start + * + * Check whether the block is bad + */ +static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs) +{ + /* Check for invalid offset */ + if (ofs > mtd->size) + return -EINVAL; + + return onenand_block_checkbad(mtd, ofs, 1, 0); +} + +/** + * onenand_default_block_markbad - [DEFAULT] mark a block bad + * @param mtd MTD device structure + * @param ofs offset from device start + * + * This is the default implementation, which can be overridden by + * a hardware specific driver. + */ +static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) +{ + struct onenand_chip *this = mtd->priv; + struct bbm_info *bbm = this->bbm; + u_char buf[2] = {0, 0}; + size_t retlen; + int block; + + /* Get block number */ + block = ((int) ofs) >> bbm->bbt_erase_shift; + if (bbm->bbt) + bbm->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); + + /* We write two bytes, so we dont have to mess with 16 bit access */ + ofs += mtd->oobsize + (bbm->badblockpos & ~0x01); + return mtd->write_oob(mtd, ofs , 2, &retlen, buf); +} + +/** + * onenand_block_markbad - [MTD Interface] Mark the block at the given offset as bad + * @param mtd MTD device structure + * @param ofs offset relative to mtd start + * + * Mark the block as bad + */ +static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs) +{ + struct onenand_chip *this = mtd->priv; + int ret; + + ret = onenand_block_isbad(mtd, ofs); + if (ret) { + /* If it was bad already, return success and do nothing */ + if (ret > 0) + return 0; + return ret; + } + + return this->block_markbad(mtd, ofs); +} + +/** + * onenand_unlock - [MTD Interface] Unlock block(s) + * @param mtd MTD device structure + * @param ofs offset relative to mtd start + * @param len number of bytes to unlock + * + * Unlock one or more blocks + */ +static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + struct onenand_chip *this = mtd->priv; + int start, end, block, value, status; + + start = ofs >> this->erase_shift; + end = len >> this->erase_shift; + + /* Continuous lock scheme */ + if (this->options & ONENAND_CONT_LOCK) { + /* Set start block address */ + this->write_word(start, this->base + ONENAND_REG_START_BLOCK_ADDRESS); + /* Set end block address */ + this->write_word(end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS); + /* Write unlock command */ + this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0); + + /* There's no return value */ + this->wait(mtd, FL_UNLOCKING); + + /* Sanity check */ + while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS) + & ONENAND_CTRL_ONGO) + continue; + + /* Check lock status */ + status = this->read_word(this->base + ONENAND_REG_WP_STATUS); + if (!(status & ONENAND_WP_US)) + printk(KERN_ERR "wp status = 0x%x\n", status); + + return 0; + } + + /* Block lock scheme */ + for (block = start; block < end; block++) { + /* Set start block address */ + this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS); + /* Write unlock command */ + this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0); + + /* There's no return value */ + this->wait(mtd, FL_UNLOCKING); + + /* Sanity check */ + while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS) + & ONENAND_CTRL_ONGO) + continue; + + /* Set block address for read block status */ + value = onenand_block_address(this, block); + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); + + /* Check lock status */ + status = this->read_word(this->base + ONENAND_REG_WP_STATUS); + if (!(status & ONENAND_WP_US)) + printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status); + } + + return 0; +} + +/** + * onenand_print_device_info - Print device ID + * @param device device ID + * + * Print device ID + */ +static void onenand_print_device_info(int device) +{ + int vcc, demuxed, ddp, density; + + vcc = device & ONENAND_DEVICE_VCC_MASK; + demuxed = device & ONENAND_DEVICE_IS_DEMUX; + ddp = device & ONENAND_DEVICE_IS_DDP; + density = device >> ONENAND_DEVICE_DENSITY_SHIFT; + printk(KERN_INFO "%sOneNAND%s %dMB %sV 16-bit (0x%02x)\n", + demuxed ? "" : "Muxed ", + ddp ? "(DDP)" : "", + (16 << density), + vcc ? "2.65/3.3" : "1.8", + device); +} + +static const struct onenand_manufacturers onenand_manuf_ids[] = { + {ONENAND_MFR_SAMSUNG, "Samsung"}, + {ONENAND_MFR_UNKNOWN, "Unknown"} +}; + +/** + * onenand_check_maf - Check manufacturer ID + * @param manuf manufacturer ID + * + * Check manufacturer ID + */ +static int onenand_check_maf(int manuf) +{ + int i; + + for (i = 0; onenand_manuf_ids[i].id; i++) { + if (manuf == onenand_manuf_ids[i].id) + break; + } + + printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n", + onenand_manuf_ids[i].name, manuf); + + return (i != ONENAND_MFR_UNKNOWN); +} + +/** + * onenand_probe - [OneNAND Interface] Probe the OneNAND device + * @param mtd MTD device structure + * + * OneNAND detection method: + * Compare the the values from command with ones from register + */ +static int onenand_probe(struct mtd_info *mtd) +{ + struct onenand_chip *this = mtd->priv; + int bram_maf_id, bram_dev_id, maf_id, dev_id; + int version_id; + int density; + + /* Send the command for reading device ID from BootRAM */ + this->write_word(ONENAND_CMD_READID, this->base + ONENAND_BOOTRAM); + + /* Read manufacturer and device IDs from BootRAM */ + bram_maf_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x0); + bram_dev_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x2); + + /* Check manufacturer ID */ + if (onenand_check_maf(bram_maf_id)) + return -ENXIO; + + /* Reset OneNAND to read default register values */ + this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM); + + /* Read manufacturer and device IDs from Register */ + maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID); + dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID); + + /* Check OneNAND device */ + if (maf_id != bram_maf_id || dev_id != bram_dev_id) + return -ENXIO; + + /* Flash device information */ + onenand_print_device_info(dev_id); + this->device_id = dev_id; + + density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; + this->chipsize = (16 << density) << 20; + /* Set density mask. it is used for DDP */ + this->density_mask = (1 << (density + 6)); + + /* OneNAND page size & block size */ + /* The data buffer size is equal to page size */ + mtd->oobblock = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE); + mtd->oobsize = mtd->oobblock >> 5; + /* Pagers per block is always 64 in OneNAND */ + mtd->erasesize = mtd->oobblock << 6; + + this->erase_shift = ffs(mtd->erasesize) - 1; + this->page_shift = ffs(mtd->oobblock) - 1; + this->ppb_shift = (this->erase_shift - this->page_shift); + this->page_mask = (mtd->erasesize / mtd->oobblock) - 1; + + /* REVIST: Multichip handling */ + + mtd->size = this->chipsize; + + /* Version ID */ + version_id = this->read_word(this->base + ONENAND_REG_VERSION_ID); + printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version_id); + + /* Lock scheme */ + if (density <= ONENAND_DEVICE_DENSITY_512Mb && + !(version_id >> ONENAND_VERSION_PROCESS_SHIFT)) { + printk(KERN_INFO "Lock scheme is Continues Lock\n"); + this->options |= ONENAND_CONT_LOCK; + } + + return 0; +} + +/** + * onenand_suspend - [MTD Interface] Suspend the OneNAND flash + * @param mtd MTD device structure + */ +static int onenand_suspend(struct mtd_info *mtd) +{ + return onenand_get_device(mtd, FL_PM_SUSPENDED); +} + +/** + * onenand_resume - [MTD Interface] Resume the OneNAND flash + * @param mtd MTD device structure + */ +static void onenand_resume(struct mtd_info *mtd) +{ + struct onenand_chip *this = mtd->priv; + + if (this->state == FL_PM_SUSPENDED) + onenand_release_device(mtd); + else + printk(KERN_ERR "resume() called for the chip which is not" + "in suspended state\n"); +} + + +/** + * onenand_scan - [OneNAND Interface] Scan for the OneNAND device + * @param mtd MTD device structure + * @param maxchips Number of chips to scan for + * + * This fills out all the not initialized function pointers + * with the defaults. + * The flash ID is read and the mtd/chip structures are + * filled with the appropriate values. + */ +int onenand_scan(struct mtd_info *mtd, int maxchips) +{ + struct onenand_chip *this = mtd->priv; + + if (!this->read_word) + this->read_word = onenand_readw; + if (!this->write_word) + this->write_word = onenand_writew; + + if (!this->command) + this->command = onenand_command; + if (!this->wait) + this->wait = onenand_wait; + + if (!this->read_bufferram) + this->read_bufferram = onenand_read_bufferram; + if (!this->write_bufferram) + this->write_bufferram = onenand_write_bufferram; + + if (!this->block_markbad) + this->block_markbad = onenand_default_block_markbad; + if (!this->scan_bbt) + this->scan_bbt = onenand_default_bbt; + + if (onenand_probe(mtd)) + return -ENXIO; + + /* Set Sync. Burst Read after probing */ + if (this->mmcontrol) { + printk(KERN_INFO "OneNAND Sync. Burst Read support\n"); + this->read_bufferram = onenand_sync_read_bufferram; + } + + this->state = FL_READY; + init_waitqueue_head(&this->wq); + spin_lock_init(&this->chip_lock); + + switch (mtd->oobsize) { + case 64: + this->autooob = &onenand_oob_64; + break; + + case 32: + this->autooob = &onenand_oob_32; + break; + + default: + printk(KERN_WARNING "No OOB scheme defined for oobsize %d\n", + mtd->oobsize); + /* To prevent kernel oops */ + this->autooob = &onenand_oob_32; + break; + } + + memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo)); + + /* Fill in remaining MTD driver data */ + mtd->type = MTD_NANDFLASH; + mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC; + mtd->ecctype = MTD_ECC_SW; + mtd->erase = onenand_erase; + mtd->point = NULL; + mtd->unpoint = NULL; + mtd->read = onenand_read; + mtd->write = onenand_write; + mtd->read_ecc = onenand_read_ecc; + mtd->write_ecc = onenand_write_ecc; + mtd->read_oob = onenand_read_oob; + mtd->write_oob = onenand_write_oob; + mtd->readv = NULL; + mtd->readv_ecc = NULL; + mtd->writev = onenand_writev; + mtd->writev_ecc = onenand_writev_ecc; + mtd->sync = onenand_sync; + mtd->lock = NULL; + mtd->unlock = onenand_unlock; + mtd->suspend = onenand_suspend; + mtd->resume = onenand_resume; + mtd->block_isbad = onenand_block_isbad; + mtd->block_markbad = onenand_block_markbad; + mtd->owner = THIS_MODULE; + + /* Unlock whole block */ + mtd->unlock(mtd, 0x0, this->chipsize); + + return this->scan_bbt(mtd); +} + +/** + * onenand_release - [OneNAND Interface] Free resources held by the OneNAND device + * @param mtd MTD device structure + */ +void onenand_release(struct mtd_info *mtd) +{ +#ifdef CONFIG_MTD_PARTITIONS + /* Deregister partitions */ + del_mtd_partitions (mtd); +#endif + /* Deregister the device */ + del_mtd_device (mtd); +} + +EXPORT_SYMBOL_GPL(onenand_scan); +EXPORT_SYMBOL_GPL(onenand_release); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kyungmin Park "); +MODULE_DESCRIPTION("Generic OneNAND flash driver code"); diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c new file mode 100644 index 0000000000000000000000000000000000000000..f40190f499e120416f9ba795a210ad357d8ad203 --- /dev/null +++ b/drivers/mtd/onenand/onenand_bbt.c @@ -0,0 +1,246 @@ +/* + * linux/drivers/mtd/onenand/onenand_bbt.c + * + * Bad Block Table support for the OneNAND driver + * + * Copyright(c) 2005 Samsung Electronics + * Kyungmin Park + * + * Derived from nand_bbt.c + * + * TODO: + * Split BBT core and chip specific BBT. + */ + +#include +#include +#include +#include + +/** + * check_short_pattern - [GENERIC] check if a pattern is in the buffer + * @param buf the buffer to search + * @param len the length of buffer to search + * @param paglen the pagelength + * @param td search pattern descriptor + * + * Check for a pattern at the given place. Used to search bad block + * tables and good / bad block identifiers. Same as check_pattern, but + * no optional empty check and the pattern is expected to start + * at offset 0. + * + */ +static int check_short_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) +{ + int i; + uint8_t *p = buf; + + /* Compare the pattern */ + for (i = 0; i < td->len; i++) { + if (p[i] != td->pattern[i]) + return -1; + } + return 0; +} + +/** + * create_bbt - [GENERIC] Create a bad block table by scanning the device + * @param mtd MTD device structure + * @param buf temporary buffer + * @param bd descriptor for the good/bad block search pattern + * @param chip create the table for a specific chip, -1 read all chips. + * Applies only if NAND_BBT_PERCHIP option is set + * + * Create a bad block table by scanning the device + * for the given good/bad block identify pattern + */ +static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) +{ + struct onenand_chip *this = mtd->priv; + struct bbm_info *bbm = this->bbm; + int i, j, numblocks, len, scanlen; + int startblock; + loff_t from; + size_t readlen, ooblen; + + printk(KERN_INFO "Scanning device for bad blocks\n"); + + len = 1; + + /* We need only read few bytes from the OOB area */ + scanlen = ooblen = 0; + readlen = bd->len; + + /* chip == -1 case only */ + /* Note that numblocks is 2 * (real numblocks) here; + * see i += 2 below as it makses shifting and masking less painful + */ + numblocks = mtd->size >> (bbm->bbt_erase_shift - 1); + startblock = 0; + from = 0; + + for (i = startblock; i < numblocks; ) { + int ret; + + for (j = 0; j < len; j++) { + size_t retlen; + + /* No need to read pages fully, + * just read required OOB bytes */ + ret = mtd->read_oob(mtd, from + j * mtd->oobblock + bd->offs, + readlen, &retlen, &buf[0]); + + if (ret) + return ret; + + if (check_short_pattern(&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { + bbm->bbt[i >> 3] |= 0x03 << (i & 0x6); + printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", + i >> 1, (unsigned int) from); + break; + } + } + i += 2; + from += (1 << bbm->bbt_erase_shift); + } + + return 0; +} + + +/** + * onenand_memory_bbt - [GENERIC] create a memory based bad block table + * @param mtd MTD device structure + * @param bd descriptor for the good/bad block search pattern + * + * The function creates a memory based bbt by scanning the device + * for manufacturer / software marked good / bad blocks + */ +static inline int onenand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) +{ + unsigned char data_buf[MAX_ONENAND_PAGESIZE]; + + bd->options &= ~NAND_BBT_SCANEMPTY; + return create_bbt(mtd, data_buf, bd, -1); +} + +/** + * onenand_isbad_bbt - [OneNAND Interface] Check if a block is bad + * @param mtd MTD device structure + * @param offs offset in the device + * @param allowbbt allow access to bad block table region + */ +static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) +{ + struct onenand_chip *this = mtd->priv; + struct bbm_info *bbm = this->bbm; + int block; + uint8_t res; + + /* Get block number * 2 */ + block = (int) (offs >> (bbm->bbt_erase_shift - 1)); + res = (bbm->bbt[block >> 3] >> (block & 0x06)) & 0x03; + + DEBUG(MTD_DEBUG_LEVEL2, "onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n", + (unsigned int) offs, block >> 1, res); + + switch ((int) res) { + case 0x00: return 0; + case 0x01: return 1; + case 0x02: return allowbbt ? 0 : 1; + } + + return 1; +} + +/** + * onenand_scan_bbt - [OneNAND Interface] scan, find, read and maybe create bad block table(s) + * @param mtd MTD device structure + * @param bd descriptor for the good/bad block search pattern + * + * The function checks, if a bad block table(s) is/are already + * available. If not it scans the device for manufacturer + * marked good / bad blocks and writes the bad block table(s) to + * the selected place. + * + * The bad block table memory is allocated here. It must be freed + * by calling the onenand_free_bbt function. + * + */ +int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) +{ + struct onenand_chip *this = mtd->priv; + struct bbm_info *bbm = this->bbm; + int len, ret = 0; + + len = mtd->size >> (this->erase_shift + 2); + /* Allocate memory (2bit per block) */ + bbm->bbt = kmalloc(len, GFP_KERNEL); + if (!bbm->bbt) { + printk(KERN_ERR "onenand_scan_bbt: Out of memory\n"); + return -ENOMEM; + } + /* Clear the memory bad block table */ + memset(bbm->bbt, 0x00, len); + + /* Set the bad block position */ + bbm->badblockpos = ONENAND_BADBLOCK_POS; + + /* Set erase shift */ + bbm->bbt_erase_shift = this->erase_shift; + + if (!bbm->isbad_bbt) + bbm->isbad_bbt = onenand_isbad_bbt; + + /* Scan the device to build a memory based bad block table */ + if ((ret = onenand_memory_bbt(mtd, bd))) { + printk(KERN_ERR "onenand_scan_bbt: Can't scan flash and build the RAM-based BBT\n"); + kfree(bbm->bbt); + bbm->bbt = NULL; + } + + return ret; +} + +/* + * Define some generic bad / good block scan pattern which are used + * while scanning a device for factory marked good / bad blocks. + */ +static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; + +static struct nand_bbt_descr largepage_memorybased = { + .options = 0, + .offs = 0, + .len = 2, + .pattern = scan_ff_pattern, +}; + +/** + * onenand_default_bbt - [OneNAND Interface] Select a default bad block table for the device + * @param mtd MTD device structure + * + * This function selects the default bad block table + * support for the device and calls the onenand_scan_bbt function + */ +int onenand_default_bbt(struct mtd_info *mtd) +{ + struct onenand_chip *this = mtd->priv; + struct bbm_info *bbm; + + this->bbm = kmalloc(sizeof(struct bbm_info), GFP_KERNEL); + if (!this->bbm) + return -ENOMEM; + + bbm = this->bbm; + + memset(bbm, 0, sizeof(struct bbm_info)); + + /* 1KB page has same configuration as 2KB page */ + if (!bbm->badblock_pattern) + bbm->badblock_pattern = &largepage_memorybased; + + return onenand_scan_bbt(mtd, bbm->badblock_pattern); +} + +EXPORT_SYMBOL(onenand_scan_bbt); +EXPORT_SYMBOL(onenand_default_bbt); diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c index 13f9e992bef8bb0bc5b5801a1dd9207bdeb2b85e..7b7ca5ab5ae41c27502c1f28800250263a2015f8 100644 --- a/drivers/mtd/redboot.c +++ b/drivers/mtd/redboot.c @@ -1,5 +1,5 @@ /* - * $Id: redboot.c,v 1.17 2004/11/22 11:33:56 ijc Exp $ + * $Id: redboot.c,v 1.18 2005/11/07 11:14:21 gleixner Exp $ * * Parse RedBoot-style Flash Image System (FIS) tables and * produce a Linux partition array to match. @@ -39,7 +39,7 @@ static inline int redboot_checksum(struct fis_image_desc *img) return 1; } -static int parse_redboot_partitions(struct mtd_info *master, +static int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts, unsigned long fis_origin) { diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c new file mode 100644 index 0000000000000000000000000000000000000000..041ee59ea77dca661b547d86088e5fe9e7d16ff1 --- /dev/null +++ b/drivers/mtd/rfd_ftl.c @@ -0,0 +1,855 @@ +/* + * rfd_ftl.c -- resident flash disk (flash translation layer) + * + * Copyright (C) 2005 Sean Young + * + * $Id: rfd_ftl.c,v 1.5 2005/11/07 11:14:21 gleixner Exp $ + * + * This type of flash translation layer (FTL) is used by the Embedded BIOS + * by General Software. It is known as the Resident Flash Disk (RFD), see: + * + * http://www.gensw.com/pages/prod/bios/rfd.htm + * + * based on ftl.c + */ + +#include +#include +#include +#include +#include + +#include + +#define const_cpu_to_le16 __constant_cpu_to_le16 + +static int block_size = 0; +module_param(block_size, int, 0); +MODULE_PARM_DESC(block_size, "Block size to use by RFD, defaults to erase unit size"); + +#define PREFIX "rfd_ftl: " + +/* Major device # for FTL device */ + +/* A request for this major has been sent to device@lanana.org */ +#ifndef RFD_FTL_MAJOR +#define RFD_FTL_MAJOR 95 +#endif + +/* Maximum number of partitions in an FTL region */ +#define PART_BITS 4 + +/* An erase unit should start with this value */ +#define RFD_MAGIC 0x9193 + +/* the second value is 0xffff or 0xffc8; function unknown */ + +/* the third value is always 0xffff, ignored */ + +/* next is an array of mapping for each corresponding sector */ +#define HEADER_MAP_OFFSET 3 +#define SECTOR_DELETED 0x0000 +#define SECTOR_ZERO 0xfffe +#define SECTOR_FREE 0xffff + +#define SECTOR_SIZE 512 + +#define SECTORS_PER_TRACK 63 + +struct block { + enum { + BLOCK_OK, + BLOCK_ERASING, + BLOCK_ERASED, + BLOCK_FAILED + } state; + int free_sectors; + int used_sectors; + int erases; + u_long offset; +}; + +struct partition { + struct mtd_blktrans_dev mbd; + + u_int block_size; /* size of erase unit */ + u_int total_blocks; /* number of erase units */ + u_int header_sectors_per_block; /* header sectors in erase unit */ + u_int data_sectors_per_block; /* data sectors in erase unit */ + u_int sector_count; /* sectors in translated disk */ + u_int header_size; /* bytes in header sector */ + int reserved_block; /* block next up for reclaim */ + int current_block; /* block to write to */ + u16 *header_cache; /* cached header */ + + int is_reclaiming; + int cylinders; + int errors; + u_long *sector_map; + struct block *blocks; +}; + +static int rfd_ftl_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf); + +static int build_block_map(struct partition *part, int block_no) +{ + struct block *block = &part->blocks[block_no]; + int i; + + block->offset = part->block_size * block_no; + + if (le16_to_cpu(part->header_cache[0]) != RFD_MAGIC) { + block->state = BLOCK_ERASED; /* assumption */ + block->free_sectors = part->data_sectors_per_block; + part->reserved_block = block_no; + return 1; + } + + block->state = BLOCK_OK; + + for (i=0; idata_sectors_per_block; i++) { + u16 entry; + + entry = le16_to_cpu(part->header_cache[HEADER_MAP_OFFSET + i]); + + if (entry == SECTOR_DELETED) + continue; + + if (entry == SECTOR_FREE) { + block->free_sectors++; + continue; + } + + if (entry == SECTOR_ZERO) + entry = 0; + + if (entry >= part->sector_count) { + printk(KERN_NOTICE PREFIX + "'%s': unit #%d: entry %d corrupt, " + "sector %d out of range\n", + part->mbd.mtd->name, block_no, i, entry); + continue; + } + + if (part->sector_map[entry] != -1) { + printk(KERN_NOTICE PREFIX + "'%s': more than one entry for sector %d\n", + part->mbd.mtd->name, entry); + part->errors = 1; + continue; + } + + part->sector_map[entry] = block->offset + + (i + part->header_sectors_per_block) * SECTOR_SIZE; + + block->used_sectors++; + } + + if (block->free_sectors == part->data_sectors_per_block) + part->reserved_block = block_no; + + return 0; +} + +static int scan_header(struct partition *part) +{ + int sectors_per_block; + int i, rc = -ENOMEM; + int blocks_found; + size_t retlen; + + sectors_per_block = part->block_size / SECTOR_SIZE; + part->total_blocks = part->mbd.mtd->size / part->block_size; + + if (part->total_blocks < 2) + return -ENOENT; + + /* each erase block has three bytes header, followed by the map */ + part->header_sectors_per_block = + ((HEADER_MAP_OFFSET + sectors_per_block) * + sizeof(u16) + SECTOR_SIZE - 1) / SECTOR_SIZE; + + part->data_sectors_per_block = sectors_per_block - + part->header_sectors_per_block; + + part->header_size = (HEADER_MAP_OFFSET + + part->data_sectors_per_block) * sizeof(u16); + + part->cylinders = (part->data_sectors_per_block * + (part->total_blocks - 1) - 1) / SECTORS_PER_TRACK; + + part->sector_count = part->cylinders * SECTORS_PER_TRACK; + + part->current_block = -1; + part->reserved_block = -1; + part->is_reclaiming = 0; + + part->header_cache = kmalloc(part->header_size, GFP_KERNEL); + if (!part->header_cache) + goto err; + + part->blocks = kcalloc(part->total_blocks, sizeof(struct block), + GFP_KERNEL); + if (!part->blocks) + goto err; + + part->sector_map = vmalloc(part->sector_count * sizeof(u_long)); + if (!part->sector_map) { + printk(KERN_ERR PREFIX "'%s': unable to allocate memory for " + "sector map", part->mbd.mtd->name); + goto err; + } + + for (i=0; isector_count; i++) + part->sector_map[i] = -1; + + for (i=0, blocks_found=0; itotal_blocks; i++) { + rc = part->mbd.mtd->read(part->mbd.mtd, + i * part->block_size, part->header_size, + &retlen, (u_char*)part->header_cache); + + if (!rc && retlen != part->header_size) + rc = -EIO; + + if (rc) + goto err; + + if (!build_block_map(part, i)) + blocks_found++; + } + + if (blocks_found == 0) { + printk(KERN_NOTICE PREFIX "no RFD magic found in '%s'\n", + part->mbd.mtd->name); + rc = -ENOENT; + goto err; + } + + if (part->reserved_block == -1) { + printk(KERN_NOTICE PREFIX "'%s': no empty erase unit found\n", + part->mbd.mtd->name); + + part->errors = 1; + } + + return 0; + +err: + vfree(part->sector_map); + kfree(part->header_cache); + kfree(part->blocks); + + return rc; +} + +static int rfd_ftl_readsect(struct mtd_blktrans_dev *dev, u_long sector, char *buf) +{ + struct partition *part = (struct partition*)dev; + u_long addr; + size_t retlen; + int rc; + + if (sector >= part->sector_count) + return -EIO; + + addr = part->sector_map[sector]; + if (addr != -1) { + rc = part->mbd.mtd->read(part->mbd.mtd, addr, SECTOR_SIZE, + &retlen, (u_char*)buf); + if (!rc && retlen != SECTOR_SIZE) + rc = -EIO; + + if (rc) { + printk(KERN_WARNING PREFIX "error reading '%s' at " + "0x%lx\n", part->mbd.mtd->name, addr); + return rc; + } + } else + memset(buf, 0, SECTOR_SIZE); + + return 0; +} + +static void erase_callback(struct erase_info *erase) +{ + struct partition *part; + u16 magic; + int i, rc; + size_t retlen; + + part = (struct partition*)erase->priv; + + i = erase->addr / part->block_size; + if (i >= part->total_blocks || part->blocks[i].offset != erase->addr) { + printk(KERN_ERR PREFIX "erase callback for unknown offset %x " + "on '%s'\n", erase->addr, part->mbd.mtd->name); + return; + } + + if (erase->state != MTD_ERASE_DONE) { + printk(KERN_WARNING PREFIX "erase failed at 0x%x on '%s', " + "state %d\n", erase->addr, + part->mbd.mtd->name, erase->state); + + part->blocks[i].state = BLOCK_FAILED; + part->blocks[i].free_sectors = 0; + part->blocks[i].used_sectors = 0; + + kfree(erase); + + return; + } + + magic = const_cpu_to_le16(RFD_MAGIC); + + part->blocks[i].state = BLOCK_ERASED; + part->blocks[i].free_sectors = part->data_sectors_per_block; + part->blocks[i].used_sectors = 0; + part->blocks[i].erases++; + + rc = part->mbd.mtd->write(part->mbd.mtd, + part->blocks[i].offset, sizeof(magic), &retlen, + (u_char*)&magic); + + if (!rc && retlen != sizeof(magic)) + rc = -EIO; + + if (rc) { + printk(KERN_NOTICE PREFIX "'%s': unable to write RFD " + "header at 0x%lx\n", + part->mbd.mtd->name, + part->blocks[i].offset); + part->blocks[i].state = BLOCK_FAILED; + } + else + part->blocks[i].state = BLOCK_OK; + + kfree(erase); +} + +static int erase_block(struct partition *part, int block) +{ + struct erase_info *erase; + int rc = -ENOMEM; + + erase = kmalloc(sizeof(struct erase_info), GFP_KERNEL); + if (!erase) + goto err; + + erase->mtd = part->mbd.mtd; + erase->callback = erase_callback; + erase->addr = part->blocks[block].offset; + erase->len = part->block_size; + erase->priv = (u_long)part; + + part->blocks[block].state = BLOCK_ERASING; + part->blocks[block].free_sectors = 0; + + rc = part->mbd.mtd->erase(part->mbd.mtd, erase); + + if (rc) { + printk(KERN_WARNING PREFIX "erase of region %x,%x on '%s' " + "failed\n", erase->addr, erase->len, + part->mbd.mtd->name); + kfree(erase); + } + +err: + return rc; +} + +static int move_block_contents(struct partition *part, int block_no, u_long *old_sector) +{ + void *sector_data; + u16 *map; + size_t retlen; + int i, rc = -ENOMEM; + + part->is_reclaiming = 1; + + sector_data = kmalloc(SECTOR_SIZE, GFP_KERNEL); + if (!sector_data) + goto err3; + + map = kmalloc(part->header_size, GFP_KERNEL); + if (!map) + goto err2; + + rc = part->mbd.mtd->read(part->mbd.mtd, + part->blocks[block_no].offset, part->header_size, + &retlen, (u_char*)map); + + if (!rc && retlen != part->header_size) + rc = -EIO; + + if (rc) { + printk(KERN_NOTICE PREFIX "error reading '%s' at " + "0x%lx\n", part->mbd.mtd->name, + part->blocks[block_no].offset); + + goto err; + } + + for (i=0; idata_sectors_per_block; i++) { + u16 entry = le16_to_cpu(map[HEADER_MAP_OFFSET + i]); + u_long addr; + + + if (entry == SECTOR_FREE || entry == SECTOR_DELETED) + continue; + + if (entry == SECTOR_ZERO) + entry = 0; + + /* already warned about and ignored in build_block_map() */ + if (entry >= part->sector_count) + continue; + + addr = part->blocks[block_no].offset + + (i + part->header_sectors_per_block) * SECTOR_SIZE; + + if (*old_sector == addr) { + *old_sector = -1; + if (!part->blocks[block_no].used_sectors--) { + rc = erase_block(part, block_no); + break; + } + continue; + } + rc = part->mbd.mtd->read(part->mbd.mtd, addr, + SECTOR_SIZE, &retlen, sector_data); + + if (!rc && retlen != SECTOR_SIZE) + rc = -EIO; + + if (rc) { + printk(KERN_NOTICE PREFIX "'%s': Unable to " + "read sector for relocation\n", + part->mbd.mtd->name); + + goto err; + } + + rc = rfd_ftl_writesect((struct mtd_blktrans_dev*)part, + entry, sector_data); + + if (rc) + goto err; + } + +err: + kfree(map); +err2: + kfree(sector_data); +err3: + part->is_reclaiming = 0; + + return rc; +} + +static int reclaim_block(struct partition *part, u_long *old_sector) +{ + int block, best_block, score, old_sector_block; + int rc; + + /* we have a race if sync doesn't exist */ + if (part->mbd.mtd->sync) + part->mbd.mtd->sync(part->mbd.mtd); + + score = 0x7fffffff; /* MAX_INT */ + best_block = -1; + if (*old_sector != -1) + old_sector_block = *old_sector / part->block_size; + else + old_sector_block = -1; + + for (block=0; blocktotal_blocks; block++) { + int this_score; + + if (block == part->reserved_block) + continue; + + /* + * Postpone reclaiming if there is a free sector as + * more removed sectors is more efficient (have to move + * less). + */ + if (part->blocks[block].free_sectors) + return 0; + + this_score = part->blocks[block].used_sectors; + + if (block == old_sector_block) + this_score--; + else { + /* no point in moving a full block */ + if (part->blocks[block].used_sectors == + part->data_sectors_per_block) + continue; + } + + this_score += part->blocks[block].erases; + + if (this_score < score) { + best_block = block; + score = this_score; + } + } + + if (best_block == -1) + return -ENOSPC; + + part->current_block = -1; + part->reserved_block = best_block; + + pr_debug("reclaim_block: reclaiming block #%d with %d used " + "%d free sectors\n", best_block, + part->blocks[best_block].used_sectors, + part->blocks[best_block].free_sectors); + + if (part->blocks[best_block].used_sectors) + rc = move_block_contents(part, best_block, old_sector); + else + rc = erase_block(part, best_block); + + return rc; +} + +/* + * IMPROVE: It would be best to choose the block with the most deleted sectors, + * because if we fill that one up first it'll have the most chance of having + * the least live sectors at reclaim. + */ +static int find_free_block(const struct partition *part) +{ + int block, stop; + + block = part->current_block == -1 ? + jiffies % part->total_blocks : part->current_block; + stop = block; + + do { + if (part->blocks[block].free_sectors && + block != part->reserved_block) + return block; + + if (++block >= part->total_blocks) + block = 0; + + } while (block != stop); + + return -1; +} + +static int find_writeable_block(struct partition *part, u_long *old_sector) +{ + int rc, block; + size_t retlen; + + block = find_free_block(part); + + if (block == -1) { + if (!part->is_reclaiming) { + rc = reclaim_block(part, old_sector); + if (rc) + goto err; + + block = find_free_block(part); + } + + if (block == -1) { + rc = -ENOSPC; + goto err; + } + } + + rc = part->mbd.mtd->read(part->mbd.mtd, part->blocks[block].offset, + part->header_size, &retlen, (u_char*)part->header_cache); + + if (!rc && retlen != part->header_size) + rc = -EIO; + + if (rc) { + printk(KERN_NOTICE PREFIX "'%s': unable to read header at " + "0x%lx\n", part->mbd.mtd->name, + part->blocks[block].offset); + goto err; + } + + part->current_block = block; + +err: + return rc; +} + +static int mark_sector_deleted(struct partition *part, u_long old_addr) +{ + int block, offset, rc; + u_long addr; + size_t retlen; + u16 del = const_cpu_to_le16(SECTOR_DELETED); + + block = old_addr / part->block_size; + offset = (old_addr % part->block_size) / SECTOR_SIZE - + part->header_sectors_per_block; + + addr = part->blocks[block].offset + + (HEADER_MAP_OFFSET + offset) * sizeof(u16); + rc = part->mbd.mtd->write(part->mbd.mtd, addr, + sizeof(del), &retlen, (u_char*)&del); + + if (!rc && retlen != sizeof(del)) + rc = -EIO; + + if (rc) { + printk(KERN_WARNING PREFIX "error writing '%s' at " + "0x%lx\n", part->mbd.mtd->name, addr); + if (rc) + goto err; + } + if (block == part->current_block) + part->header_cache[offset + HEADER_MAP_OFFSET] = del; + + part->blocks[block].used_sectors--; + + if (!part->blocks[block].used_sectors && + !part->blocks[block].free_sectors) + rc = erase_block(part, block); + +err: + return rc; +} + +static int find_free_sector(const struct partition *part, const struct block *block) +{ + int i, stop; + + i = stop = part->data_sectors_per_block - block->free_sectors; + + do { + if (le16_to_cpu(part->header_cache[HEADER_MAP_OFFSET + i]) + == SECTOR_FREE) + return i; + + if (++i == part->data_sectors_per_block) + i = 0; + } + while(i != stop); + + return -1; +} + +static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf, ulong *old_addr) +{ + struct partition *part = (struct partition*)dev; + struct block *block; + u_long addr; + int i; + int rc; + size_t retlen; + u16 entry; + + if (part->current_block == -1 || + !part->blocks[part->current_block].free_sectors) { + + rc = find_writeable_block(part, old_addr); + if (rc) + goto err; + } + + block = &part->blocks[part->current_block]; + + i = find_free_sector(part, block); + + if (i < 0) { + rc = -ENOSPC; + goto err; + } + + addr = (i + part->header_sectors_per_block) * SECTOR_SIZE + + block->offset; + rc = part->mbd.mtd->write(part->mbd.mtd, + addr, SECTOR_SIZE, &retlen, (u_char*)buf); + + if (!rc && retlen != SECTOR_SIZE) + rc = -EIO; + + if (rc) { + printk(KERN_WARNING PREFIX "error writing '%s' at 0x%lx\n", + part->mbd.mtd->name, addr); + if (rc) + goto err; + } + + part->sector_map[sector] = addr; + + entry = cpu_to_le16(sector == 0 ? SECTOR_ZERO : sector); + + part->header_cache[i + HEADER_MAP_OFFSET] = entry; + + addr = block->offset + (HEADER_MAP_OFFSET + i) * sizeof(u16); + rc = part->mbd.mtd->write(part->mbd.mtd, addr, + sizeof(entry), &retlen, (u_char*)&entry); + + if (!rc && retlen != sizeof(entry)) + rc = -EIO; + + if (rc) { + printk(KERN_WARNING PREFIX "error writing '%s' at 0x%lx\n", + part->mbd.mtd->name, addr); + if (rc) + goto err; + } + block->used_sectors++; + block->free_sectors--; + +err: + return rc; +} + +static int rfd_ftl_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf) +{ + struct partition *part = (struct partition*)dev; + u_long old_addr; + int i; + int rc = 0; + + pr_debug("rfd_ftl_writesect(sector=0x%lx)\n", sector); + + if (part->reserved_block == -1) { + rc = -EACCES; + goto err; + } + + if (sector >= part->sector_count) { + rc = -EIO; + goto err; + } + + old_addr = part->sector_map[sector]; + + for (i=0; isector_map[sector] = -1; + + if (old_addr != -1) + rc = mark_sector_deleted(part, old_addr); + +err: + return rc; +} + +static int rfd_ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) +{ + struct partition *part = (struct partition*)dev; + + geo->heads = 1; + geo->sectors = SECTORS_PER_TRACK; + geo->cylinders = part->cylinders; + + return 0; +} + +static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) +{ + struct partition *part; + + if (mtd->type != MTD_NORFLASH) + return; + + part = kcalloc(1, sizeof(struct partition), GFP_KERNEL); + if (!part) + return; + + part->mbd.mtd = mtd; + + if (block_size) + part->block_size = block_size; + else { + if (!mtd->erasesize) { + printk(KERN_NOTICE PREFIX "please provide block_size"); + return; + } + else + part->block_size = mtd->erasesize; + } + + if (scan_header(part) == 0) { + part->mbd.size = part->sector_count; + part->mbd.blksize = SECTOR_SIZE; + part->mbd.tr = tr; + part->mbd.devnum = -1; + if (!(mtd->flags & MTD_WRITEABLE)) + part->mbd.readonly = 1; + else if (part->errors) { + printk(KERN_NOTICE PREFIX "'%s': errors found, " + "setting read-only", mtd->name); + part->mbd.readonly = 1; + } + + printk(KERN_INFO PREFIX "name: '%s' type: %d flags %x\n", + mtd->name, mtd->type, mtd->flags); + + if (!add_mtd_blktrans_dev((void*)part)) + return; + } + + kfree(part); +} + +static void rfd_ftl_remove_dev(struct mtd_blktrans_dev *dev) +{ + struct partition *part = (struct partition*)dev; + int i; + + for (i=0; itotal_blocks; i++) { + pr_debug("rfd_ftl_remove_dev:'%s': erase unit #%02d: %d erases\n", + part->mbd.mtd->name, i, part->blocks[i].erases); + } + + del_mtd_blktrans_dev(dev); + vfree(part->sector_map); + kfree(part->header_cache); + kfree(part->blocks); + kfree(part); +} + +struct mtd_blktrans_ops rfd_ftl_tr = { + .name = "rfd", + .major = RFD_FTL_MAJOR, + .part_bits = PART_BITS, + .readsect = rfd_ftl_readsect, + .writesect = rfd_ftl_writesect, + .getgeo = rfd_ftl_getgeo, + .add_mtd = rfd_ftl_add_mtd, + .remove_dev = rfd_ftl_remove_dev, + .owner = THIS_MODULE, +}; + +static int __init init_rfd_ftl(void) +{ + return register_mtd_blktrans(&rfd_ftl_tr); +} + +static void __exit cleanup_rfd_ftl(void) +{ + deregister_mtd_blktrans(&rfd_ftl_tr); +} + +module_init(init_rfd_ftl); +module_exit(cleanup_rfd_ftl); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sean Young "); +MODULE_DESCRIPTION("Support code for RFD Flash Translation Layer, " + "used by General Software's Embedded BIOS"); + diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 455ba915ede738adc53f533f1b0a672cb07228d9..7488ee7f7cafa1075c6079b0f20081a614eeccb0 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -602,7 +602,7 @@ MODULE_DEVICE_TABLE(pci, vortex_pci_tbl); First the windows. There are eight register windows, with the command and status registers available in each. */ -#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD) +#define EL3WINDOW(win_num) iowrite16(SelectWindow + (win_num), ioaddr + EL3_CMD) #define EL3_CMD 0x0e #define EL3_STATUS 0x0e @@ -776,7 +776,8 @@ struct vortex_private { /* PCI configuration space information. */ struct device *gendev; - char __iomem *cb_fn_base; /* CardBus function status addr space. */ + void __iomem *ioaddr; /* IO address space */ + void __iomem *cb_fn_base; /* CardBus function status addr space. */ /* Some values here only for performance evaluation and path-coverage */ int rx_nocopy, rx_copy, queued_packet, rx_csumhits; @@ -869,12 +870,12 @@ static struct { /* number of ETHTOOL_GSTATS u64's */ #define VORTEX_NUM_STATS 3 -static int vortex_probe1(struct device *gendev, long ioaddr, int irq, +static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq, int chip_idx, int card_idx); static void vortex_up(struct net_device *dev); static void vortex_down(struct net_device *dev, int final); static int vortex_open(struct net_device *dev); -static void mdio_sync(long ioaddr, int bits); +static void mdio_sync(void __iomem *ioaddr, int bits); static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *vp, int phy_id, int location, int value); static void vortex_timer(unsigned long arg); @@ -887,7 +888,7 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) static irqreturn_t boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs); static int vortex_close(struct net_device *dev); static void dump_tx_ring(struct net_device *dev); -static void update_stats(long ioaddr, struct net_device *dev); +static void update_stats(void __iomem *ioaddr, struct net_device *dev); static struct net_device_stats *vortex_get_stats(struct net_device *dev); static void set_rx_mode(struct net_device *dev); #ifdef CONFIG_PCI @@ -902,14 +903,16 @@ static void set_8021q_mode(struct net_device *dev, int enable); /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ /* Option count limit only -- unlimited interfaces are supported. */ #define MAX_UNITS 8 -static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,}; -static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int hw_checksums[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int flow_ctrl[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int enable_wol[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int options[MAX_UNITS] = { [0 ... MAX_UNITS-1] = -1 }; +static int full_duplex[MAX_UNITS] = {[0 ... MAX_UNITS-1] = -1 }; +static int hw_checksums[MAX_UNITS] = {[0 ... MAX_UNITS-1] = -1 }; +static int flow_ctrl[MAX_UNITS] = {[0 ... MAX_UNITS-1] = -1 }; +static int enable_wol[MAX_UNITS] = {[0 ... MAX_UNITS-1] = -1 }; +static int use_mmio[MAX_UNITS] = {[0 ... MAX_UNITS-1] = -1 }; static int global_options = -1; static int global_full_duplex = -1; static int global_enable_wol = -1; +static int global_use_mmio = -1; /* #define dev_alloc_skb dev_alloc_skb_debug */ @@ -934,21 +937,25 @@ module_param(compaq_ioaddr, int, 0); module_param(compaq_irq, int, 0); module_param(compaq_device_id, int, 0); module_param(watchdog, int, 0); +module_param(global_use_mmio, int, 0); +module_param_array(use_mmio, int, NULL, 0); MODULE_PARM_DESC(debug, "3c59x debug level (0-6)"); MODULE_PARM_DESC(options, "3c59x: Bits 0-3: media type, bit 4: bus mastering, bit 9: full duplex"); MODULE_PARM_DESC(global_options, "3c59x: same as options, but applies to all NICs if options is unset"); MODULE_PARM_DESC(full_duplex, "3c59x full duplex setting(s) (1)"); -MODULE_PARM_DESC(global_full_duplex, "3c59x: same as full_duplex, but applies to all NICs if options is unset"); +MODULE_PARM_DESC(global_full_duplex, "3c59x: same as full_duplex, but applies to all NICs if full_duplex is unset"); MODULE_PARM_DESC(hw_checksums, "3c59x Hardware checksum checking by adapter(s) (0-1)"); MODULE_PARM_DESC(flow_ctrl, "3c59x 802.3x flow control usage (PAUSE only) (0-1)"); MODULE_PARM_DESC(enable_wol, "3c59x: Turn on Wake-on-LAN for adapter(s) (0-1)"); -MODULE_PARM_DESC(global_enable_wol, "3c59x: same as enable_wol, but applies to all NICs if options is unset"); +MODULE_PARM_DESC(global_enable_wol, "3c59x: same as enable_wol, but applies to all NICs if enable_wol is unset"); MODULE_PARM_DESC(rx_copybreak, "3c59x copy breakpoint for copy-only-tiny-frames"); MODULE_PARM_DESC(max_interrupt_work, "3c59x maximum events handled per interrupt"); MODULE_PARM_DESC(compaq_ioaddr, "3c59x PCI I/O base address (Compaq BIOS problem workaround)"); MODULE_PARM_DESC(compaq_irq, "3c59x PCI IRQ number (Compaq BIOS problem workaround)"); MODULE_PARM_DESC(compaq_device_id, "3c59x PCI device ID (Compaq BIOS problem workaround)"); MODULE_PARM_DESC(watchdog, "3c59x transmit timeout in milliseconds"); +MODULE_PARM_DESC(global_use_mmio, "3c59x: same as use_mmio, but applies to all NICs if options is unset"); +MODULE_PARM_DESC(use_mmio, "3c59x: use memory-mapped PCI I/O resource (0-1)"); #ifdef CONFIG_NET_POLL_CONTROLLER static void poll_vortex(struct net_device *dev) @@ -1029,18 +1036,19 @@ static struct eisa_driver vortex_eisa_driver = { static int vortex_eisa_probe (struct device *device) { - long ioaddr; + void __iomem *ioaddr; struct eisa_device *edev; edev = to_eisa_device (device); - ioaddr = edev->base_addr; - if (!request_region(ioaddr, VORTEX_TOTAL_SIZE, DRV_NAME)) + if (!request_region(edev->base_addr, VORTEX_TOTAL_SIZE, DRV_NAME)) return -EBUSY; - if (vortex_probe1(device, ioaddr, inw(ioaddr + 0xC88) >> 12, + ioaddr = ioport_map(edev->base_addr, VORTEX_TOTAL_SIZE); + + if (vortex_probe1(device, ioaddr, ioread16(ioaddr + 0xC88) >> 12, edev->id.driver_data, vortex_cards_found)) { - release_region (ioaddr, VORTEX_TOTAL_SIZE); + release_region (edev->base_addr, VORTEX_TOTAL_SIZE); return -ENODEV; } @@ -1054,7 +1062,7 @@ static int vortex_eisa_remove (struct device *device) struct eisa_device *edev; struct net_device *dev; struct vortex_private *vp; - long ioaddr; + void __iomem *ioaddr; edev = to_eisa_device (device); dev = eisa_get_drvdata (edev); @@ -1065,11 +1073,11 @@ static int vortex_eisa_remove (struct device *device) } vp = netdev_priv(dev); - ioaddr = dev->base_addr; + ioaddr = vp->ioaddr; unregister_netdev (dev); - outw (TotalReset|0x14, ioaddr + EL3_CMD); - release_region (ioaddr, VORTEX_TOTAL_SIZE); + iowrite16 (TotalReset|0x14, ioaddr + EL3_CMD); + release_region (dev->base_addr, VORTEX_TOTAL_SIZE); free_netdev (dev); return 0; @@ -1096,8 +1104,8 @@ static int __init vortex_eisa_init (void) /* Special code to work-around the Compaq PCI BIOS32 problem. */ if (compaq_ioaddr) { - vortex_probe1(NULL, compaq_ioaddr, compaq_irq, - compaq_device_id, vortex_cards_found++); + vortex_probe1(NULL, ioport_map(compaq_ioaddr, VORTEX_TOTAL_SIZE), + compaq_irq, compaq_device_id, vortex_cards_found++); } return vortex_cards_found - orig_cards_found + eisa_found; @@ -1107,15 +1115,32 @@ static int __init vortex_eisa_init (void) static int __devinit vortex_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { - int rc; + int rc, unit, pci_bar; + struct vortex_chip_info *vci; + void __iomem *ioaddr; /* wake up and enable device */ rc = pci_enable_device (pdev); if (rc < 0) goto out; - rc = vortex_probe1 (&pdev->dev, pci_resource_start (pdev, 0), - pdev->irq, ent->driver_data, vortex_cards_found); + unit = vortex_cards_found; + + if (global_use_mmio < 0 && (unit >= MAX_UNITS || use_mmio[unit] < 0)) { + /* Determine the default if the user didn't override us */ + vci = &vortex_info_tbl[ent->driver_data]; + pci_bar = vci->drv_flags & (IS_CYCLONE | IS_TORNADO) ? 1 : 0; + } else if (unit < MAX_UNITS && use_mmio[unit] >= 0) + pci_bar = use_mmio[unit] ? 1 : 0; + else + pci_bar = global_use_mmio ? 1 : 0; + + ioaddr = pci_iomap(pdev, pci_bar, 0); + if (!ioaddr) /* If mapping fails, fall-back to BAR 0... */ + ioaddr = pci_iomap(pdev, 0, 0); + + rc = vortex_probe1(&pdev->dev, ioaddr, pdev->irq, + ent->driver_data, unit); if (rc < 0) { pci_disable_device (pdev); goto out; @@ -1134,7 +1159,7 @@ static int __devinit vortex_init_one (struct pci_dev *pdev, * NOTE: pdev can be NULL, for the case of a Compaq device */ static int __devinit vortex_probe1(struct device *gendev, - long ioaddr, int irq, + void __iomem *ioaddr, int irq, int chip_idx, int card_idx) { struct vortex_private *vp; @@ -1202,15 +1227,16 @@ static int __devinit vortex_probe1(struct device *gendev, if (print_info) printk (KERN_INFO "See Documentation/networking/vortex.txt\n"); - printk(KERN_INFO "%s: 3Com %s %s at 0x%lx. Vers " DRV_VERSION "\n", + printk(KERN_INFO "%s: 3Com %s %s at %p. Vers " DRV_VERSION "\n", print_name, pdev ? "PCI" : "EISA", vci->name, ioaddr); - dev->base_addr = ioaddr; + dev->base_addr = (unsigned long)ioaddr; dev->irq = irq; dev->mtu = mtu; + vp->ioaddr = ioaddr; vp->large_frames = mtu > 1500; vp->drv_flags = vci->drv_flags; vp->has_nway = (vci->drv_flags & HAS_NWAY) ? 1 : 0; @@ -1226,7 +1252,7 @@ static int __devinit vortex_probe1(struct device *gendev, if (pdev) { /* EISA resources already marked, so only PCI needs to do this here */ /* Ignore return value, because Cardbus drivers already allocate for us */ - if (request_region(ioaddr, vci->io_size, print_name) != NULL) + if (request_region(dev->base_addr, vci->io_size, print_name) != NULL) vp->must_free_region = 1; /* enable bus-mastering if necessary */ @@ -1316,14 +1342,14 @@ static int __devinit vortex_probe1(struct device *gendev, for (i = 0; i < 0x40; i++) { int timer; - outw(base + i, ioaddr + Wn0EepromCmd); + iowrite16(base + i, ioaddr + Wn0EepromCmd); /* Pause for at least 162 us. for the read to take place. */ for (timer = 10; timer >= 0; timer--) { udelay(162); - if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0) + if ((ioread16(ioaddr + Wn0EepromCmd) & 0x8000) == 0) break; } - eeprom[i] = inw(ioaddr + Wn0EepromData); + eeprom[i] = ioread16(ioaddr + Wn0EepromData); } } for (i = 0; i < 0x18; i++) @@ -1338,6 +1364,7 @@ static int __devinit vortex_probe1(struct device *gendev, printk(" ***INVALID CHECKSUM %4.4x*** ", checksum); for (i = 0; i < 3; i++) ((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]); + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); if (print_info) { for (i = 0; i < 6; i++) printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]); @@ -1351,7 +1378,7 @@ static int __devinit vortex_probe1(struct device *gendev, } EL3WINDOW(2); for (i = 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + i); + iowrite8(dev->dev_addr[i], ioaddr + i); #ifdef __sparc__ if (print_info) @@ -1366,7 +1393,7 @@ static int __devinit vortex_probe1(struct device *gendev, #endif EL3WINDOW(4); - step = (inb(ioaddr + Wn4_NetDiag) & 0x1e) >> 1; + step = (ioread8(ioaddr + Wn4_NetDiag) & 0x1e) >> 1; if (print_info) { printk(KERN_INFO " product code %02x%02x rev %02x.%d date %02d-" "%02d-%02d\n", eeprom[6]&0xff, eeprom[6]>>8, eeprom[0x14], @@ -1375,31 +1402,30 @@ static int __devinit vortex_probe1(struct device *gendev, if (pdev && vci->drv_flags & HAS_CB_FNS) { - unsigned long fn_st_addr; /* Cardbus function status space */ unsigned short n; - fn_st_addr = pci_resource_start (pdev, 2); - if (fn_st_addr) { - vp->cb_fn_base = ioremap(fn_st_addr, 128); + vp->cb_fn_base = pci_iomap(pdev, 2, 0); + if (!vp->cb_fn_base) { retval = -ENOMEM; - if (!vp->cb_fn_base) - goto free_ring; + goto free_ring; } + if (print_info) { printk(KERN_INFO "%s: CardBus functions mapped %8.8lx->%p\n", - print_name, fn_st_addr, vp->cb_fn_base); + print_name, pci_resource_start(pdev, 2), + vp->cb_fn_base); } EL3WINDOW(2); - n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010; + n = ioread16(ioaddr + Wn2_ResetOptions) & ~0x4010; if (vp->drv_flags & INVERT_LED_PWR) n |= 0x10; if (vp->drv_flags & INVERT_MII_PWR) n |= 0x4000; - outw(n, ioaddr + Wn2_ResetOptions); + iowrite16(n, ioaddr + Wn2_ResetOptions); if (vp->drv_flags & WNO_XCVR_PWR) { EL3WINDOW(0); - outw(0x0800, ioaddr); + iowrite16(0x0800, ioaddr); } } @@ -1418,13 +1444,13 @@ static int __devinit vortex_probe1(struct device *gendev, static const char * ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; unsigned int config; EL3WINDOW(3); - vp->available_media = inw(ioaddr + Wn3_Options); + vp->available_media = ioread16(ioaddr + Wn3_Options); if ((vp->available_media & 0xff) == 0) /* Broken 3c916 */ vp->available_media = 0x40; - config = inl(ioaddr + Wn3_Config); + config = ioread32(ioaddr + Wn3_Config); if (print_info) { printk(KERN_DEBUG " Internal config register is %4.4x, " - "transceivers %#x.\n", config, inw(ioaddr + Wn3_Options)); + "transceivers %#x.\n", config, ioread16(ioaddr + Wn3_Options)); printk(KERN_INFO " %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", 8 << RAM_SIZE(config), RAM_WIDTH(config) ? "word" : "byte", @@ -1455,7 +1481,7 @@ static int __devinit vortex_probe1(struct device *gendev, if (vp->drv_flags & EXTRA_PREAMBLE) mii_preamble_required++; mdio_sync(ioaddr, 32); - mdio_read(dev, 24, 1); + mdio_read(dev, 24, MII_BMSR); for (phy = 0; phy < 32 && phy_idx < 1; phy++) { int mii_status, phyx; @@ -1469,7 +1495,7 @@ static int __devinit vortex_probe1(struct device *gendev, phyx = phy - 1; else phyx = phy; - mii_status = mdio_read(dev, phyx, 1); + mii_status = mdio_read(dev, phyx, MII_BMSR); if (mii_status && mii_status != 0xffff) { vp->phys[phy_idx++] = phyx; if (print_info) { @@ -1485,7 +1511,7 @@ static int __devinit vortex_probe1(struct device *gendev, printk(KERN_WARNING" ***WARNING*** No MII transceivers found!\n"); vp->phys[0] = 24; } else { - vp->advertising = mdio_read(dev, vp->phys[0], 4); + vp->advertising = mdio_read(dev, vp->phys[0], MII_ADVERTISE); if (vp->full_duplex) { /* Only advertise the FD media types. */ vp->advertising &= ~0x02A0; @@ -1510,10 +1536,10 @@ static int __devinit vortex_probe1(struct device *gendev, if (vp->full_bus_master_tx) { dev->hard_start_xmit = boomerang_start_xmit; /* Actually, it still should work with iommu. */ - dev->features |= NETIF_F_SG; - if (((hw_checksums[card_idx] == -1) && (vp->drv_flags & HAS_HWCKSM)) || - (hw_checksums[card_idx] == 1)) { - dev->features |= NETIF_F_IP_CSUM; + if (card_idx < MAX_UNITS && + ((hw_checksums[card_idx] == -1 && (vp->drv_flags & HAS_HWCKSM)) || + hw_checksums[card_idx] == 1)) { + dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; } } else { dev->hard_start_xmit = vortex_start_xmit; @@ -1555,7 +1581,7 @@ static int __devinit vortex_probe1(struct device *gendev, vp->rx_ring_dma); free_region: if (vp->must_free_region) - release_region(ioaddr, vci->io_size); + release_region(dev->base_addr, vci->io_size); free_netdev(dev); printk(KERN_ERR PFX "vortex_probe1 fails. Returns %d\n", retval); out: @@ -1565,17 +1591,19 @@ static int __devinit vortex_probe1(struct device *gendev, static void issue_and_wait(struct net_device *dev, int cmd) { + struct vortex_private *vp = netdev_priv(dev); + void __iomem *ioaddr = vp->ioaddr; int i; - outw(cmd, dev->base_addr + EL3_CMD); + iowrite16(cmd, ioaddr + EL3_CMD); for (i = 0; i < 2000; i++) { - if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress)) + if (!(ioread16(ioaddr + EL3_STATUS) & CmdInProgress)) return; } /* OK, that didn't work. Do it the slow way. One second */ for (i = 0; i < 100000; i++) { - if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress)) { + if (!(ioread16(ioaddr + EL3_STATUS) & CmdInProgress)) { if (vortex_debug > 1) printk(KERN_INFO "%s: command 0x%04x took %d usecs\n", dev->name, cmd, i * 10); @@ -1584,14 +1612,14 @@ issue_and_wait(struct net_device *dev, int cmd) udelay(10); } printk(KERN_ERR "%s: command 0x%04x did not complete! Status=0x%x\n", - dev->name, cmd, inw(dev->base_addr + EL3_STATUS)); + dev->name, cmd, ioread16(ioaddr + EL3_STATUS)); } static void vortex_up(struct net_device *dev) { - long ioaddr = dev->base_addr; struct vortex_private *vp = netdev_priv(dev); + void __iomem *ioaddr = vp->ioaddr; unsigned int config; int i; @@ -1604,7 +1632,7 @@ vortex_up(struct net_device *dev) /* Before initializing select the active media port. */ EL3WINDOW(3); - config = inl(ioaddr + Wn3_Config); + config = ioread32(ioaddr + Wn3_Config); if (vp->media_override != 7) { printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n", @@ -1651,14 +1679,14 @@ vortex_up(struct net_device *dev) config = BFINS(config, dev->if_port, 20, 4); if (vortex_debug > 6) printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n", config); - outl(config, ioaddr + Wn3_Config); + iowrite32(config, ioaddr + Wn3_Config); if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { int mii_reg1, mii_reg5; EL3WINDOW(4); /* Read BMSR (reg1) only to clear old status. */ - mii_reg1 = mdio_read(dev, vp->phys[0], 1); - mii_reg5 = mdio_read(dev, vp->phys[0], 5); + mii_reg1 = mdio_read(dev, vp->phys[0], MII_BMSR); + mii_reg5 = mdio_read(dev, vp->phys[0], MII_LPA); if (mii_reg5 == 0xffff || mii_reg5 == 0x0000) { netif_carrier_off(dev); /* No MII device or no link partner report */ } else { @@ -1679,7 +1707,7 @@ vortex_up(struct net_device *dev) } /* Set the full-duplex bit. */ - outw( ((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) | + iowrite16( ((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) | (vp->large_frames ? 0x40 : 0) | ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), ioaddr + Wn3_MAC_Ctrl); @@ -1695,51 +1723,51 @@ vortex_up(struct net_device *dev) */ issue_and_wait(dev, RxReset|0x04); - outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); + iowrite16(SetStatusEnb | 0x00, ioaddr + EL3_CMD); if (vortex_debug > 1) { EL3WINDOW(4); printk(KERN_DEBUG "%s: vortex_up() irq %d media status %4.4x.\n", - dev->name, dev->irq, inw(ioaddr + Wn4_Media)); + dev->name, dev->irq, ioread16(ioaddr + Wn4_Media)); } /* Set the station address and mask in window 2 each time opened. */ EL3WINDOW(2); for (i = 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + i); + iowrite8(dev->dev_addr[i], ioaddr + i); for (; i < 12; i+=2) - outw(0, ioaddr + i); + iowrite16(0, ioaddr + i); if (vp->cb_fn_base) { - unsigned short n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010; + unsigned short n = ioread16(ioaddr + Wn2_ResetOptions) & ~0x4010; if (vp->drv_flags & INVERT_LED_PWR) n |= 0x10; if (vp->drv_flags & INVERT_MII_PWR) n |= 0x4000; - outw(n, ioaddr + Wn2_ResetOptions); + iowrite16(n, ioaddr + Wn2_ResetOptions); } if (dev->if_port == XCVR_10base2) /* Start the thinnet transceiver. We should really wait 50ms...*/ - outw(StartCoax, ioaddr + EL3_CMD); + iowrite16(StartCoax, ioaddr + EL3_CMD); if (dev->if_port != XCVR_NWAY) { EL3WINDOW(4); - outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) | + iowrite16((ioread16(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) | media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); } /* Switch to the stats window, and clear all stats by reading. */ - outw(StatsDisable, ioaddr + EL3_CMD); + iowrite16(StatsDisable, ioaddr + EL3_CMD); EL3WINDOW(6); for (i = 0; i < 10; i++) - inb(ioaddr + i); - inw(ioaddr + 10); - inw(ioaddr + 12); + ioread8(ioaddr + i); + ioread16(ioaddr + 10); + ioread16(ioaddr + 12); /* New: On the Vortex we must also clear the BadSSD counter. */ EL3WINDOW(4); - inb(ioaddr + 12); + ioread8(ioaddr + 12); /* ..and on the Boomerang we enable the extra statistics bits. */ - outw(0x0040, ioaddr + Wn4_NetDiag); + iowrite16(0x0040, ioaddr + Wn4_NetDiag); /* Switch to register set 7 for normal use. */ EL3WINDOW(7); @@ -1747,30 +1775,30 @@ vortex_up(struct net_device *dev) if (vp->full_bus_master_rx) { /* Boomerang bus master. */ vp->cur_rx = vp->dirty_rx = 0; /* Initialize the RxEarly register as recommended. */ - outw(SetRxThreshold + (1536>>2), ioaddr + EL3_CMD); - outl(0x0020, ioaddr + PktStatus); - outl(vp->rx_ring_dma, ioaddr + UpListPtr); + iowrite16(SetRxThreshold + (1536>>2), ioaddr + EL3_CMD); + iowrite32(0x0020, ioaddr + PktStatus); + iowrite32(vp->rx_ring_dma, ioaddr + UpListPtr); } if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */ vp->cur_tx = vp->dirty_tx = 0; if (vp->drv_flags & IS_BOOMERANG) - outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */ + iowrite8(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */ /* Clear the Rx, Tx rings. */ for (i = 0; i < RX_RING_SIZE; i++) /* AKPM: this is done in vortex_open, too */ vp->rx_ring[i].status = 0; for (i = 0; i < TX_RING_SIZE; i++) vp->tx_skbuff[i] = NULL; - outl(0, ioaddr + DownListPtr); + iowrite32(0, ioaddr + DownListPtr); } /* Set receiver mode: presumably accept b-case and phys addr only. */ set_rx_mode(dev); /* enable 802.1q tagged frames */ set_8021q_mode(dev, 1); - outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ + iowrite16(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ // issue_and_wait(dev, SetTxStart|0x07ff); - outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ - outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ + iowrite16(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ + iowrite16(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ /* Allow status bits to be seen. */ vp->status_enable = SetStatusEnb | HostError|IntReq|StatsFull|TxComplete| (vp->full_bus_master_tx ? DownComplete : TxAvailable) | @@ -1780,13 +1808,13 @@ vortex_up(struct net_device *dev) (vp->full_bus_master_rx ? 0 : RxComplete) | StatsFull | HostError | TxComplete | IntReq | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete; - outw(vp->status_enable, ioaddr + EL3_CMD); + iowrite16(vp->status_enable, ioaddr + EL3_CMD); /* Ack all pending events, and set active indicator mask. */ - outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, + iowrite16(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, ioaddr + EL3_CMD); - outw(vp->intr_enable, ioaddr + EL3_CMD); + iowrite16(vp->intr_enable, ioaddr + EL3_CMD); if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ - writel(0x8000, vp->cb_fn_base + 4); + iowrite32(0x8000, vp->cb_fn_base + 4); netif_start_queue (dev); } @@ -1852,7 +1880,7 @@ vortex_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct vortex_private *vp = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem *ioaddr = vp->ioaddr; int next_tick = 60*HZ; int ok = 0; int media_status, mii_status, old_window; @@ -1866,9 +1894,9 @@ vortex_timer(unsigned long data) if (vp->medialock) goto leave_media_alone; disable_irq(dev->irq); - old_window = inw(ioaddr + EL3_CMD) >> 13; + old_window = ioread16(ioaddr + EL3_CMD) >> 13; EL3WINDOW(4); - media_status = inw(ioaddr + Wn4_Media); + media_status = ioread16(ioaddr + Wn4_Media); switch (dev->if_port) { case XCVR_10baseT: case XCVR_100baseTx: case XCVR_100baseFx: if (media_status & Media_LnkBeat) { @@ -1888,14 +1916,17 @@ vortex_timer(unsigned long data) case XCVR_MII: case XCVR_NWAY: { spin_lock_bh(&vp->lock); - mii_status = mdio_read(dev, vp->phys[0], 1); - mii_status = mdio_read(dev, vp->phys[0], 1); + mii_status = mdio_read(dev, vp->phys[0], MII_BMSR); + if (!(mii_status & BMSR_LSTATUS)) { + /* Re-read to get actual link status */ + mii_status = mdio_read(dev, vp->phys[0], MII_BMSR); + } ok = 1; if (vortex_debug > 2) printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n", dev->name, mii_status); if (mii_status & BMSR_LSTATUS) { - int mii_reg5 = mdio_read(dev, vp->phys[0], 5); + int mii_reg5 = mdio_read(dev, vp->phys[0], MII_LPA); if (! vp->force_fd && mii_reg5 != 0xffff) { int duplex; @@ -1909,7 +1940,7 @@ vortex_timer(unsigned long data) vp->phys[0], mii_reg5); /* Set the full-duplex bit. */ EL3WINDOW(3); - outw( (vp->full_duplex ? 0x20 : 0) | + iowrite16( (vp->full_duplex ? 0x20 : 0) | (vp->large_frames ? 0x40 : 0) | ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), ioaddr + Wn3_MAC_Ctrl); @@ -1950,15 +1981,15 @@ vortex_timer(unsigned long data) dev->name, media_tbl[dev->if_port].name); next_tick = media_tbl[dev->if_port].wait; } - outw((media_status & ~(Media_10TP|Media_SQE)) | + iowrite16((media_status & ~(Media_10TP|Media_SQE)) | media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); EL3WINDOW(3); - config = inl(ioaddr + Wn3_Config); + config = ioread32(ioaddr + Wn3_Config); config = BFINS(config, dev->if_port, 20, 4); - outl(config, ioaddr + Wn3_Config); + iowrite32(config, ioaddr + Wn3_Config); - outw(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax, + iowrite16(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax, ioaddr + EL3_CMD); if (vortex_debug > 1) printk(KERN_DEBUG "wrote 0x%08x to Wn3_Config\n", config); @@ -1974,29 +2005,29 @@ vortex_timer(unsigned long data) mod_timer(&vp->timer, RUN_AT(next_tick)); if (vp->deferred) - outw(FakeIntr, ioaddr + EL3_CMD); + iowrite16(FakeIntr, ioaddr + EL3_CMD); return; } static void vortex_tx_timeout(struct net_device *dev) { struct vortex_private *vp = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem *ioaddr = vp->ioaddr; printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n", - dev->name, inb(ioaddr + TxStatus), - inw(ioaddr + EL3_STATUS)); + dev->name, ioread8(ioaddr + TxStatus), + ioread16(ioaddr + EL3_STATUS)); EL3WINDOW(4); printk(KERN_ERR " diagnostics: net %04x media %04x dma %08x fifo %04x\n", - inw(ioaddr + Wn4_NetDiag), - inw(ioaddr + Wn4_Media), - inl(ioaddr + PktStatus), - inw(ioaddr + Wn4_FIFODiag)); + ioread16(ioaddr + Wn4_NetDiag), + ioread16(ioaddr + Wn4_Media), + ioread32(ioaddr + PktStatus), + ioread16(ioaddr + Wn4_FIFODiag)); /* Slight code bloat to be user friendly. */ - if ((inb(ioaddr + TxStatus) & 0x88) == 0x88) + if ((ioread8(ioaddr + TxStatus) & 0x88) == 0x88) printk(KERN_ERR "%s: Transmitter encountered 16 collisions --" " network cable problem?\n", dev->name); - if (inw(ioaddr + EL3_STATUS) & IntLatch) { + if (ioread16(ioaddr + EL3_STATUS) & IntLatch) { printk(KERN_ERR "%s: Interrupt posted but not delivered --" " IRQ blocked by another device?\n", dev->name); /* Bad idea here.. but we might as well handle a few events. */ @@ -2022,21 +2053,21 @@ static void vortex_tx_timeout(struct net_device *dev) vp->stats.tx_errors++; if (vp->full_bus_master_tx) { printk(KERN_DEBUG "%s: Resetting the Tx ring pointer.\n", dev->name); - if (vp->cur_tx - vp->dirty_tx > 0 && inl(ioaddr + DownListPtr) == 0) - outl(vp->tx_ring_dma + (vp->dirty_tx % TX_RING_SIZE) * sizeof(struct boom_tx_desc), + if (vp->cur_tx - vp->dirty_tx > 0 && ioread32(ioaddr + DownListPtr) == 0) + iowrite32(vp->tx_ring_dma + (vp->dirty_tx % TX_RING_SIZE) * sizeof(struct boom_tx_desc), ioaddr + DownListPtr); if (vp->cur_tx - vp->dirty_tx < TX_RING_SIZE) netif_wake_queue (dev); if (vp->drv_flags & IS_BOOMERANG) - outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); - outw(DownUnstall, ioaddr + EL3_CMD); + iowrite8(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); + iowrite16(DownUnstall, ioaddr + EL3_CMD); } else { vp->stats.tx_dropped++; netif_wake_queue(dev); } /* Issue Tx Enable */ - outw(TxEnable, ioaddr + EL3_CMD); + iowrite16(TxEnable, ioaddr + EL3_CMD); dev->trans_start = jiffies; /* Switch to register set 7 for normal use. */ @@ -2051,7 +2082,7 @@ static void vortex_error(struct net_device *dev, int status) { struct vortex_private *vp = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem *ioaddr = vp->ioaddr; int do_tx_reset = 0, reset_mask = 0; unsigned char tx_status = 0; @@ -2060,7 +2091,7 @@ vortex_error(struct net_device *dev, int status) } if (status & TxComplete) { /* Really "TxError" for us. */ - tx_status = inb(ioaddr + TxStatus); + tx_status = ioread8(ioaddr + TxStatus); /* Presumably a tx-timeout. We must merely re-enable. */ if (vortex_debug > 2 || (tx_status != 0x88 && vortex_debug > 0)) { @@ -2074,20 +2105,20 @@ vortex_error(struct net_device *dev, int status) } if (tx_status & 0x14) vp->stats.tx_fifo_errors++; if (tx_status & 0x38) vp->stats.tx_aborted_errors++; - outb(0, ioaddr + TxStatus); + iowrite8(0, ioaddr + TxStatus); if (tx_status & 0x30) { /* txJabber or txUnderrun */ do_tx_reset = 1; } else if ((tx_status & 0x08) && (vp->drv_flags & MAX_COLLISION_RESET)) { /* maxCollisions */ do_tx_reset = 1; reset_mask = 0x0108; /* Reset interface logic, but not download logic */ } else { /* Merely re-enable the transmitter. */ - outw(TxEnable, ioaddr + EL3_CMD); + iowrite16(TxEnable, ioaddr + EL3_CMD); } } if (status & RxEarly) { /* Rx early is unused. */ vortex_rx(dev); - outw(AckIntr | RxEarly, ioaddr + EL3_CMD); + iowrite16(AckIntr | RxEarly, ioaddr + EL3_CMD); } if (status & StatsFull) { /* Empty statistics. */ static int DoneDidThat; @@ -2097,29 +2128,29 @@ vortex_error(struct net_device *dev, int status) /* HACK: Disable statistics as an interrupt source. */ /* This occurs when we have the wrong media type! */ if (DoneDidThat == 0 && - inw(ioaddr + EL3_STATUS) & StatsFull) { + ioread16(ioaddr + EL3_STATUS) & StatsFull) { printk(KERN_WARNING "%s: Updating statistics failed, disabling " "stats as an interrupt source.\n", dev->name); EL3WINDOW(5); - outw(SetIntrEnb | (inw(ioaddr + 10) & ~StatsFull), ioaddr + EL3_CMD); + iowrite16(SetIntrEnb | (ioread16(ioaddr + 10) & ~StatsFull), ioaddr + EL3_CMD); vp->intr_enable &= ~StatsFull; EL3WINDOW(7); DoneDidThat++; } } if (status & IntReq) { /* Restore all interrupt sources. */ - outw(vp->status_enable, ioaddr + EL3_CMD); - outw(vp->intr_enable, ioaddr + EL3_CMD); + iowrite16(vp->status_enable, ioaddr + EL3_CMD); + iowrite16(vp->intr_enable, ioaddr + EL3_CMD); } if (status & HostError) { u16 fifo_diag; EL3WINDOW(4); - fifo_diag = inw(ioaddr + Wn4_FIFODiag); + fifo_diag = ioread16(ioaddr + Wn4_FIFODiag); printk(KERN_ERR "%s: Host error, FIFO diagnostic register %4.4x.\n", dev->name, fifo_diag); /* Adapter failure requires Tx/Rx reset and reinit. */ if (vp->full_bus_master_tx) { - int bus_status = inl(ioaddr + PktStatus); + int bus_status = ioread32(ioaddr + PktStatus); /* 0x80000000 PCI master abort. */ /* 0x40000000 PCI target abort. */ if (vortex_debug) @@ -2139,14 +2170,14 @@ vortex_error(struct net_device *dev, int status) set_rx_mode(dev); /* enable 802.1q VLAN tagged frames */ set_8021q_mode(dev, 1); - outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */ - outw(AckIntr | HostError, ioaddr + EL3_CMD); + iowrite16(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */ + iowrite16(AckIntr | HostError, ioaddr + EL3_CMD); } } if (do_tx_reset) { issue_and_wait(dev, TxReset|reset_mask); - outw(TxEnable, ioaddr + EL3_CMD); + iowrite16(TxEnable, ioaddr + EL3_CMD); if (!vp->full_bus_master_tx) netif_wake_queue(dev); } @@ -2156,29 +2187,29 @@ static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct vortex_private *vp = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem *ioaddr = vp->ioaddr; /* Put out the doubleword header... */ - outl(skb->len, ioaddr + TX_FIFO); + iowrite32(skb->len, ioaddr + TX_FIFO); if (vp->bus_master) { /* Set the bus-master controller to transfer the packet. */ int len = (skb->len + 3) & ~3; - outl( vp->tx_skb_dma = pci_map_single(VORTEX_PCI(vp), skb->data, len, PCI_DMA_TODEVICE), + iowrite32( vp->tx_skb_dma = pci_map_single(VORTEX_PCI(vp), skb->data, len, PCI_DMA_TODEVICE), ioaddr + Wn7_MasterAddr); - outw(len, ioaddr + Wn7_MasterLen); + iowrite16(len, ioaddr + Wn7_MasterLen); vp->tx_skb = skb; - outw(StartDMADown, ioaddr + EL3_CMD); + iowrite16(StartDMADown, ioaddr + EL3_CMD); /* netif_wake_queue() will be called at the DMADone interrupt. */ } else { /* ... and the packet rounded to a doubleword. */ - outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); + iowrite32_rep(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); dev_kfree_skb (skb); - if (inw(ioaddr + TxFree) > 1536) { + if (ioread16(ioaddr + TxFree) > 1536) { netif_start_queue (dev); /* AKPM: redundant? */ } else { /* Interrupt us when the FIFO has room for max-sized packet. */ netif_stop_queue(dev); - outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); + iowrite16(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); } } @@ -2189,7 +2220,7 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) int tx_status; int i = 32; - while (--i > 0 && (tx_status = inb(ioaddr + TxStatus)) > 0) { + while (--i > 0 && (tx_status = ioread8(ioaddr + TxStatus)) > 0) { if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */ if (vortex_debug > 2) printk(KERN_DEBUG "%s: Tx error, status %2.2x.\n", @@ -2199,9 +2230,9 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) if (tx_status & 0x30) { issue_and_wait(dev, TxReset); } - outw(TxEnable, ioaddr + EL3_CMD); + iowrite16(TxEnable, ioaddr + EL3_CMD); } - outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */ + iowrite8(0x00, ioaddr + TxStatus); /* Pop the status stack. */ } } return 0; @@ -2211,7 +2242,7 @@ static int boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct vortex_private *vp = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem *ioaddr = vp->ioaddr; /* Calculate the next Tx descriptor entry. */ int entry = vp->cur_tx % TX_RING_SIZE; struct boom_tx_desc *prev_entry = &vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE]; @@ -2275,8 +2306,8 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Wait for the stall to complete. */ issue_and_wait(dev, DownStall); prev_entry->next = cpu_to_le32(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc)); - if (inl(ioaddr + DownListPtr) == 0) { - outl(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc), ioaddr + DownListPtr); + if (ioread32(ioaddr + DownListPtr) == 0) { + iowrite32(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc), ioaddr + DownListPtr); vp->queued_packet++; } @@ -2291,7 +2322,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) prev_entry->status &= cpu_to_le32(~TxIntrUploaded); #endif } - outw(DownUnstall, ioaddr + EL3_CMD); + iowrite16(DownUnstall, ioaddr + EL3_CMD); spin_unlock_irqrestore(&vp->lock, flags); dev->trans_start = jiffies; return 0; @@ -2310,15 +2341,15 @@ vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; struct vortex_private *vp = netdev_priv(dev); - long ioaddr; + void __iomem *ioaddr; int status; int work_done = max_interrupt_work; int handled = 0; - ioaddr = dev->base_addr; + ioaddr = vp->ioaddr; spin_lock(&vp->lock); - status = inw(ioaddr + EL3_STATUS); + status = ioread16(ioaddr + EL3_STATUS); if (vortex_debug > 6) printk("vortex_interrupt(). status=0x%4x\n", status); @@ -2337,7 +2368,7 @@ vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (vortex_debug > 4) printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n", - dev->name, status, inb(ioaddr + Timer)); + dev->name, status, ioread8(ioaddr + Timer)); do { if (vortex_debug > 5) @@ -2350,16 +2381,16 @@ vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (vortex_debug > 5) printk(KERN_DEBUG " TX room bit was handled.\n"); /* There's room in the FIFO for a full-sized packet. */ - outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); + iowrite16(AckIntr | TxAvailable, ioaddr + EL3_CMD); netif_wake_queue (dev); } if (status & DMADone) { - if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) { - outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ + if (ioread16(ioaddr + Wn7_MasterStatus) & 0x1000) { + iowrite16(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ pci_unmap_single(VORTEX_PCI(vp), vp->tx_skb_dma, (vp->tx_skb->len + 3) & ~3, PCI_DMA_TODEVICE); dev_kfree_skb_irq(vp->tx_skb); /* Release the transferred buffer */ - if (inw(ioaddr + TxFree) > 1536) { + if (ioread16(ioaddr + TxFree) > 1536) { /* * AKPM: FIXME: I don't think we need this. If the queue was stopped due to * insufficient FIFO room, the TxAvailable test will succeed and call @@ -2367,7 +2398,7 @@ vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) */ netif_wake_queue(dev); } else { /* Interrupt when FIFO has room for max-sized packet. */ - outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); + iowrite16(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); netif_stop_queue(dev); } } @@ -2385,17 +2416,17 @@ vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* Disable all pending interrupts. */ do { vp->deferred |= status; - outw(SetStatusEnb | (~vp->deferred & vp->status_enable), + iowrite16(SetStatusEnb | (~vp->deferred & vp->status_enable), ioaddr + EL3_CMD); - outw(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD); - } while ((status = inw(ioaddr + EL3_CMD)) & IntLatch); + iowrite16(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD); + } while ((status = ioread16(ioaddr + EL3_CMD)) & IntLatch); /* The timer will reenable interrupts. */ mod_timer(&vp->timer, jiffies + 1*HZ); break; } /* Acknowledge the IRQ. */ - outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); - } while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete)); + iowrite16(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); + } while ((status = ioread16(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete)); if (vortex_debug > 4) printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n", @@ -2415,11 +2446,11 @@ boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; struct vortex_private *vp = netdev_priv(dev); - long ioaddr; + void __iomem *ioaddr; int status; int work_done = max_interrupt_work; - ioaddr = dev->base_addr; + ioaddr = vp->ioaddr; /* * It seems dopey to put the spinlock this early, but we could race against vortex_tx_timeout @@ -2427,7 +2458,7 @@ boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs) */ spin_lock(&vp->lock); - status = inw(ioaddr + EL3_STATUS); + status = ioread16(ioaddr + EL3_STATUS); if (vortex_debug > 6) printk(KERN_DEBUG "boomerang_interrupt. status=0x%4x\n", status); @@ -2448,13 +2479,13 @@ boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (vortex_debug > 4) printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n", - dev->name, status, inb(ioaddr + Timer)); + dev->name, status, ioread8(ioaddr + Timer)); do { if (vortex_debug > 5) printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n", dev->name, status); if (status & UpComplete) { - outw(AckIntr | UpComplete, ioaddr + EL3_CMD); + iowrite16(AckIntr | UpComplete, ioaddr + EL3_CMD); if (vortex_debug > 5) printk(KERN_DEBUG "boomerang_interrupt->boomerang_rx\n"); boomerang_rx(dev); @@ -2463,11 +2494,11 @@ boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (status & DownComplete) { unsigned int dirty_tx = vp->dirty_tx; - outw(AckIntr | DownComplete, ioaddr + EL3_CMD); + iowrite16(AckIntr | DownComplete, ioaddr + EL3_CMD); while (vp->cur_tx - dirty_tx > 0) { int entry = dirty_tx % TX_RING_SIZE; #if 1 /* AKPM: the latter is faster, but cyclone-only */ - if (inl(ioaddr + DownListPtr) == + if (ioread32(ioaddr + DownListPtr) == vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc)) break; /* It still hasn't been processed. */ #else @@ -2514,20 +2545,20 @@ boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* Disable all pending interrupts. */ do { vp->deferred |= status; - outw(SetStatusEnb | (~vp->deferred & vp->status_enable), + iowrite16(SetStatusEnb | (~vp->deferred & vp->status_enable), ioaddr + EL3_CMD); - outw(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD); - } while ((status = inw(ioaddr + EL3_CMD)) & IntLatch); + iowrite16(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD); + } while ((status = ioread16(ioaddr + EL3_CMD)) & IntLatch); /* The timer will reenable interrupts. */ mod_timer(&vp->timer, jiffies + 1*HZ); break; } /* Acknowledge the IRQ. */ - outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); + iowrite16(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ - writel(0x8000, vp->cb_fn_base + 4); + iowrite32(0x8000, vp->cb_fn_base + 4); - } while ((status = inw(ioaddr + EL3_STATUS)) & IntLatch); + } while ((status = ioread16(ioaddr + EL3_STATUS)) & IntLatch); if (vortex_debug > 4) printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n", @@ -2540,16 +2571,16 @@ boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs) static int vortex_rx(struct net_device *dev) { struct vortex_private *vp = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem *ioaddr = vp->ioaddr; int i; short rx_status; if (vortex_debug > 5) printk(KERN_DEBUG "vortex_rx(): status %4.4x, rx_status %4.4x.\n", - inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus)); - while ((rx_status = inw(ioaddr + RxStatus)) > 0) { + ioread16(ioaddr+EL3_STATUS), ioread16(ioaddr+RxStatus)); + while ((rx_status = ioread16(ioaddr + RxStatus)) > 0) { if (rx_status & 0x4000) { /* Error, update stats. */ - unsigned char rx_error = inb(ioaddr + RxErrors); + unsigned char rx_error = ioread8(ioaddr + RxErrors); if (vortex_debug > 2) printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error); vp->stats.rx_errors++; @@ -2572,34 +2603,35 @@ static int vortex_rx(struct net_device *dev) skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ if (vp->bus_master && - ! (inw(ioaddr + Wn7_MasterStatus) & 0x8000)) { + ! (ioread16(ioaddr + Wn7_MasterStatus) & 0x8000)) { dma_addr_t dma = pci_map_single(VORTEX_PCI(vp), skb_put(skb, pkt_len), pkt_len, PCI_DMA_FROMDEVICE); - outl(dma, ioaddr + Wn7_MasterAddr); - outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen); - outw(StartDMAUp, ioaddr + EL3_CMD); - while (inw(ioaddr + Wn7_MasterStatus) & 0x8000) + iowrite32(dma, ioaddr + Wn7_MasterAddr); + iowrite16((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen); + iowrite16(StartDMAUp, ioaddr + EL3_CMD); + while (ioread16(ioaddr + Wn7_MasterStatus) & 0x8000) ; pci_unmap_single(VORTEX_PCI(vp), dma, pkt_len, PCI_DMA_FROMDEVICE); } else { - insl(ioaddr + RX_FIFO, skb_put(skb, pkt_len), - (pkt_len + 3) >> 2); + ioread32_rep(ioaddr + RX_FIFO, + skb_put(skb, pkt_len), + (pkt_len + 3) >> 2); } - outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ + iowrite16(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; vp->stats.rx_packets++; /* Wait a limited time to go to next packet. */ for (i = 200; i >= 0; i--) - if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + if ( ! (ioread16(ioaddr + EL3_STATUS) & CmdInProgress)) break; continue; } else if (vortex_debug > 0) printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of " "size %d.\n", dev->name, pkt_len); + vp->stats.rx_dropped++; } - vp->stats.rx_dropped++; issue_and_wait(dev, RxDiscard); } @@ -2611,12 +2643,12 @@ boomerang_rx(struct net_device *dev) { struct vortex_private *vp = netdev_priv(dev); int entry = vp->cur_rx % RX_RING_SIZE; - long ioaddr = dev->base_addr; + void __iomem *ioaddr = vp->ioaddr; int rx_status; int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx; if (vortex_debug > 5) - printk(KERN_DEBUG "boomerang_rx(): status %4.4x\n", inw(ioaddr+EL3_STATUS)); + printk(KERN_DEBUG "boomerang_rx(): status %4.4x\n", ioread16(ioaddr+EL3_STATUS)); while ((rx_status = le32_to_cpu(vp->rx_ring[entry].status)) & RxDComplete){ if (--rx_work_limit < 0) @@ -2699,7 +2731,7 @@ boomerang_rx(struct net_device *dev) vp->rx_skbuff[entry] = skb; } vp->rx_ring[entry].status = 0; /* Clear complete bit. */ - outw(UpUnstall, ioaddr + EL3_CMD); + iowrite16(UpUnstall, ioaddr + EL3_CMD); } return 0; } @@ -2728,7 +2760,7 @@ static void vortex_down(struct net_device *dev, int final_down) { struct vortex_private *vp = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem *ioaddr = vp->ioaddr; netif_stop_queue (dev); @@ -2736,26 +2768,26 @@ vortex_down(struct net_device *dev, int final_down) del_timer_sync(&vp->timer); /* Turn off statistics ASAP. We update vp->stats below. */ - outw(StatsDisable, ioaddr + EL3_CMD); + iowrite16(StatsDisable, ioaddr + EL3_CMD); /* Disable the receiver and transmitter. */ - outw(RxDisable, ioaddr + EL3_CMD); - outw(TxDisable, ioaddr + EL3_CMD); + iowrite16(RxDisable, ioaddr + EL3_CMD); + iowrite16(TxDisable, ioaddr + EL3_CMD); /* Disable receiving 802.1q tagged frames */ set_8021q_mode(dev, 0); if (dev->if_port == XCVR_10base2) /* Turn off thinnet power. Green! */ - outw(StopCoax, ioaddr + EL3_CMD); + iowrite16(StopCoax, ioaddr + EL3_CMD); - outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD); + iowrite16(SetIntrEnb | 0x0000, ioaddr + EL3_CMD); update_stats(ioaddr, dev); if (vp->full_bus_master_rx) - outl(0, ioaddr + UpListPtr); + iowrite32(0, ioaddr + UpListPtr); if (vp->full_bus_master_tx) - outl(0, ioaddr + DownListPtr); + iowrite32(0, ioaddr + DownListPtr); if (final_down && VORTEX_PCI(vp)) { vp->pm_state_valid = 1; @@ -2768,7 +2800,7 @@ static int vortex_close(struct net_device *dev) { struct vortex_private *vp = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem *ioaddr = vp->ioaddr; int i; if (netif_device_present(dev)) @@ -2776,17 +2808,18 @@ vortex_close(struct net_device *dev) if (vortex_debug > 1) { printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n", - dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus)); + dev->name, ioread16(ioaddr + EL3_STATUS), ioread8(ioaddr + TxStatus)); printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d" " tx_queued %d Rx pre-checksummed %d.\n", dev->name, vp->rx_nocopy, vp->rx_copy, vp->queued_packet, vp->rx_csumhits); } #if DO_ZEROCOPY - if ( vp->rx_csumhits && - ((vp->drv_flags & HAS_HWCKSM) == 0) && - (hw_checksums[vp->card_idx] == -1)) { - printk(KERN_WARNING "%s supports hardware checksums, and we're not using them!\n", dev->name); + if (vp->rx_csumhits && + (vp->drv_flags & HAS_HWCKSM) == 0 && + (vp->card_idx >= MAX_UNITS || hw_checksums[vp->card_idx] == -1)) { + printk(KERN_WARNING "%s supports hardware checksums, and we're " + "not using them!\n", dev->name); } #endif @@ -2830,18 +2863,18 @@ dump_tx_ring(struct net_device *dev) { if (vortex_debug > 0) { struct vortex_private *vp = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem *ioaddr = vp->ioaddr; if (vp->full_bus_master_tx) { int i; - int stalled = inl(ioaddr + PktStatus) & 0x04; /* Possible racy. But it's only debug stuff */ + int stalled = ioread32(ioaddr + PktStatus) & 0x04; /* Possible racy. But it's only debug stuff */ printk(KERN_ERR " Flags; bus-master %d, dirty %d(%d) current %d(%d)\n", vp->full_bus_master_tx, vp->dirty_tx, vp->dirty_tx % TX_RING_SIZE, vp->cur_tx, vp->cur_tx % TX_RING_SIZE); printk(KERN_ERR " Transmit list %8.8x vs. %p.\n", - inl(ioaddr + DownListPtr), + ioread32(ioaddr + DownListPtr), &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]); issue_and_wait(dev, DownStall); for (i = 0; i < TX_RING_SIZE; i++) { @@ -2855,7 +2888,7 @@ dump_tx_ring(struct net_device *dev) le32_to_cpu(vp->tx_ring[i].status)); } if (!stalled) - outw(DownUnstall, ioaddr + EL3_CMD); + iowrite16(DownUnstall, ioaddr + EL3_CMD); } } } @@ -2863,11 +2896,12 @@ dump_tx_ring(struct net_device *dev) static struct net_device_stats *vortex_get_stats(struct net_device *dev) { struct vortex_private *vp = netdev_priv(dev); + void __iomem *ioaddr = vp->ioaddr; unsigned long flags; if (netif_device_present(dev)) { /* AKPM: Used to be netif_running */ spin_lock_irqsave (&vp->lock, flags); - update_stats(dev->base_addr, dev); + update_stats(ioaddr, dev); spin_unlock_irqrestore (&vp->lock, flags); } return &vp->stats; @@ -2880,37 +2914,37 @@ static struct net_device_stats *vortex_get_stats(struct net_device *dev) table. This is done by checking that the ASM (!) code generated uses atomic updates with '+='. */ -static void update_stats(long ioaddr, struct net_device *dev) +static void update_stats(void __iomem *ioaddr, struct net_device *dev) { struct vortex_private *vp = netdev_priv(dev); - int old_window = inw(ioaddr + EL3_CMD); + int old_window = ioread16(ioaddr + EL3_CMD); if (old_window == 0xffff) /* Chip suspended or ejected. */ return; /* Unlike the 3c5x9 we need not turn off stats updates while reading. */ /* Switch to the stats window, and read everything. */ EL3WINDOW(6); - vp->stats.tx_carrier_errors += inb(ioaddr + 0); - vp->stats.tx_heartbeat_errors += inb(ioaddr + 1); - vp->stats.collisions += inb(ioaddr + 3); - vp->stats.tx_window_errors += inb(ioaddr + 4); - vp->stats.rx_fifo_errors += inb(ioaddr + 5); - vp->stats.tx_packets += inb(ioaddr + 6); - vp->stats.tx_packets += (inb(ioaddr + 9)&0x30) << 4; - /* Rx packets */ inb(ioaddr + 7); /* Must read to clear */ + vp->stats.tx_carrier_errors += ioread8(ioaddr + 0); + vp->stats.tx_heartbeat_errors += ioread8(ioaddr + 1); + vp->stats.collisions += ioread8(ioaddr + 3); + vp->stats.tx_window_errors += ioread8(ioaddr + 4); + vp->stats.rx_fifo_errors += ioread8(ioaddr + 5); + vp->stats.tx_packets += ioread8(ioaddr + 6); + vp->stats.tx_packets += (ioread8(ioaddr + 9)&0x30) << 4; + /* Rx packets */ ioread8(ioaddr + 7); /* Must read to clear */ /* Don't bother with register 9, an extension of registers 6&7. If we do use the 6&7 values the atomic update assumption above is invalid. */ - vp->stats.rx_bytes += inw(ioaddr + 10); - vp->stats.tx_bytes += inw(ioaddr + 12); + vp->stats.rx_bytes += ioread16(ioaddr + 10); + vp->stats.tx_bytes += ioread16(ioaddr + 12); /* Extra stats for get_ethtool_stats() */ - vp->xstats.tx_multiple_collisions += inb(ioaddr + 2); - vp->xstats.tx_deferred += inb(ioaddr + 8); + vp->xstats.tx_multiple_collisions += ioread8(ioaddr + 2); + vp->xstats.tx_deferred += ioread8(ioaddr + 8); EL3WINDOW(4); - vp->xstats.rx_bad_ssd += inb(ioaddr + 12); + vp->xstats.rx_bad_ssd += ioread8(ioaddr + 12); { - u8 up = inb(ioaddr + 13); + u8 up = ioread8(ioaddr + 13); vp->stats.rx_bytes += (up & 0x0f) << 16; vp->stats.tx_bytes += (up & 0xf0) << 12; } @@ -2922,7 +2956,7 @@ static void update_stats(long ioaddr, struct net_device *dev) static int vortex_nway_reset(struct net_device *dev) { struct vortex_private *vp = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem *ioaddr = vp->ioaddr; unsigned long flags; int rc; @@ -2936,7 +2970,7 @@ static int vortex_nway_reset(struct net_device *dev) static u32 vortex_get_link(struct net_device *dev) { struct vortex_private *vp = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem *ioaddr = vp->ioaddr; unsigned long flags; int rc; @@ -2950,7 +2984,7 @@ static u32 vortex_get_link(struct net_device *dev) static int vortex_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct vortex_private *vp = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem *ioaddr = vp->ioaddr; unsigned long flags; int rc; @@ -2964,7 +2998,7 @@ static int vortex_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int vortex_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct vortex_private *vp = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem *ioaddr = vp->ioaddr; unsigned long flags; int rc; @@ -2994,10 +3028,11 @@ static void vortex_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) { struct vortex_private *vp = netdev_priv(dev); + void __iomem *ioaddr = vp->ioaddr; unsigned long flags; spin_lock_irqsave(&vp->lock, flags); - update_stats(dev->base_addr, dev); + update_stats(ioaddr, dev); spin_unlock_irqrestore(&vp->lock, flags); data[0] = vp->xstats.tx_deferred; @@ -3047,6 +3082,7 @@ static struct ethtool_ops vortex_ethtool_ops = { .set_settings = vortex_set_settings, .get_link = vortex_get_link, .nway_reset = vortex_nway_reset, + .get_perm_addr = ethtool_op_get_perm_addr, }; #ifdef CONFIG_PCI @@ -3057,7 +3093,7 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { int err; struct vortex_private *vp = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem *ioaddr = vp->ioaddr; unsigned long flags; int state = 0; @@ -3085,7 +3121,8 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) the chip has a very clean way to set the mode, unlike many others. */ static void set_rx_mode(struct net_device *dev) { - long ioaddr = dev->base_addr; + struct vortex_private *vp = netdev_priv(dev); + void __iomem *ioaddr = vp->ioaddr; int new_mode; if (dev->flags & IFF_PROMISC) { @@ -3097,7 +3134,7 @@ static void set_rx_mode(struct net_device *dev) } else new_mode = SetRxFilter | RxStation | RxBroadcast; - outw(new_mode, ioaddr + EL3_CMD); + iowrite16(new_mode, ioaddr + EL3_CMD); } #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) @@ -3111,8 +3148,8 @@ static void set_rx_mode(struct net_device *dev) static void set_8021q_mode(struct net_device *dev, int enable) { struct vortex_private *vp = netdev_priv(dev); - long ioaddr = dev->base_addr; - int old_window = inw(ioaddr + EL3_CMD); + void __iomem *ioaddr = vp->ioaddr; + int old_window = ioread16(ioaddr + EL3_CMD); int mac_ctrl; if ((vp->drv_flags&IS_CYCLONE) || (vp->drv_flags&IS_TORNADO)) { @@ -3124,24 +3161,24 @@ static void set_8021q_mode(struct net_device *dev, int enable) max_pkt_size += 4; /* 802.1Q VLAN tag */ EL3WINDOW(3); - outw(max_pkt_size, ioaddr+Wn3_MaxPktSize); + iowrite16(max_pkt_size, ioaddr+Wn3_MaxPktSize); /* set VlanEtherType to let the hardware checksumming treat tagged frames correctly */ EL3WINDOW(7); - outw(VLAN_ETHER_TYPE, ioaddr+Wn7_VlanEtherType); + iowrite16(VLAN_ETHER_TYPE, ioaddr+Wn7_VlanEtherType); } else { /* on older cards we have to enable large frames */ vp->large_frames = dev->mtu > 1500 || enable; EL3WINDOW(3); - mac_ctrl = inw(ioaddr+Wn3_MAC_Ctrl); + mac_ctrl = ioread16(ioaddr+Wn3_MAC_Ctrl); if (vp->large_frames) mac_ctrl |= 0x40; else mac_ctrl &= ~0x40; - outw(mac_ctrl, ioaddr+Wn3_MAC_Ctrl); + iowrite16(mac_ctrl, ioaddr+Wn3_MAC_Ctrl); } EL3WINDOW(old_window); @@ -3163,7 +3200,7 @@ static void set_8021q_mode(struct net_device *dev, int enable) /* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually met by back-to-back PCI I/O cycles, but we insert a delay to avoid "overclocking" issues. */ -#define mdio_delay() inl(mdio_addr) +#define mdio_delay() ioread32(mdio_addr) #define MDIO_SHIFT_CLK 0x01 #define MDIO_DIR_WRITE 0x04 @@ -3174,15 +3211,15 @@ static void set_8021q_mode(struct net_device *dev, int enable) /* Generate the preamble required for initial synchronization and a few older transceivers. */ -static void mdio_sync(long ioaddr, int bits) +static void mdio_sync(void __iomem *ioaddr, int bits) { - long mdio_addr = ioaddr + Wn4_PhysicalMgmt; + void __iomem *mdio_addr = ioaddr + Wn4_PhysicalMgmt; /* Establish sync by sending at least 32 logic ones. */ while (-- bits >= 0) { - outw(MDIO_DATA_WRITE1, mdio_addr); + iowrite16(MDIO_DATA_WRITE1, mdio_addr); mdio_delay(); - outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); + iowrite16(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } } @@ -3190,10 +3227,11 @@ static void mdio_sync(long ioaddr, int bits) static int mdio_read(struct net_device *dev, int phy_id, int location) { int i; - long ioaddr = dev->base_addr; + struct vortex_private *vp = netdev_priv(dev); + void __iomem *ioaddr = vp->ioaddr; int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; unsigned int retval = 0; - long mdio_addr = ioaddr + Wn4_PhysicalMgmt; + void __iomem *mdio_addr = ioaddr + Wn4_PhysicalMgmt; if (mii_preamble_required) mdio_sync(ioaddr, 32); @@ -3201,17 +3239,17 @@ static int mdio_read(struct net_device *dev, int phy_id, int location) /* Shift the read command bits out. */ for (i = 14; i >= 0; i--) { int dataval = (read_cmd&(1< 0; i--) { - outw(MDIO_ENB_IN, mdio_addr); + iowrite16(MDIO_ENB_IN, mdio_addr); mdio_delay(); - retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); - outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + retval = (retval << 1) | ((ioread16(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); + iowrite16(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff; @@ -3219,9 +3257,10 @@ static int mdio_read(struct net_device *dev, int phy_id, int location) static void mdio_write(struct net_device *dev, int phy_id, int location, int value) { - long ioaddr = dev->base_addr; + struct vortex_private *vp = netdev_priv(dev); + void __iomem *ioaddr = vp->ioaddr; int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value; - long mdio_addr = ioaddr + Wn4_PhysicalMgmt; + void __iomem *mdio_addr = ioaddr + Wn4_PhysicalMgmt; int i; if (mii_preamble_required) @@ -3230,16 +3269,16 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val /* Shift the command bits out. */ for (i = 31; i >= 0; i--) { int dataval = (write_cmd&(1<= 0; i--) { - outw(MDIO_ENB_IN, mdio_addr); + iowrite16(MDIO_ENB_IN, mdio_addr); mdio_delay(); - outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + iowrite16(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } return; @@ -3250,15 +3289,15 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val static void acpi_set_WOL(struct net_device *dev) { struct vortex_private *vp = netdev_priv(dev); - long ioaddr = dev->base_addr; + void __iomem *ioaddr = vp->ioaddr; if (vp->enable_wol) { /* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */ EL3WINDOW(7); - outw(2, ioaddr + 0x0c); + iowrite16(2, ioaddr + 0x0c); /* The RxFilter must accept the WOL frames. */ - outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD); - outw(RxEnable, ioaddr + EL3_CMD); + iowrite16(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD); + iowrite16(RxEnable, ioaddr + EL3_CMD); pci_enable_wake(VORTEX_PCI(vp), 0, 1); @@ -3280,10 +3319,9 @@ static void __devexit vortex_remove_one (struct pci_dev *pdev) vp = netdev_priv(dev); - /* AKPM: FIXME: we should have - * if (vp->cb_fn_base) iounmap(vp->cb_fn_base); - * here - */ + if (vp->cb_fn_base) + pci_iounmap(VORTEX_PCI(vp), vp->cb_fn_base); + unregister_netdev(dev); if (VORTEX_PCI(vp)) { @@ -3293,8 +3331,10 @@ static void __devexit vortex_remove_one (struct pci_dev *pdev) pci_disable_device(VORTEX_PCI(vp)); } /* Should really use issue_and_wait() here */ - outw(TotalReset | ((vp->drv_flags & EEPROM_RESET) ? 0x04 : 0x14), - dev->base_addr + EL3_CMD); + iowrite16(TotalReset | ((vp->drv_flags & EEPROM_RESET) ? 0x04 : 0x14), + vp->ioaddr + EL3_CMD); + + pci_iounmap(VORTEX_PCI(vp), vp->ioaddr); pci_free_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE @@ -3342,7 +3382,7 @@ static int __init vortex_init (void) static void __exit vortex_eisa_cleanup (void) { struct vortex_private *vp; - long ioaddr; + void __iomem *ioaddr; #ifdef CONFIG_EISA /* Take care of the EISA devices */ @@ -3351,11 +3391,13 @@ static void __exit vortex_eisa_cleanup (void) if (compaq_net_device) { vp = compaq_net_device->priv; - ioaddr = compaq_net_device->base_addr; + ioaddr = ioport_map(compaq_net_device->base_addr, + VORTEX_TOTAL_SIZE); unregister_netdev (compaq_net_device); - outw (TotalReset, ioaddr + EL3_CMD); - release_region (ioaddr, VORTEX_TOTAL_SIZE); + iowrite16 (TotalReset, ioaddr + EL3_CMD); + release_region(compaq_net_device->base_addr, + VORTEX_TOTAL_SIZE); free_netdev (compaq_net_device); } diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 1958d9e16a3aaaa606541ee56173b5811a286c5c..24f1691b84f90d37b684acb665efc66a12f40d8f 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2523,6 +2523,19 @@ config PPP_BSDCOMP module; it is called bsd_comp and will show up in the directory modules once you have said "make modules". If unsure, say N. +config PPP_MPPE + tristate "PPP MPPE compression (encryption) (EXPERIMENTAL)" + depends on PPP && EXPERIMENTAL + select CRYPTO + select CRYPTO_SHA1 + select CRYPTO_ARC4 + ---help--- + Support for the MPPE Encryption protocol, as employed by the + Microsoft Point-to-Point Tunneling Protocol. + + See http://pptpclient.sourceforge.net/ for information on + configuring PPTP clients and servers to utilize this method. + config PPPOE tristate "PPP over Ethernet (EXPERIMENTAL)" depends on EXPERIMENTAL && PPP diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 7c313cb341b8874866b9f279141f70d6ed8d8d6a..4cffd34442aafaddc00865df86c26f410ccd61a2 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -112,6 +112,7 @@ obj-$(CONFIG_PPP_ASYNC) += ppp_async.o obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o +obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o obj-$(CONFIG_PPPOE) += pppox.o pppoe.o obj-$(CONFIG_SLIP) += slip.o diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 11d25231822112b08fc478e64fea577b983a12e7..8f464271664dd0644878aeddaa5b52a19ad55abe 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -14,8 +14,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.2.21" -#define DRV_MODULE_RELDATE "September 7, 2005" +#define DRV_MODULE_VERSION "1.4.30" +#define DRV_MODULE_RELDATE "October 11, 2005" #define RUN_AT(x) (jiffies + (x)) @@ -26,7 +26,7 @@ static char version[] __devinitdata = "Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; MODULE_AUTHOR("Michael Chan "); -MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706 Driver"); +MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708 Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_MODULE_VERSION); @@ -41,6 +41,8 @@ typedef enum { NC370I, BCM5706S, NC370F, + BCM5708, + BCM5708S, } board_t; /* indexed by board_t, above */ @@ -52,6 +54,8 @@ static struct { { "HP NC370i Multifunction Gigabit Server Adapter" }, { "Broadcom NetXtreme II BCM5706 1000Base-SX" }, { "HP NC370F Multifunction Gigabit Server Adapter" }, + { "Broadcom NetXtreme II BCM5708 1000Base-T" }, + { "Broadcom NetXtreme II BCM5708 1000Base-SX" }, }; static struct pci_device_id bnx2_pci_tbl[] = { @@ -61,48 +65,102 @@ static struct pci_device_id bnx2_pci_tbl[] = { PCI_VENDOR_ID_HP, 0x3106, 0, 0, NC370I }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706 }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708 }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S, PCI_VENDOR_ID_HP, 0x3102, 0, 0, NC370F }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706S }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708S, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708S }, { 0, } }; static struct flash_spec flash_table[] = { /* Slow EEPROM */ - {0x00000000, 0x40030380, 0x009f0081, 0xa184a053, 0xaf000400, + {0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400, 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE, SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE, "EEPROM - slow"}, - /* Fast EEPROM */ - {0x02000000, 0x62008380, 0x009f0081, 0xa184a053, 0xaf000400, - 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE, - SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE, - "EEPROM - fast"}, - /* ATMEL AT45DB011B (buffered flash) */ - {0x02000003, 0x6e008173, 0x00570081, 0x68848353, 0xaf000400, - 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE, - BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE, - "Buffered flash"}, - /* Saifun SA25F005 (non-buffered flash) */ - /* strap, cfg1, & write1 need updates */ - {0x01000003, 0x5f008081, 0x00050081, 0x03840253, 0xaf020406, + /* Expansion entry 0001 */ + {0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406, 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, - SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE, - "Non-buffered flash (64kB)"}, + SAIFUN_FLASH_BYTE_ADDR_MASK, 0, + "Entry 0001"}, /* Saifun SA25F010 (non-buffered flash) */ /* strap, cfg1, & write1 need updates */ - {0x00000001, 0x47008081, 0x00050081, 0x03840253, 0xaf020406, + {0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406, 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2, "Non-buffered flash (128kB)"}, /* Saifun SA25F020 (non-buffered flash) */ /* strap, cfg1, & write1 need updates */ - {0x00000003, 0x4f008081, 0x00050081, 0x03840253, 0xaf020406, + {0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406, 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4, "Non-buffered flash (256kB)"}, + /* Expansion entry 0100 */ + {0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406, + 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + SAIFUN_FLASH_BYTE_ADDR_MASK, 0, + "Entry 0100"}, + /* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */ + {0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406, + 0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE, + ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2, + "Entry 0101: ST M45PE10 (128kB non-bufferred)"}, + /* Entry 0110: ST M45PE20 (non-buffered flash)*/ + {0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406, + 0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE, + ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4, + "Entry 0110: ST M45PE20 (256kB non-bufferred)"}, + /* Saifun SA25F005 (non-buffered flash) */ + /* strap, cfg1, & write1 need updates */ + {0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406, + 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE, + "Non-buffered flash (64kB)"}, + /* Fast EEPROM */ + {0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400, + 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE, + SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE, + "EEPROM - fast"}, + /* Expansion entry 1001 */ + {0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406, + 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + SAIFUN_FLASH_BYTE_ADDR_MASK, 0, + "Entry 1001"}, + /* Expansion entry 1010 */ + {0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406, + 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + SAIFUN_FLASH_BYTE_ADDR_MASK, 0, + "Entry 1010"}, + /* ATMEL AT45DB011B (buffered flash) */ + {0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400, + 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE, + BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE, + "Buffered flash (128kB)"}, + /* Expansion entry 1100 */ + {0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406, + 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + SAIFUN_FLASH_BYTE_ADDR_MASK, 0, + "Entry 1100"}, + /* Expansion entry 1101 */ + {0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406, + 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, + SAIFUN_FLASH_BYTE_ADDR_MASK, 0, + "Entry 1101"}, + /* Ateml Expansion entry 1110 */ + {0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400, + 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE, + BUFFERED_FLASH_BYTE_ADDR_MASK, 0, + "Entry 1110 (Atmel)"}, + /* ATMEL AT45DB021B (buffered flash) */ + {0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400, + 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE, + BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2, + "Buffered flash (256kB)"}, }; MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl); @@ -378,6 +436,62 @@ bnx2_alloc_mem(struct bnx2 *bp) return -ENOMEM; } +static void +bnx2_report_fw_link(struct bnx2 *bp) +{ + u32 fw_link_status = 0; + + if (bp->link_up) { + u32 bmsr; + + switch (bp->line_speed) { + case SPEED_10: + if (bp->duplex == DUPLEX_HALF) + fw_link_status = BNX2_LINK_STATUS_10HALF; + else + fw_link_status = BNX2_LINK_STATUS_10FULL; + break; + case SPEED_100: + if (bp->duplex == DUPLEX_HALF) + fw_link_status = BNX2_LINK_STATUS_100HALF; + else + fw_link_status = BNX2_LINK_STATUS_100FULL; + break; + case SPEED_1000: + if (bp->duplex == DUPLEX_HALF) + fw_link_status = BNX2_LINK_STATUS_1000HALF; + else + fw_link_status = BNX2_LINK_STATUS_1000FULL; + break; + case SPEED_2500: + if (bp->duplex == DUPLEX_HALF) + fw_link_status = BNX2_LINK_STATUS_2500HALF; + else + fw_link_status = BNX2_LINK_STATUS_2500FULL; + break; + } + + fw_link_status |= BNX2_LINK_STATUS_LINK_UP; + + if (bp->autoneg) { + fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED; + + bnx2_read_phy(bp, MII_BMSR, &bmsr); + bnx2_read_phy(bp, MII_BMSR, &bmsr); + + if (!(bmsr & BMSR_ANEGCOMPLETE) || + bp->phy_flags & PHY_PARALLEL_DETECT_FLAG) + fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET; + else + fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE; + } + } + else + fw_link_status = BNX2_LINK_STATUS_LINK_DOWN; + + REG_WR_IND(bp, bp->shmem_base + BNX2_LINK_STATUS, fw_link_status); +} + static void bnx2_report_link(struct bnx2 *bp) { @@ -409,6 +523,8 @@ bnx2_report_link(struct bnx2 *bp) netif_carrier_off(bp->dev); printk(KERN_ERR PFX "%s NIC Link is Down\n", bp->dev->name); } + + bnx2_report_fw_link(bp); } static void @@ -430,6 +546,18 @@ bnx2_resolve_flow_ctrl(struct bnx2 *bp) return; } + if ((bp->phy_flags & PHY_SERDES_FLAG) && + (CHIP_NUM(bp) == CHIP_NUM_5708)) { + u32 val; + + bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val); + if (val & BCM5708S_1000X_STAT1_TX_PAUSE) + bp->flow_ctrl |= FLOW_CTRL_TX; + if (val & BCM5708S_1000X_STAT1_RX_PAUSE) + bp->flow_ctrl |= FLOW_CTRL_RX; + return; + } + bnx2_read_phy(bp, MII_ADVERTISE, &local_adv); bnx2_read_phy(bp, MII_LPA, &remote_adv); @@ -476,7 +604,36 @@ bnx2_resolve_flow_ctrl(struct bnx2 *bp) } static int -bnx2_serdes_linkup(struct bnx2 *bp) +bnx2_5708s_linkup(struct bnx2 *bp) +{ + u32 val; + + bp->link_up = 1; + bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val); + switch (val & BCM5708S_1000X_STAT1_SPEED_MASK) { + case BCM5708S_1000X_STAT1_SPEED_10: + bp->line_speed = SPEED_10; + break; + case BCM5708S_1000X_STAT1_SPEED_100: + bp->line_speed = SPEED_100; + break; + case BCM5708S_1000X_STAT1_SPEED_1G: + bp->line_speed = SPEED_1000; + break; + case BCM5708S_1000X_STAT1_SPEED_2G5: + bp->line_speed = SPEED_2500; + break; + } + if (val & BCM5708S_1000X_STAT1_FD) + bp->duplex = DUPLEX_FULL; + else + bp->duplex = DUPLEX_HALF; + + return 0; +} + +static int +bnx2_5706s_linkup(struct bnx2 *bp) { u32 bmcr, local_adv, remote_adv, common; @@ -593,13 +750,27 @@ bnx2_set_mac_link(struct bnx2 *bp) val = REG_RD(bp, BNX2_EMAC_MODE); val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX | - BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK); + BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK | + BNX2_EMAC_MODE_25G); if (bp->link_up) { - if (bp->line_speed != SPEED_1000) - val |= BNX2_EMAC_MODE_PORT_MII; - else - val |= BNX2_EMAC_MODE_PORT_GMII; + switch (bp->line_speed) { + case SPEED_10: + if (CHIP_NUM(bp) == CHIP_NUM_5708) { + val |= BNX2_EMAC_MODE_PORT_MII_10; + break; + } + /* fall through */ + case SPEED_100: + val |= BNX2_EMAC_MODE_PORT_MII; + break; + case SPEED_2500: + val |= BNX2_EMAC_MODE_25G; + /* fall through */ + case SPEED_1000: + val |= BNX2_EMAC_MODE_PORT_GMII; + break; + } } else { val |= BNX2_EMAC_MODE_PORT_GMII; @@ -662,7 +833,10 @@ bnx2_set_link(struct bnx2 *bp) bp->link_up = 1; if (bp->phy_flags & PHY_SERDES_FLAG) { - bnx2_serdes_linkup(bp); + if (CHIP_NUM(bp) == CHIP_NUM_5706) + bnx2_5706s_linkup(bp); + else if (CHIP_NUM(bp) == CHIP_NUM_5708) + bnx2_5708s_linkup(bp); } else { bnx2_copper_linkup(bp); @@ -755,39 +929,61 @@ bnx2_phy_get_pause_adv(struct bnx2 *bp) static int bnx2_setup_serdes_phy(struct bnx2 *bp) { - u32 adv, bmcr; + u32 adv, bmcr, up1; u32 new_adv = 0; if (!(bp->autoneg & AUTONEG_SPEED)) { u32 new_bmcr; + int force_link_down = 0; + + if (CHIP_NUM(bp) == CHIP_NUM_5708) { + bnx2_read_phy(bp, BCM5708S_UP1, &up1); + if (up1 & BCM5708S_UP1_2G5) { + up1 &= ~BCM5708S_UP1_2G5; + bnx2_write_phy(bp, BCM5708S_UP1, up1); + force_link_down = 1; + } + } + + bnx2_read_phy(bp, MII_ADVERTISE, &adv); + adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF); bnx2_read_phy(bp, MII_BMCR, &bmcr); new_bmcr = bmcr & ~BMCR_ANENABLE; new_bmcr |= BMCR_SPEED1000; if (bp->req_duplex == DUPLEX_FULL) { + adv |= ADVERTISE_1000XFULL; new_bmcr |= BMCR_FULLDPLX; } else { + adv |= ADVERTISE_1000XHALF; new_bmcr &= ~BMCR_FULLDPLX; } - if (new_bmcr != bmcr) { + if ((new_bmcr != bmcr) || (force_link_down)) { /* Force a link down visible on the other side */ if (bp->link_up) { - bnx2_read_phy(bp, MII_ADVERTISE, &adv); - adv &= ~(ADVERTISE_1000XFULL | - ADVERTISE_1000XHALF); - bnx2_write_phy(bp, MII_ADVERTISE, adv); + bnx2_write_phy(bp, MII_ADVERTISE, adv & + ~(ADVERTISE_1000XFULL | + ADVERTISE_1000XHALF)); bnx2_write_phy(bp, MII_BMCR, bmcr | BMCR_ANRESTART | BMCR_ANENABLE); bp->link_up = 0; netif_carrier_off(bp->dev); + bnx2_write_phy(bp, MII_BMCR, new_bmcr); } + bnx2_write_phy(bp, MII_ADVERTISE, adv); bnx2_write_phy(bp, MII_BMCR, new_bmcr); } return 0; } + if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) { + bnx2_read_phy(bp, BCM5708S_UP1, &up1); + up1 |= BCM5708S_UP1_2G5; + bnx2_write_phy(bp, BCM5708S_UP1, up1); + } + if (bp->advertising & ADVERTISED_1000baseT_Full) new_adv |= ADVERTISE_1000XFULL; @@ -952,7 +1148,60 @@ bnx2_setup_phy(struct bnx2 *bp) } static int -bnx2_init_serdes_phy(struct bnx2 *bp) +bnx2_init_5708s_phy(struct bnx2 *bp) +{ + u32 val; + + bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3); + bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE); + bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG); + + bnx2_read_phy(bp, BCM5708S_1000X_CTL1, &val); + val |= BCM5708S_1000X_CTL1_FIBER_MODE | BCM5708S_1000X_CTL1_AUTODET_EN; + bnx2_write_phy(bp, BCM5708S_1000X_CTL1, val); + + bnx2_read_phy(bp, BCM5708S_1000X_CTL2, &val); + val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN; + bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val); + + if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) { + bnx2_read_phy(bp, BCM5708S_UP1, &val); + val |= BCM5708S_UP1_2G5; + bnx2_write_phy(bp, BCM5708S_UP1, val); + } + + if ((CHIP_ID(bp) == CHIP_ID_5708_A0) || + (CHIP_ID(bp) == CHIP_ID_5708_B0)) { + /* increase tx signal amplitude */ + bnx2_write_phy(bp, BCM5708S_BLK_ADDR, + BCM5708S_BLK_ADDR_TX_MISC); + bnx2_read_phy(bp, BCM5708S_TX_ACTL1, &val); + val &= ~BCM5708S_TX_ACTL1_DRIVER_VCM; + bnx2_write_phy(bp, BCM5708S_TX_ACTL1, val); + bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG); + } + + val = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG) & + BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK; + + if (val) { + u32 is_backplane; + + is_backplane = REG_RD_IND(bp, bp->shmem_base + + BNX2_SHARED_HW_CFG_CONFIG); + if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) { + bnx2_write_phy(bp, BCM5708S_BLK_ADDR, + BCM5708S_BLK_ADDR_TX_MISC); + bnx2_write_phy(bp, BCM5708S_TX_ACTL3, val); + bnx2_write_phy(bp, BCM5708S_BLK_ADDR, + BCM5708S_BLK_ADDR_DIG); + } + } + return 0; +} + +static int +bnx2_init_5706s_phy(struct bnx2 *bp) { bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG; @@ -990,6 +1239,8 @@ bnx2_init_serdes_phy(struct bnx2 *bp) static int bnx2_init_copper_phy(struct bnx2 *bp) { + u32 val; + bp->phy_flags |= PHY_CRC_FIX_FLAG; if (bp->phy_flags & PHY_CRC_FIX_FLAG) { @@ -1004,8 +1255,6 @@ bnx2_init_copper_phy(struct bnx2 *bp) } if (bp->dev->mtu > 1500) { - u32 val; - /* Set extended packet length bit */ bnx2_write_phy(bp, 0x18, 0x7); bnx2_read_phy(bp, 0x18, &val); @@ -1015,8 +1264,6 @@ bnx2_init_copper_phy(struct bnx2 *bp) bnx2_write_phy(bp, 0x10, val | 0x1); } else { - u32 val; - bnx2_write_phy(bp, 0x18, 0x7); bnx2_read_phy(bp, 0x18, &val); bnx2_write_phy(bp, 0x18, val & ~0x4007); @@ -1025,6 +1272,10 @@ bnx2_init_copper_phy(struct bnx2 *bp) bnx2_write_phy(bp, 0x10, val & ~0x1); } + /* ethernet@wirespeed */ + bnx2_write_phy(bp, 0x18, 0x7007); + bnx2_read_phy(bp, 0x18, &val); + bnx2_write_phy(bp, 0x18, val | (1 << 15) | (1 << 4)); return 0; } @@ -1048,7 +1299,10 @@ bnx2_init_phy(struct bnx2 *bp) bp->phy_id |= val & 0xffff; if (bp->phy_flags & PHY_SERDES_FLAG) { - rc = bnx2_init_serdes_phy(bp); + if (CHIP_NUM(bp) == CHIP_NUM_5706) + rc = bnx2_init_5706s_phy(bp); + else if (CHIP_NUM(bp) == CHIP_NUM_5708) + rc = bnx2_init_5708s_phy(bp); } else { rc = bnx2_init_copper_phy(bp); @@ -1084,13 +1338,13 @@ bnx2_fw_sync(struct bnx2 *bp, u32 msg_data) bp->fw_wr_seq++; msg_data |= bp->fw_wr_seq; - REG_WR_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_DRV_MB, msg_data); + REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB, msg_data); /* wait for an acknowledgement. */ for (i = 0; i < (FW_ACK_TIME_OUT_MS * 1000)/5; i++) { udelay(5); - val = REG_RD_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_FW_MB); + val = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_MB); if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ)) break; @@ -1103,7 +1357,7 @@ bnx2_fw_sync(struct bnx2 *bp, u32 msg_data) msg_data &= ~BNX2_DRV_MSG_CODE; msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT; - REG_WR_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_DRV_MB, msg_data); + REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB, msg_data); bp->fw_timed_out = 1; @@ -1279,10 +1533,11 @@ bnx2_phy_int(struct bnx2 *bp) static void bnx2_tx_int(struct bnx2 *bp) { + struct status_block *sblk = bp->status_blk; u16 hw_cons, sw_cons, sw_ring_cons; int tx_free_bd = 0; - hw_cons = bp->status_blk->status_tx_quick_consumer_index0; + hw_cons = bp->hw_tx_cons = sblk->status_tx_quick_consumer_index0; if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) { hw_cons++; } @@ -1337,7 +1592,9 @@ bnx2_tx_int(struct bnx2 *bp) dev_kfree_skb_irq(skb); - hw_cons = bp->status_blk->status_tx_quick_consumer_index0; + hw_cons = bp->hw_tx_cons = + sblk->status_tx_quick_consumer_index0; + if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) { hw_cons++; } @@ -1382,11 +1639,12 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb, static int bnx2_rx_int(struct bnx2 *bp, int budget) { + struct status_block *sblk = bp->status_blk; u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod; struct l2_fhdr *rx_hdr; int rx_pkt = 0; - hw_cons = bp->status_blk->status_rx_quick_consumer_index0; + hw_cons = bp->hw_rx_cons = sblk->status_rx_quick_consumer_index0; if ((hw_cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT) { hw_cons++; } @@ -1506,6 +1764,15 @@ bnx2_rx_int(struct bnx2 *bp, int budget) if ((rx_pkt == budget)) break; + + /* Refresh hw_cons to see if there is new work */ + if (sw_cons == hw_cons) { + hw_cons = bp->hw_rx_cons = + sblk->status_rx_quick_consumer_index0; + if ((hw_cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT) + hw_cons++; + rmb(); + } } bp->rx_cons = sw_cons; bp->rx_prod = sw_prod; @@ -1573,15 +1840,27 @@ bnx2_interrupt(int irq, void *dev_instance, struct pt_regs *regs) return IRQ_HANDLED; } +static inline int +bnx2_has_work(struct bnx2 *bp) +{ + struct status_block *sblk = bp->status_blk; + + if ((sblk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) || + (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)) + return 1; + + if (((sblk->status_attn_bits & STATUS_ATTN_BITS_LINK_STATE) != 0) != + bp->link_up) + return 1; + + return 0; +} + static int bnx2_poll(struct net_device *dev, int *budget) { struct bnx2 *bp = dev->priv; - int rx_done = 1; - bp->last_status_idx = bp->status_blk->status_idx; - - rmb(); if ((bp->status_blk->status_attn_bits & STATUS_ATTN_BITS_LINK_STATE) != (bp->status_blk->status_attn_bits_ack & @@ -1592,11 +1871,10 @@ bnx2_poll(struct net_device *dev, int *budget) spin_unlock(&bp->phy_lock); } - if (bp->status_blk->status_tx_quick_consumer_index0 != bp->tx_cons) { + if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons) bnx2_tx_int(bp); - } - if (bp->status_blk->status_rx_quick_consumer_index0 != bp->rx_cons) { + if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) { int orig_budget = *budget; int work_done; @@ -1606,13 +1884,12 @@ bnx2_poll(struct net_device *dev, int *budget) work_done = bnx2_rx_int(bp, orig_budget); *budget -= work_done; dev->quota -= work_done; - - if (work_done >= orig_budget) { - rx_done = 0; - } } - if (rx_done) { + bp->last_status_idx = bp->status_blk->status_idx; + rmb(); + + if (!bnx2_has_work(bp)) { netif_rx_complete(dev); REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | @@ -2383,21 +2660,27 @@ bnx2_init_nvram(struct bnx2 *bp) /* Flash interface has been reconfigured */ for (j = 0, flash = &flash_table[0]; j < entry_count; - j++, flash++) { - - if (val == flash->config1) { + j++, flash++) { + if ((val & FLASH_BACKUP_STRAP_MASK) == + (flash->config1 & FLASH_BACKUP_STRAP_MASK)) { bp->flash_info = flash; break; } } } else { + u32 mask; /* Not yet been reconfigured */ + if (val & (1 << 23)) + mask = FLASH_BACKUP_STRAP_MASK; + else + mask = FLASH_STRAP_MASK; + for (j = 0, flash = &flash_table[0]; j < entry_count; j++, flash++) { - if ((val & FLASH_STRAP_MASK) == flash->strapping) { + if ((val & mask) == (flash->strapping & mask)) { bp->flash_info = flash; /* Request access to the flash interface. */ @@ -2733,7 +3016,7 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code) /* Deposit a driver reset signature so the firmware knows that * this is a soft reset. */ - REG_WR_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_DRV_RESET_SIGNATURE, + REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_RESET_SIGNATURE, BNX2_DRV_RESET_SIGNATURE_MAGIC); bp->fw_timed_out = 0; @@ -2962,6 +3245,7 @@ bnx2_init_tx_ring(struct bnx2 *bp) bp->tx_prod = 0; bp->tx_cons = 0; + bp->hw_tx_cons = 0; bp->tx_prod_bseq = 0; val = BNX2_L2CTX_TYPE_TYPE_L2; @@ -2994,6 +3278,7 @@ bnx2_init_rx_ring(struct bnx2 *bp) ring_prod = prod = bp->rx_prod = 0; bp->rx_cons = 0; + bp->hw_rx_cons = 0; bp->rx_prod_bseq = 0; rxbd = &bp->rx_desc_ring[0]; @@ -3079,7 +3364,7 @@ bnx2_free_rx_skbs(struct bnx2 *bp) struct sw_bd *rx_buf = &bp->rx_buf_ring[i]; struct sk_buff *skb = rx_buf->skb; - if (skb == 0) + if (skb == NULL) continue; pci_unmap_single(bp->pdev, pci_unmap_addr(rx_buf, mapping), @@ -3234,7 +3519,7 @@ bnx2_test_registers(struct bnx2 *bp) { 0x1408, 0, 0x01c00800, 0x00000000 }, { 0x149c, 0, 0x8000ffff, 0x00000000 }, { 0x14a8, 0, 0x00000000, 0x000001ff }, - { 0x14ac, 0, 0x4fffffff, 0x10000000 }, + { 0x14ac, 0, 0x0fffffff, 0x10000000 }, { 0x14b0, 0, 0x00000002, 0x00000001 }, { 0x14b8, 0, 0x00000000, 0x00000000 }, { 0x14c0, 0, 0x00000000, 0x00000009 }, @@ -3577,7 +3862,7 @@ bnx2_test_memory(struct bnx2 *bp) u32 len; } mem_tbl[] = { { 0x60000, 0x4000 }, - { 0xa0000, 0x4000 }, + { 0xa0000, 0x3000 }, { 0xe0000, 0x4000 }, { 0x120000, 0x4000 }, { 0x1a0000, 0x4000 }, @@ -3810,7 +4095,7 @@ bnx2_timer(unsigned long data) goto bnx2_restart_timer; msg = (u32) ++bp->fw_drv_pulse_wr_seq; - REG_WR_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_DRV_PULSE_MB, msg); + REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_PULSE_MB, msg); if ((bp->phy_flags & PHY_SERDES_FLAG) && (CHIP_NUM(bp) == CHIP_NUM_5706)) { @@ -4264,7 +4549,8 @@ bnx2_get_stats(struct net_device *dev) (unsigned long) (stats_blk->stat_Dot3StatsExcessiveCollisions + stats_blk->stat_Dot3StatsLateCollisions); - if (CHIP_NUM(bp) == CHIP_NUM_5706) + if ((CHIP_NUM(bp) == CHIP_NUM_5706) || + (CHIP_ID(bp) == CHIP_ID_5708_A0)) net_stats->tx_carrier_errors = 0; else { net_stats->tx_carrier_errors = @@ -4814,6 +5100,14 @@ static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = { 4,4,4,4,4, }; +static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = { + 8,0,8,8,8,8,8,8,8,8, + 4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4, +}; + #define BNX2_NUM_TESTS 6 static struct { @@ -4922,8 +5216,13 @@ bnx2_get_ethtool_stats(struct net_device *dev, return; } - if (CHIP_NUM(bp) == CHIP_NUM_5706) + if ((CHIP_ID(bp) == CHIP_ID_5706_A0) || + (CHIP_ID(bp) == CHIP_ID_5706_A1) || + (CHIP_ID(bp) == CHIP_ID_5706_A2) || + (CHIP_ID(bp) == CHIP_ID_5708_A0)) stats_len_arr = bnx2_5706_stats_len_arr; + else + stats_len_arr = bnx2_5708_stats_len_arr; for (i = 0; i < BNX2_NUM_STATS; i++) { if (stats_len_arr[i] == 0) { @@ -5205,8 +5504,6 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->chip_id = REG_RD(bp, BNX2_MISC_ID); - bp->phy_addr = 1; - /* Get bus information. */ reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS); if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) { @@ -5269,10 +5566,18 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bnx2_init_nvram(bp); + reg = REG_RD_IND(bp, BNX2_SHM_HDR_SIGNATURE); + + if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) == + BNX2_SHM_HDR_SIGNATURE_SIG) + bp->shmem_base = REG_RD_IND(bp, BNX2_SHM_HDR_ADDR_0); + else + bp->shmem_base = HOST_VIEW_SHMEM_BASE; + /* Get the permanent MAC address. First we need to make sure the * firmware is actually running. */ - reg = REG_RD_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_DEV_INFO_SIGNATURE); + reg = REG_RD_IND(bp, bp->shmem_base + BNX2_DEV_INFO_SIGNATURE); if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) != BNX2_DEV_INFO_SIGNATURE_MAGIC) { @@ -5281,14 +5586,13 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) goto err_out_unmap; } - bp->fw_ver = REG_RD_IND(bp, HOST_VIEW_SHMEM_BASE + - BNX2_DEV_INFO_BC_REV); + bp->fw_ver = REG_RD_IND(bp, bp->shmem_base + BNX2_DEV_INFO_BC_REV); - reg = REG_RD_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_PORT_HW_CFG_MAC_UPPER); + reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_MAC_UPPER); bp->mac_addr[0] = (u8) (reg >> 8); bp->mac_addr[1] = (u8) reg; - reg = REG_RD_IND(bp, HOST_VIEW_SHMEM_BASE + BNX2_PORT_HW_CFG_MAC_LOWER); + reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_MAC_LOWER); bp->mac_addr[2] = (u8) (reg >> 24); bp->mac_addr[3] = (u8) (reg >> 16); bp->mac_addr[4] = (u8) (reg >> 8); @@ -5316,10 +5620,19 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->timer_interval = HZ; bp->current_interval = HZ; + bp->phy_addr = 1; + /* Disable WOL support if we are running on a SERDES chip. */ if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT) { bp->phy_flags |= PHY_SERDES_FLAG; bp->flags |= NO_WOL_FLAG; + if (CHIP_NUM(bp) == CHIP_NUM_5708) { + bp->phy_addr = 2; + reg = REG_RD_IND(bp, bp->shmem_base + + BNX2_SHARED_HW_CFG_CONFIG); + if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G) + bp->phy_flags |= PHY_2_5G_CAPABLE_FLAG; + } } if (CHIP_ID(bp) == CHIP_ID_5706_A0) { @@ -5339,8 +5652,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) if (bp->phy_flags & PHY_SERDES_FLAG) { bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg; - reg = REG_RD_IND(bp, HOST_VIEW_SHMEM_BASE + - BNX2_PORT_HW_CFG_CONFIG); + reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG); reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK; if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) { bp->autoneg = 0; diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 62857b6a6ee41ea7bb086904a68f75f71abc4469..76bb5f1a250bd52f43567e54bcf6f71efc720344 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -1449,8 +1449,9 @@ struct l2_fhdr { #define BNX2_EMAC_MODE_PORT_NONE (0L<<2) #define BNX2_EMAC_MODE_PORT_MII (1L<<2) #define BNX2_EMAC_MODE_PORT_GMII (2L<<2) -#define BNX2_EMAC_MODE_PORT_UNDEF (3L<<2) +#define BNX2_EMAC_MODE_PORT_MII_10 (3L<<2) #define BNX2_EMAC_MODE_MAC_LOOP (1L<<4) +#define BNX2_EMAC_MODE_25G (1L<<5) #define BNX2_EMAC_MODE_TAGGED_MAC_CTL (1L<<7) #define BNX2_EMAC_MODE_TX_BURST (1L<<8) #define BNX2_EMAC_MODE_MAX_DEFER_DROP_ENA (1L<<9) @@ -3714,6 +3715,15 @@ struct l2_fhdr { #define BNX2_MCP_ROM 0x00150000 #define BNX2_MCP_SCRATCH 0x00160000 +#define BNX2_SHM_HDR_SIGNATURE BNX2_MCP_SCRATCH +#define BNX2_SHM_HDR_SIGNATURE_SIG_MASK 0xffff0000 +#define BNX2_SHM_HDR_SIGNATURE_SIG 0x53530000 +#define BNX2_SHM_HDR_SIGNATURE_VER_MASK 0x000000ff +#define BNX2_SHM_HDR_SIGNATURE_VER_ONE 0x00000001 + +#define BNX2_SHM_HDR_ADDR_0 BNX2_MCP_SCRATCH + 4 +#define BNX2_SHM_HDR_ADDR_1 BNX2_MCP_SCRATCH + 8 + #define NUM_MC_HASH_REGISTERS 8 @@ -3724,6 +3734,53 @@ struct l2_fhdr { #define PHY_ID(id) ((id) & 0xfffffff0) #define PHY_REV_ID(id) ((id) & 0xf) +/* 5708 Serdes PHY registers */ + +#define BCM5708S_UP1 0xb + +#define BCM5708S_UP1_2G5 0x1 + +#define BCM5708S_BLK_ADDR 0x1f + +#define BCM5708S_BLK_ADDR_DIG 0x0000 +#define BCM5708S_BLK_ADDR_DIG3 0x0002 +#define BCM5708S_BLK_ADDR_TX_MISC 0x0005 + +/* Digital Block */ +#define BCM5708S_1000X_CTL1 0x10 + +#define BCM5708S_1000X_CTL1_FIBER_MODE 0x0001 +#define BCM5708S_1000X_CTL1_AUTODET_EN 0x0010 + +#define BCM5708S_1000X_CTL2 0x11 + +#define BCM5708S_1000X_CTL2_PLLEL_DET_EN 0x0001 + +#define BCM5708S_1000X_STAT1 0x14 + +#define BCM5708S_1000X_STAT1_SGMII 0x0001 +#define BCM5708S_1000X_STAT1_LINK 0x0002 +#define BCM5708S_1000X_STAT1_FD 0x0004 +#define BCM5708S_1000X_STAT1_SPEED_MASK 0x0018 +#define BCM5708S_1000X_STAT1_SPEED_10 0x0000 +#define BCM5708S_1000X_STAT1_SPEED_100 0x0008 +#define BCM5708S_1000X_STAT1_SPEED_1G 0x0010 +#define BCM5708S_1000X_STAT1_SPEED_2G5 0x0018 +#define BCM5708S_1000X_STAT1_TX_PAUSE 0x0020 +#define BCM5708S_1000X_STAT1_RX_PAUSE 0x0040 + +/* Digital3 Block */ +#define BCM5708S_DIG_3_0 0x10 + +#define BCM5708S_DIG_3_0_USE_IEEE 0x0001 + +/* Tx/Misc Block */ +#define BCM5708S_TX_ACTL1 0x15 + +#define BCM5708S_TX_ACTL1_DRIVER_VCM 0x30 + +#define BCM5708S_TX_ACTL3 0x17 + #define MIN_ETHERNET_PACKET_SIZE 60 #define MAX_ETHERNET_PACKET_SIZE 1514 #define MAX_ETHERNET_JUMBO_PACKET_SIZE 9014 @@ -3799,7 +3856,7 @@ struct sw_bd { #define BUFFERED_FLASH_PHY_PAGE_SIZE (1 << BUFFERED_FLASH_PAGE_BITS) #define BUFFERED_FLASH_BYTE_ADDR_MASK (BUFFERED_FLASH_PHY_PAGE_SIZE-1) #define BUFFERED_FLASH_PAGE_SIZE 264 -#define BUFFERED_FLASH_TOTAL_SIZE 131072 +#define BUFFERED_FLASH_TOTAL_SIZE 0x21000 #define SAIFUN_FLASH_PAGE_BITS 8 #define SAIFUN_FLASH_PHY_PAGE_SIZE (1 << SAIFUN_FLASH_PAGE_BITS) @@ -3807,6 +3864,12 @@ struct sw_bd { #define SAIFUN_FLASH_PAGE_SIZE 256 #define SAIFUN_FLASH_BASE_TOTAL_SIZE 65536 +#define ST_MICRO_FLASH_PAGE_BITS 8 +#define ST_MICRO_FLASH_PHY_PAGE_SIZE (1 << ST_MICRO_FLASH_PAGE_BITS) +#define ST_MICRO_FLASH_BYTE_ADDR_MASK (ST_MICRO_FLASH_PHY_PAGE_SIZE-1) +#define ST_MICRO_FLASH_PAGE_SIZE 256 +#define ST_MICRO_FLASH_BASE_TOTAL_SIZE 65536 + #define NVRAM_TIMEOUT_COUNT 30000 @@ -3815,6 +3878,8 @@ struct sw_bd { BNX2_NVM_CFG1_PROTECT_MODE | \ BNX2_NVM_CFG1_FLASH_SIZE) +#define FLASH_BACKUP_STRAP_MASK (0xf << 26) + struct flash_spec { u32 strapping; u32 config1; @@ -3849,6 +3914,9 @@ struct bnx2 { u16 tx_cons; int tx_ring_size; + u16 hw_tx_cons; + u16 hw_rx_cons; + #ifdef BCM_VLAN struct vlan_group *vlgrp; #endif @@ -3893,6 +3961,7 @@ struct bnx2 { #define PHY_SERDES_FLAG 1 #define PHY_CRC_FIX_FLAG 2 #define PHY_PARALLEL_DETECT_FLAG 4 +#define PHY_2_5G_CAPABLE_FLAG 8 #define PHY_INT_MODE_MASK_FLAG 0x300 #define PHY_INT_MODE_AUTO_POLLING_FLAG 0x100 #define PHY_INT_MODE_LINK_READY_FLAG 0x200 @@ -3901,6 +3970,7 @@ struct bnx2 { /* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */ #define CHIP_NUM(bp) (((bp)->chip_id) & 0xffff0000) #define CHIP_NUM_5706 0x57060000 +#define CHIP_NUM_5708 0x57080000 #define CHIP_REV(bp) (((bp)->chip_id) & 0x0000f000) #define CHIP_REV_Ax 0x00000000 @@ -3913,6 +3983,9 @@ struct bnx2 { #define CHIP_ID(bp) (((bp)->chip_id) & 0xfffffff0) #define CHIP_ID_5706_A0 0x57060000 #define CHIP_ID_5706_A1 0x57060010 +#define CHIP_ID_5706_A2 0x57060020 +#define CHIP_ID_5708_A0 0x57080000 +#define CHIP_ID_5708_B0 0x57081000 #define CHIP_BOND_ID(bp) (((bp)->chip_id) & 0xf) @@ -3991,6 +4064,8 @@ struct bnx2 { u8 mac_addr[8]; + u32 shmem_base; + u32 fw_ver; int pm_cap; @@ -4130,14 +4205,46 @@ struct fw_info { #define BNX2_FW_MSG_STATUS_FAILURE 0x00ff0000 #define BNX2_LINK_STATUS 0x0000000c +#define BNX2_LINK_STATUS_INIT_VALUE 0xffffffff +#define BNX2_LINK_STATUS_LINK_UP 0x1 +#define BNX2_LINK_STATUS_LINK_DOWN 0x0 +#define BNX2_LINK_STATUS_SPEED_MASK 0x1e +#define BNX2_LINK_STATUS_AN_INCOMPLETE (0<<1) +#define BNX2_LINK_STATUS_10HALF (1<<1) +#define BNX2_LINK_STATUS_10FULL (2<<1) +#define BNX2_LINK_STATUS_100HALF (3<<1) +#define BNX2_LINK_STATUS_100BASE_T4 (4<<1) +#define BNX2_LINK_STATUS_100FULL (5<<1) +#define BNX2_LINK_STATUS_1000HALF (6<<1) +#define BNX2_LINK_STATUS_1000FULL (7<<1) +#define BNX2_LINK_STATUS_2500HALF (8<<1) +#define BNX2_LINK_STATUS_2500FULL (9<<1) +#define BNX2_LINK_STATUS_AN_ENABLED (1<<5) +#define BNX2_LINK_STATUS_AN_COMPLETE (1<<6) +#define BNX2_LINK_STATUS_PARALLEL_DET (1<<7) +#define BNX2_LINK_STATUS_RESERVED (1<<8) +#define BNX2_LINK_STATUS_PARTNER_AD_1000FULL (1<<9) +#define BNX2_LINK_STATUS_PARTNER_AD_1000HALF (1<<10) +#define BNX2_LINK_STATUS_PARTNER_AD_100BT4 (1<<11) +#define BNX2_LINK_STATUS_PARTNER_AD_100FULL (1<<12) +#define BNX2_LINK_STATUS_PARTNER_AD_100HALF (1<<13) +#define BNX2_LINK_STATUS_PARTNER_AD_10FULL (1<<14) +#define BNX2_LINK_STATUS_PARTNER_AD_10HALF (1<<15) +#define BNX2_LINK_STATUS_TX_FC_ENABLED (1<<16) +#define BNX2_LINK_STATUS_RX_FC_ENABLED (1<<17) +#define BNX2_LINK_STATUS_PARTNER_SYM_PAUSE_CAP (1<<18) +#define BNX2_LINK_STATUS_PARTNER_ASYM_PAUSE_CAP (1<<19) +#define BNX2_LINK_STATUS_SERDES_LINK (1<<20) +#define BNX2_LINK_STATUS_PARTNER_AD_2500FULL (1<<21) +#define BNX2_LINK_STATUS_PARTNER_AD_2500HALF (1<<22) #define BNX2_DRV_PULSE_MB 0x00000010 -#define BNX2_DRV_PULSE_SEQ_MASK 0x0000ffff +#define BNX2_DRV_PULSE_SEQ_MASK 0x00007fff /* Indicate to the firmware not to go into the * OS absent when it is not getting driver pulse. * This is used for debugging. */ -#define BNX2_DRV_MSG_DATA_PULSE_CODE_ALWAYS_ALIVE 0x00010000 +#define BNX2_DRV_MSG_DATA_PULSE_CODE_ALWAYS_ALIVE 0x00080000 #define BNX2_DEV_INFO_SIGNATURE 0x00000020 #define BNX2_DEV_INFO_SIGNATURE_MAGIC 0x44564900 @@ -4160,6 +4267,8 @@ struct fw_info { #define BNX2_SHARED_HW_CFG_DESIGN_LOM 0x1 #define BNX2_SHARED_HW_CFG_PHY_COPPER 0 #define BNX2_SHARED_HW_CFG_PHY_FIBER 0x2 +#define BNX2_SHARED_HW_CFG_PHY_2_5G 0x20 +#define BNX2_SHARED_HW_CFG_PHY_BACKPLANE 0x40 #define BNX2_SHARED_HW_CFG_LED_MODE_SHIFT_BITS 8 #define BNX2_SHARED_HW_CFG_LED_MODE_MASK 0x300 #define BNX2_SHARED_HW_CFG_LED_MODE_MAC 0 @@ -4173,9 +4282,11 @@ struct fw_info { #define BNX2_PORT_HW_CFG_MAC_LOWER 0x00000054 #define BNX2_PORT_HW_CFG_CONFIG 0x00000058 +#define BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK 0x0000ffff #define BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK 0x001f0000 #define BNX2_PORT_HW_CFG_CFG_DFLT_LINK_AN 0x00000000 #define BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G 0x00030000 +#define BNX2_PORT_HW_CFG_CFG_DFLT_LINK_2_5G 0x00040000 #define BNX2_PORT_HW_CFG_IMD_MAC_A_UPPER 0x00000068 #define BNX2_PORT_HW_CFG_IMD_MAC_A_LOWER 0x0000006c diff --git a/drivers/net/bnx2_fw.h b/drivers/net/bnx2_fw.h index 35f3a2ae5ef11300a29d1843124e75e3a40ec362..ab07a4900e9aee0a472a8c99abec8750b52b7765 100644 --- a/drivers/net/bnx2_fw.h +++ b/drivers/net/bnx2_fw.h @@ -14,24 +14,23 @@ * accompanying it. */ - -static int bnx2_COM_b06FwReleaseMajor = 0x0; +static int bnx2_COM_b06FwReleaseMajor = 0x1; static int bnx2_COM_b06FwReleaseMinor = 0x0; static int bnx2_COM_b06FwReleaseFix = 0x0; -static u32 bnx2_COM_b06FwStartAddr = 0x080004a0; +static u32 bnx2_COM_b06FwStartAddr = 0x080008b4; static u32 bnx2_COM_b06FwTextAddr = 0x08000000; -static int bnx2_COM_b06FwTextLen = 0x4594; -static u32 bnx2_COM_b06FwDataAddr = 0x080045e0; +static int bnx2_COM_b06FwTextLen = 0x57bc; +static u32 bnx2_COM_b06FwDataAddr = 0x08005840; static int bnx2_COM_b06FwDataLen = 0x0; -static u32 bnx2_COM_b06FwRodataAddr = 0x08004598; -static int bnx2_COM_b06FwRodataLen = 0x18; -static u32 bnx2_COM_b06FwBssAddr = 0x08004600; +static u32 bnx2_COM_b06FwRodataAddr = 0x080057c0; +static int bnx2_COM_b06FwRodataLen = 0x58; +static u32 bnx2_COM_b06FwBssAddr = 0x08005860; static int bnx2_COM_b06FwBssLen = 0x88; -static u32 bnx2_COM_b06FwSbssAddr = 0x080045e0; +static u32 bnx2_COM_b06FwSbssAddr = 0x08005840; static int bnx2_COM_b06FwSbssLen = 0x1c; -static u32 bnx2_COM_b06FwText[(0x4594/4) + 1] = { - 0x0a000128, 0x00000000, 0x00000000, 0x0000000d, 0x636f6d20, 0x302e362e, - 0x39000000, 0x00060902, 0x00000000, 0x00000003, 0x00000014, 0x00000032, +static u32 bnx2_COM_b06FwText[(0x57bc/4) + 1] = { + 0x0a00022d, 0x00000000, 0x00000000, 0x0000000d, 0x636f6d20, 0x322e352e, + 0x38000000, 0x02050802, 0x00000000, 0x00000003, 0x00000014, 0x00000032, 0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000010, 0x000003e8, 0x0000ea60, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, @@ -79,70 +78,117 @@ static u32 bnx2_COM_b06FwText[(0x4594/4) + 1] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x10000003, 0x00000000, 0x0000000d, - 0x0000000d, 0x3c020800, 0x244245e0, 0x3c030800, 0x24634688, 0xac400000, - 0x0043202b, 0x1480fffd, 0x24420004, 0x3c1d0800, 0x37bd7ffc, 0x03a0f021, - 0x3c100800, 0x261004a0, 0x3c1c0800, 0x279c45e0, 0x0e0001f2, 0x00000000, - 0x0000000d, 0x27bdffe8, 0x3c1a8000, 0x3c020008, 0x0342d825, 0x3c036010, - 0xafbf0010, 0x8c655000, 0x3c020800, 0x24470ac8, 0x3c040800, 0x24864600, - 0x2402ff7f, 0x00a22824, 0x34a5380c, 0xac655000, 0x00002821, 0x24020037, - 0x24030c80, 0xaf420008, 0xaf430024, 0xacc70000, 0x24a50001, 0x2ca20016, - 0x1440fffc, 0x24c60004, 0x24844600, 0x3c020800, 0x24420ad4, 0x3c030800, - 0x246309d4, 0xac820004, 0x3c020800, 0x24420618, 0x3c050800, 0x24a50ca0, - 0xac82000c, 0x3c020800, 0x24423100, 0xac830008, 0x3c030800, 0x246325c8, - 0xac820014, 0x3c020800, 0x24422b0c, 0xac830018, 0xac83001c, 0x3c030800, - 0x24630adc, 0xac820024, 0x3c020800, 0x24423040, 0xac83002c, 0x3c030800, - 0x24633060, 0xac820030, 0x3c020800, 0x24422f6c, 0xac830034, 0x3c030800, - 0x24632c60, 0xac82003c, 0x3c020800, 0x24420b6c, 0xac850010, 0xac850020, - 0xac830040, 0x0e000bd6, 0xac820050, 0x8fbf0010, 0x03e00008, 0x27bd0018, - 0x27bdffe0, 0xafb00010, 0x27500100, 0xafbf0018, 0xafb10014, 0x9203000b, - 0x24020003, 0x1462005b, 0x96110008, 0x32220001, 0x10400009, 0x27430080, - 0x8e020000, 0x96040014, 0x000211c2, 0x00021040, 0x00621821, 0xa4640000, - 0x0a0001cb, 0x3c020800, 0x3c020800, 0x8c430020, 0x1060002a, 0x3c030800, - 0x0e001006, 0x00000000, 0x97420108, 0x8f850018, 0x9743010c, 0x3042003e, - 0x00021400, 0x00621825, 0xaca30000, 0x8f840018, 0x8f420100, 0xac820004, - 0x97430116, 0x9742010e, 0x8f840018, 0x00031c00, 0x00431025, 0xac820008, - 0x97430110, 0x97440112, 0x8f850018, 0x00031c00, 0x00832025, 0xaca4000c, - 0x97420114, 0x8f840018, 0x3042ffff, 0xac820010, 0x8f830018, 0xac600014, - 0x8f820018, 0x3c030800, 0xac400018, 0x9462466e, 0x8f840018, 0x3c032000, - 0x00431025, 0xac82001c, 0x0e001044, 0x24040001, 0x3c030800, 0x8c620040, - 0x24420001, 0xac620040, 0x3c020800, 0x8c430044, 0x32240004, 0x24630001, - 0x10800017, 0xac430044, 0x8f4202b8, 0x04430007, 0x8e020020, 0x3c040800, - 0x8c830060, 0x24020001, 0x24630001, 0x0a0001ed, 0xac830060, 0x3c060800, - 0x8cc4005c, 0xaf420280, 0x96030016, 0x00001021, 0xa7430284, 0x8e050004, - 0x24840001, 0x3c031000, 0xaf450288, 0xaf4302b8, 0x0a0001ed, 0xacc4005c, - 0x32220002, 0x0a0001ed, 0x0002102b, 0x3c026000, 0xac400808, 0x0000000d, - 0x00001021, 0x8fbf0018, 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, - 0x27bdffc8, 0xafbf0034, 0xafbe0030, 0xafb7002c, 0xafb60028, 0xafb50024, - 0xafb40020, 0xafb3001c, 0xafb20018, 0xafb10014, 0x0e00013f, 0xafb00010, - 0x24110020, 0x24150030, 0x2794000c, 0x27930008, 0x3c124000, 0x3c1e0800, - 0x3c170800, 0x3c160800, 0x8f820004, 0x3c040800, 0x8c830020, 0x10430004, - 0x00000000, 0xaf830004, 0x0e00110b, 0x00000000, 0x8f500000, 0x32020007, - 0x1040fff5, 0x32020001, 0x1040002b, 0x32020002, 0x8f420100, 0xaf420020, - 0x8f430104, 0xaf4300a8, 0x9342010b, 0x93630000, 0x306300ff, 0x10710005, - 0x304400ff, 0x10750006, 0x2c820016, 0x0a000227, 0x00000000, 0xaf940000, - 0x0a000228, 0x2c820016, 0xaf930000, 0x0a000228, 0x00000000, 0xaf800000, - 0x14400005, 0x00041880, 0x0e0002b2, 0x00000000, 0x0a000234, 0x00000000, - 0x3c020800, 0x24424600, 0x00621821, 0x8c620000, 0x0040f809, 0x00000000, - 0x10400005, 0x8fc20034, 0x8f420104, 0x3c016020, 0xac220014, 0x8fc20034, - 0xaf520138, 0x24420001, 0xafc20034, 0x32020002, 0x10400019, 0x32020004, - 0x8f420140, 0xaf420020, 0x93630000, 0x306300ff, 0x10710005, 0x00000000, - 0x10750006, 0x00000000, 0x0a000250, 0x00000000, 0xaf940000, 0x0a000251, - 0x00000000, 0xaf930000, 0x0a000251, 0x00000000, 0xaf800000, 0x0e0008b9, - 0x00000000, 0x8ee20038, 0xaf520178, 0x24420001, 0xaee20038, 0x32020004, - 0x1040ffad, 0x00000000, 0x8f420180, 0xaf420020, 0x93630000, 0x306300ff, - 0x10710005, 0x00000000, 0x10750006, 0x00000000, 0x0a00026a, 0x00000000, - 0xaf940000, 0x0a00026b, 0x00000000, 0xaf930000, 0x0a00026b, 0x00000000, - 0xaf800000, 0x93620000, 0x14510004, 0x8ec2003c, 0x0e000835, 0x00000000, - 0x8ec2003c, 0xaf5201b8, 0x24420001, 0x0a000206, 0xaec2003c, 0x27bdffe8, - 0xafbf0010, 0x97420108, 0x24033000, 0x30447000, 0x10830012, 0x28823001, - 0x10400007, 0x24024000, 0x1080000b, 0x24022000, 0x1082001a, 0x24020001, - 0x0a000299, 0x00000000, 0x1082000c, 0x24025000, 0x1082000e, 0x00000000, - 0x0a000299, 0x00000000, 0x0000000d, 0x0a00029b, 0x00001021, 0x0e000300, - 0x00000000, 0x0a00029b, 0x00001021, 0x0e00048f, 0x00000000, 0x0a00029b, - 0x00001021, 0x0e000fdf, 0x00000000, 0x0a00029b, 0x00001021, 0x0000000d, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c020800, 0x24425840, + 0x3c030800, 0x246358e8, 0xac400000, 0x0043202b, 0x1480fffd, 0x24420004, + 0x3c1d0800, 0x37bd7ffc, 0x03a0f021, 0x3c100800, 0x261008b4, 0x3c1c0800, + 0x279c5840, 0x0e0002f7, 0x00000000, 0x0000000d, 0x27bdffe8, 0x3c1a8000, + 0x3c020008, 0x0342d825, 0x3c036010, 0xafbf0010, 0x8c655000, 0x3c020800, + 0x24470f30, 0x3c040800, 0x24865860, 0x2402ff7f, 0x00a22824, 0x34a5380c, + 0xac655000, 0x00002821, 0x24020037, 0x24030c80, 0xaf420008, 0xaf430024, + 0xacc70000, 0x24a50001, 0x2ca20016, 0x1440fffc, 0x24c60004, 0x24845860, + 0x3c020800, 0x24420f3c, 0x3c030800, 0x24630e2c, 0xac820004, 0x3c020800, + 0x24420a2c, 0x3c050800, 0x24a51268, 0xac82000c, 0x3c020800, 0x244243dc, + 0xac830008, 0x3c030800, 0x24633698, 0xac820014, 0x3c020800, 0x24423c24, + 0xac830018, 0xac83001c, 0x3c030800, 0x24630f44, 0xac820024, 0x3c020800, + 0x244243ac, 0xac83002c, 0x3c030800, 0x246343cc, 0xac820030, 0x3c020800, + 0x244242f0, 0xac830034, 0x3c030800, 0x24633d78, 0xac82003c, 0x3c020800, + 0x24420fd4, 0xac850010, 0xac850020, 0xac830040, 0x0e0010b7, 0xac820050, + 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x27bdffe0, 0xafb00010, 0x27500100, + 0xafbf0018, 0xafb10014, 0x9203000b, 0x24020003, 0x1462005b, 0x96110008, + 0x32220001, 0x10400009, 0x27430080, 0x8e020000, 0x96040014, 0x000211c2, + 0x00021040, 0x00621821, 0xa4640000, 0x0a0002d0, 0x3c020800, 0x3c020800, + 0x8c430020, 0x1060002a, 0x3c030800, 0x0e00148e, 0x00000000, 0x97420108, + 0x8f850018, 0x9743010c, 0x3042003e, 0x00021400, 0x00621825, 0xaca30000, + 0x8f840018, 0x8f420100, 0xac820004, 0x97430116, 0x9742010e, 0x8f840018, + 0x00031c00, 0x00431025, 0xac820008, 0x97430110, 0x97440112, 0x8f850018, + 0x00031c00, 0x00832025, 0xaca4000c, 0x97420114, 0x8f840018, 0x3042ffff, + 0xac820010, 0x8f830018, 0xac600014, 0x8f820018, 0x3c030800, 0xac400018, + 0x946258ce, 0x8f840018, 0x3c032000, 0x00431025, 0xac82001c, 0x0e0014cc, + 0x24040001, 0x3c030800, 0x8c620040, 0x24420001, 0xac620040, 0x3c020800, + 0x8c430044, 0x32240004, 0x24630001, 0x10800017, 0xac430044, 0x8f4202b8, + 0x04430007, 0x8e020020, 0x3c040800, 0x8c830060, 0x24020001, 0x24630001, + 0x0a0002f2, 0xac830060, 0x3c060800, 0x8cc4005c, 0xaf420280, 0x96030016, + 0x00001021, 0xa7430284, 0x8e050004, 0x24840001, 0x3c031000, 0xaf450288, + 0xaf4302b8, 0x0a0002f2, 0xacc4005c, 0x32220002, 0x0a0002f2, 0x0002102b, + 0x3c026000, 0xac400808, 0x0000000d, 0x00001021, 0x8fbf0018, 0x8fb10014, + 0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffc8, 0xafbf0034, 0xafbe0030, + 0xafb7002c, 0xafb60028, 0xafb50024, 0xafb40020, 0xafb3001c, 0xafb20018, + 0xafb10014, 0x0e000244, 0xafb00010, 0x3c170800, 0x3c160800, 0x24110020, + 0x24150030, 0x2794000c, 0x27930008, 0x3c124000, 0x3c1e0800, 0x8f820004, + 0x3c040800, 0x8c830020, 0x10430005, 0x8ee200a4, 0xaf830004, 0x0e001593, + 0x00000000, 0x8ee200a4, 0x8ec300a0, 0x10430004, 0x26c400a0, 0x94820002, + 0xa742009e, 0xaee300a4, 0x8f500000, 0x32020007, 0x1040ffee, 0x32020001, + 0x1040002c, 0x32020002, 0x8f420100, 0xaf420020, 0x8f430104, 0xaf4300a8, + 0x9342010b, 0x93630000, 0x306300ff, 0x10710005, 0x304400ff, 0x10750006, + 0x2c820016, 0x0a000333, 0x00000000, 0xaf940000, 0x0a000334, 0x2c820016, + 0xaf930000, 0x0a000334, 0x00000000, 0xaf800000, 0x14400005, 0x00041880, + 0x0e0003cc, 0x00000000, 0x0a000340, 0x00000000, 0x3c020800, 0x24425860, + 0x00621821, 0x8c620000, 0x0040f809, 0x00000000, 0x10400005, 0x3c030800, + 0x8f420104, 0x3c016020, 0xac220014, 0x3c030800, 0x8c620034, 0xaf520138, + 0x24420001, 0xac620034, 0x32020002, 0x1040001a, 0x32020004, 0x8f420140, + 0xaf420020, 0x93630000, 0x306300ff, 0x10710005, 0x00000000, 0x10750006, + 0x00000000, 0x0a00035d, 0x00000000, 0xaf940000, 0x0a00035e, 0x00000000, + 0xaf930000, 0x0a00035e, 0x00000000, 0xaf800000, 0x0e000c7b, 0x00000000, + 0x3c040800, 0x8c820038, 0xaf520178, 0x24420001, 0xac820038, 0x32020004, + 0x1040ffa4, 0x00000000, 0x8f420180, 0xaf420020, 0x93630000, 0x306300ff, + 0x10710005, 0x00000000, 0x10750006, 0x00000000, 0x0a000378, 0x00000000, + 0xaf940000, 0x0a000379, 0x00000000, 0xaf930000, 0x0a000379, 0x00000000, + 0xaf800000, 0x8f430180, 0x24020f00, 0x14620005, 0x00000000, 0x8f420188, + 0xa742009c, 0x0a000387, 0x8fc2003c, 0x93620000, 0x14510004, 0x8fc2003c, + 0x0e000bad, 0x00000000, 0x8fc2003c, 0xaf5201b8, 0x24420001, 0x0a00030b, + 0xafc2003c, 0x27bdffe8, 0xafbf0010, 0x97420108, 0x24033000, 0x30447000, + 0x10830016, 0x28823001, 0x10400007, 0x24024000, 0x1080000b, 0x24022000, + 0x1082000c, 0x00000000, 0x0a0003b3, 0x00000000, 0x10820010, 0x24025000, + 0x10820012, 0x00000000, 0x0a0003b3, 0x00000000, 0x0000000d, 0x0a0003b5, + 0x00001021, 0x0e000442, 0x00000000, 0x0a0003b6, 0x8fbf0010, 0x0e00041a, + 0x00000000, 0x0a0003b5, 0x00001021, 0x0e000669, 0x00000000, 0x0a0003b5, + 0x00001021, 0x0e001467, 0x00000000, 0x0a0003b5, 0x00001021, 0x0000000d, 0x00001021, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x93620000, 0x24030020, - 0x304400ff, 0x10830005, 0x24020030, 0x10820007, 0x00000000, 0x0a0002af, + 0x304400ff, 0x10830005, 0x24020030, 0x10820007, 0x00000000, 0x0a0003c9, 0x00000000, 0x2782000c, 0xaf820000, 0x03e00008, 0x00000000, 0x27820008, 0xaf820000, 0x03e00008, 0x00000000, 0xaf800000, 0x03e00008, 0x00000000, 0x0000000d, 0x03e00008, 0x00001021, 0x03e00008, 0x00001021, 0x27440100, @@ -159,1000 +205,1716 @@ static u32 bnx2_COM_b06FwText[(0x4594/4) + 1] = { 0x3c020006, 0x34420001, 0xaf420030, 0x00000000, 0x00000000, 0x00000000, 0x8f420000, 0x30420010, 0x1040fffd, 0x00001021, 0x03e00008, 0x00000000, 0x3c020800, 0x8c430020, 0x27bdffe8, 0xafb00010, 0x27500100, 0x1060001e, - 0xafbf0014, 0x0e001006, 0x00000000, 0x8f830018, 0x8e020018, 0xac620000, + 0xafbf0014, 0x0e00148e, 0x00000000, 0x8f830018, 0x8e020018, 0xac620000, 0x8f840018, 0x9602000c, 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f820018, 0xac400014, 0x8f840018, - 0x3c026000, 0x8c434448, 0xac830018, 0x96020008, 0x3c030800, 0x9464466e, - 0x8f850018, 0x00021400, 0x00441025, 0x24040001, 0x0e001044, 0xaca2001c, - 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x27bdffc8, 0xafb3001c, - 0x00009821, 0xafb7002c, 0x0000b821, 0xafbe0030, 0x0000f021, 0xafb50024, - 0x27550100, 0xafbf0034, 0xafb60028, 0xafb40020, 0xafb20018, 0xafb10014, - 0xafb00010, 0x96a20008, 0x8f540100, 0x8eb20018, 0x30420001, 0x10400037, - 0x02a0b021, 0x8f630054, 0x2642ffff, 0x00431023, 0x18400006, 0x00000000, - 0x0000000d, 0x00000000, 0x24000128, 0x0a000372, 0x00002021, 0x8f62004c, - 0x02421023, 0x18400028, 0x00002021, 0x93650120, 0x93640121, 0x3c030800, - 0x8c62008c, 0x308400ff, 0x24420001, 0x30a500ff, 0x00803821, 0x1485000b, - 0xac62008c, 0x3c040800, 0x8c830090, 0x24630001, 0xac830090, 0x93620122, - 0x30420001, 0x00021023, 0x30420005, 0x0a000372, 0x34440004, 0x27660100, - 0x00041080, 0x00c21021, 0x8c430000, 0x02431823, 0x04600004, 0x24820001, - 0x30440007, 0x1485fff9, 0x00041080, 0x10870007, 0x3c030800, 0xa3640121, - 0x8c620094, 0x24040005, 0x24420001, 0x0a000372, 0xac620094, 0x24040004, - 0x00809821, 0x9362003f, 0x304400ff, 0x38830016, 0x2c630001, 0x38820010, - 0x2c420001, 0x00621825, 0x1460000c, 0x24020001, 0x38830008, 0x2c630001, - 0x38820014, 0x2c420001, 0x00621825, 0x14600005, 0x24020001, 0x24020012, - 0x14820002, 0x00001021, 0x24020001, 0x50400007, 0x8eb10020, 0x8ea20020, - 0x8f630040, 0x00408821, 0x00431023, 0x5c400001, 0x8f710040, 0x9343010b, - 0x24020004, 0x54620005, 0x36730080, 0x96a20008, 0x36730002, 0x24170001, - 0x305e0020, 0x2402fffb, 0x02628024, 0x1200002a, 0x3c030800, 0x8c620030, - 0x02021024, 0x10400026, 0x3c020800, 0x8c430020, 0x10600024, 0x32620004, - 0x0e001006, 0x00000000, 0x8f830018, 0x8f420100, 0xac620000, 0x8f840018, - 0x02201821, 0x32620002, 0xac900004, 0x8f840018, 0x50400001, 0x8ec30014, - 0xac830008, 0x8f830018, 0x8ec20020, 0xac62000c, 0x8f840018, 0x8f620040, - 0xac820010, 0x8f830018, 0x8ec20018, 0xac620014, 0x8f840018, 0x3c026000, - 0x8c434448, 0x3c020800, 0xac830018, 0x9443466e, 0x8f840018, 0x3c024010, - 0x00621825, 0xac83001c, 0x0e001044, 0x24040001, 0x32620004, 0x10400076, - 0x00003821, 0x3c029000, 0x34420001, 0x3c038000, 0x02821025, 0xa360007c, - 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93620023, - 0x30420080, 0x10400011, 0x00000000, 0x8f65005c, 0x8f63004c, 0x9764003c, - 0x8f620064, 0x00a32823, 0x00852821, 0x00a2102b, 0x54400006, 0x3c023fff, - 0x93620023, 0x3042007f, 0xa3620023, 0xaf720064, 0x3c023fff, 0x0a0003f1, - 0x3442ffff, 0x8f62005c, 0x02421023, 0x04400011, 0x00000000, 0x8f65005c, - 0x8f630064, 0x9764003c, 0x3c023fff, 0x3442ffff, 0xaf720064, 0x00a32823, - 0x00852821, 0x0045102b, 0x10400004, 0x02451021, 0x3c053fff, 0x34a5ffff, - 0x02451021, 0xaf62005c, 0x24070001, 0xaf72004c, 0x8f620054, 0x16420005, + 0x3c026000, 0x8c434448, 0xac830018, 0x96020008, 0x3c030800, 0x946458ce, + 0x8f850018, 0x00021400, 0x00441025, 0x24040001, 0x0e0014cc, 0xaca2001c, + 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x27bdffe8, 0xafb00010, + 0x27500100, 0xafbf0014, 0x92020009, 0x14400003, 0x3c020800, 0x0a00046c, + 0x24020001, 0x8c430020, 0x1060001f, 0x00001021, 0x0e00148e, 0x00000000, + 0x8f830018, 0x8e020018, 0xac620000, 0x8f840018, 0x9602000c, 0xac820004, + 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, + 0x8f820018, 0xac400014, 0x8f840018, 0x3c026000, 0x8c434448, 0xac830018, + 0x96020008, 0x3c030800, 0x946458ce, 0x8f850018, 0x00021400, 0x00441025, + 0x24040001, 0x0e0014cc, 0xaca2001c, 0x00001021, 0x8fbf0014, 0x8fb00010, + 0x03e00008, 0x27bd0018, 0x3c0b0800, 0x8d6808b0, 0x3c070800, 0x24e700b0, + 0x00084900, 0x01271821, 0xac640000, 0x93620005, 0x97660008, 0x00e95021, + 0x93630023, 0x9364003f, 0x25080001, 0x00021600, 0x00063400, 0x00461025, + 0x00031a00, 0x00431025, 0x00822025, 0xad440004, 0x9362007e, 0x9366007f, + 0x8f630178, 0x9364007a, 0x00021600, 0x00063400, 0x00461025, 0x00031a00, + 0x00431025, 0x00822025, 0xad440008, 0x93620080, 0x9363007d, 0x3108007f, + 0x01403821, 0xad6808b0, 0x00021600, 0x00031c00, 0x00431025, 0x00451025, + 0x03e00008, 0xace2000c, 0x27bdffb8, 0xafb3002c, 0x00009821, 0xafbe0040, + 0x0000f021, 0xafb50034, 0x27550100, 0xafbf0044, 0xafb7003c, 0xafb60038, + 0xafb40030, 0xafb20028, 0xafb10024, 0xafb00020, 0xafa00010, 0xafa00014, + 0x96a20008, 0x8f540100, 0x8eb10018, 0x30420001, 0x10400037, 0x02a0b821, + 0x8f630054, 0x2622ffff, 0x00431023, 0x18400006, 0x00000000, 0x0000000d, + 0x00000000, 0x2400015c, 0x0a0004e5, 0x00002021, 0x8f62004c, 0x02221023, + 0x18400028, 0x00002021, 0x93650120, 0x93640121, 0x3c030800, 0x8c62008c, + 0x308400ff, 0x24420001, 0x30a500ff, 0x00803821, 0x1485000b, 0xac62008c, + 0x3c040800, 0x8c830090, 0x24630001, 0xac830090, 0x93620122, 0x30420001, + 0x00021023, 0x30420005, 0x0a0004e5, 0x34440004, 0x27660100, 0x00041080, + 0x00c21021, 0x8c430000, 0x02231823, 0x04600004, 0x24820001, 0x30440007, + 0x1485fff9, 0x00041080, 0x10870007, 0x3c030800, 0xa3640121, 0x8c620094, + 0x24040005, 0x24420001, 0x0a0004e5, 0xac620094, 0x24040004, 0x00809821, + 0x9362003f, 0x304400ff, 0x38830016, 0x2c630001, 0x38820010, 0x2c420001, + 0x00621825, 0x1460000c, 0x24020001, 0x38830008, 0x2c630001, 0x38820014, + 0x2c420001, 0x00621825, 0x14600005, 0x24020001, 0x24020012, 0x14820002, + 0x00001021, 0x24020001, 0x10400009, 0x00000000, 0x8ea20020, 0x8f630040, + 0x0040b021, 0x00431023, 0x5c400010, 0x8f760040, 0x0a000511, 0x00000000, + 0x9343010b, 0x24020004, 0x1462000a, 0x8eb60020, 0x8f630040, 0x3c021000, + 0x00761823, 0x0043102a, 0x10400004, 0x00000000, 0x0000000d, 0x00000000, + 0x240002fa, 0x9343010b, 0x24020004, 0x5462000b, 0x96a20008, 0x24020001, + 0xafa20010, 0x96a20008, 0x24030001, 0xafa30018, 0x8eb2001c, 0x36730002, + 0x30420020, 0x0a000526, 0xafa20014, 0x36730080, 0x30420002, 0x10400003, + 0xafa00018, 0x0a000526, 0x8eb2001c, 0x8eb20014, 0x2402fffb, 0x02628024, + 0x1200002a, 0x3c030800, 0x8c620030, 0x02021024, 0x10400026, 0x3c020800, + 0x8c430020, 0x10600024, 0x32620004, 0x0e00148e, 0x00000000, 0x8f830018, + 0x8f420100, 0xac620000, 0x8f840018, 0x02401821, 0x32620002, 0xac900004, + 0x8f840018, 0x54400001, 0x02c01821, 0xac830008, 0x8f830018, 0x8ee20020, + 0xac62000c, 0x8f840018, 0x8f620040, 0xac820010, 0x8f830018, 0x8ee20018, + 0xac620014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, 0x3c020800, + 0xaca30018, 0x944358ce, 0x8f850018, 0x3c024010, 0x00621825, 0x0e0014cc, + 0xaca3001c, 0x32620004, 0x10400063, 0x00003821, 0x3c029000, 0x34420001, + 0x3c038000, 0x02821025, 0xa360007c, 0xaf420020, 0x8f420020, 0x00431024, + 0x1440fffd, 0x00000000, 0x93620023, 0x30420080, 0x10400011, 0x00000000, + 0x8f65005c, 0x8f63004c, 0x9764003c, 0x8f620064, 0x00a32823, 0x00852821, + 0x00a2102b, 0x54400006, 0x3c023fff, 0x93620023, 0x3042007f, 0xa3620023, + 0xaf710064, 0x3c023fff, 0x0a000580, 0x3442ffff, 0x8f62005c, 0x02221023, + 0x04400011, 0x00000000, 0x8f65005c, 0x8f630064, 0x9764003c, 0x3c023fff, + 0x3442ffff, 0xaf710064, 0x00a32823, 0x00852821, 0x0045102b, 0x10400004, + 0x02251021, 0x3c053fff, 0x34a5ffff, 0x02251021, 0xaf62005c, 0x24070001, + 0xaf71004c, 0x8f620054, 0x16220005, 0x00000000, 0x93620023, 0x30420040, + 0x10400017, 0x24020001, 0x9762006a, 0x00022880, 0x50a00001, 0x24050001, + 0x97630068, 0x93640081, 0x3c020800, 0x8c46004c, 0x00652821, 0x00852804, + 0x00c5102b, 0x54400001, 0x00a03021, 0x3c020800, 0x8c440050, 0x00c4182b, + 0x54600001, 0x00c02021, 0x8f420074, 0x2403fffe, 0x00832824, 0x00a21021, + 0xaf62000c, 0x93620082, 0x30420080, 0x50400001, 0xa3600081, 0x3c028000, + 0x34420001, 0x02821025, 0xaf420020, 0x9363007e, 0x9362007a, 0x10620004, + 0x00000000, 0x0e0013c4, 0x00000000, 0x00403821, 0x54e00001, 0x241e0001, + 0x8f700040, 0x8f620040, 0x14520003, 0x00521023, 0x0a0005bf, 0x00001021, + 0x28420001, 0x10400041, 0x8fa20010, 0x0e000fae, 0x02402021, 0xaf720040, + 0x9362003e, 0x30420001, 0x1440000b, 0x3c029000, 0x93620022, 0x24420001, + 0xa3620022, 0x93630022, 0x3c020800, 0x8c440098, 0x0064182b, 0x14600027, + 0x3c020800, 0x3c029000, 0x34420001, 0x02821025, 0xaf420020, 0x3c038000, + 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000, + 0x34420001, 0xa362007d, 0x8f640074, 0x34630001, 0x02831825, 0xaf430020, + 0x04810006, 0x3c038000, 0x02802021, 0x0e000470, 0x24050273, 0x0a0005f2, + 0x24050001, 0x8f4201f8, 0x00431024, 0x1440fffd, 0x24020002, 0x3c031000, + 0xaf5401c0, 0xa34201c4, 0xaf4301f8, 0x24050001, 0x24020001, 0xa7620012, + 0xa3600022, 0x0a0005fe, 0x2ca20001, 0x9743007a, 0x9444002a, 0x00002821, + 0x00641821, 0x3063fffe, 0xa7630012, 0x2ca20001, 0x00021023, 0x03c2f024, + 0x8fa20010, 0x10400004, 0x8fa30014, 0x0e0013c1, 0x00000000, 0x8fa30014, + 0x10600003, 0x00000000, 0x0e0010eb, 0x00000000, 0x13c0001f, 0x3c029000, + 0x34420001, 0x02821025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, + 0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000, 0xa362007d, 0x8f640074, + 0x34630001, 0x02831825, 0xaf430020, 0x04810006, 0x3c038000, 0x02802021, + 0x0e000470, 0x2405036c, 0x0a00062b, 0x8fa20018, 0x8f4201f8, 0x00431024, + 0x1440fffd, 0x24020002, 0x3c031000, 0xaf5401c0, 0xa34201c4, 0xaf4301f8, + 0x8fa20018, 0x5040002f, 0x96a20008, 0x8f620048, 0x8f630024, 0x00761821, + 0xaf630048, 0x9764003c, 0x00501023, 0x0044102b, 0x10400025, 0x3c029000, + 0x34420001, 0x3c040800, 0x8c830080, 0x8f450100, 0x3c068000, 0x24630001, + 0x00a21025, 0xac830080, 0xaf420020, 0x8f420020, 0x00461024, 0x1440fffd, + 0x00000000, 0x9362007d, 0x3c038000, 0x34420004, 0xa362007d, 0x8f640074, + 0x34630001, 0x00a31825, 0xaf430020, 0x04810006, 0x3c038000, 0x00a02021, + 0x0e000470, 0x2405038a, 0x0a00065b, 0x96a20008, 0x8f4201f8, 0x00431024, + 0x1440fffd, 0x24020002, 0x3c031000, 0xaf4501c0, 0xa34201c4, 0xaf4301f8, + 0x96a20008, 0x8fbf0044, 0x8fbe0040, 0x8fb7003c, 0x8fb60038, 0x8fb50034, + 0x8fb40030, 0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020, 0x00021042, + 0x30420001, 0x03e00008, 0x27bd0048, 0x27bdffe0, 0xafbf0018, 0x97420108, + 0x24030019, 0x304400ff, 0x10830065, 0x2882001a, 0x1040001a, 0x2882000a, + 0x1040000f, 0x28820008, 0x10400040, 0x24020001, 0x1082003a, 0x28820002, + 0x50400005, 0x24020006, 0x10800032, 0x3c026000, 0x0a0006fb, 0x00000000, + 0x1082003d, 0x00000000, 0x0a0006fb, 0x00000000, 0x2402000b, 0x10820044, + 0x2882000b, 0x1440004b, 0x2402000e, 0x10820045, 0x00000000, 0x0a0006fb, + 0x00000000, 0x24020020, 0x10820062, 0x28820021, 0x1040000e, 0x2402001c, + 0x1082004c, 0x2882001d, 0x10400005, 0x2402001b, 0x10820043, 0x00000000, + 0x0a0006fb, 0x00000000, 0x2402001f, 0x10820050, 0x00000000, 0x0a0006fb, + 0x00000000, 0x240200c1, 0x10820042, 0x288200c2, 0x10400005, 0x24020080, + 0x10820021, 0x00000000, 0x0a0006fb, 0x00000000, 0x240200c2, 0x1082003d, + 0x240200c9, 0x50820049, 0xafa00010, 0x0a0006fb, 0x00000000, 0x0e001163, + 0xac400808, 0x0a0006fd, 0x8fbf0018, 0x3c026000, 0x8c444448, 0x3c030800, + 0xac640064, 0x0e001163, 0x00000000, 0x3c026000, 0x8c444448, 0x3c030800, + 0x0a0006fc, 0xac640068, 0x8f440100, 0x0e0006ff, 0x00000000, 0x3c026000, + 0x8c444448, 0x3c030800, 0x0a0006fc, 0xac64006c, 0x0e001191, 0x00000000, + 0x0a0006fd, 0x8fbf0018, 0x8f440100, 0x0e0011bb, 0x00000000, 0x0a0006fd, + 0x8fbf0018, 0x0e001202, 0x00000000, 0x0a0006fd, 0x8fbf0018, 0x0000000d, + 0x0a0006fd, 0x8fbf0018, 0x0e000826, 0x00000000, 0x0a0006fd, 0x8fbf0018, + 0x8f440100, 0x0e001264, 0x00000000, 0x0a0006fd, 0x8fbf0018, 0x0e00134e, + 0x00000000, 0x0a0006fd, 0x8fbf0018, 0x0e00087c, 0x27440100, 0x0a0006fd, + 0x8fbf0018, 0x8f640040, 0x0e000fae, 0x00000000, 0x0a0006fd, 0x8fbf0018, + 0x8f440100, 0x0e001059, 0x00000000, 0x0a0006fd, 0x8fbf0018, 0x0e001417, + 0x00000000, 0x0a0006fd, 0x8fbf0018, 0xafa00014, 0x8f440100, 0x8f450118, + 0x8f46011c, 0x0e001439, 0x8f470120, 0x0a0006fd, 0x8fbf0018, 0x0000000d, + 0x8fbf0018, 0x03e00008, 0x27bd0020, 0x27bdffe8, 0xafbf0010, 0x9742010c, + 0x1440005e, 0x00803821, 0x3c029000, 0x34420001, 0x00e21025, 0xaf420020, + 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93620023, + 0x30420010, 0x14400026, 0x3c030800, 0x8f630074, 0x3c027fff, 0x3442ffff, + 0x00621824, 0xaf630074, 0x93620005, 0x34420001, 0xa3620005, 0x8f63004c, + 0x8f620054, 0x10620021, 0x24040001, 0x9762006a, 0x00022880, 0x50a00001, + 0x24050001, 0x97630068, 0x93640081, 0x3c020800, 0x8c46004c, 0x00652821, + 0x00852804, 0x00c5102b, 0x54400001, 0x00a03021, 0x3c020800, 0x8c440050, + 0x00c4182b, 0x54600001, 0x00c02021, 0x8f420074, 0x2403fffe, 0x00832824, + 0x00a21021, 0xaf62000c, 0x0a00073d, 0x24040001, 0x8c6200a8, 0x00002021, + 0x24420001, 0xac6200a8, 0x0000000d, 0x00000000, 0x2400044d, 0x3c028000, + 0x34420001, 0x00e21025, 0xaf420020, 0x1080001f, 0x3c029000, 0x34420001, + 0x00e21025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, + 0x00000000, 0x9362007d, 0x3c038000, 0xa362007d, 0x8f640074, 0x34630001, + 0x00e31825, 0xaf430020, 0x04810006, 0x3c038000, 0x00e02021, 0x0e000470, + 0x24050455, 0x0a000761, 0x00000000, 0x8f4201f8, 0x00431024, 0x1440fffd, + 0x24020002, 0x3c031000, 0xaf4701c0, 0xa34201c4, 0xaf4301f8, 0x0e001163, + 0x00000000, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x27bdffd8, 0xafbf0024, + 0xafb40020, 0xafb3001c, 0xafb20018, 0xafb10014, 0xafb00010, 0x93630005, + 0x00809821, 0x24020030, 0x30630030, 0x146200ac, 0x00a0a021, 0x3c020800, + 0x8c430020, 0x106000a6, 0x00000000, 0x0e00148e, 0x00000000, 0x8f830018, + 0xac730000, 0x936200c4, 0x30420002, 0x10400004, 0x24020001, 0x8f830018, + 0x0a000784, 0x00000000, 0x8f830018, 0x24020003, 0xac620004, 0x8f6200dc, + 0x8f630040, 0x00431023, 0x18400004, 0x00000000, 0x0000000d, 0x00000000, + 0x24000509, 0x8f840018, 0x8f6200dc, 0xac820008, 0x8f830018, 0xac60000c, + 0x8f820018, 0xac400010, 0x8f830018, 0x8f62004c, 0x3c100800, 0xac620014, + 0x8f850018, 0x3c026000, 0x8c434448, 0x261258c0, 0x00002021, 0xaca30018, + 0x9642000e, 0x8f850018, 0x3c034010, 0x00431025, 0x0e0014cc, 0xaca2001c, + 0x8f830018, 0xac730000, 0x9362003e, 0x9363003f, 0x8f840018, 0x00021200, + 0x00621825, 0xac830004, 0x93620081, 0x93630082, 0x8f840018, 0x00021600, + 0x00031c00, 0x00431025, 0xac820008, 0x8f830018, 0x8f620040, 0xac62000c, + 0x8f840018, 0x8f620048, 0xac820010, 0x8f71004c, 0x8f820018, 0xac510014, + 0x8f620050, 0x8f850018, 0x00401821, 0x02221023, 0x5c400001, 0x02201821, + 0x00002021, 0xaca30018, 0x9642000e, 0x8f850018, 0x3c03c00b, 0x00431025, + 0x0e0014cc, 0xaca2001c, 0x8f620054, 0x8f840018, 0x00401821, 0x02221023, + 0x5c400001, 0x02201821, 0xac830000, 0x8f840018, 0x8f630058, 0xac830004, + 0x93620023, 0x30420010, 0x10400004, 0x00000000, 0x8f830018, 0x0a0007dd, + 0x8f620148, 0x8f830018, 0x8f62005c, 0xac620008, 0x8f830018, 0x8f620060, + 0xac62000c, 0x8f840018, 0x8f620064, 0xac820010, 0x97630068, 0x9762006a, + 0x8f840018, 0x00031c00, 0x00431025, 0xac820014, 0x8f850018, 0x00002021, + 0x2402ffff, 0x260358c0, 0xaca20018, 0x9462000e, 0x8f850018, 0x3c03c00c, + 0x00431025, 0x0e0014cc, 0xaca2001c, 0x8f840018, 0x8f630018, 0xac830000, + 0x936200c4, 0x30420002, 0x10400006, 0x00000000, 0x976200c8, 0x8f830018, + 0x3042ffff, 0x0a000803, 0xac620004, 0x8f820018, 0xac400004, 0x8f830018, + 0x8f62006c, 0xac620008, 0x8f840018, 0x8f6200dc, 0xac82000c, 0x8f830018, + 0xac600010, 0x93620005, 0x8f830018, 0x00021600, 0x00541025, 0xac620014, + 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, 0x260258c0, 0xaca30018, + 0x9443000e, 0x8f850018, 0x3c02400d, 0x00621825, 0x0e0014cc, 0xaca3001c, + 0x0e00122e, 0x02602021, 0x8fbf0024, 0x8fb40020, 0x8fb3001c, 0x8fb20018, + 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0028, 0x27bdffe0, 0xafb00010, + 0x27500100, 0xafbf0018, 0xafb10014, 0x9603000c, 0x240200c1, 0x54620024, + 0x8e040000, 0x3c029000, 0x8f450100, 0x34420001, 0x3c038000, 0x00a21025, + 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x9362007d, + 0x3c038000, 0x34420004, 0xa362007d, 0x8f640074, 0x34630001, 0x00a31825, + 0xaf430020, 0x04810006, 0x3c038000, 0x00a02021, 0x0e000470, 0x240505b2, + 0x0a000878, 0x8fbf0018, 0x8f4201f8, 0x00431024, 0x1440fffd, 0x24020002, + 0x3c031000, 0xaf4501c0, 0xa34201c4, 0xaf4301f8, 0x0a000878, 0x8fbf0018, + 0x8f65004c, 0x24060001, 0x0e0012a3, 0x240705be, 0x3c020800, 0x8c430020, + 0x9611000c, 0x1060001d, 0x8e100000, 0x0e00148e, 0x00000000, 0x8f820018, + 0xac500000, 0x8f840018, 0x00111400, 0xac820004, 0x8f830018, 0xac600008, + 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f840018, 0x240205c1, + 0xac820014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, 0x3c020800, + 0xaca30018, 0x944358ce, 0x8f850018, 0x3c024019, 0x00621825, 0x0e0014cc, + 0xaca3001c, 0x8fbf0018, 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, + 0x27bdffb0, 0xafb5003c, 0x0000a821, 0xafbe0048, 0x0000f021, 0xafb70044, + 0x0000b821, 0xafb30034, 0x00009821, 0xafb60040, 0x0080b021, 0xafbf004c, + 0xafb40038, 0xafb20030, 0xafb1002c, 0xafb00028, 0xafa00010, 0x8f620040, + 0x8ec30014, 0x96d1000c, 0x00431023, 0x04410025, 0x8ed40000, 0x32220401, + 0x1040030c, 0x3c029000, 0x34420001, 0x02821025, 0xaf420020, 0x3c038000, + 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000, + 0x34420004, 0xa362007d, 0x8f640074, 0x34630001, 0x02831825, 0xaf430020, + 0x04810006, 0x3c038000, 0x02802021, 0x0e000470, 0x24050664, 0x0a000ba2, + 0x8fbf004c, 0x8f4201f8, 0x00431024, 0x1440fffd, 0x24020002, 0x3c031000, + 0xaf5401c0, 0xa34201c4, 0xaf4301f8, 0x0a000ba2, 0x8fbf004c, 0x32220010, + 0x1040006b, 0x00003021, 0x9362003f, 0x92c6000f, 0x304500ff, 0x24c3fff8, + 0x2c62000f, 0x10400057, 0x3c020800, 0x244257c0, 0x00031880, 0x00621821, + 0x8c640000, 0x00800008, 0x00000000, 0x38a20012, 0x0a000924, 0x0002a82b, + 0x2402000e, 0x14a20004, 0x2402000c, 0x24150001, 0x0a000924, 0x24060010, + 0x10a20049, 0x38a30010, 0x2c630001, 0x38a20016, 0x2c420001, 0x00621825, + 0x1460004d, 0x0000a821, 0x24020014, 0x10a2004a, 0x00000000, 0x0000000d, + 0x00000000, 0x2400069c, 0x0a000924, 0x0000a821, 0x24020016, 0x14a20005, + 0x2402000c, 0x24150001, 0x24060010, 0x0a000924, 0x3231fffd, 0x10a20032, + 0x38a30010, 0x2c630001, 0x38a2000e, 0x2c420001, 0x00621825, 0x14600036, + 0x0000a821, 0x24020014, 0x14a20003, 0x24150001, 0x0a000924, 0x24060012, + 0x0000000d, 0x00000000, 0x240006bc, 0x0a000924, 0x0000a821, 0x2402000e, + 0x14a20004, 0x24020016, 0x24150001, 0x0a000924, 0x3231fffb, 0x14a20004, + 0x24020014, 0x24150001, 0x0a000924, 0x3231fffd, 0x54a20013, 0x92c2000e, + 0x24150001, 0x24060012, 0x0a000924, 0x3231fffd, 0x2402000c, 0x54a2000c, + 0x92c2000e, 0x92c3000e, 0x2402000a, 0x10620005, 0x24150001, 0x0000000d, + 0x00000000, 0x240006e8, 0x24150001, 0x0a000924, 0x24060014, 0x92c2000e, + 0x14a20003, 0x00000000, 0x0a000924, 0x24150001, 0x10a6ffc1, 0x24020012, + 0x10a20005, 0x0000a821, 0x0000000d, 0x00000000, 0x24000704, 0x0000a821, + 0x12a00022, 0x32220004, 0x10400002, 0x24020001, 0xafa20010, 0x32230102, + 0x24020002, 0x1462000f, 0x00000000, 0x92c2000a, 0x30420020, 0x1440000b, + 0x00000000, 0x8f630048, 0x8f620040, 0x14620004, 0x00000000, 0x8f620048, + 0x24420001, 0xaf620048, 0x8f620040, 0x24420001, 0xaf620040, 0xa366003f, + 0x38c30012, 0x2c630001, 0x38c20010, 0x2c420001, 0x00621825, 0x10600005, + 0x3c030800, 0x8c620074, 0x24420001, 0x0e00140d, 0xac620074, 0x32220040, + 0x32230020, 0xafa30020, 0x32230080, 0xafa30024, 0x32230001, 0xafa30018, + 0x32230008, 0xafa3001c, 0x32230100, 0x104000c4, 0xafa30014, 0x8ec60010, + 0x8f630054, 0x24c2ffff, 0x00431023, 0x18400006, 0x00000000, 0x0000000d, + 0x00000000, 0x2400015c, 0x0a000989, 0x00009021, 0x8f62004c, 0x00c21023, + 0x18400028, 0x00009021, 0x93650120, 0x93640121, 0x3c030800, 0x8c62008c, + 0x308400ff, 0x24420001, 0x30a500ff, 0x00804021, 0x1485000b, 0xac62008c, + 0x3c040800, 0x8c830090, 0x24630001, 0xac830090, 0x93620122, 0x30420001, + 0x00021023, 0x30420005, 0x0a000989, 0x34520004, 0x27670100, 0x00041080, + 0x00e21021, 0x8c430000, 0x00c31823, 0x04600004, 0x24820001, 0x30440007, + 0x1485fff9, 0x00041080, 0x10880007, 0x3c030800, 0xa3640121, 0x8c620094, + 0x24120005, 0x24420001, 0x0a000989, 0xac620094, 0x24120004, 0x32420001, + 0x10400021, 0x3c020800, 0x8c430020, 0x8ed00000, 0x1060001c, 0x8ed30010, + 0x0e00148e, 0x00000000, 0x8f820018, 0xac500000, 0x8f840018, 0x24020001, + 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, + 0xac600010, 0x8f820018, 0xac530014, 0x8f850018, 0x3c026000, 0x8c434448, + 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, 0x3c024010, + 0x00621825, 0x0e0014cc, 0xaca3001c, 0x24130001, 0x32420004, 0x10400068, + 0x00003821, 0x3c029000, 0x8ec60010, 0x34420001, 0x3c038000, 0x02821025, + 0xa360007c, 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, + 0x93620023, 0x30420080, 0x10400011, 0x00000000, 0x8f65005c, 0x8f63004c, + 0x9764003c, 0x8f620064, 0x00a32823, 0x00852821, 0x00a2102b, 0x54400006, + 0x3c023fff, 0x93620023, 0x3042007f, 0xa3620023, 0xaf660064, 0x3c023fff, + 0x0a0009da, 0x3442ffff, 0x8f62005c, 0x00c21023, 0x04400011, 0x00000000, + 0x8f65005c, 0x8f630064, 0x9764003c, 0x3c023fff, 0x3442ffff, 0xaf660064, + 0x00a32823, 0x00852821, 0x0045102b, 0x10400004, 0x00c51021, 0x3c053fff, + 0x34a5ffff, 0x00c51021, 0xaf62005c, 0x24070001, 0xaf66004c, 0x8fa20010, + 0x10400003, 0x00000000, 0xaf660050, 0xaf660054, 0x8f620054, 0x14c20005, 0x00000000, 0x93620023, 0x30420040, 0x10400017, 0x24020001, 0x9762006a, 0x00022880, 0x50a00001, 0x24050001, 0x97630068, 0x93640081, 0x3c020800, 0x8c46004c, 0x00652821, 0x00852804, 0x00c5102b, 0x54400001, 0x00a03021, 0x3c020800, 0x8c440050, 0x00c4182b, 0x54600001, 0x00c02021, 0x8f420074, - 0x2403fffe, 0x00832824, 0x00a21021, 0xaf62000c, 0x3c028000, 0x34420001, - 0x02821025, 0xa3600081, 0xaf420020, 0x9363007e, 0x9362007a, 0x10620004, - 0x00000000, 0x0e000f2a, 0x00000000, 0x00403821, 0x10e00017, 0x3c029000, + 0x2403fffe, 0x00832824, 0x00a21021, 0xaf62000c, 0x93620082, 0x30420080, + 0x50400001, 0xa3600081, 0x3c028000, 0x34420001, 0x02821025, 0xaf420020, + 0x9363007e, 0x9362007a, 0x10620005, 0x00e0b821, 0x0e0013c4, 0x00000000, + 0x00403821, 0x00e0b821, 0x8fa30020, 0x10600009, 0x8fa20010, 0x8ec20018, + 0xaf620018, 0x8ec3001c, 0xaf63001c, 0x8ec20020, 0x24170001, 0xaf620058, + 0x8fa20010, 0x10400057, 0x8fa30024, 0x93620023, 0x30420040, 0x10400053, + 0x00000000, 0x16600021, 0x3c120800, 0x8e420020, 0x8f70004c, 0x1040001e, + 0x24130001, 0x0e00148e, 0x00000000, 0x8f820018, 0xac540000, 0x8f840018, + 0x24020001, 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, + 0x8f830018, 0xac600010, 0x8f820018, 0xac500014, 0x8f850018, 0x3c026000, + 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, + 0x3c024010, 0x00621825, 0xaca3001c, 0x0e0014cc, 0x24130001, 0x8e420020, + 0x1040001c, 0x8ed00000, 0x0e00148e, 0x00000000, 0x8f820018, 0xac500000, + 0x8f830018, 0xac600004, 0x8f820018, 0xac400008, 0x8f830018, 0xac60000c, + 0x8f820018, 0xac400010, 0x8f830018, 0x24020798, 0xac620014, 0x8f850018, + 0x3c026000, 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, + 0x8f850018, 0x3c024019, 0x00621825, 0x0e0014cc, 0xaca3001c, 0x3c029000, 0x34420001, 0x02821025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, - 0x1440fffd, 0x3c028000, 0x9363007d, 0x34420001, 0x3c048000, 0x02821025, - 0xa363007d, 0xaf420020, 0x8f4201f8, 0x00441024, 0x1440fffd, 0x24020002, - 0x3c031000, 0xaf5401c0, 0xa34201c4, 0xaf4301f8, 0x8ea30014, 0x8f620040, - 0x14430003, 0x00431023, 0x0a000443, 0x00001021, 0x28420001, 0x10400034, - 0x00000000, 0x8f620040, 0xaf630040, 0x9362003e, 0x30420001, 0x1440000b, - 0x3c029000, 0x93620022, 0x24420001, 0xa3620022, 0x93630022, 0x3c020800, - 0x8c440098, 0x0064182b, 0x1460001e, 0x3c020800, 0x3c029000, 0x34420001, + 0x1440fffd, 0x24020001, 0xaf62000c, 0x93630023, 0x3c028000, 0x34420001, + 0x02821025, 0x306300bf, 0xa3630023, 0xaf420020, 0x8fa30024, 0x10600012, + 0x8fa30018, 0x9362007c, 0x24420001, 0xa362007c, 0x9363007e, 0x9362007a, + 0x1462000b, 0x8fa30018, 0x9362007c, 0x3c030800, 0x8c640024, 0x0044102b, + 0x14400005, 0x8fa30018, 0x0e0013c4, 0x00000000, 0x02e2b825, 0x8fa30018, + 0x3062ffff, 0x10400003, 0x32220200, 0x0a000a94, 0x241e0004, 0x10400003, + 0x00000000, 0x241e0040, 0x24170001, 0x12a000d0, 0x32220002, 0x104000cf, + 0x8fa2001c, 0x92c2000a, 0x30420002, 0x5040003b, 0x92c2000a, 0x93620023, + 0x30420008, 0x54400037, 0x92c2000a, 0x3c020800, 0x8c430020, 0x10600023, + 0x3c029000, 0x0e00148e, 0x00000000, 0x8f840018, 0x8ec30000, 0xac830000, + 0x92c2000a, 0x8f830018, 0x00021600, 0xac620004, 0x8f840018, 0x8f620040, + 0xac820008, 0x8f850018, 0x8f63004c, 0xaca3000c, 0x9362003f, 0x8f840018, + 0x304200ff, 0xac820010, 0x8f830018, 0x3c026000, 0xac600014, 0x8f850018, + 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, + 0x3c02401a, 0x00621825, 0x0e0014cc, 0xaca3001c, 0x3c029000, 0x34420001, 0x02821025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, - 0x00000000, 0x3c038000, 0x9362007d, 0x34630001, 0x3c048000, 0x02831825, - 0x34420001, 0xa362007d, 0xaf430020, 0x8f4201f8, 0x00441024, 0x1440fffd, - 0x24020002, 0x3c031000, 0xaf5401c0, 0xa34201c4, 0x24020001, 0xaf4301f8, - 0xa7620012, 0x0a000476, 0xa3600022, 0x9743007a, 0x9444002a, 0x00641821, - 0x3063fffe, 0xa7630012, 0x0e000b68, 0x00000000, 0x12e00003, 0x00000000, - 0x0e000f27, 0x00000000, 0x53c00004, 0x96a20008, 0x0e000c10, 0x00000000, - 0x96a20008, 0x8fbf0034, 0x8fbe0030, 0x8fb7002c, 0x8fb60028, 0x8fb50024, - 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x00021042, - 0x30420001, 0x03e00008, 0x27bd0038, 0x27bdffe8, 0xafbf0010, 0x97420108, - 0x2403000b, 0x304400ff, 0x1083004e, 0x2882000c, 0x10400011, 0x24020006, - 0x1082003e, 0x28820007, 0x10400007, 0x28820008, 0x1080002b, 0x24020001, - 0x1082002e, 0x3c026000, 0x0a000504, 0x00000000, 0x14400061, 0x2882000a, - 0x1440002b, 0x00000000, 0x0a0004ec, 0x00000000, 0x2402001c, 0x1082004e, - 0x2882001d, 0x1040000e, 0x24020019, 0x10820041, 0x2882001a, 0x10400005, - 0x2402000e, 0x10820036, 0x00000000, 0x0a000504, 0x00000000, 0x2402001b, - 0x1082003c, 0x00000000, 0x0a000504, 0x00000000, 0x240200c1, 0x10820040, - 0x288200c2, 0x10400005, 0x24020080, 0x1082001f, 0x00000000, 0x0a000504, - 0x00000000, 0x240200c2, 0x1082003b, 0x00000000, 0x0a000504, 0x00000000, - 0x3c026000, 0x0e000c7d, 0xac400808, 0x0a000506, 0x8fbf0010, 0x8c444448, - 0x3c030800, 0xac640064, 0x0e000c7d, 0x00000000, 0x3c026000, 0x8c444448, - 0x3c030800, 0x0a000505, 0xac640068, 0x8f440100, 0x0e000508, 0x00000000, - 0x3c026000, 0x8c444448, 0x3c030800, 0x0a000505, 0xac64006c, 0x0e000cab, - 0x00000000, 0x0a000506, 0x8fbf0010, 0x8f440100, 0x0e000cd5, 0x00000000, - 0x0a000506, 0x8fbf0010, 0x0e000d1c, 0x00000000, 0x0a000506, 0x8fbf0010, - 0x0000000d, 0x0a000506, 0x8fbf0010, 0x0e0005d7, 0x00000000, 0x0a000506, - 0x8fbf0010, 0x8f440100, 0x0e000d7e, 0x00000000, 0x0a000506, 0x8fbf0010, - 0x0e000e95, 0x00000000, 0x0a000506, 0x8fbf0010, 0x0e000626, 0x00000000, - 0x0a000506, 0x8fbf0010, 0x0e000b68, 0x00000000, 0x0a000506, 0x8fbf0010, - 0x0000000d, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x27bdffe8, 0x3c029000, - 0x34420001, 0xafb00010, 0x00808021, 0x02021025, 0x3c038000, 0xafbf0014, - 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93620005, - 0x34420001, 0xa3620005, 0x8f63004c, 0x8f620054, 0x10620019, 0x3c028000, - 0x9762006a, 0x00022880, 0x50a00001, 0x24050001, 0x97630068, 0x93640081, - 0x3c020800, 0x8c46004c, 0x00652821, 0x00852804, 0x00c5102b, 0x54400001, - 0x00a03021, 0x3c020800, 0x8c440050, 0x00c4182b, 0x54600001, 0x00c02021, - 0x8f420074, 0x2403fffe, 0x00832824, 0x00a21021, 0xaf62000c, 0x3c028000, - 0x34420001, 0x02021025, 0x0e000c7d, 0xaf420020, 0x3c029000, 0x34420001, - 0x3c038000, 0x02021025, 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, - 0x3c028000, 0x9363007d, 0x34420001, 0x3c048000, 0x02021025, 0xa363007d, - 0xaf420020, 0x8f4201f8, 0x00441024, 0x1440fffd, 0x8fbf0014, 0xaf5001c0, - 0x8fb00010, 0x24020002, 0x3c031000, 0xa34201c4, 0xaf4301f8, 0x03e00008, - 0x27bd0018, 0x27bdffd8, 0xafbf0020, 0xafb3001c, 0xafb20018, 0xafb10014, - 0xafb00010, 0x93630005, 0x00809021, 0x24020030, 0x30630030, 0x14620072, - 0x00a09821, 0x3c020800, 0x8c430020, 0x1060006c, 0x00000000, 0x0e001006, - 0x00000000, 0x8f820018, 0xac520000, 0x9363003e, 0x9362003f, 0x8f840018, - 0x00031a00, 0x00431025, 0xac820004, 0x93630081, 0x93620082, 0x8f850018, - 0x00031e00, 0x00021400, 0x00621825, 0xaca30008, 0x8f840018, 0x8f620040, - 0xac82000c, 0x8f830018, 0x8f620048, 0xac620010, 0x8f840018, 0x8f62004c, - 0x3c110800, 0xac820014, 0x8f830018, 0x8f620050, 0x26304660, 0x00002021, - 0xac620018, 0x9602000e, 0x8f850018, 0x3c03c00b, 0x00431025, 0x0e001044, - 0xaca2001c, 0x8f830018, 0x8f620054, 0xac620000, 0x8f840018, 0x8f620058, - 0xac820004, 0x8f830018, 0x8f62005c, 0xac620008, 0x8f840018, 0x8f620060, - 0xac82000c, 0x8f850018, 0x8f620064, 0xaca20010, 0x97630068, 0x9762006a, - 0x8f840018, 0x00031c00, 0x00431025, 0xac820014, 0x8f830018, 0x00002021, - 0xac600018, 0x9602000e, 0x8f850018, 0x3c03c00c, 0x00431025, 0x0e001044, - 0xaca2001c, 0x8f840018, 0x8f630018, 0xac830000, 0x936200c4, 0x30420002, - 0x10400006, 0x00000000, 0x976200c8, 0x8f830018, 0x3042ffff, 0x0a0005b5, - 0xac620004, 0x8f820018, 0xac400004, 0x8f830018, 0x8f62006c, 0xac620008, - 0x8f840018, 0x8f6200dc, 0xac82000c, 0x8f830018, 0xac600010, 0x93620005, - 0x8f830018, 0x00021600, 0x00531025, 0xac620014, 0x8f850018, 0x3c026000, - 0x8c434448, 0x24040001, 0x26224660, 0xaca30018, 0x9443000e, 0x8f850018, - 0x3c02400d, 0x00621825, 0x0e001044, 0xaca3001c, 0x0e000d48, 0x02402021, - 0x8fbf0020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x03e00008, - 0x27bd0028, 0x27bdffe0, 0xafb00010, 0x27500100, 0xafbf0018, 0xafb10014, - 0x9603000c, 0x240200c1, 0x5462001d, 0x8e040000, 0x3c029000, 0x8f440100, - 0x34420001, 0x3c038000, 0x00821025, 0xaf420020, 0x8f420020, 0x00431024, - 0x1440fffd, 0x00000000, 0x3c038000, 0x9362007d, 0x34630001, 0x3c058000, - 0x00831825, 0x34420004, 0xa362007d, 0xaf430020, 0x8f4201f8, 0x00451024, - 0x1440fffd, 0x24020002, 0x3c031000, 0xaf4401c0, 0xa34201c4, 0xaf4301f8, - 0x0a000622, 0x8fbf0018, 0x8f65004c, 0x24060001, 0x0e000db5, 0x2407049f, - 0x3c020800, 0x8c430020, 0x9611000c, 0x1060001d, 0x8e100000, 0x0e001006, - 0x00000000, 0x8f820018, 0xac500000, 0x8f840018, 0x00111400, 0xac820004, - 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, - 0x8f840018, 0x240204a2, 0xac820014, 0x8f850018, 0x3c026000, 0x8c434448, - 0x24040001, 0x3c020800, 0xaca30018, 0x9443466e, 0x8f850018, 0x3c024019, - 0x00621825, 0x0e001044, 0xaca3001c, 0x8fbf0018, 0x8fb10014, 0x8fb00010, - 0x03e00008, 0x27bd0020, 0x27bdffb0, 0xafb1002c, 0x27510100, 0xafbf004c, - 0xafbe0048, 0xafb70044, 0xafb60040, 0xafb5003c, 0xafb40038, 0xafb30034, - 0xafb20030, 0xafb00028, 0x8e350000, 0x9634000c, 0x3c026000, 0x8c434448, - 0x0000f021, 0xaf630170, 0x8f620040, 0x8e230014, 0x0000b821, 0x00431023, - 0x044001ec, 0x0000b021, 0x32820010, 0x1040002e, 0x3c026000, 0x9363003f, - 0x9222000e, 0x10430006, 0x2402000c, 0x9223000f, 0x10620003, 0x24020014, - 0x14620025, 0x3c026000, 0x32820004, 0x10400007, 0x241e0001, 0x8f620050, - 0x24420001, 0xaf620050, 0x8f630054, 0x24630001, 0xaf630054, 0x32830102, - 0x24020002, 0x5462000d, 0x9222000f, 0x8f620040, 0x24420001, 0xaf620040, - 0x8f630048, 0x8f620040, 0x24630001, 0x54620005, 0x9222000f, 0x8f620048, - 0x24420001, 0xaf620048, 0x9222000f, 0xa362003f, 0x9223000f, 0x24020012, - 0x14620007, 0x3c026000, 0x3c030800, 0x8c620074, 0x24420001, 0x0e000f6e, - 0xac620074, 0x3c026000, 0x8c434448, 0x32820040, 0xaf630174, 0x32830020, - 0xafa30010, 0x32830080, 0xafa30014, 0x32830001, 0xafa3001c, 0x32830008, - 0xafa30020, 0x32830100, 0x104000bb, 0xafa30018, 0x8e260010, 0x8f630054, - 0x24c2ffff, 0x00431023, 0x18400006, 0x00000000, 0x0000000d, 0x00000000, - 0x24000128, 0x0a0006b2, 0x00009021, 0x8f62004c, 0x00c21023, 0x18400028, - 0x00009021, 0x93650120, 0x93640121, 0x3c030800, 0x8c62008c, 0x308400ff, - 0x24420001, 0x30a500ff, 0x00804021, 0x1485000b, 0xac62008c, 0x3c040800, - 0x8c830090, 0x24630001, 0xac830090, 0x93620122, 0x30420001, 0x00021023, - 0x30420005, 0x0a0006b2, 0x34520004, 0x27670100, 0x00041080, 0x00e21021, - 0x8c430000, 0x00c31823, 0x04600004, 0x24820001, 0x30440007, 0x1485fff9, - 0x00041080, 0x10880007, 0x3c030800, 0xa3640121, 0x8c620094, 0x24120005, - 0x24420001, 0x0a0006b2, 0xac620094, 0x24120004, 0x32420001, 0x10400020, - 0x3c020800, 0x8c430020, 0x8e300000, 0x1060001c, 0x8e330010, 0x0e001006, - 0x00000000, 0x8f820018, 0xac500000, 0x8f840018, 0x24020001, 0xac820004, - 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, - 0x8f820018, 0xac530014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, - 0x3c020800, 0xaca30018, 0x9443466e, 0x8f850018, 0x3c024010, 0x00621825, - 0x0e001044, 0xaca3001c, 0x32420004, 0x10400060, 0x00003821, 0x3c029000, - 0x8e260010, 0x34420001, 0x3c038000, 0x02a21025, 0xa360007c, 0xaf420020, - 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93620023, 0x30420080, - 0x10400011, 0x00000000, 0x8f65005c, 0x8f63004c, 0x9764003c, 0x8f620064, - 0x00a32823, 0x00852821, 0x00a2102b, 0x54400006, 0x3c023fff, 0x93620023, - 0x3042007f, 0xa3620023, 0xaf660064, 0x3c023fff, 0x0a000702, 0x3442ffff, - 0x8f62005c, 0x00c21023, 0x04400011, 0x00000000, 0x8f65005c, 0x8f630064, - 0x9764003c, 0x3c023fff, 0x3442ffff, 0xaf660064, 0x00a32823, 0x00852821, - 0x0045102b, 0x10400004, 0x00c51021, 0x3c053fff, 0x34a5ffff, 0x00c51021, - 0xaf62005c, 0x24070001, 0xaf66004c, 0x8f620054, 0x14c20005, 0x00000000, - 0x93620023, 0x30420040, 0x10400017, 0x24020001, 0x9762006a, 0x00022880, - 0x50a00001, 0x24050001, 0x97630068, 0x93640081, 0x3c020800, 0x8c46004c, - 0x00652821, 0x00852804, 0x00c5102b, 0x54400001, 0x00a03021, 0x3c020800, - 0x8c440050, 0x00c4182b, 0x54600001, 0x00c02021, 0x8f420074, 0x2403fffe, - 0x00832824, 0x00a21021, 0xaf62000c, 0x3c028000, 0x34420001, 0x02a21025, - 0xa3600081, 0xaf420020, 0x9363007e, 0x9362007a, 0x10620005, 0x00e0b021, - 0x0e000f2a, 0x00000000, 0x00403821, 0x00e0b021, 0x8fa20010, 0x10400008, - 0x00000000, 0x8e220018, 0xaf620018, 0x8e23001c, 0xaf63001c, 0x8e220020, - 0x24160001, 0xaf620058, 0x13c00036, 0x32820004, 0x10400035, 0x8fa30014, - 0x93620023, 0x30420040, 0x10400031, 0x3c020800, 0x8c430020, 0x1060001c, - 0x8e300000, 0x0e001006, 0x00000000, 0x8f820018, 0xac500000, 0x8f830018, - 0xac600004, 0x8f820018, 0xac400008, 0x8f830018, 0xac60000c, 0x8f820018, - 0xac400010, 0x8f830018, 0x24020587, 0xac620014, 0x8f850018, 0x3c026000, - 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x9443466e, 0x8f850018, - 0x3c024019, 0x00621825, 0x0e001044, 0xaca3001c, 0x3c029000, 0x34420001, - 0x02a21025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, - 0x24020001, 0xaf62000c, 0x93630023, 0x3c028000, 0x34420001, 0x02a21025, - 0x306300bf, 0xa3630023, 0xaf420020, 0x8fa30014, 0x10600012, 0x8fa3001c, - 0x9362007c, 0x24420001, 0xa362007c, 0x9363007e, 0x9362007a, 0x1462000b, - 0x8fa3001c, 0x9362007c, 0x3c030800, 0x8c640024, 0x0044102b, 0x14400005, - 0x8fa3001c, 0x0e000f2a, 0x00000000, 0x02c2b025, 0x8fa3001c, 0x3062ffff, - 0x10400003, 0x32820200, 0x0a000793, 0x24170004, 0x10400003, 0x00000000, - 0x24170040, 0x24160001, 0x13c0005d, 0x32820002, 0x1040005c, 0x8fa20020, - 0x9222000a, 0x30420020, 0x10400033, 0x3c100800, 0x93620023, 0x30420040, - 0x1040002f, 0x8e020020, 0x1040001e, 0x3c029000, 0x0e001006, 0x00000000, - 0x8f820018, 0xac550000, 0x8f840018, 0x3c02008d, 0xac820004, 0x8f830018, - 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f840018, - 0x240205bf, 0xac820014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, - 0x3c020800, 0xaca30018, 0x9443466e, 0x8f850018, 0x3c024019, 0x00621825, - 0x0e001044, 0xaca3001c, 0x3c029000, 0x34420001, 0x02a21025, 0xaf420020, - 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93630023, - 0x3c028000, 0x34420001, 0x02a21025, 0x306300bf, 0xa3630023, 0xaf420020, - 0x8e020020, 0x10400023, 0x8fa20020, 0x0e001006, 0x00000000, 0x8f840018, - 0x8e230000, 0xac830000, 0x9222000a, 0x8f830018, 0x00021600, 0xac620004, - 0x8f840018, 0x8f620040, 0xac820008, 0x8f850018, 0x8f63004c, 0xaca3000c, - 0x9362003f, 0x8f840018, 0x304200ff, 0xac820010, 0x8f830018, 0x3c026000, - 0xac600014, 0x8f850018, 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, - 0x9443466e, 0x8f850018, 0x3c02401a, 0x00621825, 0x0e001044, 0xaca3001c, - 0x8fa20020, 0x1040000e, 0x8fa20018, 0x9222000a, 0xa3620082, 0x56e00005, - 0x36f70008, 0x8fa30018, 0x10600004, 0x00000000, 0x36f70008, 0x0a000801, - 0x24160001, 0x0e000de1, 0x02a02021, 0x8fa20018, 0x10400003, 0x00000000, - 0x36f70010, 0x24160001, 0x12c00019, 0x3c029000, 0x34420001, 0x02a21025, - 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, - 0x3c038000, 0x9362007d, 0x34630001, 0x3c048000, 0x02a31825, 0x02e21025, - 0xa362007d, 0xaf430020, 0x8f4201f8, 0x00441024, 0x1440fffd, 0x24020002, - 0x3c031000, 0xaf5501c0, 0xa34201c4, 0xaf4301f8, 0x9363003f, 0x24020012, - 0x14620004, 0x3c026000, 0x0e000f6e, 0x00000000, 0x3c026000, 0x8c434448, - 0xaf630178, 0x8fbf004c, 0x8fbe0048, 0x8fb70044, 0x8fb60040, 0x8fb5003c, + 0x00000000, 0x93630023, 0x3c028000, 0x34420001, 0x02821025, 0x34630008, + 0xa3630023, 0xaf420020, 0x92c2000a, 0x30420020, 0x1040008e, 0x8fa2001c, + 0x93620023, 0x30420001, 0x14400035, 0x3c020800, 0x8c430020, 0x10600023, + 0x3c029000, 0x0e00148e, 0x00000000, 0x8f840018, 0x8ec30000, 0xac830000, + 0x92c2000a, 0x8f830018, 0x00021600, 0xac620004, 0x8f840018, 0x8f620040, + 0xac820008, 0x8f850018, 0x8f63004c, 0xaca3000c, 0x9362003f, 0x8f840018, + 0x304200ff, 0xac820010, 0x8f830018, 0x3c026000, 0xac600014, 0x8f850018, + 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, + 0x3c02401a, 0x00621825, 0x0e0014cc, 0xaca3001c, 0x3c029000, 0x34420001, + 0x02821025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, + 0x00000000, 0x93630023, 0x3c028000, 0x34420001, 0x02821025, 0x34630001, + 0xa3630023, 0xaf420020, 0x93620023, 0x30420040, 0x10400052, 0x8fa2001c, + 0x16600020, 0x3c120800, 0x8e420020, 0x8f70004c, 0x1040003c, 0x3c029000, + 0x0e00148e, 0x00000000, 0x8f820018, 0xac540000, 0x8f840018, 0x24020001, + 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, + 0xac600010, 0x8f820018, 0xac500014, 0x8f850018, 0x3c026000, 0x8c434448, + 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, 0x3c024010, + 0x00621825, 0x0e0014cc, 0xaca3001c, 0x8e420020, 0x1040001e, 0x3c029000, + 0x0e00148e, 0x00000000, 0x8f820018, 0xac540000, 0x8f840018, 0x3c02008d, + 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, + 0xac600010, 0x8f840018, 0x240207ee, 0xac820014, 0x8f850018, 0x3c026000, + 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, + 0x3c024019, 0x00621825, 0x0e0014cc, 0xaca3001c, 0x3c029000, 0x34420001, + 0x02821025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, + 0x00000000, 0x93630023, 0x3c028000, 0x34420001, 0x02821025, 0x306300bf, + 0xa3630023, 0xaf420020, 0x8fa2001c, 0x1040000e, 0x8fa20014, 0x92c2000a, + 0xa3620082, 0x57c00005, 0x37de0008, 0x8fa30014, 0x10600004, 0x00000000, + 0x37de0008, 0x0a000b75, 0x24170001, 0x0e0012cf, 0x02802021, 0x8fa20014, + 0x10400003, 0x00000000, 0x37de0010, 0x24170001, 0x12e00020, 0x3c029000, + 0x34420001, 0x02821025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, + 0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000, 0x03c21025, 0xa362007d, + 0x8f640074, 0x34630001, 0x02831825, 0xaf430020, 0x04810006, 0x3c038000, + 0x02802021, 0x0e000470, 0x2405082a, 0x0a000b9b, 0x00000000, 0x8f4201f8, + 0x00431024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf5401c0, 0xa34201c4, + 0xaf4301f8, 0x9363003f, 0x24020012, 0x14620004, 0x8fbf004c, 0x0e00140d, + 0x00000000, 0x8fbf004c, 0x8fbe0048, 0x8fb70044, 0x8fb60040, 0x8fb5003c, 0x8fb40038, 0x8fb30034, 0x8fb20030, 0x8fb1002c, 0x8fb00028, 0x03e00008, 0x27bd0050, 0x27bdffe8, 0xafbf0014, 0xafb00010, 0x8f500180, 0x97420184, 0x30420200, 0x14400015, 0x00000000, 0x8f430188, 0x3c02ff00, 0x00621824, 0x3c020200, 0x10620031, 0x0043102b, 0x14400007, 0x3c020300, 0x1060000b, - 0x3c020100, 0x1062000d, 0x00000000, 0x0a0008b4, 0x00000000, 0x10620027, - 0x3c020400, 0x1062003e, 0x02002021, 0x0a0008b4, 0x00000000, 0x0e000e1e, - 0x02002021, 0x0a0008b6, 0x8fbf0014, 0x93620005, 0x30420020, 0x1440005e, + 0x3c020100, 0x1062000d, 0x00000000, 0x0a000c2c, 0x00000000, 0x10620027, + 0x3c020400, 0x1062003e, 0x02002021, 0x0a000c2c, 0x00000000, 0x0e000c31, + 0x02002021, 0x0a000c2e, 0x8fbf0014, 0x93620005, 0x30420020, 0x1440005e, 0x8fbf0014, 0x3c029000, 0x34420001, 0x02021025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93620005, 0x3c038000, 0x34630001, 0x02031825, 0x34420020, 0xa3620005, 0xaf430020, 0x93620005, - 0x30420020, 0x14400003, 0x02002021, 0x0000000d, 0x02002021, 0x0e000553, - 0x24055854, 0x0a0008b6, 0x8fbf0014, 0x93620005, 0x30420001, 0x1040003f, + 0x30420020, 0x14400003, 0x02002021, 0x0000000d, 0x02002021, 0x0e000766, + 0x24055854, 0x0a000c2e, 0x8fbf0014, 0x93620005, 0x30420001, 0x1040003f, 0x3c029000, 0x34420001, 0x02021025, 0xaf420020, 0x3c038000, 0x8f420020, - 0x00431024, 0x1440fffd, 0x00000000, 0x93620005, 0x3c048000, 0x3c030800, - 0x304200fe, 0xa3620005, 0x8c620020, 0x34840001, 0x02042025, 0xaf440020, - 0x1040002d, 0x8fbf0014, 0x0a000894, 0x00000000, 0x00002821, 0x00003021, - 0x0e000f78, 0x240706a4, 0x3c020800, 0x8c430020, 0x10600023, 0x8fbf0014, - 0x0e001006, 0x00000000, 0x8f820018, 0xac500000, 0x93630082, 0x9362003f, + 0x00431024, 0x1440fffd, 0x00000000, 0x93620023, 0x34420004, 0xa3620023, + 0x93630005, 0x3c048000, 0x3c020800, 0x306300fe, 0xa3630005, 0x8c430020, + 0x34840001, 0x02042025, 0x0a000c0a, 0xaf440020, 0x00002821, 0x00003021, + 0x0e000fb1, 0x240708d9, 0x3c020800, 0x8c430020, 0x10600023, 0x8fbf0014, + 0x0e00148e, 0x00000000, 0x8f820018, 0xac500000, 0x93630082, 0x9362003f, 0x8f840018, 0x00031a00, 0x00431025, 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f820018, 0xac400014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, - 0x9443466e, 0x8f850018, 0x3c02400a, 0x00621825, 0x0e001044, 0xaca3001c, - 0x0a0008b6, 0x8fbf0014, 0x0000000d, 0x8fbf0014, 0x8fb00010, 0x03e00008, - 0x27bd0018, 0x27bdffe8, 0xafbf0010, 0x93420148, 0x2444ffff, 0x2c830005, - 0x10600047, 0x3c020800, 0x24424598, 0x00041880, 0x00621821, 0x8c640000, - 0x00800008, 0x00000000, 0x8f430144, 0x8f62000c, 0x14620006, 0x24020001, - 0xaf62000c, 0x0e000909, 0x00000000, 0x0a000907, 0x8fbf0010, 0x8f62000c, - 0x0a000900, 0x00000000, 0x97630010, 0x8f420144, 0x14430006, 0x24020001, - 0xa7620010, 0x0e000eeb, 0x00000000, 0x0a000907, 0x8fbf0010, 0x97620010, - 0x0a000900, 0x00000000, 0x97630012, 0x8f420144, 0x14430006, 0x24020001, - 0xa7620012, 0x0e000f06, 0x00000000, 0x0a000907, 0x8fbf0010, 0x97620012, - 0x0a000900, 0x00000000, 0x97630014, 0x8f420144, 0x14430006, 0x24020001, - 0xa7620014, 0x0e000f21, 0x00000000, 0x0a000907, 0x8fbf0010, 0x97620014, - 0x0a000900, 0x00000000, 0x97630016, 0x8f420144, 0x14430006, 0x24020001, - 0xa7620016, 0x0e000f24, 0x00000000, 0x0a000907, 0x8fbf0010, 0x97620016, - 0x14400006, 0x8fbf0010, 0x3c030800, 0x8c620070, 0x24420001, 0xac620070, - 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x27bdffe8, 0xafbf0010, 0x93620081, - 0x3c030800, 0x8c640048, 0x0044102b, 0x14400028, 0x3c029000, 0x8f460140, - 0x34420001, 0x3c038000, 0x00c21025, 0xaf420020, 0x8f420020, 0x00431024, - 0x1440fffd, 0x3c048000, 0x34840001, 0x3c059000, 0x34a50001, 0x3c078000, - 0x24020012, 0x24030080, 0x00c42025, 0x00c52825, 0xa362003f, 0xa3630082, - 0xaf440020, 0xaf450020, 0x8f420020, 0x00471024, 0x1440fffd, 0x3c038000, - 0x9362007d, 0x34630001, 0x3c048000, 0x00c31825, 0x34420020, 0xa362007d, - 0xaf430020, 0x8f4201f8, 0x00441024, 0x1440fffd, 0x24020002, 0x3c031000, - 0x0a00096d, 0xaf4601c0, 0x93620081, 0x24420001, 0x0e000f2a, 0xa3620081, - 0x9763006a, 0x00032880, 0x14a00002, 0x00403821, 0x24050001, 0x97630068, + 0x944358ce, 0x8f850018, 0x3c02400a, 0x00621825, 0x0e0014cc, 0xaca3001c, + 0x0a000c2e, 0x8fbf0014, 0x0000000d, 0x8fbf0014, 0x8fb00010, 0x03e00008, + 0x27bd0018, 0x27bdffe8, 0xafbf0010, 0x8f420188, 0x00803021, 0x93640000, + 0x24030020, 0x00021402, 0x10830008, 0x304500ff, 0x3c036018, 0x8c625000, + 0x34420400, 0xac625000, 0x0000000d, 0x00000000, 0x24000955, 0x9363003f, + 0x24020012, 0x14620023, 0x3c029000, 0x34420001, 0x3c038000, 0x00c21025, + 0xaf650178, 0xa365007a, 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, + 0x00000000, 0x9362007d, 0x3c038000, 0xa362007d, 0x8f640074, 0x34630001, + 0x00c31825, 0xaf430020, 0x04810006, 0x3c038000, 0x00c02021, 0x0e000470, + 0x24050963, 0x0a000c79, 0x8fbf0010, 0x8f4201f8, 0x00431024, 0x1440fffd, + 0x24020002, 0x3c031000, 0xaf4601c0, 0xa34201c4, 0xaf4301f8, 0x0a000c79, + 0x8fbf0010, 0x9362007e, 0x1445000e, 0x00000000, 0x8f620178, 0x1045000b, + 0x00000000, 0x8f820000, 0xaf650178, 0x8f660178, 0x8f440180, 0x8f65004c, + 0x8c430000, 0x0060f809, 0x30c600ff, 0x0a000c79, 0x8fbf0010, 0xaf650178, + 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x27bdffe8, 0xafbf0010, 0x93630000, + 0x24020020, 0x10620005, 0x00000000, 0x93630000, 0x24020030, 0x1462004d, + 0x8fbf0010, 0x93420148, 0x2444ffff, 0x2c830005, 0x10600047, 0x3c020800, + 0x24425800, 0x00041880, 0x00621821, 0x8c640000, 0x00800008, 0x00000000, + 0x8f430144, 0x8f62000c, 0x14620006, 0x24020001, 0xaf62000c, 0x0e000d59, + 0x00000000, 0x0a000cd1, 0x8fbf0010, 0x8f62000c, 0x0a000cca, 0x00000000, + 0x97630010, 0x8f420144, 0x14430006, 0x24020001, 0xa7620010, 0x0e00137a, + 0x00000000, 0x0a000cd1, 0x8fbf0010, 0x97620010, 0x0a000cca, 0x00000000, + 0x97630012, 0x8f420144, 0x14430006, 0x24020001, 0xa7620012, 0x0e001395, + 0x00000000, 0x0a000cd1, 0x8fbf0010, 0x97620012, 0x0a000cca, 0x00000000, + 0x97630014, 0x8f420144, 0x14430006, 0x24020001, 0xa7620014, 0x0e0013bb, + 0x00000000, 0x0a000cd1, 0x8fbf0010, 0x97620014, 0x0a000cca, 0x00000000, + 0x97630016, 0x8f420144, 0x14430006, 0x24020001, 0xa7620016, 0x0e0013be, + 0x00000000, 0x0a000cd1, 0x8fbf0010, 0x97620016, 0x14400006, 0x8fbf0010, + 0x3c030800, 0x8c620070, 0x24420001, 0xac620070, 0x8fbf0010, 0x03e00008, + 0x27bd0018, 0x27bdffe0, 0x3c029000, 0xafbf001c, 0xafb20018, 0xafb10014, + 0xafb00010, 0x8f500140, 0x34420001, 0x3c038000, 0x02021025, 0xaf420020, + 0x8f420020, 0x00431024, 0x1440fffd, 0x24020012, 0x24030080, 0xa362003f, + 0xa3630082, 0x93620023, 0x30420040, 0x10400007, 0x00008821, 0x93620023, + 0x24110001, 0x304200bf, 0xa3620023, 0x0a000cf0, 0x3c028000, 0x3c028000, + 0x34420001, 0x3c039000, 0x34630001, 0x3c048000, 0x02021025, 0x02031825, + 0xaf420020, 0xaf430020, 0x8f420020, 0x00441024, 0x1440fffd, 0x00000000, + 0x9362007d, 0x3c038000, 0x34420020, 0xa362007d, 0x8f640074, 0x34630001, + 0x02031825, 0xaf430020, 0x04810006, 0x3c038000, 0x02002021, 0x0e000470, + 0x24050a63, 0x0a000d13, 0x00000000, 0x8f4201f8, 0x00431024, 0x1440fffd, + 0x24020002, 0x3c031000, 0xaf5001c0, 0xa34201c4, 0xaf4301f8, 0x1220003f, + 0x3c120800, 0x8e420020, 0x8f71004c, 0x1040003c, 0x8fbf001c, 0x0e00148e, + 0x00000000, 0x8f820018, 0xac500000, 0x8f840018, 0x24020001, 0xac820004, + 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, + 0x8f820018, 0xac510014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, + 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, 0x3c024010, 0x00621825, + 0x0e0014cc, 0xaca3001c, 0x8e420020, 0x1040001e, 0x8fbf001c, 0x0e00148e, + 0x00000000, 0x8f820018, 0xac500000, 0x8f840018, 0x3c02008d, 0xac820004, + 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, + 0x8f840018, 0x24020a6a, 0xac820014, 0x8f850018, 0x3c026000, 0x8c434448, + 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, 0x3c024019, + 0x00621825, 0x0e0014cc, 0xaca3001c, 0x8fbf001c, 0x8fb20018, 0x8fb10014, + 0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffe8, 0xafbf0010, 0x93620081, + 0x3c030800, 0x8c640048, 0x0044102b, 0x14400005, 0x00000000, 0x0e000cd3, + 0x00000000, 0x0a000da4, 0x8fbf0010, 0x93620081, 0x24420001, 0x0e0013c4, + 0xa3620081, 0x9763006a, 0x00032880, 0x14a00002, 0x00403821, 0x24050001, + 0x97630068, 0x93640081, 0x3c020800, 0x8c46004c, 0x00652821, 0x00852804, + 0x00c5102b, 0x54400001, 0x00a03021, 0x3c020800, 0x8c440050, 0x00c4182b, + 0x54600001, 0x00c02021, 0x8f420074, 0x2403fffe, 0x00832824, 0x00a21021, + 0xaf62000c, 0x10e00021, 0x3c029000, 0x8f450140, 0x34420001, 0x3c038000, + 0x00a21025, 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, + 0x9362007d, 0x3c038000, 0x34420004, 0xa362007d, 0x8f640074, 0x34630001, + 0x00a31825, 0xaf430020, 0x04810006, 0x3c038000, 0x00a02021, 0x0e000470, + 0x24050a92, 0x0a000da4, 0x8fbf0010, 0x8f4201f8, 0x00431024, 0x1440fffd, + 0x24020002, 0x3c031000, 0xaf4501c0, 0xa34201c4, 0xaf4301f8, 0x8fbf0010, + 0x03e00008, 0x27bd0018, 0x27bdffd8, 0xafb3001c, 0x27530100, 0xafbf0024, + 0xafb40020, 0xafb20018, 0xafb10014, 0xafb00010, 0x96620008, 0x3c140800, + 0x8f520100, 0x30420001, 0x104000da, 0x00000000, 0x8e700018, 0x8f630054, + 0x2602ffff, 0x00431023, 0x18400006, 0x00000000, 0x0000000d, 0x00000000, + 0x2400015c, 0x0a000dea, 0x00008821, 0x8f62004c, 0x02021023, 0x18400028, + 0x00008821, 0x93650120, 0x93640121, 0x3c030800, 0x8c62008c, 0x308400ff, + 0x24420001, 0x30a500ff, 0x00803821, 0x1485000b, 0xac62008c, 0x3c040800, + 0x8c830090, 0x24630001, 0xac830090, 0x93620122, 0x30420001, 0x00021023, + 0x30420005, 0x0a000dea, 0x34510004, 0x27660100, 0x00041080, 0x00c21021, + 0x8c430000, 0x02031823, 0x04600004, 0x24820001, 0x30440007, 0x1485fff9, + 0x00041080, 0x10870007, 0x3c030800, 0xa3640121, 0x8c620094, 0x24110005, + 0x24420001, 0x0a000dea, 0xac620094, 0x24110004, 0x32220001, 0x1040001e, + 0x8e820020, 0x1040001d, 0x32220004, 0x0e00148e, 0x00000000, 0x8f820018, + 0xac520000, 0x8f840018, 0x24020001, 0xac820004, 0x8f830018, 0xac600008, + 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f820018, 0xac500014, + 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, + 0x944358ce, 0x8f850018, 0x3c024010, 0x00621825, 0x0e0014cc, 0xaca3001c, + 0x32220004, 0x10400081, 0x00003821, 0x3c029000, 0x34420001, 0x3c038000, + 0x02421025, 0xa360007c, 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, + 0x00000000, 0x93620023, 0x30420080, 0x10400011, 0x00000000, 0x8f65005c, + 0x8f63004c, 0x9764003c, 0x8f620064, 0x00a32823, 0x00852821, 0x00a2102b, + 0x54400006, 0x3c023fff, 0x93620023, 0x3042007f, 0xa3620023, 0xaf700064, + 0x3c023fff, 0x0a000e37, 0x3442ffff, 0x8f62005c, 0x02021023, 0x04400011, + 0x00000000, 0x8f65005c, 0x8f630064, 0x9764003c, 0x3c023fff, 0x3442ffff, + 0xaf700064, 0x00a32823, 0x00852821, 0x0045102b, 0x10400004, 0x02051021, + 0x3c053fff, 0x34a5ffff, 0x02051021, 0xaf62005c, 0x24070001, 0xaf70004c, + 0x8f620054, 0x16020005, 0x00000000, 0x93620023, 0x30420040, 0x10400017, + 0x24020001, 0x9762006a, 0x00022880, 0x50a00001, 0x24050001, 0x97630068, 0x93640081, 0x3c020800, 0x8c46004c, 0x00652821, 0x00852804, 0x00c5102b, 0x54400001, 0x00a03021, 0x3c020800, 0x8c440050, 0x00c4182b, 0x54600001, 0x00c02021, 0x8f420074, 0x2403fffe, 0x00832824, 0x00a21021, 0xaf62000c, - 0x10e0001a, 0x3c029000, 0x8f440140, 0x34420001, 0x3c038000, 0x00821025, - 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x3c038000, - 0x9362007d, 0x34630001, 0x3c058000, 0x00831825, 0x34420004, 0xa362007d, - 0xaf430020, 0x8f4201f8, 0x00451024, 0x1440fffd, 0x24020002, 0x3c031000, - 0xaf4401c0, 0xa34201c4, 0xaf4301f8, 0x8fbf0010, 0x03e00008, 0x27bd0018, - 0x27bdffd8, 0xafb3001c, 0x27530100, 0xafbf0024, 0xafb40020, 0xafb20018, - 0xafb10014, 0xafb00010, 0x96620008, 0x3c140800, 0x8f520100, 0x30420001, - 0x104000cf, 0x00000000, 0x8e700018, 0x8f630054, 0x2602ffff, 0x00431023, - 0x18400006, 0x00000000, 0x0000000d, 0x00000000, 0x24000128, 0x0a0009b6, - 0x00008821, 0x8f62004c, 0x02021023, 0x18400028, 0x00008821, 0x93650120, - 0x93640121, 0x3c030800, 0x8c62008c, 0x308400ff, 0x24420001, 0x30a500ff, - 0x00803821, 0x1485000b, 0xac62008c, 0x3c040800, 0x8c830090, 0x24630001, - 0xac830090, 0x93620122, 0x30420001, 0x00021023, 0x30420005, 0x0a0009b6, - 0x34510004, 0x27660100, 0x00041080, 0x00c21021, 0x8c430000, 0x02031823, - 0x04600004, 0x24820001, 0x30440007, 0x1485fff9, 0x00041080, 0x10870007, - 0x3c030800, 0xa3640121, 0x8c620094, 0x24110005, 0x24420001, 0x0a0009b6, - 0xac620094, 0x24110004, 0x32220001, 0x1040001e, 0x8e820020, 0x1040001d, - 0x32220004, 0x0e001006, 0x00000000, 0x8f820018, 0xac520000, 0x8f840018, - 0x24020001, 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, - 0x8f830018, 0xac600010, 0x8f820018, 0xac500014, 0x8f850018, 0x3c026000, - 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x9443466e, 0x8f850018, - 0x3c024010, 0x00621825, 0x0e001044, 0xaca3001c, 0x32220004, 0x10400076, - 0x00003821, 0x3c029000, 0x34420001, 0x3c038000, 0x02421025, 0xa360007c, - 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93620023, - 0x30420080, 0x10400011, 0x00000000, 0x8f65005c, 0x8f63004c, 0x9764003c, - 0x8f620064, 0x00a32823, 0x00852821, 0x00a2102b, 0x54400006, 0x3c023fff, - 0x93620023, 0x3042007f, 0xa3620023, 0xaf700064, 0x3c023fff, 0x0a000a03, - 0x3442ffff, 0x8f62005c, 0x02021023, 0x04400011, 0x00000000, 0x8f65005c, - 0x8f630064, 0x9764003c, 0x3c023fff, 0x3442ffff, 0xaf700064, 0x00a32823, - 0x00852821, 0x0045102b, 0x10400004, 0x02051021, 0x3c053fff, 0x34a5ffff, - 0x02051021, 0xaf62005c, 0x24070001, 0xaf70004c, 0x8f620054, 0x16020005, - 0x00000000, 0x93620023, 0x30420040, 0x10400017, 0x24020001, 0x9762006a, - 0x00022880, 0x50a00001, 0x24050001, 0x97630068, 0x93640081, 0x3c020800, - 0x8c46004c, 0x00652821, 0x00852804, 0x00c5102b, 0x54400001, 0x00a03021, - 0x3c020800, 0x8c440050, 0x00c4182b, 0x54600001, 0x00c02021, 0x8f420074, - 0x2403fffe, 0x00832824, 0x00a21021, 0xaf62000c, 0x3c028000, 0x34420001, - 0x02421025, 0xa3600081, 0xaf420020, 0x9363007e, 0x9362007a, 0x10620004, - 0x00000000, 0x0e000f2a, 0x00000000, 0x00403821, 0x10e00017, 0x3c029000, + 0x93620082, 0x30420080, 0x50400001, 0xa3600081, 0x3c028000, 0x34420001, + 0x02421025, 0xaf420020, 0x9363007e, 0x9362007a, 0x10620004, 0x00000000, + 0x0e0013c4, 0x00000000, 0x00403821, 0x10e0001f, 0x3c029000, 0x34420001, + 0x02421025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, + 0x00000000, 0x9362007d, 0x3c038000, 0xa362007d, 0x8f640074, 0x34630001, + 0x02431825, 0xaf430020, 0x04810006, 0x3c038000, 0x02402021, 0x0e000470, + 0x24050b3d, 0x0a000e8d, 0x00000000, 0x8f4201f8, 0x00431024, 0x1440fffd, + 0x24020002, 0x3c031000, 0xaf5201c0, 0xa34201c4, 0xaf4301f8, 0x9342010b, + 0x9343010b, 0x8e820020, 0x27500100, 0x38630006, 0x10400029, 0x2c710001, + 0x0e00148e, 0x00000000, 0x8f830018, 0x8e020000, 0xac620000, 0x8f840018, + 0x96020008, 0xac820004, 0x8f830018, 0x8e020014, 0xac620008, 0x8f850018, + 0x3c026000, 0x8c434448, 0xaca3000c, 0x8f840018, 0x96020012, 0xac820010, + 0x8f850018, 0x8e030020, 0xaca30014, 0x9602000c, 0x9603000e, 0x8f840018, + 0x00021400, 0x00431025, 0xac820018, 0x12200005, 0x3c020800, 0x944358ce, + 0x8f840018, 0x0a000eb8, 0x3c024013, 0x944358ce, 0x8f840018, 0x3c024014, + 0x00621825, 0xac83001c, 0x0e0014cc, 0x24040001, 0x8e700014, 0x8f620040, + 0x14500003, 0x00501023, 0x0a000ec3, 0x00001021, 0x28420001, 0x1040003a, + 0x00000000, 0x0e000fae, 0x02002021, 0xaf700040, 0x9362003e, 0x30420001, + 0x1440000b, 0x3c029000, 0x93620022, 0x24420001, 0xa3620022, 0x93630022, + 0x3c020800, 0x8c440098, 0x0064182b, 0x14600025, 0x3c020800, 0x3c029000, 0x34420001, 0x02421025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, - 0x1440fffd, 0x3c028000, 0x9363007d, 0x34420001, 0x3c048000, 0x02421025, - 0xa363007d, 0xaf420020, 0x8f4201f8, 0x00441024, 0x1440fffd, 0x24020002, - 0x3c031000, 0xaf5201c0, 0xa34201c4, 0xaf4301f8, 0x9342010b, 0x8e830020, - 0x27500100, 0x38420006, 0x10600029, 0x2c510001, 0x0e001006, 0x00000000, - 0x8f830018, 0x8e020000, 0xac620000, 0x8f840018, 0x96020008, 0xac820004, - 0x8f830018, 0x8e020014, 0xac620008, 0x8f850018, 0x3c026000, 0x8c434448, - 0xaca3000c, 0x8f840018, 0x96020012, 0xac820010, 0x8f850018, 0x8e030020, - 0xaca30014, 0x9602000c, 0x9603000e, 0x8f840018, 0x00021400, 0x00431025, - 0xac820018, 0x12200005, 0x3c020800, 0x9443466e, 0x8f840018, 0x0a000a78, - 0x3c024013, 0x9443466e, 0x8f840018, 0x3c024014, 0x00621825, 0xac83001c, - 0x0e001044, 0x24040001, 0x8e630014, 0x8f620040, 0x14430003, 0x00431023, - 0x0a000a83, 0x00001021, 0x28420001, 0x10400034, 0x00000000, 0x8f620040, - 0xaf630040, 0x9362003e, 0x30420001, 0x1440000b, 0x3c029000, 0x93620022, - 0x24420001, 0xa3620022, 0x93630022, 0x3c020800, 0x8c440098, 0x0064182b, - 0x1460001e, 0x3c020800, 0x3c029000, 0x34420001, 0x02421025, 0xaf420020, - 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x3c038000, - 0x9362007d, 0x34630001, 0x3c048000, 0x02431825, 0x34420001, 0xa362007d, - 0xaf430020, 0x8f4201f8, 0x00441024, 0x1440fffd, 0x24020002, 0x3c031000, - 0xaf5201c0, 0xa34201c4, 0x24020001, 0xaf4301f8, 0xa7620012, 0x0a000ab6, - 0xa3600022, 0x9743007a, 0x9444002a, 0x00641821, 0x3063fffe, 0xa7630012, - 0x0e000b68, 0x00000000, 0x97420108, 0x8fbf0024, 0x8fb40020, 0x8fb3001c, - 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x00021042, 0x30420001, 0x03e00008, - 0x27bd0028, 0x27bdffe0, 0xafb20018, 0x3c120800, 0x8e420020, 0xafb00010, - 0x27500100, 0xafbf001c, 0x10400046, 0xafb10014, 0x0e001006, 0x00000000, - 0x8f840018, 0x8e020000, 0xac820000, 0x936300b1, 0x936200c5, 0x8f850018, - 0x00031e00, 0x00021400, 0x34420100, 0x00621825, 0xaca30004, 0x8f840018, - 0x8e02001c, 0xac820008, 0x8f830018, 0x8f620048, 0xac62000c, 0x8f840018, - 0x96020012, 0xac820010, 0x8f830018, 0x8f620040, 0x24040001, 0xac620014, - 0x8f850018, 0x3c026000, 0x8c434448, 0x3c020800, 0x24514660, 0xaca30018, - 0x9623000e, 0x8f850018, 0x3c024016, 0x00621825, 0x0e001044, 0xaca3001c, - 0x96030008, 0x30630010, 0x1060001c, 0x8e420020, 0x1040001a, 0x8e100000, - 0x0e001006, 0x00000000, 0x8f820018, 0xac500000, 0x8f830018, 0xac600004, - 0x8f820018, 0xac400008, 0x8f830018, 0xac60000c, 0x8f820018, 0xac400010, - 0x8f830018, 0xac600014, 0x8f850018, 0x3c036000, 0x8c634448, 0x24040001, - 0xaca30018, 0x9622000e, 0x8f850018, 0x3c034015, 0x00431025, 0x0e001044, - 0xaca2001c, 0x00001021, 0x8fbf001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, - 0x03e00008, 0x27bd0020, 0x27bdffe0, 0xafb20018, 0x3c120800, 0x8e420020, - 0xafb00010, 0x27500100, 0xafbf001c, 0x10400041, 0xafb10014, 0x0e001006, - 0x00000000, 0x8f830018, 0x8e020000, 0xac620000, 0x8f840018, 0x24020100, - 0xac820004, 0x8f830018, 0x8e02001c, 0xac620008, 0x8f840018, 0x8e020018, - 0xac82000c, 0x8f830018, 0x96020012, 0xac620010, 0x8f840018, 0x96020008, - 0xac820014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, 0x3c020800, - 0x24514660, 0xaca30018, 0x9623000e, 0x8f850018, 0x3c024017, 0x00621825, - 0x0e001044, 0xaca3001c, 0x96030008, 0x30630010, 0x1060001c, 0x8e420020, - 0x1040001a, 0x8e100000, 0x0e001006, 0x00000000, 0x8f820018, 0xac500000, + 0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000, 0x34420001, 0xa362007d, + 0x8f640074, 0x34630001, 0x02431825, 0xaf430020, 0x04810006, 0x3c038000, + 0x02402021, 0x0e000470, 0x24050273, 0x0a000ef6, 0x24020001, 0x8f4201f8, + 0x00431024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf5201c0, 0xa34201c4, + 0xaf4301f8, 0x24020001, 0xa7620012, 0x0a000efe, 0xa3600022, 0x9743007a, + 0x9444002a, 0x00641821, 0x3063fffe, 0xa7630012, 0x97420108, 0x8fbf0024, + 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x00021042, + 0x30420001, 0x03e00008, 0x27bd0028, 0x27bdffe0, 0xafb20018, 0x3c120800, + 0x8e420020, 0xafb00010, 0x27500100, 0xafbf001c, 0x10400046, 0xafb10014, + 0x0e00148e, 0x00000000, 0x8f840018, 0x8e020000, 0xac820000, 0x936300b1, + 0x936200c5, 0x8f850018, 0x00031e00, 0x00021400, 0x34420100, 0x00621825, + 0xaca30004, 0x8f840018, 0x8e02001c, 0xac820008, 0x8f830018, 0x8f620048, + 0xac62000c, 0x8f840018, 0x96020012, 0xac820010, 0x8f830018, 0x8f620040, + 0x24040001, 0xac620014, 0x8f850018, 0x3c026000, 0x8c434448, 0x3c020800, + 0x245158c0, 0xaca30018, 0x9623000e, 0x8f850018, 0x3c024016, 0x00621825, + 0x0e0014cc, 0xaca3001c, 0x96030008, 0x30630010, 0x1060001c, 0x8e420020, + 0x1040001a, 0x8e100000, 0x0e00148e, 0x00000000, 0x8f820018, 0xac500000, 0x8f830018, 0xac600004, 0x8f820018, 0xac400008, 0x8f830018, 0xac60000c, 0x8f820018, 0xac400010, 0x8f830018, 0xac600014, 0x8f850018, 0x3c036000, 0x8c634448, 0x24040001, 0xaca30018, 0x9622000e, 0x8f850018, 0x3c034015, - 0x00431025, 0x0e001044, 0xaca2001c, 0x00001021, 0x8fbf001c, 0x8fb20018, - 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffe8, 0xafbf0010, - 0x936200c4, 0x30420002, 0x10400019, 0x00000000, 0x936200c5, 0x936300b1, - 0x00431023, 0x304400ff, 0x30830080, 0x10600004, 0x00000000, 0x0000000d, - 0x00000000, 0x24000a6a, 0x93620004, 0x00441023, 0x304400ff, 0x30830080, - 0x10600004, 0x2482ffff, 0x8f650024, 0x0a000b82, 0x00000000, 0x00022b00, - 0x8f620024, 0x0045102b, 0x10400002, 0x00000000, 0x8f650024, 0x8f620048, - 0x8f630040, 0x00431823, 0x0065202b, 0x10800004, 0x00000000, 0x8f620040, - 0x00451021, 0xaf620048, 0x9762003c, 0x0062102b, 0x10400041, 0x8fbf0010, - 0x10a0003f, 0x3c029000, 0x34420001, 0x3c040800, 0x8c830080, 0x8f450100, - 0x3c068000, 0x24630001, 0x00a21025, 0xac830080, 0xaf420020, 0x8f420020, - 0x00461024, 0x1440fffd, 0x3c038000, 0x9362007d, 0x34630001, 0x3c048000, - 0x00a31825, 0x34420004, 0xa362007d, 0xaf430020, 0x8f4201f8, 0x00441024, - 0x1440fffd, 0x24020002, 0x3c030800, 0xaf4501c0, 0xa34201c4, 0x8c640020, - 0x3c021000, 0xaf4201f8, 0x1080001f, 0x8fbf0010, 0x0e001006, 0x00000000, - 0x8f830018, 0x8f420100, 0xac620000, 0x8f840018, 0x8f620040, 0xac820004, - 0x8f850018, 0x8f620048, 0xaca20008, 0x8f830018, 0xac60000c, 0x8f820018, - 0xac400010, 0x8f830018, 0x3c026000, 0xac600014, 0x8f840018, 0x8c434448, - 0x3c020800, 0xac830018, 0x9443466e, 0x8f840018, 0x3c0240c2, 0x00621825, - 0xac83001c, 0x0e001044, 0x24040001, 0x8fbf0010, 0x03e00008, 0x27bd0018, - 0x3c020800, 0x24423958, 0xaf82000c, 0x03e00008, 0x00000000, 0x27bdffe8, - 0xafb00010, 0x27500100, 0xafbf0014, 0x8e02001c, 0x14400003, 0x3c020800, - 0x0000000d, 0x3c020800, 0x8c430020, 0x10600026, 0x00001021, 0x0e001006, - 0x00000000, 0x8f830018, 0x8e020000, 0xac620000, 0x8f840018, 0x8e02001c, - 0xac820004, 0x8f830018, 0xac600008, 0x8f840018, 0x8e020018, 0xac82000c, - 0x8f850018, 0x96020012, 0xaca20010, 0x8f830018, 0x3c106000, 0xac600014, - 0x8f840018, 0x8e024448, 0x3c030800, 0xac820018, 0x9462466e, 0x8f840018, - 0x3c034012, 0x00431025, 0xac82001c, 0x0e001044, 0x24040001, 0x8e036800, - 0x00001021, 0x3c040001, 0x00641825, 0xae036800, 0x0a000c0d, 0x8fbf0014, - 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x3c020800, 0x97430078, - 0x9444002e, 0x00001021, 0x00641821, 0x3063fffe, 0x03e00008, 0xa7630010, - 0x27450100, 0x8f640048, 0x8ca30018, 0x00641023, 0x18400021, 0x00000000, - 0xaf630048, 0x8f620040, 0x9763003c, 0x00821023, 0x0043102a, 0x1040001a, - 0x3c029000, 0x8ca40000, 0x34420001, 0x3c038000, 0x00821025, 0xaf420020, - 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x3c038000, 0x9362007d, - 0x34630001, 0x3c058000, 0x00831825, 0x34420004, 0xa362007d, 0xaf430020, - 0x8f4201f8, 0x00451024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf4401c0, - 0xa34201c4, 0xaf4301f8, 0x03e00008, 0x00001021, 0x8f420100, 0x34420001, - 0xaf4200a4, 0x03e00008, 0x00001021, 0x27bdffe0, 0xafbf0018, 0xafb10014, - 0xafb00010, 0x9362007e, 0x30d000ff, 0x16020029, 0x00808821, 0x93620080, - 0x16020026, 0x00000000, 0x9362007f, 0x16020023, 0x00000000, 0x9362007a, - 0x16020004, 0x00000000, 0x0000000d, 0x00000000, 0x24000771, 0x0e000f49, - 0x00000000, 0x3c039000, 0x34630001, 0x3c048000, 0x02231825, 0xa370007a, - 0xaf430020, 0x8f420020, 0x00441024, 0x1440fffd, 0x3c028000, 0x9363007d, - 0x34420001, 0x3c048000, 0x02221025, 0xa363007d, 0xaf420020, 0x8f4201f8, - 0x00441024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf5101c0, 0xa34201c4, - 0xaf4301f8, 0x0a000c79, 0x8fbf0018, 0x0000000d, 0x00000000, 0x24000781, - 0x8fbf0018, 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x3c020800, + 0x00431025, 0x0e0014cc, 0xaca2001c, 0x00001021, 0x8fbf001c, 0x8fb20018, + 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffe0, 0xafb20018, + 0x3c120800, 0x8e420020, 0xafb00010, 0x27500100, 0xafbf001c, 0x10400041, + 0xafb10014, 0x0e00148e, 0x00000000, 0x8f830018, 0x8e020000, 0xac620000, + 0x8f840018, 0x24020100, 0xac820004, 0x8f830018, 0x8e02001c, 0xac620008, + 0x8f840018, 0x8e020018, 0xac82000c, 0x8f830018, 0x96020012, 0xac620010, + 0x8f840018, 0x96020008, 0xac820014, 0x8f850018, 0x3c026000, 0x8c434448, + 0x24040001, 0x3c020800, 0x245158c0, 0xaca30018, 0x9623000e, 0x8f850018, + 0x3c024017, 0x00621825, 0x0e0014cc, 0xaca3001c, 0x96030008, 0x30630010, + 0x1060001c, 0x8e420020, 0x1040001a, 0x8e100000, 0x0e00148e, 0x00000000, + 0x8f820018, 0xac500000, 0x8f830018, 0xac600004, 0x8f820018, 0xac400008, + 0x8f830018, 0xac60000c, 0x8f820018, 0xac400010, 0x8f830018, 0xac600014, + 0x8f850018, 0x3c036000, 0x8c634448, 0x24040001, 0xaca30018, 0x9622000e, + 0x8f850018, 0x3c034015, 0x00431025, 0x0e0014cc, 0xaca2001c, 0x00001021, + 0x8fbf001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, + 0x27bdfff0, 0x03e00008, 0x27bd0010, 0x27bdffd0, 0xafb10014, 0x00808821, + 0xafb40020, 0x00c0a021, 0xafbf0028, 0xafb50024, 0xafb3001c, 0xafb20018, + 0xafb00010, 0x93620023, 0x00e0a821, 0x30420040, 0x1040003e, 0x30b3ffff, + 0x3c120800, 0x8e420020, 0x1040003a, 0x8f70004c, 0x0e00148e, 0x00000000, + 0x8f820018, 0xac510000, 0x8f840018, 0x24020001, 0xac820004, 0x8f830018, + 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f820018, + 0x24040001, 0xac500014, 0x8f850018, 0x3c026000, 0x8c434448, 0x3c020800, + 0x245058c0, 0xaca30018, 0x9603000e, 0x8f850018, 0x3c024010, 0x00621825, + 0x0e0014cc, 0xaca3001c, 0x8e430020, 0x1060001b, 0x00000000, 0x0e00148e, + 0x00000000, 0x8f820018, 0xac510000, 0x8f840018, 0x3c02008d, 0xac820004, + 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, + 0x8f820018, 0xac550014, 0x8f850018, 0x3c036000, 0x8c634448, 0x24040001, + 0xaca30018, 0x9602000e, 0x8f850018, 0x3c034019, 0x00431025, 0x0e0014cc, + 0xaca2001c, 0x93620023, 0x30420020, 0x14400003, 0x3c120800, 0x1280003f, + 0x3c029000, 0x8e420020, 0x8f70004c, 0x1040003b, 0x3c029000, 0x0e00148e, + 0x00000000, 0x8f820018, 0xac510000, 0x8f840018, 0x24020001, 0xac820004, + 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, + 0x8f820018, 0x24040001, 0xac500014, 0x8f850018, 0x3c026000, 0x8c434448, + 0x3c020800, 0x245058c0, 0xaca30018, 0x9603000e, 0x8f850018, 0x3c024010, + 0x00621825, 0x0e0014cc, 0xaca3001c, 0x8e430020, 0x1060001c, 0x3c029000, + 0x0e00148e, 0x00000000, 0x8f820018, 0xac510000, 0x8f840018, 0x00131400, + 0xac820004, 0x8f830018, 0xac750008, 0x8f820018, 0xac40000c, 0x8f830018, + 0xac600010, 0x8f820018, 0xac400014, 0x8f850018, 0x3c036000, 0x8c634448, + 0x24040001, 0xaca30018, 0x9602000e, 0x8f850018, 0x3c03401b, 0x00431025, + 0x0e0014cc, 0xaca2001c, 0x3c029000, 0x34420001, 0x02221025, 0xaf420020, + 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93630023, + 0x3c028000, 0x34420001, 0x02221025, 0x8fbf0028, 0x8fb50024, 0x8fb40020, + 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3063009f, 0xa3630023, + 0xaf420020, 0x03e00008, 0x27bd0030, 0x27bdffe0, 0xafb10014, 0x27510100, + 0x3c029000, 0x34420001, 0xafb00010, 0x00808021, 0x02021025, 0x3c038000, + 0xafbf0018, 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, + 0xa7600008, 0x8f63005c, 0x3c028000, 0x34420001, 0xaf630148, 0x8f640050, + 0x02021025, 0x3c039000, 0xaf64017c, 0xaf420020, 0x8f450100, 0x34630001, + 0x3c048000, 0x00a31825, 0xaf430020, 0x8f420020, 0x00441024, 0x1440fffd, + 0x00000000, 0x9362007d, 0x3c038000, 0x34420001, 0xa362007d, 0x8f640074, + 0x34630001, 0x00a31825, 0xaf430020, 0x04810006, 0x3c038000, 0x00a02021, + 0x0e000470, 0x24050de5, 0x0a001093, 0x3c020800, 0x8f4201f8, 0x00431024, + 0x1440fffd, 0x24020002, 0x3c031000, 0xaf4501c0, 0xa34201c4, 0xaf4301f8, + 0x3c020800, 0x8c430020, 0x1060001e, 0x8fbf0018, 0x0e00148e, 0x00000000, + 0x8f830018, 0xac700000, 0x9622000c, 0x8f840018, 0x00021400, 0xac820004, + 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, + 0x8f820018, 0xac400014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, + 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, 0x3c02401f, 0x00621825, + 0x0e0014cc, 0xaca3001c, 0x8fbf0018, 0x8fb10014, 0x8fb00010, 0x03e00008, + 0x27bd0020, 0x3c020800, 0x24424c3c, 0xaf82000c, 0x03e00008, 0x00000000, + 0x27bdffe8, 0xafb00010, 0x27500100, 0xafbf0014, 0x8e02001c, 0x14400003, + 0x3c020800, 0x0000000d, 0x3c020800, 0x8c430020, 0x10600020, 0x00001021, + 0x0e00148e, 0x00000000, 0x8f830018, 0x8e020000, 0xac620000, 0x8f840018, + 0x8e02001c, 0xac820004, 0x8f830018, 0xac600008, 0x8f840018, 0x8e020018, + 0xac82000c, 0x8f850018, 0x96020012, 0xaca20010, 0x8f830018, 0x3c026000, + 0xac600014, 0x8f840018, 0x8c434448, 0x3c020800, 0xac830018, 0x944358ce, + 0x8f840018, 0x3c024012, 0x00621825, 0xac83001c, 0x0e0014cc, 0x24040001, + 0x00001021, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x3c020800, + 0x97430078, 0x9444002e, 0x00001021, 0x00641821, 0x3063fffe, 0x03e00008, + 0xa7630010, 0x27bdfff0, 0x00001021, 0x03e00008, 0x27bd0010, 0x8f420100, + 0x34420001, 0xaf4200a4, 0x03e00008, 0x00001021, 0x27bdffe0, 0xafbf0018, + 0xafb10014, 0xafb00010, 0x9362007e, 0x30d000ff, 0x16020031, 0x00808821, + 0x8f620178, 0x1602002e, 0x00000000, 0x9362007f, 0x1602002b, 0x00000000, + 0x9362007a, 0x16020004, 0x00000000, 0x0000000d, 0x00000000, 0x240009d2, + 0x0e0013e6, 0x00000000, 0x3c039000, 0x34630001, 0x3c048000, 0x02231825, + 0xa370007a, 0xaf430020, 0x8f420020, 0x00441024, 0x1440fffd, 0x00000000, + 0x9362007d, 0x3c038000, 0xa362007d, 0x8f640074, 0x34630001, 0x02231825, + 0xaf430020, 0x04810006, 0x3c038000, 0x02202021, 0x0e000470, 0x240509dd, + 0x0a001138, 0x8fbf0018, 0x8f4201f8, 0x00431024, 0x1440fffd, 0x24020002, + 0x3c031000, 0xaf5101c0, 0xa34201c4, 0xaf4301f8, 0x0a001138, 0x8fbf0018, + 0x0000000d, 0x00000000, 0x240009e2, 0x8fbf0018, 0x8fb10014, 0x8fb00010, + 0x03e00008, 0x27bd0020, 0x27bdffe8, 0x30a500ff, 0x3c029000, 0x34420001, + 0x00803821, 0x00e21025, 0x3c038000, 0xafbf0010, 0xaf420020, 0x8f420020, + 0x00431024, 0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000, 0x00a21025, + 0xa362007d, 0x8f640074, 0x34630001, 0x00e31825, 0xaf430020, 0x04810006, + 0x3c038000, 0x00e02021, 0x0e000470, 0x00c02821, 0x0a001161, 0x8fbf0010, + 0x8f4201f8, 0x00431024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf4701c0, + 0xa34201c4, 0xaf4301f8, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x3c020800, 0x8c430020, 0x27bdffe8, 0xafb00010, 0x27500100, 0x10600024, 0xafbf0014, - 0x0e001006, 0x00000000, 0x8f830018, 0x8e020000, 0xac620000, 0x8f840018, + 0x0e00148e, 0x00000000, 0x8f830018, 0x8e020000, 0xac620000, 0x8f840018, 0x8e020004, 0xac820004, 0x8f830018, 0x8e020018, 0xac620008, 0x8f840018, 0x8e03001c, 0xac83000c, 0x9602000c, 0x9203000a, 0x8f840018, 0x00021400, 0x00431025, 0xac820010, 0x8f830018, 0x3c026000, 0xac600014, 0x8f840018, - 0x8c434448, 0xac830018, 0x96020008, 0x3c030800, 0x9464466e, 0x8f850018, - 0x00021400, 0x00441025, 0x24040001, 0x0e001044, 0xaca2001c, 0x8fbf0014, + 0x8c434448, 0xac830018, 0x96020008, 0x3c030800, 0x946458ce, 0x8f850018, + 0x00021400, 0x00441025, 0x24040001, 0x0e0014cc, 0xaca2001c, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x3c020800, 0x8c430020, 0x27bdffe8, - 0xafb00010, 0x27500100, 0x10600020, 0xafbf0014, 0x0e001006, 0x00000000, + 0xafb00010, 0x27500100, 0x10600020, 0xafbf0014, 0x0e00148e, 0x00000000, 0x8f820018, 0xac400000, 0x8f830018, 0xac600004, 0x8f820018, 0xac400008, 0x8f830018, 0xac60000c, 0x9602000c, 0x9603000e, 0x8f840018, 0x00021400, 0x00431025, 0xac820010, 0x8f830018, 0x3c026000, 0xac600014, 0x8f840018, - 0x8c434448, 0xac830018, 0x96020008, 0x3c030800, 0x9464466e, 0x8f850018, - 0x00021400, 0x00441025, 0x24040001, 0x0e001044, 0xaca2001c, 0x8fbf0014, + 0x8c434448, 0xac830018, 0x96020008, 0x3c030800, 0x946458ce, 0x8f850018, + 0x00021400, 0x00441025, 0x24040001, 0x0e0014cc, 0xaca2001c, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x27bdffe8, 0xafb00010, 0x27500100, 0xafbf0014, 0x9602000c, 0x10400024, 0x00802821, 0x3c020800, 0x8c430020, - 0x1060003a, 0x8fbf0014, 0x0e001006, 0x00000000, 0x8f840018, 0x8e030000, + 0x1060003a, 0x8fbf0014, 0x0e00148e, 0x00000000, 0x8f840018, 0x8e030000, 0xac830000, 0x9602000c, 0x8f840018, 0x00021400, 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f820018, 0xac400014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, 0x3c020800, - 0xaca30018, 0x9443466e, 0x8f850018, 0x3c02400b, 0x00621825, 0x0e001044, - 0xaca3001c, 0x0a000d19, 0x8fbf0014, 0x93620005, 0x30420010, 0x14400015, + 0xaca30018, 0x944358ce, 0x8f850018, 0x3c02400b, 0x00621825, 0x0e0014cc, + 0xaca3001c, 0x0a0011ff, 0x8fbf0014, 0x93620005, 0x30420010, 0x14400015, 0x3c029000, 0x34420001, 0x00a21025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x3c038000, 0x93620005, 0x34630001, - 0x00a02021, 0x00a31825, 0x24055852, 0x34420010, 0xa3620005, 0x0e000553, - 0xaf430020, 0x0a000d19, 0x8fbf0014, 0x0000000d, 0x8fbf0014, 0x8fb00010, + 0x00a02021, 0x00a31825, 0x24055852, 0x34420010, 0xa3620005, 0x0e000766, + 0xaf430020, 0x0a0011ff, 0x8fbf0014, 0x0000000d, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x3c020800, 0x8c430020, 0x27bdffe8, 0xafb00010, - 0x27500100, 0x10600022, 0xafbf0014, 0x0e001006, 0x00000000, 0x8f840018, + 0x27500100, 0x10600022, 0xafbf0014, 0x0e00148e, 0x00000000, 0x8f840018, 0x8e020004, 0xac820000, 0x9603000c, 0x9762002c, 0x8f840018, 0x00031c00, 0x00431025, 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f820018, 0xac400014, 0x8f850018, 0x3c026000, - 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x9443466e, 0x8f850018, - 0x3c02400e, 0x00621825, 0x0e001044, 0xaca3001c, 0x0e000d48, 0x8e040000, + 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, + 0x3c02400e, 0x00621825, 0x0e0014cc, 0xaca3001c, 0x0e00122e, 0x8e040000, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x3c038000, 0x8f420278, 0x00431024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf440240, 0xa3420244, 0x03e00008, 0xaf430278, 0x3c020800, 0x8c430020, 0x27bdffe0, 0xafb10014, 0x00808821, 0xafb20018, 0x00c09021, 0xafb00010, 0x30b0ffff, 0x1060001c, - 0xafbf001c, 0x0e001006, 0x00000000, 0x8f820018, 0xac510000, 0x8f840018, + 0xafbf001c, 0x0e00148e, 0x00000000, 0x8f820018, 0xac510000, 0x8f840018, 0x00101400, 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f820018, 0xac520014, 0x8f840018, 0x3c026000, - 0x8c434448, 0x3c020800, 0xac830018, 0x9443466e, 0x8f840018, 0x3c024019, - 0x00621825, 0xac83001c, 0x0e001044, 0x24040001, 0x8fbf001c, 0x8fb20018, + 0x8c434448, 0x3c020800, 0xac830018, 0x944358ce, 0x8f840018, 0x3c024019, + 0x00621825, 0xac83001c, 0x0e0014cc, 0x24040001, 0x8fbf001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffe8, 0x27450100, - 0xafbf0010, 0x94a3000c, 0x240200c1, 0x14620029, 0x00803021, 0x3c029000, + 0xafbf0010, 0x94a3000c, 0x240200c1, 0x14620031, 0x00803021, 0x3c029000, 0x34420001, 0x00c21025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, 0x3c028000, 0x34420001, 0x3c049000, 0x34840001, 0x3c058000, 0x24030012, 0x00c21025, 0x00c42025, 0xa363003f, 0xaf420020, 0xaf440020, - 0x8f420020, 0x00451024, 0x1440fffd, 0x3c038000, 0x9362007d, 0x34630001, - 0x3c048000, 0x00c31825, 0x34420020, 0xa362007d, 0xaf430020, 0x8f4201f8, - 0x00441024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf4601c0, 0xa34201c4, - 0xaf4301f8, 0x0a000db3, 0x8fbf0010, 0x00c02021, 0x94a5000c, 0x24060001, - 0x0e000f78, 0x240706d8, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x3c020800, - 0x8c430020, 0x27bdffe0, 0xafb00010, 0x00808021, 0xafb20018, 0x00a09021, - 0xafb10014, 0x30d100ff, 0x1060001c, 0xafbf001c, 0x0e001006, 0x00000000, - 0x8f820018, 0xac500000, 0x8f840018, 0x24020001, 0xac820004, 0x8f830018, - 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, 0x8f820018, - 0xac520014, 0x8f840018, 0x3c026000, 0x8c434448, 0x3c020800, 0xac830018, - 0x9443466e, 0x8f840018, 0x3c024010, 0x00621825, 0xac83001c, 0x0e001044, - 0x02202021, 0x8fbf001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x03e00008, - 0x27bd0020, 0x27bdffe8, 0xafbf0014, 0xafb00010, 0x93620005, 0x30420001, - 0x10400033, 0x00808021, 0x3c029000, 0x34420001, 0x02021025, 0xaf420020, - 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93620005, - 0x3c048000, 0x3c030800, 0x304200fe, 0xa3620005, 0x8c620020, 0x34840001, - 0x02042025, 0xaf440020, 0x10400020, 0x8fbf0014, 0x0e001006, 0x00000000, - 0x8f820018, 0xac500000, 0x93630082, 0x9362003f, 0x8f840018, 0x00031a00, - 0x00431025, 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, - 0x8f830018, 0xac600010, 0x8f820018, 0xac400014, 0x8f840018, 0x3c026000, - 0x8c434448, 0x3c020800, 0xac830018, 0x9443466e, 0x8f840018, 0x3c02400a, - 0x00621825, 0xac83001c, 0x0e001044, 0x24040001, 0x8fbf0014, 0x8fb00010, - 0x03e00008, 0x27bd0018, 0x27bdffe8, 0xafbf0010, 0x8f420188, 0x00803021, - 0x9364003f, 0x24030012, 0x00021402, 0x1483001c, 0x304500ff, 0x3c029000, - 0x34420001, 0x3c038000, 0x00c21025, 0xa3650080, 0xa365007a, 0xaf420020, - 0x8f420020, 0x00431024, 0x1440fffd, 0x3c028000, 0x9363007d, 0x34420001, - 0x3c048000, 0x00c21025, 0xa363007d, 0xaf420020, 0x8f4201f8, 0x00441024, - 0x1440fffd, 0x24020002, 0x3c031000, 0xaf4601c0, 0xa34201c4, 0xaf4301f8, - 0x0a000e54, 0x8fbf0010, 0x9362007e, 0x1445000e, 0x00000000, 0x93620080, - 0x1045000b, 0x00000000, 0xa3650080, 0x8f820000, 0x93660080, 0x8f440180, - 0x8f65004c, 0x8c430000, 0x0060f809, 0x00000000, 0x0a000e54, 0x8fbf0010, - 0xa3650080, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x3c020800, 0x8c430020, - 0x27bdffe0, 0xafb10014, 0x00808821, 0xafb20018, 0x00a09021, 0xafb00010, - 0x30d000ff, 0x1060002f, 0xafbf001c, 0x0e001006, 0x00000000, 0x8f820018, - 0xac510000, 0x8f830018, 0xac700004, 0x8f820018, 0xac520008, 0x8f830018, - 0xac60000c, 0x8f820018, 0xac400010, 0x9763006a, 0x00032880, 0x50a00001, - 0x24050001, 0x97630068, 0x93640081, 0x3c020800, 0x8c46004c, 0x00652821, - 0x00852804, 0x00c5102b, 0x54400001, 0x00a03021, 0x3c020800, 0x8c440050, - 0x00c4182b, 0x54600001, 0x00c02021, 0x8f830018, 0x2402fffe, 0x00822824, - 0x3c026000, 0xac650014, 0x8f840018, 0x8c434448, 0x3c020800, 0xac830018, - 0x9443466e, 0x8f840018, 0x3c024011, 0x00621825, 0xac83001c, 0x0e001044, - 0x24040001, 0x8fbf001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x03e00008, - 0x27bd0020, 0x27bdffe8, 0xafbf0014, 0xafb00010, 0x8f440100, 0x27500100, - 0x8f650050, 0x0e000c45, 0x9206001b, 0x3c020800, 0x8c430020, 0x1060001d, - 0x8e100018, 0x0e001006, 0x00000000, 0x8f840018, 0x8f420100, 0xac820000, - 0x8f830018, 0xac700004, 0x8f840018, 0x8f620050, 0xac820008, 0x8f830018, - 0xac60000c, 0x8f820018, 0xac400010, 0x8f830018, 0x3c026000, 0xac600014, - 0x8f850018, 0x8c434448, 0x24040001, 0x3c020800, 0xaca30018, 0x9443466e, - 0x8f850018, 0x3c02401c, 0x00621825, 0x0e001044, 0xaca3001c, 0x8fbf0014, - 0x8fb00010, 0x03e00008, 0x27bd0018, 0x3c029000, 0x8f460140, 0x34420001, - 0x3c038000, 0x00c21025, 0xaf420020, 0x8f420020, 0x00431024, 0x1440fffd, - 0x3c048000, 0x34840001, 0x3c059000, 0x34a50001, 0x3c078000, 0x24020012, - 0x24030080, 0x00c42025, 0x00c52825, 0xa362003f, 0xa3630082, 0xaf440020, - 0xaf450020, 0x8f420020, 0x00471024, 0x1440fffd, 0x3c038000, 0x9362007d, - 0x34630001, 0x3c048000, 0x00c31825, 0x34420020, 0xa362007d, 0xaf430020, - 0x8f4201f8, 0x00441024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf4601c0, - 0xa34201c4, 0x03e00008, 0xaf4301f8, 0x8f430238, 0x3c020800, 0x04610013, - 0x8c44009c, 0x2406fffe, 0x3c050800, 0x3c038000, 0x2484ffff, 0x14800009, - 0x00000000, 0x97420078, 0x8ca3007c, 0x24420001, 0x00461024, 0x24630001, - 0xa7620010, 0x03e00008, 0xaca3007c, 0x8f420238, 0x00431024, 0x1440fff3, - 0x2484ffff, 0x8f420140, 0x3c031000, 0xaf420200, 0x03e00008, 0xaf430238, - 0x3c029000, 0x8f440140, 0x34420001, 0x3c038000, 0x00821025, 0xaf420020, - 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x3c038000, 0x9362007d, - 0x34630001, 0x3c058000, 0x00831825, 0x34420001, 0xa362007d, 0xaf430020, - 0x8f4201f8, 0x00451024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf4401c0, - 0xa34201c4, 0x03e00008, 0xaf4301f8, 0x0000000d, 0x03e00008, 0x00000000, - 0x0000000d, 0x03e00008, 0x00000000, 0x24020001, 0x03e00008, 0xa7620010, - 0x9362003f, 0x304400ff, 0x3883000e, 0x2c630001, 0x38820010, 0x2c420001, - 0x00621825, 0x14600003, 0x24020012, 0x14820003, 0x00000000, 0x03e00008, - 0x00001021, 0x9363007e, 0x9362007a, 0x14620006, 0x00000000, 0x9363007e, - 0x24020001, 0x24630001, 0x03e00008, 0xa363007e, 0x9363007e, 0x93620080, - 0x14620004, 0x24020001, 0xa362000b, 0x03e00008, 0x24020001, 0x03e00008, - 0x00001021, 0x9362000b, 0x10400021, 0x00001021, 0xa360000b, 0x9362003f, - 0x304400ff, 0x3883000e, 0x2c630001, 0x38820010, 0x2c420001, 0x00621825, - 0x14600015, 0x00001821, 0x24020012, 0x10820012, 0x00000000, 0x9363007e, - 0x9362007a, 0x14620007, 0x00000000, 0x9362007e, 0x24030001, 0x24420001, - 0xa362007e, 0x03e00008, 0x00601021, 0x9363007e, 0x93620080, 0x14620004, - 0x00001821, 0x24020001, 0xa362000b, 0x24030001, 0x03e00008, 0x00601021, - 0x03e00008, 0x00000000, 0x24040001, 0xaf64000c, 0x8f6300dc, 0x8f6200cc, - 0x50620001, 0xa7640010, 0xa7640012, 0xa7640014, 0x03e00008, 0xa7640016, - 0x27bdffd8, 0xafb00010, 0x00808021, 0xafb3001c, 0x00c09821, 0xafbf0020, - 0xafb20018, 0xafb10014, 0x93620023, 0x00e09021, 0x30420040, 0x10400020, - 0x30b1ffff, 0x3c020800, 0x8c430020, 0x1060001c, 0x00000000, 0x0e001006, - 0x00000000, 0x8f820018, 0xac500000, 0x8f840018, 0x3c02008d, 0xac820004, - 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, - 0x8f820018, 0xac520014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, - 0x3c020800, 0xaca30018, 0x9443466e, 0x8f850018, 0x3c024019, 0x00621825, - 0x0e001044, 0xaca3001c, 0x93620023, 0x30420020, 0x14400003, 0x3c020800, - 0x52600020, 0x3c029000, 0x8c430020, 0x1060001d, 0x3c029000, 0x0e001006, - 0x00000000, 0x8f820018, 0xac500000, 0x8f840018, 0x00111400, 0xac820004, - 0x8f830018, 0xac720008, 0x8f820018, 0xac40000c, 0x8f830018, 0xac600010, - 0x8f820018, 0xac400014, 0x8f850018, 0x3c026000, 0x8c434448, 0x24040001, - 0x3c020800, 0xaca30018, 0x9443466e, 0x8f850018, 0x3c02401b, 0x00621825, - 0x0e001044, 0xaca3001c, 0x3c029000, 0x34420001, 0x02021025, 0xaf420020, - 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x93630023, - 0x3c028000, 0x34420001, 0x02021025, 0x8fbf0020, 0x8fb3001c, 0x8fb20018, - 0x8fb10014, 0x8fb00010, 0x3063009f, 0xa3630023, 0xaf420020, 0x03e00008, - 0x27bd0028, 0x3c020800, 0x8c430020, 0x27bdffe8, 0xafb00010, 0x27500100, - 0x1060001d, 0xafbf0014, 0x0e001006, 0x00000000, 0x8f830018, 0x8e020004, - 0xac620000, 0x8f840018, 0x8e020018, 0xac820004, 0x8f850018, 0x8e020000, - 0xaca20008, 0x8f830018, 0xac60000c, 0x8f820018, 0xac400010, 0x8f830018, - 0xac600014, 0x8f820018, 0xac400018, 0x96030008, 0x3c020800, 0x9444466e, - 0x8f850018, 0x00031c00, 0x00641825, 0x24040001, 0x0e001044, 0xaca3001c, - 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x3c060800, 0x24c54660, - 0x3c02000a, 0x03421821, 0x94640006, 0x94a2000a, 0x00441023, 0x00021400, - 0x00021c03, 0x04610006, 0xa4a40006, 0x0000000d, 0x00000000, 0x2400005a, - 0x0a00101b, 0x24020001, 0x8f820014, 0x0062102b, 0x14400002, 0x00001021, - 0x24020001, 0x304200ff, 0x1040001c, 0x274a0400, 0x3c07000a, 0x3c020800, - 0x24454660, 0x94a9000a, 0x8f880014, 0x03471021, 0x94430006, 0x00402021, - 0xa4a30006, 0x94820006, 0xa4a20006, 0x01221023, 0x00021400, 0x00021403, - 0x04410006, 0x0048102b, 0x0000000d, 0x00000000, 0x2400005a, 0x0a001036, - 0x24020001, 0x14400002, 0x00001021, 0x24020001, 0x304200ff, 0x1440ffec, - 0x03471021, 0x24c44660, 0x8c820010, 0xaf420038, 0x8c830014, 0x3c020005, - 0xaf43003c, 0xaf420030, 0xaf800010, 0xaf8a0018, 0x03e00008, 0x00000000, - 0x27bdffe0, 0x8f820010, 0x8f850018, 0x3c070800, 0x24e84660, 0xafbf001c, - 0xafb20018, 0xafb10014, 0xafb00010, 0x9503000a, 0x8d060014, 0x00009021, - 0x309000ff, 0x00e08821, 0x24420001, 0x24a50020, 0x24630001, 0xaf820010, - 0xaf850018, 0xa503000a, 0x24c30020, 0x3c028000, 0x04c10007, 0xad030014, - 0x00621024, 0x14400005, 0x26224660, 0x8d020010, 0x24420001, 0xad020010, - 0x26224660, 0x9444000a, 0x94450018, 0x0010102b, 0x00a41826, 0x2c630001, - 0x00621825, 0x1060001c, 0x3c030006, 0x8f820010, 0x24120001, 0x00021140, - 0x00431025, 0xaf420030, 0x00000000, 0x00000000, 0x00000000, 0x27450400, - 0x8f420000, 0x30420010, 0x1040fffd, 0x26224660, 0x9444000a, 0x94430018, - 0xaf800010, 0xaf850018, 0x14830012, 0x26274660, 0x0e0010d2, 0x00000000, - 0x1600000e, 0x26274660, 0x0e001006, 0x00000000, 0x0a00108f, 0x26274660, - 0x00041c00, 0x00031c03, 0x00051400, 0x00021403, 0x00621823, 0x18600002, - 0x3c026000, 0xac400808, 0x26274660, 0x94e2000e, 0x94e3000c, 0x24420001, - 0xa4e2000e, 0x3042ffff, 0x50430001, 0xa4e0000e, 0x12000005, 0x3c02000a, - 0x94e2000a, 0xa74200a2, 0x0a0010cc, 0x02401021, 0x03421821, 0x94640006, - 0x94e2000a, 0x00441023, 0x00021400, 0x00021c03, 0x04610006, 0xa4e40006, - 0x0000000d, 0x00000000, 0x2400005a, 0x0a0010ae, 0x24020001, 0x8f820014, - 0x0062102b, 0x14400002, 0x00001021, 0x24020001, 0x304200ff, 0x1040001b, - 0x3c020800, 0x3c06000a, 0x24454660, 0x94a8000a, 0x8f870014, 0x03461021, - 0x94430006, 0x00402021, 0xa4a30006, 0x94820006, 0xa4a20006, 0x01021023, - 0x00021400, 0x00021403, 0x04410006, 0x0047102b, 0x0000000d, 0x00000000, - 0x2400005a, 0x0a0010c8, 0x24020001, 0x14400002, 0x00001021, 0x24020001, - 0x304200ff, 0x1440ffec, 0x03461021, 0x02401021, 0x8fbf001c, 0x8fb20018, - 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x3c020800, 0x24454660, - 0x94a3001a, 0x8ca40024, 0x00403021, 0x000318c0, 0x00832021, 0xaf44003c, - 0x8ca20020, 0xaf420038, 0x3c020050, 0x34420008, 0xaf420030, 0x00000000, - 0x00000000, 0x00000000, 0x8f420000, 0x30420020, 0x1040fffd, 0x00000000, - 0x8f430400, 0x24c64660, 0xacc30010, 0x8f420404, 0x3c030020, 0xacc20014, - 0xaf430030, 0x94c40018, 0x94c3001c, 0x94c2001a, 0x94c5001e, 0x00832021, - 0x24420001, 0xa4c2001a, 0x3042ffff, 0x14450002, 0xa4c40018, 0xa4c0001a, - 0x03e00008, 0x00000000, 0x8f820010, 0x3c030006, 0x00021140, 0x00431025, - 0xaf420030, 0x00000000, 0x00000000, 0x00000000, 0x27430400, 0x8f420000, - 0x30420010, 0x1040fffd, 0x00000000, 0xaf800010, 0xaf830018, 0x03e00008, - 0x00000000, 0x27bdffe8, 0xafb00010, 0x3c100800, 0x26104660, 0x3c05000a, - 0x02002021, 0x03452821, 0xafbf0014, 0x0e001128, 0x2406000a, 0x96020002, - 0x9603001e, 0x3042000f, 0x24420003, 0x00431804, 0x24027fff, 0x0043102b, - 0xaf830014, 0x10400004, 0x00000000, 0x0000000d, 0x00000000, 0x24000043, - 0x0e0010d2, 0x00000000, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, - 0x10c00007, 0x00000000, 0x8ca20000, 0x24c6ffff, 0x24a50004, 0xac820000, - 0x14c0fffb, 0x24840004, 0x03e00008, 0x00000000, 0x0a001137, 0x00a01021, - 0xac860000, 0x24840004, 0x00a01021, 0x1440fffc, 0x24a5ffff, 0x03e00008, - 0x00000000, 0x3c036000, 0x8c642b7c, 0x3c036010, 0x8c6553fc, 0x00041582, - 0x00042302, 0x308403ff, 0x00052d82, 0x00441026, 0x0002102b, 0x0005282b, - 0x00451025, 0x1440000d, 0x3c020050, 0x34420004, 0xaf400038, 0xaf40003c, - 0xaf420030, 0x00000000, 0x00000000, 0x8f420000, 0x30420020, 0x1040fffd, - 0x3c020020, 0xaf420030, 0x0000000d, 0x03e00008, 0x00000000, 0x3c020050, - 0x34420004, 0xaf440038, 0xaf45003c, 0xaf420030, 0x00000000, 0x00000000, - 0x8f420000, 0x30420020, 0x1040fffd, 0x3c020020, 0xaf420030, 0x03e00008, - 0x00000000, 0x00000000 }; - -static u32 bnx2_COM_b06FwData[(0x0/4) + 1] = { 0x00000000 }; -static u32 bnx2_COM_b06FwRodata[(0x18/4) + 1] = { - 0x08002318, 0x08002348, 0x08002378, 0x080023a8, 0x080023d8, 0x00000000, - 0x00000000 }; + 0x8f420020, 0x00451024, 0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000, + 0x34420020, 0xa362007d, 0x8f640074, 0x34630001, 0x00c31825, 0xaf430020, + 0x04810006, 0x3c038000, 0x00c02021, 0x0e000470, 0x24050906, 0x0a0012a1, + 0x8fbf0010, 0x8f4201f8, 0x00431024, 0x1440fffd, 0x24020002, 0x3c031000, + 0xaf4601c0, 0xa34201c4, 0xaf4301f8, 0x0a0012a1, 0x8fbf0010, 0x00c02021, + 0x94a5000c, 0x24060001, 0x0e000fb1, 0x2407090e, 0x8fbf0010, 0x03e00008, + 0x27bd0018, 0x3c020800, 0x8c430020, 0x27bdffe0, 0xafb00010, 0x00808021, + 0xafb20018, 0x00a09021, 0xafb10014, 0x30d100ff, 0x1060001c, 0xafbf001c, + 0x0e00148e, 0x00000000, 0x8f820018, 0xac500000, 0x8f840018, 0x24020001, + 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, + 0xac600010, 0x8f820018, 0xac520014, 0x8f840018, 0x3c026000, 0x8c434448, + 0x3c020800, 0xac830018, 0x944358ce, 0x8f840018, 0x3c024010, 0x00621825, + 0xac83001c, 0x0e0014cc, 0x02202021, 0x8fbf001c, 0x8fb20018, 0x8fb10014, + 0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffe8, 0xafbf0014, 0xafb00010, + 0x93620005, 0x30420001, 0x10400036, 0x00808021, 0x3c029000, 0x34420001, + 0x02021025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, + 0x00000000, 0x93620023, 0x34420004, 0xa3620023, 0x93630005, 0x3c048000, + 0x3c020800, 0x306300fe, 0xa3630005, 0x8c430020, 0x34840001, 0x02042025, + 0xaf440020, 0x10600020, 0x8fbf0014, 0x0e00148e, 0x00000000, 0x8f820018, + 0xac500000, 0x93630082, 0x9362003f, 0x8f840018, 0x00031a00, 0x00431025, + 0xac820004, 0x8f830018, 0xac600008, 0x8f820018, 0xac40000c, 0x8f830018, + 0xac600010, 0x8f820018, 0xac400014, 0x8f840018, 0x3c026000, 0x8c434448, + 0x3c020800, 0xac830018, 0x944358ce, 0x8f840018, 0x3c02400a, 0x00621825, + 0xac83001c, 0x0e0014cc, 0x24040001, 0x8fbf0014, 0x8fb00010, 0x03e00008, + 0x27bd0018, 0x3c020800, 0x8c430020, 0x27bdffe0, 0xafb10014, 0x00808821, + 0xafb20018, 0x00a09021, 0xafb00010, 0x30d000ff, 0x1060002f, 0xafbf001c, + 0x0e00148e, 0x00000000, 0x8f820018, 0xac510000, 0x8f830018, 0xac700004, + 0x8f820018, 0xac520008, 0x8f830018, 0xac60000c, 0x8f820018, 0xac400010, + 0x9763006a, 0x00032880, 0x50a00001, 0x24050001, 0x97630068, 0x93640081, + 0x3c020800, 0x8c46004c, 0x00652821, 0x00852804, 0x00c5102b, 0x54400001, + 0x00a03021, 0x3c020800, 0x8c440050, 0x00c4182b, 0x54600001, 0x00c02021, + 0x8f830018, 0x2402fffe, 0x00822824, 0x3c026000, 0xac650014, 0x8f840018, + 0x8c434448, 0x3c020800, 0xac830018, 0x944358ce, 0x8f840018, 0x3c024011, + 0x00621825, 0xac83001c, 0x0e0014cc, 0x24040001, 0x8fbf001c, 0x8fb20018, + 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x27bdffe8, 0xafbf0014, + 0xafb00010, 0x8f440100, 0x27500100, 0x8f650050, 0x0e0010fc, 0x9206001b, + 0x3c020800, 0x8c430020, 0x1060001d, 0x8e100018, 0x0e00148e, 0x00000000, + 0x8f840018, 0x8f420100, 0xac820000, 0x8f830018, 0xac700004, 0x8f840018, + 0x8f620050, 0xac820008, 0x8f830018, 0xac60000c, 0x8f820018, 0xac400010, + 0x8f830018, 0x3c026000, 0xac600014, 0x8f850018, 0x8c434448, 0x24040001, + 0x3c020800, 0xaca30018, 0x944358ce, 0x8f850018, 0x3c02401c, 0x00621825, + 0x0e0014cc, 0xaca3001c, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, + 0x8f430238, 0x3c020800, 0x04610013, 0x8c44009c, 0x2406fffe, 0x3c050800, + 0x3c038000, 0x2484ffff, 0x14800009, 0x00000000, 0x97420078, 0x8ca3007c, + 0x24420001, 0x00461024, 0x24630001, 0xa7620010, 0x03e00008, 0xaca3007c, + 0x8f420238, 0x00431024, 0x1440fff3, 0x2484ffff, 0x8f420140, 0x3c031000, + 0xaf420200, 0x03e00008, 0xaf430238, 0x27bdffe8, 0x3c029000, 0xafbf0010, + 0x8f450140, 0x34420001, 0x3c038000, 0x00a21025, 0xaf420020, 0x8f420020, + 0x00431024, 0x1440fffd, 0x00000000, 0x9362007d, 0x3c038000, 0x34420001, + 0xa362007d, 0x8f640074, 0x34630001, 0x00a31825, 0xaf430020, 0x04810006, + 0x3c038000, 0x00a02021, 0x0e000470, 0x24050ac7, 0x0a0013b9, 0x8fbf0010, + 0x8f4201f8, 0x00431024, 0x1440fffd, 0x24020002, 0x3c031000, 0xaf4501c0, + 0xa34201c4, 0xaf4301f8, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x0000000d, + 0x03e00008, 0x00000000, 0x0000000d, 0x03e00008, 0x00000000, 0x24020001, + 0x03e00008, 0xa7620010, 0x9362003f, 0x304400ff, 0x3883000e, 0x2c630001, + 0x38820010, 0x2c420001, 0x00621825, 0x14600003, 0x24020012, 0x14820003, + 0x00000000, 0x03e00008, 0x00001021, 0x9363007e, 0x9362007a, 0x14620006, + 0x00000000, 0x9363007e, 0x24020001, 0x24630001, 0x03e00008, 0xa363007e, + 0x9362007e, 0x8f630178, 0x304200ff, 0x14430006, 0x00000000, 0x9363000b, + 0x24020001, 0x24630001, 0x03e00008, 0xa363000b, 0x03e00008, 0x00001021, + 0x9362000b, 0x10400023, 0x00001021, 0xa360000b, 0x9362003f, 0x304400ff, + 0x3883000e, 0x2c630001, 0x38820010, 0x2c420001, 0x00621825, 0x14600017, + 0x00001821, 0x24020012, 0x10820014, 0x00000000, 0x9363007e, 0x9362007a, + 0x14620007, 0x00000000, 0x9362007e, 0x24030001, 0x24420001, 0xa362007e, + 0x03e00008, 0x00601021, 0x9362007e, 0x8f630178, 0x304200ff, 0x14430005, + 0x00001821, 0x9362000b, 0x24030001, 0x24420001, 0xa362000b, 0x03e00008, + 0x00601021, 0x03e00008, 0x00000000, 0x24040001, 0xaf64000c, 0x8f6300dc, + 0x8f6200cc, 0x50620001, 0xa7640010, 0xa7640012, 0xa7640014, 0x03e00008, + 0xa7640016, 0x3c020800, 0x8c430020, 0x27bdffe8, 0x1060001b, 0xafbf0010, + 0x0e00148e, 0x00000000, 0x8f820018, 0xac400000, 0x8f830018, 0xac600004, + 0x8f820018, 0xac400008, 0x8f830018, 0xac60000c, 0x8f820018, 0xac400010, + 0x8f830018, 0x3c026000, 0xac600014, 0x8f840018, 0x8c434448, 0x3c020800, + 0xac830018, 0x944358ce, 0x8f840018, 0x3c024020, 0x00621825, 0xac83001c, + 0x0e0014cc, 0x24040001, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x3c020800, + 0x8c430020, 0x27bdffe0, 0xafb00010, 0x00a08021, 0xafb10014, 0x00c08821, + 0xafb20018, 0x00e09021, 0x1060001e, 0xafbf001c, 0x0e00148e, 0x00000000, + 0x8f840018, 0x8f420100, 0xac820000, 0x8f830018, 0xac700004, 0x8f820018, + 0xac510008, 0x8f830018, 0xac72000c, 0x8f840018, 0x8fa20030, 0xac820010, + 0x8f830018, 0x8fa20034, 0xac620014, 0x8f840018, 0x3c026000, 0x8c434448, + 0x3c020800, 0xac830018, 0x944358ce, 0x8f840018, 0x3c0240c9, 0x00621825, + 0xac83001c, 0x0e0014cc, 0x24040001, 0x8fbf001c, 0x8fb20018, 0x8fb10014, + 0x8fb00010, 0x03e00008, 0x27bd0020, 0x3c020800, 0x8c430020, 0x27bdffe8, + 0xafb00010, 0x27500100, 0x1060001d, 0xafbf0014, 0x0e00148e, 0x00000000, + 0x8f830018, 0x8e020004, 0xac620000, 0x8f840018, 0x8e020018, 0xac820004, + 0x8f850018, 0x8e020000, 0xaca20008, 0x8f830018, 0xac60000c, 0x8f820018, + 0xac400010, 0x8f830018, 0xac600014, 0x8f820018, 0xac400018, 0x96030008, + 0x3c020800, 0x944458ce, 0x8f850018, 0x00031c00, 0x00641825, 0x24040001, + 0x0e0014cc, 0xaca3001c, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, + 0x3c060800, 0x24c558c0, 0x3c02000a, 0x03421821, 0x94640006, 0x94a2000a, + 0x00441023, 0x00021400, 0x00021c03, 0x04610006, 0xa4a40006, 0x0000000d, + 0x00000000, 0x2400005a, 0x0a0014a3, 0x24020001, 0x8f820014, 0x0062102b, + 0x14400002, 0x00001021, 0x24020001, 0x304200ff, 0x1040001c, 0x274a0400, + 0x3c07000a, 0x3c020800, 0x244558c0, 0x94a9000a, 0x8f880014, 0x03471021, + 0x94430006, 0x00402021, 0xa4a30006, 0x94820006, 0xa4a20006, 0x01221023, + 0x00021400, 0x00021403, 0x04410006, 0x0048102b, 0x0000000d, 0x00000000, + 0x2400005a, 0x0a0014be, 0x24020001, 0x14400002, 0x00001021, 0x24020001, + 0x304200ff, 0x1440ffec, 0x03471021, 0x24c458c0, 0x8c820010, 0xaf420038, + 0x8c830014, 0x3c020005, 0xaf43003c, 0xaf420030, 0xaf800010, 0xaf8a0018, + 0x03e00008, 0x00000000, 0x27bdffe0, 0x8f820010, 0x8f850018, 0x3c070800, + 0x24e858c0, 0xafbf001c, 0xafb20018, 0xafb10014, 0xafb00010, 0x9503000a, + 0x8d060014, 0x00009021, 0x309000ff, 0x00e08821, 0x24420001, 0x24a50020, + 0x24630001, 0xaf820010, 0xaf850018, 0xa503000a, 0x24c30020, 0x3c028000, + 0x04c10007, 0xad030014, 0x00621024, 0x14400005, 0x262258c0, 0x8d020010, + 0x24420001, 0xad020010, 0x262258c0, 0x9444000a, 0x94450018, 0x0010102b, + 0x00a41826, 0x2c630001, 0x00621825, 0x1060001c, 0x3c030006, 0x8f820010, + 0x24120001, 0x00021140, 0x00431025, 0xaf420030, 0x00000000, 0x00000000, + 0x00000000, 0x27450400, 0x8f420000, 0x30420010, 0x1040fffd, 0x262258c0, + 0x9444000a, 0x94430018, 0xaf800010, 0xaf850018, 0x14830012, 0x262758c0, + 0x0e00155a, 0x00000000, 0x1600000e, 0x262758c0, 0x0e00148e, 0x00000000, + 0x0a001517, 0x262758c0, 0x00041c00, 0x00031c03, 0x00051400, 0x00021403, + 0x00621823, 0x18600002, 0x3c026000, 0xac400808, 0x262758c0, 0x94e2000e, + 0x94e3000c, 0x24420001, 0xa4e2000e, 0x3042ffff, 0x50430001, 0xa4e0000e, + 0x12000005, 0x3c02000a, 0x94e2000a, 0xa74200a2, 0x0a001554, 0x02401021, + 0x03421821, 0x94640006, 0x94e2000a, 0x00441023, 0x00021400, 0x00021c03, + 0x04610006, 0xa4e40006, 0x0000000d, 0x00000000, 0x2400005a, 0x0a001536, + 0x24020001, 0x8f820014, 0x0062102b, 0x14400002, 0x00001021, 0x24020001, + 0x304200ff, 0x1040001b, 0x3c020800, 0x3c06000a, 0x244558c0, 0x94a8000a, + 0x8f870014, 0x03461021, 0x94430006, 0x00402021, 0xa4a30006, 0x94820006, + 0xa4a20006, 0x01021023, 0x00021400, 0x00021403, 0x04410006, 0x0047102b, + 0x0000000d, 0x00000000, 0x2400005a, 0x0a001550, 0x24020001, 0x14400002, + 0x00001021, 0x24020001, 0x304200ff, 0x1440ffec, 0x03461021, 0x02401021, + 0x8fbf001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, + 0x3c020800, 0x244558c0, 0x94a3001a, 0x8ca40024, 0x00403021, 0x000318c0, + 0x00832021, 0xaf44003c, 0x8ca20020, 0xaf420038, 0x3c020050, 0x34420008, + 0xaf420030, 0x00000000, 0x00000000, 0x00000000, 0x8f420000, 0x30420020, + 0x1040fffd, 0x00000000, 0x8f430400, 0x24c658c0, 0xacc30010, 0x8f420404, + 0x3c030020, 0xacc20014, 0xaf430030, 0x94c40018, 0x94c3001c, 0x94c2001a, + 0x94c5001e, 0x00832021, 0x24420001, 0xa4c2001a, 0x3042ffff, 0x14450002, + 0xa4c40018, 0xa4c0001a, 0x03e00008, 0x00000000, 0x8f820010, 0x3c030006, + 0x00021140, 0x00431025, 0xaf420030, 0x00000000, 0x00000000, 0x00000000, + 0x27430400, 0x8f420000, 0x30420010, 0x1040fffd, 0x00000000, 0xaf800010, + 0xaf830018, 0x03e00008, 0x00000000, 0x27bdffe8, 0xafb00010, 0x3c100800, + 0x261058c0, 0x3c05000a, 0x02002021, 0x03452821, 0xafbf0014, 0x0e0015b0, + 0x2406000a, 0x96020002, 0x9603001e, 0x3042000f, 0x24420003, 0x00431804, + 0x24027fff, 0x0043102b, 0xaf830014, 0x10400004, 0x00000000, 0x0000000d, + 0x00000000, 0x24000043, 0x0e00155a, 0x00000000, 0x8fbf0014, 0x8fb00010, + 0x03e00008, 0x27bd0018, 0x10c00007, 0x00000000, 0x8ca20000, 0x24c6ffff, + 0x24a50004, 0xac820000, 0x14c0fffb, 0x24840004, 0x03e00008, 0x00000000, + 0x0a0015c1, 0x00a01021, 0xac860000, 0x00000000, 0x00000000, 0x24840004, + 0x00a01021, 0x1440fffa, 0x24a5ffff, 0x03e00008, 0x00000000, 0x3c036000, + 0x8c642b7c, 0x3c036010, 0x8c6553fc, 0x00041582, 0x00042302, 0x308403ff, + 0x00052d82, 0x00441026, 0x0002102b, 0x0005282b, 0x00451025, 0x1440000d, + 0x3c020050, 0x34420004, 0xaf400038, 0xaf40003c, 0xaf420030, 0x00000000, + 0x00000000, 0x8f420000, 0x30420020, 0x1040fffd, 0x3c020020, 0xaf420030, + 0x0000000d, 0x03e00008, 0x00000000, 0x3c020050, 0x34420004, 0xaf440038, + 0xaf45003c, 0xaf420030, 0x00000000, 0x00000000, 0x8f420000, 0x30420020, + 0x1040fffd, 0x3c020020, 0xaf420030, 0x03e00008, 0x00000000, 0x00000000}; -static u32 bnx2_COM_b06FwBss[(0x88/4) + 1] = { 0x00000000 }; -static u32 bnx2_COM_b06FwSbss[(0x1c/4) + 1] = { 0x00000000 }; +static u32 bnx2_COM_b06FwData[(0x0/4) + 1] = { 0x0 }; +static u32 bnx2_COM_b06FwRodata[(0x58/4) + 1] = { + 0x08002428, 0x0800245c, 0x0800245c, 0x0800245c, 0x0800245c, 0x0800245c, + 0x08002380, 0x0800245c, 0x080023e4, 0x0800245c, 0x0800231c, 0x0800245c, + 0x0800245c, 0x0800245c, 0x08002328, 0x00000000, 0x08003240, 0x08003270, + 0x080032a0, 0x080032d0, 0x08003300, 0x00000000, 0x00000000 }; +static u32 bnx2_COM_b06FwBss[(0x88/4) + 1] = { 0x0 }; +static u32 bnx2_COM_b06FwSbss[(0x1c/4) + 1] = { 0x0 }; -static int bnx2_RXP_b06FwReleaseMajor = 0x0; +static int bnx2_RXP_b06FwReleaseMajor = 0x1; static int bnx2_RXP_b06FwReleaseMinor = 0x0; static int bnx2_RXP_b06FwReleaseFix = 0x0; -static u32 bnx2_RXP_b06FwStartAddr = 0x08000060; +static u32 bnx2_RXP_b06FwStartAddr = 0x08003104; static u32 bnx2_RXP_b06FwTextAddr = 0x08000000; -static int bnx2_RXP_b06FwTextLen = 0x20b8; -static u32 bnx2_RXP_b06FwDataAddr = 0x080020e0; +static int bnx2_RXP_b06FwTextLen = 0x562c; +static u32 bnx2_RXP_b06FwDataAddr = 0x08005660; static int bnx2_RXP_b06FwDataLen = 0x0; static u32 bnx2_RXP_b06FwRodataAddr = 0x00000000; static int bnx2_RXP_b06FwRodataLen = 0x0; -static u32 bnx2_RXP_b06FwBssAddr = 0x08002100; -static int bnx2_RXP_b06FwBssLen = 0x239c; -static u32 bnx2_RXP_b06FwSbssAddr = 0x080020e0; -static int bnx2_RXP_b06FwSbssLen = 0x14; - -static u32 bnx2_RXP_b06FwText[(0x20b8/4) + 1] = { - 0x0a000018, 0x00000000, 0x00000000, 0x0000000d, 0x72787020, 0x302e362e, - 0x39000000, 0x00060903, 0x00000000, 0x0000000d, 0x00000000, 0x00000000, +static u32 bnx2_RXP_b06FwBssAddr = 0x08005680; +static int bnx2_RXP_b06FwBssLen = 0x1394; +static u32 bnx2_RXP_b06FwSbssAddr = 0x08005660; +static int bnx2_RXP_b06FwSbssLen = 0x18; +static u32 bnx2_RXP_b06FwText[(0x562c/4) + 1] = { + 0x0a000c41, 0x00000000, 0x00000000, 0x0000000d, 0x72787020, 0x322e352e, + 0x38000000, 0x02050803, 0x00000000, 0x0000000d, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c020800, - 0x244220e0, 0x3c030800, 0x2463449c, 0xac400000, 0x0043202b, 0x1480fffd, - 0x24420004, 0x3c1d0800, 0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100060, - 0x3c1c0800, 0x279c20e0, 0x0e000329, 0x00000000, 0x0000000d, 0x8f870008, - 0x2ce20080, 0x10400018, 0x3c030800, 0x24633490, 0x8f460100, 0x00072140, - 0x00831021, 0xac460000, 0x8f450104, 0x00641021, 0xac450004, 0x8f460108, - 0xac460008, 0x8f45010c, 0xac45000c, 0x8f460114, 0xac460010, 0x8f450118, - 0xac450014, 0x8f460124, 0xac460018, 0x8f450128, 0x00641821, 0x24e20001, - 0xaf820008, 0xac65001c, 0x03e00008, 0x00000000, 0x00804021, 0x8f830000, - 0x24070001, 0x3c020001, 0x00621024, 0x10400037, 0x00603021, 0x9742010e, - 0x3c038000, 0x3045ffff, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, - 0xa342018b, 0x8f840004, 0x24020080, 0x24030002, 0xaf420180, 0xa743018c, - 0x10800005, 0xa745018e, 0x9743011c, 0x9742011e, 0x0a000069, 0x00021400, - 0x9743011e, 0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8, 0x8f84000c, - 0x24020003, 0x30838000, 0x1060000d, 0xa7420188, 0x93420116, 0x304200fc, - 0x005a1021, 0x24424004, 0x8c430000, 0x3063ffff, 0x14600005, 0x00000000, - 0x3c02ffff, 0x34427fff, 0x00821024, 0xaf82000c, 0x9782000e, 0x9743010c, - 0x8f440104, 0x3042bfff, 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, - 0xaf4301ac, 0x3c021000, 0xaf4201b8, 0x03e00008, 0x00001021, 0x30c21000, - 0x1040000f, 0x00000000, 0x9742010c, 0x3042fc00, 0x5440000b, 0x24070005, - 0x3c021000, 0x00c21024, 0x10400007, 0x3c030dff, 0x3463ffff, 0x3c020e00, - 0x00c21024, 0x0062182b, 0x54600001, 0x24070005, 0x8f82000c, 0x30434000, - 0x10600016, 0x00404821, 0x3c020f00, 0x00c21024, 0x14400012, 0x00000000, - 0x93420116, 0x34424000, 0x03421821, 0x94650002, 0x2ca21389, 0x1040000b, - 0x3c020800, 0x24422100, 0x00051942, 0x00031880, 0x00621821, 0x30a5001f, - 0x8c640000, 0x24020001, 0x00a21004, 0x00822024, 0x01044025, 0x11000037, - 0x3c021000, 0x9742010e, 0x34e60002, 0x3c038000, 0x24420004, 0x3045ffff, - 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, 0xa342018b, 0x8f840004, - 0x24020180, 0x24030002, 0xaf420180, 0xa743018c, 0x10800005, 0xa745018e, - 0x9743011c, 0x9742011e, 0x0a0000cd, 0x00021400, 0x9743011e, 0x9742011c, - 0x00021400, 0x00621825, 0xaf4301a8, 0x8f84000c, 0x30828000, 0x1040000c, - 0xa7460188, 0x93420116, 0x304200fc, 0x005a1021, 0x24424004, 0x8c430000, - 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff, 0x00821024, 0xaf82000c, - 0x9782000e, 0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00, 0x3084ffff, - 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000, 0xaf4201b8, 0x03e00008, - 0x00001021, 0x00c21024, 0x104000ba, 0x3c020800, 0x8c430030, 0x1060003e, - 0x31224000, 0x1040003c, 0x3c030f00, 0x00c31824, 0x3c020100, 0x0043102b, - 0x14400038, 0x3c030800, 0x9742010e, 0x34e60002, 0x3c038000, 0x24420004, - 0x3045ffff, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, 0xa342018b, - 0x8f840004, 0x24020080, 0x24030002, 0xaf420180, 0xa743018c, 0x10800005, - 0xa745018e, 0x9743011c, 0x9742011e, 0x0a000110, 0x00021400, 0x9743011e, - 0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8, 0x8f84000c, 0x30828000, - 0x1040000c, 0xa7460188, 0x93420116, 0x304200fc, 0x005a1021, 0x24424004, - 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff, 0x00821024, - 0xaf82000c, 0x9782000e, 0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00, - 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000, 0xaf4201b8, - 0x03e00008, 0x00001021, 0x3c030800, 0x8c620024, 0x30420008, 0x1040003d, - 0x34e80002, 0x3c020f00, 0x00c21024, 0x5440003a, 0x3107ffff, 0x9742010c, - 0x30420200, 0x50400036, 0x3107ffff, 0x9742010e, 0x30e6fffb, 0x3c038000, - 0x24420004, 0x3045ffff, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, - 0xa342018b, 0x8f840004, 0x24020180, 0x24030002, 0xaf420180, 0xa743018c, - 0x10800005, 0xa745018e, 0x9743011c, 0x9742011e, 0x0a000153, 0x00021400, - 0x9743011e, 0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8, 0x8f84000c, - 0x30828000, 0x1040000c, 0xa7460188, 0x93420116, 0x304200fc, 0x005a1021, - 0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff, - 0x00821024, 0xaf82000c, 0x9782000e, 0x9743010c, 0x8f440104, 0x3042bfff, - 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000, - 0xaf4201b8, 0x3107ffff, 0x8f820000, 0x3c068000, 0x9743010e, 0x00021442, - 0x30440780, 0x24630004, 0x3065ffff, 0x8f4201b8, 0x00461024, 0x1440fffd, - 0x24020003, 0xa342018b, 0x8f830004, 0x24020002, 0xaf440180, 0xa742018c, - 0x10600005, 0xa745018e, 0x9743011c, 0x9742011e, 0x0a000189, 0x00021400, - 0x9743011e, 0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8, 0x8f84000c, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c020800, 0x24425660, + 0x3c030800, 0x24636a14, 0xac400000, 0x0043202b, 0x1480fffd, 0x24420004, + 0x3c1d0800, 0x37bd7ffc, 0x03a0f021, 0x3c100800, 0x26103104, 0x3c1c0800, + 0x279c5660, 0x0e001035, 0x00000000, 0x0000000d, 0x3c080800, 0x8d023100, + 0x2c420080, 0x50400001, 0xad003100, 0x8d073100, 0x3c040800, 0x24840100, + 0x8f460100, 0x00071840, 0x00671821, 0x00031940, 0x00641021, 0xac460000, + 0x8f450104, 0x00831021, 0xac450004, 0x8f460108, 0xac460008, 0x8f45010c, + 0xac45000c, 0x8f460114, 0xac460010, 0x8f450118, 0xac450014, 0x8f460124, + 0xac460018, 0x8f450128, 0xac45001c, 0x8f464010, 0xac460020, 0x8f454014, + 0xac450024, 0x8f464018, 0xac460028, 0x8f45401c, 0xac45002c, 0x8f464020, + 0xac460030, 0x8f454024, 0xac450034, 0x8f464028, 0xac460038, 0x8f45402c, + 0xac45003c, 0x8f464030, 0xac460040, 0x8f454034, 0xac450044, 0x8f464038, + 0xac460048, 0x8f45403c, 0xac45004c, 0x8f464040, 0xac460050, 0x8f454044, + 0xac450054, 0x8f464048, 0xac460058, 0x8f45404c, 0x24e70001, 0x00402021, + 0xad073100, 0x03e00008, 0xac85005c, 0x8f820004, 0x9743010c, 0x00804821, + 0x00403021, 0x30421000, 0x10400010, 0x306affff, 0x30c20020, 0x1440000e, + 0x24070005, 0x3c021000, 0x00c21024, 0x10400009, 0x3c030dff, 0x3463ffff, + 0x3c020e00, 0x00c21024, 0x0062182b, 0x50600004, 0x24070001, 0x0a000cb1, + 0x3c020800, 0x24070001, 0x3c020800, 0x8c430034, 0x1460001d, 0x00405821, + 0x8f820010, 0x30424000, 0x1440001a, 0x3c020001, 0x3c021f01, 0x00c24024, + 0x3c031000, 0x15030015, 0x3c020001, 0x31420200, 0x54400012, 0x3c020001, + 0x9744010e, 0x24020003, 0xa342018b, 0x97850012, 0x24020002, 0x34e30002, + 0xaf400180, 0xa742018c, 0xa7430188, 0x24840004, 0x30a5bfff, 0xa744018e, + 0xa74501a6, 0xaf4801b8, 0x03e00008, 0x00001021, 0x3c020001, 0x00c21024, + 0x10400039, 0x00000000, 0x9742010e, 0x3c038000, 0x3046ffff, 0x8f4201b8, + 0x00431024, 0x1440fffd, 0x24020003, 0xa342018b, 0x97840006, 0x8f85000c, + 0x24020080, 0x24030002, 0xaf420180, 0xa743018c, 0xa746018e, 0x10a00005, + 0xa7440190, 0x9743011c, 0x9742011e, 0x0a000cec, 0x00021400, 0x9743011e, + 0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8, 0x8f840010, 0x24020003, + 0x30838000, 0x1060000d, 0xa7420188, 0x93420116, 0x304200fc, 0x005a1021, + 0x24424004, 0x8c430000, 0x3063ffff, 0x14600005, 0x00000000, 0x3c02ffff, + 0x34427fff, 0x00821024, 0xaf820010, 0x97820012, 0x9743010c, 0x8f440104, + 0x3042bfff, 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, + 0x3c021000, 0xaf4201b8, 0x03e00008, 0x00001021, 0x8f820010, 0x30434000, + 0x10600016, 0x00404021, 0x3c020f00, 0x00c21024, 0x14400012, 0x00000000, + 0x93420116, 0x34424000, 0x03421821, 0x94650002, 0x2ca21389, 0x1040000b, + 0x3c020800, 0x24425680, 0x00051942, 0x00031880, 0x00621821, 0x30a5001f, + 0x8c640000, 0x24020001, 0x00a21004, 0x00822024, 0x01244825, 0x11200039, + 0x3c021000, 0x9742010e, 0x34e70002, 0x3c038000, 0x24420004, 0x3046ffff, + 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, 0xa342018b, 0x97840006, + 0x8f85000c, 0x24020180, 0x24030002, 0xaf420180, 0xa743018c, 0xa746018e, + 0x10a00005, 0xa7440190, 0x9743011c, 0x9742011e, 0x0a000d41, 0x00021400, + 0x9743011e, 0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8, 0x8f840010, 0x30828000, 0x1040000c, 0xa7470188, 0x93420116, 0x304200fc, 0x005a1021, 0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff, - 0x00821024, 0xaf82000c, 0x9782000e, 0x9743010c, 0x8f440104, 0x3042bfff, + 0x00821024, 0xaf820010, 0x97820012, 0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000, - 0xaf4201b8, 0x03e00008, 0x00001021, 0x8f424000, 0x30420100, 0x104000ef, - 0x3c020800, 0x8c440024, 0x24030001, 0x14830036, 0x00404021, 0x9742010e, - 0x34e50002, 0x3c038000, 0x24420004, 0x3044ffff, 0x8f4201b8, 0x00431024, - 0x1440fffd, 0x24020003, 0xa342018b, 0x8f830004, 0x24020002, 0xaf400180, - 0xa742018c, 0x10600005, 0xa744018e, 0x9743011c, 0x9742011e, 0x0a0001c6, + 0xaf4201b8, 0x03e00008, 0x00001021, 0x00c21024, 0x104000e3, 0x3c020800, + 0x8c430030, 0x10600040, 0x31024000, 0x1040003e, 0x3c030f00, 0x00c31824, + 0x3c020100, 0x0043102b, 0x1440003a, 0x3c030800, 0x9742010e, 0x34e70002, + 0x3c038000, 0x24420004, 0x3046ffff, 0x8f4201b8, 0x00431024, 0x1440fffd, + 0x24020003, 0xa342018b, 0x97840006, 0x8f85000c, 0x24020080, 0x24030002, + 0xaf420180, 0xa743018c, 0xa746018e, 0x10a00005, 0xa7440190, 0x9743011c, + 0x9742011e, 0x0a000d86, 0x00021400, 0x9743011e, 0x9742011c, 0x00021400, + 0x00621825, 0xaf4301a8, 0x8f840010, 0x30828000, 0x1040000c, 0xa7470188, + 0x93420116, 0x304200fc, 0x005a1021, 0x24424004, 0x8c430000, 0x3063ffff, + 0x14600004, 0x3c02ffff, 0x34427fff, 0x00821024, 0xaf820010, 0x97820012, + 0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00, 0x3084ffff, 0x00641825, + 0xa74201a6, 0xaf4301ac, 0x3c021000, 0xaf4201b8, 0x03e00008, 0x00001021, + 0x3c030800, 0x8c620024, 0x30420008, 0x1040003e, 0x34e80002, 0x3c020f00, + 0x00c21024, 0x1440003b, 0x8d620034, 0x31420200, 0x10400038, 0x8d620034, + 0x9742010e, 0x30e7fffb, 0x3c038000, 0x24420004, 0x3046ffff, 0x8f4201b8, + 0x00431024, 0x1440fffd, 0x24020003, 0xa342018b, 0x97840006, 0x8f85000c, + 0x24020180, 0x24030002, 0xaf420180, 0xa743018c, 0xa746018e, 0x10a00005, + 0xa7440190, 0x9743011c, 0x9742011e, 0x0a000dca, 0x00021400, 0x9743011e, + 0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8, 0x8f840010, 0x30828000, + 0x1040000c, 0xa7470188, 0x93420116, 0x304200fc, 0x005a1021, 0x24424004, + 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff, 0x00821024, + 0xaf820010, 0x97820012, 0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00, + 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000, 0xaf4201b8, + 0x8d620034, 0x8f860004, 0x1040001a, 0x30c20100, 0x10400018, 0x3c020f00, + 0x00c21024, 0x3c030200, 0x10430014, 0x00000000, 0x8f82000c, 0x10400004, + 0x00000000, 0x9742011c, 0x0a000df8, 0x3044ffff, 0x9742011e, 0x3044ffff, + 0x3c030800, 0x8c620038, 0x3c030800, 0x2463003c, 0x2442ffff, 0x00822024, + 0x00831821, 0x90620000, 0x24420004, 0x0a000e0d, 0x000229c0, 0x00000000, + 0x00061602, 0x3042000f, 0x000229c0, 0x3c04fc00, 0x00441021, 0x3c030300, + 0x0062182b, 0x50600001, 0x24050800, 0x9742010e, 0x3107ffff, 0x3c038000, + 0x24420004, 0x3046ffff, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, + 0xa342018b, 0x97830006, 0x8f84000c, 0x24020002, 0xaf450180, 0xa742018c, + 0xa746018e, 0x10800005, 0xa7430190, 0x9743011c, 0x9742011e, 0x0a000e26, 0x00021400, 0x9743011e, 0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8, - 0x8f84000c, 0x30828000, 0x1040000c, 0xa7450188, 0x93420116, 0x304200fc, + 0x8f840010, 0x30828000, 0x1040000c, 0xa7470188, 0x93420116, 0x304200fc, 0x005a1021, 0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, - 0x34427fff, 0x00821024, 0xaf82000c, 0x9782000e, 0x9743010c, 0x8f440104, + 0x34427fff, 0x00821024, 0xaf820010, 0x97820012, 0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, - 0x3c021000, 0xaf4201b8, 0x03e00008, 0x00001021, 0x30820001, 0x10400035, - 0x30e90004, 0x9742010e, 0x30e6fffb, 0x3c038000, 0x24420004, 0x3044ffff, - 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, 0xa342018b, 0x8f830004, - 0x24020002, 0xaf400180, 0xa742018c, 0x10600005, 0xa744018e, 0x9743011c, - 0x9742011e, 0x0a0001fe, 0x00021400, 0x9743011e, 0x9742011c, 0x00021400, - 0x00621825, 0xaf4301a8, 0x8f84000c, 0x30828000, 0x1040000c, 0xa7470188, - 0x93420116, 0x304200fc, 0x005a1021, 0x24424004, 0x8c430000, 0x3063ffff, - 0x14600004, 0x3c02ffff, 0x34427fff, 0x00821024, 0xaf82000c, 0x9782000e, - 0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00, 0x3084ffff, 0x00641825, - 0xa74201a6, 0xaf4301ac, 0x3c021000, 0xaf4201b8, 0x30c7ffff, 0x8d020024, - 0x30420004, 0x10400037, 0x8d020024, 0x9742010e, 0x30e6fffb, 0x3c038000, - 0x24420004, 0x3045ffff, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, - 0xa342018b, 0x8f840004, 0x24020100, 0x24030002, 0xaf420180, 0xa743018c, - 0x10800005, 0xa745018e, 0x9743011c, 0x9742011e, 0x0a000237, 0x00021400, - 0x9743011e, 0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8, 0x8f84000c, - 0x30828000, 0x1040000c, 0xa7470188, 0x93420116, 0x304200fc, 0x005a1021, - 0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff, - 0x00821024, 0xaf82000c, 0x9782000e, 0x9743010c, 0x8f440104, 0x3042bfff, - 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000, - 0xaf4201b8, 0x30c7ffff, 0x8d020024, 0x30420008, 0x10400034, 0x00000000, - 0x9742010e, 0x3c038000, 0x24420004, 0x3045ffff, 0x8f4201b8, 0x00431024, - 0x1440fffd, 0x24020003, 0xa342018b, 0x8f840004, 0x24020180, 0x24030002, - 0xaf420180, 0xa743018c, 0x10800005, 0xa745018e, 0x9743011c, 0x9742011e, - 0x0a00026f, 0x00021400, 0x9743011e, 0x9742011c, 0x00021400, 0x00621825, - 0xaf4301a8, 0x8f84000c, 0x30828000, 0x1040000c, 0xa7470188, 0x93420116, + 0x3c021000, 0xaf4201b8, 0x03e00008, 0x00001021, 0x8f424000, 0x30420100, + 0x104000f9, 0x3c020800, 0x8c440024, 0x24030001, 0x14830038, 0x00404821, + 0x9742010e, 0x34e60002, 0x3c038000, 0x24420004, 0x3045ffff, 0x8f4201b8, + 0x00431024, 0x1440fffd, 0x24020003, 0xa342018b, 0x97830006, 0x8f84000c, + 0x24020002, 0xaf400180, 0xa742018c, 0xa745018e, 0x10800005, 0xa7430190, + 0x9743011c, 0x9742011e, 0x0a000e65, 0x00021400, 0x9743011e, 0x9742011c, + 0x00021400, 0x00621825, 0xaf4301a8, 0x8f840010, 0x30828000, 0x1040000c, + 0xa7460188, 0x93420116, 0x304200fc, 0x005a1021, 0x24424004, 0x8c430000, + 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff, 0x00821024, 0xaf820010, + 0x97820012, 0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00, 0x3084ffff, + 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000, 0xaf4201b8, 0x03e00008, + 0x00001021, 0x30820001, 0x10400037, 0x30ea0004, 0x9742010e, 0x30e8fffb, + 0x3c038000, 0x24420004, 0x3045ffff, 0x8f4201b8, 0x00431024, 0x1440fffd, + 0x24020003, 0xa342018b, 0x97830006, 0x8f84000c, 0x24020002, 0xaf400180, + 0xa742018c, 0xa745018e, 0x10800005, 0xa7430190, 0x9743011c, 0x9742011e, + 0x0a000e9f, 0x00021400, 0x9743011e, 0x9742011c, 0x00021400, 0x00621825, + 0xaf4301a8, 0x8f840010, 0x30828000, 0x1040000c, 0xa7470188, 0x93420116, 0x304200fc, 0x005a1021, 0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, - 0x3c02ffff, 0x34427fff, 0x00821024, 0xaf82000c, 0x9782000e, 0x9743010c, + 0x3c02ffff, 0x34427fff, 0x00821024, 0xaf820010, 0x97820012, 0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, - 0xaf4301ac, 0x3c021000, 0xaf4201b8, 0x15200046, 0x00001021, 0x3c038000, - 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020002, 0x24032000, 0xa342018b, - 0xa7430188, 0x3c021000, 0xaf4201b8, 0x03e00008, 0x00001021, 0x3c030800, - 0x8c620024, 0x30420001, 0x10400035, 0x00001021, 0x9742010e, 0x34e50002, - 0x3c038000, 0x24420004, 0x3044ffff, 0x8f4201b8, 0x00431024, 0x1440fffd, - 0x24020003, 0xa342018b, 0x8f830004, 0x24020002, 0xaf400180, 0xa742018c, - 0x10600005, 0xa744018e, 0x9743011c, 0x9742011e, 0x0a0002b5, 0x00021400, - 0x9743011e, 0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8, 0x8f84000c, - 0x30828000, 0x1040000c, 0xa7450188, 0x93420116, 0x304200fc, 0x005a1021, - 0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff, - 0x00821024, 0xaf82000c, 0x9782000e, 0x9743010c, 0x8f440104, 0x3042bfff, - 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000, - 0xaf4201b8, 0x00001021, 0x03e00008, 0x00000000, 0x27bdffe0, 0xafbf0018, - 0xafb10014, 0xafb00010, 0x8f420140, 0xaf420020, 0x8f430148, 0x3c027000, - 0x00621824, 0x3c024000, 0x1062000c, 0x0043102b, 0x14400006, 0x3c025000, - 0x3c023000, 0x1062000b, 0x3c024000, 0x0a00031f, 0x00000000, 0x10620034, - 0x3c024000, 0x0a00031f, 0x00000000, 0x0e00067c, 0x00000000, 0x0a00031f, + 0xaf4301ac, 0x3c021000, 0xaf4201b8, 0x3107ffff, 0x8d220024, 0x30420004, + 0x10400039, 0x8d220024, 0x9742010e, 0x30e8fffb, 0x3c038000, 0x24420004, + 0x3046ffff, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, 0xa342018b, + 0x97840006, 0x8f85000c, 0x24020100, 0x24030002, 0xaf420180, 0xa743018c, + 0xa746018e, 0x10a00005, 0xa7440190, 0x9743011c, 0x9742011e, 0x0a000eda, + 0x00021400, 0x9743011e, 0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8, + 0x8f840010, 0x30828000, 0x1040000c, 0xa7470188, 0x93420116, 0x304200fc, + 0x005a1021, 0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, + 0x34427fff, 0x00821024, 0xaf820010, 0x97820012, 0x9743010c, 0x8f440104, + 0x3042bfff, 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, + 0x3c021000, 0xaf4201b8, 0x3107ffff, 0x8d220024, 0x30420008, 0x10400036, + 0x00000000, 0x9742010e, 0x3c038000, 0x24420004, 0x3046ffff, 0x8f4201b8, + 0x00431024, 0x1440fffd, 0x24020003, 0xa342018b, 0x97840006, 0x8f85000c, + 0x24020180, 0x24030002, 0xaf420180, 0xa743018c, 0xa746018e, 0x10a00005, + 0xa7440190, 0x9743011c, 0x9742011e, 0x0a000f14, 0x00021400, 0x9743011e, + 0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8, 0x8f840010, 0x30828000, + 0x1040000c, 0xa7470188, 0x93420116, 0x304200fc, 0x005a1021, 0x24424004, + 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff, 0x00821024, + 0xaf820010, 0x97820012, 0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00, + 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000, 0xaf4201b8, + 0x1540004a, 0x00001021, 0x27440180, 0x3c038000, 0x8f4201b8, 0x00431024, + 0x1440fffd, 0x24022000, 0x24030002, 0xa4820008, 0xa083000b, 0xa4800010, + 0x3c021000, 0xaf4201b8, 0x03e00008, 0x00001021, 0x3c030800, 0x8c620024, + 0x30420001, 0x10400037, 0x00001021, 0x9742010e, 0x34e60002, 0x3c038000, + 0x24420004, 0x3045ffff, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, + 0xa342018b, 0x97830006, 0x8f84000c, 0x24020002, 0xaf400180, 0xa742018c, + 0xa745018e, 0x10800005, 0xa7430190, 0x9743011c, 0x9742011e, 0x0a000f5e, + 0x00021400, 0x9743011e, 0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8, + 0x8f840010, 0x30828000, 0x1040000c, 0xa7460188, 0x93420116, 0x304200fc, + 0x005a1021, 0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, + 0x34427fff, 0x00821024, 0xaf820010, 0x97820012, 0x9743010c, 0x8f440104, + 0x3042bfff, 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, + 0x3c021000, 0xaf4201b8, 0x00001021, 0x03e00008, 0x00000000, 0x27bdffe8, + 0xafbf0010, 0x8f460128, 0x8f84000c, 0xaf460020, 0x8f450104, 0x8f420100, + 0x24030800, 0xaf850004, 0xaf820010, 0xaf4301b8, 0x1080000a, 0x3c020800, + 0x8c430034, 0x10600007, 0x30a22000, 0x10400005, 0x34a30100, 0x8f820008, + 0xaf830004, 0x24420001, 0xaf820008, 0x3c020800, 0x8c4300c0, 0x10600006, + 0x3c030800, 0x8c6200c4, 0x24040001, 0x24420001, 0x0a000fc0, 0xac6200c4, + 0x8f820004, 0x3c030010, 0x00431024, 0x14400009, 0x3c02001f, 0x3c030800, + 0x8c620020, 0x00002021, 0x24420001, 0x0e000c99, 0xac620020, 0x0a000fc0, + 0x00402021, 0x3442ff00, 0x14c20009, 0x2403bfff, 0x3c030800, 0x8c620020, + 0x24040001, 0x24420001, 0x0e000c99, 0xac620020, 0x0a000fc0, 0x00402021, + 0x8f820010, 0x00431024, 0x14400006, 0x00000000, 0xaf400048, 0x0e001144, + 0xaf400040, 0x0a000fc0, 0x00402021, 0x0e0014c9, 0x00000000, 0x00402021, + 0x10800005, 0x3c024000, 0x8f430124, 0x3c026020, 0xac430014, 0x3c024000, + 0xaf420138, 0x00000000, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x27bdffe0, + 0xafbf0018, 0xafb10014, 0xafb00010, 0x8f420140, 0xaf420020, 0x8f430148, + 0x3c027000, 0x00621824, 0x3c023000, 0x10620021, 0x0043102b, 0x14400006, + 0x3c024000, 0x3c022000, 0x10620009, 0x3c024000, 0x0a00102b, 0x00000000, + 0x10620045, 0x3c025000, 0x10620047, 0x3c024000, 0x0a00102b, 0x00000000, + 0x27440180, 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000, + 0x8f420148, 0x24030002, 0xa083000b, 0x00021402, 0xa4820008, 0x8f430148, + 0xa4830010, 0x8f420144, 0x3c031000, 0xac820024, 0xaf4301b8, 0x0a00102b, 0x3c024000, 0x8f420148, 0x24030002, 0x3044ffff, 0x00021402, 0x305000ff, 0x1203000c, 0x27510180, 0x2a020003, 0x10400005, 0x24020003, 0x0600001d, - 0x36053000, 0x0a00030a, 0x3c038000, 0x12020007, 0x00000000, 0x0a000317, - 0x00000000, 0x0e000423, 0x00000000, 0x0a000308, 0x00402021, 0x0e000435, + 0x36053000, 0x0a001012, 0x3c038000, 0x12020007, 0x00000000, 0x0a00101f, + 0x00000000, 0x0e00111f, 0x00000000, 0x0a001010, 0x00402021, 0x0e001131, 0x00000000, 0x00402021, 0x36053000, 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020002, 0xa6250008, 0xa222000b, 0xa6240010, 0x8f420144, - 0x3c031000, 0xae220024, 0xaf4301b8, 0x0a00031f, 0x3c024000, 0x0000000d, - 0x00000000, 0x240001c3, 0x0a00031f, 0x3c024000, 0x0e0007f7, 0x00000000, - 0x3c024000, 0xaf420178, 0x00000000, 0x8fbf0018, 0x8fb10014, 0x8fb00010, - 0x03e00008, 0x27bd0020, 0x24020800, 0x03e00008, 0xaf4201b8, 0x27bdffe8, - 0x3c04600c, 0xafbf0014, 0xafb00010, 0x8c825000, 0x3c1a8000, 0x2403ff7f, - 0x3c106000, 0x00431024, 0x3442380c, 0x24030003, 0xac825000, 0x3c040008, - 0xaf430008, 0x8e020808, 0x3c030800, 0xac600020, 0x3042fff0, 0x2c420001, - 0xaf820004, 0x0e000819, 0x0344d825, 0x0e000781, 0x00000000, 0x3c020400, - 0x3442000c, 0x3c03ffff, 0x34630806, 0xae021948, 0xae03194c, 0x8e021980, - 0x34420200, 0xae021980, 0x8f500000, 0x32020003, 0x1040fffd, 0x32020001, - 0x10400004, 0x32020002, 0x0e0003bd, 0x00000000, 0x32020002, 0x1040fff6, - 0x00000000, 0x0e0002d4, 0x00000000, 0x0a00034a, 0x00000000, 0x27bdffe8, - 0x3c04600c, 0xafbf0014, 0xafb00010, 0x8c825000, 0x3c1a8000, 0x2403ff7f, - 0x3c106000, 0x00431024, 0x3442380c, 0x24030003, 0xac825000, 0x3c040008, - 0xaf430008, 0x8e020808, 0x3c030800, 0xac600020, 0x3042fff0, 0x2c420001, - 0xaf820004, 0x0e000819, 0x0344d825, 0x0e000781, 0x00000000, 0x3c020400, - 0x3442000c, 0x3c03ffff, 0x34630806, 0xae021948, 0xae03194c, 0x8e021980, - 0x8fbf0014, 0x34420200, 0xae021980, 0x8fb00010, 0x03e00008, 0x27bd0018, - 0x30a5ffff, 0x30c6ffff, 0x30e7ffff, 0x3c038000, 0x8f4201b8, 0x00431024, - 0x1440fffd, 0x24020003, 0xa342018b, 0x8f830004, 0xaf440180, 0xa745018c, - 0x10600005, 0xa746018e, 0x9743011c, 0x9742011e, 0x0a000393, 0x00021400, - 0x9743011e, 0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8, 0x8f84000c, + 0x3c031000, 0xae220024, 0xaf4301b8, 0x0a00102b, 0x3c024000, 0x0000000d, + 0x00000000, 0x24000295, 0x0a00102b, 0x3c024000, 0x0e0013a7, 0x00000000, + 0x0a00102b, 0x3c024000, 0x0e001552, 0x00000000, 0x3c024000, 0xaf420178, + 0x00000000, 0x8fbf0018, 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, + 0x24020800, 0x03e00008, 0xaf4201b8, 0x27bdffe8, 0x3c04600c, 0xafbf0014, + 0xafb00010, 0x8c825000, 0x3c1a8000, 0x2403ff7f, 0x3c106000, 0x00431024, + 0x3442380c, 0x24030003, 0xac825000, 0x3c020008, 0xaf430008, 0x8e040808, + 0x0342d825, 0x8e020808, 0x3c030800, 0xac600020, 0x3084fff0, 0x2c840001, + 0x3042fff0, 0x38420010, 0x2c420001, 0xaf84000c, 0xaf820000, 0x0e001574, + 0x00000000, 0x0e0014c7, 0x00000000, 0x3c020400, 0x3442000c, 0x3c03ffff, + 0x34630806, 0xae021948, 0xae03194c, 0x8e021980, 0x34420200, 0xae021980, + 0x8f500000, 0x32020003, 0x1040fffd, 0x32020001, 0x10400004, 0x32020002, + 0x0e000f7d, 0x00000000, 0x32020002, 0x1040fff6, 0x00000000, 0x0e000fcb, + 0x00000000, 0x0a00105c, 0x00000000, 0x27bdffe8, 0x3c04600c, 0xafbf0014, + 0xafb00010, 0x8c825000, 0x3c1a8000, 0x2403ff7f, 0x3c106000, 0x00431024, + 0x3442380c, 0x24030003, 0xac825000, 0x3c020008, 0xaf430008, 0x8e040808, + 0x0342d825, 0x8e020808, 0x3c030800, 0xac600020, 0x3084fff0, 0x2c840001, + 0x3042fff0, 0x38420010, 0x2c420001, 0xaf84000c, 0xaf820000, 0x0e001574, + 0x00000000, 0x0e0014c7, 0x00000000, 0x3c020400, 0x3442000c, 0x3c03ffff, + 0x34630806, 0xae021948, 0xae03194c, 0x8e021980, 0x8fbf0014, 0x34420200, + 0xae021980, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x30a5ffff, 0x30c6ffff, + 0x30e7ffff, 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020003, + 0xa342018b, 0x97830006, 0x8f82000c, 0xaf440180, 0xa745018c, 0xa746018e, + 0x10400005, 0xa7430190, 0x9743011c, 0x9742011e, 0x0a0010ad, 0x00021400, + 0x9743011e, 0x9742011c, 0x00021400, 0x00621825, 0xaf4301a8, 0x8f840010, 0x30828000, 0x1040000c, 0xa7470188, 0x93420116, 0x304200fc, 0x005a1021, 0x24424004, 0x8c430000, 0x3063ffff, 0x14600004, 0x3c02ffff, 0x34427fff, - 0x00821024, 0xaf82000c, 0x9782000e, 0x9743010c, 0x8f440104, 0x3042bfff, + 0x00821024, 0xaf820010, 0x97820012, 0x9743010c, 0x8f440104, 0x3042bfff, 0x00031c00, 0x3084ffff, 0x00641825, 0xa74201a6, 0xaf4301ac, 0x3c021000, - 0xaf4201b8, 0x03e00008, 0x00000000, 0x3c038000, 0x8f4201b8, 0x00431024, - 0x1440fffd, 0x24020002, 0x24032000, 0xa342018b, 0xa7430188, 0x3c021000, - 0xaf4201b8, 0x03e00008, 0x00000000, 0x27bdffe8, 0xafbf0010, 0x8f460128, - 0xaf460020, 0x8f420104, 0x8f450100, 0x24030800, 0x3c040010, 0xaf820000, - 0x00441024, 0xaf85000c, 0xaf4301b8, 0x14400005, 0x3c02001f, 0x3c030800, - 0x8c620020, 0x0a0003d5, 0x00002021, 0x3442ff00, 0x14c20009, 0x2402bfff, - 0x3c030800, 0x8c620020, 0x24040001, 0x24420001, 0x0e00004c, 0xac620020, - 0x0a0003e4, 0x00000000, 0x00a21024, 0x14400006, 0x00000000, 0xaf400048, - 0x0e000448, 0xaf400040, 0x0a0003e4, 0x00000000, 0x0e000783, 0x00000000, - 0x10400005, 0x3c024000, 0x8f430124, 0x3c026020, 0xac430014, 0x3c024000, - 0xaf420138, 0x00000000, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x27bdffe0, + 0xaf4201b8, 0x03e00008, 0x00000000, 0x27440180, 0x3c038000, 0x8f4201b8, + 0x00431024, 0x1440fffd, 0x24022000, 0x24030002, 0xa4820008, 0xa083000b, + 0xa4800010, 0x3c021000, 0xaf4201b8, 0x03e00008, 0x00000000, 0x27440180, + 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000, 0x8f420148, + 0x24030002, 0xa083000b, 0x00021402, 0xa4820008, 0x8f430148, 0xa4830010, + 0x8f420144, 0x3c031000, 0xac820024, 0x03e00008, 0xaf4301b8, 0x27bdffe0, 0xafbf0018, 0xafb10014, 0xafb00010, 0x8f420148, 0x24030002, 0x3044ffff, 0x00021402, 0x305000ff, 0x1203000c, 0x27510180, 0x2a020003, 0x10400005, - 0x24020003, 0x0600001d, 0x36053000, 0x0a00040e, 0x3c038000, 0x12020007, - 0x00000000, 0x0a00041b, 0x00000000, 0x0e000423, 0x00000000, 0x0a00040c, - 0x00402021, 0x0e000435, 0x00000000, 0x00402021, 0x36053000, 0x3c038000, + 0x24020003, 0x0600001d, 0x36053000, 0x0a00110a, 0x3c038000, 0x12020007, + 0x00000000, 0x0a001117, 0x00000000, 0x0e00111f, 0x00000000, 0x0a001108, + 0x00402021, 0x0e001131, 0x00000000, 0x00402021, 0x36053000, 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020002, 0xa6250008, 0xa222000b, - 0xa6240010, 0x8f420144, 0x3c031000, 0xae220024, 0xaf4301b8, 0x0a00041f, - 0x8fbf0018, 0x0000000d, 0x00000000, 0x240001c3, 0x8fbf0018, 0x8fb10014, + 0xa6240010, 0x8f420144, 0x3c031000, 0xae220024, 0xaf4301b8, 0x0a00111b, + 0x8fbf0018, 0x0000000d, 0x00000000, 0x24000295, 0x8fbf0018, 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x3084ffff, 0x2c821389, 0x1040000d, - 0x00001021, 0x3c030800, 0x24632100, 0x00042942, 0x00052880, 0x00a32821, + 0x00001021, 0x3c030800, 0x24635680, 0x00042942, 0x00052880, 0x00a32821, 0x3086001f, 0x8ca40000, 0x24030001, 0x00c31804, 0x00832025, 0x03e00008, 0xaca40000, 0x03e00008, 0x24020091, 0x3084ffff, 0x2c821389, 0x1040000e, - 0x00001021, 0x3c030800, 0x24632100, 0x00042942, 0x00052880, 0x00a32821, + 0x00001021, 0x3c030800, 0x24635680, 0x00042942, 0x00052880, 0x00a32821, 0x3086001f, 0x24030001, 0x8ca40000, 0x00c31804, 0x00031827, 0x00832024, - 0x03e00008, 0xaca40000, 0x03e00008, 0x24020091, 0x27bdffb0, 0x3c026000, - 0xafbf0048, 0x8c434448, 0xaf630140, 0x93620005, 0x30420001, 0x14400005, - 0x00000000, 0x0e0007ed, 0x00000000, 0x0a00067a, 0x8fbf0048, 0x93420116, - 0x93430112, 0x8f430104, 0x3c040020, 0x34424000, 0x00641824, 0x1060000d, - 0x03426021, 0x8f430128, 0x27420180, 0xac430000, 0x8f650040, 0x24040008, - 0x240340c1, 0xa4430008, 0x24030002, 0xa043000b, 0x3c031000, 0x0a000563, - 0xa044000a, 0x8f420104, 0x3c030040, 0x00431024, 0x10400007, 0x00000000, - 0x8f430128, 0x27420180, 0xac430000, 0x8f650040, 0x0a00055c, 0x24040010, - 0xaf400048, 0xaf400054, 0xaf400040, 0x8f630048, 0x8f620040, 0x00624823, - 0x05210004, 0x00000000, 0x0000000d, 0x00000000, 0x24000132, 0x9742011a, - 0x3046ffff, 0x10c00004, 0x8d880004, 0x01061021, 0x0a000487, 0x2445ffff, - 0x01002821, 0x918a000d, 0xa7a00020, 0xafa00028, 0x9364003f, 0x3c026000, - 0x8c434448, 0x308700ff, 0x31420004, 0x10400033, 0xaf630144, 0x24090012, - 0x14e90006, 0x3c040800, 0x8c830028, 0x24020001, 0x24630001, 0x0a00054e, - 0xac830028, 0x8f620044, 0x15020012, 0x97a20020, 0x27a60010, 0x27450180, - 0x3442001a, 0xa7a20020, 0x8f630040, 0x3c048000, 0x24020020, 0xa3a70022, - 0xa3a90023, 0xa3a2001a, 0xafa30028, 0x8f4201b8, 0x00441024, 0x1440fffd, - 0x00000000, 0x0a000533, 0x00000000, 0x8f620044, 0x01021023, 0x0440009e, - 0x24020001, 0x8f620048, 0x01021023, 0x0441009a, 0x24020001, 0x97a20020, - 0x27a60010, 0x34420001, 0xa7a20020, 0x8f630040, 0x27450180, 0x3c048000, - 0xafa30028, 0x8f4201b8, 0x00441024, 0x1440fffd, 0x00000000, 0x0a000533, - 0x00000000, 0x3c026000, 0x8c424448, 0xaf620148, 0x8f630040, 0x00685823, - 0x19600013, 0x00cb102a, 0x54400007, 0x314a00fe, 0x5566000c, 0x010b4021, - 0x31420001, 0x54400009, 0x010b4021, 0x314a00fe, 0x24020001, 0xa7a20020, - 0x8f630040, 0x00c05821, 0x00003021, 0x0a0004dd, 0xafa30028, 0x00cb1023, - 0x0a0004dd, 0x3046ffff, 0x00005821, 0x8f620048, 0x2442ffff, 0x00a21823, - 0x18600019, 0x0066102a, 0x14400013, 0x24020001, 0xa7a20020, 0x8f630040, - 0xafa30028, 0x8f620040, 0x55020005, 0x27a60010, 0x55200003, 0x27a60010, - 0x0a0004f6, 0x00c01821, 0x27450180, 0x3c038000, 0x8f4201b8, 0x00431024, - 0x1440fffd, 0x00000000, 0x0a000533, 0x00000000, 0x8f650048, 0x00c31023, - 0x3046ffff, 0x314a00f6, 0x3c046000, 0x8c824448, 0x31430002, 0x1060001e, - 0xaf62014c, 0x8f620044, 0x1502000e, 0x97a20020, 0x27a60010, 0x34420200, - 0xa7a20020, 0x8f630040, 0x27450180, 0x3c048000, 0xafa30028, 0x8f4201b8, - 0x00441024, 0x1440fffd, 0x00000000, 0x0a000533, 0x00000000, 0x27a60010, - 0x34420001, 0xa7a20020, 0x8f630040, 0x27450180, 0x3c048000, 0xafa30028, - 0x8f4201b8, 0x00441024, 0x1440fffd, 0x00000000, 0x0a000533, 0x00000000, - 0x3c026000, 0x8c424448, 0x31430010, 0xaf620150, 0x54600003, 0x8d890008, - 0x0a00054e, 0x24020001, 0x8f630054, 0x2522ffff, 0x00431023, 0x1840002a, - 0x24020001, 0x27a60010, 0xa7a20020, 0x8f630040, 0x27450180, 0x3c048000, - 0xafa30028, 0x8f4201b8, 0x00441024, 0x1440fffd, 0x00000000, 0x8f420128, - 0xaca20000, 0x8cc30018, 0x240240c1, 0xa4a20008, 0xaca30018, 0x90c4000a, - 0x24020002, 0xa0a2000b, 0xa0a4000a, 0x94c20010, 0xa4a20010, 0x90c30012, - 0xa0a30012, 0x90c20013, 0xa0a20013, 0x8cc30014, 0xaca30014, 0x8cc20024, - 0xaca20024, 0x8cc30028, 0xaca30028, 0x8cc4002c, 0x24020001, 0x3c031000, - 0xaca4002c, 0xaf4301b8, 0xaf400044, 0xaf400050, 0x0a00067a, 0x8fbf0048, - 0x3c026000, 0x8c424448, 0x31430020, 0x10600019, 0xaf620154, 0x8f430128, - 0x27420180, 0xac430000, 0x8f650040, 0x24040004, 0x240340c1, 0xa4430008, - 0x24030002, 0xa044000a, 0x24040008, 0xa043000b, 0x3c031000, 0xa4440010, - 0xa0400012, 0xa0400013, 0xac400014, 0xac400024, 0xac400028, 0xac40002c, - 0xac450018, 0x0e0007ed, 0xaf4301b8, 0x0a00067a, 0x8fbf0048, 0x8f430104, - 0x8c824448, 0x38e3000a, 0x2c630001, 0xaf620158, 0x38e2000c, 0x2c420001, - 0x00621825, 0x14600003, 0x2402000e, 0x14e2002a, 0x00000000, 0x50c00008, - 0x9584000e, 0x10c00004, 0xa7a60040, 0x01061021, 0x0a000583, 0x2445ffff, - 0x01002821, 0x9584000e, 0x93630035, 0x8f62004c, 0x00642004, 0x00892021, - 0x00821023, 0x1840001f, 0x3c026000, 0x8f620018, 0x01021023, 0x1c40000f, - 0x97a20020, 0x8f620018, 0x15020018, 0x3c026000, 0x8f62001c, 0x01221023, - 0x1c400008, 0x97a20020, 0x8f62001c, 0x15220011, 0x3c026000, 0x8f620058, - 0x00821023, 0x1840000c, 0x97a20020, 0xafa50028, 0xafa80034, 0xafa90038, - 0xafa4003c, 0x34420020, 0x0a0005a8, 0xa7a20020, 0x8f680040, 0x00003021, - 0x8f640058, 0x01002821, 0x3c026000, 0x8c434448, 0xaf63015c, 0x8f62004c, - 0x01221023, 0x18400009, 0x00000000, 0x8f620054, 0x01221023, 0x1c400005, - 0x97a20020, 0xafa50028, 0xafa90024, 0x0a0005c3, 0x34420040, 0x9742011a, - 0x1440000c, 0x24020014, 0x8f620058, 0x14820009, 0x24020014, 0x8f63004c, - 0x8f620054, 0x10620004, 0x97a20020, 0xafa50028, 0x34420080, 0xa7a20020, - 0x24020014, 0x10e2000a, 0x28e20015, 0x10400005, 0x2402000c, 0x10e20006, - 0x3c026000, 0x0a000600, 0x00000000, 0x24020016, 0x14e20031, 0x3c026000, - 0x8f620054, 0x24420001, 0x1522002d, 0x3c026000, 0x24020014, 0x10e2001e, - 0x28e20015, 0x10400005, 0x2402000c, 0x10e20008, 0x3c026000, 0x0a000600, - 0x00000000, 0x24020016, 0x10e2000c, 0x97a20020, 0x0a000600, 0x3c026000, - 0x97a30020, 0x2402000e, 0xafa50028, 0xa3a70022, 0xa3a20023, 0xafa90024, - 0x34630054, 0x0a0005ff, 0xa7a30020, 0x24030010, 0x24040002, 0xafa50028, - 0xa3a70022, 0xa3a30023, 0xa3a4001a, 0xafa90024, 0x0a0005fe, 0x3442005d, - 0x97a20020, 0x24030012, 0x24040002, 0xafa50028, 0xa3a70022, 0xa3a30023, - 0xa3a4001a, 0xafa90024, 0x3042fffe, 0x3442005c, 0xa7a20020, 0x3c026000, - 0x8c434448, 0x31420001, 0xaf630160, 0x1040002c, 0x2402000c, 0x10e20014, - 0x28e2000d, 0x10400005, 0x2402000a, 0x10e20008, 0x97a20020, 0x0a000631, - 0x3c026000, 0x2402000e, 0x10e20018, 0x3c026000, 0x0a000631, 0x00000000, - 0x24030008, 0x24040002, 0xafa50028, 0xa3a70022, 0xa3a30023, 0xa3a4001a, - 0x0a00062f, 0x34420013, 0x97a30020, 0x30620004, 0x1440000b, 0x97a20020, - 0x3462001b, 0xa7a20020, 0x24020016, 0x24030002, 0xafa50028, 0xa3a70022, - 0xa3a20023, 0x0a000630, 0xa3a3001a, 0x97a20020, 0x24030010, 0x24040002, - 0xafa50028, 0xa3a70022, 0xa3a30023, 0xa3a4001a, 0x3442001b, 0xa7a20020, - 0x3c026000, 0x8c434448, 0x31420009, 0x0002102b, 0x00021023, 0x30420007, - 0x34440003, 0xaf630164, 0x10c00016, 0x24030800, 0x8f820010, 0x27450180, - 0x24420001, 0xaf820010, 0x24020004, 0xaf4301b8, 0xa4a40008, 0xa0a2000b, - 0x93440120, 0x3c031000, 0xa4a6000e, 0xaca90024, 0xaca80028, 0x008b2021, - 0xa4a4000c, 0xaf4301b8, 0x97a20020, 0x00003021, 0x3042ffbf, 0x0a000650, - 0xa7a20020, 0x24060001, 0x3c026000, 0x8c434448, 0xaf630168, 0x97a20020, - 0x10400020, 0x27450180, 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, - 0x00000000, 0x8f420128, 0xaca20000, 0x8fa30028, 0x240240c1, 0xa4a20008, - 0xaca30018, 0x93a4001a, 0x24020002, 0xa0a2000b, 0xa0a4000a, 0x97a20020, - 0xa4a20010, 0x93a30022, 0xa0a30012, 0x93a20023, 0xa0a20013, 0x8fa30024, - 0xaca30014, 0x8fa20034, 0xaca20024, 0x8fa30038, 0xaca30028, 0x8fa2003c, - 0x3c031000, 0xaca2002c, 0xaf4301b8, 0x3c026000, 0x8c434448, 0x00c01021, - 0xaf63016c, 0x8fbf0048, 0x03e00008, 0x27bd0050, 0x8f460140, 0x8f470148, - 0x3c028000, 0x00e24024, 0x00072c02, 0x30a300ff, 0x2402000b, 0x1062008f, - 0x27440180, 0x2862000c, 0x10400011, 0x24020006, 0x1062005a, 0x28620007, - 0x10400007, 0x24020008, 0x10600024, 0x24020001, 0x10620037, 0x00000000, - 0x0a00077e, 0x00000000, 0x106200a9, 0x24020009, 0x106200bb, 0x00071c02, - 0x0a00077e, 0x00000000, 0x2402001b, 0x106200c7, 0x2862001c, 0x10400007, - 0x2402000e, 0x106200b1, 0x24020019, 0x106200c2, 0x00071c02, 0x0a00077e, - 0x00000000, 0x24020080, 0x10620060, 0x28620081, 0x10400005, 0x2402001c, - 0x10620094, 0x00071c02, 0x0a00077e, 0x00000000, 0x240200c2, 0x106200c5, - 0x00a01821, 0x0a00077e, 0x00000000, 0x00a01821, 0x3c058000, 0x8f4201b8, - 0x00451024, 0x1440fffd, 0x24020001, 0xa4830008, 0x24030002, 0xac860000, - 0xac800004, 0xa082000a, 0xa083000b, 0xa4870010, 0x8f430144, 0x3c021000, + 0x03e00008, 0xaca40000, 0x03e00008, 0x24020091, 0x27bdffb0, 0xafbf0048, + 0x93620023, 0x30420010, 0x1440025b, 0x24020001, 0x93420116, 0x93630005, + 0x34424000, 0x30630001, 0x14600005, 0x03425821, 0x0e001548, 0x00000000, + 0x0a0013a5, 0x8fbf0048, 0x93420112, 0x8f430104, 0x3c040020, 0x34424000, + 0x00641824, 0x10600012, 0x03422821, 0x27450180, 0x3c038000, 0x8f4201b8, + 0x00431024, 0x1440fffd, 0x00000000, 0x8f420128, 0xaca20000, 0x8f640040, + 0x24030008, 0x240240c1, 0xa4a20008, 0x24020002, 0xa0a2000b, 0x3c021000, + 0x0a001181, 0xa0a3000a, 0x8f420104, 0x3c030040, 0x00431024, 0x1040001d, + 0x3c038000, 0x27450180, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000, + 0x8f420128, 0xaca20000, 0x8f640040, 0x24030010, 0x240240c1, 0xa4a20008, + 0x24020002, 0xa0a3000a, 0x24030008, 0xa0a2000b, 0x3c021000, 0xa4a30010, + 0xa0a00012, 0xa0a00013, 0xaca00014, 0xaca00024, 0xaca00028, 0xaca0002c, + 0xaca40018, 0x0e001548, 0xaf4201b8, 0x0a0013a5, 0x8fbf0048, 0x8f820000, + 0x10400016, 0x00000000, 0x8f420104, 0x3c030001, 0x00431024, 0x10400011, + 0x00000000, 0x8ca3000c, 0x8f620030, 0x1462020c, 0x24020001, 0x8ca30010, + 0x8f62002c, 0x14620208, 0x24020001, 0x9763003a, 0x95620000, 0x14430204, + 0x24020001, 0x97630038, 0x95620002, 0x14430200, 0x24020001, 0xaf400048, + 0xaf400054, 0xaf400040, 0x8f690040, 0x8f6a0048, 0x01497023, 0x05c10004, + 0x00000000, 0x0000000d, 0x00000000, 0x24000169, 0x9742011a, 0x3046ffff, + 0x10c00004, 0x8d680004, 0x01061021, 0x0a0011b8, 0x2445ffff, 0x01002821, + 0x916c000d, 0xa7a00020, 0xa3a0001a, 0xafa00028, 0x9362003f, 0x31830004, + 0x1060003a, 0x304700ff, 0x24040012, 0x14e40006, 0x24020001, 0x3c040800, + 0x8c830028, 0x24630001, 0x0a00128d, 0xac830028, 0x8f620044, 0x15020010, + 0x27a60010, 0x27450180, 0x3c038000, 0x2402001a, 0xa7a20020, 0x24020020, + 0xafa90028, 0xa3a70022, 0xa3a40023, 0xa3a2001a, 0x8f4201b8, 0x00431024, + 0x1440fffd, 0x00000000, 0x0a001272, 0x00000000, 0x8f620044, 0x01021023, + 0x0440001a, 0x010a1023, 0x044100ae, 0x24020001, 0x3c020800, 0x8c4300d8, + 0x10600004, 0x24020001, 0xa7a20020, 0x0a0011ee, 0xafa90028, 0x2402001a, + 0xa7a20020, 0x24020020, 0xafa90028, 0xa3a70022, 0xa3a40023, 0xa3a2001a, + 0x27a60010, 0x27450180, 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, + 0x00000000, 0x0a001272, 0x00000000, 0x0a00128d, 0x24020001, 0x01286823, + 0x19a00016, 0x00cd102a, 0x54400007, 0x318c00fe, 0x55a6000f, 0x010d4021, + 0x31820001, 0x5440000c, 0x010d4021, 0x318c00fe, 0x00c06821, 0x3c040800, + 0x8c8300c8, 0x00003021, 0x24020001, 0xa7a20020, 0xafa90028, 0x24630001, + 0x0a001212, 0xac8300c8, 0x00cd1023, 0x0a001212, 0x3046ffff, 0x00006821, + 0x2542ffff, 0x00a21823, 0x1860001e, 0x0066102a, 0x14400018, 0x01402821, + 0x97a20020, 0x3c040800, 0x8c8300cc, 0xafa90028, 0x34420001, 0x24630001, + 0xa7a20020, 0x01091026, 0x2c420001, 0xac8300cc, 0x2dc30001, 0x00431024, + 0x1440000a, 0x00c01821, 0x27a60010, 0x27450180, 0x3c038000, 0x8f4201b8, + 0x00431024, 0x1440fffd, 0x00000000, 0x0a001272, 0x00000000, 0x00c31023, + 0x3046ffff, 0x0a00123d, 0x318c00f6, 0x01091023, 0x18400008, 0x97a20020, + 0x3c040800, 0x8c8300d4, 0xafa80028, 0x34420400, 0x24630001, 0xa7a20020, + 0xac8300d4, 0x31820002, 0x1040001c, 0x31820010, 0x8f620044, 0x1502000d, + 0x27a60010, 0x97a20020, 0x27450180, 0x3c038000, 0xafa90028, 0x34420001, + 0xa7a20020, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000, 0x0a001272, + 0x00000000, 0x97a20020, 0x27450180, 0x3c038000, 0xafa90028, 0x34420001, + 0xa7a20020, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000, 0x0a001272, + 0x00000000, 0x54400003, 0x8d6a0008, 0x0a00128d, 0x24020001, 0x8f630054, + 0x2542ffff, 0x00431023, 0x1840002e, 0x97a20020, 0x27a60010, 0x3c040800, + 0x8c8300d0, 0x27450180, 0x3c078000, 0xafa90028, 0x34420001, 0x24630001, + 0xa7a20020, 0xac8300d0, 0x8f4201b8, 0x00471024, 0x1440fffd, 0x00000000, + 0x8f420128, 0xaca20000, 0x8cc30018, 0x240240c1, 0xa4a20008, 0xaca30018, + 0x90c4000a, 0x24020002, 0xa0a2000b, 0xa0a4000a, 0x94c20010, 0xa4a20010, + 0x90c30012, 0xa0a30012, 0x90c20013, 0xa0a20013, 0x8cc30014, 0xaca30014, + 0x8cc20024, 0xaca20024, 0x8cc30028, 0xaca30028, 0x8cc4002c, 0x24020001, + 0x3c031000, 0xaca4002c, 0xaf4301b8, 0xaf400044, 0xaf400050, 0x0a0013a5, + 0x8fbf0048, 0x31820020, 0x10400011, 0x00000000, 0x95620012, 0x0046102b, + 0x10400008, 0x97a20020, 0x95660012, 0x10c00003, 0x01061021, 0x0a00129e, + 0x2445ffff, 0x01002821, 0x97a20020, 0x93a3001a, 0x34420008, 0x34630004, + 0xa7a20020, 0xa3a3001a, 0x8f420104, 0x38e3000a, 0x2c630001, 0x38e2000c, + 0x2c420001, 0x00621825, 0x14600003, 0x2402000e, 0x54e2002a, 0x00003021, + 0x50c00008, 0x9564000e, 0x10c00004, 0xa7a60040, 0x01061021, 0x0a0012b6, + 0x2445ffff, 0x01002821, 0x9564000e, 0x93630035, 0x8f62004c, 0x00642004, + 0x008a2021, 0x00821023, 0x1840001d, 0x00000000, 0x8f620018, 0x01021023, + 0x1c40000f, 0x97a20020, 0x8f620018, 0x15020016, 0x00000000, 0x8f62001c, + 0x01421023, 0x1c400008, 0x97a20020, 0x8f62001c, 0x1542000f, 0x00000000, + 0x8f620058, 0x00821023, 0x1840000b, 0x97a20020, 0xafa50028, 0xafa80034, + 0xafaa0038, 0xafa4003c, 0x34420020, 0x0a0012da, 0xa7a20020, 0x01204021, + 0x01002821, 0x8f640058, 0x8f62004c, 0x01421023, 0x18400009, 0x00000000, + 0x8f620054, 0x01421023, 0x1c400005, 0x97a20020, 0xafa50028, 0xafaa0024, + 0x0a0012f2, 0x34420040, 0x9742011a, 0x1440000c, 0x24020014, 0x8f620058, + 0x14820009, 0x24020014, 0x8f63004c, 0x8f620054, 0x10620004, 0x97a20020, + 0xafa50028, 0x34420080, 0xa7a20020, 0x24020014, 0x10e2000a, 0x28e20015, + 0x10400005, 0x2402000c, 0x10e20006, 0x31820001, 0x0a001333, 0x00000000, + 0x24020016, 0x14e20035, 0x31820001, 0x8f620084, 0x24420001, 0x15420031, + 0x31820001, 0x24020014, 0x10e20021, 0x28e20015, 0x10400005, 0x2402000c, + 0x10e20008, 0x31820001, 0x0a001333, 0x00000000, 0x24020016, 0x10e2000c, + 0x31820001, 0x0a001333, 0x00000000, 0x97a30020, 0x2402000e, 0xafa50028, + 0xa3a70022, 0xa3a20023, 0xafaa0024, 0x34630054, 0x0a001332, 0xa7a30020, + 0x97a20020, 0x93a4001a, 0x24030010, 0xafa50028, 0xa3a70022, 0xa3a30023, + 0xafaa0024, 0x3442005d, 0x34840002, 0xa7a20020, 0x0a001332, 0xa3a4001a, + 0x97a20020, 0x24030012, 0xa3a30023, 0x93a3001a, 0xafa50028, 0xa3a70022, + 0xafaa0024, 0x3042fffe, 0x3442005c, 0x34630002, 0xa7a20020, 0xa3a3001a, + 0x31820001, 0x10400030, 0x2402000c, 0x10e20013, 0x28e2000d, 0x10400005, + 0x2402000a, 0x10e20008, 0x97a20020, 0x0a001365, 0x31820009, 0x2402000e, + 0x10e2001b, 0x31820009, 0x0a001366, 0x0002102b, 0x93a4001a, 0x24030008, + 0xafa50028, 0xa3a70022, 0xa3a30023, 0x0a001361, 0x34420013, 0x97a30020, + 0x30620004, 0x14400005, 0x93a2001a, 0x3463001b, 0xa7a30020, 0x0a001354, + 0x24030016, 0x3463001b, 0xa7a30020, 0x24030010, 0xafa50028, 0xa3a70022, + 0xa3a30023, 0x34420002, 0x0a001364, 0xa3a2001a, 0x97a20020, 0x93a4001a, + 0x24030010, 0xafa50028, 0xa3a70022, 0xa3a30023, 0x3442001b, 0x34840002, + 0xa7a20020, 0xa3a4001a, 0x31820009, 0x0002102b, 0x00021023, 0x30420007, + 0x10c00017, 0x34440003, 0x8f820014, 0x24030800, 0x27450180, 0x24420001, + 0xaf820014, 0x24020004, 0xaf4301b8, 0xa4a40008, 0xa0a2000b, 0x93440120, + 0x3c031000, 0xa4a6000e, 0xacaa0024, 0xaca80028, 0x008d2021, 0xa4a4000c, + 0xaf4301b8, 0x97a20020, 0x00003021, 0x3042ffbf, 0x0a001381, 0xa7a20020, + 0x24060001, 0x97a20020, 0x10400020, 0x27450180, 0x3c038000, 0x8f4201b8, + 0x00431024, 0x1440fffd, 0x00000000, 0x8f420128, 0xaca20000, 0x8fa30028, + 0x240240c1, 0xa4a20008, 0xaca30018, 0x93a4001a, 0x24020002, 0xa0a2000b, + 0xa0a4000a, 0x97a20020, 0xa4a20010, 0x93a30022, 0xa0a30012, 0x93a20023, + 0xa0a20013, 0x8fa30024, 0xaca30014, 0x8fa20034, 0xaca20024, 0x8fa30038, + 0xaca30028, 0x8fa2003c, 0x3c031000, 0xaca2002c, 0xaf4301b8, 0x00c01021, + 0x8fbf0048, 0x03e00008, 0x27bd0050, 0x8f470140, 0x8f460148, 0x3c028000, + 0x00c24024, 0x00062c02, 0x30a300ff, 0x24020019, 0x106200e7, 0x27440180, + 0x2862001a, 0x1040001f, 0x24020008, 0x106200be, 0x28620009, 0x1040000d, + 0x24020001, 0x10620046, 0x28620002, 0x50400005, 0x24020006, 0x1060002e, + 0x00a01821, 0x0a0014c4, 0x00000000, 0x1062005b, 0x00a01821, 0x0a0014c4, + 0x00000000, 0x2402000b, 0x10620084, 0x2862000c, 0x10400005, 0x24020009, + 0x106200bc, 0x00061c02, 0x0a0014c4, 0x00000000, 0x2402000e, 0x106200b7, + 0x00061c02, 0x0a0014c4, 0x00000000, 0x28620021, 0x10400009, 0x2862001f, + 0x104000c1, 0x2402001b, 0x106200bf, 0x2402001c, 0x1062009a, 0x00061c02, + 0x0a0014c4, 0x00000000, 0x240200c2, 0x106200ca, 0x286200c3, 0x10400005, + 0x24020080, 0x1062005a, 0x00a01821, 0x0a0014c4, 0x00000000, 0x240200c9, + 0x106200cd, 0x30c5ffff, 0x0a0014c4, 0x00000000, 0x3c058000, 0x8f4201b8, + 0x00451024, 0x1440fffd, 0x24020001, 0xa4830008, 0x24030002, 0xac870000, + 0xac800004, 0xa082000a, 0xa083000b, 0xa4860010, 0x8f430144, 0x3c021000, 0xac800028, 0xac830024, 0x3c036000, 0xaf4201b8, 0x03e00008, 0xac600808, - 0x11000009, 0x00a01821, 0x3c020800, 0x24030002, 0xa0434490, 0x24424490, - 0xac460008, 0x8f430144, 0x03e00008, 0xac430004, 0x3c058000, 0x8f4201b8, - 0x00451024, 0x1440fffd, 0x24020002, 0xac800000, 0xac860004, 0xa4830008, - 0xa082000a, 0xa082000b, 0xa4870010, 0xac800024, 0x8f420144, 0x3c031000, - 0xac820028, 0x3c026000, 0xaf4301b8, 0x03e00008, 0xac400808, 0x00a01821, - 0x3c080800, 0x3c058000, 0x8f4201b8, 0x00451024, 0x1440fffd, 0x00000000, - 0xac860000, 0x91024490, 0x00002821, 0x10400002, 0x25064490, 0x8cc50008, - 0xac850004, 0xa4830008, 0x91034490, 0x24020002, 0xa082000b, 0xa4870010, - 0x34630001, 0xa083000a, 0x8f420144, 0xac820024, 0x91034490, 0x10600002, - 0x00001021, 0x8cc20004, 0xac820028, 0x3c021000, 0xaf4201b8, 0x3c026000, - 0xa1004490, 0x03e00008, 0xac400808, 0x00a01821, 0x3c058000, 0x8f4201b8, - 0x00451024, 0x1440fffd, 0x24020002, 0xa082000b, 0xa4830008, 0xa4870010, - 0x8f420144, 0x3c031000, 0xa4820012, 0x03e00008, 0xaf4301b8, 0x30e2ffff, - 0x14400028, 0x00071c02, 0x93620005, 0x30420004, 0x14400020, 0x3c029000, - 0x34420001, 0x00c21025, 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, - 0x1440fffd, 0x00000000, 0x93620005, 0x3c038000, 0x34630001, 0x00c31825, - 0x34420004, 0xa3620005, 0xaf430020, 0x93620005, 0x30420004, 0x14400003, - 0x3c038000, 0x0000000d, 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, - 0x24020005, 0x3c031000, 0xac860000, 0xa082000b, 0xaf4301b8, 0x0a00073d, - 0x00071c02, 0x0000000d, 0x03e00008, 0x00000000, 0x00071c02, 0x3c058000, - 0x8f4201b8, 0x00451024, 0x1440fffd, 0x24020001, 0xa4830008, 0x24030002, - 0xac860000, 0xac800004, 0xa082000a, 0xa083000b, 0xa4870010, 0x8f430144, - 0x3c021000, 0xac800028, 0xac830024, 0x03e00008, 0xaf4201b8, 0x00071c02, - 0x3c058000, 0x8f4201b8, 0x00451024, 0x1440fffd, 0x24020002, 0xac800000, - 0xac860004, 0xa4830008, 0xa082000a, 0xa082000b, 0xa4870010, 0xac800024, - 0x8f420144, 0x3c031000, 0xac820028, 0x03e00008, 0xaf4301b8, 0x00071c02, - 0x3c058000, 0x8f4201b8, 0x00451024, 0x1440fffd, 0x24020001, 0xa4830008, - 0x24030002, 0xa082000a, 0x3c021000, 0xac860000, 0xac800004, 0xa083000b, - 0xa4870010, 0xac800024, 0xac800028, 0x03e00008, 0xaf4201b8, 0x3c058000, - 0x8f4201b8, 0x00451024, 0x1440fffd, 0x24020002, 0xac860000, 0xac800004, - 0xa4830008, 0xa080000a, 0x0a000748, 0xa082000b, 0x0000000d, 0x03e00008, - 0x00000000, 0x03e00008, 0x00000000, 0x8f420100, 0x3042003e, 0x14400011, - 0x24020001, 0xaf400048, 0x8f420100, 0x304207c0, 0x10400005, 0x00000000, - 0xaf40004c, 0xaf400050, 0x03e00008, 0x24020001, 0xaf400054, 0xaf400040, - 0x8f420100, 0x30423800, 0x54400001, 0xaf400044, 0x24020001, 0x03e00008, - 0x00000000, 0x3c029000, 0x34420001, 0x00822025, 0xaf440020, 0x3c038000, - 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, 0x03e00008, 0x00000000, - 0x3c028000, 0x34420001, 0x00822025, 0x03e00008, 0xaf440020, 0x8f430128, - 0x27420180, 0xac430000, 0x8f650040, 0x240340c1, 0xa4430008, 0x24030002, - 0xa044000a, 0x24040008, 0xa043000b, 0x3c031000, 0xa4440010, 0xa0400012, - 0xa0400013, 0xac400014, 0xac400024, 0xac400028, 0xac40002c, 0xac450018, - 0x03e00008, 0xaf4301b8, 0x24020001, 0xacc40000, 0x03e00008, 0xa4e50000, - 0x03e00008, 0x24020001, 0x24020001, 0xaf400044, 0x03e00008, 0xaf400050, - 0x00803021, 0x27450180, 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, - 0x00000000, 0x8f420128, 0xaca20000, 0x8cc30018, 0x240240c1, 0xa4a20008, - 0xaca30018, 0x90c4000a, 0x24020002, 0xa0a2000b, 0xa0a4000a, 0x94c20010, - 0xa4a20010, 0x90c30012, 0xa0a30012, 0x90c20013, 0xa0a20013, 0x8cc30014, - 0xaca30014, 0x8cc20024, 0xaca20024, 0x8cc30028, 0xaca30028, 0x8cc2002c, - 0x3c031000, 0xaca2002c, 0x24020001, 0xaf4301b8, 0xaf400044, 0x03e00008, - 0xaf400050, 0x27bdffe8, 0xafbf0010, 0x0e000326, 0x00000000, 0x00002021, - 0x0e00004c, 0xaf400180, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x8f460148, - 0x27450180, 0x3c038000, 0x00061402, 0x304700ff, 0x8f4201b8, 0x00431024, - 0x1440fffd, 0x00000000, 0x8f440140, 0x00061202, 0x304200ff, 0x00061c02, - 0xaca20004, 0x24020002, 0xa4a30008, 0x30c300ff, 0xa0a2000b, 0xaca30024, - 0x10e0000a, 0xaca40000, 0x28e20004, 0x14400005, 0x24020001, 0x24020005, - 0x54e20005, 0xa0a0000a, 0x24020001, 0x0a000816, 0xa0a2000a, 0xa0a0000a, - 0x3c021000, 0x03e00008, 0xaf4201b8, 0x03e00008, 0x00001021, 0x10c00007, - 0x00000000, 0x8ca20000, 0x24c6ffff, 0x24a50004, 0xac820000, 0x14c0fffb, - 0x24840004, 0x03e00008, 0x00000000, 0x0a00082a, 0x00a01021, 0xac860000, - 0x24840004, 0x00a01021, 0x1440fffc, 0x24a5ffff, 0x03e00008, 0x00000000, - 0x00000000 }; + 0x11000009, 0x00a01821, 0x3c020800, 0x24030002, 0xa0436a08, 0x24426a08, + 0xac470008, 0x8f430144, 0x03e00008, 0xac430004, 0x3c058000, 0x8f4201b8, + 0x00451024, 0x1440fffd, 0x24020002, 0xac800000, 0xac870004, 0xa4830008, + 0xa082000a, 0xa082000b, 0xa4860010, 0xac800024, 0x8f420144, 0x3c031000, + 0xac820028, 0x3c026000, 0xaf4301b8, 0x03e00008, 0xac400808, 0x3c080800, + 0x3c058000, 0x8f4201b8, 0x00451024, 0x1440fffd, 0x00000000, 0xac870000, + 0x91026a08, 0x00002821, 0x10400002, 0x25076a08, 0x8ce50008, 0xac850004, + 0xa4830008, 0x91036a08, 0x24020002, 0xa082000b, 0xa4860010, 0x34630001, + 0xa083000a, 0x8f420144, 0xac820024, 0x91036a08, 0x10600002, 0x00001021, + 0x8ce20004, 0xac820028, 0x3c021000, 0xaf4201b8, 0x3c026000, 0xa1006a08, + 0x03e00008, 0xac400808, 0x3c058000, 0x8f4201b8, 0x00451024, 0x1440fffd, + 0x24020002, 0xa082000b, 0xa4830008, 0xa4860010, 0x8f420144, 0x3c031000, + 0xa4820012, 0x03e00008, 0xaf4301b8, 0x30c2ffff, 0x14400028, 0x00061c02, + 0x93620005, 0x30420004, 0x14400020, 0x3c029000, 0x34420001, 0x00e21025, + 0xaf420020, 0x3c038000, 0x8f420020, 0x00431024, 0x1440fffd, 0x00000000, + 0x93620005, 0x3c038000, 0x34630001, 0x00e31825, 0x34420004, 0xa3620005, + 0xaf430020, 0x93620005, 0x30420004, 0x14400003, 0x3c038000, 0x0000000d, + 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x24020005, 0x3c031000, + 0xac870000, 0xa082000b, 0xaf4301b8, 0x0a001473, 0x00061c02, 0x0000000d, + 0x03e00008, 0x00000000, 0x00061c02, 0x3c058000, 0x8f4201b8, 0x00451024, + 0x1440fffd, 0x24020001, 0xa4830008, 0x24030002, 0xac870000, 0xac800004, + 0xa082000a, 0xa083000b, 0xa4860010, 0x8f430144, 0x3c021000, 0xac800028, + 0xac830024, 0x03e00008, 0xaf4201b8, 0x3c058000, 0x8f4201b8, 0x00451024, + 0x1440fffd, 0x24020002, 0xac800000, 0xac870004, 0xa4830008, 0xa082000a, + 0xa082000b, 0xa4860010, 0xac800024, 0x8f420144, 0x3c031000, 0xac820028, + 0x03e00008, 0xaf4301b8, 0x00061c02, 0x3c058000, 0x8f4201b8, 0x00451024, + 0x1440fffd, 0x24020001, 0xa4830008, 0x24030002, 0xa082000a, 0x3c021000, + 0xac870000, 0xac800004, 0xa083000b, 0xa4860010, 0xac800024, 0xac800028, + 0x03e00008, 0xaf4201b8, 0x00a01821, 0x3c058000, 0x8f4201b8, 0x00451024, + 0x1440fffd, 0x24020002, 0xac870000, 0xac800004, 0xa4830008, 0xa080000a, + 0x0a00147e, 0xa082000b, 0x8f440144, 0x3c038000, 0x8f4201b8, 0x00431024, + 0x1440fffd, 0x24020002, 0x240340c9, 0xaf470180, 0xa342018b, 0x3c021000, + 0xa7430188, 0xaf4401a4, 0xaf4501a8, 0xaf4001ac, 0x03e00008, 0xaf4201b8, + 0x0000000d, 0x03e00008, 0x00000000, 0x03e00008, 0x00000000, 0x8f420100, + 0x3042003e, 0x14400011, 0x24020001, 0xaf400048, 0x8f420100, 0x304207c0, + 0x10400005, 0x00000000, 0xaf40004c, 0xaf400050, 0x03e00008, 0x24020001, + 0xaf400054, 0xaf400040, 0x8f420100, 0x30423800, 0x54400001, 0xaf400044, + 0x24020001, 0x03e00008, 0x00000000, 0x3c038000, 0x8f4201b8, 0x00431024, + 0x1440fffd, 0x24020002, 0x240340c9, 0xaf440180, 0xa342018b, 0x3c021000, + 0xa7430188, 0xaf4501a4, 0xaf4601a8, 0xaf4701ac, 0x03e00008, 0xaf4201b8, + 0x3c029000, 0x34420001, 0x00822025, 0xaf440020, 0x3c038000, 0x8f420020, + 0x00431024, 0x1440fffd, 0x00000000, 0x03e00008, 0x00000000, 0x3c028000, + 0x34420001, 0x00822025, 0x03e00008, 0xaf440020, 0x308600ff, 0x27450180, + 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000, 0x8f420128, + 0xaca20000, 0x8f640040, 0x24030008, 0x240240c1, 0xa4a20008, 0x24020002, + 0xa0a2000b, 0x3c021000, 0xa0a6000a, 0xa4a30010, 0xa0a00012, 0xa0a00013, + 0xaca00014, 0xaca00024, 0xaca00028, 0xaca0002c, 0xaca40018, 0x03e00008, + 0xaf4201b8, 0x24020001, 0xacc40000, 0x03e00008, 0xa4e50000, 0x03e00008, + 0x24020001, 0x24020001, 0xaf400044, 0x03e00008, 0xaf400050, 0x00803021, + 0x27450180, 0x3c038000, 0x8f4201b8, 0x00431024, 0x1440fffd, 0x00000000, + 0x8f420128, 0xaca20000, 0x8cc30018, 0x240240c1, 0xa4a20008, 0xaca30018, + 0x90c4000a, 0x24020002, 0xa0a2000b, 0xa0a4000a, 0x94c20010, 0xa4a20010, + 0x90c30012, 0xa0a30012, 0x90c20013, 0xa0a20013, 0x8cc30014, 0xaca30014, + 0x8cc20024, 0xaca20024, 0x8cc30028, 0xaca30028, 0x8cc2002c, 0x3c031000, + 0xaca2002c, 0x24020001, 0xaf4301b8, 0xaf400044, 0x03e00008, 0xaf400050, + 0x27bdffe8, 0xafbf0010, 0x0e001032, 0x00000000, 0x00002021, 0x0e000c99, + 0xaf400180, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x8f460148, 0x27450180, + 0x3c038000, 0x00061402, 0x304700ff, 0x8f4201b8, 0x00431024, 0x1440fffd, + 0x00000000, 0x8f440140, 0x00061202, 0x304200ff, 0x00061c02, 0xaca20004, + 0x24020002, 0xa4a30008, 0x30c300ff, 0xa0a2000b, 0xaca30024, 0x10e0000a, + 0xaca40000, 0x28e20004, 0x14400005, 0x24020001, 0x24020005, 0x54e20005, + 0xa0a0000a, 0x24020001, 0x0a001571, 0xa0a2000a, 0xa0a0000a, 0x3c021000, + 0x03e00008, 0xaf4201b8, 0x03e00008, 0x00001021, 0x10c00007, 0x00000000, + 0x8ca20000, 0x24c6ffff, 0x24a50004, 0xac820000, 0x14c0fffb, 0x24840004, + 0x03e00008, 0x00000000, 0x0a001587, 0x00a01021, 0xac860000, 0x00000000, + 0x00000000, 0x24840004, 0x00a01021, 0x1440fffa, 0x24a5ffff, 0x03e00008, + 0x00000000, 0x00000000 }; -static u32 bnx2_RXP_b06FwData[(0x0/4) + 1] = { 0x00000000 }; -static u32 bnx2_RXP_b06FwRodata[(0x0/4) + 1] = { 0x00000000 }; -static u32 bnx2_RXP_b06FwBss[(0x239c/4) + 1] = { 0x00000000 }; -static u32 bnx2_RXP_b06FwSbss[(0x14/4) + 1] = { 0x00000000 }; +static u32 bnx2_RXP_b06FwData[(0x0/4) + 1] = { 0x0 }; +static u32 bnx2_RXP_b06FwRodata[(0x0/4) + 1] = { 0x0 }; +static u32 bnx2_RXP_b06FwBss[(0x1394/4) + 1] = { 0x0 }; +static u32 bnx2_RXP_b06FwSbss[(0x18/4) + 1] = { 0x0 }; static u32 bnx2_rv2p_proc1[] = { 0x00000008, 0xac000001, 0x0000000c, 0x2f800001, 0x00000010, 0x213f0004, @@ -1536,249 +2298,328 @@ static u32 bnx2_rv2p_proc2[] = { 0x0000000c, 0x29520000, 0x00000018, 0x80000002, 0x0000000c, 0x29800000, 0x00000018, 0x00570000 }; -static int bnx2_TPAT_b06FwReleaseMajor = 0x0; +static int bnx2_TPAT_b06FwReleaseMajor = 0x1; static int bnx2_TPAT_b06FwReleaseMinor = 0x0; static int bnx2_TPAT_b06FwReleaseFix = 0x0; -static u32 bnx2_TPAT_b06FwStartAddr = 0x08000858; +static u32 bnx2_TPAT_b06FwStartAddr = 0x08000860; static u32 bnx2_TPAT_b06FwTextAddr = 0x08000800; -static int bnx2_TPAT_b06FwTextLen = 0x1314; -static u32 bnx2_TPAT_b06FwDataAddr = 0x08001b40; +static int bnx2_TPAT_b06FwTextLen = 0x122c; +static u32 bnx2_TPAT_b06FwDataAddr = 0x08001a60; static int bnx2_TPAT_b06FwDataLen = 0x0; static u32 bnx2_TPAT_b06FwRodataAddr = 0x00000000; static int bnx2_TPAT_b06FwRodataLen = 0x0; -static u32 bnx2_TPAT_b06FwBssAddr = 0x08001b90; -static int bnx2_TPAT_b06FwBssLen = 0x80; -static u32 bnx2_TPAT_b06FwSbssAddr = 0x08001b40; -static int bnx2_TPAT_b06FwSbssLen = 0x48; - -static u32 bnx2_TPAT_b06FwText[(0x1314/4) + 1] = { - 0x0a000216, 0x00000000, 0x00000000, 0x0000000d, 0x74706174, 0x20302e36, - 0x2e390000, 0x00060901, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x10000003, - 0x00000000, 0x0000000d, 0x0000000d, 0x3c020800, 0x24421b40, 0x3c030800, - 0x24631c10, 0xac400000, 0x0043202b, 0x1480fffd, 0x24420004, 0x3c1d0800, - 0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100858, 0x3c1c0800, 0x279c1b40, - 0x0e00051f, 0x00000000, 0x0000000d, 0x8f820024, 0x27bdffe8, 0xafbf0014, - 0x10400004, 0xafb00010, 0x0000000d, 0x00000000, 0x2400015f, 0x8f82001c, +static u32 bnx2_TPAT_b06FwBssAddr = 0x08001aa0; +static int bnx2_TPAT_b06FwBssLen = 0x250; +static u32 bnx2_TPAT_b06FwSbssAddr = 0x08001a60; +static int bnx2_TPAT_b06FwSbssLen = 0x34; +static u32 bnx2_TPAT_b06FwText[(0x122c/4) + 1] = { + 0x0a000218, 0x00000000, 0x00000000, 0x0000000d, 0x74706174, 0x20322e35, + 0x2e313100, 0x02050b01, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c020800, + 0x24421a60, 0x3c030800, 0x24631cf0, 0xac400000, 0x0043202b, 0x1480fffd, + 0x24420004, 0x3c1d0800, 0x37bd2ffc, 0x03a0f021, 0x3c100800, 0x26100860, + 0x3c1c0800, 0x279c1a60, 0x0e000546, 0x00000000, 0x0000000d, 0x8f820010, 0x8c450008, 0x24030800, 0xaf430178, 0x97430104, 0x3c020008, 0xaf420140, - 0x8f820034, 0x30420001, 0x10400006, 0x3070ffff, 0x24020002, 0x2603fffe, - 0xa7420146, 0x0a000246, 0xa7430148, 0xa7400146, 0x8f850034, 0x30a20020, - 0x0002102b, 0x00021023, 0x30460009, 0x30a30c00, 0x24020400, 0x14620002, - 0x34c40001, 0x34c40005, 0xa744014a, 0x3c020800, 0x8c440820, 0x3c030048, - 0x24020002, 0x00832025, 0x30a30006, 0x1062000d, 0x2c620003, 0x50400005, - 0x24020004, 0x10600012, 0x3c020001, 0x0a000271, 0x00000000, 0x10620007, - 0x24020006, 0x1462000f, 0x3c020111, 0x0a000269, 0x00821025, 0x0a000268, - 0x3c020101, 0x3c020011, 0x00821025, 0x24030001, 0xaf421000, 0xaf830030, - 0x0a000271, 0x00000000, 0x00821025, 0xaf421000, 0xaf800030, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x8f830030, 0x1060003f, 0x3c048000, - 0x8f421000, 0x00441024, 0x1040fffd, 0x00000000, 0x10600039, 0x00000000, - 0x8f421000, 0x3c030020, 0x00431024, 0x10400034, 0x00000000, 0x97421014, - 0x14400031, 0x00000000, 0x97421008, 0x8f84001c, 0x24420006, 0x00024082, - 0x00081880, 0x00643821, 0x8ce50000, 0x30430003, 0x30420001, 0x10400004, - 0x00000000, 0x0000000d, 0x0a0002b0, 0x00081080, 0x5460000f, 0x30a5ffff, - 0x3c06ffff, 0x00a62824, 0x0005182b, 0x00a61026, 0x0002102b, 0x00621824, - 0x10600004, 0x00000000, 0x0000000d, 0x00000000, 0x240001fc, 0x8ce20000, - 0x0a0002af, 0x00462825, 0x0005182b, 0x38a2ffff, 0x0002102b, 0x00621824, - 0x10600004, 0x00000000, 0x0000000d, 0x00000000, 0x24000206, 0x8ce20000, - 0x3445ffff, 0x00081080, 0x00441021, 0x3c030800, 0xac450000, 0x8c620840, - 0x24420001, 0xac620840, 0x8f820008, 0x10400003, 0x00000000, 0x0e000660, - 0x00000000, 0x8f840028, 0x02002821, 0x24820008, 0x30421fff, 0x24434000, - 0x0343d821, 0x30a30007, 0xaf840018, 0xaf820028, 0xaf420084, 0x10600002, - 0x24a20007, 0x3045fff8, 0x8f820044, 0x8f840004, 0x00451821, 0xaf82002c, - 0x0064102b, 0xaf830044, 0x14400002, 0x00641023, 0xaf820044, 0x8f840044, - 0x34028000, 0x8fbf0014, 0x8fb00010, 0x00821021, 0x03421821, 0x3c021000, - 0xaf83001c, 0xaf440080, 0xaf420178, 0x03e00008, 0x27bd0018, 0x8f820024, - 0x27bdffe8, 0xafbf0014, 0x10400004, 0xafb00010, 0x0000000d, 0x00000000, - 0x24000249, 0x8f85001c, 0x24020001, 0xaf820024, 0x8ca70008, 0xa3800023, - 0x8f620004, 0x3c100800, 0x26041b90, 0x00021402, 0xa3820010, 0x304600ff, - 0x24c60005, 0x0e00064a, 0x00063082, 0x8f640004, 0x8f430108, 0x3c021000, - 0x00621824, 0xa7840020, 0x10600008, 0x00000000, 0x97420104, 0x93830023, - 0x2442ffec, 0x34630002, 0xa3830023, 0x0a000304, 0x3045ffff, 0x97420104, - 0x2442fff0, 0x3045ffff, 0x8f620004, 0x3042ffff, 0x2c420013, 0x14400004, - 0x00000000, 0x93820023, 0x34420001, 0xa3820023, 0x93830023, 0x24020001, - 0x10620009, 0x28620002, 0x14400014, 0x24020002, 0x10620012, 0x24020003, - 0x1062000a, 0x00000000, 0x0a000325, 0x00000000, 0x8f82001c, 0x8c43000c, - 0x3c04ffff, 0x00641824, 0x00651825, 0x0a000325, 0xac43000c, 0x8f82001c, - 0x8c430010, 0x3c04ffff, 0x00641824, 0x00651825, 0xac430010, 0x8f620004, - 0x3042ffff, 0x24420002, 0x00021083, 0xa3820038, 0x304500ff, 0x8f82001c, - 0x3c04ffff, 0x00052880, 0x00a22821, 0x8ca70000, 0x97820020, 0x97430104, - 0x00e42024, 0x24420002, 0x00621823, 0x00833825, 0xaca70000, 0x93840038, - 0x26061b90, 0x00041080, 0x00461021, 0x90430000, 0x3063000f, 0x00832021, - 0xa3840022, 0x308200ff, 0x3c04fff6, 0x24420003, 0x00021080, 0x00461021, - 0x8c450000, 0x93830022, 0x8f82001c, 0x3484ffff, 0x00a43824, 0x00031880, - 0x00621821, 0xaf850000, 0xac67000c, 0x93820022, 0x93830022, 0x8f84001c, - 0x24420003, 0x00021080, 0x00461021, 0x24630004, 0x00031880, 0xac470000, - 0x93820022, 0x00661821, 0x94670002, 0x00021080, 0x00441021, 0xac670000, - 0x24030010, 0xac470010, 0xa7430140, 0x24030002, 0xa7400142, 0xa7400144, - 0xa7430146, 0x97420104, 0x8f840034, 0x24030001, 0x2442fffe, 0x30840006, - 0xa7420148, 0x24020002, 0xa743014a, 0x1082000d, 0x2c820003, 0x10400005, - 0x24020004, 0x10800011, 0x3c020009, 0x0a000383, 0x00000000, 0x10820007, - 0x24020006, 0x1482000d, 0x3c020119, 0x0a00037d, 0x24030001, 0x0a00037c, - 0x3c020109, 0x3c020019, 0x24030001, 0xaf421000, 0xaf830030, 0x0a000383, - 0x00000000, 0xaf421000, 0xaf800030, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x93820010, 0x24030008, 0x8f840030, 0x24420002, 0x30420007, - 0x00621823, 0x30630007, 0xaf83000c, 0x10800005, 0x3c038000, 0x8f421000, - 0x00431024, 0x1040fffd, 0x00000000, 0x8f820028, 0xaf820018, 0x24420010, - 0x30421fff, 0xaf820028, 0xaf420084, 0x97430104, 0x24424000, 0x0342d821, - 0x3063ffff, 0x30620007, 0x10400002, 0x24620007, 0x3043fff8, 0x8f820044, - 0x8f840004, 0x00431821, 0xaf82002c, 0x0064102b, 0xaf830044, 0x14400002, - 0x00641023, 0xaf820044, 0x8f840044, 0x34028000, 0x8fbf0014, 0x8fb00010, - 0x00821021, 0x03421821, 0x3c021000, 0xaf83001c, 0xaf440080, 0xaf420178, - 0x03e00008, 0x27bd0018, 0x8f820024, 0x27bdffe8, 0xafbf0014, 0x14400004, - 0xafb00010, 0x0000000d, 0x00000000, 0x240002db, 0x8f620004, 0x04410009, - 0x3c050800, 0x93820022, 0x8f830000, 0x24a41b90, 0xaf800024, 0x24420003, - 0x00021080, 0x00441021, 0xac430000, 0x93820038, 0x24a51b90, 0x93860010, - 0x3c040001, 0x27700008, 0x24420001, 0x00021080, 0x00451021, 0x8c430000, - 0x24c60005, 0x00063082, 0x00641821, 0x02002021, 0x0e00064a, 0xac430000, - 0x93840022, 0x3c057fff, 0x8f620004, 0x00042080, 0x00902021, 0x8c830004, - 0x34a5ffff, 0x00451024, 0x00621821, 0xac830004, 0x93850038, 0x3c07ffff, - 0x93840010, 0x00052880, 0x00b02821, 0x8ca30000, 0x97420104, 0x97860020, - 0x00671824, 0x00441021, 0x00461023, 0x3042ffff, 0x00621825, 0xaca30000, - 0x93830023, 0x24020001, 0x10620009, 0x28620002, 0x1440001a, 0x24020002, - 0x10620018, 0x24020003, 0x1062000d, 0x00000000, 0x0a000411, 0x00000000, - 0x93820010, 0x97430104, 0x8e04000c, 0x00621821, 0x2463fff2, 0x3063ffff, - 0x00872024, 0x00832025, 0x0a000411, 0xae04000c, 0x93820010, 0x97430104, - 0x8e040010, 0x00621821, 0x2463ffee, 0x3063ffff, 0x00872024, 0x00832025, - 0xae040010, 0x9783000e, 0x8f840034, 0x2402000a, 0xa7420140, 0xa7430142, - 0x93820010, 0xa7420144, 0xa7400146, 0x97430104, 0x30840006, 0x24020001, - 0xa7430148, 0xa742014a, 0x24020002, 0x1082000d, 0x2c820003, 0x10400005, - 0x24020004, 0x10800011, 0x3c020041, 0x0a000437, 0x00000000, 0x10820007, - 0x24020006, 0x1482000d, 0x3c020151, 0x0a000431, 0x24030001, 0x0a000430, - 0x3c020141, 0x3c020051, 0x24030001, 0xaf421000, 0xaf830030, 0x0a000437, - 0x00000000, 0xaf421000, 0xaf800030, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x8f820030, 0x93840010, 0x8f850028, 0x10400005, 0x3c038000, - 0x8f421000, 0x00431024, 0x1040fffd, 0x00000000, 0x2483000a, 0x30620007, - 0x10400002, 0x24620007, 0x304303f8, 0x00a31021, 0x30421fff, 0xaf850018, - 0xaf820028, 0xaf420084, 0x97430104, 0x24424000, 0x0342d821, 0x3063ffff, - 0x30620007, 0x10400002, 0x24620007, 0x3043fff8, 0x8f820044, 0x8f840004, - 0x00431821, 0xaf82002c, 0x0064102b, 0xaf830044, 0x14400002, 0x00641023, - 0xaf820044, 0x8f840044, 0x34028000, 0x8fbf0014, 0x8fb00010, 0x00821021, - 0x03421821, 0x3c021000, 0xaf83001c, 0xaf440080, 0xaf420178, 0x03e00008, - 0x27bd0018, 0x3c026000, 0x8c444448, 0x3c030800, 0xac64082c, 0x8f620000, - 0x97430104, 0x3c048000, 0x3046ffff, 0x3067ffff, 0x8f420178, 0x00441024, - 0x1440fffd, 0x2402000a, 0x30c30007, 0xa7420140, 0x24020008, 0x00431023, - 0x30420007, 0x24c3fffe, 0xa7420142, 0xa7430144, 0xa7400146, 0xa7470148, - 0x8f420108, 0x3c036000, 0x8f850034, 0x30420020, 0x0002102b, 0x00021023, - 0x30420009, 0x34420001, 0xa742014a, 0x8c644448, 0x3c020800, 0x30a50006, - 0xac440830, 0x24020002, 0x10a2000d, 0x2ca20003, 0x10400005, 0x24020004, - 0x10a00011, 0x3c020041, 0x0a0004a8, 0x00000000, 0x10a20007, 0x24020006, - 0x14a2000d, 0x3c020151, 0x0a0004a2, 0x24030001, 0x0a0004a1, 0x3c020141, - 0x3c020051, 0x24030001, 0xaf421000, 0xaf830030, 0x0a0004a8, 0x00000000, - 0xaf421000, 0xaf800030, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x8f820030, 0x24c30008, 0x10400006, 0x30e6ffff, 0x3c048000, 0x8f421000, - 0x00441024, 0x1040fffd, 0x00000000, 0x3c026000, 0x8c444448, 0x3065ffff, - 0x3c020800, 0x30a30007, 0x10600003, 0xac440834, 0x24a20007, 0x3045fff8, - 0x8f840028, 0x00851021, 0x30421fff, 0x24434000, 0x0343d821, 0x30c30007, - 0xaf840018, 0xaf820028, 0xaf420084, 0x10600002, 0x24c20007, 0x3046fff8, - 0x8f820044, 0x8f840004, 0x00461821, 0xaf82002c, 0x0064102b, 0xaf830044, - 0x14400002, 0x00641023, 0xaf820044, 0x8f840044, 0x34028000, 0x3c030800, - 0x8c650844, 0x00821021, 0x03421821, 0xaf83001c, 0xaf440080, 0x10a00006, - 0x2402000e, 0x93830043, 0x14620004, 0x3c021000, 0x2402043f, 0xa7420148, - 0x3c021000, 0x3c036000, 0xaf420178, 0x8c644448, 0x3c020800, 0x03e00008, - 0xac440838, 0x8f820034, 0x30424000, 0x10400005, 0x24020800, 0x0000000d, - 0x00000000, 0x24000405, 0x24020800, 0xaf420178, 0x97440104, 0x3c030008, - 0xaf430140, 0x8f820034, 0x30420001, 0x10400006, 0x3085ffff, 0x24020002, - 0x24a3fffe, 0xa7420146, 0x0a0004ff, 0xa7430148, 0xa7400146, 0x8f840028, - 0x2402000d, 0xa742014a, 0x24830008, 0x30631fff, 0x24624000, 0x0342d821, - 0x30a20007, 0xaf840018, 0xaf830028, 0xaf430084, 0x10400002, 0x24a20007, - 0x3045fff8, 0x8f820044, 0x8f840004, 0x00451821, 0xaf82002c, 0x0064102b, - 0xaf830044, 0x14400002, 0x00641023, 0xaf820044, 0x8f840044, 0x34028000, - 0x00821021, 0x03421821, 0x3c021000, 0xaf83001c, 0xaf440080, 0x03e00008, - 0xaf420178, 0x27bdffe8, 0x3c046008, 0xafbf0014, 0xafb00010, 0x8c825000, - 0x3c1a8000, 0x2403ff7f, 0x375b4000, 0x00431024, 0x3442380c, 0xac825000, - 0x8f430008, 0x3c100800, 0x37428000, 0x34630001, 0xaf430008, 0xaf82001c, - 0x3c02601c, 0xaf800028, 0xaf400080, 0xaf400084, 0x8c450008, 0x3c036000, - 0x8c620808, 0x3c040800, 0x3c030080, 0xac830820, 0x3042fff0, 0x38420010, - 0x2c420001, 0xaf850004, 0xaf820008, 0x0e00062f, 0x00000000, 0x8f420000, - 0x30420001, 0x1040fffb, 0x00000000, 0x8f440108, 0x30822000, 0xaf840034, - 0x10400004, 0x8e02083c, 0x24420001, 0x0a00059d, 0xae02083c, 0x30820200, - 0x10400027, 0x00000000, 0x97420104, 0x1040001c, 0x30824000, 0x14400005, - 0x00000000, 0x0e00022d, 0x00000000, 0x0a000592, 0x00000000, 0x8f620008, - 0x8f630000, 0x24020030, 0x00031e02, 0x306300f0, 0x10620007, 0x28620031, - 0x14400031, 0x24020040, 0x10620007, 0x00000000, 0x0a000592, 0x00000000, - 0x0e0002dd, 0x00000000, 0x0a000592, 0x00000000, 0x0e0003b8, 0x00000000, - 0x0a000592, 0x00000000, 0x30820040, 0x1440002d, 0x00000000, 0x0000000d, - 0x00000000, 0x240004a6, 0x0a00059d, 0x00000000, 0x8f430100, 0x24020d00, - 0x1462000f, 0x30820006, 0x97420104, 0x10400005, 0x30820040, 0x0e0004e9, - 0x00000000, 0x0a000592, 0x00000000, 0x1440001b, 0x00000000, 0x0000000d, - 0x00000000, 0x240004b8, 0x0a00059d, 0x00000000, 0x1040000e, 0x30821000, - 0x10400005, 0x00000000, 0x0e00065d, 0x00000000, 0x0a000592, 0x00000000, - 0x0e00046b, 0x00000000, 0x8f820040, 0x24420001, 0xaf820040, 0x0a00059d, - 0x00000000, 0x30820040, 0x14400004, 0x00000000, 0x0000000d, 0x00000000, - 0x240004cf, 0x8f420138, 0x3c034000, 0x00431025, 0xaf420138, 0x0a00053f, - 0x00000000, 0x3c046008, 0x8c835000, 0x3c1a8000, 0x2402ff7f, 0x375b4000, - 0x00621824, 0x3463380c, 0xac835000, 0x8f420008, 0x3c056000, 0x3c03601c, - 0x34420001, 0xaf420008, 0x37428000, 0xaf800028, 0xaf82001c, 0xaf400080, - 0xaf400084, 0x8c660008, 0x8ca20808, 0x3c040800, 0x3c030080, 0xac830820, - 0x3042fff0, 0x38420010, 0x2c420001, 0xaf860004, 0xaf820008, 0x03e00008, - 0x00000000, 0x3084ffff, 0x30820007, 0x10400002, 0x24820007, 0x3044fff8, - 0x8f820028, 0x00441821, 0x30631fff, 0x24644000, 0x0344d821, 0xaf820018, - 0xaf830028, 0x03e00008, 0xaf430084, 0x3084ffff, 0x30820007, 0x10400002, - 0x24820007, 0x3044fff8, 0x8f820044, 0x8f830004, 0x00442021, 0xaf82002c, - 0x0083102b, 0xaf840044, 0x14400002, 0x00831023, 0xaf820044, 0x8f820044, - 0x34038000, 0x00431821, 0x03432021, 0xaf84001c, 0x03e00008, 0xaf420080, - 0x8f830034, 0x24020002, 0x30630006, 0x1062000d, 0x2c620003, 0x50400005, - 0x24020004, 0x10600012, 0x3c020001, 0x0a000601, 0x00000000, 0x10620007, - 0x24020006, 0x1462000f, 0x3c020111, 0x0a0005f9, 0x00821025, 0x0a0005f8, - 0x3c020101, 0x3c020011, 0x00821025, 0x24030001, 0xaf421000, 0xaf830030, - 0x0a000601, 0x00000000, 0x00821025, 0xaf421000, 0xaf800030, 0x00000000, - 0x00000000, 0x00000000, 0x03e00008, 0x00000000, 0x8f820030, 0x10400005, - 0x3c038000, 0x8f421000, 0x00431024, 0x1040fffd, 0x00000000, 0x03e00008, - 0x00000000, 0x8f820034, 0x27bdffe8, 0x30424000, 0x14400005, 0xafbf0010, - 0x0e00022d, 0x00000000, 0x0a00062d, 0x8fbf0010, 0x8f620008, 0x8f630000, - 0x24020030, 0x00031e02, 0x306300f0, 0x10620008, 0x28620031, 0x1440000d, - 0x8fbf0010, 0x24020040, 0x10620007, 0x00000000, 0x0a00062d, 0x00000000, - 0x0e0002dd, 0x00000000, 0x0a00062d, 0x8fbf0010, 0x0e0003b8, 0x00000000, - 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x8f84003c, 0x1080000f, 0x3c026000, - 0x8c430c3c, 0x30630fff, 0xaf830014, 0x14600011, 0x3082000f, 0x10400005, - 0x308200f0, 0x10400003, 0x30820f00, 0x14400006, 0x00000000, 0x0000000d, - 0x00000000, 0x2400050e, 0x03e00008, 0x00000000, 0x0000000d, 0x00000000, - 0x24000513, 0x03e00008, 0x00000000, 0xaf83003c, 0x03e00008, 0x00000000, - 0x10c00007, 0x00000000, 0x8ca20000, 0x24c6ffff, 0x24a50004, 0xac820000, - 0x14c0fffb, 0x24840004, 0x03e00008, 0x00000000, 0x0a000659, 0x00a01021, - 0xac860000, 0x24840004, 0x00a01021, 0x1440fffc, 0x24a5ffff, 0x03e00008, - 0x00000000, 0x0000000d, 0x03e00008, 0x00000000, 0x3c040800, 0x8c82084c, - 0x54400007, 0xac80084c, 0x8f820034, 0x24030400, 0x30420c00, 0x1443005b, - 0x00000000, 0xac80084c, 0x0000000d, 0x00000000, 0x2400003c, 0x3c026000, - 0x8c444448, 0x3c030800, 0xac640850, 0x24000043, 0x97420104, 0x3045ffff, - 0x000530c2, 0x24a2007f, 0x000239c2, 0x2400004e, 0x3c046020, 0x24030020, - 0xac830000, 0x8c820000, 0x30420020, 0x10400005, 0x3c036020, 0x8c620000, - 0x30420020, 0x1440fffd, 0x00000000, 0x3c026020, 0x8c430010, 0x24040001, - 0x0087102b, 0x30ea007f, 0x24abfffe, 0x10400010, 0x00034240, 0x3c056020, - 0x24090020, 0xaca90000, 0x8ca20000, 0x30420020, 0x10400006, 0x24840001, - 0x3c036020, 0x8c620000, 0x30420020, 0x1440fffd, 0x00000000, 0x0087102b, - 0x1440fff4, 0x00000000, 0x8f85001c, 0x3c026020, 0x8c430010, 0x3c046020, - 0x34848000, 0x006a1825, 0x01034025, 0x2400006b, 0x10c0000b, 0x00000000, - 0x8ca30000, 0x24a50004, 0x8ca20000, 0x24a50004, 0x24c6ffff, 0xac820000, - 0x24840004, 0xac830000, 0x14c0fff7, 0x24840004, 0x24000077, 0x3c020007, - 0x34427700, 0x3c036000, 0xac6223c8, 0xac6b23cc, 0xac6823e4, 0x24000086, - 0x3c046000, 0x3c038000, 0x8c8223f8, 0x00431024, 0x1440fffd, 0x3c021000, - 0x3c056000, 0x24030019, 0xaca223f8, 0xa743014a, 0x8ca44448, 0x3c020800, - 0xac440854, 0x03e00008, 0x00000000, 0x00000000 }; + 0x8f820024, 0x30420001, 0x10400007, 0x3069ffff, 0x24020002, 0x2523fffe, + 0xa7420146, 0xa7430148, 0x0a000242, 0x3c020800, 0xa7400146, 0x3c020800, + 0x8c43083c, 0x1460000e, 0x24020f00, 0x8f820024, 0x30430020, 0x0003182b, + 0x00031823, 0x30650009, 0x30420c00, 0x24030400, 0x14430002, 0x34a40001, + 0x34a40005, 0xa744014a, 0x0a000264, 0x3c020800, 0x8f830014, 0x14620008, + 0x00000000, 0x8f820024, 0x30420020, 0x0002102b, 0x00021023, 0x3042000d, + 0x0a000262, 0x34420005, 0x8f820024, 0x30420020, 0x0002102b, 0x00021023, + 0x30420009, 0x34420001, 0xa742014a, 0x3c020800, 0x8c430820, 0x8f840024, + 0x3c020048, 0x00621825, 0x30840006, 0x24020002, 0x1082000d, 0x2c820003, + 0x50400005, 0x24020004, 0x10800012, 0x3c020001, 0x0a000284, 0x00000000, + 0x10820007, 0x24020006, 0x1482000f, 0x3c020111, 0x0a00027c, 0x00621025, + 0x0a00027b, 0x3c020101, 0x3c020011, 0x00621025, 0x24030001, 0xaf421000, + 0xaf830020, 0x0a000284, 0x00000000, 0x00621025, 0xaf421000, 0xaf800020, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8f830020, 0x1060003f, + 0x3c048000, 0x8f421000, 0x00441024, 0x1040fffd, 0x00000000, 0x10600039, + 0x00000000, 0x8f421000, 0x3c030020, 0x00431024, 0x10400034, 0x00000000, + 0x97421014, 0x14400031, 0x00000000, 0x97421008, 0x8f840010, 0x24420006, + 0x00024082, 0x00081880, 0x00643821, 0x8ce50000, 0x30430003, 0x30420001, + 0x10400004, 0x00000000, 0x0000000d, 0x0a0002c3, 0x00081080, 0x5460000f, + 0x30a5ffff, 0x3c06ffff, 0x00a62824, 0x0005182b, 0x00a61026, 0x0002102b, + 0x00621824, 0x10600004, 0x00000000, 0x0000000d, 0x00000000, 0x240001fb, + 0x8ce20000, 0x0a0002c2, 0x00462825, 0x0005182b, 0x38a2ffff, 0x0002102b, + 0x00621824, 0x10600004, 0x00000000, 0x0000000d, 0x00000000, 0x24000205, + 0x8ce20000, 0x3445ffff, 0x00081080, 0x00441021, 0x3c030800, 0xac450000, + 0x8c620830, 0x24420001, 0xac620830, 0x8f840018, 0x01202821, 0x24820008, + 0x30421fff, 0x24434000, 0x0343d821, 0x30a30007, 0xaf84000c, 0xaf820018, + 0xaf420084, 0x10600002, 0x24a20007, 0x3045fff8, 0x8f820030, 0x8f840000, + 0x00451821, 0xaf82001c, 0x0064102b, 0xaf830030, 0x14400002, 0x00641023, + 0xaf820030, 0x8f840030, 0x34028000, 0x00821021, 0x03421821, 0x3c021000, + 0xaf830010, 0xaf440080, 0x03e00008, 0xaf420178, 0x8f830024, 0x27bdffe0, + 0xafbf0018, 0xafb10014, 0x30620200, 0x14400004, 0xafb00010, 0x0000000d, + 0x00000000, 0x24000242, 0x00031a82, 0x30630003, 0x000310c0, 0x00431021, + 0x00021080, 0x00431021, 0x00021080, 0x3c030800, 0x24631aa0, 0x00438821, + 0x8e240000, 0x10800004, 0x00000000, 0x0000000d, 0x00000000, 0x2400024d, + 0x8f850010, 0x24020001, 0xae220000, 0x8ca70008, 0xa2200007, 0x8f620004, + 0x26300014, 0x02002021, 0x00021402, 0xa2220004, 0x304600ff, 0x24c60005, + 0x0e000673, 0x00063082, 0x8f620004, 0xa6220008, 0x8f430108, 0x3c021000, + 0x00621824, 0x10600008, 0x00000000, 0x97420104, 0x92230007, 0x2442ffec, + 0x3045ffff, 0x34630002, 0x0a000321, 0xa2230007, 0x97420104, 0x2442fff0, + 0x3045ffff, 0x8f620004, 0x3042ffff, 0x2c420013, 0x54400005, 0x92230007, + 0x92220007, 0x34420001, 0xa2220007, 0x92230007, 0x24020001, 0x10620009, + 0x28620002, 0x14400014, 0x24020002, 0x10620012, 0x24020003, 0x1062000a, + 0x00000000, 0x0a000342, 0x00000000, 0x8f820010, 0x8c43000c, 0x3c04ffff, + 0x00641824, 0x00651825, 0x0a000342, 0xac43000c, 0x8f820010, 0x8c430010, + 0x3c04ffff, 0x00641824, 0x00651825, 0xac430010, 0x8f620004, 0x3042ffff, + 0x24420002, 0x00021083, 0xa2220005, 0x304500ff, 0x8f820010, 0x3c04ffff, + 0x00052880, 0x00a22821, 0x8ca70000, 0x96220008, 0x97430104, 0x00e42024, + 0x24420002, 0x00621823, 0x00833825, 0xaca70000, 0x92240005, 0x00041080, + 0x02021021, 0x90430000, 0x3c05fff6, 0x34a5ffff, 0x3063000f, 0x00832021, + 0xa2240006, 0x308200ff, 0x24420003, 0x00021080, 0x02021021, 0x8c460000, + 0x308300ff, 0x8f820010, 0x3c04ff3f, 0x00031880, 0x00c53824, 0x00621821, + 0xae26000c, 0xac67000c, 0x8e22000c, 0x92230006, 0x3484ffff, 0x00441024, + 0x24630003, 0x00031880, 0x02031821, 0x00e42024, 0xae22000c, 0xac640000, + 0x92220006, 0x24420004, 0x00021080, 0x02021021, 0x94470002, 0xac470000, + 0x92230006, 0x8f820010, 0x00031880, 0x00621821, 0x24020010, 0xac670010, + 0x24030002, 0xa7420140, 0xa7400142, 0xa7400144, 0xa7430146, 0x97420104, + 0x24030001, 0x2442fffe, 0xa7420148, 0xa743014a, 0x8f820024, 0x24030002, + 0x30440006, 0x1083000d, 0x2c820003, 0x10400005, 0x24020004, 0x10800011, + 0x3c020009, 0x0a0003a5, 0x00000000, 0x10820007, 0x24020006, 0x1482000d, + 0x3c020119, 0x0a00039f, 0x24030001, 0x0a00039e, 0x3c020109, 0x3c020019, + 0x24030001, 0xaf421000, 0xaf830020, 0x0a0003a5, 0x00000000, 0xaf421000, + 0xaf800020, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x92220004, + 0x24030008, 0x8f840020, 0x24420002, 0x30420007, 0x00621823, 0x30630007, + 0x10800006, 0xae230010, 0x3c038000, 0x8f421000, 0x00431024, 0x1040fffd, + 0x00000000, 0x8f820018, 0xaf82000c, 0x24420010, 0x30421fff, 0xaf820018, + 0xaf420084, 0x97430104, 0x24424000, 0x0342d821, 0x3063ffff, 0x30620007, + 0x10400002, 0x24620007, 0x3043fff8, 0x8f820030, 0x8f840000, 0x00431821, + 0xaf82001c, 0x0064102b, 0xaf830030, 0x14400002, 0x00641023, 0xaf820030, + 0x8f840030, 0x34028000, 0x8fbf0018, 0x8fb10014, 0x8fb00010, 0x00821021, + 0x03421821, 0x3c021000, 0xaf830010, 0xaf440080, 0xaf420178, 0x03e00008, + 0x27bd0020, 0x8f830024, 0x27bdffe0, 0xafbf0018, 0xafb10014, 0x30620200, + 0x14400004, 0xafb00010, 0x0000000d, 0x00000000, 0x240002e4, 0x00031a82, + 0x30630003, 0x000310c0, 0x00431021, 0x00021080, 0x00431021, 0x00021080, + 0x3c030800, 0x24631aa0, 0x00438021, 0x8e040000, 0x14800004, 0x00000000, + 0x0000000d, 0x00000000, 0x240002e9, 0x8f620004, 0x04410008, 0x26050014, + 0x92020006, 0x8e03000c, 0x24420003, 0x00021080, 0x00a21021, 0xac430000, + 0xae000000, 0x92020005, 0x24420001, 0x00021080, 0x00a21021, 0x8c430000, + 0x3c040001, 0x00641821, 0xac430000, 0x92060004, 0x27710008, 0x02202021, + 0x24c60005, 0x0e000673, 0x00063082, 0x92040006, 0x3c057fff, 0x8f620004, + 0x00042080, 0x00912021, 0x8c830004, 0x34a5ffff, 0x00451024, 0x00621821, + 0xac830004, 0x92050005, 0x3c07ffff, 0x92040004, 0x00052880, 0x00b12821, + 0x8ca30000, 0x97420104, 0x96060008, 0x00671824, 0x00441021, 0x00461023, + 0x3042ffff, 0x00621825, 0xaca30000, 0x92030007, 0x24020001, 0x1062000a, + 0x28620002, 0x1440001d, 0x2402000a, 0x24020002, 0x10620019, 0x24020003, + 0x1062000e, 0x2402000a, 0x0a000447, 0x00000000, 0x92020004, 0x97430104, + 0x8e24000c, 0x00621821, 0x2463fff2, 0x3063ffff, 0x00872024, 0x00832025, + 0xae24000c, 0x0a000447, 0x2402000a, 0x92020004, 0x97430104, 0x8e240010, + 0x00621821, 0x2463ffee, 0x3063ffff, 0x00872024, 0x00832025, 0xae240010, + 0x2402000a, 0xa7420140, 0x96030012, 0x8f840024, 0xa7430142, 0x92020004, + 0xa7420144, 0xa7400146, 0x97430104, 0x30840006, 0x24020001, 0xa7430148, + 0xa742014a, 0x24020002, 0x1082000d, 0x2c820003, 0x10400005, 0x24020004, + 0x10800011, 0x3c020041, 0x0a00046c, 0x00000000, 0x10820007, 0x24020006, + 0x1482000d, 0x3c020151, 0x0a000466, 0x24030001, 0x0a000465, 0x3c020141, + 0x3c020051, 0x24030001, 0xaf421000, 0xaf830020, 0x0a00046c, 0x00000000, + 0xaf421000, 0xaf800020, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x8f820020, 0x8f840018, 0x10400006, 0x92030004, 0x3c058000, 0x8f421000, + 0x00451024, 0x1040fffd, 0x00000000, 0x2463000a, 0x30620007, 0x10400002, + 0x24620007, 0x304303f8, 0x00831021, 0x30421fff, 0xaf84000c, 0xaf820018, + 0xaf420084, 0x97430104, 0x24424000, 0x0342d821, 0x3063ffff, 0x30620007, + 0x10400002, 0x24620007, 0x3043fff8, 0x8f820030, 0x8f840000, 0x00431821, + 0xaf82001c, 0x0064102b, 0xaf830030, 0x14400002, 0x00641023, 0xaf820030, + 0x8f840030, 0x34028000, 0x8fbf0018, 0x8fb10014, 0x8fb00010, 0x00821021, + 0x03421821, 0x3c021000, 0xaf830010, 0xaf440080, 0xaf420178, 0x03e00008, + 0x27bd0020, 0x8f620000, 0x97430104, 0x3c048000, 0x3045ffff, 0x3066ffff, + 0x8f420178, 0x00441024, 0x1440fffd, 0x2402000a, 0x30a30007, 0xa7420140, + 0x24020008, 0x00431023, 0x30420007, 0x24a3fffe, 0xa7420142, 0xa7430144, + 0xa7400146, 0xa7460148, 0x8f420108, 0x8f830024, 0x30420020, 0x0002102b, + 0x00021023, 0x30420009, 0x34420001, 0x30630006, 0xa742014a, 0x24020002, + 0x1062000d, 0x2c620003, 0x10400005, 0x24020004, 0x10600011, 0x3c020041, + 0x0a0004d6, 0x00000000, 0x10620007, 0x24020006, 0x1462000d, 0x3c020151, + 0x0a0004d0, 0x24030001, 0x0a0004cf, 0x3c020141, 0x3c020051, 0x24030001, + 0xaf421000, 0xaf830020, 0x0a0004d6, 0x00000000, 0xaf421000, 0xaf800020, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8f820020, 0x24a30008, + 0x8f850018, 0x10400006, 0x30c6ffff, 0x3c048000, 0x8f421000, 0x00441024, + 0x1040fffd, 0x00000000, 0x3063ffff, 0x30620007, 0x10400002, 0x24620007, + 0x3043fff8, 0x00a31021, 0x30421fff, 0x24434000, 0x0343d821, 0x00c02021, + 0x30830007, 0xaf85000c, 0xaf820018, 0xaf420084, 0x10600002, 0x24820007, + 0x3044fff8, 0x8f820030, 0x8f850000, 0x00441821, 0xaf82001c, 0x0065102b, + 0xaf830030, 0x14400002, 0x00651023, 0xaf820030, 0x8f840030, 0x34028000, + 0x3c030800, 0x8c650834, 0x00821021, 0x03421821, 0xaf830010, 0xaf440080, + 0x10a00006, 0x2402000e, 0x9383002f, 0x14620004, 0x3c021000, 0x2402043f, + 0xa7420148, 0x3c021000, 0x03e00008, 0xaf420178, 0x8f820024, 0x30424000, + 0x10400005, 0x24020800, 0x0000000d, 0x00000000, 0x2400040e, 0x24020800, + 0xaf420178, 0x97440104, 0x3c030008, 0xaf430140, 0x8f820024, 0x30420001, + 0x10400006, 0x3085ffff, 0x24020002, 0x24a3fffe, 0xa7420146, 0x0a000526, + 0xa7430148, 0xa7400146, 0x8f840018, 0x2402000d, 0xa742014a, 0x24830008, + 0x30631fff, 0x24624000, 0x0342d821, 0x30a20007, 0xaf84000c, 0xaf830018, + 0xaf430084, 0x10400002, 0x24a20007, 0x3045fff8, 0x8f820030, 0x8f840000, + 0x00451821, 0xaf82001c, 0x0064102b, 0xaf830030, 0x14400002, 0x00641023, + 0xaf820030, 0x8f840030, 0x34028000, 0x00821021, 0x03421821, 0x3c021000, + 0xaf830010, 0xaf440080, 0x03e00008, 0xaf420178, 0x27bdffe8, 0x3c046008, + 0xafbf0014, 0xafb00010, 0x8c825000, 0x3c1a8000, 0x2403ff7f, 0x375b4000, + 0x00431024, 0x3442380c, 0xac825000, 0x8f430008, 0x3c100800, 0x37428000, + 0x34630001, 0xaf430008, 0xaf820010, 0x3c02601c, 0xaf800018, 0xaf400080, + 0xaf400084, 0x8c450008, 0x3c036000, 0x8c620808, 0x3c040800, 0x3c030080, + 0xac830820, 0x3042fff0, 0x38420010, 0x2c420001, 0xaf850000, 0xaf820004, + 0x0e000658, 0x00000000, 0x8f420000, 0x30420001, 0x1040fffb, 0x00000000, + 0x8f430108, 0x8f440100, 0x30622000, 0xaf830024, 0xaf840014, 0x10400004, + 0x8e02082c, 0x24420001, 0x0a0005c6, 0xae02082c, 0x30620200, 0x14400003, + 0x24020f00, 0x14820027, 0x24020d00, 0x97420104, 0x1040001c, 0x30624000, + 0x14400005, 0x00000000, 0x0e00022f, 0x00000000, 0x0a0005bb, 0x00000000, + 0x8f620008, 0x8f630000, 0x24020030, 0x00031e02, 0x306300f0, 0x10620007, + 0x28620031, 0x1440002f, 0x24020040, 0x10620007, 0x00000000, 0x0a0005bb, + 0x00000000, 0x0e0002e8, 0x00000000, 0x0a0005bb, 0x00000000, 0x0e0003db, + 0x00000000, 0x0a0005bb, 0x00000000, 0x30620040, 0x1440002b, 0x00000000, + 0x0000000d, 0x00000000, 0x240004b2, 0x0a0005c6, 0x00000000, 0x1482000f, + 0x30620006, 0x97420104, 0x10400005, 0x30620040, 0x0e000510, 0x00000000, + 0x0a0005bb, 0x00000000, 0x1440001b, 0x00000000, 0x0000000d, 0x00000000, + 0x240004c4, 0x0a0005c6, 0x00000000, 0x1040000e, 0x30621000, 0x10400005, + 0x00000000, 0x0e000688, 0x00000000, 0x0a0005bb, 0x00000000, 0x0e0004a1, + 0x00000000, 0x8f82002c, 0x24420001, 0xaf82002c, 0x0a0005c6, 0x00000000, + 0x30620040, 0x14400004, 0x00000000, 0x0000000d, 0x00000000, 0x240004db, + 0x8f420138, 0x3c034000, 0x00431025, 0xaf420138, 0x0a000566, 0x00000000, + 0x3c046008, 0x8c835000, 0x3c1a8000, 0x2402ff7f, 0x375b4000, 0x00621824, + 0x3463380c, 0xac835000, 0x8f420008, 0x3c056000, 0x3c03601c, 0x34420001, + 0xaf420008, 0x37428000, 0xaf800018, 0xaf820010, 0xaf400080, 0xaf400084, + 0x8c660008, 0x8ca20808, 0x3c040800, 0x3c030080, 0xac830820, 0x3042fff0, + 0x38420010, 0x2c420001, 0xaf860000, 0xaf820004, 0x03e00008, 0x00000000, + 0x3084ffff, 0x30820007, 0x10400002, 0x24820007, 0x3044fff8, 0x8f820018, + 0x00441821, 0x30631fff, 0x24644000, 0x0344d821, 0xaf82000c, 0xaf830018, + 0x03e00008, 0xaf430084, 0x3084ffff, 0x30820007, 0x10400002, 0x24820007, + 0x3044fff8, 0x8f820030, 0x8f830000, 0x00442021, 0xaf82001c, 0x0083102b, + 0xaf840030, 0x14400002, 0x00831023, 0xaf820030, 0x8f820030, 0x34038000, + 0x00431821, 0x03432021, 0xaf840010, 0x03e00008, 0xaf420080, 0x8f830024, + 0x24020002, 0x30630006, 0x1062000d, 0x2c620003, 0x50400005, 0x24020004, + 0x10600012, 0x3c020001, 0x0a00062a, 0x00000000, 0x10620007, 0x24020006, + 0x1462000f, 0x3c020111, 0x0a000622, 0x00821025, 0x0a000621, 0x3c020101, + 0x3c020011, 0x00821025, 0x24030001, 0xaf421000, 0xaf830020, 0x0a00062a, + 0x00000000, 0x00821025, 0xaf421000, 0xaf800020, 0x00000000, 0x00000000, + 0x00000000, 0x03e00008, 0x00000000, 0x8f820020, 0x10400005, 0x3c038000, + 0x8f421000, 0x00431024, 0x1040fffd, 0x00000000, 0x03e00008, 0x00000000, + 0x8f820024, 0x27bdffe8, 0x30424000, 0x14400005, 0xafbf0010, 0x0e00022f, + 0x00000000, 0x0a000656, 0x8fbf0010, 0x8f620008, 0x8f630000, 0x24020030, + 0x00031e02, 0x306300f0, 0x10620008, 0x28620031, 0x1440000d, 0x8fbf0010, + 0x24020040, 0x10620007, 0x00000000, 0x0a000656, 0x00000000, 0x0e0002e8, + 0x00000000, 0x0a000656, 0x8fbf0010, 0x0e0003db, 0x00000000, 0x8fbf0010, + 0x03e00008, 0x27bd0018, 0x8f840028, 0x1080000f, 0x3c026000, 0x8c430c3c, + 0x30630fff, 0xaf830008, 0x14600011, 0x3082000f, 0x10400005, 0x308200f0, + 0x10400003, 0x30820f00, 0x14400006, 0x00000000, 0x0000000d, 0x00000000, + 0x2400051a, 0x03e00008, 0x00000000, 0x0000000d, 0x00000000, 0x2400051f, + 0x03e00008, 0x00000000, 0xaf830028, 0x03e00008, 0x00000000, 0x10c00007, + 0x00000000, 0x8ca20000, 0x24c6ffff, 0x24a50004, 0xac820000, 0x14c0fffb, + 0x24840004, 0x03e00008, 0x00000000, 0x0a000684, 0x00a01021, 0xac860000, + 0x00000000, 0x00000000, 0x24840004, 0x00a01021, 0x1440fffa, 0x24a5ffff, + 0x03e00008, 0x00000000, 0x0000000d, 0x03e00008, 0x00000000, 0x00000000}; -static u32 bnx2_TPAT_b06FwData[(0x0/4) + 1] = { 0x00000000 }; -static u32 bnx2_TPAT_b06FwRodata[(0x0/4) + 1] = { 0x00000000 }; -static u32 bnx2_TPAT_b06FwBss[(0x80/4) + 1] = { 0x00000000 }; -static u32 bnx2_TPAT_b06FwSbss[(0x48/4) + 1] = { 0x00000000 }; +static u32 bnx2_TPAT_b06FwData[(0x0/4) + 1] = { 0x0 }; +static u32 bnx2_TPAT_b06FwRodata[(0x0/4) + 1] = { 0x0 }; +static u32 bnx2_TPAT_b06FwBss[(0x250/4) + 1] = { 0x0 }; +static u32 bnx2_TPAT_b06FwSbss[(0x34/4) + 1] = { 0x0 }; -static int bnx2_TXP_b06FwReleaseMajor = 0x0; +static int bnx2_TXP_b06FwReleaseMajor = 0x1; static int bnx2_TXP_b06FwReleaseMinor = 0x0; static int bnx2_TXP_b06FwReleaseFix = 0x0; -static u32 bnx2_TXP_b06FwStartAddr = 0x08002090; +static u32 bnx2_TXP_b06FwStartAddr = 0x080034b0; static u32 bnx2_TXP_b06FwTextAddr = 0x08000000; -static int bnx2_TXP_b06FwTextLen = 0x3ffc; -static u32 bnx2_TXP_b06FwDataAddr = 0x08004020; +static int bnx2_TXP_b06FwTextLen = 0x5748; +static u32 bnx2_TXP_b06FwDataAddr = 0x08005760; static int bnx2_TXP_b06FwDataLen = 0x0; static u32 bnx2_TXP_b06FwRodataAddr = 0x00000000; static int bnx2_TXP_b06FwRodataLen = 0x0; -static u32 bnx2_TXP_b06FwBssAddr = 0x08004060; -static int bnx2_TXP_b06FwBssLen = 0x194; -static u32 bnx2_TXP_b06FwSbssAddr = 0x08004020; -static int bnx2_TXP_b06FwSbssLen = 0x34; -static u32 bnx2_TXP_b06FwText[(0x3ffc/4) + 1] = { - 0x0a000824, 0x00000000, 0x00000000, 0x0000000d, 0x74787020, 0x302e362e, - 0x39000000, 0x00060900, 0x0000000a, 0x000003e8, 0x0000ea60, 0x00000000, +static u32 bnx2_TXP_b06FwBssAddr = 0x080057a0; +static int bnx2_TXP_b06FwBssLen = 0x1c4; +static u32 bnx2_TXP_b06FwSbssAddr = 0x08005760; +static int bnx2_TXP_b06FwSbssLen = 0x38; +static u32 bnx2_TXP_b06FwText[(0x5748/4) + 1] = { + 0x0a000d2c, 0x00000000, 0x00000000, 0x0000000d, 0x74787020, 0x322e352e, + 0x38000000, 0x02050800, 0x0000000a, 0x000003e8, 0x0000ea60, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, @@ -2124,55 +2965,182 @@ static u32 bnx2_TXP_b06FwText[(0x3ffc/4) + 1] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x10000003, 0x00000000, 0x0000000d, - 0x0000000d, 0x3c020800, 0x24424020, 0x3c030800, 0x246341f4, 0xac400000, - 0x0043202b, 0x1480fffd, 0x24420004, 0x3c1d0800, 0x37bd7ffc, 0x03a0f021, - 0x3c100800, 0x26102090, 0x3c1c0800, 0x279c4020, 0x0e000a0e, 0x00000000, - 0x0000000d, 0x8f840014, 0x27bdffe8, 0xafb00010, 0x8f460104, 0x8f830008, - 0x8c8500ac, 0xaf430080, 0x948200a8, 0xa7420e10, 0x948300aa, 0xa7430e12, - 0x8c8200ac, 0xaf420e18, 0x97430e10, 0xa7430e14, 0x97420e12, 0xa7420e16, - 0x8f430e18, 0x00005021, 0x00c53023, 0x10c001a3, 0xaf430e1c, 0x240f0800, - 0x3c0e1000, 0x2419fff8, 0x24100010, 0x3c188100, 0x93620008, 0x10400009, - 0x00000000, 0x97620010, 0x00c2102b, 0x14400005, 0x00000000, 0x97620010, - 0x3042ffff, 0x0a000862, 0xaf420e00, 0xaf460e00, 0x8f420000, 0x30420008, - 0x1040fffd, 0x00000000, 0x97420e08, 0x8f450e04, 0x3044ffff, 0x30820001, - 0x14400005, 0x00000000, 0x14a00005, 0x3083a040, 0x0a0009e6, 0x00000000, - 0x0000000d, 0x3083a040, 0x24020040, 0x14620049, 0x3082a000, 0x8f87000c, - 0x30880036, 0x30890008, 0xaf4f0178, 0x00e01821, 0x9742008a, 0x00431023, - 0x2442ffff, 0x30421fff, 0x2c420008, 0x1440fffa, 0x00000000, 0x8f830018, - 0x00a05021, 0x00c53023, 0x24e24000, 0x03422821, 0x306b00ff, 0x24630001, - 0xaf830018, 0x93840012, 0x000b1400, 0x3c030100, 0x00431025, 0xaca20000, - 0x8f820018, 0x30840007, 0x00042240, 0x34870001, 0x00e83825, 0x1120000f, - 0xaca20004, 0x97430e0a, 0x8f84000c, 0x00ee3825, 0x2402000e, 0x00781825, - 0xaf430160, 0x25430006, 0x24840008, 0x30841fff, 0xa742015a, 0xa7430158, - 0xaf84000c, 0x0a0008a9, 0x00000000, 0x8f83000c, 0x25420002, 0xa7420158, - 0x24630008, 0x30631fff, 0xaf83000c, 0x54c0000c, 0x8f420e14, 0x97420e10, - 0x97430e12, 0x8f840014, 0x00021400, 0x00621825, 0xac8300a8, 0x8f850014, - 0x8f420e18, 0x34e70040, 0xaca200ac, 0x8f420e14, 0x8f430e1c, 0xaf420144, - 0xaf430148, 0xa34b0152, 0xaf470154, 0x0a0009f1, 0xaf4e0178, 0x10400128, - 0x00000000, 0x97620010, 0x00a2102b, 0x10400003, 0x30820040, 0x10400122, - 0x00000000, 0xafa60008, 0xa7840010, 0xaf850004, 0x93620008, 0x1440005e, - 0x27ac0008, 0xaf60000c, 0x97820010, 0x30424000, 0x10400002, 0x2403000e, - 0x24030016, 0xa363000a, 0x24034007, 0xaf630014, 0x93820012, 0x8f630014, - 0x30420007, 0x00021240, 0x00621825, 0xaf630014, 0x97820010, 0x8f630014, - 0x30420010, 0x00621825, 0xaf630014, 0x97820010, 0x30420008, 0x5040000e, - 0x00002821, 0x8f620014, 0x004e1025, 0xaf620014, 0x97430e0a, 0x2402000e, - 0x00781825, 0xaf630004, 0xa3620002, 0x9363000a, 0x3405fffc, 0x24630004, - 0x0a0008f2, 0xa363000a, 0xaf600004, 0xa3600002, 0x97820010, 0x9363000a, - 0x30421f00, 0x00021182, 0x24420028, 0x00621821, 0xa3630009, 0x97420e0c, - 0xa7620010, 0x93630009, 0x24020008, 0x24630002, 0x30630007, 0x00431023, - 0x30420007, 0xa362000b, 0x93640009, 0x97620010, 0x8f890004, 0x97830010, - 0x00441021, 0x00a21021, 0x30630040, 0x10600006, 0x3045ffff, 0x15250005, - 0x0125102b, 0x3c068000, 0x0a000925, 0x00005821, 0x0125102b, 0x144000c8, - 0x00005021, 0x97420e14, 0xa7420e10, 0x97430e16, 0xa7430e12, 0x8f420e1c, - 0xaf420e18, 0xaf450e00, 0x8f420000, 0x30420008, 0x1040fffd, 0x00000000, - 0x97420e08, 0x00a04821, 0xa7820010, 0x8f430e04, 0x00003021, 0x240b0001, - 0xaf830004, 0x97620010, 0x0a000936, 0x304dffff, 0x8f890004, 0x97820010, - 0x30420040, 0x10400004, 0x01206821, 0x3c068000, 0x0a000936, 0x00005821, - 0x97630010, 0x8f820004, 0x144300a7, 0x00005021, 0x00003021, 0x240b0001, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c020800, + 0x24425760, 0x3c030800, 0x24635964, 0xac400000, 0x0043202b, 0x1480fffd, + 0x24420004, 0x3c1d0800, 0x37bd7ffc, 0x03a0f021, 0x3c100800, 0x261034b0, + 0x3c1c0800, 0x279c5760, 0x0e000f5b, 0x00000000, 0x0000000d, 0x8f840014, + 0x27bdffe8, 0xafb10014, 0xafb00010, 0x8f460104, 0x8f830008, 0x8c8500ac, + 0xaf430080, 0x948200a8, 0xa7420e10, 0x948300aa, 0xa7430e12, 0x8c8200ac, + 0xaf420e18, 0x97430e10, 0xa7430e14, 0x97420e12, 0x00008021, 0xa7420e16, + 0x8f430e18, 0x00006021, 0x00c53023, 0xaf430e1c, 0x10c001a2, 0x2d820001, + 0x3c0e1000, 0x2419fff8, 0x24110010, 0x240f0f00, 0x3c188100, 0x93620008, + 0x10400009, 0x00000000, 0x97620010, 0x00c2102b, 0x14400005, 0x00000000, + 0x97620010, 0x3042ffff, 0x0a000d6d, 0xaf420e00, 0xaf460e00, 0x8f420000, + 0x30420008, 0x1040fffd, 0x00000000, 0x97420e08, 0x8f450e04, 0x3044ffff, + 0x30820001, 0x14400005, 0x00000000, 0x14a00005, 0x3083a040, 0x0a000f34, + 0x00000000, 0x0000000d, 0x3083a040, 0x24020040, 0x1462004f, 0x3082a000, + 0x308a0036, 0x8f88000c, 0x30890008, 0x24020800, 0xaf420178, 0x01001821, + 0x9742008a, 0x00431023, 0x2442ffff, 0x30421fff, 0x2c420008, 0x1440fffa, + 0x00a06021, 0x8f820018, 0x00cc3023, 0x24070001, 0x8f830008, 0x304b00ff, + 0x24420001, 0xaf820018, 0x25024000, 0x106f0005, 0x03422021, 0x93820012, + 0x30420007, 0x00021240, 0x34470001, 0x000b1400, 0x3c030100, 0x00431025, + 0xac820000, 0x8f830018, 0x00ea3825, 0x1120000f, 0xac830004, 0x97430e0a, + 0x8f84000c, 0x00ee3825, 0x2402000e, 0x00781825, 0xaf430160, 0x25830006, + 0x24840008, 0x30841fff, 0xa742015a, 0xa7430158, 0xaf84000c, 0x0a000db7, + 0x00000000, 0x8f83000c, 0x25820002, 0xa7420158, 0x24630008, 0x30631fff, + 0xaf83000c, 0x54c0000f, 0x8f420e14, 0x8f820008, 0x504f0002, 0x24100001, + 0x34e70040, 0x97420e10, 0x97430e12, 0x8f850014, 0x00021400, 0x00621825, + 0xaca300a8, 0x8f840014, 0x8f420e18, 0xac8200ac, 0x8f420e14, 0x8f430e1c, + 0xaf420144, 0xaf430148, 0xa34b0152, 0xaf470154, 0x0a000efb, 0xaf4e0178, + 0x10400165, 0x00000000, 0x93620008, 0x50400008, 0xafa60008, 0x97620010, + 0x00a2102b, 0x10400003, 0x30820040, 0x1040015c, 0x00000000, 0xafa60008, + 0xa7840010, 0xaf850004, 0x93620008, 0x1440005f, 0x27ac0008, 0xaf60000c, + 0x97820010, 0x30424000, 0x10400002, 0x2403000e, 0x24030016, 0xa363000a, + 0x24034007, 0xaf630014, 0x93820012, 0x8f630014, 0x30420007, 0x00021240, + 0x00621825, 0xaf630014, 0x97820010, 0x8f630014, 0x30420010, 0x00621825, + 0xaf630014, 0x97820010, 0x30420008, 0x5040000e, 0x00002821, 0x8f620014, + 0x004e1025, 0xaf620014, 0x97430e0a, 0x2402000e, 0x00781825, 0xaf630004, + 0xa3620002, 0x9363000a, 0x3405fffc, 0x24630004, 0x0a000e06, 0xa363000a, + 0xaf600004, 0xa3600002, 0x97820010, 0x9363000a, 0x30421f00, 0x00021182, + 0x24420028, 0x00621821, 0xa3630009, 0x97420e0c, 0xa7620010, 0x93630009, + 0x24020008, 0x24630002, 0x30630007, 0x00431023, 0x30420007, 0xa362000b, + 0x93640009, 0x97620010, 0x8f890004, 0x97830010, 0x00441021, 0x00a21021, + 0x30630040, 0x10600007, 0x3045ffff, 0x00a9102b, 0x14400005, 0x0125102b, + 0x3c068000, 0x0a000e3a, 0x00005821, 0x0125102b, 0x544000c7, 0x00006021, + 0x97420e14, 0xa7420e10, 0x97430e16, 0xa7430e12, 0x8f420e1c, 0xaf420e18, + 0xaf450e00, 0x8f420000, 0x30420008, 0x1040fffd, 0x00000000, 0x97420e08, + 0x00a04821, 0xa7820010, 0x8f430e04, 0x00003021, 0x240b0001, 0xaf830004, + 0x97620010, 0x0a000e4c, 0x304dffff, 0x8f890004, 0x97820010, 0x30420040, + 0x10400004, 0x01206821, 0x3c068000, 0x0a000e4c, 0x00005821, 0x97630010, + 0x8f820004, 0x10430003, 0x00003021, 0x0a000eee, 0x00006021, 0x240b0001, 0x8d820000, 0x00491023, 0x1440000d, 0xad820000, 0x8f620014, 0x34420040, 0xaf620014, 0x97430e10, 0x97420e12, 0x8f840014, 0x00031c00, 0x00431025, - 0xac8200a8, 0x8f830014, 0x8f420e18, 0xac6200ac, 0x93620008, 0x1440003f, + 0xac8200a8, 0x8f830014, 0x8f420e18, 0xac6200ac, 0x93620008, 0x1440003e, 0x00000000, 0x25260002, 0x8f84000c, 0x9743008a, 0x3063ffff, 0xafa30000, 0x8fa20000, 0x00441023, 0x2442ffff, 0x30421fff, 0x2c420010, 0x1440fff7, 0x00000000, 0x8f82000c, 0x8f830018, 0x00021082, 0x00021080, 0x24424000, @@ -2180,289 +3148,320 @@ static u32 bnx2_TXP_b06FwText[(0x3ffc/4) + 1] = { 0x3c033200, 0x00431025, 0xaca20000, 0x93630009, 0x9362000a, 0x00031c00, 0x00431025, 0xaca20004, 0x8f830018, 0xaca30008, 0x97820010, 0x30420008, 0x10400002, 0x00c04021, 0x25280006, 0x97430e14, 0x93640002, 0x8f450e1c, - 0x8f660004, 0x8f670014, 0xaf4f0178, 0x3063ffff, 0xa7430144, 0x97420e16, - 0xa7420146, 0xaf450148, 0xa34a0152, 0x8f82000c, 0x308400ff, 0xa744015a, - 0xaf460160, 0xa7480158, 0xaf470154, 0xaf4e0178, 0x00501021, 0x30421fff, - 0xaf82000c, 0x0a0009c5, 0x8d820000, 0x93620009, 0x9363000b, 0x8f85000c, - 0x2463000a, 0x00435021, 0x25440007, 0x00992024, 0x9743008a, 0x3063ffff, - 0xafa30000, 0x8fa20000, 0x00451023, 0x2442ffff, 0x30421fff, 0x0044102b, - 0x1440fff7, 0x00000000, 0x8f82000c, 0x8f840018, 0x00021082, 0x00021080, - 0x24424000, 0x03422821, 0x00804021, 0x24840001, 0xaf840018, 0x93630009, - 0x310200ff, 0x00022400, 0x3c024100, 0x24630002, 0x00621825, 0x00832025, - 0xaca40000, 0x8f62000c, 0x00461025, 0xaca20004, 0x97430e14, 0x93640002, - 0x8f450e1c, 0x8f660004, 0x8f670014, 0xaf4f0178, 0x3063ffff, 0xa7430144, - 0x97420e16, 0x308400ff, 0xa7420146, 0xaf450148, 0xa3480152, 0x8f83000c, - 0x25420007, 0x00591024, 0xa744015a, 0xaf460160, 0xa7490158, 0xaf470154, - 0xaf4e0178, 0x00621821, 0x30631fff, 0xaf83000c, 0x8d820000, 0x14400005, - 0x00000000, 0x8f620014, 0x2403ffbf, 0x00431024, 0xaf620014, 0x8f62000c, - 0x004d1021, 0xaf62000c, 0x93630008, 0x14600008, 0x00000000, 0x11600006, - 0x00000000, 0x8f630014, 0x3c02efff, 0x3442fffe, 0x00621824, 0xaf630014, - 0xa36b0008, 0x01205021, 0x15400016, 0x8fa60008, 0x97420e14, 0x97430e16, - 0x8f850014, 0x00021400, 0x00621825, 0xaca300a8, 0x8f840014, 0x8f420e1c, - 0x0a0009f3, 0xac8200ac, 0x97420e14, 0x97430e16, 0x8f840014, 0x00021400, - 0x00621825, 0xac8300a8, 0x8f850014, 0x8f420e1c, 0x00005021, 0x0a0009f3, - 0xaca200ac, 0x14c0fe64, 0x00000000, 0x55400018, 0x8fb00010, 0x3c038000, - 0x8f420178, 0x00431024, 0x1440fffd, 0x00000000, 0x97430e14, 0x8f440e1c, - 0x24020800, 0xaf420178, 0x3063ffff, 0xa7430144, 0x97420e16, 0x3c031000, - 0xa7420146, 0x24020240, 0xaf440148, 0xa3400152, 0xa740015a, 0xaf400160, - 0xa7400158, 0xaf420154, 0xaf430178, 0x8fb00010, 0x03e00008, 0x27bd0018, - 0x27bdffd8, 0x3c1a8000, 0x3c0420ff, 0x3484fffd, 0x3c020008, 0x03421821, - 0xafbf0020, 0xafb3001c, 0xafb20018, 0xafb10014, 0xafb00010, 0xaf830014, - 0xaf440e00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x3c0200ff, 0x3442fffd, 0x3c046004, 0xaf420e00, 0x8c835000, 0x24130d00, - 0x3c120800, 0x3c114000, 0x2402ff7f, 0x00621824, 0x3463380c, 0x24020009, - 0xac835000, 0xaf420008, 0xaf800018, 0xaf80000c, 0x0e000fa1, 0x00000000, - 0x0e000a96, 0x00000000, 0x3c020800, 0x24504080, 0x8f420000, 0x30420001, - 0x1040fffd, 0x00000000, 0x8f440100, 0xaf840008, 0xaf440020, 0x93430108, - 0xa3830012, 0x93820012, 0x30420001, 0x10400008, 0x00000000, 0x93820012, - 0x30420006, 0x00021100, 0x0e00083b, 0x0050d821, 0x0a000a52, 0x00000000, - 0x14930005, 0x00000000, 0x0e00083b, 0x265b4100, 0x0a000a52, 0x00000000, - 0x0e000ba3, 0x00000000, 0xaf510138, 0x0a000a36, 0x00000000, 0x27bdfff8, - 0x3084ffff, 0x24820007, 0x3044fff8, 0x8f85000c, 0x9743008a, 0x3063ffff, - 0xafa30000, 0x8fa20000, 0x00451023, 0x2442ffff, 0x30421fff, 0x0044102b, - 0x1440fff7, 0x00000000, 0x8f82000c, 0x00021082, 0x00021080, 0x24424000, - 0x03421021, 0x03e00008, 0x27bd0008, 0x3084ffff, 0x8f82000c, 0x24840007, - 0x3084fff8, 0x00441021, 0x30421fff, 0xaf82000c, 0x03e00008, 0x00000000, - 0x27bdffe8, 0x3c1a8000, 0x3c0420ff, 0x3484fffd, 0x3c020008, 0x03421821, - 0xafbf0010, 0xaf830014, 0xaf440e00, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x3c0200ff, 0x3442fffd, 0x3c046004, 0xaf420e00, - 0x8c825000, 0x2403ff7f, 0x00431024, 0x3442380c, 0x24030009, 0xac825000, - 0xaf430008, 0xaf800018, 0xaf80000c, 0x0e000fa1, 0x00000000, 0x0e000a96, - 0x00000000, 0x8fbf0010, 0x03e00008, 0x27bd0018, 0x27bdffe8, 0x3c02000a, - 0x03421821, 0x3c040800, 0x24844120, 0x24050018, 0xafbf0010, 0xaf830024, - 0x0e000fad, 0x00003021, 0x3c050800, 0x3c020800, 0x24423d60, 0xaca24180, - 0x24a54180, 0x3c020800, 0x24423e18, 0x3c030800, 0x24633e2c, 0x3c040800, - 0xaca20004, 0x3c020800, 0x24423d68, 0xaca30008, 0xac824190, 0x24844190, - 0x3c020800, 0x24423da4, 0x3c070800, 0x24e73de4, 0x3c060800, 0x24c63e40, - 0x3c050800, 0x24a52b28, 0x3c030800, 0xac820004, 0x3c020800, 0x24423e48, - 0xac870008, 0xac86000c, 0xac850010, 0xac6241b0, 0x246341b0, 0x8fbf0010, - 0x3c020800, 0x24423e60, 0xac620004, 0xac670008, 0xac66000c, 0xac650010, - 0x03e00008, 0x27bd0018, 0x27bdffc8, 0x3c020800, 0x24424120, 0xafbf0030, - 0xafb3002c, 0xafb20028, 0xafb10024, 0xafb00020, 0x90470021, 0x8c510008, - 0x8c45001c, 0x8f900020, 0x3c060800, 0x3c038000, 0x8f420178, 0x00431024, - 0x1440fffd, 0x8cc2414c, 0x24c3414c, 0x2473ffd4, 0xaf420144, 0x8e620030, - 0x30b22000, 0xaf420148, 0x3c021000, 0xaf50014c, 0xa3470152, 0xa7510158, - 0xaf450154, 0xaf420178, 0x12400004, 0x3c030800, 0x8c620030, 0x24420001, - 0xac620030, 0x93420109, 0x9344010a, 0x00111c00, 0xafa30018, 0x00071a00, - 0xafa50014, 0x8cc5414c, 0x00021600, 0x00042400, 0x00441025, 0x00431025, - 0xafa20010, 0x8f440100, 0x8e660030, 0x0e000fe1, 0x02003821, 0x1640000e, - 0x8fbf0030, 0x8f820000, 0x8e630030, 0x8c44017c, 0x02031823, 0x00711823, - 0x00641823, 0x2c630002, 0x14600006, 0x8fb3002c, 0x0000000d, 0x00000000, - 0x240000ca, 0x8fbf0030, 0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020, - 0x03e00008, 0x27bd0038, 0x974309da, 0x00804021, 0xad030000, 0x8f4209dc, - 0xad020004, 0x8f4309e0, 0xad030008, 0x934409d9, 0x24020001, 0x30840003, - 0x1082001f, 0x30a900ff, 0x28820002, 0x10400005, 0x24020002, 0x10800009, - 0x3c0a0800, 0x0a000b64, 0x93420934, 0x1082000b, 0x24020003, 0x10820026, - 0x3c0a0800, 0x0a000b64, 0x93420934, 0x974209e4, 0x00021400, 0x34420800, - 0xad02000c, 0x0a000b63, 0x25080010, 0x974209e4, 0x00021400, 0x34428100, - 0xad02000c, 0x974309e8, 0x3c0a0800, 0x00031c00, 0x34630800, 0xad030010, - 0x0a000b63, 0x25080014, 0x974409e4, 0x3c050800, 0x24a24120, 0x94430018, - 0x94460010, 0x9447000c, 0x00a05021, 0x24020800, 0xad000010, 0xad020014, - 0x00042400, 0x00661821, 0x00671823, 0x2463fff2, 0x00832025, 0xad04000c, - 0x0a000b63, 0x25080018, 0x974209e4, 0x3c050800, 0x00021400, 0x34428100, - 0xad02000c, 0x974409e8, 0x24a24120, 0x94430018, 0x94460010, 0x9447000c, - 0x00a05021, 0x24020800, 0xad000014, 0xad020018, 0x00042400, 0x00661821, - 0x00671823, 0x2463ffee, 0x00832025, 0xad040010, 0x2508001c, 0x93420934, - 0x93450921, 0x3c074000, 0x25444120, 0x94830014, 0x94860010, 0x00021082, - 0x00021600, 0x00052c00, 0x00a72825, 0x00451025, 0x00661821, 0x00431025, - 0xad020000, 0x97830028, 0x974209ea, 0x00621821, 0x00031c00, 0xad030004, - 0x97820028, 0x24420001, 0x30427fff, 0xa7820028, 0x93430920, 0x3c020006, - 0x00031e00, 0x00621825, 0xad030008, 0x8f42092c, 0xad02000c, 0x8f430930, - 0xad030010, 0x8f440938, 0x25080014, 0xad040000, 0x8f820020, 0x11200004, - 0xad020004, 0x8f420940, 0x0a000b8d, 0x2442ffff, 0x8f420940, 0xad020008, - 0x8f440948, 0x8f420940, 0x93430936, 0x00822823, 0x00652806, 0x3402ffff, - 0x0045102b, 0x54400001, 0x3405ffff, 0x93420937, 0x25444120, 0x90830020, - 0xad000010, 0x00021700, 0x34630010, 0x00031c00, 0x00431025, 0x00451025, - 0xad02000c, 0x03e00008, 0x25020014, 0x27bdffb0, 0x3c020008, 0x03421821, - 0xafbf004c, 0xafbe0048, 0xafb70044, 0xafb60040, 0xafb5003c, 0xafb40038, - 0xafb30034, 0xafb20030, 0xafb1002c, 0xafb00028, 0xaf830000, 0x24020040, - 0xaf420814, 0xaf400810, 0x8f420944, 0x8f430950, 0x8f440954, 0x8f45095c, - 0xaf820030, 0xaf830020, 0xaf84001c, 0xaf85002c, 0x93430900, 0x24020020, - 0x10620005, 0x24020030, 0x10620022, 0x3c030800, 0x0a000bf1, 0x8c62002c, - 0x24020088, 0xaf420818, 0x3c020800, 0x24424180, 0xafa20020, 0x93430109, - 0x3c020800, 0x10600009, 0x24574190, 0x3c026000, 0x24030100, 0xac43081c, - 0x3c030001, 0xac43081c, 0x0000000d, 0x00000000, 0x2400031d, 0x9342010a, - 0x30420080, 0x1440001c, 0x00000000, 0x3c026000, 0x24030100, 0xac43081c, - 0x3c030001, 0xac43081c, 0x0000000d, 0x00000000, 0x24000324, 0x0a000bf4, - 0x00000000, 0x93430109, 0x3063007f, 0x00031140, 0x000318c0, 0x00431021, - 0x24430088, 0xaf430818, 0x0000000d, 0x3c020800, 0x244241d0, 0x3c030800, - 0x247741e0, 0x0a000bf4, 0xafa20020, 0x24420001, 0x0a000f4c, 0xac62002c, - 0x8f840000, 0x8f850020, 0x24020800, 0xaf420178, 0x8f4209a4, 0x8c83017c, - 0x00a21023, 0x00431023, 0x2c420002, 0x14400004, 0x00000000, 0x0000000d, - 0x00000000, 0x24000349, 0x8f420104, 0x8f430988, 0x00431023, 0x58400005, - 0x8f4209a0, 0x0000000d, 0x00000000, 0x2400034d, 0x8f4209a0, 0x3c100800, - 0xae02414c, 0x8f4309a4, 0x2604414c, 0x2491ffd4, 0xae230030, 0x8f420104, - 0xae250024, 0x00431023, 0xac82ffd4, 0x8fa30020, 0x8c620000, 0x0040f809, + 0x8f660004, 0x8f670014, 0x3063ffff, 0xa7430144, 0x97420e16, 0xa7420146, + 0xaf450148, 0xa34a0152, 0x8f82000c, 0x308400ff, 0xa744015a, 0xaf460160, + 0xa7480158, 0xaf470154, 0xaf4e0178, 0x00511021, 0x30421fff, 0xaf82000c, + 0x0a000ed9, 0x8d820000, 0x93620009, 0x9363000b, 0x8f85000c, 0x2463000a, + 0x00435021, 0x25440007, 0x00992024, 0x9743008a, 0x3063ffff, 0xafa30000, + 0x8fa20000, 0x00451023, 0x2442ffff, 0x30421fff, 0x0044102b, 0x1440fff7, + 0x00000000, 0x8f82000c, 0x8f840018, 0x00021082, 0x00021080, 0x24424000, + 0x03422821, 0x00804021, 0x24840001, 0xaf840018, 0x93630009, 0x310200ff, + 0x00022400, 0x3c024100, 0x24630002, 0x00621825, 0x00832025, 0xaca40000, + 0x8f62000c, 0x00461025, 0xaca20004, 0x97430e14, 0x93640002, 0x8f450e1c, + 0x8f660004, 0x8f670014, 0x3063ffff, 0xa7430144, 0x97420e16, 0x308400ff, + 0xa7420146, 0xaf450148, 0xa3480152, 0x8f83000c, 0x25420007, 0x00591024, + 0xa744015a, 0xaf460160, 0xa7490158, 0xaf470154, 0xaf4e0178, 0x00621821, + 0x30631fff, 0xaf83000c, 0x8d820000, 0x14400005, 0x00000000, 0x8f620014, + 0x2403ffbf, 0x00431024, 0xaf620014, 0x8f62000c, 0x004d1021, 0xaf62000c, + 0x93630008, 0x14600008, 0x00000000, 0x11600006, 0x00000000, 0x8f630014, + 0x3c02efff, 0x3442fffe, 0x00621824, 0xaf630014, 0xa36b0008, 0x01206021, + 0x1580000c, 0x8fa60008, 0x97420e14, 0x97430e16, 0x8f850014, 0x00021400, + 0x00621825, 0xaca300a8, 0x8f840014, 0x8f420e1c, 0xac8200ac, 0x0a000efd, + 0x2d820001, 0x14c0fe65, 0x2d820001, 0x00501025, 0x10400058, 0x24020f00, + 0x8f830008, 0x14620023, 0x3c048000, 0x11800009, 0x3c038000, 0x97420e08, + 0x30420040, 0x14400005, 0x00000000, 0x0000000d, 0x00000000, 0x2400032c, + 0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd, 0x00000000, 0x97420e10, + 0x3c030500, 0x00431025, 0xaf42014c, 0x97430e14, 0xa7430144, 0x97420e16, + 0xa7420146, 0x8f430e1c, 0x24022000, 0xaf430148, 0x3c031000, 0xa3400152, + 0xa740015a, 0xaf400160, 0xa7400158, 0xaf420154, 0xaf430178, 0x8f830008, + 0x3c048000, 0x8f420178, 0x00441024, 0x1440fffd, 0x24020f00, 0x10620016, + 0x00000000, 0x97420e14, 0xa7420144, 0x97430e16, 0xa7430146, 0x8f420e1c, + 0x3c031000, 0xaf420148, 0x0a000f51, 0x24020240, 0x97420e14, 0x97430e16, + 0x8f840014, 0x00021400, 0x00621825, 0xac8300a8, 0x8f850014, 0x8f420e1c, + 0x00006021, 0xaca200ac, 0x0a000efd, 0x2d820001, 0xaf40014c, 0x11800007, + 0x00000000, 0x97420e10, 0xa7420144, 0x97430e12, 0xa7430146, 0x0a000f4e, + 0x8f420e18, 0x97420e14, 0xa7420144, 0x97430e16, 0xa7430146, 0x8f420e1c, + 0xaf420148, 0x24020040, 0x3c031000, 0xa3400152, 0xa740015a, 0xaf400160, + 0xa7400158, 0xaf420154, 0xaf430178, 0x8fb10014, 0x8fb00010, 0x03e00008, + 0x27bd0018, 0x27bdffd0, 0x3c1a8000, 0x3c0420ff, 0x3484fffd, 0x3c020008, + 0x03421821, 0xafbf002c, 0xafb60028, 0xafb50024, 0xafb40020, 0xafb3001c, + 0xafb20018, 0xafb10014, 0xafb00010, 0xaf830014, 0xaf440e00, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3c0200ff, 0x3442fffd, + 0x3c046004, 0xaf420e00, 0x8c835000, 0x24160800, 0x24150d00, 0x3c140800, + 0x24130f00, 0x3c120800, 0x3c114000, 0x2402ff7f, 0x00621824, 0x3463380c, + 0x24020009, 0xac835000, 0xaf420008, 0xaf800018, 0xaf80000c, 0x0e001559, + 0x00000000, 0x0e000ff0, 0x00000000, 0x3c020800, 0x245057c0, 0x8f420000, + 0x30420001, 0x1040fffd, 0x00000000, 0x8f440100, 0xaf840008, 0xaf440020, + 0xaf560178, 0x93430108, 0xa3830012, 0x93820012, 0x30420001, 0x10400008, + 0x00000000, 0x93820012, 0x30420006, 0x00021100, 0x0e000d43, 0x0050d821, + 0x0a000fac, 0x00000000, 0x14950005, 0x00000000, 0x0e000d43, 0x269b5840, + 0x0a000fac, 0x00000000, 0x14930005, 0x00000000, 0x0e000d43, 0x265b5860, + 0x0a000fac, 0x00000000, 0x0e0010ea, 0x00000000, 0xaf510138, 0x0a000f89, + 0x00000000, 0x27bdfff8, 0x3084ffff, 0x24820007, 0x3044fff8, 0x8f85000c, + 0x9743008a, 0x3063ffff, 0xafa30000, 0x8fa20000, 0x00451023, 0x2442ffff, + 0x30421fff, 0x0044102b, 0x1440fff7, 0x00000000, 0x8f82000c, 0x00021082, + 0x00021080, 0x24424000, 0x03421021, 0x03e00008, 0x27bd0008, 0x3084ffff, + 0x8f82000c, 0x24840007, 0x3084fff8, 0x00441021, 0x30421fff, 0xaf82000c, + 0x03e00008, 0x00000000, 0x27bdffe8, 0x3c1a8000, 0x3c0420ff, 0x3484fffd, + 0x3c020008, 0x03421821, 0xafbf0010, 0xaf830014, 0xaf440e00, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3c0200ff, 0x3442fffd, + 0x3c046004, 0xaf420e00, 0x8c825000, 0x2403ff7f, 0x00431024, 0x3442380c, + 0x24030009, 0xac825000, 0xaf430008, 0xaf800018, 0xaf80000c, 0x0e001559, + 0x00000000, 0x0e000ff0, 0x00000000, 0x8fbf0010, 0x03e00008, 0x27bd0018, + 0x27bdffe8, 0x3c02000a, 0x03421821, 0x3c040800, 0x24845880, 0x24050019, + 0xafbf0010, 0xaf830024, 0x0e001565, 0x00003021, 0x3c050800, 0x3c020800, + 0x24425330, 0xaca258e8, 0x24a558e8, 0x3c020800, 0x244254f8, 0x3c030800, + 0x2463550c, 0x3c040800, 0xaca20004, 0x3c020800, 0x24425338, 0xaca30008, + 0xac825900, 0x24845900, 0x3c020800, 0x244253c4, 0x3c070800, 0x24e75404, + 0x3c060800, 0x24c65520, 0x3c050800, 0x24a55438, 0x3c030800, 0xac820004, + 0x3c020800, 0x24425528, 0xac870008, 0xac86000c, 0xac850010, 0xac625920, + 0x24635920, 0x8fbf0010, 0x3c020800, 0x24425540, 0xac620004, 0x3c020800, + 0xac670008, 0xac66000c, 0xac650010, 0xac400048, 0x03e00008, 0x27bd0018, + 0x974309da, 0x00804021, 0xad030000, 0x8f4209dc, 0xad020004, 0x8f4309e0, + 0xad030008, 0x934409d9, 0x24020001, 0x30840003, 0x1082001f, 0x30a900ff, + 0x28820002, 0x10400005, 0x24020002, 0x10800009, 0x3c0a0800, 0x0a001078, + 0x93420934, 0x1082000b, 0x24020003, 0x10820026, 0x3c0a0800, 0x0a001078, + 0x93420934, 0x974209e4, 0x00021400, 0x34420800, 0xad02000c, 0x0a001077, + 0x25080010, 0x974209e4, 0x00021400, 0x34428100, 0xad02000c, 0x974309e8, + 0x3c0a0800, 0x00031c00, 0x34630800, 0xad030010, 0x0a001077, 0x25080014, + 0x974409e4, 0x3c050800, 0x24a25880, 0x9443001c, 0x94460014, 0x94470010, + 0x00a05021, 0x24020800, 0xad000010, 0xad020014, 0x00042400, 0x00661821, + 0x00671823, 0x2463fff2, 0x00832025, 0xad04000c, 0x0a001077, 0x25080018, + 0x974209e4, 0x3c050800, 0x00021400, 0x34428100, 0xad02000c, 0x974409e8, + 0x24a25880, 0x9443001c, 0x94460014, 0x94470010, 0x00a05021, 0x24020800, + 0xad000014, 0xad020018, 0x00042400, 0x00661821, 0x00671823, 0x2463ffee, + 0x00832025, 0xad040010, 0x2508001c, 0x93420934, 0x93450921, 0x3c074000, + 0x25445880, 0x94830018, 0x94860014, 0x00021082, 0x00021600, 0x00052c00, + 0x00a72825, 0x00451025, 0x00661821, 0x00431025, 0xad020000, 0x9783002c, + 0x974209ea, 0x00621821, 0x00031c00, 0xad030004, 0x9782002c, 0x24420001, + 0x30427fff, 0xa782002c, 0x93430920, 0x3c020006, 0x00031e00, 0x00621825, + 0xad030008, 0x8f42092c, 0xad02000c, 0x8f430930, 0xad030010, 0x8f440938, + 0x25080014, 0xad040000, 0x8f820020, 0x11200004, 0xad020004, 0x8f420940, + 0x0a0010a1, 0x2442ffff, 0x8f420940, 0xad020008, 0x8f440948, 0x8f420940, + 0x93430936, 0x00823023, 0x00663006, 0x3402ffff, 0x0046102b, 0x54400001, + 0x3406ffff, 0x93420937, 0x25445880, 0x90830024, 0xad000010, 0x00021700, + 0x34630010, 0x00031c00, 0x00431025, 0x00461025, 0xad02000c, 0x8c830008, + 0x14600031, 0x25080014, 0x3c020800, 0x8c430048, 0x1060002d, 0x00000000, + 0x9342010b, 0xad020000, 0x8f830000, 0x8c6200b0, 0xad020004, 0x8f830000, + 0x8c6200b4, 0xad020008, 0x8f830000, 0x8c6200c0, 0xad02000c, 0x8f830000, + 0x8c6200c4, 0xad020010, 0x8f830000, 0x8c6200c8, 0xad020014, 0x8f830000, + 0x8c6200cc, 0xad020018, 0x8f830000, 0x8c6200e0, 0xad02001c, 0x8f830000, + 0x8c6200e8, 0xad020020, 0x8f830000, 0x8c6200f0, 0x3c04600e, 0xad020024, + 0x8c8200d0, 0xad020028, 0x8c8300d4, 0xad03002c, 0x8f820028, 0x3c046012, + 0xad020030, 0x8c8200a8, 0xad020034, 0x8c8300ac, 0x3c026000, 0xad030038, + 0x8c434448, 0xad03003c, 0x03e00008, 0x01001021, 0x27bdffa8, 0x3c020008, + 0x03423021, 0xafbf0054, 0xafbe0050, 0xafb7004c, 0xafb60048, 0xafb50044, + 0xafb40040, 0xafb3003c, 0xafb20038, 0xafb10034, 0xafb00030, 0xaf860000, + 0x24020040, 0xaf420814, 0xaf400810, 0x8f420944, 0x8f430950, 0x8f440954, + 0x8f45095c, 0xaf820034, 0xaf830020, 0xaf84001c, 0xaf850030, 0x90c20000, + 0x24030020, 0x304400ff, 0x10830005, 0x24020030, 0x10820022, 0x3c030800, + 0x0a001139, 0x8c62002c, 0x24020088, 0xaf420818, 0x3c020800, 0x244258e8, + 0xafa20020, 0x93430109, 0x3c020800, 0x10600009, 0x24575900, 0x3c026000, + 0x24030100, 0xac43081c, 0x3c030001, 0xac43081c, 0x0000000d, 0x00000000, + 0x24000376, 0x9342010a, 0x30420080, 0x14400021, 0x24020800, 0x3c026000, + 0x24030100, 0xac43081c, 0x3c030001, 0xac43081c, 0x0000000d, 0x00000000, + 0x2400037d, 0x0a001141, 0x24020800, 0x93430109, 0x3063007f, 0x00031140, + 0x000318c0, 0x00431021, 0x24430088, 0xaf430818, 0x0000000d, 0x3c020800, + 0x24425940, 0x3c030800, 0x24775950, 0x0a001140, 0xafa20020, 0x24420001, + 0xac62002c, 0x0000000d, 0x00000000, 0x24000395, 0x0a0014c1, 0x8fbf0054, + 0x24020800, 0xaf420178, 0x8f450104, 0x8f420988, 0x00a21023, 0x58400005, + 0x8f4309a0, 0x0000000d, 0x00000000, 0x240003b1, 0x8f4309a0, 0x3c100800, + 0xae0358b0, 0x8f4209a4, 0x8f830020, 0x260458b0, 0x2491ffd0, 0xae220034, + 0x00a21023, 0xae230028, 0xac82ffd0, 0x8fa30020, 0x8c620000, 0x0040f809, 0x0200b021, 0x00409021, 0x32440010, 0x32420002, 0x10400007, 0xafa40024, - 0x8e22001c, 0x32500040, 0x2403ffbf, 0x00431024, 0x0a000f13, 0xae22001c, - 0x32420020, 0x10400002, 0x3c020800, 0x245741b0, 0x32420001, 0x14400007, - 0x00000000, 0x8f820008, 0xaf420080, 0x8ec3414c, 0xaf430e10, 0x8e220030, + 0x8e220020, 0x32530040, 0x2403ffbf, 0x00431024, 0x0a001493, 0xae220020, + 0x32420020, 0x10400002, 0x3c020800, 0x24575920, 0x32420001, 0x14400007, + 0x00000000, 0x8f820008, 0xaf420080, 0x8ec358b0, 0xaf430e10, 0x8e220034, 0xaf420e18, 0x9343010b, 0x93420905, 0x30420008, 0x1040003c, 0x307400ff, 0x8f820000, 0x8c430074, 0x0460000a, 0x00000000, 0x3c026000, 0x24030100, - 0xac43081c, 0x3c030001, 0xac43081c, 0x0000000d, 0x00000000, 0x24000384, - 0x8f820000, 0x9044007b, 0x9343010a, 0x14830027, 0x32500040, 0x24072000, - 0x3c090800, 0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd, 0x8ec2414c, - 0x26c4414c, 0x2484ffd4, 0xaf420144, 0x8c820030, 0x3c030100, 0xaf420148, - 0x24020047, 0xaf43014c, 0x00001821, 0xa3420152, 0x3c021000, 0xa7430158, - 0xaf470154, 0xaf420178, 0x8ec5414c, 0x8d230030, 0x8c860030, 0x24630001, - 0xad230030, 0x93420109, 0x9343010a, 0xafa70014, 0xafa00018, 0x00021600, - 0x00031c00, 0x00431025, 0x34424700, 0xafa20010, 0x8f440100, 0x0e000fe1, - 0x3c070100, 0x3c030800, 0x24624120, 0x0a000d01, 0x8c43001c, 0x32820002, - 0x10400047, 0x3c039000, 0x34630001, 0x8f820008, 0x32500040, 0x3c048000, - 0x00431025, 0xaf420020, 0x8f420020, 0x00441024, 0x1440fffd, 0x00000000, - 0x8f830000, 0x90620005, 0x3c058000, 0x34420008, 0xa0620005, 0x8f860000, - 0x34a50001, 0x8f840008, 0x8cc20074, 0x3c038000, 0x00852025, 0x00431025, - 0xacc20074, 0xaf440020, 0x90c3007b, 0x9342010a, 0x14620028, 0x3c040800, - 0x24072000, 0x3c090800, 0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd, - 0x8ec2414c, 0x26c4414c, 0x2484ffd4, 0xaf420144, 0x8c820030, 0x3c030100, - 0xaf420148, 0x24020046, 0xaf43014c, 0x00001821, 0xa3420152, 0x3c021000, - 0xa7430158, 0xaf470154, 0xaf420178, 0x8ec5414c, 0x8d230030, 0x8c860030, - 0x24630001, 0xad230030, 0x93420109, 0x9343010a, 0xafa70014, 0xafa00018, - 0x00021600, 0x00031c00, 0x00431025, 0x34424600, 0xafa20010, 0x8f440100, - 0x0e000fe1, 0x3c070100, 0x3c040800, 0x24824120, 0x0a000d01, 0x8c43001c, - 0x93420108, 0x30420010, 0x50400050, 0x9343093f, 0x8f860000, 0x90c3007f, - 0x90c2007e, 0x90c40080, 0x306800ff, 0x00021600, 0x00081c00, 0x00431025, - 0x00042200, 0x90c3007a, 0x90c5000a, 0x00441025, 0x11050028, 0x00623825, - 0xa0c8000a, 0x24086000, 0x3c090800, 0x3c038000, 0x8f420178, 0x00431024, - 0x1440fffd, 0x8ec2414c, 0x26c4414c, 0x2484ffd4, 0xaf420144, 0x8c820030, - 0x00001821, 0xaf420148, 0x24020052, 0xaf47014c, 0xa3420152, 0x3c021000, - 0xa7430158, 0xaf480154, 0xaf420178, 0x8ec5414c, 0x8d230030, 0x8c860030, - 0x24630001, 0xad230030, 0x93420109, 0x9343010a, 0xafa80014, 0xafa00018, - 0x00021600, 0x00031c00, 0x00431025, 0x34425200, 0xafa20010, 0x0e000fe1, - 0x8f440100, 0x0a000cfb, 0x00000000, 0x3c026000, 0x24030100, 0xac43081c, - 0x3c030001, 0xac43081c, 0x0000000d, 0x00000000, 0x240003cd, 0x16800009, - 0x3c040800, 0x3c030800, 0x24624120, 0x8c43001c, 0x32500040, 0x2404ffbf, - 0x00641824, 0x0a000f13, 0xac43001c, 0x8c824120, 0x10400005, 0x3c030800, - 0x8c620034, 0xac804120, 0x24420001, 0xac620034, 0x9343093f, 0x24020012, - 0x1462000f, 0x329e0038, 0x17c0000c, 0x3c030800, 0x8f830000, 0x8c62004c, - 0xac62005c, 0x3c020800, 0x24444120, 0x8c82001c, 0x32500040, 0x2403ffbf, - 0x00431024, 0x0a000f13, 0xac82001c, 0xac604120, 0x97420908, 0x000211c0, + 0xac43081c, 0x3c030001, 0xac43081c, 0x0000000d, 0x00000000, 0x240003ed, + 0x8f820000, 0x9044007b, 0x9343010a, 0x14830027, 0x32530040, 0x00003821, + 0x24052000, 0x3c090800, 0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd, + 0x8ec258b0, 0x26c458b0, 0x2484ffd0, 0xaf420144, 0x8c820034, 0x3c030100, + 0xaf420148, 0x24020047, 0xaf43014c, 0xa3420152, 0x8d230030, 0x3c021000, + 0xa7470158, 0xaf450154, 0xaf420178, 0x8c860034, 0x24630001, 0xad230030, + 0x9342010a, 0x3c030047, 0xafa50014, 0x00021600, 0x00431025, 0x00471025, + 0xafa20010, 0x9343010b, 0xafa30018, 0x8f440100, 0x8f450104, 0x0e00159b, + 0x3c070100, 0x3c050800, 0x24a25880, 0x0a001250, 0x8c430020, 0x32820002, + 0x10400050, 0x00000000, 0x0e0015b9, 0x32530040, 0x3c039000, 0x34630001, + 0x8f820008, 0x3c048000, 0x00431025, 0xaf420020, 0x8f420020, 0x00441024, + 0x1440fffd, 0x00000000, 0x8f830000, 0x90620005, 0x34420008, 0xa0620005, + 0x8f840000, 0x8c820074, 0x3c038000, 0x00431025, 0xac820074, 0x90830000, + 0x24020020, 0x10620004, 0x00000000, 0x0000000d, 0x00000000, 0x2400040b, + 0x8f830008, 0x3c028000, 0x34420001, 0x00621825, 0xaf430020, 0x9084007b, + 0x9342010a, 0x14820028, 0x3c030800, 0x00003821, 0x24052000, 0x3c090800, + 0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd, 0x8ec258b0, 0x26c458b0, + 0x2484ffd0, 0xaf420144, 0x8c820034, 0x3c030100, 0xaf420148, 0x24020046, + 0xaf43014c, 0xa3420152, 0x8d230030, 0x3c021000, 0xa7470158, 0xaf450154, + 0xaf420178, 0x8c860034, 0x24630001, 0xad230030, 0x9342010a, 0x3c030046, + 0xafa50014, 0x00021600, 0x00431025, 0x00471025, 0xafa20010, 0x9343010b, + 0xafa30018, 0x8f440100, 0x8f450104, 0x0e00159b, 0x3c070100, 0x3c030800, + 0x24625880, 0x0a001250, 0x8c430020, 0x93420108, 0x30420010, 0x50400056, + 0x9343093f, 0x8f860000, 0x90c2007f, 0x8cc30178, 0x304800ff, 0x15030004, + 0x00000000, 0x0000000d, 0x00000000, 0x24000425, 0x90c2007e, 0x90c40080, + 0x00081c00, 0x00021600, 0x00431025, 0x00042200, 0x90c3007a, 0x90c5000a, + 0x00441025, 0x11050028, 0x00623825, 0xa0c8000a, 0x00004021, 0x24056000, + 0x3c090800, 0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd, 0x8ec258b0, + 0x26c458b0, 0x2484ffd0, 0xaf420144, 0x8c820034, 0xaf420148, 0x24020052, + 0xaf47014c, 0xa3420152, 0x8d230030, 0x3c021000, 0xa7480158, 0xaf450154, + 0xaf420178, 0x8c860034, 0x24630001, 0xad230030, 0x9342010a, 0x3c030052, + 0xafa50014, 0x00021600, 0x00431025, 0x00481025, 0xafa20010, 0x9343010b, + 0xafa30018, 0x8f440100, 0x0e00159b, 0x8f450104, 0x0a00124a, 0x00000000, + 0x3c026000, 0x24030100, 0xac43081c, 0x3c030001, 0xac43081c, 0x0000000d, + 0x00000000, 0x2400043e, 0x16800009, 0x3c050800, 0x3c040800, 0x24825880, + 0x8c430020, 0x32530040, 0x2404ffbf, 0x00641824, 0x0a001493, 0xac430020, + 0x8ca25880, 0x10400005, 0x3c030800, 0x8c620034, 0xaca05880, 0x24420001, + 0xac620034, 0x9343093f, 0x24020012, 0x5462000e, 0x97420908, 0x32820038, + 0x14400009, 0x3c030800, 0x8f830000, 0x8c62004c, 0xac62005c, 0x3c020800, + 0x24445880, 0x8c820020, 0x0a001285, 0x32530040, 0xac605880, 0x97420908, + 0x5440001c, 0x97420908, 0x3c039000, 0x34630001, 0x8f820008, 0x32530040, + 0x3c048000, 0x00431025, 0xaf420020, 0x8f420020, 0x00441024, 0x1440fffd, + 0x3c028000, 0x8f840000, 0x8f850008, 0x8c830050, 0x34420001, 0x00a22825, + 0xaf830020, 0xac830070, 0xac83005c, 0xaf450020, 0x3c050800, 0x24a45880, + 0x8c820020, 0x2403ffbf, 0x00431024, 0x0a001493, 0xac820020, 0x000211c0, 0xaf420024, 0x97420908, 0x3c030080, 0x34630003, 0x000211c0, 0xaf42080c, - 0xaf43081c, 0x974209ec, 0x8f4309a4, 0xa7820028, 0x3c020800, 0x24444120, - 0xac830028, 0x93420937, 0x93430934, 0x00021080, 0x00621821, 0xa4830014, - 0x934209d8, 0x00621821, 0xa4830016, 0x934209d8, 0x93430934, 0x00809821, - 0x00431021, 0x24420010, 0xa4820012, 0x0000a821, 0x24020006, 0x13c00003, - 0xae62001c, 0x0a000d82, 0x24120008, 0x8f420958, 0x8f830020, 0x8f84002c, - 0x00431023, 0x00832023, 0x04800003, 0xae620004, 0x04410003, 0x0082102b, - 0x0a000d4e, 0xae600004, 0x54400001, 0xae640004, 0x8ee20000, 0x0040f809, - 0x00000000, 0x00409021, 0x32420001, 0x5440001e, 0x8ee20004, 0x8e630008, - 0x1060002b, 0x3c02c000, 0x00621025, 0xaf420e00, 0x8f420000, 0x30420008, - 0x1040fffd, 0x00000000, 0x97420e08, 0xa7820010, 0x8f430e04, 0x8e620008, - 0xaf830004, 0x8f840004, 0x0044102b, 0x1040000b, 0x24150001, 0x24020100, - 0x3c016000, 0xac22081c, 0x3c020001, 0x3c016000, 0xac22081c, 0x0000000d, - 0x00000000, 0x24000449, 0x24150001, 0x8ee20004, 0x0040f809, 0x00000000, - 0x02429025, 0x32420002, 0x5040001d, 0x8f470940, 0x12a00006, 0x8ec2414c, - 0x8f830000, 0xac6200a8, 0x8f840000, 0x8e620030, 0xac8200ac, 0x32420004, - 0x50400013, 0x8f470940, 0x3c020800, 0x3283007d, 0x106000fe, 0x245741b0, - 0x32820001, 0x50400006, 0x36520002, 0x8f830030, 0x8f420940, 0x106200f7, - 0x00000000, 0x36520002, 0x24020008, 0xa660000c, 0xa662000e, 0xae600008, - 0xa2600020, 0x8f470940, 0x3c030800, 0x24684120, 0x8d020028, 0x8d050008, - 0x9504000c, 0x9506000a, 0x95030022, 0x00451021, 0x00862021, 0x00641821, - 0xaf870030, 0xad020028, 0x32820030, 0x10400006, 0xa5030010, 0x91020020, - 0x32910040, 0x34420004, 0x0a000dd4, 0xa1020020, 0x93420923, 0x30420040, + 0xaf43081c, 0x974209ec, 0x8f4309a4, 0xa782002c, 0x3c020800, 0x24445880, + 0xac83002c, 0x93420937, 0x93430934, 0x00021080, 0x00621821, 0xa4830018, + 0x934209d8, 0x32850038, 0xafa50028, 0x00621821, 0xa483001a, 0x934209d8, + 0x93430934, 0x3c1e0800, 0x00809821, 0x00431021, 0x24420010, 0xa4820016, + 0x24020006, 0xae620020, 0x8fa20028, 0x10400003, 0x0000a821, 0x0a0012f0, + 0x24120008, 0x8f420958, 0x8f830020, 0x8f840030, 0x00431023, 0x00832023, + 0x04800003, 0xae620004, 0x04410003, 0x0082102b, 0x0a0012bc, 0xae600004, + 0x54400001, 0xae640004, 0x8ee20000, 0x0040f809, 0x00000000, 0x00409021, + 0x32420001, 0x5440001e, 0x8ee20004, 0x8e630008, 0x1060002b, 0x3c02c000, + 0x00621025, 0xaf420e00, 0x8f420000, 0x30420008, 0x1040fffd, 0x00000000, + 0x97420e08, 0xa7820010, 0x8f430e04, 0x8e620008, 0xaf830004, 0x8f840004, + 0x0044102b, 0x1040000b, 0x24150001, 0x24020100, 0x3c016000, 0xac22081c, + 0x3c020001, 0x3c016000, 0xac22081c, 0x0000000d, 0x00000000, 0x240004cd, + 0x24150001, 0x8ee20004, 0x0040f809, 0x00000000, 0x02429025, 0x32420002, + 0x5040001d, 0x8f470940, 0x12a00006, 0x8ec258b0, 0x8f830000, 0xac6200a8, + 0x8f840000, 0x8e620034, 0xac8200ac, 0x32420004, 0x50400013, 0x8f470940, + 0x3c020800, 0x3283007d, 0x10600110, 0x24575920, 0x32820001, 0x50400006, + 0x36520002, 0x8f830034, 0x8f420940, 0x10620109, 0x00000000, 0x36520002, + 0x24020008, 0xa6600010, 0xa6620012, 0xae600008, 0xa2600024, 0x8f470940, + 0x3c030800, 0x24685880, 0x8d02002c, 0x8d050008, 0x95040010, 0x9506000a, + 0x95030026, 0x00451021, 0x00862021, 0x00641821, 0xaf870034, 0xad02002c, + 0x32820030, 0x10400008, 0xa5030014, 0x91020024, 0x32910040, 0x34420004, + 0xa1020024, 0xaf400048, 0x0a001345, 0x3c040800, 0x93420923, 0x30420002, 0x10400029, 0x32910040, 0x8f830000, 0x8f840020, 0x8c620084, 0x00441023, - 0x0442000a, 0x3c039000, 0x95020010, 0x8c630084, 0x00821021, 0x00621823, - 0x1c600004, 0x3c039000, 0x91020020, 0x34420001, 0xa1020020, 0x34630001, + 0x0442000a, 0x3c039000, 0x95020014, 0x8c630084, 0x00821021, 0x00621823, + 0x1c600004, 0x3c039000, 0x91020024, 0x34420001, 0xa1020024, 0x34630001, 0x8f820008, 0x32910040, 0x3c048000, 0x00431025, 0xaf420020, 0x8f420020, 0x00441024, 0x1440fffd, 0x00000000, 0x8f840000, 0x9083003f, 0x2402000a, 0x10620005, 0x2402000c, 0x9083003f, 0x24020008, 0x14620002, 0x24020014, 0xa082003f, 0x8f830008, 0x3c028000, 0x34420001, 0x00621825, 0xaf430020, - 0x3c040800, 0x24904120, 0x9602000c, 0x96030016, 0x9604000e, 0x00431021, - 0x00442021, 0x24840002, 0x3084ffff, 0x0e000a55, 0xa6020018, 0x8f850018, - 0x00a01821, 0xa2030021, 0x8ee60008, 0x00402021, 0x24a50001, 0xaf850018, - 0x00c0f809, 0x00000000, 0x00402021, 0x0e000b12, 0x02202821, 0x8ee3000c, - 0x0060f809, 0x00402021, 0x96040018, 0x9602000e, 0x00822021, 0x24840002, - 0x0e000a6b, 0x3084ffff, 0x3c030800, 0x8c624120, 0x8e030008, 0x3c040800, - 0x00431023, 0x14400012, 0xac824120, 0x54600006, 0x8e02001c, 0x3243004a, - 0x24020002, 0x14620005, 0x00000000, 0x8e02001c, 0x34420040, 0x0a000e0b, - 0xae02001c, 0x52a00006, 0x36520002, 0x8e02002c, 0xaf420e10, 0x8e030030, - 0xaf430e18, 0x36520002, 0x52a00008, 0x96670010, 0x8f830000, 0x8f420e10, - 0xac6200a8, 0x8f840000, 0x8f420e18, 0xac8200ac, 0x96670010, 0x92680020, - 0x24020040, 0xaf420814, 0x8f830020, 0x8f82001c, 0x00671821, 0x00621023, - 0xaf830020, 0x58400005, 0x8f42095c, 0x8f820000, 0xaf83001c, 0xac430054, - 0x8f42095c, 0x31030008, 0xaf82002c, 0x1060001a, 0x00000000, 0x8f840000, - 0x90820120, 0x90830121, 0x304600ff, 0x00c31823, 0x30630007, 0x24020007, - 0x1062000e, 0x00000000, 0x90820122, 0x304200fe, 0xa0820122, 0x8f850000, - 0x00061880, 0x8f840020, 0x24a20100, 0x00431021, 0x24c30001, 0x30630007, - 0xac440000, 0x0a000e40, 0xa0a30120, 0x90820122, 0x34420001, 0xa0820122, - 0x14e00003, 0x31020001, 0x10400031, 0x32510002, 0x8f820000, 0x8c43000c, - 0x30630001, 0x1060002c, 0x32510002, 0x3c029000, 0x8f830008, 0x34420001, - 0x3c048000, 0x00621825, 0xaf430020, 0x8f420020, 0x00441024, 0x1440fffd, - 0x00000000, 0x8f870000, 0x8ce2000c, 0x30420001, 0x10400018, 0x00000000, - 0x94e2006a, 0x00022880, 0x50a00001, 0x24050001, 0x94e30068, 0x90e40081, - 0x3c020800, 0x8c460024, 0x00652821, 0x00852804, 0x00c5102b, 0x54400001, - 0x00a03021, 0x3c020800, 0x8c440028, 0x00c4182b, 0x54600001, 0x00c02021, - 0x8f430074, 0x2402fffe, 0x00822824, 0x00a31821, 0xace3000c, 0x8f830008, - 0x3c028000, 0x34420001, 0x00621825, 0xaf430020, 0x8f830020, 0x3c020800, - 0x24504120, 0xae030024, 0x8ee20010, 0x0040f809, 0x00000000, 0x12a00005, - 0x00000000, 0x8f420e10, 0xae02002c, 0x8f430e18, 0xae030030, 0x1220feba, - 0x0000a821, 0x8f870024, 0x97860028, 0x8f830000, 0x8f820030, 0x8f840020, - 0x8f85001c, 0x32500040, 0xa4e6002c, 0xac620044, 0x32420008, 0xac640050, - 0xac650054, 0x1040007a, 0x32820020, 0x10400027, 0x32910010, 0x24072000, - 0x3c090800, 0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd, 0x8ec2414c, - 0x26c4414c, 0x2484ffd4, 0xaf420144, 0x8c820030, 0x3c030400, 0xaf420148, - 0x24020041, 0xaf43014c, 0x00001821, 0xa3420152, 0x3c021000, 0xa7430158, - 0xaf470154, 0xaf420178, 0x8ec5414c, 0x8d230030, 0x8c860030, 0x24630001, - 0xad230030, 0x93420109, 0x9343010a, 0xafa70014, 0xafa00018, 0x00021600, - 0x00031c00, 0x00431025, 0x34424100, 0xafa20010, 0x8f440100, 0x0e000fe1, - 0x3c070400, 0x12200028, 0x24072000, 0x3c090800, 0x3c038000, 0x8f420178, - 0x00431024, 0x1440fffd, 0x8ec2414c, 0x26c4414c, 0x2484ffd4, 0xaf420144, - 0x8c820030, 0x3c030300, 0xaf420148, 0x2402004e, 0xaf43014c, 0x00001821, - 0xa3420152, 0x3c021000, 0xa7430158, 0xaf470154, 0xaf420178, 0x8ec5414c, - 0x8d230030, 0x8c860030, 0x24630001, 0xad230030, 0x93420109, 0x9343010a, - 0xafa70014, 0xafa00018, 0x00021600, 0x00031c00, 0x00431025, 0x34424e00, - 0xafa20010, 0x8f440100, 0x0e000fe1, 0x3c070300, 0x0a000f0b, 0x8fa30024, - 0x32820008, 0x10400026, 0x3c090800, 0x24072000, 0x3c038000, 0x8f420178, - 0x00431024, 0x1440fffd, 0x8ec2414c, 0x26c4414c, 0x2484ffd4, 0xaf420144, - 0x8c820030, 0x3c030200, 0xaf420148, 0x2402004b, 0xaf43014c, 0x00001821, - 0xa3420152, 0x3c021000, 0xa7430158, 0xaf470154, 0xaf420178, 0x8ec5414c, - 0x8d230030, 0x8c860030, 0x24630001, 0xad230030, 0x93420109, 0x9343010a, - 0xafa70014, 0xafa00018, 0x00021600, 0x00031c00, 0x00431025, 0x34424b00, - 0xafa20010, 0x8f440100, 0x0e000fe1, 0x3c070200, 0x8fa30024, 0x14600004, - 0x8fa40020, 0x32420010, 0x10400004, 0x00000000, 0x8c820004, 0x0040f809, - 0x00000000, 0x12000006, 0x8fa30020, 0x8c620008, 0x0040f809, 0x00000000, - 0x0a000f4d, 0x8fbf004c, 0x3c030800, 0x8c62413c, 0x30420040, 0x1440002f, - 0x8fbf004c, 0x24040040, 0x8f910020, 0x3c038000, 0x8f420178, 0x00431024, - 0x1440fffd, 0x8ec2414c, 0x26d0414c, 0x2610ffd4, 0xaf420144, 0x8e020030, - 0x00001821, 0xaf420148, 0x24020049, 0xaf51014c, 0xa3420152, 0x3c021000, - 0xa7430158, 0xaf440154, 0xaf420178, 0x8ec5414c, 0x8e060030, 0x93420109, - 0x9343010a, 0xafa40014, 0xafa00018, 0x00021600, 0x00031c00, 0x00431025, - 0x34424900, 0xafa20010, 0x8f440100, 0x0e000fe1, 0x02203821, 0x8f830000, - 0x8e020030, 0x8c64017c, 0x02221023, 0x00441023, 0x2c420002, 0x14400005, - 0x8fbf004c, 0x0000000d, 0x00000000, 0x240000ca, 0x8fbf004c, 0x8fbe0048, - 0x8fb70044, 0x8fb60040, 0x8fb5003c, 0x8fb40038, 0x8fb30034, 0x8fb20030, - 0x8fb1002c, 0x8fb00028, 0x03e00008, 0x27bd0050, 0x03e00008, 0x00001021, - 0x3c030800, 0x24654120, 0x8ca40004, 0x8c634120, 0x0064102b, 0x54400001, - 0x00602021, 0x9743093c, 0x0083102b, 0x54400001, 0x00801821, 0x00001021, - 0xaca30008, 0x03e00008, 0xa4a00022, 0x8f850004, 0x97840010, 0x3c030800, - 0x24634120, 0x24020008, 0xa462000e, 0x8f820004, 0xa460000c, 0x000420c2, + 0x3c040800, 0x24865880, 0x94c20010, 0x94c3001a, 0x8cc40008, 0x00432821, + 0x14800006, 0xa4c5001c, 0x3c020800, 0x8c430048, 0x10600002, 0x24a20040, + 0xa4c2001c, 0x27d05880, 0x9604001c, 0x96020012, 0x00822021, 0x24840002, + 0x0e000faf, 0x3084ffff, 0x8f850018, 0x00a01821, 0xa2030025, 0x8ee60008, + 0x00402021, 0x24a50001, 0xaf850018, 0x00c0f809, 0x00000000, 0x00402021, + 0x0e001026, 0x02202821, 0x8ee3000c, 0x0060f809, 0x00402021, 0x9604001c, + 0x96020012, 0x00822021, 0x24840002, 0x0e000fc5, 0x3084ffff, 0x8fc25880, + 0x8e030008, 0x00431023, 0x14400012, 0xafc25880, 0x54600006, 0x8e020020, + 0x3243004a, 0x24020002, 0x14620005, 0x00000000, 0x8e020020, 0x34420040, + 0x0a001382, 0xae020020, 0x52a00006, 0x36520002, 0x8e020030, 0xaf420e10, + 0x8e030034, 0xaf430e18, 0x36520002, 0x52a00008, 0x96670014, 0x8f830000, + 0x8f420e10, 0xac6200a8, 0x8f840000, 0x8f420e18, 0xac8200ac, 0x96670014, + 0x92680024, 0x24020040, 0xaf420814, 0x8f830020, 0x8f82001c, 0x00671821, + 0x00621023, 0xaf830020, 0x18400008, 0x00000000, 0x8f820000, 0xaf83001c, + 0xac430054, 0x54e00005, 0xaf400040, 0x0a0013a0, 0x8f42095c, 0x54e00001, + 0xaf400044, 0x8f42095c, 0x31030008, 0xaf820030, 0x1060001a, 0x00000000, + 0x8f840000, 0x90820120, 0x90830121, 0x304600ff, 0x00c31823, 0x30630007, + 0x24020007, 0x1062000e, 0x00000000, 0x90820122, 0x304200fe, 0xa0820122, + 0x8f850000, 0x00061880, 0x8f840020, 0x24a20100, 0x00431021, 0x24c30001, + 0x30630007, 0xac440000, 0x0a0013bd, 0xa0a30120, 0x90820122, 0x34420001, + 0xa0820122, 0x14e00003, 0x31020001, 0x10400031, 0x32510002, 0x8f820000, + 0x8c43000c, 0x30630001, 0x1060002c, 0x32510002, 0x3c029000, 0x8f830008, + 0x34420001, 0x3c048000, 0x00621825, 0xaf430020, 0x8f420020, 0x00441024, + 0x1440fffd, 0x00000000, 0x8f870000, 0x8ce2000c, 0x30420001, 0x10400018, + 0x00000000, 0x94e2006a, 0x00022880, 0x50a00001, 0x24050001, 0x94e30068, + 0x90e40081, 0x3c020800, 0x8c460024, 0x00652821, 0x00852804, 0x00c5102b, + 0x54400001, 0x00a03021, 0x3c020800, 0x8c440028, 0x00c4182b, 0x54600001, + 0x00c02021, 0x8f430074, 0x2402fffe, 0x00822824, 0x00a31821, 0xace3000c, + 0x8f830008, 0x3c028000, 0x34420001, 0x00621825, 0xaf430020, 0x8f820020, + 0x3c050800, 0x24b05880, 0xae020028, 0x8ee30010, 0x0060f809, 0x00000000, + 0x8f820028, 0x24420001, 0xaf820028, 0x12a00005, 0xaf40004c, 0x8f420e10, + 0xae020030, 0x8f430e18, 0xae030034, 0x1220fea7, 0x24020006, 0x8f870024, + 0x9786002c, 0x8f830000, 0x8f820034, 0x8f840020, 0x8f85001c, 0x32530040, + 0xa4e6002c, 0xac620044, 0x32420008, 0xac640050, 0xac650054, 0x1040007a, + 0x32820020, 0x10400027, 0x32910010, 0x00003821, 0x24052000, 0x3c090800, + 0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd, 0x8ec258b0, 0x26c458b0, + 0x2484ffd0, 0xaf420144, 0x8c820034, 0x3c030400, 0xaf420148, 0x24020041, + 0xaf43014c, 0xa3420152, 0x8d230030, 0x3c021000, 0xa7470158, 0xaf450154, + 0xaf420178, 0x8c860034, 0x24630001, 0xad230030, 0x9342010a, 0x3c030041, + 0xafa50014, 0x00021600, 0x00431025, 0x00471025, 0xafa20010, 0x9343010b, + 0xafa30018, 0x8f440100, 0x8f450104, 0x0e00159b, 0x3c070400, 0x12200028, + 0x00003821, 0x24052000, 0x3c090800, 0x3c038000, 0x8f420178, 0x00431024, + 0x1440fffd, 0x8ec258b0, 0x26c458b0, 0x2484ffd0, 0xaf420144, 0x8c820034, + 0x3c030300, 0xaf420148, 0x2402004e, 0xaf43014c, 0xa3420152, 0x8d230030, + 0x3c021000, 0xa7470158, 0xaf450154, 0xaf420178, 0x8c860034, 0x24630001, + 0xad230030, 0x9342010a, 0x3c03004e, 0xafa50014, 0x00021600, 0x00431025, + 0x00471025, 0xafa20010, 0x9343010b, 0xafa30018, 0x8f440100, 0x8f450104, + 0x0e00159b, 0x3c070300, 0x0a00148b, 0x8fa20024, 0x32820008, 0x10400026, + 0x24052000, 0x00003821, 0x3c090800, 0x3c038000, 0x8f420178, 0x00431024, + 0x1440fffd, 0x8ec258b0, 0x26c458b0, 0x2484ffd0, 0xaf420144, 0x8c820034, + 0x3c030200, 0xaf420148, 0x2402004b, 0xaf43014c, 0xa3420152, 0x8d230030, + 0x3c021000, 0xa7470158, 0xaf450154, 0xaf420178, 0x8c860034, 0x24630001, + 0xad230030, 0x9342010a, 0x3c03004b, 0xafa50014, 0x00021600, 0x00431025, + 0x00471025, 0xafa20010, 0x9343010b, 0xafa30018, 0x8f440100, 0x8f450104, + 0x0e00159b, 0x3c070200, 0x8fa20024, 0x14400004, 0x8fa30020, 0x32420010, + 0x10400004, 0x00000000, 0x8c620004, 0x0040f809, 0x00000000, 0x12600006, + 0x8fa40020, 0x8c820008, 0x0040f809, 0x00000000, 0x0a0014c1, 0x8fbf0054, + 0x3c030800, 0x8c6258a0, 0x30420040, 0x14400023, 0x8fbf0054, 0x00002821, + 0x24040040, 0x8f870020, 0x3c038000, 0x8f420178, 0x00431024, 0x1440fffd, + 0x8ec258b0, 0x26c358b0, 0x2463ffd0, 0xaf420144, 0x8c620034, 0xaf420148, + 0x24020049, 0xaf47014c, 0xa3420152, 0x3c021000, 0xa7450158, 0xaf440154, + 0xaf420178, 0x8c660034, 0x9342010a, 0x3c030049, 0xafa40014, 0x00021600, + 0x00431025, 0x00451025, 0xafa20010, 0x9343010b, 0xafa30018, 0x8f440100, + 0x0e00159b, 0x8f450104, 0x8fbf0054, 0x8fbe0050, 0x8fb7004c, 0x8fb60048, + 0x8fb50044, 0x8fb40040, 0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030, + 0x03e00008, 0x27bd0058, 0x03e00008, 0x00001021, 0x3c020800, 0x24435880, + 0x8c650004, 0x8c445880, 0x0085182b, 0x10600002, 0x00403021, 0x00802821, + 0x9744093c, 0x00a4102b, 0x54400001, 0x00a02021, 0x93420923, 0x0004182b, + 0x00021042, 0x30420001, 0x00431024, 0x1040000d, 0x24c25880, 0x8f850000, + 0x8f830020, 0x8ca20084, 0x00431023, 0x04420007, 0x24c25880, 0x8ca20084, + 0x00641821, 0x00431023, 0x28420001, 0x00822023, 0x24c25880, 0xac440008, + 0xa4400026, 0x03e00008, 0x00001021, 0x8f850004, 0x97840010, 0x3c030800, + 0x24635880, 0x24020008, 0xa4620012, 0x8f820004, 0xa4600010, 0x000420c2, 0x30840008, 0x2c420001, 0x00021023, 0x30420006, 0xac650008, 0x03e00008, - 0xa0640020, 0x3c020800, 0x24424120, 0x90450021, 0x94430018, 0x3c021100, + 0xa0640024, 0x3c020800, 0x24425880, 0x90450025, 0x9443001c, 0x3c021100, 0xac800004, 0x00052c00, 0x24630002, 0x00621825, 0x00a32825, 0x24820008, - 0x03e00008, 0xac850000, 0x0000000d, 0x00000000, 0x2400016f, 0x03e00008, - 0x00000000, 0x0000000d, 0x00000000, 0x2400017b, 0x03e00008, 0x00000000, - 0x03e00008, 0x00000000, 0x3c020800, 0x24424120, 0xac400008, 0xa4400022, - 0x03e00008, 0x24020001, 0x3c020800, 0x24424120, 0x24030008, 0xac400008, - 0xa440000c, 0xa443000e, 0xa0400020, 0x03e00008, 0x24020004, 0x03e00008, + 0x03e00008, 0xac850000, 0x27bdffd8, 0x3c020800, 0x24425880, 0xafbf0020, + 0x90480025, 0x8c440008, 0x8c460020, 0x8f870020, 0x3c030800, 0x3c058000, + 0x8f420178, 0x00451024, 0x1440fffd, 0x8c6258b0, 0x246358b0, 0x2469ffd0, + 0xaf420144, 0x8d220034, 0x30c32000, 0xaf420148, 0x3c021000, 0xaf47014c, + 0xa3480152, 0xa7440158, 0xaf460154, 0xaf420178, 0x10600004, 0x3c030800, + 0x8c620030, 0x24420001, 0xac620030, 0x9342010a, 0x00081c00, 0x3084ffff, + 0xafa60014, 0x00021600, 0x00431025, 0x00441025, 0xafa20010, 0x9343010b, + 0xafa30018, 0x8f440100, 0x8f450104, 0x0e00159b, 0x8d260034, 0x8fbf0020, + 0x03e00008, 0x27bd0028, 0x0000000d, 0x00000000, 0x2400019d, 0x03e00008, + 0x00000000, 0x0000000d, 0x00000000, 0x240001a9, 0x03e00008, 0x00000000, + 0x03e00008, 0x00000000, 0x3c020800, 0x24425880, 0xac400008, 0xa4400026, + 0x03e00008, 0x24020001, 0x3c020800, 0x24425880, 0x24030008, 0xac400008, + 0xa4400010, 0xa4430012, 0xa0400024, 0x03e00008, 0x24020004, 0x03e00008, 0x00001021, 0x10c00007, 0x00000000, 0x8ca20000, 0x24c6ffff, 0x24a50004, - 0xac820000, 0x14c0fffb, 0x24840004, 0x03e00008, 0x00000000, 0x0a000fb2, - 0x00a01021, 0xac860000, 0x24840004, 0x00a01021, 0x1440fffc, 0x24a5ffff, - 0x03e00008, 0x00000000, 0x3c0a0800, 0x8d490068, 0x3c050800, 0x24a51090, - 0x00093140, 0x00c51021, 0xac440000, 0x8f440e04, 0x00a61021, 0xac440004, - 0x97430e08, 0x97420e0c, 0x00a62021, 0x00031c00, 0x00431025, 0xac820008, - 0x8f430e10, 0x00801021, 0xac43000c, 0x8f440e14, 0xac440010, 0x8f430e18, - 0x3c0800ff, 0xac430014, 0x8f470e1c, 0x3508ffff, 0x25290001, 0xac470018, - 0x3c070800, 0x8ce3006c, 0x9344010a, 0x3c026000, 0x24630001, 0xace3006c, - 0x8c434448, 0x3129007f, 0x00a62821, 0xad490068, 0x00042600, 0x00681824, - 0x00832025, 0x03e00008, 0xaca4001c, 0x8fac0010, 0x8fad0014, 0x8fae0018, - 0x3c0b0800, 0x8d6a0060, 0x3c080800, 0x25080078, 0x000a4940, 0x01281021, - 0x01091821, 0xac440000, 0x00601021, 0xac650004, 0xac460008, 0xac67000c, - 0xac4c0010, 0xac6d0014, 0x3c036000, 0xac4e0018, 0x8c654448, 0x3c040800, - 0x8c820064, 0x254a0001, 0x314a007f, 0x01094021, 0xad6a0060, 0x24420001, - 0xac820064, 0x03e00008, 0xad05001c, 0x00000000 }; - -static u32 bnx2_TXP_b06FwData[(0x0/4) + 1] = { 0x00000000 }; -static u32 bnx2_TXP_b06FwRodata[(0x0/4) + 1] = { 0x00000000 }; -static u32 bnx2_TXP_b06FwBss[(0x194/4) + 1] = { 0x00000000 }; -static u32 bnx2_TXP_b06FwSbss[(0x34/4) + 1] = { 0x00000000 }; + 0xac820000, 0x14c0fffb, 0x24840004, 0x03e00008, 0x00000000, 0x0a00156c, + 0x00a01021, 0xac860000, 0x00000000, 0x00000000, 0x24840004, 0x00a01021, + 0x1440fffa, 0x24a5ffff, 0x03e00008, 0x00000000, 0x3c0a0800, 0x8d490068, + 0x3c050800, 0x24a52098, 0x00093140, 0x00c51021, 0xac440000, 0x8f440e04, + 0x00a61021, 0xac440004, 0x97430e08, 0x97420e0c, 0x00a62021, 0x00031c00, + 0x00431025, 0xac820008, 0x8f430e10, 0x00801021, 0xac43000c, 0x8f440e14, + 0xac440010, 0x8f430e18, 0x3c0800ff, 0xac430014, 0x8f470e1c, 0x3508ffff, + 0x25290001, 0xac470018, 0x3c070800, 0x8ce3006c, 0x9344010a, 0x3c026000, + 0x24630001, 0xace3006c, 0x8c434448, 0x3129007f, 0x00a62821, 0xad490068, + 0x00042600, 0x00681824, 0x00832025, 0x03e00008, 0xaca4001c, 0x8fac0010, + 0x8fad0014, 0x8fae0018, 0x3c0b0800, 0x8d6a0060, 0x3c080800, 0x25080080, + 0x000a4940, 0x01281021, 0x01091821, 0xac440000, 0x00601021, 0xac650004, + 0xac460008, 0xac67000c, 0xac4c0010, 0xac6d0014, 0x3c036000, 0xac4e0018, + 0x8c654448, 0x3c040800, 0x8c820064, 0x254a0001, 0x314a00ff, 0x01094021, + 0xad6a0060, 0x24420001, 0xac820064, 0x03e00008, 0xad05001c, 0x3c030800, + 0x3c090800, 0x8d250070, 0x246330b0, 0x8f460100, 0x00053900, 0x00e31021, + 0xac460000, 0x8f440104, 0x00671021, 0xac440004, 0x8f460108, 0x8f840014, + 0x24a50001, 0xac460008, 0x8c880074, 0x3c060800, 0x8cc20074, 0x30a5003f, + 0x00671821, 0xad250070, 0x24420001, 0xacc20074, 0x03e00008, 0xac68000c, + 0x00000000 }; +static u32 bnx2_TXP_b06FwData[(0x0/4) + 1] = { 0x0 }; +static u32 bnx2_TXP_b06FwRodata[(0x0/4) + 1] = { 0x0 }; +static u32 bnx2_TXP_b06FwBss[(0x1c4/4) + 1] = { 0x0 }; +static u32 bnx2_TXP_b06FwSbss[(0x38/4) + 1] = { 0x0 }; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 9c7feaeaa6a46b264473ced37a56e88402864089..8eae8ba27e84da532250b16756c60456e00dcee1 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -1739,7 +1739,7 @@ e1000_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data) } } -struct ethtool_ops e1000_ethtool_ops = { +static struct ethtool_ops e1000_ethtool_ops = { .get_settings = e1000_get_settings, .set_settings = e1000_set_settings, .get_drvinfo = e1000_get_drvinfo, diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 8fc876da43b43fafb5c0f6f7455856da013b68f0..a267c5235fc0d153b08c07a7b4fe3fc41a1df666 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -68,6 +68,38 @@ static int32_t e1000_polarity_reversal_workaround(struct e1000_hw *hw); static int32_t e1000_set_phy_mode(struct e1000_hw *hw); static int32_t e1000_host_if_read_cookie(struct e1000_hw *hw, uint8_t *buffer); static uint8_t e1000_calculate_mng_checksum(char *buffer, uint32_t length); +static uint8_t e1000_arc_subsystem_valid(struct e1000_hw *hw); +static int32_t e1000_check_downshift(struct e1000_hw *hw); +static int32_t e1000_check_polarity(struct e1000_hw *hw, uint16_t *polarity); +static void e1000_clear_hw_cntrs(struct e1000_hw *hw); +static void e1000_clear_vfta(struct e1000_hw *hw); +static int32_t e1000_commit_shadow_ram(struct e1000_hw *hw); +static int32_t e1000_config_dsp_after_link_change(struct e1000_hw *hw, + boolean_t link_up); +static int32_t e1000_config_fc_after_link_up(struct e1000_hw *hw); +static int32_t e1000_detect_gig_phy(struct e1000_hw *hw); +static int32_t e1000_get_auto_rd_done(struct e1000_hw *hw); +static int32_t e1000_get_cable_length(struct e1000_hw *hw, + uint16_t *min_length, + uint16_t *max_length); +static int32_t e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw); +static int32_t e1000_get_phy_cfg_done(struct e1000_hw *hw); +static int32_t e1000_id_led_init(struct e1000_hw * hw); +static void e1000_init_rx_addrs(struct e1000_hw *hw); +static boolean_t e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw); +static int32_t e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int eerd); +static void e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw); +static int32_t e1000_read_eeprom_eerd(struct e1000_hw *hw, uint16_t offset, + uint16_t words, uint16_t *data); +static int32_t e1000_set_d0_lplu_state(struct e1000_hw *hw, boolean_t active); +static int32_t e1000_set_d3_lplu_state(struct e1000_hw *hw, boolean_t active); +static int32_t e1000_wait_autoneg(struct e1000_hw *hw); + +static void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, + uint32_t value); + +#define E1000_WRITE_REG_IO(a, reg, val) \ + e1000_write_reg_io((a), E1000_##reg, val) /* IGP cable length table */ static const @@ -2035,7 +2067,7 @@ e1000_force_mac_fc(struct e1000_hw *hw) * based on the flow control negotiated by the PHY. In TBI mode, the TFCE * and RFCE bits will be automaticaly set to the negotiated flow control mode. *****************************************************************************/ -int32_t +static int32_t e1000_config_fc_after_link_up(struct e1000_hw *hw) { int32_t ret_val; @@ -2537,7 +2569,7 @@ e1000_get_speed_and_duplex(struct e1000_hw *hw, * * hw - Struct containing variables accessed by shared code ******************************************************************************/ -int32_t +static int32_t e1000_wait_autoneg(struct e1000_hw *hw) { int32_t ret_val; @@ -3021,7 +3053,7 @@ e1000_phy_reset(struct e1000_hw *hw) * * hw - Struct containing variables accessed by shared code ******************************************************************************/ -int32_t +static int32_t e1000_detect_gig_phy(struct e1000_hw *hw) { int32_t phy_init_status, ret_val; @@ -3121,7 +3153,7 @@ e1000_phy_reset_dsp(struct e1000_hw *hw) * hw - Struct containing variables accessed by shared code * phy_info - PHY information structure ******************************************************************************/ -int32_t +static int32_t e1000_phy_igp_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info) { @@ -3195,7 +3227,7 @@ e1000_phy_igp_get_info(struct e1000_hw *hw, * hw - Struct containing variables accessed by shared code * phy_info - PHY information structure ******************************************************************************/ -int32_t +static int32_t e1000_phy_m88_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info) { @@ -3905,7 +3937,7 @@ e1000_read_eeprom(struct e1000_hw *hw, * data - word read from the EEPROM * words - number of words to read *****************************************************************************/ -int32_t +static int32_t e1000_read_eeprom_eerd(struct e1000_hw *hw, uint16_t offset, uint16_t words, @@ -3939,7 +3971,7 @@ e1000_read_eeprom_eerd(struct e1000_hw *hw, * data - word read from the EEPROM * words - number of words to read *****************************************************************************/ -int32_t +static int32_t e1000_write_eeprom_eewr(struct e1000_hw *hw, uint16_t offset, uint16_t words, @@ -3976,7 +4008,7 @@ e1000_write_eeprom_eewr(struct e1000_hw *hw, * * hw - Struct containing variables accessed by shared code *****************************************************************************/ -int32_t +static int32_t e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int eerd) { uint32_t attempts = 100000; @@ -4004,7 +4036,7 @@ e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int eerd) * * hw - Struct containing variables accessed by shared code ****************************************************************************/ -boolean_t +static boolean_t e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw) { uint32_t eecd = 0; @@ -4322,7 +4354,7 @@ e1000_write_eeprom_microwire(struct e1000_hw *hw, * data - word read from the EEPROM * words - number of words to read *****************************************************************************/ -int32_t +static int32_t e1000_commit_shadow_ram(struct e1000_hw *hw) { uint32_t attempts = 100000; @@ -4453,7 +4485,7 @@ e1000_read_mac_addr(struct e1000_hw * hw) * of the receive addresss registers. Clears the multicast table. Assumes * the receiver is in reset when the routine is called. *****************************************************************************/ -void +static void e1000_init_rx_addrs(struct e1000_hw *hw) { uint32_t i; @@ -4481,6 +4513,7 @@ e1000_init_rx_addrs(struct e1000_hw *hw) } } +#if 0 /****************************************************************************** * Updates the MAC's list of multicast addresses. * @@ -4564,6 +4597,7 @@ e1000_mc_addr_list_update(struct e1000_hw *hw, } DEBUGOUT("MC Update Complete\n"); } +#endif /* 0 */ /****************************************************************************** * Hashes an address to determine its location in the multicast table @@ -4705,7 +4739,7 @@ e1000_write_vfta(struct e1000_hw *hw, * * hw - Struct containing variables accessed by shared code *****************************************************************************/ -void +static void e1000_clear_vfta(struct e1000_hw *hw) { uint32_t offset; @@ -4735,7 +4769,7 @@ e1000_clear_vfta(struct e1000_hw *hw) } } -int32_t +static int32_t e1000_id_led_init(struct e1000_hw * hw) { uint32_t ledctl; @@ -4997,7 +5031,7 @@ e1000_led_off(struct e1000_hw *hw) * * hw - Struct containing variables accessed by shared code *****************************************************************************/ -void +static void e1000_clear_hw_cntrs(struct e1000_hw *hw) { volatile uint32_t temp; @@ -5283,6 +5317,8 @@ e1000_get_bus_info(struct e1000_hw *hw) break; } } + +#if 0 /****************************************************************************** * Reads a value from one of the devices registers using port I/O (as opposed * memory mapped I/O). Only 82544 and newer devices support port I/O. @@ -5300,6 +5336,7 @@ e1000_read_reg_io(struct e1000_hw *hw, e1000_io_write(hw, io_addr, offset); return e1000_io_read(hw, io_data); } +#endif /* 0 */ /****************************************************************************** * Writes a value to one of the devices registers using port I/O (as opposed to @@ -5309,7 +5346,7 @@ e1000_read_reg_io(struct e1000_hw *hw, * offset - offset to write to * value - value to write *****************************************************************************/ -void +static void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value) @@ -5337,7 +5374,7 @@ e1000_write_reg_io(struct e1000_hw *hw, * register to the minimum and maximum range. * For IGP phy's, the function calculates the range by the AGC registers. *****************************************************************************/ -int32_t +static int32_t e1000_get_cable_length(struct e1000_hw *hw, uint16_t *min_length, uint16_t *max_length) @@ -5489,7 +5526,7 @@ e1000_get_cable_length(struct e1000_hw *hw, * return 0. If the link speed is 1000 Mbps the polarity status is in the * IGP01E1000_PHY_PCS_INIT_REG. *****************************************************************************/ -int32_t +static int32_t e1000_check_polarity(struct e1000_hw *hw, uint16_t *polarity) { @@ -5551,7 +5588,7 @@ e1000_check_polarity(struct e1000_hw *hw, * Link Health register. In IGP this bit is latched high, so the driver must * read it immediately after link is established. *****************************************************************************/ -int32_t +static int32_t e1000_check_downshift(struct e1000_hw *hw) { int32_t ret_val; @@ -5592,7 +5629,7 @@ e1000_check_downshift(struct e1000_hw *hw) * ****************************************************************************/ -int32_t +static int32_t e1000_config_dsp_after_link_change(struct e1000_hw *hw, boolean_t link_up) { @@ -5823,7 +5860,7 @@ e1000_set_phy_mode(struct e1000_hw *hw) * ****************************************************************************/ -int32_t +static int32_t e1000_set_d3_lplu_state(struct e1000_hw *hw, boolean_t active) { @@ -5936,7 +5973,7 @@ e1000_set_d3_lplu_state(struct e1000_hw *hw, * ****************************************************************************/ -int32_t +static int32_t e1000_set_d0_lplu_state(struct e1000_hw *hw, boolean_t active) { @@ -6103,7 +6140,7 @@ e1000_host_if_read_cookie(struct e1000_hw * hw, uint8_t *buffer) * timeout * - E1000_SUCCESS for success. ****************************************************************************/ -int32_t +static int32_t e1000_mng_enable_host_if(struct e1000_hw * hw) { uint32_t hicr; @@ -6137,7 +6174,7 @@ e1000_mng_enable_host_if(struct e1000_hw * hw) * * returns - E1000_SUCCESS for success. ****************************************************************************/ -int32_t +static int32_t e1000_mng_host_if_write(struct e1000_hw * hw, uint8_t *buffer, uint16_t length, uint16_t offset, uint8_t *sum) { @@ -6205,7 +6242,7 @@ e1000_mng_host_if_write(struct e1000_hw * hw, uint8_t *buffer, * * returns - E1000_SUCCESS for success. ****************************************************************************/ -int32_t +static int32_t e1000_mng_write_cmd_header(struct e1000_hw * hw, struct e1000_host_mng_command_header * hdr) { @@ -6243,7 +6280,7 @@ e1000_mng_write_cmd_header(struct e1000_hw * hw, * * returns - E1000_SUCCESS for success. ****************************************************************************/ -int32_t +static int32_t e1000_mng_write_commit( struct e1000_hw * hw) { @@ -6496,7 +6533,7 @@ e1000_polarity_reversal_workaround(struct e1000_hw *hw) * returns: - none. * ***************************************************************************/ -void +static void e1000_set_pci_express_master_disable(struct e1000_hw *hw) { uint32_t ctrl; @@ -6511,6 +6548,7 @@ e1000_set_pci_express_master_disable(struct e1000_hw *hw) E1000_WRITE_REG(hw, CTRL, ctrl); } +#if 0 /*************************************************************************** * * Enables PCI-Express master access. @@ -6534,6 +6572,7 @@ e1000_enable_pciex_master(struct e1000_hw *hw) ctrl &= ~E1000_CTRL_GIO_MASTER_DISABLE; E1000_WRITE_REG(hw, CTRL, ctrl); } +#endif /* 0 */ /******************************************************************************* * @@ -6584,7 +6623,7 @@ e1000_disable_pciex_master(struct e1000_hw *hw) * E1000_SUCCESS at any other case. * ******************************************************************************/ -int32_t +static int32_t e1000_get_auto_rd_done(struct e1000_hw *hw) { int32_t timeout = AUTO_READ_DONE_TIMEOUT; @@ -6623,7 +6662,7 @@ e1000_get_auto_rd_done(struct e1000_hw *hw) * E1000_SUCCESS at any other case. * ***************************************************************************/ -int32_t +static int32_t e1000_get_phy_cfg_done(struct e1000_hw *hw) { int32_t timeout = PHY_CFG_TIMEOUT; @@ -6666,7 +6705,7 @@ e1000_get_phy_cfg_done(struct e1000_hw *hw) * E1000_SUCCESS at any other case. * ***************************************************************************/ -int32_t +static int32_t e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw) { int32_t timeout; @@ -6711,7 +6750,7 @@ e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw) * returns: - None. * ***************************************************************************/ -void +static void e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw) { uint32_t swsm; @@ -6747,7 +6786,7 @@ e1000_check_phy_reset_block(struct e1000_hw *hw) E1000_BLK_PHY_RESET : E1000_SUCCESS; } -uint8_t +static uint8_t e1000_arc_subsystem_valid(struct e1000_hw *hw) { uint32_t fwsm; diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 4f2c196dc314cd68d79b9297e0b352c1118fa786..76ce12809a11641cc6788fcc75a99cdca1d5dd70 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -284,7 +284,6 @@ typedef enum { /* Initialization */ int32_t e1000_reset_hw(struct e1000_hw *hw); int32_t e1000_init_hw(struct e1000_hw *hw); -int32_t e1000_id_led_init(struct e1000_hw * hw); int32_t e1000_set_mac_type(struct e1000_hw *hw); void e1000_set_media_type(struct e1000_hw *hw); @@ -292,10 +291,8 @@ void e1000_set_media_type(struct e1000_hw *hw); int32_t e1000_setup_link(struct e1000_hw *hw); int32_t e1000_phy_setup_autoneg(struct e1000_hw *hw); void e1000_config_collision_dist(struct e1000_hw *hw); -int32_t e1000_config_fc_after_link_up(struct e1000_hw *hw); int32_t e1000_check_for_link(struct e1000_hw *hw); int32_t e1000_get_speed_and_duplex(struct e1000_hw *hw, uint16_t * speed, uint16_t * duplex); -int32_t e1000_wait_autoneg(struct e1000_hw *hw); int32_t e1000_force_mac_fc(struct e1000_hw *hw); /* PHY */ @@ -303,21 +300,11 @@ int32_t e1000_read_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *phy int32_t e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data); int32_t e1000_phy_hw_reset(struct e1000_hw *hw); int32_t e1000_phy_reset(struct e1000_hw *hw); -int32_t e1000_detect_gig_phy(struct e1000_hw *hw); int32_t e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info); -int32_t e1000_phy_m88_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info); -int32_t e1000_phy_igp_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info); -int32_t e1000_get_cable_length(struct e1000_hw *hw, uint16_t *min_length, uint16_t *max_length); -int32_t e1000_check_polarity(struct e1000_hw *hw, uint16_t *polarity); -int32_t e1000_check_downshift(struct e1000_hw *hw); int32_t e1000_validate_mdi_setting(struct e1000_hw *hw); /* EEPROM Functions */ int32_t e1000_init_eeprom_params(struct e1000_hw *hw); -boolean_t e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw); -int32_t e1000_read_eeprom_eerd(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data); -int32_t e1000_write_eeprom_eewr(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data); -int32_t e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int eerd); /* MNG HOST IF functions */ uint32_t e1000_enable_mng_pass_thru(struct e1000_hw *hw); @@ -377,13 +364,6 @@ int32_t e1000_mng_write_dhcp_info(struct e1000_hw *hw, uint8_t *buffer, uint16_t length); boolean_t e1000_check_mng_mode(struct e1000_hw *hw); boolean_t e1000_enable_tx_pkt_filtering(struct e1000_hw *hw); -int32_t e1000_mng_enable_host_if(struct e1000_hw *hw); -int32_t e1000_mng_host_if_write(struct e1000_hw *hw, uint8_t *buffer, - uint16_t length, uint16_t offset, uint8_t *sum); -int32_t e1000_mng_write_cmd_header(struct e1000_hw* hw, - struct e1000_host_mng_command_header* hdr); - -int32_t e1000_mng_write_commit(struct e1000_hw *hw); int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t words, uint16_t *data); int32_t e1000_validate_eeprom_checksum(struct e1000_hw *hw); @@ -395,13 +375,10 @@ int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask); void e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask); /* Filters (multicast, vlan, receive) */ -void e1000_init_rx_addrs(struct e1000_hw *hw); -void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad, uint32_t rar_used_count); uint32_t e1000_hash_mc_addr(struct e1000_hw *hw, uint8_t * mc_addr); void e1000_mta_set(struct e1000_hw *hw, uint32_t hash_value); void e1000_rar_set(struct e1000_hw *hw, uint8_t * mc_addr, uint32_t rar_index); void e1000_write_vfta(struct e1000_hw *hw, uint32_t offset, uint32_t value); -void e1000_clear_vfta(struct e1000_hw *hw); /* LED functions */ int32_t e1000_setup_led(struct e1000_hw *hw); @@ -412,7 +389,6 @@ int32_t e1000_led_off(struct e1000_hw *hw); /* Adaptive IFS Functions */ /* Everything else */ -void e1000_clear_hw_cntrs(struct e1000_hw *hw); void e1000_reset_adaptive(struct e1000_hw *hw); void e1000_update_adaptive(struct e1000_hw *hw); void e1000_tbi_adjust_stats(struct e1000_hw *hw, struct e1000_hw_stats *stats, uint32_t frame_len, uint8_t * mac_addr); @@ -423,29 +399,11 @@ void e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value); void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value); /* Port I/O is only supported on 82544 and newer */ uint32_t e1000_io_read(struct e1000_hw *hw, unsigned long port); -uint32_t e1000_read_reg_io(struct e1000_hw *hw, uint32_t offset); void e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value); -void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value); -int32_t e1000_config_dsp_after_link_change(struct e1000_hw *hw, boolean_t link_up); -int32_t e1000_set_d3_lplu_state(struct e1000_hw *hw, boolean_t active); -int32_t e1000_set_d0_lplu_state(struct e1000_hw *hw, boolean_t active); -void e1000_set_pci_express_master_disable(struct e1000_hw *hw); -void e1000_enable_pciex_master(struct e1000_hw *hw); int32_t e1000_disable_pciex_master(struct e1000_hw *hw); -int32_t e1000_get_auto_rd_done(struct e1000_hw *hw); -int32_t e1000_get_phy_cfg_done(struct e1000_hw *hw); int32_t e1000_get_software_semaphore(struct e1000_hw *hw); void e1000_release_software_semaphore(struct e1000_hw *hw); int32_t e1000_check_phy_reset_block(struct e1000_hw *hw); -int32_t e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw); -void e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw); -int32_t e1000_commit_shadow_ram(struct e1000_hw *hw); -uint8_t e1000_arc_subsystem_valid(struct e1000_hw *hw); - -#define E1000_READ_REG_IO(a, reg) \ - e1000_read_reg_io((a), E1000_##reg) -#define E1000_WRITE_REG_IO(a, reg, val) \ - e1000_write_reg_io((a), E1000_##reg, val) /* PCI Device IDs */ #define E1000_DEV_ID_82542 0x1000 diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index efbbda7cbcbfe36382730ec7781605c18ecd3dc7..8b207f0e139e04fb9894ec771195f0866ea8210b 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -37,7 +37,7 @@ */ char e1000_driver_name[] = "e1000"; -char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; +static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; #ifndef CONFIG_E1000_NAPI #define DRIVERNAPI #else @@ -45,7 +45,7 @@ char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; #endif #define DRV_VERSION "6.1.16-k2"DRIVERNAPI char e1000_driver_version[] = DRV_VERSION; -char e1000_copyright[] = "Copyright (c) 1999-2005 Intel Corporation."; +static char e1000_copyright[] = "Copyright (c) 1999-2005 Intel Corporation."; /* e1000_pci_tbl - PCI Device ID Table * @@ -112,14 +112,14 @@ int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); void e1000_free_all_tx_resources(struct e1000_adapter *adapter); void e1000_free_all_rx_resources(struct e1000_adapter *adapter); -int e1000_setup_tx_resources(struct e1000_adapter *adapter, - struct e1000_tx_ring *txdr); -int e1000_setup_rx_resources(struct e1000_adapter *adapter, - struct e1000_rx_ring *rxdr); -void e1000_free_tx_resources(struct e1000_adapter *adapter, - struct e1000_tx_ring *tx_ring); -void e1000_free_rx_resources(struct e1000_adapter *adapter, - struct e1000_rx_ring *rx_ring); +static int e1000_setup_tx_resources(struct e1000_adapter *adapter, + struct e1000_tx_ring *txdr); +static int e1000_setup_rx_resources(struct e1000_adapter *adapter, + struct e1000_rx_ring *rxdr); +static void e1000_free_tx_resources(struct e1000_adapter *adapter, + struct e1000_tx_ring *tx_ring); +static void e1000_free_rx_resources(struct e1000_adapter *adapter, + struct e1000_rx_ring *rx_ring); void e1000_update_stats(struct e1000_adapter *adapter); /* Local Function Prototypes */ @@ -296,7 +296,8 @@ e1000_irq_enable(struct e1000_adapter *adapter) E1000_WRITE_FLUSH(&adapter->hw); } } -void + +static void e1000_update_mng_vlan(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; @@ -1141,7 +1142,7 @@ e1000_check_64k_bound(struct e1000_adapter *adapter, * Return 0 on success, negative on failure **/ -int +static int e1000_setup_tx_resources(struct e1000_adapter *adapter, struct e1000_tx_ring *txdr) { @@ -1359,7 +1360,7 @@ e1000_configure_tx(struct e1000_adapter *adapter) * Returns 0 on success, negative on failure **/ -int +static int e1000_setup_rx_resources(struct e1000_adapter *adapter, struct e1000_rx_ring *rxdr) { @@ -1747,7 +1748,7 @@ e1000_configure_rx(struct e1000_adapter *adapter) * Free all transmit software resources **/ -void +static void e1000_free_tx_resources(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring) { @@ -1858,7 +1859,7 @@ e1000_clean_all_tx_rings(struct e1000_adapter *adapter) * Free all receive software resources **/ -void +static void e1000_free_rx_resources(struct e1000_adapter *adapter, struct e1000_rx_ring *rx_ring) { diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 85504fb900dab5a62402a2ddc60e7ec5febe52e3..bd6983d1afbac77ed852c8991cb7b653d4272128 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -18,8 +18,8 @@ * Much better multiple PHY support by Magnus Damm. * Copyright (c) 2000 Ericsson Radio Systems AB. * - * Support for FEC controller of ColdFire/5270/5271/5272/5274/5275/5280/5282. - * Copyright (c) 2001-2004 Greg Ungerer (gerg@snapgear.com) + * Support for FEC controller of ColdFire processors. + * Copyright (c) 2001-2005 Greg Ungerer (gerg@snapgear.com) * * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be) * Copyright (c) 2004-2005 Macq Electronique SA. @@ -50,7 +50,8 @@ #include #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || \ - defined(CONFIG_M5272) || defined(CONFIG_M528x) + defined(CONFIG_M5272) || defined(CONFIG_M528x) || \ + defined(CONFIG_M520x) #include #include #include "fec.h" @@ -77,6 +78,8 @@ static unsigned int fec_hw[] = { (MCF_MBAR + 0x1800), #elif defined(CONFIG_M523x) || defined(CONFIG_M528x) (MCF_MBAR + 0x1000), +#elif defined(CONFIG_M520x) + (MCF_MBAR+0x30000), #else &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec), #endif @@ -139,6 +142,10 @@ typedef struct { #define TX_RING_SIZE 16 /* Must be power of two */ #define TX_RING_MOD_MASK 15 /* for this to work */ +#if (((RX_RING_SIZE + TX_RING_SIZE) * 8) > PAGE_SIZE) +#error "FEC: descriptor ring size contants too large" +#endif + /* Interrupt events/masks. */ #define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */ @@ -164,7 +171,8 @@ typedef struct { * size bits. Other FEC hardware does not, so we need to take that into * account when setting it. */ -#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) +#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ + defined(CONFIG_M520x) #define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16) #else #define OPT_FRAME_SIZE 0 @@ -1136,6 +1144,65 @@ static phy_info_t const phy_info_ks8721bl = { .shutdown = phy_cmd_ks8721bl_shutdown }; +/* ------------------------------------------------------------------------- */ +/* register definitions for the DP83848 */ + +#define MII_DP8384X_PHYSTST 16 /* PHY Status Register */ + +static void mii_parse_dp8384x_sr2(uint mii_reg, struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + volatile uint *s = &(fep->phy_status); + + *s &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC); + + /* Link up */ + if (mii_reg & 0x0001) { + fep->link = 1; + *s |= PHY_STAT_LINK; + } else + fep->link = 0; + /* Status of link */ + if (mii_reg & 0x0010) /* Autonegotioation complete */ + *s |= PHY_STAT_ANC; + if (mii_reg & 0x0002) { /* 10MBps? */ + if (mii_reg & 0x0004) /* Full Duplex? */ + *s |= PHY_STAT_10FDX; + else + *s |= PHY_STAT_10HDX; + } else { /* 100 Mbps? */ + if (mii_reg & 0x0004) /* Full Duplex? */ + *s |= PHY_STAT_100FDX; + else + *s |= PHY_STAT_100HDX; + } + if (mii_reg & 0x0008) + *s |= PHY_STAT_FAULT; +} + +static phy_info_t phy_info_dp83848= { + 0x020005c9, + "DP83848", + + (const phy_cmd_t []) { /* config */ + { mk_mii_read(MII_REG_CR), mii_parse_cr }, + { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, + { mk_mii_read(MII_DP8384X_PHYSTST), mii_parse_dp8384x_sr2 }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* startup - enable interrupts */ + { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ + { mk_mii_read(MII_REG_SR), mii_parse_sr }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* ack_int - never happens, no interrupt */ + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* shutdown */ + { mk_mii_end, } + }, +}; + /* ------------------------------------------------------------------------- */ static phy_info_t const * const phy_info[] = { @@ -1144,6 +1211,7 @@ static phy_info_t const * const phy_info[] = { &phy_info_qs6612, &phy_info_am79c874, &phy_info_ks8721bl, + &phy_info_dp83848, NULL }; @@ -1422,6 +1490,134 @@ static void __inline__ fec_uncache(unsigned long addr) /* ------------------------------------------------------------------------- */ +#elif defined(CONFIG_M520x) + +/* + * Code specific to Coldfire 520x + */ +static void __inline__ fec_request_intrs(struct net_device *dev) +{ + struct fec_enet_private *fep; + int b; + static const struct idesc { + char *name; + unsigned short irq; + } *idp, id[] = { + { "fec(TXF)", 23 }, + { "fec(TXB)", 24 }, + { "fec(TXFIFO)", 25 }, + { "fec(TXCR)", 26 }, + { "fec(RXF)", 27 }, + { "fec(RXB)", 28 }, + { "fec(MII)", 29 }, + { "fec(LC)", 30 }, + { "fec(HBERR)", 31 }, + { "fec(GRA)", 32 }, + { "fec(EBERR)", 33 }, + { "fec(BABT)", 34 }, + { "fec(BABR)", 35 }, + { NULL }, + }; + + fep = netdev_priv(dev); + b = 64 + 13; + + /* Setup interrupt handlers. */ + for (idp = id; idp->name; idp++) { + if (request_irq(b+idp->irq,fec_enet_interrupt,0,idp->name,dev)!=0) + printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, b+idp->irq); + } + + /* Unmask interrupts at ColdFire interrupt controller */ + { + volatile unsigned char *icrp; + volatile unsigned long *imrp; + + icrp = (volatile unsigned char *) (MCF_IPSBAR + MCFICM_INTC0 + + MCFINTC_ICR0); + for (b = 36; (b < 49); b++) + icrp[b] = 0x04; + imrp = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + + MCFINTC_IMRH); + *imrp &= ~0x0001FFF0; + } + *(volatile unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FEC) |= 0xf0; + *(volatile unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FECI2C) |= 0x0f; +} + +static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep) +{ + volatile fec_t *fecp; + + fecp = fep->hwp; + fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04; + fecp->fec_x_cntrl = 0x00; + + /* + * Set MII speed to 2.5 MHz + * See 5282 manual section 17.5.4.7: MSCR + */ + fep->phy_speed = ((((MCF_CLK / 2) / (2500000 / 10)) + 5) / 10) * 2; + fecp->fec_mii_speed = fep->phy_speed; + + fec_restart(dev, 0); +} + +static void __inline__ fec_get_mac(struct net_device *dev) +{ + struct fec_enet_private *fep = netdev_priv(dev); + volatile fec_t *fecp; + unsigned char *iap, tmpaddr[ETH_ALEN]; + + fecp = fep->hwp; + + if (FEC_FLASHMAC) { + /* + * Get MAC address from FLASH. + * If it is all 1's or 0's, use the default. + */ + iap = FEC_FLASHMAC; + if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) && + (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0)) + iap = fec_mac_default; + if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) && + (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff)) + iap = fec_mac_default; + } else { + *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low; + *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16); + iap = &tmpaddr[0]; + } + + memcpy(dev->dev_addr, iap, ETH_ALEN); + + /* Adjust MAC if using default MAC address */ + if (iap == fec_mac_default) + dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index; +} + +static void __inline__ fec_enable_phy_intr(void) +{ +} + +static void __inline__ fec_disable_phy_intr(void) +{ +} + +static void __inline__ fec_phy_ack_intr(void) +{ +} + +static void __inline__ fec_localhw_setup(void) +{ +} + +static void __inline__ fec_uncache(unsigned long addr) +{ +} + +/* ------------------------------------------------------------------------- */ + #else /* @@ -1952,6 +2148,14 @@ int __init fec_enet_init(struct net_device *dev) if (index >= FEC_MAX_PORTS) return -ENXIO; + /* Allocate memory for buffer descriptors. + */ + mem_addr = __get_free_page(GFP_KERNEL); + if (mem_addr == 0) { + printk("FEC: allocate descriptor memory failed?\n"); + return -ENOMEM; + } + /* Create an Ethernet device instance. */ fecp = (volatile fec_t *) fec_hw[index]; @@ -1964,16 +2168,6 @@ int __init fec_enet_init(struct net_device *dev) fecp->fec_ecntrl = 1; udelay(10); - /* Clear and enable interrupts */ - fecp->fec_ievent = 0xffc00000; - fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | - FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); - fecp->fec_hash_table_high = 0; - fecp->fec_hash_table_low = 0; - fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; - fecp->fec_ecntrl = 2; - fecp->fec_r_des_active = 0x01000000; - /* Set the Ethernet address. If using multiple Enets on the 8xx, * this needs some work to get unique addresses. * @@ -1982,14 +2176,6 @@ int __init fec_enet_init(struct net_device *dev) */ fec_get_mac(dev); - /* Allocate memory for buffer descriptors. - */ - if (((RX_RING_SIZE + TX_RING_SIZE) * sizeof(cbd_t)) > PAGE_SIZE) { - printk("FEC init error. Need more space.\n"); - printk("FEC initialization failed.\n"); - return 1; - } - mem_addr = __get_free_page(GFP_KERNEL); cbd_base = (cbd_t *)mem_addr; /* XXX: missing check for allocation failure */ @@ -2067,6 +2253,16 @@ int __init fec_enet_init(struct net_device *dev) */ fec_request_intrs(dev); + /* Clear and enable interrupts */ + fecp->fec_ievent = 0xffc00000; + fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | + FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); + fecp->fec_hash_table_high = 0; + fecp->fec_hash_table_low = 0; + fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; + fecp->fec_ecntrl = 2; + fecp->fec_r_des_active = 0x01000000; + dev->base_addr = (unsigned long)fecp; /* The FEC Ethernet specific entries in the device structure. */ diff --git a/drivers/net/fec.h b/drivers/net/fec.h index 045761b8a6004ab1f25c73bcd082d00573024589..965c5c49fcdce023906942f2aa117d7cb94a35f4 100644 --- a/drivers/net/fec.h +++ b/drivers/net/fec.h @@ -1,11 +1,10 @@ /****************************************************************************/ /* - * fec.h -- Fast Ethernet Controller for Motorola ColdFire 5230, - * 5231, 5232, 5234, 5235, 5270, 5271, 5272, 5274, 5275, - * 5280 and 5282. + * fec.h -- Fast Ethernet Controller for Motorola ColdFire SoC + * processors. * - * (C) Copyright 2000-2003, Greg Ungerer (gerg@snapgear.com) + * (C) Copyright 2000-2005, Greg Ungerer (gerg@snapgear.com) * (C) Copyright 2000-2001, Lineo (www.lineo.com) */ @@ -14,7 +13,8 @@ #define FEC_H /****************************************************************************/ -#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) +#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ + defined(CONFIG_M520x) /* * Just figures, Motorola would have to change the offsets for * registers in the same peripheral device on different models diff --git a/drivers/net/fec_8xx/Kconfig b/drivers/net/fec_8xx/Kconfig index 4560026ed419d776851273b2316e5244d57557f5..94e7a9af87055f0642abccb1309a43a2ec95d8cc 100644 --- a/drivers/net/fec_8xx/Kconfig +++ b/drivers/net/fec_8xx/Kconfig @@ -1,6 +1,6 @@ config FEC_8XX tristate "Motorola 8xx FEC driver" - depends on NET_ETHERNET + depends on NET_ETHERNET && FEC select MII config FEC_8XX_GENERIC_PHY diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index 3be3f916643a17fcb53574f83cf39d8c8ae5bb9e..c8dc40214a087f752a0be4ce7b644e7c24fc223c 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c @@ -311,16 +311,6 @@ static void __exit dmascc_exit(void) } } -#ifndef MODULE -void __init dmascc_setup(char *str, int *ints) -{ - int i; - - for (i = 0; i < MAX_NUM_DEVS && i < ints[0]; i++) - io[i] = ints[i + 1]; -} -#endif - static int __init dmascc_init(void) { int h, i, j, n; diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index 49e5467bdd7336a34dc9cb5bd5928291c683b408..6a3129bc15a6d6327c5dec32f8e518049e6c5787 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -46,10 +46,8 @@ #include #ifdef CONFIG_SERIAL_8250 -#include -#include -#define IOC3_BAUD (22000000 / (3*16)) -#define IOC3_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) +#include +#include #endif #include @@ -1146,12 +1144,11 @@ static inline int ioc3_is_menet(struct pci_dev *pdev) * around ioc3 oddities in this respect. * * The IOC3 serials use a 22MHz clock rate with an additional divider by 3. - * (IOC3_BAUD = (22000000 / (3*16))) */ static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3) { - struct serial_struct req; + struct uart_port port; /* * We need to recognice and treat the fourth MENET serial as it @@ -1165,20 +1162,25 @@ static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3) if (ioc3_is_menet(pdev) && PCI_SLOT(pdev->devfn) == 3) return; - /* Register to interrupt zero because we share the interrupt with - the serial driver which we don't properly support yet. */ - memset(&req, 0, sizeof(req)); - req.irq = 0; - req.flags = IOC3_COM_FLAGS; - req.io_type = SERIAL_IO_MEM; - req.iomem_reg_shift = 0; - req.baud_base = IOC3_BAUD; - - req.iomem_base = (unsigned char *) &ioc3->sregs.uarta; - register_serial(&req); - - req.iomem_base = (unsigned char *) &ioc3->sregs.uartb; - register_serial(&req); + /* + * Register to interrupt zero because we share the interrupt with + * the serial driver which we don't properly support yet. + * + * Can't use UPF_IOREMAP as the whole of IOC3 resources have already + * been registered. + */ + memset(&port, 0, sizeof(port)); + port.irq = 0; + port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF; + port.iotype = UPIO_MEM; + port.regshift = 0; + port.uartclk = 22000000 / 3; + + port.membase = (unsigned char *) &ioc3->sregs.uarta; + serial8250_register_port(&port); + + port.membase = (unsigned char *) &ioc3->sregs.uartb; + serial8250_register_port(&port); } #endif diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 0282771b1cbb3ca27d625c0b8b60dc8810672fcb..3137592d60c01816f3bb03bb0d4bd05227432f99 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -1459,8 +1459,10 @@ toshoboe_net_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) */ IRDA_DEBUG (1, "%s(BANDWIDTH), %s, (%X/%ld\n", __FUNCTION__ ,dev->name, INB (OBOE_STATUS), irq->ifr_baudrate ); - if (!in_interrupt () && !capable (CAP_NET_ADMIN)) - return -EPERM; + if (!in_interrupt () && !capable (CAP_NET_ADMIN)) { + ret = -EPERM; + goto out; + } /* self->speed=irq->ifr_baudrate; */ /* toshoboe_setbaud(self); */ @@ -1470,8 +1472,10 @@ toshoboe_net_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) case SIOCSMEDIABUSY: /* Set media busy */ IRDA_DEBUG (1, "%s(MEDIABUSY), %s, (%X/%x)\n", __FUNCTION__ ,dev->name, INB (OBOE_STATUS), capable (CAP_NET_ADMIN) ); - if (!capable (CAP_NET_ADMIN)) - return -EPERM; + if (!capable (CAP_NET_ADMIN)) { + ret = -EPERM; + goto out; + } irda_device_set_media_busy (self->netdev, TRUE); break; case SIOCGRECEIVING: /* Check if we are receiving right now */ @@ -1483,7 +1487,7 @@ toshoboe_net_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) IRDA_DEBUG (1, "%s(?), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd); ret = -EOPNOTSUPP; } - +out: spin_unlock_irqrestore(&self->spinlock, flags); return ret; diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index 04e47189d830105a848d6b6db71c8dd26f625de9..d38ade5f2f4e614f30a0755958f1b64ee484de28 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -694,7 +694,7 @@ ixgb_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data) } } -struct ethtool_ops ixgb_ethtool_ops = { +static struct ethtool_ops ixgb_ethtool_ops = { .get_settings = ixgb_get_settings, .set_settings = ixgb_set_settings, .get_drvinfo = ixgb_get_drvinfo, diff --git a/drivers/net/ixgb/ixgb_hw.c b/drivers/net/ixgb/ixgb_hw.c index 69329c73095ab253bf306eb7f6b6d2a8eebabae4..620cad48bdea98a8ab4302b6c9119b71b7a471ee 100644 --- a/drivers/net/ixgb/ixgb_hw.c +++ b/drivers/net/ixgb/ixgb_hw.c @@ -47,9 +47,22 @@ static void ixgb_optics_reset(struct ixgb_hw *hw); static ixgb_phy_type ixgb_identify_phy(struct ixgb_hw *hw); -uint32_t ixgb_mac_reset(struct ixgb_hw *hw); +static void ixgb_clear_hw_cntrs(struct ixgb_hw *hw); -uint32_t ixgb_mac_reset(struct ixgb_hw *hw) +static void ixgb_clear_vfta(struct ixgb_hw *hw); + +static void ixgb_init_rx_addrs(struct ixgb_hw *hw); + +static uint16_t ixgb_read_phy_reg(struct ixgb_hw *hw, + uint32_t reg_address, + uint32_t phy_address, + uint32_t device_type); + +static boolean_t ixgb_setup_fc(struct ixgb_hw *hw); + +static boolean_t mac_addr_valid(uint8_t *mac_addr); + +static uint32_t ixgb_mac_reset(struct ixgb_hw *hw) { uint32_t ctrl_reg; @@ -335,7 +348,7 @@ ixgb_init_hw(struct ixgb_hw *hw) * of the receive addresss registers. Clears the multicast table. Assumes * the receiver is in reset when the routine is called. *****************************************************************************/ -void +static void ixgb_init_rx_addrs(struct ixgb_hw *hw) { uint32_t i; @@ -604,7 +617,7 @@ ixgb_write_vfta(struct ixgb_hw *hw, * * hw - Struct containing variables accessed by shared code *****************************************************************************/ -void +static void ixgb_clear_vfta(struct ixgb_hw *hw) { uint32_t offset; @@ -620,7 +633,7 @@ ixgb_clear_vfta(struct ixgb_hw *hw) * hw - Struct containing variables accessed by shared code *****************************************************************************/ -boolean_t +static boolean_t ixgb_setup_fc(struct ixgb_hw *hw) { uint32_t ctrl_reg; @@ -722,7 +735,7 @@ ixgb_setup_fc(struct ixgb_hw *hw) * This requires that first an address cycle command is sent, followed by a * read command. *****************************************************************************/ -uint16_t +static uint16_t ixgb_read_phy_reg(struct ixgb_hw *hw, uint32_t reg_address, uint32_t phy_address, @@ -815,7 +828,7 @@ ixgb_read_phy_reg(struct ixgb_hw *hw, * This requires that first an address cycle command is sent, followed by a * write command. *****************************************************************************/ -void +static void ixgb_write_phy_reg(struct ixgb_hw *hw, uint32_t reg_address, uint32_t phy_address, @@ -959,7 +972,7 @@ boolean_t ixgb_check_for_bad_link(struct ixgb_hw *hw) * * hw - Struct containing variables accessed by shared code *****************************************************************************/ -void +static void ixgb_clear_hw_cntrs(struct ixgb_hw *hw) { volatile uint32_t temp_reg; @@ -1114,7 +1127,7 @@ ixgb_get_bus_info(struct ixgb_hw *hw) * mac_addr - pointer to MAC address. * *****************************************************************************/ -boolean_t +static boolean_t mac_addr_valid(uint8_t *mac_addr) { boolean_t is_valid = TRUE; diff --git a/drivers/net/ixgb/ixgb_hw.h b/drivers/net/ixgb/ixgb_hw.h index 8bcf31ed10c221ad5609f57f6fecc155d5fbc81a..382c6300ccc23901bb073f4de7591f4354c5dfc7 100644 --- a/drivers/net/ixgb/ixgb_hw.h +++ b/drivers/net/ixgb/ixgb_hw.h @@ -784,23 +784,8 @@ struct ixgb_hw_stats { extern boolean_t ixgb_adapter_stop(struct ixgb_hw *hw); extern boolean_t ixgb_init_hw(struct ixgb_hw *hw); extern boolean_t ixgb_adapter_start(struct ixgb_hw *hw); -extern void ixgb_init_rx_addrs(struct ixgb_hw *hw); extern void ixgb_check_for_link(struct ixgb_hw *hw); extern boolean_t ixgb_check_for_bad_link(struct ixgb_hw *hw); -extern boolean_t ixgb_setup_fc(struct ixgb_hw *hw); -extern void ixgb_clear_hw_cntrs(struct ixgb_hw *hw); -extern boolean_t mac_addr_valid(uint8_t *mac_addr); - -extern uint16_t ixgb_read_phy_reg(struct ixgb_hw *hw, - uint32_t reg_addr, - uint32_t phy_addr, - uint32_t device_type); - -extern void ixgb_write_phy_reg(struct ixgb_hw *hw, - uint32_t reg_addr, - uint32_t phy_addr, - uint32_t device_type, - uint16_t data); extern void ixgb_rar_set(struct ixgb_hw *hw, uint8_t *addr, @@ -818,8 +803,6 @@ extern void ixgb_write_vfta(struct ixgb_hw *hw, uint32_t offset, uint32_t value); -extern void ixgb_clear_vfta(struct ixgb_hw *hw); - /* Access functions to eeprom data */ void ixgb_get_ee_mac_addr(struct ixgb_hw *hw, uint8_t *mac_addr); uint32_t ixgb_get_ee_pba_number(struct ixgb_hw *hw); diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 176680cb153e8b114797f4e6a8bad2f1837c678c..f9f77e4f59650d8ae8ba2a34d1c842b3ade11760 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -45,7 +45,7 @@ */ char ixgb_driver_name[] = "ixgb"; -char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver"; +static char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver"; #ifndef CONFIG_IXGB_NAPI #define DRIVERNAPI diff --git a/drivers/net/phy/cicada.c b/drivers/net/phy/cicada.c index c47fb2ecd1470513fd265a90202d6e924451f13b..7d8d534255c07f3a53955361b1a1791848362ee3 100644 --- a/drivers/net/phy/cicada.c +++ b/drivers/net/phy/cicada.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c index 6caf499fae32e42d6e5cf88afae4f32f7d746196..5e9002e444c52ddc35838e717091388da7d433eb 100644 --- a/drivers/net/phy/davicom.c +++ b/drivers/net/phy/davicom.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c index 4c840448ec8686918728023999bfcf669169de21..bef79e454c337c0c3d9bf5b1f365be56470b94a9 100644 --- a/drivers/net/phy/lxt.c +++ b/drivers/net/phy/lxt.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 4a72b025006b0c56d0f5e7ee3fec3c2d96f4cef6..a2d6386d13bcb187e2473ebeb9856108d7fb704d 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 5eab9c42a111228e827fae0a2d37fbae4f0c1a2e..02940c0fef680af5d913e7aac2af9d86337c42a2 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 9209da9dde0da9738d662e7a8167ae2136f2d831..b8686e47f8996470c780305e15905e434649dda2 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 6da1aa0706a1441ba227829ec529bd98089cf0a9..16bebe7a7ce1fdf43c45334b826bb919d7cb9444 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/phy/qsemi.c b/drivers/net/phy/qsemi.c index d461ba457631eff23113691484fcfcc3db2f8766..65d995b02b25249d1fcdc18f6e3dd3c636c27266 100644 --- a/drivers/net/phy/qsemi.c +++ b/drivers/net/phy/qsemi.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c index 59e8183c639e0be7e9a07dc9c8295d5bd78281e6..400f652282d76f4fe7c0d003ca0ec1f22d3da27f 100644 --- a/drivers/net/ppp_async.c +++ b/drivers/net/ppp_async.c @@ -31,6 +31,7 @@ #include #include #include +#include #define PPP_VERSION "2.4.2" @@ -835,8 +836,11 @@ process_input_packet(struct asyncppp *ap) err: /* frame had an error, remember that, reset SC_TOSS & SC_ESCAPE */ ap->state = SC_PREV_ERROR; - if (skb) + if (skb) { + /* make skb appear as freshly allocated */ skb_trim(skb, 0); + skb_reserve(skb, - skb_headroom(skb)); + } } /* Called when the tty driver has data for us. Runs parallel with the @@ -889,10 +893,17 @@ ppp_async_input(struct asyncppp *ap, const unsigned char *buf, skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2); if (skb == 0) goto nomem; - /* Try to get the payload 4-byte aligned */ + ap->rpkt = skb; + } + if (skb->len == 0) { + /* Try to get the payload 4-byte aligned. + * This should match the + * PPP_ALLSTATIONS/PPP_UI/compressed tests in + * process_input_packet, but we do not have + * enough chars here to test buf[1] and buf[2]. + */ if (buf[0] != PPP_ALLSTATIONS) skb_reserve(skb, 2 + (buf[0] & 1)); - ap->rpkt = skb; } if (n > skb_tailroom(skb)) { /* packet overflowed MRU */ diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index d3c9958b00d06db4895a7d6e2b54a58726c2e088..50430f79f8cf8190541e47495d625cae0cd7a765 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -137,13 +137,14 @@ struct ppp { /* * Bits in flags: SC_NO_TCP_CCID, SC_CCP_OPEN, SC_CCP_UP, SC_LOOP_TRAFFIC, - * SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ, SC_COMP_TCP, SC_REJ_COMP_TCP. + * SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ, SC_COMP_TCP, SC_REJ_COMP_TCP, + * SC_MUST_COMP * Bits in rstate: SC_DECOMP_RUN, SC_DC_ERROR, SC_DC_FERROR. * Bits in xstate: SC_COMP_RUN */ #define SC_FLAG_BITS (SC_NO_TCP_CCID|SC_CCP_OPEN|SC_CCP_UP|SC_LOOP_TRAFFIC \ |SC_MULTILINK|SC_MP_SHORTSEQ|SC_MP_XSHORTSEQ \ - |SC_COMP_TCP|SC_REJ_COMP_TCP) + |SC_COMP_TCP|SC_REJ_COMP_TCP|SC_MUST_COMP) /* * Private data structure for each channel. @@ -1027,6 +1028,56 @@ ppp_xmit_process(struct ppp *ppp) ppp_xmit_unlock(ppp); } +static inline struct sk_buff * +pad_compress_skb(struct ppp *ppp, struct sk_buff *skb) +{ + struct sk_buff *new_skb; + int len; + int new_skb_size = ppp->dev->mtu + + ppp->xcomp->comp_extra + ppp->dev->hard_header_len; + int compressor_skb_size = ppp->dev->mtu + + ppp->xcomp->comp_extra + PPP_HDRLEN; + new_skb = alloc_skb(new_skb_size, GFP_ATOMIC); + if (!new_skb) { + if (net_ratelimit()) + printk(KERN_ERR "PPP: no memory (comp pkt)\n"); + return NULL; + } + if (ppp->dev->hard_header_len > PPP_HDRLEN) + skb_reserve(new_skb, + ppp->dev->hard_header_len - PPP_HDRLEN); + + /* compressor still expects A/C bytes in hdr */ + len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2, + new_skb->data, skb->len + 2, + compressor_skb_size); + if (len > 0 && (ppp->flags & SC_CCP_UP)) { + kfree_skb(skb); + skb = new_skb; + skb_put(skb, len); + skb_pull(skb, 2); /* pull off A/C bytes */ + } else if (len == 0) { + /* didn't compress, or CCP not up yet */ + kfree_skb(new_skb); + new_skb = skb; + } else { + /* + * (len < 0) + * MPPE requires that we do not send unencrypted + * frames. The compressor will return -1 if we + * should drop the frame. We cannot simply test + * the compress_proto because MPPE and MPPC share + * the same number. + */ + if (net_ratelimit()) + printk(KERN_ERR "ppp: compressor dropped pkt\n"); + kfree_skb(skb); + kfree_skb(new_skb); + new_skb = NULL; + } + return new_skb; +} + /* * Compress and send a frame. * The caller should have locked the xmit path, @@ -1113,29 +1164,14 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) /* try to do packet compression */ if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state != 0 && proto != PPP_LCP && proto != PPP_CCP) { - new_skb = alloc_skb(ppp->dev->mtu + ppp->dev->hard_header_len, - GFP_ATOMIC); - if (new_skb == 0) { - printk(KERN_ERR "PPP: no memory (comp pkt)\n"); + if (!(ppp->flags & SC_CCP_UP) && (ppp->flags & SC_MUST_COMP)) { + if (net_ratelimit()) + printk(KERN_ERR "ppp: compression required but down - pkt dropped.\n"); goto drop; } - if (ppp->dev->hard_header_len > PPP_HDRLEN) - skb_reserve(new_skb, - ppp->dev->hard_header_len - PPP_HDRLEN); - - /* compressor still expects A/C bytes in hdr */ - len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2, - new_skb->data, skb->len + 2, - ppp->dev->mtu + PPP_HDRLEN); - if (len > 0 && (ppp->flags & SC_CCP_UP)) { - kfree_skb(skb); - skb = new_skb; - skb_put(skb, len); - skb_pull(skb, 2); /* pull off A/C bytes */ - } else { - /* didn't compress, or CCP not up yet */ - kfree_skb(new_skb); - } + skb = pad_compress_skb(ppp, skb); + if (!skb) + goto drop; } /* @@ -1155,7 +1191,8 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) return; drop: - kfree_skb(skb); + if (skb) + kfree_skb(skb); ++ppp->stats.tx_errors; } @@ -1552,6 +1589,9 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) && (ppp->rstate & (SC_DC_FERROR | SC_DC_ERROR)) == 0) skb = ppp_decompress_frame(ppp, skb); + if (ppp->flags & SC_MUST_COMP && ppp->rstate & SC_DC_FERROR) + goto err; + proto = PPP_PROTO(skb); switch (proto) { case PPP_VJC_COMP: diff --git a/drivers/net/ppp_mppe.c b/drivers/net/ppp_mppe.c new file mode 100644 index 0000000000000000000000000000000000000000..1985d1b57c45360b8a889430792c6934a0120e51 --- /dev/null +++ b/drivers/net/ppp_mppe.c @@ -0,0 +1,724 @@ +/* + * ppp_mppe.c - interface MPPE to the PPP code. + * This version is for use with Linux kernel 2.6.14+ + * + * By Frank Cusack . + * Copyright (c) 2002,2003,2004 Google, Inc. + * All rights reserved. + * + * License: + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies. This software is provided without any + * warranty, express or implied. + * + * ALTERNATIVELY, provided that this notice is retained in full, this product + * may be distributed under the terms of the GNU General Public License (GPL), + * in which case the provisions of the GPL apply INSTEAD OF those given above. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * Changelog: + * 08/12/05 - Matt Domsch + * Only need extra skb padding on transmit, not receive. + * 06/18/04 - Matt Domsch , Oleg Makarenko + * Use Linux kernel 2.6 arc4 and sha1 routines rather than + * providing our own. + * 2/15/04 - TS: added #include and testing for Kernel + * version before using + * MOD_DEC_USAGE_COUNT/MOD_INC_USAGE_COUNT which are + * deprecated in 2.6 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ppp_mppe.h" + +MODULE_AUTHOR("Frank Cusack "); +MODULE_DESCRIPTION("Point-to-Point Protocol Microsoft Point-to-Point Encryption support"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_ALIAS("ppp-compress-" __stringify(CI_MPPE)); +MODULE_VERSION("1.0.2"); + +static void +setup_sg(struct scatterlist *sg, const void *address, unsigned int length) +{ + sg[0].page = virt_to_page(address); + sg[0].offset = offset_in_page(address); + sg[0].length = length; +} + +#define SHA1_PAD_SIZE 40 + +/* + * kernel crypto API needs its arguments to be in kmalloc'd memory, not in the module + * static data area. That means sha_pad needs to be kmalloc'd. + */ + +struct sha_pad { + unsigned char sha_pad1[SHA1_PAD_SIZE]; + unsigned char sha_pad2[SHA1_PAD_SIZE]; +}; +static struct sha_pad *sha_pad; + +static inline void sha_pad_init(struct sha_pad *shapad) +{ + memset(shapad->sha_pad1, 0x00, sizeof(shapad->sha_pad1)); + memset(shapad->sha_pad2, 0xF2, sizeof(shapad->sha_pad2)); +} + +/* + * State for an MPPE (de)compressor. + */ +struct ppp_mppe_state { + struct crypto_tfm *arc4; + struct crypto_tfm *sha1; + unsigned char *sha1_digest; + unsigned char master_key[MPPE_MAX_KEY_LEN]; + unsigned char session_key[MPPE_MAX_KEY_LEN]; + unsigned keylen; /* key length in bytes */ + /* NB: 128-bit == 16, 40-bit == 8! */ + /* If we want to support 56-bit, */ + /* the unit has to change to bits */ + unsigned char bits; /* MPPE control bits */ + unsigned ccount; /* 12-bit coherency count (seqno) */ + unsigned stateful; /* stateful mode flag */ + int discard; /* stateful mode packet loss flag */ + int sanity_errors; /* take down LCP if too many */ + int unit; + int debug; + struct compstat stats; +}; + +/* struct ppp_mppe_state.bits definitions */ +#define MPPE_BIT_A 0x80 /* Encryption table were (re)inititalized */ +#define MPPE_BIT_B 0x40 /* MPPC only (not implemented) */ +#define MPPE_BIT_C 0x20 /* MPPC only (not implemented) */ +#define MPPE_BIT_D 0x10 /* This is an encrypted frame */ + +#define MPPE_BIT_FLUSHED MPPE_BIT_A +#define MPPE_BIT_ENCRYPTED MPPE_BIT_D + +#define MPPE_BITS(p) ((p)[4] & 0xf0) +#define MPPE_CCOUNT(p) ((((p)[4] & 0x0f) << 8) + (p)[5]) +#define MPPE_CCOUNT_SPACE 0x1000 /* The size of the ccount space */ + +#define MPPE_OVHD 2 /* MPPE overhead/packet */ +#define SANITY_MAX 1600 /* Max bogon factor we will tolerate */ + +/* + * Key Derivation, from RFC 3078, RFC 3079. + * Equivalent to Get_Key() for MS-CHAP as described in RFC 3079. + */ +static void get_new_key_from_sha(struct ppp_mppe_state * state, unsigned char *InterimKey) +{ + struct scatterlist sg[4]; + + setup_sg(&sg[0], state->master_key, state->keylen); + setup_sg(&sg[1], sha_pad->sha_pad1, sizeof(sha_pad->sha_pad1)); + setup_sg(&sg[2], state->session_key, state->keylen); + setup_sg(&sg[3], sha_pad->sha_pad2, sizeof(sha_pad->sha_pad2)); + + crypto_digest_digest (state->sha1, sg, 4, state->sha1_digest); + + memcpy(InterimKey, state->sha1_digest, state->keylen); +} + +/* + * Perform the MPPE rekey algorithm, from RFC 3078, sec. 7.3. + * Well, not what's written there, but rather what they meant. + */ +static void mppe_rekey(struct ppp_mppe_state * state, int initial_key) +{ + unsigned char InterimKey[MPPE_MAX_KEY_LEN]; + struct scatterlist sg_in[1], sg_out[1]; + + get_new_key_from_sha(state, InterimKey); + if (!initial_key) { + crypto_cipher_setkey(state->arc4, InterimKey, state->keylen); + setup_sg(sg_in, InterimKey, state->keylen); + setup_sg(sg_out, state->session_key, state->keylen); + if (crypto_cipher_encrypt(state->arc4, sg_out, sg_in, + state->keylen) != 0) { + printk(KERN_WARNING "mppe_rekey: cipher_encrypt failed\n"); + } + } else { + memcpy(state->session_key, InterimKey, state->keylen); + } + if (state->keylen == 8) { + /* See RFC 3078 */ + state->session_key[0] = 0xd1; + state->session_key[1] = 0x26; + state->session_key[2] = 0x9e; + } + crypto_cipher_setkey(state->arc4, state->session_key, state->keylen); +} + +/* + * Allocate space for a (de)compressor. + */ +static void *mppe_alloc(unsigned char *options, int optlen) +{ + struct ppp_mppe_state *state; + unsigned int digestsize; + + if (optlen != CILEN_MPPE + sizeof(state->master_key) + || options[0] != CI_MPPE || options[1] != CILEN_MPPE) + goto out; + + state = (struct ppp_mppe_state *) kmalloc(sizeof(*state), GFP_KERNEL); + if (state == NULL) + goto out; + + memset(state, 0, sizeof(*state)); + + state->arc4 = crypto_alloc_tfm("arc4", 0); + if (!state->arc4) + goto out_free; + + state->sha1 = crypto_alloc_tfm("sha1", 0); + if (!state->sha1) + goto out_free; + + digestsize = crypto_tfm_alg_digestsize(state->sha1); + if (digestsize < MPPE_MAX_KEY_LEN) + goto out_free; + + state->sha1_digest = kmalloc(digestsize, GFP_KERNEL); + if (!state->sha1_digest) + goto out_free; + + /* Save keys. */ + memcpy(state->master_key, &options[CILEN_MPPE], + sizeof(state->master_key)); + memcpy(state->session_key, state->master_key, + sizeof(state->master_key)); + + /* + * We defer initial key generation until mppe_init(), as mppe_alloc() + * is called frequently during negotiation. + */ + + return (void *)state; + + out_free: + if (state->sha1_digest) + kfree(state->sha1_digest); + if (state->sha1) + crypto_free_tfm(state->sha1); + if (state->arc4) + crypto_free_tfm(state->arc4); + kfree(state); + out: + return NULL; +} + +/* + * Deallocate space for a (de)compressor. + */ +static void mppe_free(void *arg) +{ + struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; + if (state) { + if (state->sha1_digest) + kfree(state->sha1_digest); + if (state->sha1) + crypto_free_tfm(state->sha1); + if (state->arc4) + crypto_free_tfm(state->arc4); + kfree(state); + } +} + +/* + * Initialize (de)compressor state. + */ +static int +mppe_init(void *arg, unsigned char *options, int optlen, int unit, int debug, + const char *debugstr) +{ + struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; + unsigned char mppe_opts; + + if (optlen != CILEN_MPPE + || options[0] != CI_MPPE || options[1] != CILEN_MPPE) + return 0; + + MPPE_CI_TO_OPTS(&options[2], mppe_opts); + if (mppe_opts & MPPE_OPT_128) + state->keylen = 16; + else if (mppe_opts & MPPE_OPT_40) + state->keylen = 8; + else { + printk(KERN_WARNING "%s[%d]: unknown key length\n", debugstr, + unit); + return 0; + } + if (mppe_opts & MPPE_OPT_STATEFUL) + state->stateful = 1; + + /* Generate the initial session key. */ + mppe_rekey(state, 1); + + if (debug) { + int i; + char mkey[sizeof(state->master_key) * 2 + 1]; + char skey[sizeof(state->session_key) * 2 + 1]; + + printk(KERN_DEBUG "%s[%d]: initialized with %d-bit %s mode\n", + debugstr, unit, (state->keylen == 16) ? 128 : 40, + (state->stateful) ? "stateful" : "stateless"); + + for (i = 0; i < sizeof(state->master_key); i++) + sprintf(mkey + i * 2, "%02x", state->master_key[i]); + for (i = 0; i < sizeof(state->session_key); i++) + sprintf(skey + i * 2, "%02x", state->session_key[i]); + printk(KERN_DEBUG + "%s[%d]: keys: master: %s initial session: %s\n", + debugstr, unit, mkey, skey); + } + + /* + * Initialize the coherency count. The initial value is not specified + * in RFC 3078, but we can make a reasonable assumption that it will + * start at 0. Setting it to the max here makes the comp/decomp code + * do the right thing (determined through experiment). + */ + state->ccount = MPPE_CCOUNT_SPACE - 1; + + /* + * Note that even though we have initialized the key table, we don't + * set the FLUSHED bit. This is contrary to RFC 3078, sec. 3.1. + */ + state->bits = MPPE_BIT_ENCRYPTED; + + state->unit = unit; + state->debug = debug; + + return 1; +} + +static int +mppe_comp_init(void *arg, unsigned char *options, int optlen, int unit, + int hdrlen, int debug) +{ + /* ARGSUSED */ + return mppe_init(arg, options, optlen, unit, debug, "mppe_comp_init"); +} + +/* + * We received a CCP Reset-Request (actually, we are sending a Reset-Ack), + * tell the compressor to rekey. Note that we MUST NOT rekey for + * every CCP Reset-Request; we only rekey on the next xmit packet. + * We might get multiple CCP Reset-Requests if our CCP Reset-Ack is lost. + * So, rekeying for every CCP Reset-Request is broken as the peer will not + * know how many times we've rekeyed. (If we rekey and THEN get another + * CCP Reset-Request, we must rekey again.) + */ +static void mppe_comp_reset(void *arg) +{ + struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; + + state->bits |= MPPE_BIT_FLUSHED; +} + +/* + * Compress (encrypt) a packet. + * It's strange to call this a compressor, since the output is always + * MPPE_OVHD + 2 bytes larger than the input. + */ +static int +mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf, + int isize, int osize) +{ + struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; + int proto; + struct scatterlist sg_in[1], sg_out[1]; + + /* + * Check that the protocol is in the range we handle. + */ + proto = PPP_PROTOCOL(ibuf); + if (proto < 0x0021 || proto > 0x00fa) + return 0; + + /* Make sure we have enough room to generate an encrypted packet. */ + if (osize < isize + MPPE_OVHD + 2) { + /* Drop the packet if we should encrypt it, but can't. */ + printk(KERN_DEBUG "mppe_compress[%d]: osize too small! " + "(have: %d need: %d)\n", state->unit, + osize, osize + MPPE_OVHD + 2); + return -1; + } + + osize = isize + MPPE_OVHD + 2; + + /* + * Copy over the PPP header and set control bits. + */ + obuf[0] = PPP_ADDRESS(ibuf); + obuf[1] = PPP_CONTROL(ibuf); + obuf[2] = PPP_COMP >> 8; /* isize + MPPE_OVHD + 1 */ + obuf[3] = PPP_COMP; /* isize + MPPE_OVHD + 2 */ + obuf += PPP_HDRLEN; + + state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; + if (state->debug >= 7) + printk(KERN_DEBUG "mppe_compress[%d]: ccount %d\n", state->unit, + state->ccount); + obuf[0] = state->ccount >> 8; + obuf[1] = state->ccount & 0xff; + + if (!state->stateful || /* stateless mode */ + ((state->ccount & 0xff) == 0xff) || /* "flag" packet */ + (state->bits & MPPE_BIT_FLUSHED)) { /* CCP Reset-Request */ + /* We must rekey */ + if (state->debug && state->stateful) + printk(KERN_DEBUG "mppe_compress[%d]: rekeying\n", + state->unit); + mppe_rekey(state, 0); + state->bits |= MPPE_BIT_FLUSHED; + } + obuf[0] |= state->bits; + state->bits &= ~MPPE_BIT_FLUSHED; /* reset for next xmit */ + + obuf += MPPE_OVHD; + ibuf += 2; /* skip to proto field */ + isize -= 2; + + /* Encrypt packet */ + setup_sg(sg_in, ibuf, isize); + setup_sg(sg_out, obuf, osize); + if (crypto_cipher_encrypt(state->arc4, sg_out, sg_in, isize) != 0) { + printk(KERN_DEBUG "crypto_cypher_encrypt failed\n"); + return -1; + } + + state->stats.unc_bytes += isize; + state->stats.unc_packets++; + state->stats.comp_bytes += osize; + state->stats.comp_packets++; + + return osize; +} + +/* + * Since every frame grows by MPPE_OVHD + 2 bytes, this is always going + * to look bad ... and the longer the link is up the worse it will get. + */ +static void mppe_comp_stats(void *arg, struct compstat *stats) +{ + struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; + + *stats = state->stats; +} + +static int +mppe_decomp_init(void *arg, unsigned char *options, int optlen, int unit, + int hdrlen, int mru, int debug) +{ + /* ARGSUSED */ + return mppe_init(arg, options, optlen, unit, debug, "mppe_decomp_init"); +} + +/* + * We received a CCP Reset-Ack. Just ignore it. + */ +static void mppe_decomp_reset(void *arg) +{ + /* ARGSUSED */ + return; +} + +/* + * Decompress (decrypt) an MPPE packet. + */ +static int +mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf, + int osize) +{ + struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; + unsigned ccount; + int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED; + int sanity = 0; + struct scatterlist sg_in[1], sg_out[1]; + + if (isize <= PPP_HDRLEN + MPPE_OVHD) { + if (state->debug) + printk(KERN_DEBUG + "mppe_decompress[%d]: short pkt (%d)\n", + state->unit, isize); + return DECOMP_ERROR; + } + + /* + * Make sure we have enough room to decrypt the packet. + * Note that for our test we only subtract 1 byte whereas in + * mppe_compress() we added 2 bytes (+MPPE_OVHD); + * this is to account for possible PFC. + */ + if (osize < isize - MPPE_OVHD - 1) { + printk(KERN_DEBUG "mppe_decompress[%d]: osize too small! " + "(have: %d need: %d)\n", state->unit, + osize, isize - MPPE_OVHD - 1); + return DECOMP_ERROR; + } + osize = isize - MPPE_OVHD - 2; /* assume no PFC */ + + ccount = MPPE_CCOUNT(ibuf); + if (state->debug >= 7) + printk(KERN_DEBUG "mppe_decompress[%d]: ccount %d\n", + state->unit, ccount); + + /* sanity checks -- terminate with extreme prejudice */ + if (!(MPPE_BITS(ibuf) & MPPE_BIT_ENCRYPTED)) { + printk(KERN_DEBUG + "mppe_decompress[%d]: ENCRYPTED bit not set!\n", + state->unit); + state->sanity_errors += 100; + sanity = 1; + } + if (!state->stateful && !flushed) { + printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set in " + "stateless mode!\n", state->unit); + state->sanity_errors += 100; + sanity = 1; + } + if (state->stateful && ((ccount & 0xff) == 0xff) && !flushed) { + printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set on " + "flag packet!\n", state->unit); + state->sanity_errors += 100; + sanity = 1; + } + + if (sanity) { + if (state->sanity_errors < SANITY_MAX) + return DECOMP_ERROR; + else + /* + * Take LCP down if the peer is sending too many bogons. + * We don't want to do this for a single or just a few + * instances since it could just be due to packet corruption. + */ + return DECOMP_FATALERROR; + } + + /* + * Check the coherency count. + */ + + if (!state->stateful) { + /* RFC 3078, sec 8.1. Rekey for every packet. */ + while (state->ccount != ccount) { + mppe_rekey(state, 0); + state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; + } + } else { + /* RFC 3078, sec 8.2. */ + if (!state->discard) { + /* normal state */ + state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; + if (ccount != state->ccount) { + /* + * (ccount > state->ccount) + * Packet loss detected, enter the discard state. + * Signal the peer to rekey (by sending a CCP Reset-Request). + */ + state->discard = 1; + return DECOMP_ERROR; + } + } else { + /* discard state */ + if (!flushed) { + /* ccp.c will be silent (no additional CCP Reset-Requests). */ + return DECOMP_ERROR; + } else { + /* Rekey for every missed "flag" packet. */ + while ((ccount & ~0xff) != + (state->ccount & ~0xff)) { + mppe_rekey(state, 0); + state->ccount = + (state->ccount + + 256) % MPPE_CCOUNT_SPACE; + } + + /* reset */ + state->discard = 0; + state->ccount = ccount; + /* + * Another problem with RFC 3078 here. It implies that the + * peer need not send a Reset-Ack packet. But RFC 1962 + * requires it. Hopefully, M$ does send a Reset-Ack; even + * though it isn't required for MPPE synchronization, it is + * required to reset CCP state. + */ + } + } + if (flushed) + mppe_rekey(state, 0); + } + + /* + * Fill in the first part of the PPP header. The protocol field + * comes from the decrypted data. + */ + obuf[0] = PPP_ADDRESS(ibuf); /* +1 */ + obuf[1] = PPP_CONTROL(ibuf); /* +1 */ + obuf += 2; + ibuf += PPP_HDRLEN + MPPE_OVHD; + isize -= PPP_HDRLEN + MPPE_OVHD; /* -6 */ + /* net osize: isize-4 */ + + /* + * Decrypt the first byte in order to check if it is + * a compressed or uncompressed protocol field. + */ + setup_sg(sg_in, ibuf, 1); + setup_sg(sg_out, obuf, 1); + if (crypto_cipher_decrypt(state->arc4, sg_out, sg_in, 1) != 0) { + printk(KERN_DEBUG "crypto_cypher_decrypt failed\n"); + return DECOMP_ERROR; + } + + /* + * Do PFC decompression. + * This would be nicer if we were given the actual sk_buff + * instead of a char *. + */ + if ((obuf[0] & 0x01) != 0) { + obuf[1] = obuf[0]; + obuf[0] = 0; + obuf++; + osize++; + } + + /* And finally, decrypt the rest of the packet. */ + setup_sg(sg_in, ibuf + 1, isize - 1); + setup_sg(sg_out, obuf + 1, osize - 1); + if (crypto_cipher_decrypt(state->arc4, sg_out, sg_in, isize - 1) != 0) { + printk(KERN_DEBUG "crypto_cypher_decrypt failed\n"); + return DECOMP_ERROR; + } + + state->stats.unc_bytes += osize; + state->stats.unc_packets++; + state->stats.comp_bytes += isize; + state->stats.comp_packets++; + + /* good packet credit */ + state->sanity_errors >>= 1; + + return osize; +} + +/* + * Incompressible data has arrived (this should never happen!). + * We should probably drop the link if the protocol is in the range + * of what should be encrypted. At the least, we should drop this + * packet. (How to do this?) + */ +static void mppe_incomp(void *arg, unsigned char *ibuf, int icnt) +{ + struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; + + if (state->debug && + (PPP_PROTOCOL(ibuf) >= 0x0021 && PPP_PROTOCOL(ibuf) <= 0x00fa)) + printk(KERN_DEBUG + "mppe_incomp[%d]: incompressible (unencrypted) data! " + "(proto %04x)\n", state->unit, PPP_PROTOCOL(ibuf)); + + state->stats.inc_bytes += icnt; + state->stats.inc_packets++; + state->stats.unc_bytes += icnt; + state->stats.unc_packets++; +} + +/************************************************************* + * Module interface table + *************************************************************/ + +/* + * Procedures exported to if_ppp.c. + */ +static struct compressor ppp_mppe = { + .compress_proto = CI_MPPE, + .comp_alloc = mppe_alloc, + .comp_free = mppe_free, + .comp_init = mppe_comp_init, + .comp_reset = mppe_comp_reset, + .compress = mppe_compress, + .comp_stat = mppe_comp_stats, + .decomp_alloc = mppe_alloc, + .decomp_free = mppe_free, + .decomp_init = mppe_decomp_init, + .decomp_reset = mppe_decomp_reset, + .decompress = mppe_decompress, + .incomp = mppe_incomp, + .decomp_stat = mppe_comp_stats, + .owner = THIS_MODULE, + .comp_extra = MPPE_PAD, +}; + +/* + * ppp_mppe_init() + * + * Prior to allowing load, try to load the arc4 and sha1 crypto + * libraries. The actual use will be allocated later, but + * this way the module will fail to insmod if they aren't available. + */ + +static int __init ppp_mppe_init(void) +{ + int answer; + if (!(crypto_alg_available("arc4", 0) && + crypto_alg_available("sha1", 0))) + return -ENODEV; + + sha_pad = kmalloc(sizeof(struct sha_pad), GFP_KERNEL); + if (!sha_pad) + return -ENOMEM; + sha_pad_init(sha_pad); + + answer = ppp_register_compressor(&ppp_mppe); + + if (answer == 0) + printk(KERN_INFO "PPP MPPE Compression module registered\n"); + else + kfree(sha_pad); + + return answer; +} + +static void __exit ppp_mppe_cleanup(void) +{ + ppp_unregister_compressor(&ppp_mppe); + kfree(sha_pad); +} + +module_init(ppp_mppe_init); +module_exit(ppp_mppe_cleanup); diff --git a/drivers/net/ppp_mppe.h b/drivers/net/ppp_mppe.h new file mode 100644 index 0000000000000000000000000000000000000000..7a14e058c6684487425a80774a69df056c39a5aa --- /dev/null +++ b/drivers/net/ppp_mppe.h @@ -0,0 +1,86 @@ +#define MPPE_PAD 4 /* MPPE growth per frame */ +#define MPPE_MAX_KEY_LEN 16 /* largest key length (128-bit) */ + +/* option bits for ccp_options.mppe */ +#define MPPE_OPT_40 0x01 /* 40 bit */ +#define MPPE_OPT_128 0x02 /* 128 bit */ +#define MPPE_OPT_STATEFUL 0x04 /* stateful mode */ +/* unsupported opts */ +#define MPPE_OPT_56 0x08 /* 56 bit */ +#define MPPE_OPT_MPPC 0x10 /* MPPC compression */ +#define MPPE_OPT_D 0x20 /* Unknown */ +#define MPPE_OPT_UNSUPPORTED (MPPE_OPT_56|MPPE_OPT_MPPC|MPPE_OPT_D) +#define MPPE_OPT_UNKNOWN 0x40 /* Bits !defined in RFC 3078 were set */ + +/* + * This is not nice ... the alternative is a bitfield struct though. + * And unfortunately, we cannot share the same bits for the option + * names above since C and H are the same bit. We could do a u_int32 + * but then we have to do a htonl() all the time and/or we still need + * to know which octet is which. + */ +#define MPPE_C_BIT 0x01 /* MPPC */ +#define MPPE_D_BIT 0x10 /* Obsolete, usage unknown */ +#define MPPE_L_BIT 0x20 /* 40-bit */ +#define MPPE_S_BIT 0x40 /* 128-bit */ +#define MPPE_M_BIT 0x80 /* 56-bit, not supported */ +#define MPPE_H_BIT 0x01 /* Stateless (in a different byte) */ + +/* Does not include H bit; used for least significant octet only. */ +#define MPPE_ALL_BITS (MPPE_D_BIT|MPPE_L_BIT|MPPE_S_BIT|MPPE_M_BIT|MPPE_H_BIT) + +/* Build a CI from mppe opts (see RFC 3078) */ +#define MPPE_OPTS_TO_CI(opts, ci) \ + do { \ + u_char *ptr = ci; /* u_char[4] */ \ + \ + /* H bit */ \ + if (opts & MPPE_OPT_STATEFUL) \ + *ptr++ = 0x0; \ + else \ + *ptr++ = MPPE_H_BIT; \ + *ptr++ = 0; \ + *ptr++ = 0; \ + \ + /* S,L bits */ \ + *ptr = 0; \ + if (opts & MPPE_OPT_128) \ + *ptr |= MPPE_S_BIT; \ + if (opts & MPPE_OPT_40) \ + *ptr |= MPPE_L_BIT; \ + /* M,D,C bits not supported */ \ + } while (/* CONSTCOND */ 0) + +/* The reverse of the above */ +#define MPPE_CI_TO_OPTS(ci, opts) \ + do { \ + u_char *ptr = ci; /* u_char[4] */ \ + \ + opts = 0; \ + \ + /* H bit */ \ + if (!(ptr[0] & MPPE_H_BIT)) \ + opts |= MPPE_OPT_STATEFUL; \ + \ + /* S,L bits */ \ + if (ptr[3] & MPPE_S_BIT) \ + opts |= MPPE_OPT_128; \ + if (ptr[3] & MPPE_L_BIT) \ + opts |= MPPE_OPT_40; \ + \ + /* M,D,C bits */ \ + if (ptr[3] & MPPE_M_BIT) \ + opts |= MPPE_OPT_56; \ + if (ptr[3] & MPPE_D_BIT) \ + opts |= MPPE_OPT_D; \ + if (ptr[3] & MPPE_C_BIT) \ + opts |= MPPE_OPT_MPPC; \ + \ + /* Other bits */ \ + if (ptr[0] & ~MPPE_H_BIT) \ + opts |= MPPE_OPT_UNKNOWN; \ + if (ptr[1] || ptr[2]) \ + opts |= MPPE_OPT_UNKNOWN; \ + if (ptr[3] & ~MPPE_ALL_BITS) \ + opts |= MPPE_OPT_UNKNOWN; \ + } while (/* CONSTCOND */ 0) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 9c4935407f268c298946073361cb5bad09cab5c9..0745dd9d01f396415b0b3613341bd3953c207a60 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -2110,7 +2110,7 @@ int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb) { struct net_device *dev = nic->dev; struct sk_buff *frag_list; - u64 tmp; + void *tmp; /* Buffer-1 receives L3/L4 headers */ ((RxD3_t*)rxdp)->Buffer1_ptr = pci_map_single @@ -2125,11 +2125,9 @@ int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb) } frag_list = skb_shinfo(skb)->frag_list; frag_list->next = NULL; - tmp = (u64) frag_list->data; - tmp += ALIGN_SIZE; - tmp &= ~ALIGN_SIZE; - frag_list->data = (void *) tmp; - frag_list->tail = (void *) tmp; + tmp = (void *)ALIGN((long)frag_list->data, ALIGN_SIZE + 1); + frag_list->data = tmp; + frag_list->tail = tmp; /* Buffer-2 receives L4 data payload */ ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev, diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 849ac88bcccc217bb4aa83aa41be050a23968f7f..6afc6e5dee9b74190e59d50697a76c9cb2364ceb 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -47,6 +47,8 @@ #include #include +#include "airo.h" + #ifdef CONFIG_PCI static struct pci_device_id card_ids[] = { { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, }, diff --git a/drivers/net/wireless/airo.h b/drivers/net/wireless/airo.h new file mode 100644 index 0000000000000000000000000000000000000000..e480adf86be6525a6caac9236ad99fd672dee60e --- /dev/null +++ b/drivers/net/wireless/airo.h @@ -0,0 +1,9 @@ +#ifndef _AIRO_H_ +#define _AIRO_H_ + +struct net_device *init_airo_card(unsigned short irq, int port, int is_pcmcia, + struct device *dmdev); +int reset_airo_card(struct net_device *dev); +void stop_airo_card(struct net_device *dev, int freeres); + +#endif /* _AIRO_H_ */ diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index 784de9109113bac53a86d879bb28e245451bc755..96ed8da8661d2aba1afe78e531812c32d2908b83 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -42,6 +42,8 @@ #include #include +#include "airo.h" + /* All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If you do not define PCMCIA_DEBUG at all, all the debug code will be @@ -78,10 +80,6 @@ MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340 PCMCIA cards"); event handler. */ -struct net_device *init_airo_card( int, int, int, struct device * ); -void stop_airo_card( struct net_device *, int ); -int reset_airo_card( struct net_device * ); - static void airo_config(dev_link_t *link); static void airo_release(dev_link_t *link); static int airo_event(event_t event, int priority, diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c index 3b49efa37ee56050f3294304ad0ce0c8dd539d59..fc1eb35648329a5848f4076b5730b8ae48321c7e 100644 --- a/drivers/net/wireless/prism54/islpci_eth.c +++ b/drivers/net/wireless/prism54/islpci_eth.c @@ -244,7 +244,6 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) priv->statistics.tx_dropped++; spin_unlock_irqrestore(&priv->slock, flags); dev_kfree_skb(skb); - skb = NULL; return err; } diff --git a/drivers/parport/probe.c b/drivers/parport/probe.c index 6e6f42d01e64847cc626ca974e01f58f15d755f5..4b48b31ec235ae16457ccc0b31678f502db8d493 100644 --- a/drivers/parport/probe.c +++ b/drivers/parport/probe.c @@ -78,17 +78,15 @@ static void parse_data(struct parport *port, int device, char *str) u++; } if (!strcmp(p, "MFG") || !strcmp(p, "MANUFACTURER")) { - if (info->mfr) - kfree (info->mfr); + kfree(info->mfr); info->mfr = kstrdup(sep, GFP_KERNEL); } else if (!strcmp(p, "MDL") || !strcmp(p, "MODEL")) { - if (info->model) - kfree (info->model); + kfree(info->model); info->model = kstrdup(sep, GFP_KERNEL); } else if (!strcmp(p, "CLS") || !strcmp(p, "CLASS")) { int i; - if (info->class_name) - kfree (info->class_name); + + kfree(info->class_name); info->class_name = kstrdup(sep, GFP_KERNEL); for (u = sep; *u; u++) *u = toupper(*u); @@ -102,21 +100,22 @@ static void parse_data(struct parport *port, int device, char *str) info->class = PARPORT_CLASS_OTHER; } else if (!strcmp(p, "CMD") || !strcmp(p, "COMMAND SET")) { - if (info->cmdset) - kfree (info->cmdset); + kfree(info->cmdset); info->cmdset = kstrdup(sep, GFP_KERNEL); /* if it speaks printer language, it's probably a printer */ if (strstr(sep, "PJL") || strstr(sep, "PCL")) guessed_class = PARPORT_CLASS_PRINTER; } else if (!strcmp(p, "DES") || !strcmp(p, "DESCRIPTION")) { - if (info->description) - kfree (info->description); + kfree(info->description); info->description = kstrdup(sep, GFP_KERNEL); } } rock_on: - if (q) p = q+1; else p=NULL; + if (q) + p = q + 1; + else + p = NULL; } /* If the device didn't tell us its class, maybe we have managed to diff --git a/drivers/parport/share.c b/drivers/parport/share.c index ae7becf7efa5a5b45fef251003c230ce945530ad..9cb3ab156b09c40d82477b23f2de41a15e5d3f42 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -202,16 +202,11 @@ static void free_port (struct parport *port) list_del(&port->full_list); spin_unlock(&full_list_lock); for (d = 0; d < 5; d++) { - if (port->probe_info[d].class_name) - kfree (port->probe_info[d].class_name); - if (port->probe_info[d].mfr) - kfree (port->probe_info[d].mfr); - if (port->probe_info[d].model) - kfree (port->probe_info[d].model); - if (port->probe_info[d].cmdset) - kfree (port->probe_info[d].cmdset); - if (port->probe_info[d].description) - kfree (port->probe_info[d].description); + kfree(port->probe_info[d].class_name); + kfree(port->probe_info[d].mfr); + kfree(port->probe_info[d].model); + kfree(port->probe_info[d].cmdset); + kfree(port->probe_info[d].description); } kfree(port->name); @@ -618,9 +613,9 @@ parport_register_device(struct parport *port, const char *name, return tmp; out_free_all: - kfree (tmp->state); + kfree(tmp->state); out_free_pardevice: - kfree (tmp); + kfree(tmp); out: parport_put_port (port); module_put(port->ops->owner); diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c index 93e39c4096a927bf8b6737b298f875b1ebf2583a..00b81a7bdd266a9513a6c39506236bb52c1c3622 100644 --- a/drivers/pci/hotplug/cpqphp_pci.c +++ b/drivers/pci/hotplug/cpqphp_pci.c @@ -259,8 +259,7 @@ static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num sizeof(struct irq_routing_table)) / sizeof(struct irq_info); // Make sure I got at least one entry if (len == 0) { - if (PCIIRQRoutingInfoLength != NULL) - kfree(PCIIRQRoutingInfoLength ); + kfree(PCIIRQRoutingInfoLength ); return -1; } @@ -275,8 +274,7 @@ static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num ctrl->pci_bus->number = tbus; pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_VENDOR_ID, &work); if (!nobridge || (work == 0xffffffff)) { - if (PCIIRQRoutingInfoLength != NULL) - kfree(PCIIRQRoutingInfoLength ); + kfree(PCIIRQRoutingInfoLength ); return 0; } @@ -289,20 +287,17 @@ static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num dbg("Scan bus for Non Bridge: bus %d\n", tbus); if (PCI_ScanBusForNonBridge(ctrl, tbus, dev_num) == 0) { *bus_num = tbus; - if (PCIIRQRoutingInfoLength != NULL) - kfree(PCIIRQRoutingInfoLength ); + kfree(PCIIRQRoutingInfoLength ); return 0; } } else { - if (PCIIRQRoutingInfoLength != NULL) - kfree(PCIIRQRoutingInfoLength ); + kfree(PCIIRQRoutingInfoLength ); return 0; } } } - if (PCIIRQRoutingInfoLength != NULL) - kfree(PCIIRQRoutingInfoLength ); + kfree(PCIIRQRoutingInfoLength ); return -1; } diff --git a/drivers/pci/hotplug/pciehprm_nonacpi.c b/drivers/pci/hotplug/pciehprm_nonacpi.c index 33b2c69a08295b786553b5697f5481b99e4c509f..76c727c74cc014c456b4c57c713c7a47a414a136 100644 --- a/drivers/pci/hotplug/pciehprm_nonacpi.c +++ b/drivers/pci/hotplug/pciehprm_nonacpi.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index ae986e590b48213544dd6f322147909bf52efcec..94e68c54d27397bf06c56b32d7539c927b8dcf41 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "pci.h" /* diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 3afb682255a04d112dfa1a34f5bc4aac4d4e4b5f..2dc3e611a9a3473fbbb2a715db4de58d270a3f63 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -334,10 +334,8 @@ void destroy_cis_cache(struct pcmcia_socket *s) /* * If there was a fake CIS, destroy that as well. */ - if (s->fake_cis) { - kfree(s->fake_cis); - s->fake_cis = NULL; - } + kfree(s->fake_cis); + s->fake_cis = NULL; } EXPORT_SYMBOL(destroy_cis_cache); @@ -386,10 +384,8 @@ int verify_cis_cache(struct pcmcia_socket *s) int pcmcia_replace_cis(struct pcmcia_socket *s, cisdump_t *cis) { - if (s->fake_cis != NULL) { - kfree(s->fake_cis); - s->fake_cis = NULL; - } + kfree(s->fake_cis); + s->fake_cis = NULL; if (cis->Length > CISTPL_MAX_CIS_SIZE) return CS_BAD_SIZE; s->fake_cis = kmalloc(cis->Length, GFP_KERNEL); diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index d5e76423a0ee89b15a3888e0b411f688e49b05fb..234cdca6fe137e8967fbe43bf6c71557a84c434b 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -331,10 +331,8 @@ static void shutdown_socket(struct pcmcia_socket *s) cb_free(s); #endif s->functions = 0; - if (s->config) { - kfree(s->config); - s->config = NULL; - } + kfree(s->config); + s->config = NULL; { int status; diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c index fe5ea36e7de3878e63b7819cab7872c89d8acd49..56c58831e80e593eae62c2e33744fcd508ad7cd2 100644 --- a/drivers/pcmcia/pxa2xx_sharpsl.c +++ b/drivers/pcmcia/pxa2xx_sharpsl.c @@ -22,16 +22,20 @@ #include #include #include -#ifdef CONFIG_SA1100_COLLIE -#include -#else -#include -#endif #include "soc_common.h" #define NO_KEEP_VS 0x0001 +/* PCMCIA to Scoop linkage + + There is no easy way to link multiple scoop devices into one + single entity for the pxa2xx_pcmcia device so this structure + is used which is setup by the platform code +*/ +struct scoop_pcmcia_config *platform_scoop_config; +#define SCOOP_DEV platform_scoop_config->devs + static void sharpsl_pcmcia_init_reset(struct scoop_pcmcia_dev *scoopdev) { reset_scoop(scoopdev->dev); @@ -43,38 +47,16 @@ static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { int ret; -#ifndef CONFIG_SA1100_COLLIE - /* - * Setup default state of GPIO outputs - * before we enable them as outputs. - */ - GPSR(GPIO48_nPOE) = - GPIO_bit(GPIO48_nPOE) | - GPIO_bit(GPIO49_nPWE) | - GPIO_bit(GPIO50_nPIOR) | - GPIO_bit(GPIO51_nPIOW) | - GPIO_bit(GPIO52_nPCE_1) | - GPIO_bit(GPIO53_nPCE_2); - - pxa_gpio_mode(GPIO48_nPOE_MD); - pxa_gpio_mode(GPIO49_nPWE_MD); - pxa_gpio_mode(GPIO50_nPIOR_MD); - pxa_gpio_mode(GPIO51_nPIOW_MD); - pxa_gpio_mode(GPIO52_nPCE_1_MD); - pxa_gpio_mode(GPIO53_nPCE_2_MD); - pxa_gpio_mode(GPIO54_pSKTSEL_MD); - pxa_gpio_mode(GPIO55_nPREG_MD); - pxa_gpio_mode(GPIO56_nPWAIT_MD); - pxa_gpio_mode(GPIO57_nIOIS16_MD); -#endif + if (platform_scoop_config->pcmcia_init) + platform_scoop_config->pcmcia_init(); /* Register interrupts */ - if (scoop_devs[skt->nr].cd_irq >= 0) { + if (SCOOP_DEV[skt->nr].cd_irq >= 0) { struct pcmcia_irqs cd_irq; cd_irq.sock = skt->nr; - cd_irq.irq = scoop_devs[skt->nr].cd_irq; - cd_irq.str = scoop_devs[skt->nr].cd_irq_str; + cd_irq.irq = SCOOP_DEV[skt->nr].cd_irq; + cd_irq.str = SCOOP_DEV[skt->nr].cd_irq_str; ret = soc_pcmcia_request_irqs(skt, &cd_irq, 1); if (ret) { @@ -83,19 +65,19 @@ static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt) } } - skt->irq = scoop_devs[skt->nr].irq; + skt->irq = SCOOP_DEV[skt->nr].irq; return 0; } static void sharpsl_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) { - if (scoop_devs[skt->nr].cd_irq >= 0) { + if (SCOOP_DEV[skt->nr].cd_irq >= 0) { struct pcmcia_irqs cd_irq; cd_irq.sock = skt->nr; - cd_irq.irq = scoop_devs[skt->nr].cd_irq; - cd_irq.str = scoop_devs[skt->nr].cd_irq_str; + cd_irq.irq = SCOOP_DEV[skt->nr].cd_irq; + cd_irq.str = SCOOP_DEV[skt->nr].cd_irq_str; soc_pcmcia_free_irqs(skt, &cd_irq, 1); } } @@ -105,9 +87,9 @@ static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state) { unsigned short cpr, csr; - struct device *scoop = scoop_devs[skt->nr].dev; + struct device *scoop = SCOOP_DEV[skt->nr].dev; - cpr = read_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR); + cpr = read_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR); write_scoop_reg(scoop, SCOOP_IRM, 0x00FF); write_scoop_reg(scoop, SCOOP_ISR, 0x0000); @@ -116,21 +98,25 @@ static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt, if (csr & 0x0004) { /* card eject */ write_scoop_reg(scoop, SCOOP_CDR, 0x0000); - scoop_devs[skt->nr].keep_vs = NO_KEEP_VS; + SCOOP_DEV[skt->nr].keep_vs = NO_KEEP_VS; } - else if (!(scoop_devs[skt->nr].keep_vs & NO_KEEP_VS)) { + else if (!(SCOOP_DEV[skt->nr].keep_vs & NO_KEEP_VS)) { /* keep vs1,vs2 */ write_scoop_reg(scoop, SCOOP_CDR, 0x0000); - csr |= scoop_devs[skt->nr].keep_vs; + csr |= SCOOP_DEV[skt->nr].keep_vs; } else if (cpr & 0x0003) { /* power on */ write_scoop_reg(scoop, SCOOP_CDR, 0x0000); - scoop_devs[skt->nr].keep_vs = (csr & 0x00C0); + SCOOP_DEV[skt->nr].keep_vs = (csr & 0x00C0); } else { /* card detect */ - write_scoop_reg(scoop, SCOOP_CDR, 0x0002); + if ((machine_is_spitz() || machine_is_borzoi()) && skt->nr == 1) { + write_scoop_reg(scoop, SCOOP_CDR, 0x0000); + } else { + write_scoop_reg(scoop, SCOOP_CDR, 0x0002); + } } state->detect = (csr & 0x0004) ? 0 : 1; @@ -144,7 +130,6 @@ static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt, if ((cpr & 0x0080) && ((cpr & 0x8040) != 0x8040)) { printk(KERN_ERR "sharpsl_pcmcia_socket_state(): CPR=%04X, Low voltage!\n", cpr); } - } @@ -152,7 +137,7 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) { unsigned long flags; - struct device *scoop = scoop_devs[skt->nr].dev; + struct device *scoop = SCOOP_DEV[skt->nr].dev; unsigned short cpr, ncpr, ccr, nccr, mcr, nmcr, imr, nimr; @@ -177,8 +162,13 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, nccr = (ccr = read_scoop_reg(scoop, SCOOP_CCR)) & ~0x0080; nimr = (imr = read_scoop_reg(scoop, SCOOP_IMR)) & ~0x003E; - ncpr |= (state->Vcc == 33) ? 0x0001 : - (state->Vcc == 50) ? 0x0002 : 0; + if ((machine_is_spitz() || machine_is_borzoi() || machine_is_akita()) && skt->nr == 0) { + ncpr |= (state->Vcc == 33) ? 0x0002 : + (state->Vcc == 50) ? 0x0002 : 0; + } else { + ncpr |= (state->Vcc == 33) ? 0x0001 : + (state->Vcc == 50) ? 0x0002 : 0; + } nmcr |= (state->flags&SS_IOCARD) ? 0x0010 : 0; ncpr |= (state->flags&SS_OUTPUT_ENA) ? 0x0080 : 0; nccr |= (state->flags&SS_RESET)? 0x0080: 0; @@ -190,18 +180,22 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, ((skt->status&SS_WRPROT) ? 0x0008 : 0); if (!(ncpr & 0x0003)) { - scoop_devs[skt->nr].keep_rd = 0; - } else if (!scoop_devs[skt->nr].keep_rd) { + SCOOP_DEV[skt->nr].keep_rd = 0; + } else if (!SCOOP_DEV[skt->nr].keep_rd) { if (nccr & 0x0080) - scoop_devs[skt->nr].keep_rd = 1; + SCOOP_DEV[skt->nr].keep_rd = 1; else nccr |= 0x0080; } if (mcr != nmcr) write_scoop_reg(scoop, SCOOP_MCR, nmcr); - if (cpr != ncpr) - write_scoop_reg(scoop, SCOOP_CPR, ncpr); + if (cpr != ncpr) { + if (platform_scoop_config->power_ctrl) + platform_scoop_config->power_ctrl(scoop, ncpr , skt->nr); + else + write_scoop_reg(scoop, SCOOP_CPR, ncpr); + } if (ccr != nccr) write_scoop_reg(scoop, SCOOP_CCR, nccr); if (imr != nimr) @@ -214,43 +208,43 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, static void sharpsl_pcmcia_socket_init(struct soc_pcmcia_socket *skt) { - sharpsl_pcmcia_init_reset(&scoop_devs[skt->nr]); + sharpsl_pcmcia_init_reset(&SCOOP_DEV[skt->nr]); /* Enable interrupt */ - write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_IMR, 0x00C0); - write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_MCR, 0x0101); - scoop_devs[skt->nr].keep_vs = NO_KEEP_VS; + write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_IMR, 0x00C0); + write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_MCR, 0x0101); + SCOOP_DEV[skt->nr].keep_vs = NO_KEEP_VS; if (machine_is_collie()) /* We need to disable SS_OUTPUT_ENA here. */ - write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR, read_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR) & ~0x0080); + write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR, read_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR) & ~0x0080); } static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) { /* CF_BUS_OFF */ - sharpsl_pcmcia_init_reset(&scoop_devs[skt->nr]); + sharpsl_pcmcia_init_reset(&SCOOP_DEV[skt->nr]); if (machine_is_collie()) /* We need to disable SS_OUTPUT_ENA here. */ - write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR, read_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR) & ~0x0080); + write_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR, read_scoop_reg(SCOOP_DEV[skt->nr].dev, SCOOP_CPR) & ~0x0080); } static struct pcmcia_low_level sharpsl_pcmcia_ops = { - .owner = THIS_MODULE, - .hw_init = sharpsl_pcmcia_hw_init, - .hw_shutdown = sharpsl_pcmcia_hw_shutdown, - .socket_state = sharpsl_pcmcia_socket_state, - .configure_socket = sharpsl_pcmcia_configure_socket, - .socket_init = sharpsl_pcmcia_socket_init, - .socket_suspend = sharpsl_pcmcia_socket_suspend, - .first = 0, - .nr = 0, + .owner = THIS_MODULE, + .hw_init = sharpsl_pcmcia_hw_init, + .hw_shutdown = sharpsl_pcmcia_hw_shutdown, + .socket_state = sharpsl_pcmcia_socket_state, + .configure_socket = sharpsl_pcmcia_configure_socket, + .socket_init = sharpsl_pcmcia_socket_init, + .socket_suspend = sharpsl_pcmcia_socket_suspend, + .first = 0, + .nr = 0, }; -static struct platform_device *sharpsl_pcmcia_device; - #ifdef CONFIG_SA1100_COLLIE +#include "sa11xx_base.h" + int __init pcmcia_collie_init(struct device *dev) { int ret = -ENODEV; @@ -263,11 +257,13 @@ int __init pcmcia_collie_init(struct device *dev) #else +static struct platform_device *sharpsl_pcmcia_device; + static int __init sharpsl_pcmcia_init(void) { int ret; - sharpsl_pcmcia_ops.nr=scoop_num; + sharpsl_pcmcia_ops.nr=platform_scoop_config->num_devs; sharpsl_pcmcia_device = kmalloc(sizeof(*sharpsl_pcmcia_device), GFP_KERNEL); if (!sharpsl_pcmcia_device) return -ENOMEM; @@ -275,7 +271,7 @@ static int __init sharpsl_pcmcia_init(void) memset(sharpsl_pcmcia_device, 0, sizeof(*sharpsl_pcmcia_device)); sharpsl_pcmcia_device->name = "pxa2xx-pcmcia"; sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops; - sharpsl_pcmcia_device->dev.parent=scoop_devs[0].dev; + sharpsl_pcmcia_device->dev.parent=platform_scoop_config->devs[0].dev; ret = platform_device_register(sharpsl_pcmcia_device); if (ret) diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c index e95ed67d4f050afddf5918d34628e4586ba70951..bd7c966ea2d7f8ee7dfe250bd4e4a26343a6fd72 100644 --- a/drivers/pnp/card.c +++ b/drivers/pnp/card.c @@ -12,7 +12,7 @@ #include "base.h" LIST_HEAD(pnp_cards); -LIST_HEAD(pnp_card_drivers); +static LIST_HEAD(pnp_card_drivers); static const struct pnp_card_device_id * match_card(struct pnp_card_driver * drv, struct pnp_card * card) @@ -374,11 +374,13 @@ void pnp_unregister_card_driver(struct pnp_card_driver * drv) pnp_unregister_driver(&drv->link); } +#if 0 EXPORT_SYMBOL(pnp_add_card); EXPORT_SYMBOL(pnp_remove_card); EXPORT_SYMBOL(pnp_add_card_device); EXPORT_SYMBOL(pnp_remove_card_device); EXPORT_SYMBOL(pnp_add_card_id); +#endif /* 0 */ EXPORT_SYMBOL(pnp_request_card_device); EXPORT_SYMBOL(pnp_release_card_device); EXPORT_SYMBOL(pnp_register_card_driver); diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c index deed92459bc5e34feddcb5a27ff3cc3f1163365e..aec83ec5ea23f2471c55fbbe3dafd073b296c42e 100644 --- a/drivers/pnp/core.c +++ b/drivers/pnp/core.c @@ -158,13 +158,14 @@ void __pnp_remove_device(struct pnp_dev *dev) * * this function will free all mem used by dev */ - +#if 0 void pnp_remove_device(struct pnp_dev *dev) { if (!dev || dev->card) return; __pnp_remove_device(dev); } +#endif /* 0 */ static int __init pnp_init(void) { @@ -174,7 +175,9 @@ static int __init pnp_init(void) subsys_initcall(pnp_init); +#if 0 EXPORT_SYMBOL(pnp_register_protocol); EXPORT_SYMBOL(pnp_unregister_protocol); EXPORT_SYMBOL(pnp_add_device); EXPORT_SYMBOL(pnp_remove_device); +#endif /* 0 */ diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c index 33da25f3213f4614a6dc338b9743034452dab3de..d3ccce706ab4ce9ee20bf45e46112249fcdcf4c3 100644 --- a/drivers/pnp/driver.c +++ b/drivers/pnp/driver.c @@ -214,6 +214,8 @@ int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev) EXPORT_SYMBOL(pnp_register_driver); EXPORT_SYMBOL(pnp_unregister_driver); +#if 0 EXPORT_SYMBOL(pnp_add_id); +#endif EXPORT_SYMBOL(pnp_device_attach); EXPORT_SYMBOL(pnp_device_detach); diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c index beedd86800f4e26093643ec765961a2fbd6f0e25..57fd60314d591516e1a7a7c81ff030ac552978a9 100644 --- a/drivers/pnp/isapnp/core.c +++ b/drivers/pnp/isapnp/core.c @@ -941,7 +941,9 @@ EXPORT_SYMBOL(isapnp_protocol); EXPORT_SYMBOL(isapnp_present); EXPORT_SYMBOL(isapnp_cfg_begin); EXPORT_SYMBOL(isapnp_cfg_end); +#if 0 EXPORT_SYMBOL(isapnp_read_byte); +#endif EXPORT_SYMBOL(isapnp_write_byte); static int isapnp_read_resources(struct pnp_dev *dev, struct pnp_resource_table *res) diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c index cbb2749db178e1332be1c0693ce627ad29c502fa..261668618b2d481d8bd5074e8297e0f9374f145b 100644 --- a/drivers/pnp/manager.c +++ b/drivers/pnp/manager.c @@ -555,7 +555,9 @@ void pnp_resource_change(struct resource *resource, unsigned long start, unsigne EXPORT_SYMBOL(pnp_manual_config_dev); +#if 0 EXPORT_SYMBOL(pnp_auto_config_dev); +#endif EXPORT_SYMBOL(pnp_activate_dev); EXPORT_SYMBOL(pnp_disable_dev); EXPORT_SYMBOL(pnp_resource_change); diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index 1a8915e74160bba5b0b4a94f2ecbe6322168b8e6..816479ad217b044dd3c9eb5cd27d3b6683616e6a 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -117,7 +117,7 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev) return ACPI_FAILURE(status) ? -ENODEV : 0; } -struct pnp_protocol pnpacpi_protocol = { +static struct pnp_protocol pnpacpi_protocol = { .name = "Plug and Play ACPI", .get = pnpacpi_get_resources, .set = pnpacpi_set_resources, @@ -234,7 +234,7 @@ static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle, } int pnpacpi_disabled __initdata; -int __init pnpacpi_init(void) +static int __init pnpacpi_init(void) { if (acpi_disabled || pnpacpi_disabled) { pnp_info("PnP ACPI: disabled"); @@ -258,4 +258,6 @@ static int __init pnpacpi_setup(char *str) } __setup("pnpacpi=", pnpacpi_setup); +#if 0 EXPORT_SYMBOL(pnpacpi_protocol); +#endif diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c index 887ad8939349e9f3eb37fc9bcc1ddb893b64fce4..6ded527169f4b805b43a77dba11a5c0b23d42af8 100644 --- a/drivers/pnp/resource.c +++ b/drivers/pnp/resource.c @@ -477,12 +477,14 @@ int pnp_check_dma(struct pnp_dev * dev, int idx) } +#if 0 EXPORT_SYMBOL(pnp_register_dependent_option); EXPORT_SYMBOL(pnp_register_independent_option); EXPORT_SYMBOL(pnp_register_irq_resource); EXPORT_SYMBOL(pnp_register_dma_resource); EXPORT_SYMBOL(pnp_register_port_resource); EXPORT_SYMBOL(pnp_register_mem_resource); +#endif /* 0 */ /* format is: pnp_reserve_irq=irq1[,irq2] .... */ diff --git a/drivers/rapidio/Kconfig b/drivers/rapidio/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..0b2d2c3579a77b655f723b0d59d4a9b2d16de211 --- /dev/null +++ b/drivers/rapidio/Kconfig @@ -0,0 +1,18 @@ +# +# RapidIO configuration +# +config RAPIDIO_8_BIT_TRANSPORT + bool "8-bit transport addressing" + depends on RAPIDIO + ---help--- + By default, the kernel assumes a 16-bit addressed RapidIO + network. By selecting this option, the kernel will support + an 8-bit addressed network. + +config RAPIDIO_DISC_TIMEOUT + int "Discovery timeout duration (seconds)" + depends on RAPIDIO + default "30" + ---help--- + Amount of time a discovery node waits for a host to complete + enumeration beforing giving up. diff --git a/drivers/rapidio/Makefile b/drivers/rapidio/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7c0e1818de5139e43207a1e479bb4328eec4ec97 --- /dev/null +++ b/drivers/rapidio/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for RapidIO interconnect services +# +obj-y += rio.o rio-access.o rio-driver.o rio-scan.o rio-sysfs.o + +obj-$(CONFIG_RAPIDIO) += switches/ diff --git a/drivers/rapidio/rio-access.c b/drivers/rapidio/rio-access.c new file mode 100644 index 0000000000000000000000000000000000000000..b9fab2ae3a36108ed2bbc48499682382c8e3b88f --- /dev/null +++ b/drivers/rapidio/rio-access.c @@ -0,0 +1,175 @@ +/* + * RapidIO configuration space access support + * + * Copyright 2005 MontaVista Software, Inc. + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include + +/* + * These interrupt-safe spinlocks protect all accesses to RIO + * configuration space and doorbell access. + */ +static spinlock_t rio_config_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t rio_doorbell_lock = SPIN_LOCK_UNLOCKED; + +/* + * Wrappers for all RIO configuration access functions. They just check + * alignment, do locking and call the low-level functions pointed to + * by rio_mport->ops. + */ + +#define RIO_8_BAD 0 +#define RIO_16_BAD (offset & 1) +#define RIO_32_BAD (offset & 3) + +/** + * RIO_LOP_READ - Generate rio_local_read_config_* functions + * @size: Size of configuration space read (8, 16, 32 bits) + * @type: C type of value argument + * @len: Length of configuration space read (1, 2, 4 bytes) + * + * Generates rio_local_read_config_* functions used to access + * configuration space registers on the local device. + */ +#define RIO_LOP_READ(size,type,len) \ +int __rio_local_read_config_##size \ + (struct rio_mport *mport, u32 offset, type *value) \ +{ \ + int res; \ + unsigned long flags; \ + u32 data = 0; \ + if (RIO_##size##_BAD) return RIO_BAD_SIZE; \ + spin_lock_irqsave(&rio_config_lock, flags); \ + res = mport->ops->lcread(mport->id, offset, len, &data); \ + *value = (type)data; \ + spin_unlock_irqrestore(&rio_config_lock, flags); \ + return res; \ +} + +/** + * RIO_LOP_WRITE - Generate rio_local_write_config_* functions + * @size: Size of configuration space write (8, 16, 32 bits) + * @type: C type of value argument + * @len: Length of configuration space write (1, 2, 4 bytes) + * + * Generates rio_local_write_config_* functions used to access + * configuration space registers on the local device. + */ +#define RIO_LOP_WRITE(size,type,len) \ +int __rio_local_write_config_##size \ + (struct rio_mport *mport, u32 offset, type value) \ +{ \ + int res; \ + unsigned long flags; \ + if (RIO_##size##_BAD) return RIO_BAD_SIZE; \ + spin_lock_irqsave(&rio_config_lock, flags); \ + res = mport->ops->lcwrite(mport->id, offset, len, value); \ + spin_unlock_irqrestore(&rio_config_lock, flags); \ + return res; \ +} + +RIO_LOP_READ(8, u8, 1) +RIO_LOP_READ(16, u16, 2) +RIO_LOP_READ(32, u32, 4) +RIO_LOP_WRITE(8, u8, 1) +RIO_LOP_WRITE(16, u16, 2) +RIO_LOP_WRITE(32, u32, 4) + +EXPORT_SYMBOL_GPL(__rio_local_read_config_8); +EXPORT_SYMBOL_GPL(__rio_local_read_config_16); +EXPORT_SYMBOL_GPL(__rio_local_read_config_32); +EXPORT_SYMBOL_GPL(__rio_local_write_config_8); +EXPORT_SYMBOL_GPL(__rio_local_write_config_16); +EXPORT_SYMBOL_GPL(__rio_local_write_config_32); + +/** + * RIO_OP_READ - Generate rio_mport_read_config_* functions + * @size: Size of configuration space read (8, 16, 32 bits) + * @type: C type of value argument + * @len: Length of configuration space read (1, 2, 4 bytes) + * + * Generates rio_mport_read_config_* functions used to access + * configuration space registers on the local device. + */ +#define RIO_OP_READ(size,type,len) \ +int rio_mport_read_config_##size \ + (struct rio_mport *mport, u16 destid, u8 hopcount, u32 offset, type *value) \ +{ \ + int res; \ + unsigned long flags; \ + u32 data = 0; \ + if (RIO_##size##_BAD) return RIO_BAD_SIZE; \ + spin_lock_irqsave(&rio_config_lock, flags); \ + res = mport->ops->cread(mport->id, destid, hopcount, offset, len, &data); \ + *value = (type)data; \ + spin_unlock_irqrestore(&rio_config_lock, flags); \ + return res; \ +} + +/** + * RIO_OP_WRITE - Generate rio_mport_write_config_* functions + * @size: Size of configuration space write (8, 16, 32 bits) + * @type: C type of value argument + * @len: Length of configuration space write (1, 2, 4 bytes) + * + * Generates rio_mport_write_config_* functions used to access + * configuration space registers on the local device. + */ +#define RIO_OP_WRITE(size,type,len) \ +int rio_mport_write_config_##size \ + (struct rio_mport *mport, u16 destid, u8 hopcount, u32 offset, type value) \ +{ \ + int res; \ + unsigned long flags; \ + if (RIO_##size##_BAD) return RIO_BAD_SIZE; \ + spin_lock_irqsave(&rio_config_lock, flags); \ + res = mport->ops->cwrite(mport->id, destid, hopcount, offset, len, value); \ + spin_unlock_irqrestore(&rio_config_lock, flags); \ + return res; \ +} + +RIO_OP_READ(8, u8, 1) +RIO_OP_READ(16, u16, 2) +RIO_OP_READ(32, u32, 4) +RIO_OP_WRITE(8, u8, 1) +RIO_OP_WRITE(16, u16, 2) +RIO_OP_WRITE(32, u32, 4) + +EXPORT_SYMBOL_GPL(rio_mport_read_config_8); +EXPORT_SYMBOL_GPL(rio_mport_read_config_16); +EXPORT_SYMBOL_GPL(rio_mport_read_config_32); +EXPORT_SYMBOL_GPL(rio_mport_write_config_8); +EXPORT_SYMBOL_GPL(rio_mport_write_config_16); +EXPORT_SYMBOL_GPL(rio_mport_write_config_32); + +/** + * rio_mport_send_doorbell - Send a doorbell message + * + * @mport: RIO master port + * @destid: RIO device destination ID + * @data: Doorbell message data + * + * Send a doorbell message to a RIO device. The doorbell message + * has a 16-bit info field provided by the data argument. + */ +int rio_mport_send_doorbell(struct rio_mport *mport, u16 destid, u16 data) +{ + int res; + unsigned long flags; + + spin_lock_irqsave(&rio_doorbell_lock, flags); + res = mport->ops->dsend(mport->id, destid, data); + spin_unlock_irqrestore(&rio_doorbell_lock, flags); + + return res; +} + +EXPORT_SYMBOL_GPL(rio_mport_send_doorbell); diff --git a/drivers/rapidio/rio-driver.c b/drivers/rapidio/rio-driver.c new file mode 100644 index 0000000000000000000000000000000000000000..dc749609699aa178e5e1321942d44930378d2285 --- /dev/null +++ b/drivers/rapidio/rio-driver.c @@ -0,0 +1,229 @@ +/* + * RapidIO driver support + * + * Copyright 2005 MontaVista Software, Inc. + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include + +#include "rio.h" + +/** + * rio_match_device - Tell if a RIO device has a matching RIO device id structure + * @id: the RIO device id structure to match against + * @rdev: the RIO device structure to match against + * + * Used from driver probe and bus matching to check whether a RIO device + * matches a device id structure provided by a RIO driver. Returns the + * matching &struct rio_device_id or %NULL if there is no match. + */ +static const struct rio_device_id *rio_match_device(const struct rio_device_id + *id, + const struct rio_dev *rdev) +{ + while (id->vid || id->asm_vid) { + if (((id->vid == RIO_ANY_ID) || (id->vid == rdev->vid)) && + ((id->did == RIO_ANY_ID) || (id->did == rdev->did)) && + ((id->asm_vid == RIO_ANY_ID) + || (id->asm_vid == rdev->asm_vid)) + && ((id->asm_did == RIO_ANY_ID) + || (id->asm_did == rdev->asm_did))) + return id; + id++; + } + return NULL; +} + +/** + * rio_dev_get - Increments the reference count of the RIO device structure + * + * @rdev: RIO device being referenced + * + * Each live reference to a device should be refcounted. + * + * Drivers for RIO devices should normally record such references in + * their probe() methods, when they bind to a device, and release + * them by calling rio_dev_put(), in their disconnect() methods. + */ +struct rio_dev *rio_dev_get(struct rio_dev *rdev) +{ + if (rdev) + get_device(&rdev->dev); + + return rdev; +} + +/** + * rio_dev_put - Release a use of the RIO device structure + * + * @rdev: RIO device being disconnected + * + * Must be called when a user of a device is finished with it. + * When the last user of the device calls this function, the + * memory of the device is freed. + */ +void rio_dev_put(struct rio_dev *rdev) +{ + if (rdev) + put_device(&rdev->dev); +} + +/** + * rio_device_probe - Tell if a RIO device structure has a matching RIO + * device id structure + * @id: the RIO device id structure to match against + * @dev: the RIO device structure to match against + * + * return 0 and set rio_dev->driver when drv claims rio_dev, else error + */ +static int rio_device_probe(struct device *dev) +{ + struct rio_driver *rdrv = to_rio_driver(dev->driver); + struct rio_dev *rdev = to_rio_dev(dev); + int error = -ENODEV; + const struct rio_device_id *id; + + if (!rdev->driver && rdrv->probe) { + if (!rdrv->id_table) + return error; + id = rio_match_device(rdrv->id_table, rdev); + rio_dev_get(rdev); + if (id) + error = rdrv->probe(rdev, id); + if (error >= 0) { + rdev->driver = rdrv; + error = 0; + rio_dev_put(rdev); + } + } + return error; +} + +/** + * rio_device_remove - Remove a RIO device from the system + * + * @dev: the RIO device structure to match against + * + * Remove a RIO device from the system. If it has an associated + * driver, then run the driver remove() method. Then update + * the reference count. + */ +static int rio_device_remove(struct device *dev) +{ + struct rio_dev *rdev = to_rio_dev(dev); + struct rio_driver *rdrv = rdev->driver; + + if (rdrv) { + if (rdrv->remove) + rdrv->remove(rdev); + rdev->driver = NULL; + } + + rio_dev_put(rdev); + + return 0; +} + +/** + * rio_register_driver - register a new RIO driver + * @rdrv: the RIO driver structure to register + * + * Adds a &struct rio_driver to the list of registered drivers + * Returns a negative value on error, otherwise 0. If no error + * occurred, the driver remains registered even if no device + * was claimed during registration. + */ +int rio_register_driver(struct rio_driver *rdrv) +{ + /* initialize common driver fields */ + rdrv->driver.name = rdrv->name; + rdrv->driver.bus = &rio_bus_type; + rdrv->driver.probe = rio_device_probe; + rdrv->driver.remove = rio_device_remove; + + /* register with core */ + return driver_register(&rdrv->driver); +} + +/** + * rio_unregister_driver - unregister a RIO driver + * @rdrv: the RIO driver structure to unregister + * + * Deletes the &struct rio_driver from the list of registered RIO + * drivers, gives it a chance to clean up by calling its remove() + * function for each device it was responsible for, and marks those + * devices as driverless. + */ +void rio_unregister_driver(struct rio_driver *rdrv) +{ + driver_unregister(&rdrv->driver); +} + +/** + * rio_match_bus - Tell if a RIO device structure has a matching RIO + * driver device id structure + * @dev: the standard device structure to match against + * @drv: the standard driver structure containing the ids to match against + * + * Used by a driver to check whether a RIO device present in the + * system is in its list of supported devices. Returns 1 if + * there is a matching &struct rio_device_id or 0 if there is + * no match. + */ +static int rio_match_bus(struct device *dev, struct device_driver *drv) +{ + struct rio_dev *rdev = to_rio_dev(dev); + struct rio_driver *rdrv = to_rio_driver(drv); + const struct rio_device_id *id = rdrv->id_table; + const struct rio_device_id *found_id; + + if (!id) + goto out; + + found_id = rio_match_device(id, rdev); + + if (found_id) + return 1; + + out:return 0; +} + +static struct device rio_bus = { + .bus_id = "rapidio", +}; + +struct bus_type rio_bus_type = { + .name = "rapidio", + .match = rio_match_bus, + .dev_attrs = rio_dev_attrs +}; + +/** + * rio_bus_init - Register the RapidIO bus with the device model + * + * Registers the RIO bus device and RIO bus type with the Linux + * device model. + */ +static int __init rio_bus_init(void) +{ + if (device_register(&rio_bus) < 0) + printk("RIO: failed to register RIO bus device\n"); + return bus_register(&rio_bus_type); +} + +postcore_initcall(rio_bus_init); + +EXPORT_SYMBOL_GPL(rio_register_driver); +EXPORT_SYMBOL_GPL(rio_unregister_driver); +EXPORT_SYMBOL_GPL(rio_bus_type); +EXPORT_SYMBOL_GPL(rio_dev_get); +EXPORT_SYMBOL_GPL(rio_dev_put); diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c new file mode 100644 index 0000000000000000000000000000000000000000..4f7ed4bd3be93d2f4870090ec5911e264afde7bd --- /dev/null +++ b/drivers/rapidio/rio-scan.c @@ -0,0 +1,945 @@ +/* + * RapidIO enumeration and discovery support + * + * Copyright 2005 MontaVista Software, Inc. + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rio.h" + +LIST_HEAD(rio_devices); +static LIST_HEAD(rio_switches); + +#define RIO_ENUM_CMPL_MAGIC 0xdeadbeef + +static void rio_enum_timeout(unsigned long); + +DEFINE_SPINLOCK(rio_global_list_lock); + +static int next_destid = 0; +static int next_switchid = 0; +static int next_net = 0; + +static struct timer_list rio_enum_timer = +TIMER_INITIALIZER(rio_enum_timeout, 0, 0); + +static int rio_mport_phys_table[] = { + RIO_EFB_PAR_EP_ID, + RIO_EFB_PAR_EP_REC_ID, + RIO_EFB_SER_EP_ID, + RIO_EFB_SER_EP_REC_ID, + -1, +}; + +static int rio_sport_phys_table[] = { + RIO_EFB_PAR_EP_FREE_ID, + RIO_EFB_SER_EP_FREE_ID, + -1, +}; + +/** + * rio_get_device_id - Get the base/extended device id for a device + * @port: RIO master port + * @destid: Destination ID of device + * @hopcount: Hopcount to device + * + * Reads the base/extended device id from a device. Returns the + * 8/16-bit device ID. + */ +static u16 rio_get_device_id(struct rio_mport *port, u16 destid, u8 hopcount) +{ + u32 result; + + rio_mport_read_config_32(port, destid, hopcount, RIO_DID_CSR, &result); + + return RIO_GET_DID(result); +} + +/** + * rio_set_device_id - Set the base/extended device id for a device + * @port: RIO master port + * @destid: Destination ID of device + * @hopcount: Hopcount to device + * @did: Device ID value to be written + * + * Writes the base/extended device id from a device. + */ +static void rio_set_device_id(struct rio_mport *port, u16 destid, u8 hopcount, u16 did) +{ + rio_mport_write_config_32(port, destid, hopcount, RIO_DID_CSR, + RIO_SET_DID(did)); +} + +/** + * rio_local_set_device_id - Set the base/extended device id for a port + * @port: RIO master port + * @did: Device ID value to be written + * + * Writes the base/extended device id from a device. + */ +static void rio_local_set_device_id(struct rio_mport *port, u16 did) +{ + rio_local_write_config_32(port, RIO_DID_CSR, RIO_SET_DID(did)); +} + +/** + * rio_clear_locks- Release all host locks and signal enumeration complete + * @port: Master port to issue transaction + * + * Marks the component tag CSR on each device with the enumeration + * complete flag. When complete, it then release the host locks on + * each device. Returns 0 on success or %-EINVAL on failure. + */ +static int rio_clear_locks(struct rio_mport *port) +{ + struct rio_dev *rdev; + u32 result; + int ret = 0; + + /* Write component tag CSR magic complete value */ + rio_local_write_config_32(port, RIO_COMPONENT_TAG_CSR, + RIO_ENUM_CMPL_MAGIC); + list_for_each_entry(rdev, &rio_devices, global_list) + rio_write_config_32(rdev, RIO_COMPONENT_TAG_CSR, + RIO_ENUM_CMPL_MAGIC); + + /* Release host device id locks */ + rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR, + port->host_deviceid); + rio_local_read_config_32(port, RIO_HOST_DID_LOCK_CSR, &result); + if ((result & 0xffff) != 0xffff) { + printk(KERN_INFO + "RIO: badness when releasing host lock on master port, result %8.8x\n", + result); + ret = -EINVAL; + } + list_for_each_entry(rdev, &rio_devices, global_list) { + rio_write_config_32(rdev, RIO_HOST_DID_LOCK_CSR, + port->host_deviceid); + rio_read_config_32(rdev, RIO_HOST_DID_LOCK_CSR, &result); + if ((result & 0xffff) != 0xffff) { + printk(KERN_INFO + "RIO: badness when releasing host lock on vid %4.4x did %4.4x\n", + rdev->vid, rdev->did); + ret = -EINVAL; + } + } + + return ret; +} + +/** + * rio_enum_host- Set host lock and initialize host destination ID + * @port: Master port to issue transaction + * + * Sets the local host master port lock and destination ID register + * with the host device ID value. The host device ID value is provided + * by the platform. Returns %0 on success or %-1 on failure. + */ +static int rio_enum_host(struct rio_mport *port) +{ + u32 result; + + /* Set master port host device id lock */ + rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR, + port->host_deviceid); + + rio_local_read_config_32(port, RIO_HOST_DID_LOCK_CSR, &result); + if ((result & 0xffff) != port->host_deviceid) + return -1; + + /* Set master port destid and init destid ctr */ + rio_local_set_device_id(port, port->host_deviceid); + + if (next_destid == port->host_deviceid) + next_destid++; + + return 0; +} + +/** + * rio_device_has_destid- Test if a device contains a destination ID register + * @port: Master port to issue transaction + * @src_ops: RIO device source operations + * @dst_ops: RIO device destination operations + * + * Checks the provided @src_ops and @dst_ops for the necessary transaction + * capabilities that indicate whether or not a device will implement a + * destination ID register. Returns 1 if true or 0 if false. + */ +static int rio_device_has_destid(struct rio_mport *port, int src_ops, + int dst_ops) +{ + u32 mask = RIO_OPS_READ | RIO_OPS_WRITE | RIO_OPS_ATOMIC_TST_SWP | RIO_OPS_ATOMIC_INC | RIO_OPS_ATOMIC_DEC | RIO_OPS_ATOMIC_SET | RIO_OPS_ATOMIC_CLR; + + return !!((src_ops | dst_ops) & mask); +} + +/** + * rio_release_dev- Frees a RIO device struct + * @dev: LDM device associated with a RIO device struct + * + * Gets the RIO device struct associated a RIO device struct. + * The RIO device struct is freed. + */ +static void rio_release_dev(struct device *dev) +{ + struct rio_dev *rdev; + + rdev = to_rio_dev(dev); + kfree(rdev); +} + +/** + * rio_is_switch- Tests if a RIO device has switch capabilities + * @rdev: RIO device + * + * Gets the RIO device Processing Element Features register + * contents and tests for switch capabilities. Returns 1 if + * the device is a switch or 0 if it is not a switch. + * The RIO device struct is freed. + */ +static int rio_is_switch(struct rio_dev *rdev) +{ + if (rdev->pef & RIO_PEF_SWITCH) + return 1; + return 0; +} + +/** + * rio_route_set_ops- Sets routing operations for a particular vendor switch + * @rdev: RIO device + * + * Searches the RIO route ops table for known switch types. If the vid + * and did match a switch table entry, then set the add_entry() and + * get_entry() ops to the table entry values. + */ +static void rio_route_set_ops(struct rio_dev *rdev) +{ + struct rio_route_ops *cur = __start_rio_route_ops; + struct rio_route_ops *end = __end_rio_route_ops; + + while (cur < end) { + if ((cur->vid == rdev->vid) && (cur->did == rdev->did)) { + pr_debug("RIO: adding routing ops for %s\n", rio_name(rdev)); + rdev->rswitch->add_entry = cur->add_hook; + rdev->rswitch->get_entry = cur->get_hook; + } + cur++; + } + + if (!rdev->rswitch->add_entry || !rdev->rswitch->get_entry) + printk(KERN_ERR "RIO: missing routing ops for %s\n", + rio_name(rdev)); +} + +/** + * rio_add_device- Adds a RIO device to the device model + * @rdev: RIO device + * + * Adds the RIO device to the global device list and adds the RIO + * device to the RIO device list. Creates the generic sysfs nodes + * for an RIO device. + */ +static void __devinit rio_add_device(struct rio_dev *rdev) +{ + device_add(&rdev->dev); + + spin_lock(&rio_global_list_lock); + list_add_tail(&rdev->global_list, &rio_devices); + spin_unlock(&rio_global_list_lock); + + rio_create_sysfs_dev_files(rdev); +} + +/** + * rio_setup_device- Allocates and sets up a RIO device + * @net: RIO network + * @port: Master port to send transactions + * @destid: Current destination ID + * @hopcount: Current hopcount + * @do_enum: Enumeration/Discovery mode flag + * + * Allocates a RIO device and configures fields based on configuration + * space contents. If device has a destination ID register, a destination + * ID is either assigned in enumeration mode or read from configuration + * space in discovery mode. If the device has switch capabilities, then + * a switch is allocated and configured appropriately. Returns a pointer + * to a RIO device on success or NULL on failure. + * + */ +static struct rio_dev *rio_setup_device(struct rio_net *net, + struct rio_mport *port, u16 destid, + u8 hopcount, int do_enum) +{ + struct rio_dev *rdev; + struct rio_switch *rswitch; + int result, rdid; + + rdev = kmalloc(sizeof(struct rio_dev), GFP_KERNEL); + if (!rdev) + goto out; + + memset(rdev, 0, sizeof(struct rio_dev)); + rdev->net = net; + rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_ID_CAR, + &result); + rdev->did = result >> 16; + rdev->vid = result & 0xffff; + rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_INFO_CAR, + &rdev->device_rev); + rio_mport_read_config_32(port, destid, hopcount, RIO_ASM_ID_CAR, + &result); + rdev->asm_did = result >> 16; + rdev->asm_vid = result & 0xffff; + rio_mport_read_config_32(port, destid, hopcount, RIO_ASM_INFO_CAR, + &result); + rdev->asm_rev = result >> 16; + rio_mport_read_config_32(port, destid, hopcount, RIO_PEF_CAR, + &rdev->pef); + if (rdev->pef & RIO_PEF_EXT_FEATURES) + rdev->efptr = result & 0xffff; + + rio_mport_read_config_32(port, destid, hopcount, RIO_SRC_OPS_CAR, + &rdev->src_ops); + rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR, + &rdev->dst_ops); + + if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops) + && do_enum) { + rio_set_device_id(port, destid, hopcount, next_destid); + rdev->destid = next_destid++; + if (next_destid == port->host_deviceid) + next_destid++; + } else + rdev->destid = rio_get_device_id(port, destid, hopcount); + + /* If a PE has both switch and other functions, show it as a switch */ + if (rio_is_switch(rdev)) { + rio_mport_read_config_32(port, destid, hopcount, + RIO_SWP_INFO_CAR, &rdev->swpinfo); + rswitch = kmalloc(sizeof(struct rio_switch), GFP_KERNEL); + if (!rswitch) { + kfree(rdev); + rdev = NULL; + goto out; + } + rswitch->switchid = next_switchid; + rswitch->hopcount = hopcount; + rswitch->destid = 0xffff; + /* Initialize switch route table */ + for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES; rdid++) + rswitch->route_table[rdid] = RIO_INVALID_ROUTE; + rdev->rswitch = rswitch; + sprintf(rio_name(rdev), "%02x:s:%04x", rdev->net->id, + rdev->rswitch->switchid); + rio_route_set_ops(rdev); + + list_add_tail(&rswitch->node, &rio_switches); + + } else + sprintf(rio_name(rdev), "%02x:e:%04x", rdev->net->id, + rdev->destid); + + rdev->dev.bus = &rio_bus_type; + + device_initialize(&rdev->dev); + rdev->dev.release = rio_release_dev; + rio_dev_get(rdev); + + rdev->dma_mask = DMA_32BIT_MASK; + rdev->dev.dma_mask = &rdev->dma_mask; + rdev->dev.coherent_dma_mask = DMA_32BIT_MASK; + + if ((rdev->pef & RIO_PEF_INB_DOORBELL) && + (rdev->dst_ops & RIO_DST_OPS_DOORBELL)) + rio_init_dbell_res(&rdev->riores[RIO_DOORBELL_RESOURCE], + 0, 0xffff); + + rio_add_device(rdev); + + out: + return rdev; +} + +/** + * rio_sport_is_active- Tests if a switch port has an active connection. + * @port: Master port to send transaction + * @destid: Associated destination ID for switch + * @hopcount: Hopcount to reach switch + * @sport: Switch port number + * + * Reads the port error status CSR for a particular switch port to + * determine if the port has an active link. Returns + * %PORT_N_ERR_STS_PORT_OK if the port is active or %0 if it is + * inactive. + */ +static int +rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport) +{ + u32 result; + u32 ext_ftr_ptr; + + int *entry = rio_sport_phys_table; + + do { + if ((ext_ftr_ptr = + rio_mport_get_feature(port, 0, destid, hopcount, *entry))) + + break; + } while (*++entry >= 0); + + if (ext_ftr_ptr) + rio_mport_read_config_32(port, destid, hopcount, + ext_ftr_ptr + + RIO_PORT_N_ERR_STS_CSR(sport), + &result); + + return (result & PORT_N_ERR_STS_PORT_OK); +} + +/** + * rio_route_add_entry- Add a route entry to a switch routing table + * @mport: Master port to send transaction + * @rdev: Switch device + * @table: Routing table ID + * @route_destid: Destination ID to be routed + * @route_port: Port number to be routed + * + * Calls the switch specific add_entry() method to add a route entry + * on a switch. The route table can be specified using the @table + * argument if a switch has per port routing tables or the normal + * use is to specific all tables (or the global table) by passing + * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL + * on failure. + */ +static int rio_route_add_entry(struct rio_mport *mport, struct rio_dev *rdev, + u16 table, u16 route_destid, u8 route_port) +{ + return rdev->rswitch->add_entry(mport, rdev->rswitch->destid, + rdev->rswitch->hopcount, table, + route_destid, route_port); +} + +/** + * rio_route_get_entry- Read a route entry in a switch routing table + * @mport: Master port to send transaction + * @rdev: Switch device + * @table: Routing table ID + * @route_destid: Destination ID to be routed + * @route_port: Pointer to read port number into + * + * Calls the switch specific get_entry() method to read a route entry + * in a switch. The route table can be specified using the @table + * argument if a switch has per port routing tables or the normal + * use is to specific all tables (or the global table) by passing + * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL + * on failure. + */ +static int +rio_route_get_entry(struct rio_mport *mport, struct rio_dev *rdev, u16 table, + u16 route_destid, u8 * route_port) +{ + return rdev->rswitch->get_entry(mport, rdev->rswitch->destid, + rdev->rswitch->hopcount, table, + route_destid, route_port); +} + +/** + * rio_get_host_deviceid_lock- Reads the Host Device ID Lock CSR on a device + * @port: Master port to send transaction + * @hopcount: Number of hops to the device + * + * Used during enumeration to read the Host Device ID Lock CSR on a + * RIO device. Returns the value of the lock register. + */ +static u16 rio_get_host_deviceid_lock(struct rio_mport *port, u8 hopcount) +{ + u32 result; + + rio_mport_read_config_32(port, RIO_ANY_DESTID, hopcount, + RIO_HOST_DID_LOCK_CSR, &result); + + return (u16) (result & 0xffff); +} + +/** + * rio_get_swpinfo_inport- Gets the ingress port number + * @mport: Master port to send transaction + * @destid: Destination ID associated with the switch + * @hopcount: Number of hops to the device + * + * Returns port number being used to access the switch device. + */ +static u8 +rio_get_swpinfo_inport(struct rio_mport *mport, u16 destid, u8 hopcount) +{ + u32 result; + + rio_mport_read_config_32(mport, destid, hopcount, RIO_SWP_INFO_CAR, + &result); + + return (u8) (result & 0xff); +} + +/** + * rio_get_swpinfo_tports- Gets total number of ports on the switch + * @mport: Master port to send transaction + * @destid: Destination ID associated with the switch + * @hopcount: Number of hops to the device + * + * Returns total numbers of ports implemented by the switch device. + */ +static u8 rio_get_swpinfo_tports(struct rio_mport *mport, u16 destid, + u8 hopcount) +{ + u32 result; + + rio_mport_read_config_32(mport, destid, hopcount, RIO_SWP_INFO_CAR, + &result); + + return RIO_GET_TOTAL_PORTS(result); +} + +/** + * rio_net_add_mport- Add a master port to a RIO network + * @net: RIO network + * @port: Master port to add + * + * Adds a master port to the network list of associated master + * ports.. + */ +static void rio_net_add_mport(struct rio_net *net, struct rio_mport *port) +{ + spin_lock(&rio_global_list_lock); + list_add_tail(&port->nnode, &net->mports); + spin_unlock(&rio_global_list_lock); +} + +/** + * rio_enum_peer- Recursively enumerate a RIO network through a master port + * @net: RIO network being enumerated + * @port: Master port to send transactions + * @hopcount: Number of hops into the network + * + * Recursively enumerates a RIO network. Transactions are sent via the + * master port passed in @port. + */ +static int rio_enum_peer(struct rio_net *net, struct rio_mport *port, + u8 hopcount) +{ + int port_num; + int num_ports; + int cur_destid; + struct rio_dev *rdev; + u16 destid; + int tmp; + + if (rio_get_host_deviceid_lock(port, hopcount) == port->host_deviceid) { + pr_debug("RIO: PE already discovered by this host\n"); + /* + * Already discovered by this host. Add it as another + * master port for the current network. + */ + rio_net_add_mport(net, port); + return 0; + } + + /* Attempt to acquire device lock */ + rio_mport_write_config_32(port, RIO_ANY_DESTID, hopcount, + RIO_HOST_DID_LOCK_CSR, port->host_deviceid); + while ((tmp = rio_get_host_deviceid_lock(port, hopcount)) + < port->host_deviceid) { + /* Delay a bit */ + mdelay(1); + /* Attempt to acquire device lock again */ + rio_mport_write_config_32(port, RIO_ANY_DESTID, hopcount, + RIO_HOST_DID_LOCK_CSR, + port->host_deviceid); + } + + if (rio_get_host_deviceid_lock(port, hopcount) > port->host_deviceid) { + pr_debug( + "RIO: PE locked by a higher priority host...retreating\n"); + return -1; + } + + /* Setup new RIO device */ + if ((rdev = rio_setup_device(net, port, RIO_ANY_DESTID, hopcount, 1))) { + /* Add device to the global and bus/net specific list. */ + list_add_tail(&rdev->net_list, &net->devices); + } else + return -1; + + if (rio_is_switch(rdev)) { + next_switchid++; + + for (destid = 0; destid < next_destid; destid++) { + rio_route_add_entry(port, rdev, RIO_GLOBAL_TABLE, + destid, rio_get_swpinfo_inport(port, + RIO_ANY_DESTID, + hopcount)); + rdev->rswitch->route_table[destid] = + rio_get_swpinfo_inport(port, RIO_ANY_DESTID, + hopcount); + } + + num_ports = + rio_get_swpinfo_tports(port, RIO_ANY_DESTID, hopcount); + pr_debug( + "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", + rio_name(rdev), rdev->vid, rdev->did, num_ports); + for (port_num = 0; port_num < num_ports; port_num++) { + if (rio_get_swpinfo_inport + (port, RIO_ANY_DESTID, hopcount) == port_num) + continue; + + cur_destid = next_destid; + + if (rio_sport_is_active + (port, RIO_ANY_DESTID, hopcount, port_num)) { + pr_debug( + "RIO: scanning device on port %d\n", + port_num); + rio_route_add_entry(port, rdev, + RIO_GLOBAL_TABLE, + RIO_ANY_DESTID, port_num); + + if (rio_enum_peer(net, port, hopcount + 1) < 0) + return -1; + + /* Update routing tables */ + if (next_destid > cur_destid) { + for (destid = cur_destid; + destid < next_destid; destid++) { + rio_route_add_entry(port, rdev, + RIO_GLOBAL_TABLE, + destid, + port_num); + rdev->rswitch-> + route_table[destid] = + port_num; + } + rdev->rswitch->destid = cur_destid; + } + } + } + } else + pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n", + rio_name(rdev), rdev->vid, rdev->did); + + return 0; +} + +/** + * rio_enum_complete- Tests if enumeration of a network is complete + * @port: Master port to send transaction + * + * Tests the Component Tag CSR for presence of the magic enumeration + * complete flag. Return %1 if enumeration is complete or %0 if + * enumeration is incomplete. + */ +static int rio_enum_complete(struct rio_mport *port) +{ + u32 tag_csr; + int ret = 0; + + rio_local_read_config_32(port, RIO_COMPONENT_TAG_CSR, &tag_csr); + + if (tag_csr == RIO_ENUM_CMPL_MAGIC) + ret = 1; + + return ret; +} + +/** + * rio_disc_peer- Recursively discovers a RIO network through a master port + * @net: RIO network being discovered + * @port: Master port to send transactions + * @destid: Current destination ID in network + * @hopcount: Number of hops into the network + * + * Recursively discovers a RIO network. Transactions are sent via the + * master port passed in @port. + */ +static int +rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, + u8 hopcount) +{ + u8 port_num, route_port; + int num_ports; + struct rio_dev *rdev; + u16 ndestid; + + /* Setup new RIO device */ + if ((rdev = rio_setup_device(net, port, destid, hopcount, 0))) { + /* Add device to the global and bus/net specific list. */ + list_add_tail(&rdev->net_list, &net->devices); + } else + return -1; + + if (rio_is_switch(rdev)) { + next_switchid++; + + /* Associated destid is how we accessed this switch */ + rdev->rswitch->destid = destid; + + num_ports = rio_get_swpinfo_tports(port, destid, hopcount); + pr_debug( + "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", + rio_name(rdev), rdev->vid, rdev->did, num_ports); + for (port_num = 0; port_num < num_ports; port_num++) { + if (rio_get_swpinfo_inport(port, destid, hopcount) == + port_num) + continue; + + if (rio_sport_is_active + (port, destid, hopcount, port_num)) { + pr_debug( + "RIO: scanning device on port %d\n", + port_num); + for (ndestid = 0; ndestid < RIO_ANY_DESTID; + ndestid++) { + rio_route_get_entry(port, rdev, + RIO_GLOBAL_TABLE, + ndestid, + &route_port); + if (route_port == port_num) + break; + } + + if (rio_disc_peer + (net, port, ndestid, hopcount + 1) < 0) + return -1; + } + } + } else + pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n", + rio_name(rdev), rdev->vid, rdev->did); + + return 0; +} + +/** + * rio_mport_is_active- Tests if master port link is active + * @port: Master port to test + * + * Reads the port error status CSR for the master port to + * determine if the port has an active link. Returns + * %PORT_N_ERR_STS_PORT_OK if the master port is active + * or %0 if it is inactive. + */ +static int rio_mport_is_active(struct rio_mport *port) +{ + u32 result = 0; + u32 ext_ftr_ptr; + int *entry = rio_mport_phys_table; + + do { + if ((ext_ftr_ptr = + rio_mport_get_feature(port, 1, 0, 0, *entry))) + break; + } while (*++entry >= 0); + + if (ext_ftr_ptr) + rio_local_read_config_32(port, + ext_ftr_ptr + + RIO_PORT_N_ERR_STS_CSR(port->index), + &result); + + return (result & PORT_N_ERR_STS_PORT_OK); +} + +/** + * rio_alloc_net- Allocate and configure a new RIO network + * @port: Master port associated with the RIO network + * + * Allocates a RIO network structure, initializes per-network + * list heads, and adds the associated master port to the + * network list of associated master ports. Returns a + * RIO network pointer on success or %NULL on failure. + */ +static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port) +{ + struct rio_net *net; + + net = kmalloc(sizeof(struct rio_net), GFP_KERNEL); + if (net) { + memset(net, 0, sizeof(struct rio_net)); + INIT_LIST_HEAD(&net->node); + INIT_LIST_HEAD(&net->devices); + INIT_LIST_HEAD(&net->mports); + list_add_tail(&port->nnode, &net->mports); + net->hport = port; + net->id = next_net++; + } + return net; +} + +/** + * rio_enum_mport- Start enumeration through a master port + * @mport: Master port to send transactions + * + * Starts the enumeration process. If somebody has enumerated our + * master port device, then give up. If not and we have an active + * link, then start recursive peer enumeration. Returns %0 if + * enumeration succeeds or %-EBUSY if enumeration fails. + */ +int rio_enum_mport(struct rio_mport *mport) +{ + struct rio_net *net = NULL; + int rc = 0; + + printk(KERN_INFO "RIO: enumerate master port %d, %s\n", mport->id, + mport->name); + /* If somebody else enumerated our master port device, bail. */ + if (rio_enum_host(mport) < 0) { + printk(KERN_INFO + "RIO: master port %d device has been enumerated by a remote host\n", + mport->id); + rc = -EBUSY; + goto out; + } + + /* If master port has an active link, allocate net and enum peers */ + if (rio_mport_is_active(mport)) { + if (!(net = rio_alloc_net(mport))) { + printk(KERN_ERR "RIO: failed to allocate new net\n"); + rc = -ENOMEM; + goto out; + } + if (rio_enum_peer(net, mport, 0) < 0) { + /* A higher priority host won enumeration, bail. */ + printk(KERN_INFO + "RIO: master port %d device has lost enumeration to a remote host\n", + mport->id); + rio_clear_locks(mport); + rc = -EBUSY; + goto out; + } + rio_clear_locks(mport); + } else { + printk(KERN_INFO "RIO: master port %d link inactive\n", + mport->id); + rc = -EINVAL; + } + + out: + return rc; +} + +/** + * rio_build_route_tables- Generate route tables from switch route entries + * + * For each switch device, generate a route table by copying existing + * route entries from the switch. + */ +static void rio_build_route_tables(void) +{ + struct rio_dev *rdev; + int i; + u8 sport; + + list_for_each_entry(rdev, &rio_devices, global_list) + if (rio_is_switch(rdev)) + for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) { + if (rio_route_get_entry + (rdev->net->hport, rdev, RIO_GLOBAL_TABLE, i, + &sport) < 0) + continue; + rdev->rswitch->route_table[i] = sport; + } +} + +/** + * rio_enum_timeout- Signal that enumeration timed out + * @data: Address of timeout flag. + * + * When the enumeration complete timer expires, set a flag that + * signals to the discovery process that enumeration did not + * complete in a sane amount of time. + */ +static void rio_enum_timeout(unsigned long data) +{ + /* Enumeration timed out, set flag */ + *(int *)data = 1; +} + +/** + * rio_disc_mport- Start discovery through a master port + * @mport: Master port to send transactions + * + * Starts the discovery process. If we have an active link, + * then wait for the signal that enumeration is complete. + * When enumeration completion is signaled, start recursive + * peer discovery. Returns %0 if discovery succeeds or %-EBUSY + * on failure. + */ +int rio_disc_mport(struct rio_mport *mport) +{ + struct rio_net *net = NULL; + int enum_timeout_flag = 0; + + printk(KERN_INFO "RIO: discover master port %d, %s\n", mport->id, + mport->name); + + /* If master port has an active link, allocate net and discover peers */ + if (rio_mport_is_active(mport)) { + if (!(net = rio_alloc_net(mport))) { + printk(KERN_ERR "RIO: Failed to allocate new net\n"); + goto bail; + } + + pr_debug("RIO: wait for enumeration complete..."); + + rio_enum_timer.expires = + jiffies + CONFIG_RAPIDIO_DISC_TIMEOUT * HZ; + rio_enum_timer.data = (unsigned long)&enum_timeout_flag; + add_timer(&rio_enum_timer); + while (!rio_enum_complete(mport)) { + mdelay(1); + if (enum_timeout_flag) { + del_timer_sync(&rio_enum_timer); + goto timeout; + } + } + del_timer_sync(&rio_enum_timer); + + pr_debug("done\n"); + if (rio_disc_peer(net, mport, RIO_ANY_DESTID, 0) < 0) { + printk(KERN_INFO + "RIO: master port %d device has failed discovery\n", + mport->id); + goto bail; + } + + rio_build_route_tables(); + } + + return 0; + + timeout: + pr_debug("timeout\n"); + bail: + return -EBUSY; +} diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c new file mode 100644 index 0000000000000000000000000000000000000000..30a11436e2411acd05f20d019bbf4e1f96791348 --- /dev/null +++ b/drivers/rapidio/rio-sysfs.c @@ -0,0 +1,230 @@ +/* + * RapidIO sysfs attributes and support + * + * Copyright 2005 MontaVista Software, Inc. + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include + +#include "rio.h" + +/* Sysfs support */ +#define rio_config_attr(field, format_string) \ +static ssize_t \ +field##_show(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + struct rio_dev *rdev = to_rio_dev(dev); \ + \ + return sprintf(buf, format_string, rdev->field); \ +} \ + +rio_config_attr(did, "0x%04x\n"); +rio_config_attr(vid, "0x%04x\n"); +rio_config_attr(device_rev, "0x%08x\n"); +rio_config_attr(asm_did, "0x%04x\n"); +rio_config_attr(asm_vid, "0x%04x\n"); +rio_config_attr(asm_rev, "0x%04x\n"); + +static ssize_t routes_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct rio_dev *rdev = to_rio_dev(dev); + char *str = buf; + int i; + + if (!rdev->rswitch) + goto out; + + for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++) { + if (rdev->rswitch->route_table[i] == RIO_INVALID_ROUTE) + continue; + str += + sprintf(str, "%04x %02x\n", i, + rdev->rswitch->route_table[i]); + } + + out: + return (str - buf); +} + +struct device_attribute rio_dev_attrs[] = { + __ATTR_RO(did), + __ATTR_RO(vid), + __ATTR_RO(device_rev), + __ATTR_RO(asm_did), + __ATTR_RO(asm_vid), + __ATTR_RO(asm_rev), + __ATTR_RO(routes), + __ATTR_NULL, +}; + +static ssize_t +rio_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + struct rio_dev *dev = + to_rio_dev(container_of(kobj, struct device, kobj)); + unsigned int size = 0x100; + loff_t init_off = off; + u8 *data = (u8 *) buf; + + /* Several chips lock up trying to read undefined config space */ + if (capable(CAP_SYS_ADMIN)) + size = 0x200000; + + if (off > size) + return 0; + if (off + count > size) { + size -= off; + count = size; + } else { + size = count; + } + + if ((off & 1) && size) { + u8 val; + rio_read_config_8(dev, off, &val); + data[off - init_off] = val; + off++; + size--; + } + + if ((off & 3) && size > 2) { + u16 val; + rio_read_config_16(dev, off, &val); + data[off - init_off] = (val >> 8) & 0xff; + data[off - init_off + 1] = val & 0xff; + off += 2; + size -= 2; + } + + while (size > 3) { + u32 val; + rio_read_config_32(dev, off, &val); + data[off - init_off] = (val >> 24) & 0xff; + data[off - init_off + 1] = (val >> 16) & 0xff; + data[off - init_off + 2] = (val >> 8) & 0xff; + data[off - init_off + 3] = val & 0xff; + off += 4; + size -= 4; + } + + if (size >= 2) { + u16 val; + rio_read_config_16(dev, off, &val); + data[off - init_off] = (val >> 8) & 0xff; + data[off - init_off + 1] = val & 0xff; + off += 2; + size -= 2; + } + + if (size > 0) { + u8 val; + rio_read_config_8(dev, off, &val); + data[off - init_off] = val; + off++; + --size; + } + + return count; +} + +static ssize_t +rio_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + struct rio_dev *dev = + to_rio_dev(container_of(kobj, struct device, kobj)); + unsigned int size = count; + loff_t init_off = off; + u8 *data = (u8 *) buf; + + if (off > 0x200000) + return 0; + if (off + count > 0x200000) { + size = 0x200000 - off; + count = size; + } + + if ((off & 1) && size) { + rio_write_config_8(dev, off, data[off - init_off]); + off++; + size--; + } + + if ((off & 3) && (size > 2)) { + u16 val = data[off - init_off + 1]; + val |= (u16) data[off - init_off] << 8; + rio_write_config_16(dev, off, val); + off += 2; + size -= 2; + } + + while (size > 3) { + u32 val = data[off - init_off + 3]; + val |= (u32) data[off - init_off + 2] << 8; + val |= (u32) data[off - init_off + 1] << 16; + val |= (u32) data[off - init_off] << 24; + rio_write_config_32(dev, off, val); + off += 4; + size -= 4; + } + + if (size >= 2) { + u16 val = data[off - init_off + 1]; + val |= (u16) data[off - init_off] << 8; + rio_write_config_16(dev, off, val); + off += 2; + size -= 2; + } + + if (size) { + rio_write_config_8(dev, off, data[off - init_off]); + off++; + --size; + } + + return count; +} + +static struct bin_attribute rio_config_attr = { + .attr = { + .name = "config", + .mode = S_IRUGO | S_IWUSR, + .owner = THIS_MODULE, + }, + .size = 0x200000, + .read = rio_read_config, + .write = rio_write_config, +}; + +/** + * rio_create_sysfs_dev_files - create RIO specific sysfs files + * @rdev: device whose entries should be created + * + * Create files when @rdev is added to sysfs. + */ +int rio_create_sysfs_dev_files(struct rio_dev *rdev) +{ + sysfs_create_bin_file(&rdev->dev.kobj, &rio_config_attr); + + return 0; +} + +/** + * rio_remove_sysfs_dev_files - cleanup RIO specific sysfs files + * @rdev: device whose entries we should free + * + * Cleanup when @rdev is removed from sysfs. + */ +void rio_remove_sysfs_dev_files(struct rio_dev *rdev) +{ + sysfs_remove_bin_file(&rdev->dev.kobj, &rio_config_attr); +} diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c new file mode 100644 index 0000000000000000000000000000000000000000..3ca1011ceaac7fa24b6b2e42c2365201d9495188 --- /dev/null +++ b/drivers/rapidio/rio.c @@ -0,0 +1,510 @@ +/* + * RapidIO interconnect services + * (RapidIO Interconnect Specification, http://www.rapidio.org) + * + * Copyright 2005 MontaVista Software, Inc. + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rio.h" + +static LIST_HEAD(rio_mports); + +/** + * rio_local_get_device_id - Get the base/extended device id for a port + * @port: RIO master port from which to get the deviceid + * + * Reads the base/extended device id from the local device + * implementing the master port. Returns the 8/16-bit device + * id. + */ +u16 rio_local_get_device_id(struct rio_mport *port) +{ + u32 result; + + rio_local_read_config_32(port, RIO_DID_CSR, &result); + + return (RIO_GET_DID(result)); +} + +/** + * rio_request_inb_mbox - request inbound mailbox service + * @mport: RIO master port from which to allocate the mailbox resource + * @dev_id: Device specific pointer to pass on event + * @mbox: Mailbox number to claim + * @entries: Number of entries in inbound mailbox queue + * @minb: Callback to execute when inbound message is received + * + * Requests ownership of an inbound mailbox resource and binds + * a callback function to the resource. Returns %0 on success. + */ +int rio_request_inb_mbox(struct rio_mport *mport, + void *dev_id, + int mbox, + int entries, + void (*minb) (struct rio_mport * mport, void *dev_id, int mbox, + int slot)) +{ + int rc = 0; + + struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL); + + if (res) { + rio_init_mbox_res(res, mbox, mbox); + + /* Make sure this mailbox isn't in use */ + if ((rc = + request_resource(&mport->riores[RIO_INB_MBOX_RESOURCE], + res)) < 0) { + kfree(res); + goto out; + } + + mport->inb_msg[mbox].res = res; + + /* Hook the inbound message callback */ + mport->inb_msg[mbox].mcback = minb; + + rc = rio_open_inb_mbox(mport, dev_id, mbox, entries); + } else + rc = -ENOMEM; + + out: + return rc; +} + +/** + * rio_release_inb_mbox - release inbound mailbox message service + * @mport: RIO master port from which to release the mailbox resource + * @mbox: Mailbox number to release + * + * Releases ownership of an inbound mailbox resource. Returns 0 + * if the request has been satisfied. + */ +int rio_release_inb_mbox(struct rio_mport *mport, int mbox) +{ + rio_close_inb_mbox(mport, mbox); + + /* Release the mailbox resource */ + return release_resource(mport->inb_msg[mbox].res); +} + +/** + * rio_request_outb_mbox - request outbound mailbox service + * @mport: RIO master port from which to allocate the mailbox resource + * @dev_id: Device specific pointer to pass on event + * @mbox: Mailbox number to claim + * @entries: Number of entries in outbound mailbox queue + * @moutb: Callback to execute when outbound message is sent + * + * Requests ownership of an outbound mailbox resource and binds + * a callback function to the resource. Returns 0 on success. + */ +int rio_request_outb_mbox(struct rio_mport *mport, + void *dev_id, + int mbox, + int entries, + void (*moutb) (struct rio_mport * mport, void *dev_id, int mbox, int slot)) +{ + int rc = 0; + + struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL); + + if (res) { + rio_init_mbox_res(res, mbox, mbox); + + /* Make sure this outbound mailbox isn't in use */ + if ((rc = + request_resource(&mport->riores[RIO_OUTB_MBOX_RESOURCE], + res)) < 0) { + kfree(res); + goto out; + } + + mport->outb_msg[mbox].res = res; + + /* Hook the inbound message callback */ + mport->outb_msg[mbox].mcback = moutb; + + rc = rio_open_outb_mbox(mport, dev_id, mbox, entries); + } else + rc = -ENOMEM; + + out: + return rc; +} + +/** + * rio_release_outb_mbox - release outbound mailbox message service + * @mport: RIO master port from which to release the mailbox resource + * @mbox: Mailbox number to release + * + * Releases ownership of an inbound mailbox resource. Returns 0 + * if the request has been satisfied. + */ +int rio_release_outb_mbox(struct rio_mport *mport, int mbox) +{ + rio_close_outb_mbox(mport, mbox); + + /* Release the mailbox resource */ + return release_resource(mport->outb_msg[mbox].res); +} + +/** + * rio_setup_inb_dbell - bind inbound doorbell callback + * @mport: RIO master port to bind the doorbell callback + * @dev_id: Device specific pointer to pass on event + * @res: Doorbell message resource + * @dinb: Callback to execute when doorbell is received + * + * Adds a doorbell resource/callback pair into a port's + * doorbell event list. Returns 0 if the request has been + * satisfied. + */ +static int +rio_setup_inb_dbell(struct rio_mport *mport, void *dev_id, struct resource *res, + void (*dinb) (struct rio_mport * mport, void *dev_id, u16 src, u16 dst, + u16 info)) +{ + int rc = 0; + struct rio_dbell *dbell; + + if (!(dbell = kmalloc(sizeof(struct rio_dbell), GFP_KERNEL))) { + rc = -ENOMEM; + goto out; + } + + dbell->res = res; + dbell->dinb = dinb; + dbell->dev_id = dev_id; + + list_add_tail(&dbell->node, &mport->dbells); + + out: + return rc; +} + +/** + * rio_request_inb_dbell - request inbound doorbell message service + * @mport: RIO master port from which to allocate the doorbell resource + * @dev_id: Device specific pointer to pass on event + * @start: Doorbell info range start + * @end: Doorbell info range end + * @dinb: Callback to execute when doorbell is received + * + * Requests ownership of an inbound doorbell resource and binds + * a callback function to the resource. Returns 0 if the request + * has been satisfied. + */ +int rio_request_inb_dbell(struct rio_mport *mport, + void *dev_id, + u16 start, + u16 end, + void (*dinb) (struct rio_mport * mport, void *dev_id, u16 src, + u16 dst, u16 info)) +{ + int rc = 0; + + struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL); + + if (res) { + rio_init_dbell_res(res, start, end); + + /* Make sure these doorbells aren't in use */ + if ((rc = + request_resource(&mport->riores[RIO_DOORBELL_RESOURCE], + res)) < 0) { + kfree(res); + goto out; + } + + /* Hook the doorbell callback */ + rc = rio_setup_inb_dbell(mport, dev_id, res, dinb); + } else + rc = -ENOMEM; + + out: + return rc; +} + +/** + * rio_release_inb_dbell - release inbound doorbell message service + * @mport: RIO master port from which to release the doorbell resource + * @start: Doorbell info range start + * @end: Doorbell info range end + * + * Releases ownership of an inbound doorbell resource and removes + * callback from the doorbell event list. Returns 0 if the request + * has been satisfied. + */ +int rio_release_inb_dbell(struct rio_mport *mport, u16 start, u16 end) +{ + int rc = 0, found = 0; + struct rio_dbell *dbell; + + list_for_each_entry(dbell, &mport->dbells, node) { + if ((dbell->res->start == start) && (dbell->res->end == end)) { + found = 1; + break; + } + } + + /* If we can't find an exact match, fail */ + if (!found) { + rc = -EINVAL; + goto out; + } + + /* Delete from list */ + list_del(&dbell->node); + + /* Release the doorbell resource */ + rc = release_resource(dbell->res); + + /* Free the doorbell event */ + kfree(dbell); + + out: + return rc; +} + +/** + * rio_request_outb_dbell - request outbound doorbell message range + * @rdev: RIO device from which to allocate the doorbell resource + * @start: Doorbell message range start + * @end: Doorbell message range end + * + * Requests ownership of a doorbell message range. Returns a resource + * if the request has been satisfied or %NULL on failure. + */ +struct resource *rio_request_outb_dbell(struct rio_dev *rdev, u16 start, + u16 end) +{ + struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL); + + if (res) { + rio_init_dbell_res(res, start, end); + + /* Make sure these doorbells aren't in use */ + if (request_resource(&rdev->riores[RIO_DOORBELL_RESOURCE], res) + < 0) { + kfree(res); + res = NULL; + } + } + + return res; +} + +/** + * rio_release_outb_dbell - release outbound doorbell message range + * @rdev: RIO device from which to release the doorbell resource + * @res: Doorbell resource to be freed + * + * Releases ownership of a doorbell message range. Returns 0 if the + * request has been satisfied. + */ +int rio_release_outb_dbell(struct rio_dev *rdev, struct resource *res) +{ + int rc = release_resource(res); + + kfree(res); + + return rc; +} + +/** + * rio_mport_get_feature - query for devices' extended features + * @port: Master port to issue transaction + * @local: Indicate a local master port or remote device access + * @destid: Destination ID of the device + * @hopcount: Number of switch hops to the device + * @ftr: Extended feature code + * + * Tell if a device supports a given RapidIO capability. + * Returns the offset of the requested extended feature + * block within the device's RIO configuration space or + * 0 in case the device does not support it. Possible + * values for @ftr: + * + * %RIO_EFB_PAR_EP_ID LP/LVDS EP Devices + * + * %RIO_EFB_PAR_EP_REC_ID LP/LVDS EP Recovery Devices + * + * %RIO_EFB_PAR_EP_FREE_ID LP/LVDS EP Free Devices + * + * %RIO_EFB_SER_EP_ID LP/Serial EP Devices + * + * %RIO_EFB_SER_EP_REC_ID LP/Serial EP Recovery Devices + * + * %RIO_EFB_SER_EP_FREE_ID LP/Serial EP Free Devices + */ +u32 +rio_mport_get_feature(struct rio_mport * port, int local, u16 destid, + u8 hopcount, int ftr) +{ + u32 asm_info, ext_ftr_ptr, ftr_header; + + if (local) + rio_local_read_config_32(port, RIO_ASM_INFO_CAR, &asm_info); + else + rio_mport_read_config_32(port, destid, hopcount, + RIO_ASM_INFO_CAR, &asm_info); + + ext_ftr_ptr = asm_info & RIO_EXT_FTR_PTR_MASK; + + while (ext_ftr_ptr) { + if (local) + rio_local_read_config_32(port, ext_ftr_ptr, + &ftr_header); + else + rio_mport_read_config_32(port, destid, hopcount, + ext_ftr_ptr, &ftr_header); + if (RIO_GET_BLOCK_ID(ftr_header) == ftr) + return ext_ftr_ptr; + if (!(ext_ftr_ptr = RIO_GET_BLOCK_PTR(ftr_header))) + break; + } + + return 0; +} + +/** + * rio_get_asm - Begin or continue searching for a RIO device by vid/did/asm_vid/asm_did + * @vid: RIO vid to match or %RIO_ANY_ID to match all vids + * @did: RIO did to match or %RIO_ANY_ID to match all dids + * @asm_vid: RIO asm_vid to match or %RIO_ANY_ID to match all asm_vids + * @asm_did: RIO asm_did to match or %RIO_ANY_ID to match all asm_dids + * @from: Previous RIO device found in search, or %NULL for new search + * + * Iterates through the list of known RIO devices. If a RIO device is + * found with a matching @vid, @did, @asm_vid, @asm_did, the reference + * count to the device is incrememted and a pointer to its device + * structure is returned. Otherwise, %NULL is returned. A new search + * is initiated by passing %NULL to the @from argument. Otherwise, if + * @from is not %NULL, searches continue from next device on the global + * list. The reference count for @from is always decremented if it is + * not %NULL. + */ +struct rio_dev *rio_get_asm(u16 vid, u16 did, + u16 asm_vid, u16 asm_did, struct rio_dev *from) +{ + struct list_head *n; + struct rio_dev *rdev; + + WARN_ON(in_interrupt()); + spin_lock(&rio_global_list_lock); + n = from ? from->global_list.next : rio_devices.next; + + while (n && (n != &rio_devices)) { + rdev = rio_dev_g(n); + if ((vid == RIO_ANY_ID || rdev->vid == vid) && + (did == RIO_ANY_ID || rdev->did == did) && + (asm_vid == RIO_ANY_ID || rdev->asm_vid == asm_vid) && + (asm_did == RIO_ANY_ID || rdev->asm_did == asm_did)) + goto exit; + n = n->next; + } + rdev = NULL; + exit: + rio_dev_put(from); + rdev = rio_dev_get(rdev); + spin_unlock(&rio_global_list_lock); + return rdev; +} + +/** + * rio_get_device - Begin or continue searching for a RIO device by vid/did + * @vid: RIO vid to match or %RIO_ANY_ID to match all vids + * @did: RIO did to match or %RIO_ANY_ID to match all dids + * @from: Previous RIO device found in search, or %NULL for new search + * + * Iterates through the list of known RIO devices. If a RIO device is + * found with a matching @vid and @did, the reference count to the + * device is incrememted and a pointer to its device structure is returned. + * Otherwise, %NULL is returned. A new search is initiated by passing %NULL + * to the @from argument. Otherwise, if @from is not %NULL, searches + * continue from next device on the global list. The reference count for + * @from is always decremented if it is not %NULL. + */ +struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *from) +{ + return rio_get_asm(vid, did, RIO_ANY_ID, RIO_ANY_ID, from); +} + +static void rio_fixup_device(struct rio_dev *dev) +{ +} + +static int __devinit rio_init(void) +{ + struct rio_dev *dev = NULL; + + while ((dev = rio_get_device(RIO_ANY_ID, RIO_ANY_ID, dev)) != NULL) { + rio_fixup_device(dev); + } + return 0; +} + +device_initcall(rio_init); + +int rio_init_mports(void) +{ + int rc = 0; + struct rio_mport *port; + + list_for_each_entry(port, &rio_mports, node) { + if (!request_mem_region(port->iores.start, + port->iores.end - port->iores.start, + port->name)) { + printk(KERN_ERR + "RIO: Error requesting master port region %8.8lx-%8.8lx\n", + port->iores.start, port->iores.end - 1); + rc = -ENOMEM; + goto out; + } + + if (port->host_deviceid >= 0) + rio_enum_mport(port); + else + rio_disc_mport(port); + } + + out: + return rc; +} + +void rio_register_mport(struct rio_mport *port) +{ + list_add_tail(&port->node, &rio_mports); +} + +EXPORT_SYMBOL_GPL(rio_local_get_device_id); +EXPORT_SYMBOL_GPL(rio_get_device); +EXPORT_SYMBOL_GPL(rio_get_asm); +EXPORT_SYMBOL_GPL(rio_request_inb_dbell); +EXPORT_SYMBOL_GPL(rio_release_inb_dbell); +EXPORT_SYMBOL_GPL(rio_request_outb_dbell); +EXPORT_SYMBOL_GPL(rio_release_outb_dbell); +EXPORT_SYMBOL_GPL(rio_request_inb_mbox); +EXPORT_SYMBOL_GPL(rio_release_inb_mbox); +EXPORT_SYMBOL_GPL(rio_request_outb_mbox); +EXPORT_SYMBOL_GPL(rio_release_outb_mbox); diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h new file mode 100644 index 0000000000000000000000000000000000000000..b242cee656e77e5bf1a57069e15db0517b389ee2 --- /dev/null +++ b/drivers/rapidio/rio.h @@ -0,0 +1,60 @@ +/* + * RapidIO interconnect services + * + * Copyright 2005 MontaVista Software, Inc. + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include + +/* Functions internal to the RIO core code */ + +extern u32 rio_mport_get_feature(struct rio_mport *mport, int local, u16 destid, + u8 hopcount, int ftr); +extern int rio_create_sysfs_dev_files(struct rio_dev *rdev); +extern int rio_enum_mport(struct rio_mport *mport); +extern int rio_disc_mport(struct rio_mport *mport); + +/* Structures internal to the RIO core code */ +extern struct device_attribute rio_dev_attrs[]; +extern spinlock_t rio_global_list_lock; + +extern struct rio_route_ops __start_rio_route_ops[]; +extern struct rio_route_ops __end_rio_route_ops[]; + +/* Helpers internal to the RIO core code */ +#define DECLARE_RIO_ROUTE_SECTION(section, vid, did, add_hook, get_hook) \ + static struct rio_route_ops __rio_route_ops __attribute_used__ \ + __attribute__((__section__(#section))) = { vid, did, add_hook, get_hook }; + +/** + * DECLARE_RIO_ROUTE_OPS - Registers switch routing operations + * @vid: RIO vendor ID + * @did: RIO device ID + * @add_hook: Callback that adds a route entry + * @get_hook: Callback that gets a route entry + * + * Manipulating switch route tables in RIO is switch specific. This + * registers a switch by vendor and device ID with two callbacks for + * modifying and retrieving route entries in a switch. A &struct + * rio_route_ops is initialized with the ops and placed into a + * RIO-specific kernel section. + */ +#define DECLARE_RIO_ROUTE_OPS(vid, did, add_hook, get_hook) \ + DECLARE_RIO_ROUTE_SECTION(.rio_route_ops, \ + vid, did, add_hook, get_hook) + +#ifdef CONFIG_RAPIDIO_8_BIT_TRANSPORT +#define RIO_GET_DID(x) ((x & 0x00ff0000) >> 16) +#define RIO_SET_DID(x) ((x & 0x000000ff) << 16) +#else +#define RIO_GET_DID(x) (x & 0xffff) +#define RIO_SET_DID(x) (x & 0xffff) +#endif diff --git a/drivers/rapidio/switches/Makefile b/drivers/rapidio/switches/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b924f830176116169608c602f8509e85fce96ff3 --- /dev/null +++ b/drivers/rapidio/switches/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for RIO switches +# + +obj-$(CONFIG_RAPIDIO) += tsi500.o diff --git a/drivers/rapidio/switches/tsi500.c b/drivers/rapidio/switches/tsi500.c new file mode 100644 index 0000000000000000000000000000000000000000..c77c23bd9840d8e76c4a6b11d218f1ac17fbd08a --- /dev/null +++ b/drivers/rapidio/switches/tsi500.c @@ -0,0 +1,60 @@ +/* + * RapidIO Tsi500 switch support + * + * Copyright 2005 MontaVista Software, Inc. + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include "../rio.h" + +static int +tsi500_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, u16 table, u16 route_destid, u8 route_port) +{ + int i; + u32 offset = 0x10000 + 0xa00 + ((route_destid / 2)&~0x3); + u32 result; + + if (table == 0xff) { + rio_mport_read_config_32(mport, destid, hopcount, offset, &result); + result &= ~(0xf << (4*(route_destid & 0x7))); + for (i=0;i<4;i++) + rio_mport_write_config_32(mport, destid, hopcount, offset + (0x20000*i), result | (route_port << (4*(route_destid & 0x7)))); + } + else { + rio_mport_read_config_32(mport, destid, hopcount, offset + (0x20000*table), &result); + result &= ~(0xf << (4*(route_destid & 0x7))); + rio_mport_write_config_32(mport, destid, hopcount, offset + (0x20000*table), result | (route_port << (4*(route_destid & 0x7)))); + } + + return 0; +} + +static int +tsi500_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, u16 table, u16 route_destid, u8 *route_port) +{ + int ret = 0; + u32 offset = 0x10000 + 0xa00 + ((route_destid / 2)&~0x3); + u32 result; + + if (table == 0xff) + rio_mport_read_config_32(mport, destid, hopcount, offset, &result); + else + rio_mport_read_config_32(mport, destid, hopcount, offset + (0x20000*table), &result); + + result &= 0xf << (4*(route_destid & 0x7)); + *route_port = result >> (4*(route_destid & 0x7)); + if (*route_port > 3) + ret = -1; + + return ret; +} + +DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI500, tsi500_route_add_entry, tsi500_route_get_entry); diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 8fc891a9d47f569b823c02ed7dc85855f464fd0c..7008d32433bf9d12725748f67d8d7c8bc746678b 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -115,8 +115,7 @@ dasd_alloc_device(void) void dasd_free_device(struct dasd_device *device) { - if (device->private) - kfree(device->private); + kfree(device->private); free_page((unsigned long) device->erp_mem); free_pages((unsigned long) device->ccw_mem, 1); kfree(device); @@ -539,8 +538,7 @@ dasd_kmalloc_request(char *magic, int cplength, int datasize, if (datasize > 0) { cqr->data = kmalloc(datasize, GFP_ATOMIC | GFP_DMA); if (cqr->data == NULL) { - if (cqr->cpaddr != NULL) - kfree(cqr->cpaddr); + kfree(cqr->cpaddr); kfree(cqr); return ERR_PTR(-ENOMEM); } @@ -615,10 +613,8 @@ dasd_kfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device) clear_normalized_cda(ccw); } while (ccw++->flags & (CCW_FLAG_CC | CCW_FLAG_DC)); #endif - if (cqr->cpaddr != NULL) - kfree(cqr->cpaddr); - if (cqr->data != NULL) - kfree(cqr->data); + kfree(cqr->cpaddr); + kfree(cqr->data); kfree(cqr); dasd_put_device(device); } diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index bda896d9d788f3b4ab83a694324c641a8b02223d..caee16a3dc624d48c3fbb84de7678c9557adbe5d 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -387,8 +387,7 @@ dasd_add_busid(char *bus_id, int features) new = 0; } spin_unlock(&dasd_devmap_lock); - if (new) - kfree(new); + kfree(new); return devmap; } diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 7478423b53bb2e6b1ae09f4296466c0998344e08..ab8754e566bcbdff183f22982dbe91d2ba431cac 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -6,7 +6,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.49 $ + * $Revision: 1.51 $ */ #include @@ -67,9 +67,9 @@ static const u8 DASD_DIAG_CMS1[] = { 0xc3, 0xd4, 0xe2, 0xf1 };/* EBCDIC CMS1 */ static __inline__ int dia250(void *iob, int cmd) { - typedef struct { - char _[max(sizeof (struct dasd_diag_init_io), - sizeof (struct dasd_diag_rw_io))]; + typedef union { + struct dasd_diag_init_io init_io; + struct dasd_diag_rw_io rw_io; } addr_type; int rc; @@ -190,7 +190,7 @@ dasd_start_diag(struct dasd_ccw_req * cqr) private->iob.flags = DASD_DIAG_RWFLAG_ASYNC; private->iob.block_count = dreq->block_count; private->iob.interrupt_params = (addr_t) cqr; - private->iob.bio_list = __pa(dreq->bio); + private->iob.bio_list = dreq->bio; private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT; cqr->startclk = get_clock(); @@ -394,47 +394,57 @@ dasd_diag_check_device(struct dasd_device *device) memset(&bio, 0, sizeof (struct dasd_diag_bio)); bio.type = MDSK_READ_REQ; bio.block_number = private->pt_block + 1; - bio.buffer = __pa(label); + bio.buffer = label; memset(&private->iob, 0, sizeof (struct dasd_diag_rw_io)); private->iob.dev_nr = rdc_data->dev_nr; private->iob.key = 0; private->iob.flags = 0; /* do synchronous io */ private->iob.block_count = 1; private->iob.interrupt_params = 0; - private->iob.bio_list = __pa(&bio); + private->iob.bio_list = &bio; private->iob.flaga = DASD_DIAG_FLAGA_DEFAULT; rc = dia250(&private->iob, RW_BIO); - if (rc == 0 || rc == 3) - break; + if (rc == 3) { + DEV_MESSAGE(KERN_WARNING, device, "%s", + "DIAG call failed"); + rc = -EOPNOTSUPP; + goto out; + } mdsk_term_io(device); + if (rc == 0) + break; } - if (rc == 3) { - DEV_MESSAGE(KERN_WARNING, device, "%s", "DIAG call failed"); - rc = -EOPNOTSUPP; - } else if (rc != 0) { + if (bsize > PAGE_SIZE) { DEV_MESSAGE(KERN_WARNING, device, "device access failed " "(rc=%d)", rc); rc = -EIO; + goto out; + } + /* check for label block */ + if (memcmp(label->label_id, DASD_DIAG_CMS1, + sizeof(DASD_DIAG_CMS1)) == 0) { + /* get formatted blocksize from label block */ + bsize = (unsigned int) label->block_size; + device->blocks = (unsigned long) label->block_count; + } else + device->blocks = end_block; + device->bp_block = bsize; + device->s2b_shift = 0; /* bits to shift 512 to get a block */ + for (sb = 512; sb < bsize; sb = sb << 1) + device->s2b_shift++; + rc = mdsk_init_io(device, device->bp_block, 0, NULL); + if (rc) { + DEV_MESSAGE(KERN_WARNING, device, "DIAG initialization " + "failed (rc=%d)", rc); + rc = -EIO; } else { - if (memcmp(label->label_id, DASD_DIAG_CMS1, - sizeof(DASD_DIAG_CMS1)) == 0) { - /* get formatted blocksize from label block */ - bsize = (unsigned int) label->block_size; - device->blocks = (unsigned long) label->block_count; - } else - device->blocks = end_block; - device->bp_block = bsize; - device->s2b_shift = 0; /* bits to shift 512 to get a block */ - for (sb = 512; sb < bsize; sb = sb << 1) - device->s2b_shift++; - DEV_MESSAGE(KERN_INFO, device, "(%ld B/blk): %ldkB", (unsigned long) device->bp_block, (unsigned long) (device->blocks << device->s2b_shift) >> 1); - rc = 0; } +out: free_page((long) label); return rc; } @@ -529,7 +539,7 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req) memset(dbio, 0, sizeof (struct dasd_diag_bio)); dbio->type = rw_cmd; dbio->block_number = recid + 1; - dbio->buffer = __pa(dst); + dbio->buffer = dst; dbio++; dst += blksize; recid++; diff --git a/drivers/s390/block/dasd_diag.h b/drivers/s390/block/dasd_diag.h index b26eb28df4bf093e4b6816275ba46d91d4236896..df31484d73a77a088cb388507db5ad556c457d47 100644 --- a/drivers/s390/block/dasd_diag.h +++ b/drivers/s390/block/dasd_diag.h @@ -6,7 +6,7 @@ * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 * - * $Revision: 1.7 $ + * $Revision: 1.8 $ */ #define MDSK_WRITE_REQ 0x01 @@ -78,7 +78,7 @@ struct dasd_diag_bio { u8 spare1[2]; u32 alet; blocknum_t block_number; - u64 buffer; + void *buffer; } __attribute__ ((packed, aligned(8))); struct dasd_diag_init_io { @@ -104,7 +104,7 @@ struct dasd_diag_rw_io { u32 alet; u8 spare3[4]; u64 interrupt_params; - u64 bio_list; + struct dasd_diag_bio *bio_list; u8 spare4[8]; } __attribute__ ((packed, aligned(8))); #else /* CONFIG_ARCH_S390X */ @@ -119,7 +119,7 @@ struct dasd_diag_bio { u16 spare1; blocknum_t block_number; u32 alet; - u32 buffer; + void *buffer; } __attribute__ ((packed, aligned(8))); struct dasd_diag_init_io { @@ -142,7 +142,7 @@ struct dasd_diag_rw_io { u8 spare2[2]; u32 block_count; u32 alet; - u32 bio_list; + struct dasd_diag_bio *bio_list; u32 interrupt_params; u8 spare3[20]; } __attribute__ ((packed, aligned(8))); diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index f11a67fda40e55a4a009ff04f16a6217b8fa76c1..75419cf9d35351b0b2c2a3cb1c3296046d1d7e51 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -727,8 +727,7 @@ raw3215_remove (struct ccw_device *cdev) raw = cdev->dev.driver_data; if (raw) { cdev->dev.driver_data = NULL; - if (raw->buffer) - kfree(raw->buffer); + kfree(raw->buffer); kfree(raw); } } diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c index fd43d99b45a3359382e17ebd208f643021352635..5bda2340a39d93a843fd1f090da240f0d1c6af36 100644 --- a/drivers/s390/char/keyboard.c +++ b/drivers/s390/char/keyboard.c @@ -99,13 +99,11 @@ kbd_alloc(void) { kfree(kbd->fn_handler); out_func: for (i = 0; i < ARRAY_SIZE(func_table); i++) - if (kbd->func_table[i]) - kfree(kbd->func_table[i]); + kfree(kbd->func_table[i]); kfree(kbd->func_table); out_maps: for (i = 0; i < ARRAY_SIZE(key_maps); i++) - if (kbd->key_maps[i]) - kfree(kbd->key_maps[i]); + kfree(kbd->key_maps[i]); kfree(kbd->key_maps); out_kbd: kfree(kbd); @@ -121,12 +119,10 @@ kbd_free(struct kbd_data *kbd) kfree(kbd->accent_table); kfree(kbd->fn_handler); for (i = 0; i < ARRAY_SIZE(func_table); i++) - if (kbd->func_table[i]) - kfree(kbd->func_table[i]); + kfree(kbd->func_table[i]); kfree(kbd->func_table); for (i = 0; i < ARRAY_SIZE(key_maps); i++) - if (kbd->key_maps[i]) - kfree(kbd->key_maps[i]); + kfree(kbd->key_maps[i]); kfree(kbd->key_maps); kfree(kbd); } @@ -452,8 +448,7 @@ do_kdgkb_ioctl(struct kbd_data *kbd, struct kbsentry __user *u_kbs, return -EFAULT; } p[len] = 0; - if (kbd->func_table[kb_func]) - kfree(kbd->func_table[kb_func]); + kfree(kbd->func_table[kb_func]); kbd->func_table[kb_func] = p; break; } diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index d66946443dfc19f3df8186bfa9fdd77fb48d9233..f5b7d360fc10ae5973003ad2cd25031b71976503 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -183,8 +183,7 @@ raw3270_request_alloc_bootmem(size_t size) void raw3270_request_free (struct raw3270_request *rq) { - if (rq->buffer) - kfree(rq->buffer); + kfree(rq->buffer); kfree(rq); } diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 6c52e8307dc54bdf009a853fead4619b38573ac8..8f486e1a85075657fd890c94b3016ab4f99a80f1 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -682,8 +682,7 @@ tape_alloc_request(int cplength, int datasize) request->cpdata = kmalloc(datasize, GFP_KERNEL | GFP_DMA); if (request->cpdata == NULL) { DBF_EXCEPTION(1, "cqra nomem\n"); - if (request->cpaddr != NULL) - kfree(request->cpaddr); + kfree(request->cpaddr); kfree(request); return ERR_PTR(-ENOMEM); } @@ -706,10 +705,8 @@ tape_free_request (struct tape_request * request) if (request->device != NULL) { request->device = tape_put_device(request->device); } - if (request->cpdata != NULL) - kfree(request->cpdata); - if (request->cpaddr != NULL) - kfree(request->cpaddr); + kfree(request->cpdata); + kfree(request->cpaddr); kfree(request); } diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 8990d8076e7da0733d7c8bb0a8b32fa55908af2d..19762f3476aadd22289d4ddb4a44d82985465bf4 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -103,8 +103,10 @@ vmcp_write(struct file *file, const char __user * buff, size_t count, } cmd[count] = '\0'; session = (struct vmcp_session *)file->private_data; - if (down_interruptible(&session->mutex)) + if (down_interruptible(&session->mutex)) { + kfree(cmd); return -ERESTARTSYS; + } if (!session->response) session->response = (char *)__get_free_pages(GFP_KERNEL | __GFP_REPEAT | GFP_DMA, diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index dbb3eb0e330b00d017ca7b98817d8f2fde5f4932..e7bd7f37f080615e2cfe12929d10e3d8c4062c26 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -1,7 +1,7 @@ /* * drivers/s390/cio/ccwgroup.c * bus driver for ccwgroup - * $Revision: 1.29 $ + * $Revision: 1.32 $ * * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -274,7 +274,7 @@ ccwgroup_set_online(struct ccwgroup_device *gdev) goto out; } gdrv = to_ccwgroupdrv (gdev->dev.driver); - if ((ret = gdrv->set_online(gdev))) + if ((ret = gdrv->set_online ? gdrv->set_online(gdev) : 0)) goto out; gdev->state = CCWGROUP_ONLINE; @@ -300,7 +300,7 @@ ccwgroup_set_offline(struct ccwgroup_device *gdev) goto out; } gdrv = to_ccwgroupdrv (gdev->dev.driver); - if ((ret = gdrv->set_offline(gdev))) + if ((ret = gdrv->set_offline ? gdrv->set_offline(gdev) : 0)) goto out; gdev->state = CCWGROUP_OFFLINE; diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index c05b069c29965e9894c5b87a5c6ce10627470eb9..b978f7fe8327546aca8a195f82183a1e87601af4 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -642,8 +642,7 @@ static void free_cmbe (struct ccw_device *cdev) { spin_lock_irq(cdev->ccwlock); - if (cdev->private->cmb) - kfree(cdev->private->cmb); + kfree(cdev->private->cmb); cdev->private->cmb = NULL; spin_unlock_irq(cdev->ccwlock); diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index ad3fe5aeb663a01d3f034cba4db8a879ec65e374..85a3026e6900a37c001d5ba48fa63ef63b27643e 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -550,10 +550,8 @@ ccw_device_stlck(struct ccw_device *cdev) /* Clear irb. */ memset(&cdev->private->irb, 0, sizeof(struct irb)); out_unlock: - if (buf) - kfree(buf); - if (buf2) - kfree(buf2); + kfree(buf); + kfree(buf2); spin_unlock_irqrestore(&sch->lock, flags); return ret; } diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 381f339e3200a9d98d2031d1d30495c18e713a62..eb39218b925e742b5d93ee2c3ca38279f87c136b 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -56,7 +56,7 @@ #include "ioasm.h" #include "chsc.h" -#define VERSION_QDIO_C "$Revision: 1.101 $" +#define VERSION_QDIO_C "$Revision: 1.108 $" /****************** MODULE PARAMETER VARIABLES ********************/ MODULE_AUTHOR("Utz Bacher "); @@ -1338,16 +1338,14 @@ qdio_release_irq_memory(struct qdio_irq *irq_ptr) if (!irq_ptr->input_qs[i]) goto next; - if (irq_ptr->input_qs[i]->slib) - kfree(irq_ptr->input_qs[i]->slib); + kfree(irq_ptr->input_qs[i]->slib); kfree(irq_ptr->input_qs[i]); next: if (!irq_ptr->output_qs[i]) continue; - if (irq_ptr->output_qs[i]->slib) - kfree(irq_ptr->output_qs[i]->slib); + kfree(irq_ptr->output_qs[i]->slib); kfree(irq_ptr->output_qs[i]); } @@ -2873,10 +2871,10 @@ qdio_establish(struct qdio_initialize *init_data) return result; } - wait_event_interruptible_timeout(cdev->private->wait_q, + /* Timeout is cared for already by using ccw_device_start_timeout(). */ + wait_event_interruptible(cdev->private->wait_q, irq_ptr->state == QDIO_IRQ_STATE_ESTABLISHED || - irq_ptr->state == QDIO_IRQ_STATE_ERR, - QDIO_ESTABLISH_TIMEOUT); + irq_ptr->state == QDIO_IRQ_STATE_ERR); if (irq_ptr->state == QDIO_IRQ_STATE_ESTABLISHED) result = 0; @@ -3315,8 +3313,7 @@ qdio_get_qdio_memory(void) static void qdio_release_qdio_memory(void) { - if (indicators) - kfree(indicators); + kfree(indicators); } static void diff --git a/drivers/s390/crypto/z90main.c b/drivers/s390/crypto/z90main.c index 0cb47eca91f3d9d459132ee34574da528c7f0831..04c2ef778ec69bc209bf830ab783a5234a56c108 100644 --- a/drivers/s390/crypto/z90main.c +++ b/drivers/s390/crypto/z90main.c @@ -3051,8 +3051,7 @@ destroy_crypto_device(int index) if (dev_ptr) { disabledFlag = dev_ptr->disabled; t = dev_ptr->dev_type; - if (dev_ptr->dev_resp_p) - kfree(dev_ptr->dev_resp_p); + kfree(dev_ptr->dev_resp_p); kfree(dev_ptr); } else { disabledFlag = 0; @@ -3080,11 +3079,11 @@ static void destroy_z90crypt(void) { int i; + for (i = 0; i < z90crypt.max_count; i++) if (z90crypt.device_p[i]) destroy_crypto_device(i); - if (z90crypt.hdware_info) - kfree((void *)z90crypt.hdware_info); + kfree(z90crypt.hdware_info); memset((void *)&z90crypt, 0, sizeof(z90crypt)); } diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 3092473991a7f7a934a7e242bd432de79c110b24..1a1c3decea728c0ec0ae48fcc50398e662d1ce41 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -2743,14 +2743,10 @@ probe_error( struct ccwgroup_device *cgdev) #endif privptr=(struct claw_privbk *)cgdev->dev.driver_data; if (privptr!=NULL) { - if (privptr->p_env != NULL) { - kfree(privptr->p_env); - privptr->p_env=NULL; - } - if (privptr->p_mtc_envelope!=NULL) { - kfree(privptr->p_mtc_envelope); - privptr->p_mtc_envelope=NULL; - } + kfree(privptr->p_env); + privptr->p_env=NULL; + kfree(privptr->p_mtc_envelope); + privptr->p_mtc_envelope=NULL; kfree(privptr); privptr=NULL; } @@ -4121,22 +4117,14 @@ claw_remove_device(struct ccwgroup_device *cgdev) if (cgdev->state == CCWGROUP_ONLINE) claw_shutdown_device(cgdev); claw_remove_files(&cgdev->dev); - if (priv->p_mtc_envelope!=NULL) { - kfree(priv->p_mtc_envelope); - priv->p_mtc_envelope=NULL; - } - if (priv->p_env != NULL) { - kfree(priv->p_env); - priv->p_env=NULL; - } - if (priv->channel[0].irb != NULL) { - kfree(priv->channel[0].irb); - priv->channel[0].irb=NULL; - } - if (priv->channel[1].irb != NULL) { - kfree(priv->channel[1].irb); - priv->channel[1].irb=NULL; - } + kfree(priv->p_mtc_envelope); + priv->p_mtc_envelope=NULL; + kfree(priv->p_env); + priv->p_env=NULL; + kfree(priv->channel[0].irb); + priv->channel[0].irb=NULL; + kfree(priv->channel[1].irb); + priv->channel[1].irb=NULL; kfree(priv); cgdev->dev.driver_data=NULL; cgdev->cdev[READ]->dev.driver_data = NULL; diff --git a/drivers/s390/net/fsm.c b/drivers/s390/net/fsm.c index 38f50b7129a24fce668493909b15d385de086db3..24029bd9c7d09e682fb97ab8397c4ff6b5c99b51 100644 --- a/drivers/s390/net/fsm.c +++ b/drivers/s390/net/fsm.c @@ -78,8 +78,7 @@ kfree_fsm(fsm_instance *this) { if (this) { if (this->f) { - if (this->f->jumpmatrix) - kfree(this->f->jumpmatrix); + kfree(this->f->jumpmatrix); kfree(this->f); } kfree(this); diff --git a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c index e08e74e16124704b1f7b8bede6092a2d1cab376e..df7647c3c100dcc14960b8c9cfd69766439751d0 100644 --- a/drivers/s390/net/iucv.c +++ b/drivers/s390/net/iucv.c @@ -447,14 +447,10 @@ static void iucv_exit(void) { iucv_retrieve_buffer(); - if (iucv_external_int_buffer) { - kfree(iucv_external_int_buffer); - iucv_external_int_buffer = NULL; - } - if (iucv_param_pool) { - kfree(iucv_param_pool); - iucv_param_pool = NULL; - } + kfree(iucv_external_int_buffer); + iucv_external_int_buffer = NULL; + kfree(iucv_param_pool); + iucv_param_pool = NULL; s390_root_dev_unregister(iucv_root); bus_unregister(&iucv_bus); printk(KERN_INFO "IUCV lowlevel driver unloaded\n"); diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 46f34ba93ac5c76de5a821a38e6d75eb94fafea6..1c8ad2fcad8a59d2d67270de4cde2a5cdc43127d 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -145,8 +145,7 @@ lcs_free_channel(struct lcs_channel *channel) LCS_DBF_TEXT(2, setup, "ichfree"); for (cnt = 0; cnt < LCS_NUM_BUFFS; cnt++) { - if (channel->iob[cnt].data != NULL) - kfree(channel->iob[cnt].data); + kfree(channel->iob[cnt].data); channel->iob[cnt].data = NULL; } } diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c index f94f1f25eec60a8e57ba9d311a90c47b2df58594..011915d5e243c885eccca9e7e3d1131e08963b29 100644 --- a/drivers/s390/net/qeth_eddp.c +++ b/drivers/s390/net/qeth_eddp.c @@ -62,8 +62,7 @@ qeth_eddp_free_context(struct qeth_eddp_context *ctx) for (i = 0; i < ctx->num_pages; ++i) free_page((unsigned long)ctx->pages[i]); kfree(ctx->pages); - if (ctx->elements != NULL) - kfree(ctx->elements); + kfree(ctx->elements); kfree(ctx); } diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index cab098556b44577f3178c040f0daf02bcf9ab1f0..c218b5c944a6f1d54f2f89df3bc8994fee3c9a23 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -450,8 +450,7 @@ zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, kfree(sg_list); } - if (sense_data != NULL) - kfree(sense_data); + kfree(sense_data); return retval; } diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c index c82abeb59d3aa858fefd1b46cae9f98ff44dac7e..071ae24be8925b13ddbc03dae77a39d3e4e9de26 100644 --- a/drivers/sbus/char/cpwatchdog.c +++ b/drivers/sbus/char/cpwatchdog.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -394,6 +395,28 @@ static int wd_ioctl(struct inode *inode, struct file *file, return(0); } +static long wd_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int rval = -ENOIOCTLCMD; + + switch (cmd) { + /* solaris ioctls are specific to this driver */ + case WIOCSTART: + case WIOCSTOP: + case WIOCGSTAT: + lock_kernel(); + rval = wd_ioctl(file->f_dentry->d_inode, file, cmd, arg); + lock_kernel(); + break; + /* everything else is handled by the generic compat layer */ + default: + break; + } + + return rval; +} + static ssize_t wd_write(struct file *file, const char __user *buf, size_t count, @@ -441,6 +464,7 @@ static irqreturn_t wd_interrupt(int irq, void *dev_id, struct pt_regs *regs) static struct file_operations wd_fops = { .owner = THIS_MODULE, .ioctl = wd_ioctl, + .compat_ioctl = wd_compat_ioctl, .open = wd_open, .write = wd_write, .read = wd_read, diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c index 24ed5893b4f047f3ca3f74c565afa59fa145555d..39f54213a6d5545b0b0ca53c851998c3ded071c0 100644 --- a/drivers/sbus/char/display7seg.c +++ b/drivers/sbus/char/display7seg.c @@ -15,6 +15,7 @@ #include #include #include /* request_region */ +#include #include #include /* EBus device */ #include /* OpenProm Library */ @@ -114,22 +115,25 @@ static int d7s_release(struct inode *inode, struct file *f) return 0; } -static int d7s_ioctl(struct inode *inode, struct file *f, - unsigned int cmd, unsigned long arg) +static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { __u8 regs = readb(d7s_regs); __u8 ireg = 0; + int error = 0 - if (D7S_MINOR != iminor(inode)) + if (D7S_MINOR != iminor(file->f_dentry->d_inode)) return -ENODEV; + lock_kernel(); switch (cmd) { case D7SIOCWR: /* assign device register values * we mask-out D7S_FLIP if in sol_compat mode */ - if (get_user(ireg, (int __user *) arg)) - return -EFAULT; + if (get_user(ireg, (int __user *) arg)) { + error = -EFAULT; + break; + } if (0 != sol_compat) { (regs & D7S_FLIP) ? (ireg |= D7S_FLIP) : (ireg &= ~D7S_FLIP); @@ -144,8 +148,10 @@ static int d7s_ioctl(struct inode *inode, struct file *f, * This driver will not misinform you about the state * of your hardware while in sol_compat mode */ - if (put_user(regs, (int __user *) arg)) - return -EFAULT; + if (put_user(regs, (int __user *) arg)) { + error = -EFAULT; + break; + } break; case D7SIOCTM: @@ -155,15 +161,17 @@ static int d7s_ioctl(struct inode *inode, struct file *f, writeb(regs, d7s_regs); break; }; + lock_kernel(); - return 0; + return error; } static struct file_operations d7s_fops = { - .owner = THIS_MODULE, - .ioctl = d7s_ioctl, - .open = d7s_open, - .release = d7s_release, + .owner = THIS_MODULE, + .unlocked_ioctl = d7s_ioctl, + .compat_ioctl = d7s_ioctl, + .open = d7s_open, + .release = d7s_release, }; static struct miscdevice d7s_miscdev = { D7S_MINOR, D7S_DEVNAME, &d7s_fops }; diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index b0cc3c2588fdd44074cf6ae873c920489b0a111f..19e8eddf887a8538325307d135d38883d3dbb08c 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -654,9 +654,8 @@ envctrl_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) /* Function Description: Command what to read. Mapped to user ioctl(). * Return: Gives 0 for implemented commands, -EINVAL otherwise. */ -static int -envctrl_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long +envctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { char __user *infobuf; @@ -715,11 +714,14 @@ envctrl_release(struct inode *inode, struct file *file) } static struct file_operations envctrl_fops = { - .owner = THIS_MODULE, - .read = envctrl_read, - .ioctl = envctrl_ioctl, - .open = envctrl_open, - .release = envctrl_release, + .owner = THIS_MODULE, + .read = envctrl_read, + .unlocked_ioctl = envctrl_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = envctrl_ioctl, +#endif + .open = envctrl_open, + .release = envctrl_release, }; static struct miscdevice envctrl_dev = { @@ -1125,10 +1127,9 @@ static int __init envctrl_init(void) misc_deregister(&envctrl_dev); out_iounmap: iounmap(i2c); - for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++) { - if (i2c_childlist[i].tables) - kfree(i2c_childlist[i].tables); - } + for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++) + kfree(i2c_childlist[i].tables); + return err; } @@ -1141,10 +1142,8 @@ static void __exit envctrl_cleanup(void) iounmap(i2c); misc_deregister(&envctrl_dev); - for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++) { - if (i2c_childlist[i].tables) - kfree(i2c_childlist[i].tables); - } + for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++) + kfree(i2c_childlist[i].tables); } module_init(envctrl_init); diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index 58ed33749571dde2078dd3bc28538bbc49be430c..383a95f34a0da4e8adec682df992786d572efe27 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -565,6 +566,40 @@ static int openprom_ioctl(struct inode * inode, struct file * file, } } +static long openprom_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + long rval = -ENOTTY; + + /* + * SunOS/Solaris only, the NetBSD one's have embedded pointers in + * the arg which we'd need to clean up... + */ + switch (cmd) { + case OPROMGETOPT: + case OPROMSETOPT: + case OPROMNXTOPT: + case OPROMSETOPT2: + case OPROMNEXT: + case OPROMCHILD: + case OPROMGETPROP: + case OPROMNXTPROP: + case OPROMU2P: + case OPROMGETCONS: + case OPROMGETFBNAME: + case OPROMGETBOOTARGS: + case OPROMSETCUR: + case OPROMPCI2NODE: + case OPROMPATH2NODE: + lock_kernel(); + rval = openprom_ioctl(file->f_dentry->d_inode, file, cmd, arg); + lock_kernel(); + break; + } + + return rval; +} + static int openprom_open(struct inode * inode, struct file * file) { DATA *data; @@ -590,6 +625,7 @@ static struct file_operations openprom_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .ioctl = openprom_ioctl, + .compat_ioctl = openprom_compat_ioctl, .open = openprom_open, .release = openprom_release, }; diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index d06ee65d668d845676d3886c001578073f038be6..3ff74f472249bb638a30933389b9046e75862633 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -1017,8 +1017,7 @@ static void twa_free_device_extension(TW_Device_Extension *tw_dev) tw_dev->generic_buffer_virt[0], tw_dev->generic_buffer_phys[0]); - if (tw_dev->event_queue[0]) - kfree(tw_dev->event_queue[0]); + kfree(tw_dev->event_queue[0]); } /* End twa_free_device_extension() */ /* This function will free a request id */ diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index cc9ecb35b412a2bc51738215ab9c6de1f0dc8378..cba9655d0f14075af5903b7d0c82ab5b6989f36a 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -606,10 +606,7 @@ static int __init NCR5380_probe_irq(struct Scsi_Host *instance, int possible) NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_SEL); while (probe_irq == SCSI_IRQ_NONE && time_before(jiffies, timeout)) - { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } + schedule_timeout_uninterruptible(1); NCR5380_write(SELECT_ENABLE_REG, 0); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index ee9067255930f8943505cdd6b694af0932ad349f..723c0cea7c04a4ade79767a22eadc27ed2747c67 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -1164,7 +1164,7 @@ int aac_command_thread(struct aac_dev * dev) kfree(hw_fib_pool); hw_fib_pool = NULL; } - } else if (hw_fib_pool) { + } else { kfree(hw_fib_pool); hw_fib_pool = NULL; } @@ -1247,17 +1247,13 @@ int aac_command_thread(struct aac_dev * dev) hw_fib_p = hw_fib_pool; fib_p = fib_pool; while (hw_fib_p < &hw_fib_pool[num]) { - if (*hw_fib_p) - kfree(*hw_fib_p); - if (*fib_p) - kfree(*fib_p); + kfree(*hw_fib_p); + kfree(*fib_p); ++fib_p; ++hw_fib_p; } - if (hw_fib_pool) - kfree(hw_fib_pool); - if (fib_pool) - kfree(fib_pool); + kfree(hw_fib_pool); + kfree(fib_pool); } kfree(fib); spin_lock_irqsave(dev->queues->queue[HostNormCmdQueue].lock, flags); diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c index fc4c73c2a6a9ec81b4759b5fd8691f72759c7857..e9b775d6bec9b54b5827e0d82c41665adc3182a5 100644 --- a/drivers/scsi/aacraid/rkt.c +++ b/drivers/scsi/aacraid/rkt.c @@ -183,8 +183,7 @@ static int rkt_sync_cmd(struct aac_dev *dev, u32 command, /* * Yield the processor in case we are slow */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } if (ok != 1) { /* @@ -452,8 +451,7 @@ int aac_rkt_init(struct aac_dev *dev) dev->name, instance, status); goto error_iounmap; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } if (request_irq(dev->scsi_host_ptr->irq, aac_rkt_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev)<0) { diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index da99046e539342e7047ba2d82247086cc3ed9a82..6998bc877dd685726b0c20c1c467ed57d1fe677a 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c @@ -183,8 +183,7 @@ static int rx_sync_cmd(struct aac_dev *dev, u32 command, /* * Yield the processor in case we are slow */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } if (ok != 1) { /* @@ -452,8 +451,7 @@ int aac_rx_init(struct aac_dev *dev) dev->name, instance, status); goto error_iounmap; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } if (request_irq(dev->scsi_host_ptr->irq, aac_rx_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev)<0) { diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c index 8b9596209164904d63b4bf8f197a5ed9f488ed4e..466f05cfbf0ce280596ec955f2e1ec7605ba227f 100644 --- a/drivers/scsi/aacraid/sa.c +++ b/drivers/scsi/aacraid/sa.c @@ -189,8 +189,7 @@ static int sa_sync_cmd(struct aac_dev *dev, u32 command, ok = 1; break; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } if (ok != 1) @@ -325,8 +324,7 @@ int aac_sa_init(struct aac_dev *dev) name, instance, status); goto error_iounmap; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } if (request_irq(dev->scsi_host_ptr->irq, aac_sa_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev ) < 0) { diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 37ec5411e325578ff572429e4868efa44884789d..f4cfb8f29620f53ba091487c7ac635134299e83e 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -5402,10 +5402,8 @@ advansys_detect(struct scsi_host_template *tpnt) release_region(shp->io_port, boardp->asc_n_io_port); if (ASC_WIDE_BOARD(boardp)) { iounmap(boardp->ioremap_addr); - if (boardp->orig_carrp) { - kfree(boardp->orig_carrp); - boardp->orig_carrp = NULL; - } + kfree(boardp->orig_carrp); + boardp->orig_carrp = NULL; if (boardp->orig_reqp) { kfree(boardp->orig_reqp); boardp->orig_reqp = boardp->adv_reqp = NULL; @@ -5457,10 +5455,8 @@ advansys_release(struct Scsi_Host *shp) adv_sgblk_t *sgp = NULL; iounmap(boardp->ioremap_addr); - if (boardp->orig_carrp) { - kfree(boardp->orig_carrp); - boardp->orig_carrp = NULL; - } + kfree(boardp->orig_carrp); + boardp->orig_carrp = NULL; if (boardp->orig_reqp) { kfree(boardp->orig_reqp); boardp->orig_reqp = boardp->adv_reqp = NULL; diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index adda750412f29a25ad0d870995062c10b7d54606..1b1adfb384cb9adaec27941fea08067d7582d2e5 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -543,10 +543,8 @@ static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id, struct pt return; } my_done = SCtmp->scsi_done; - if (SCtmp->host_scribble) { - kfree(SCtmp->host_scribble); - SCtmp->host_scribble = NULL; - } + kfree(SCtmp->host_scribble); + SCtmp->host_scribble = NULL; /* Fetch the sense data, and tuck it away, in the required slot. The Adaptec automatically fetches it, and there is no guarantee that we will still have it in the cdb when we come back */ @@ -1432,10 +1430,8 @@ static int aha1542_dev_reset(Scsi_Cmnd * SCpnt) HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target) { Scsi_Cmnd *SCtmp; SCtmp = HOSTDATA(SCpnt->host)->SCint[i]; - if (SCtmp->host_scribble) { - kfree(SCtmp->host_scribble); - SCtmp->host_scribble = NULL; - } + kfree(SCtmp->host_scribble); + SCtmp->host_scribble = NULL; HOSTDATA(SCpnt->host)->SCint[i] = NULL; HOSTDATA(SCpnt->host)->mb[i].status = 0; } @@ -1495,10 +1491,8 @@ static int aha1542_bus_reset(Scsi_Cmnd * SCpnt) */ continue; } - if (SCtmp->host_scribble) { - kfree(SCtmp->host_scribble); - SCtmp->host_scribble = NULL; - } + kfree(SCtmp->host_scribble); + SCtmp->host_scribble = NULL; HOSTDATA(SCpnt->device->host)->SCint[i] = NULL; HOSTDATA(SCpnt->device->host)->mb[i].status = 0; } @@ -1565,10 +1559,8 @@ static int aha1542_host_reset(Scsi_Cmnd * SCpnt) */ continue; } - if (SCtmp->host_scribble) { - kfree(SCtmp->host_scribble); - SCtmp->host_scribble = NULL; - } + kfree(SCtmp->host_scribble); + SCtmp->host_scribble = NULL; HOSTDATA(SCpnt->device->host)->SCint[i] = NULL; HOSTDATA(SCpnt->device->host)->mb[i].status = 0; } @@ -1711,10 +1703,8 @@ static int aha1542_old_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) Scsi_Cmnd *SCtmp; SCtmp = HOSTDATA(SCpnt->host)->SCint[i]; SCtmp->result = DID_RESET << 16; - if (SCtmp->host_scribble) { - kfree(SCtmp->host_scribble); - SCtmp->host_scribble = NULL; - } + kfree(SCtmp->host_scribble); + SCtmp->host_scribble = NULL; printk(KERN_WARNING "Sending DID_RESET for target %d\n", SCpnt->target); SCtmp->scsi_done(SCpnt); @@ -1757,10 +1747,8 @@ static int aha1542_old_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) Scsi_Cmnd *SCtmp; SCtmp = HOSTDATA(SCpnt->host)->SCint[i]; SCtmp->result = DID_RESET << 16; - if (SCtmp->host_scribble) { - kfree(SCtmp->host_scribble); - SCtmp->host_scribble = NULL; - } + kfree(SCtmp->host_scribble); + SCtmp->host_scribble = NULL; printk(KERN_WARNING "Sending DID_RESET for target %d\n", SCpnt->target); SCtmp->scsi_done(SCpnt); diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c index 52b72d7794f51aeadc11df93a1a53aed02f1b478..880e2d9ffe9bde841fec29501f7cdd28c0e4bd56 100644 --- a/drivers/scsi/aic7xxx_old.c +++ b/drivers/scsi/aic7xxx_old.c @@ -8492,8 +8492,7 @@ aic7xxx_free(struct aic7xxx_host *p) - scb_dma->dma_offset), scb_dma->dma_address); } - if (p->scb_data->scb_array[i]->kmalloc_ptr != NULL) - kfree(p->scb_data->scb_array[i]->kmalloc_ptr); + kfree(p->scb_data->scb_array[i]->kmalloc_ptr); p->scb_data->scb_array[i] = NULL; } diff --git a/drivers/scsi/arm/queue.c b/drivers/scsi/arm/queue.c index e6d159270d294836ad6eb91436ae1785fe3b890c..b10750bb5c09b428687419376507190f125afec4 100644 --- a/drivers/scsi/arm/queue.c +++ b/drivers/scsi/arm/queue.c @@ -91,8 +91,7 @@ void queue_free (Queue_t *queue) { if (!list_empty(&queue->head)) printk(KERN_WARNING "freeing non-empty queue %p\n", queue); - if (queue->alloc) - kfree(queue->alloc); + kfree(queue->alloc); } diff --git a/drivers/scsi/atari_dma_emul.c b/drivers/scsi/atari_dma_emul.c index 7026045527fd41a01309b9bf60489a3e2830553d..8d5d2a5da961e195dc2882e6523c8ed670f363e6 100644 --- a/drivers/scsi/atari_dma_emul.c +++ b/drivers/scsi/atari_dma_emul.c @@ -19,6 +19,8 @@ * this code. */ +#include +#include #include #define hades_dma_ctrl (*(unsigned char *) 0xffff8717) diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index c44af5795b10a547f0c7e915a7aed4de90e7cc0b..c8a32cf47d738fba4e991d1c2f37e09c6a5b08c2 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -4270,8 +4270,7 @@ static void adapter_sg_tables_free(struct AdapterCtlBlk *acb) const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN; for (i = 0; i < DC395x_MAX_SRB_CNT; i += srbs_per_page) - if (acb->srb_array[i].segment_x) - kfree(acb->srb_array[i].segment_x); + kfree(acb->srb_array[i].segment_x); } diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index 7235f94f1191ef06ce816e0539527c0cd11f256d..c28e3aea1c3cef83f28e3b3bccb00dac2e8ada27 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -1037,18 +1037,10 @@ static void adpt_i2o_delete_hba(adpt_hba* pHba) if(pHba->msg_addr_virt != pHba->base_addr_virt){ iounmap(pHba->msg_addr_virt); } - if(pHba->hrt) { - kfree(pHba->hrt); - } - if(pHba->lct){ - kfree(pHba->lct); - } - if(pHba->status_block) { - kfree(pHba->status_block); - } - if(pHba->reply_pool){ - kfree(pHba->reply_pool); - } + kfree(pHba->hrt); + kfree(pHba->lct); + kfree(pHba->status_block); + kfree(pHba->reply_pool); for(d = pHba->devices; d ; d = next){ next = d->next; @@ -1218,8 +1210,7 @@ static s32 adpt_i2o_post_this(adpt_hba* pHba, u32* data, int len) printk(KERN_WARNING"dpti%d: Timeout waiting for message frame!\n", pHba->unit); return -ETIMEDOUT; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while(m == EMPTY_QUEUE); msg = pHba->msg_addr_virt + m; @@ -1294,8 +1285,7 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba) printk(KERN_WARNING"Timeout waiting for message!\n"); return -ETIMEDOUT; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (m == EMPTY_QUEUE); status = (u8*)kmalloc(4, GFP_KERNEL|ADDR32); @@ -1327,8 +1317,7 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba) return -ETIMEDOUT; } rmb(); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } if(*status == 0x01 /*I2O_EXEC_IOP_RESET_IN_PROGRESS*/) { @@ -1345,8 +1334,7 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba) printk(KERN_ERR "%s:Timeout waiting for IOP Reset.\n",pHba->name); return -ETIMEDOUT; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (m == EMPTY_QUEUE); // Flush the offset adpt_send_nop(pHba, m); @@ -1917,11 +1905,8 @@ static int adpt_ioctl(struct inode *inode, struct file *file, uint cmd, return -ENXIO; } - while((volatile u32) pHba->state & DPTI_STATE_RESET ) { - set_task_state(current,TASK_UNINTERRUPTIBLE); - schedule_timeout(2); - - } + while((volatile u32) pHba->state & DPTI_STATE_RESET ) + schedule_timeout_uninterruptible(2); switch (cmd) { // TODO: handle 3 cases @@ -2635,8 +2620,7 @@ static s32 adpt_send_nop(adpt_hba*pHba,u32 m) printk(KERN_ERR "%s: Timeout waiting for message frame!\n",pHba->name); return 2; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } msg = (u32 __iomem *)(pHba->msg_addr_virt + m); writel( THREE_WORD_MSG_SIZE | SGL_OFFSET_0,&msg[0]); @@ -2670,8 +2654,7 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba) printk(KERN_WARNING"%s: Timeout waiting for message frame\n",pHba->name); return -ETIMEDOUT; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while(m == EMPTY_QUEUE); msg=(u32 __iomem *)(pHba->msg_addr_virt+m); @@ -2709,21 +2692,18 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba) printk(KERN_WARNING"%s: Timeout Initializing\n",pHba->name); return -ETIMEDOUT; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (1); // If the command was successful, fill the fifo with our reply // message packets if(*status != 0x04 /*I2O_EXEC_OUTBOUND_INIT_COMPLETE*/) { - kfree((void*)status); + kfree(status); return -2; } - kfree((void*)status); + kfree(status); - if(pHba->reply_pool != NULL){ - kfree(pHba->reply_pool); - } + kfree(pHba->reply_pool); pHba->reply_pool = (u32*)kmalloc(pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, GFP_KERNEL|ADDR32); if(!pHba->reply_pool){ @@ -2788,8 +2768,7 @@ static s32 adpt_i2o_status_get(adpt_hba* pHba) pHba->name); return -ETIMEDOUT; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while(m==EMPTY_QUEUE); @@ -2816,8 +2795,7 @@ static s32 adpt_i2o_status_get(adpt_hba* pHba) return -ETIMEDOUT; } rmb(); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } // Set up our number of outbound and inbound messages @@ -2941,8 +2919,7 @@ static int adpt_i2o_build_sys_table(void) sys_tbl_len = sizeof(struct i2o_sys_tbl) + // Header + IOPs (hba_count) * sizeof(struct i2o_sys_tbl_entry); - if(sys_tbl) - kfree(sys_tbl); + kfree(sys_tbl); sys_tbl = kmalloc(sys_tbl_len, GFP_KERNEL|ADDR32); if(!sys_tbl) { diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index b45a4c7302305d5b78e19494f431604362c893e0..b3f9de8f75955f69d7bfa9f0a69c0d22cd8432da 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -2580,8 +2580,7 @@ static int eata2x_release(struct Scsi_Host *shost) unsigned int i; for (i = 0; i < shost->can_queue; i++) - if ((&ha->cp[i])->sglist) - kfree((&ha->cp[i])->sglist); + kfree((&ha->cp[i])->sglist); for (i = 0; i < shost->can_queue; i++) pci_unmap_single(ha->pdev, ha->cp[i].cp_dma_addr, diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index f04f3289938d1c6f3ee30ac9faaff26b70f125c9..c888af4a45629cf8fa138dabcc99646f8199723d 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -331,9 +331,9 @@ static int idescsi_check_condition(ide_drive_t *drive, struct request *failed_co rq = kmalloc (sizeof (struct request), GFP_ATOMIC); buf = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_ATOMIC); if (pc == NULL || rq == NULL || buf == NULL) { - if (pc) kfree(pc); - if (rq) kfree(rq); - if (buf) kfree(buf); + kfree(buf); + kfree(rq); + kfree(pc); return -ENOMEM; } memset (pc, 0, sizeof (idescsi_pc_t)); @@ -949,8 +949,8 @@ static int idescsi_queue (struct scsi_cmnd *cmd, spin_lock_irq(host->host_lock); return 0; abort: - if (pc) kfree (pc); - if (rq) kfree (rq); + kfree (pc); + kfree (rq); cmd->result = DID_ERROR << 16; done(cmd); return 0; diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 68e5b2ab27c4ac346d02ae4eb3926aa3212bf589..cd9b95db5a7d419ba29f82d6fd8aa45233d2b146 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -4517,10 +4517,8 @@ ips_free(ips_ha_t * ha) ha->enq = NULL; } - if (ha->conf) { - kfree(ha->conf); - ha->conf = NULL; - } + kfree(ha->conf); + ha->conf = NULL; if (ha->adapt) { pci_free_consistent(ha->pcidev, @@ -4538,15 +4536,11 @@ ips_free(ips_ha_t * ha) ha->logical_drive_info = NULL; } - if (ha->nvram) { - kfree(ha->nvram); - ha->nvram = NULL; - } + kfree(ha->nvram); + ha->nvram = NULL; - if (ha->subsys) { - kfree(ha->subsys); - ha->subsys = NULL; - } + kfree(ha->subsys); + ha->subsys = NULL; if (ha->ioctl_data) { pci_free_consistent(ha->pcidev, ha->ioctl_len, diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 08a0c00cfc302eee9f97a8f9668910672d39d08a..bcc29ec126dc1a29761885fe31193f75c1ad29d9 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -127,8 +127,7 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, if (((pcmd = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == 0) || ((pcmd->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(pcmd->phys))) == 0)) { - if (pcmd) - kfree(pcmd); + kfree(pcmd); spin_lock_irq(phba->host->host_lock); lpfc_sli_release_iocbq(phba, elsiocb); @@ -145,8 +144,7 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &prsp->phys); if (prsp == 0 || prsp->virt == 0) { - if (prsp) - kfree(prsp); + kfree(prsp); lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); kfree(pcmd); spin_lock_irq(phba->host->host_lock); @@ -172,8 +170,7 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, lpfc_mbuf_free(phba, prsp->virt, prsp->phys); kfree(pcmd); kfree(prsp); - if (pbuflist) - kfree(pbuflist); + kfree(pbuflist); return NULL; } diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 4e04470321a27352391d78708d21133be8d48515..c90723860a049e15232452b60921909645c81bde 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -894,8 +894,7 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt, mp1->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &mp1->phys); if (mp1 == 0 || mp1->virt == 0) { - if (mp1) - kfree(mp1); + kfree(mp1); spin_lock_irq(phba->host->host_lock); lpfc_sli_release_iocbq(phba, iocb); spin_unlock_irq(phba->host->host_lock); @@ -911,8 +910,7 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt, mp2->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &mp2->phys); if (mp2 == 0 || mp2->virt == 0) { - if (mp2) - kfree(mp2); + kfree(mp2); lpfc_mbuf_free(phba, mp1->virt, mp1->phys); kfree(mp1); spin_lock_irq(phba->host->host_lock); diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 31c20cc00609cda49a41ec52c144c548fb87b6f7..e3bc8d3f7302fa7bd9326ea34d39d60b6a2c1dfe 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -248,8 +248,7 @@ lpfc_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) if (((mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == 0) || ((mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys))) == 0)) { - if (mp) - kfree(mp); + kfree(mp); mb->mbxCommand = MBX_READ_SPARM64; /* READ_SPARAM: no buffers */ lpfc_printf_log(phba, @@ -363,9 +362,7 @@ lpfc_reg_login(struct lpfc_hba * phba, /* Get a buffer to hold NPorts Service Parameters */ if (((mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == NULL) || ((mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys))) == 0)) { - if (mp) - kfree(mp); - + kfree(mp); mb->mbxCommand = MBX_REG_LOGIN64; /* REG_LOGIN: no buffers */ lpfc_printf_log(phba, diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index c34d3cf4f19c09b0ba945f07e80e1eaa51310e0b..c63275e66e2e6644c1e187904b4838476eda8e37 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -825,8 +825,7 @@ __lpfc_abort_handler(struct scsi_cmnd *cmnd) while (lpfc_cmd->pCmd == cmnd) { spin_unlock_irq(phba->host->host_lock); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(LPFC_ABORT_WAIT*HZ); + schedule_timeout_uninterruptible(LPFC_ABORT_WAIT*HZ); spin_lock_irq(phba->host->host_lock); if (++loop_count > (2 * phba->cfg_nodev_tmo)/LPFC_ABORT_WAIT) @@ -885,8 +884,7 @@ __lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) if (pnode->nlp_state != NLP_STE_MAPPED_NODE) { spin_unlock_irq(phba->host->host_lock); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout( HZ/2); + schedule_timeout_uninterruptible(msecs_to_jiffies(500)); spin_lock_irq(phba->host->host_lock); } if ((pnode) && (pnode->nlp_state == NLP_STE_MAPPED_NODE)) @@ -939,8 +937,7 @@ __lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) cmnd->device->id, cmnd->device->lun, LPFC_CTX_LUN))) { spin_unlock_irq(phba->host->host_lock); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(LPFC_RESET_WAIT*HZ); + schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ); spin_lock_irq(phba->host->host_lock); if (++loopcnt @@ -1038,8 +1035,7 @@ __lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) &phba->sli.ring[phba->sli.fcp_ring], 0, 0, LPFC_CTX_HOST))) { spin_unlock_irq(phba->host->host_lock); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(LPFC_RESET_WAIT*HZ); + schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ); spin_lock_irq(phba->host->host_lock); if (++loopcnt diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 508710001ed61a9de13bdc37f3a34f4b0b885b54..e2c08c5d83fb3d75b605d2596152951baa6114e0 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -2269,11 +2269,8 @@ lpfc_sli_hba_down(struct lpfc_hba * phba) INIT_LIST_HEAD(&(pring->txq)); - if (pring->fast_lookup) { - kfree(pring->fast_lookup); - pring->fast_lookup = NULL; - } - + kfree(pring->fast_lookup); + pring->fast_lookup = NULL; } spin_unlock_irqrestore(phba->host->host_lock, flags); diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index c9e743ba09ec108d23129ae9d06d90092299aa8e..1a3d195a2d366d3994a39bc525bf5a0e5b69fe20 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -3937,9 +3937,8 @@ megaraid_sysfs_free_resources(adapter_t *adapter) { mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - if (raid_dev->sysfs_uioc) kfree(raid_dev->sysfs_uioc); - - if (raid_dev->sysfs_mbox64) kfree(raid_dev->sysfs_mbox64); + kfree(raid_dev->sysfs_uioc); + kfree(raid_dev->sysfs_mbox64); if (raid_dev->sysfs_buffer) { pci_free_consistent(adapter->pdev, PAGE_SIZE, diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c index 37d110e864c49c9c524e8347118e42050cdd3e49..8f3ce0432295b38424903a339cfb39bb1dee39d8 100644 --- a/drivers/scsi/megaraid/megaraid_mm.c +++ b/drivers/scsi/megaraid/megaraid_mm.c @@ -995,17 +995,13 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp) memalloc_error: - if (adapter->kioc_list) - kfree(adapter->kioc_list); - - if (adapter->mbox_list) - kfree(adapter->mbox_list); + kfree(adapter->kioc_list); + kfree(adapter->mbox_list); if (adapter->pthru_dma_pool) pci_pool_destroy(adapter->pthru_dma_pool); - if (adapter) - kfree(adapter); + kfree(adapter); return rval; } @@ -1157,7 +1153,6 @@ mraid_mm_free_adp_resources(mraid_mmadp_t *adp) } kfree(adp->kioc_list); - kfree(adp->mbox_list); pci_pool_destroy(adp->pthru_dma_pool); diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 1cf11c3322fbd0b4d1c3fe7a2ea1adf3e02d835f..d9946bd95492e68ae43d9df891d497c86592d58d 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -862,8 +862,7 @@ static int osst_recover_wait_frame(struct osst_tape * STp, struct scsi_request * retval = osst_write_error_recovery(STp, aSRpnt, 0); break; } - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout (HZ / OSST_POLL_PER_SEC); + schedule_timeout_interruptible(HZ / OSST_POLL_PER_SEC); STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24; memset(cmd, 0, MAX_COMMAND_SIZE); @@ -1558,8 +1557,7 @@ static int osst_reposition_and_retry(struct osst_tape * STp, struct scsi_request osst_set_frame_position(STp, aSRpnt, frame + skip, 1); flag = 0; attempts--; - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 10); + schedule_timeout_interruptible(msecs_to_jiffies(100)); } if (osst_get_frame_position(STp, aSRpnt) < 0) { /* additional write error */ #if DEBUG @@ -1620,8 +1618,7 @@ static int osst_reposition_and_retry(struct osst_tape * STp, struct scsi_request debugging = 0; } #endif - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 10); + schedule_timeout_interruptible(msecs_to_jiffies(100)); } printk(KERN_ERR "%s:E: Failed to find valid tape media\n", name); #if DEBUG diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 290a6b92616ca9c83e6fa3b23abed5ce476671ca..72d9090df3dff8e8863204183b938c854392ce38 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1977,8 +1977,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha) } cleanup_allocation: - if (new_fcport) - kfree(new_fcport); + kfree(new_fcport); if (rval != QLA_SUCCESS) { DEBUG2(printk("scsi(%ld): Configure local loop error exit: " @@ -2348,8 +2347,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports) /* Allocate temporary fcport for any new fcports discovered. */ new_fcport = qla2x00_alloc_fcport(ha, GFP_KERNEL); if (new_fcport == NULL) { - if (swl) - kfree(swl); + kfree(swl); return (QLA_MEMORY_ALLOC_FAILED); } new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED); @@ -2485,19 +2483,15 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports) nxt_d_id.b24 = new_fcport->d_id.b24; new_fcport = qla2x00_alloc_fcport(ha, GFP_KERNEL); if (new_fcport == NULL) { - if (swl) - kfree(swl); + kfree(swl); return (QLA_MEMORY_ALLOC_FAILED); } new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED); new_fcport->d_id.b24 = nxt_d_id.b24; } - if (swl) - kfree(swl); - - if (new_fcport) - kfree(new_fcport); + kfree(swl); + kfree(new_fcport); if (!list_empty(new_fcports)) ha->device_flags |= DFLG_FABRIC_DEVICES; diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c index f1ea5027865f5851310769b08e0f5b53df163f71..caa0c3629626c3a6102d28df8164521964a228ca 100644 --- a/drivers/scsi/raid_class.c +++ b/drivers/scsi/raid_class.c @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 0cc766a9aa6585a5ffef2292b355478cd31b4235..edabbd05d258882050661058b8bb32da15e69672 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 4f30a37db63c90c26e111036aaf70d51af916507..62e3f340cc5200c38e630ff04151852fbf1c1a32 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -476,8 +476,7 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) sg_finish_rem_req(srp); retval = count; free_old_hdr: - if (old_hdr) - kfree(old_hdr); + kfree(old_hdr); return retval; } @@ -1703,10 +1702,8 @@ exit_sg(void) sg_sysfs_valid = 0; unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS); - if (sg_dev_arr != NULL) { - kfree((char *) sg_dev_arr); - sg_dev_arr = NULL; - } + kfree((char *)sg_dev_arr); + sg_dev_arr = NULL; sg_dev_max = 0; } diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 6b85f84c839756680e8373ad45532ad946f8fce8..770c4324f3d5750e51eae824fd59a985209b9732 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -4107,8 +4107,7 @@ static int st_probe(struct device *dev) write_unlock(&st_dev_arr_lock); out_put_disk: put_disk(disk); - if (tpnt) - kfree(tpnt); + kfree(tpnt); out_buffer_free: kfree(buffer); out: diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index a1a58e1d5ad327330b96603c18afd511bbf9dd40..a7420cad4547d068951fe768408f6f6a150db102 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -39,6 +39,7 @@ */ #include +#include /* for timeouts in units of HZ */ #include "sym_glue.h" #include "sym_nvram.h" diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index cfab8f197084f167ed2dc5d2610e783583c40be3..1ce29ba683eb72a8953adb95cd9fa0e2d660d83c 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -1953,11 +1953,11 @@ static int u14_34f_release(struct Scsi_Host *shpnt) { for (j = 0; sh[j] != NULL && sh[j] != shpnt; j++); - if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n", - driver_name); + if (sh[j] == NULL) + panic("%s: release, invalid Scsi_Host pointer.\n", driver_name); for (i = 0; i < sh[j]->can_queue; i++) - if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist); + kfree((&HD(j)->cp[i])->sglist); for (i = 0; i < sh[j]->can_queue; i++) pci_unmap_single(HD(j)->pdev, HD(j)->cp[i].cp_dma_addr, @@ -1965,7 +1965,8 @@ static int u14_34f_release(struct Scsi_Host *shpnt) { free_irq(sh[j]->irq, &sha[j]); - if (sh[j]->dma_channel != NO_DMA) free_dma(sh[j]->dma_channel); + if (sh[j]->dma_channel != NO_DMA) + free_dma(sh[j]->dma_channel); release_region(sh[j]->io_port, sh[j]->n_io_port); scsi_unregister(sh[j]); diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 186e96c47b3da09cfe06a66b17d545a6facc9ae9..98820603e75fd2a4a7b27206817744d60c10f833 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -2208,6 +2209,8 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count) unsigned int ier; int i; + touch_nmi_watchdog(); + /* * First save the UER then disable the interrupts */ diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c index 40d3e7139cfea2518fff6c2a758e0bdc4c5cd53d..08c42c000188405f6363b3d49293dbe1e43a104b 100644 --- a/drivers/serial/crisv10.c +++ b/drivers/serial/crisv10.c @@ -4416,10 +4416,8 @@ rs_close(struct tty_struct *tty, struct file * filp) info->event = 0; info->tty = 0; if (info->blocked_open) { - if (info->close_delay) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(info->close_delay); - } + if (info->close_delay) + schedule_timeout_interruptible(info->close_delay); wake_up_interruptible(&info->open_wait); } info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); @@ -4469,8 +4467,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) while (info->xmit.head != info->xmit.tail || /* More in send queue */ (*info->ostatusadr & 0x007f) || /* more in FIFO */ (elapsed_usec < 2*info->char_time_usec)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_interruptible(1); if (signal_pending(current)) break; if (timeout && time_after(jiffies, orig_jiffies + timeout)) diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c index e2ebdcad553c405b012a83c7674fe69472b42a1f..47f7404cb04542a80408254685b3d57451eaea06 100644 --- a/drivers/serial/mcfserial.c +++ b/drivers/serial/mcfserial.c @@ -57,7 +57,8 @@ struct timer_list mcfrs_timer_struct; * keep going. Perhaps one day the cflag settings for the * console can be used instead. */ -#if defined(CONFIG_ARNEWSH) || defined(CONFIG_MOTOROLA) || defined(CONFIG_senTec) || defined(CONFIG_SNEHA) +#if defined(CONFIG_ARNEWSH) || defined(CONFIG_FREESCALE) || \ + defined(CONFIG_senTec) || defined(CONFIG_SNEHA) #define CONSOLE_BAUD_RATE 19200 #define DEFAULT_CBAUD B19200 #endif @@ -67,7 +68,7 @@ struct timer_list mcfrs_timer_struct; #define DEFAULT_CBAUD B38400 #endif -#if defined(CONFIG_MOD5272) +#if defined(CONFIG_MOD5272) || defined(CONFIG_M5208EVB) #define CONSOLE_BAUD_RATE 115200 #define DEFAULT_CBAUD B115200 #endif @@ -95,7 +96,8 @@ static struct tty_driver *mcfrs_serial_driver; #undef SERIAL_DEBUG_OPEN #undef SERIAL_DEBUG_FLOW -#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) +#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ + defined(CONFIG_M520x) #define IRQBASE (MCFINT_VECBASE+MCFINT_UART0) #else #define IRQBASE 73 @@ -1528,6 +1530,35 @@ static void mcfrs_irqinit(struct mcf_serial *info) imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 + MCFINTC_IMRL); *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1); +#elif defined(CONFIG_M520x) + volatile unsigned char *icrp, *uartp; + volatile unsigned long *imrp; + + uartp = info->addr; + + icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 + + MCFINTC_ICR0 + MCFINT_UART0 + info->line); + *icrp = 0x03; + + imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 + + MCFINTC_IMRL); + *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1); + if (info->line < 2) { + unsigned short *uart_par; + uart_par = (unsigned short *)(MCF_IPSBAR + MCF_GPIO_PAR_UART); + if (info->line == 0) + *uart_par |= MCF_GPIO_PAR_UART_PAR_UTXD0 + | MCF_GPIO_PAR_UART_PAR_URXD0; + else if (info->line == 1) + *uart_par |= MCF_GPIO_PAR_UART_PAR_UTXD1 + | MCF_GPIO_PAR_UART_PAR_URXD1; + } else if (info->line == 2) { + unsigned char *feci2c_par; + feci2c_par = (unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FECI2C); + *feci2c_par &= ~0x0F; + *feci2c_par |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 + | MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2; + } #else volatile unsigned char *icrp, *uartp; diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 656c0e8d160eac0dc9ee73fa5eea7bb903df050c..f0738533f39a7f5adddb1a24737155851eed43de 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -1441,7 +1441,7 @@ static void sunsu_console_write(struct console *co, const char *s, * - initialize the serial port * Return non-zero if we didn't find a serial port. */ -static int __init sunsu_console_setup(struct console *co, char *options) +static int sunsu_console_setup(struct console *co, char *options) { struct uart_port *port; int baud = 9600; diff --git a/drivers/sh/superhyway/superhyway-sysfs.c b/drivers/sh/superhyway/superhyway-sysfs.c index dc119ce68e3eafa7a0c6c4e03d244224b3e3c8df..55434330867b27c1b90c331fb1189202439dcff8 100644 --- a/drivers/sh/superhyway/superhyway-sysfs.c +++ b/drivers/sh/superhyway/superhyway-sysfs.c @@ -30,7 +30,7 @@ superhyway_ro_attr(bot_mb, "0x%02x\n", vcr.bot_mb); superhyway_ro_attr(top_mb, "0x%02x\n", vcr.top_mb); /* Misc */ -superhyway_ro_attr(resource, "0x%08lx\n", resource.start); +superhyway_ro_attr(resource, "0x%08lx\n", resource[0].start); struct device_attribute superhyway_dev_attrs[] = { __ATTR_RO(perr_flags), diff --git a/drivers/sh/superhyway/superhyway.c b/drivers/sh/superhyway/superhyway.c index 28757cb9d246665ad8e4eba116f19679657aea57..7bdab2a7f59c61f25f7dd8b6b44c1b10e5ff6b42 100644 --- a/drivers/sh/superhyway/superhyway.c +++ b/drivers/sh/superhyway/superhyway.c @@ -27,19 +27,20 @@ static struct device superhyway_bus_device = { static void superhyway_device_release(struct device *dev) { - kfree(to_superhyway_device(dev)); + struct superhyway_device *sdev = to_superhyway_device(dev); + + kfree(sdev->resource); + kfree(sdev); } /** * superhyway_add_device - Add a SuperHyway module - * @mod_id: Module ID (taken from MODULE.VCR.MOD_ID). * @base: Physical address where module is mapped. - * @vcr: VCR value. + * @sdev: SuperHyway device to add, or NULL to allocate a new one. + * @bus: Bus where SuperHyway module resides. * * This is responsible for adding a new SuperHyway module. This sets up a new - * struct superhyway_device for the module being added. Each one of @mod_id, - * @base, and @vcr are registered with the new device for further use - * elsewhere. + * struct superhyway_device for the module being added if @sdev == NULL. * * Devices are initially added in the order that they are scanned (from the * top-down of the memory map), and are assigned an ID based on the order that @@ -49,28 +50,40 @@ static void superhyway_device_release(struct device *dev) * Further work can and should be done in superhyway_scan_bus(), to be sure * that any new modules are properly discovered and subsequently registered. */ -int superhyway_add_device(unsigned int mod_id, unsigned long base, - unsigned long long vcr) +int superhyway_add_device(unsigned long base, struct superhyway_device *sdev, + struct superhyway_bus *bus) { - struct superhyway_device *dev; + struct superhyway_device *dev = sdev; + + if (!dev) { + dev = kmalloc(sizeof(struct superhyway_device), GFP_KERNEL); + if (!dev) + return -ENOMEM; - dev = kmalloc(sizeof(struct superhyway_device), GFP_KERNEL); - if (!dev) - return -ENOMEM; + memset(dev, 0, sizeof(struct superhyway_device)); + } - memset(dev, 0, sizeof(struct superhyway_device)); + dev->bus = bus; + superhyway_read_vcr(dev, base, &dev->vcr); - dev->id.id = mod_id; - sprintf(dev->name, "SuperHyway device %04x", dev->id.id); + if (!dev->resource) { + dev->resource = kmalloc(sizeof(struct resource), GFP_KERNEL); + if (!dev->resource) { + kfree(dev); + return -ENOMEM; + } + + dev->resource->name = dev->name; + dev->resource->start = base; + dev->resource->end = dev->resource->start + 0x01000000; + } - dev->vcr = *((struct vcr_info *)(&vcr)); - dev->resource.name = dev->name; - dev->resource.start = base; - dev->resource.end = dev->resource.start + 0x01000000; dev->dev.parent = &superhyway_bus_device; dev->dev.bus = &superhyway_bus_type; dev->dev.release = superhyway_device_release; + dev->id.id = dev->vcr.mod_id; + sprintf(dev->name, "SuperHyway device %04x", dev->id.id); sprintf(dev->dev.bus_id, "%02x", superhyway_devices); superhyway_devices++; @@ -78,10 +91,31 @@ int superhyway_add_device(unsigned int mod_id, unsigned long base, return device_register(&dev->dev); } +int superhyway_add_devices(struct superhyway_bus *bus, + struct superhyway_device **devices, + int nr_devices) +{ + int i, ret = 0; + + for (i = 0; i < nr_devices; i++) { + struct superhyway_device *dev = devices[i]; + ret |= superhyway_add_device(dev->resource[0].start, dev, bus); + } + + return ret; +} + static int __init superhyway_init(void) { + struct superhyway_bus *bus; + int ret = 0; + device_register(&superhyway_bus_device); - return superhyway_scan_bus(); + + for (bus = superhyway_channels; bus->ops; bus++) + ret |= superhyway_scan_bus(bus); + + return ret; } postcore_initcall(superhyway_init); @@ -197,6 +231,7 @@ module_exit(superhyway_bus_exit); EXPORT_SYMBOL(superhyway_bus_type); EXPORT_SYMBOL(superhyway_add_device); +EXPORT_SYMBOL(superhyway_add_devices); EXPORT_SYMBOL(superhyway_register_driver); EXPORT_SYMBOL(superhyway_unregister_driver); diff --git a/drivers/tc/.gitignore b/drivers/tc/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..acc0e1e6a650489da7fc08e78d55d6e71bc428d9 --- /dev/null +++ b/drivers/tc/.gitignore @@ -0,0 +1 @@ +lk201-map.c diff --git a/drivers/video/68328fb.c b/drivers/video/68328fb.c index 6a3cfbdc6dc92ed56d2f522f6ea9b7f18378b4ad..3b0ddc55236b7624a5ee48a2fad150711ad90f35 100644 --- a/drivers/video/68328fb.c +++ b/drivers/video/68328fb.c @@ -113,7 +113,6 @@ static struct fb_ops mc68x328fb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, .fb_mmap = mc68x328fb_mmap, }; diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 7192b770bfb650a7c68ca2b76a735617f78dec72..44b6ca290ce36bdcde56a22a8ec13b02e5fa8fd8 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -65,15 +65,6 @@ config FB_CFB_IMAGEBLIT blitting. This is used by drivers that don't provide their own (accelerated) version. -config FB_SOFT_CURSOR - tristate - depends on FB - default n - ---help--- - Include the soft_cursor function for generic software cursor support. - This is used by drivers that don't provide their own (accelerated) - version. - config FB_MACMODES tristate depends on FB @@ -114,7 +105,6 @@ config FB_CIRRUS select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR ---help--- This enables support for Cirrus Logic GD542x/543x based boards on Amiga: SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum. @@ -133,7 +123,6 @@ config FB_PM2 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This is the frame buffer device driver for the Permedia2 AGP frame buffer card from ASK, aka `Graphic Blaster Exxtreme'. There is a @@ -152,7 +141,6 @@ config FB_ARMCLCD select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This framebuffer device driver is for the ARM PrimeCell PL110 Colour LCD controller. ARM PrimeCells provide the building @@ -169,7 +157,6 @@ config FB_ACORN select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This is the frame buffer device driver for the Acorn VIDC graphics hardware found in Acorn RISC PCs and other ARM-based machines. If @@ -181,7 +168,9 @@ config FB_CLPS711X select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR + help + Say Y to enable the Framebuffer driver for the CLPS7111 and + EP7212 processors. config FB_SA1100 bool "SA-1100 LCD support" @@ -189,7 +178,6 @@ config FB_SA1100 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This is a framebuffer device for the SA-1100 LCD Controller. See for information on framebuffer @@ -204,7 +192,6 @@ config FB_IMX select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR config FB_CYBER2000 tristate "CyberPro 2000/2010/5000 support" @@ -212,7 +199,6 @@ config FB_CYBER2000 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This enables support for the Integraphics CyberPro 20x0 and 5000 VGA chips used in the Rebel.com Netwinder and other machines. @@ -225,7 +211,6 @@ config FB_APOLLO default y select FB_CFB_FILLRECT select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR config FB_Q40 bool @@ -234,12 +219,10 @@ config FB_Q40 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR config FB_AMIGA tristate "Amiga native chipset support" depends on FB && AMIGA - select FB_SOFT_CURSOR help This is the frame buffer device driver for the builtin graphics chipset found in Amigas. @@ -279,7 +262,6 @@ config FB_CYBER select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This enables support for the Cybervision 64 graphics card from Phase5. Please note that its use is not all that intuitive (i.e. if @@ -294,7 +276,6 @@ config FB_VIRGE select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This enables support for the Cybervision 64/3D graphics card from Phase5. Please note that its use is not all that intuitive (i.e. if @@ -317,7 +298,6 @@ config FB_FM2 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This is the frame buffer device driver for the Amiga FrameMaster card from BSC (exhibited 1992 but not shipped as a CBM product). @@ -328,7 +308,6 @@ config FB_ARC select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This enables support for the Arc Monochrome LCD board. The board is based on the KS-108 lcd controller and is typically a matrix @@ -351,7 +330,6 @@ config FB_OF select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR select FB_MACMODES help Say Y if you want support with Open Firmware for your graphics @@ -363,7 +341,6 @@ config FB_CONTROL select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR select FB_MACMODES help This driver supports a frame buffer for the graphics adapter in the @@ -375,7 +352,6 @@ config FB_PLATINUM select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR select FB_MACMODES help This driver supports a frame buffer for the "platinum" graphics @@ -387,7 +363,6 @@ config FB_VALKYRIE select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR select FB_MACMODES help This driver supports a frame buffer for the "valkyrie" graphics @@ -399,42 +374,32 @@ config FB_CT65550 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This is the frame buffer device driver for the Chips & Technologies 65550 graphics chip in PowerBooks. config FB_ASILIANT - bool "Chips 69000 display support" + bool "Asiliant (Chips) 69000 display support" depends on (FB = y) && PCI select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR config FB_IMSTT bool "IMS Twin Turbo display support" depends on (FB = y) && PCI select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR select FB_MACMODES if PPC help The IMS Twin Turbo is a PCI-based frame buffer card bundled with many Macintosh and compatible computers. -config FB_S3TRIO - bool "S3 Trio display support" - depends on (FB = y) && PPC && BROKEN - help - If you have a S3 Trio say Y. Say N for S3 Virge. - config FB_VGA16 tristate "VGA 16-color graphics support" depends on FB && (X86 || PPC) select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This is the frame buffer device driver for VGA 16 color graphic cards. Say Y if you have such a card. @@ -448,7 +413,6 @@ config FB_STI select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR default y ---help--- STI refers to the HP "Standard Text Interface" which is a set of @@ -469,7 +433,6 @@ config FB_MAC select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR select FB_MACMODES # bool ' Apple DAFB display support' CONFIG_FB_DAFB @@ -478,7 +441,6 @@ config FB_HP300 depends on (FB = y) && HP300 select FB_CFB_FILLRECT select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR default y config FB_TGA @@ -487,7 +449,6 @@ config FB_TGA select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This is the frame buffer device driver for generic TGA graphic cards. Say Y if you have one of those. @@ -498,7 +459,6 @@ config FB_VESA select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This is the frame buffer device driver for generic VESA 2.0 compliant graphic cards. The older VESA 1.2 cards are not supported. @@ -516,7 +476,6 @@ config FB_HGA select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help Say Y here if you have a Hercules mono graphics card. @@ -545,7 +504,6 @@ config FB_SGIVW select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help SGI Visual Workstation support for framebuffer graphics. @@ -555,7 +513,6 @@ config FB_GBE select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This is the frame buffer device driver for SGI Graphics Backend. This chip is used in SGI O2 and Visual Workstation 320/540. @@ -583,7 +540,6 @@ config FB_BW2 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This is the frame buffer device driver for the BWtwo frame buffer. @@ -592,7 +548,6 @@ config FB_CG3 depends on (FB = y) && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3) select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This is the frame buffer device driver for the CGthree frame buffer. @@ -601,7 +556,6 @@ config FB_CG6 depends on (FB = y) && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3) select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This is the frame buffer device driver for the CGsix (GX, TurboGX) frame buffer. @@ -612,7 +566,6 @@ config FB_PVR2 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR ---help--- Say Y here if you have a PowerVR 2 card in your box. If you plan to run linux on your Dreamcast, you will have to say Y here. @@ -634,13 +587,55 @@ config FB_EPSON1355 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help Build in support for the SED1355 Epson Research Embedded RAMDAC LCD/CRT Controller (since redesignated as the S1D13505) as a framebuffer. Product specs at . +config FB_E1356 + tristate "Epson SED1356 framebuffer support" + depends on FB && EXPERIMENTAL && PCI && MIPS + +config PB1000_CRT + bool "Use CRT on Pb1000 (J65)" + depends on MIPS_PB1000=y && FB_E1356 + +config PB1000_NTSC + bool "Use Compsite NTSC on Pb1000 (J63)" + depends on MIPS_PB1000=y && FB_E1356 + +config PB1000_TFT + bool "Use TFT Panel on Pb1000 (J64)" + depends on MIPS_PB1000=y && FB_E1356 + +config PB1500_CRT + bool "Use CRT on Pb1500 " if MIPS_PB1500=y + depends on FB_E1356 + +config PB1500_CRT + prompt "Use CRT on Pb1100 " + depends on FB_E1356 && MIPS_PB1100=y + +config PB1500_TFT + bool "Use TFT Panel on Pb1500 " if MIPS_PB1500=y + depends on FB_E1356 + +config PB1500_TFT + prompt "Use TFT Panel on Pb1100 " + depends on FB_E1356 && MIPS_PB1100=y + +config FB_S1D13XXX + tristate "Epson S1D13XXX framebuffer support" + depends on FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + help + Support for S1D13XXX framebuffer device family (currently only + working with S1D13806). Product specs at + + config FB_NVIDIA tristate "nVidia Framebuffer Support" depends on FB && PCI @@ -650,7 +645,6 @@ config FB_NVIDIA select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This driver supports graphics boards with the nVidia chips, TNT and newer. For very old chipsets, such as the RIVA128, then use @@ -662,7 +656,7 @@ config FB_NVIDIA config FB_NVIDIA_I2C bool "Enable DDC Support" - depends on FB_NVIDIA && !PPC_OF + depends on FB_NVIDIA help This enables I2C support for nVidia Chipsets. This is used only for getting EDID information from the attached display @@ -768,7 +762,6 @@ config FB_INTEL select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This driver supports the on-board graphics built in to the Intel 830M/845G/852GM/855GM/865G chipsets. @@ -791,7 +784,6 @@ config FB_MATROX select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR select FB_TILEBLITTING select FB_MACMODES if PPC_PMAC ---help--- @@ -932,7 +924,6 @@ config FB_RADEON_OLD select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR select FB_MACMODES if PPC help Choose this option if you want to use an ATI Radeon graphics card as @@ -950,7 +941,6 @@ config FB_RADEON select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR select FB_MACMODES if PPC_OF help Choose this option if you want to use an ATI Radeon graphics card as @@ -988,7 +978,6 @@ config FB_ATY128 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR select FB_MACMODES if PPC_PMAC help This driver supports graphics boards with the ATI Rage128 chips. @@ -1004,7 +993,6 @@ config FB_ATY select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR select FB_MACMODES if PPC help This driver supports graphics boards with the ATI Mach64 chips. @@ -1047,6 +1035,12 @@ config FB_ATY_GX is at . +config FB_S3TRIO + bool "S3 Trio display support" + depends on (FB = y) && PPC && BROKEN + help + If you have a S3 Trio say Y. Say N for S3 Virge. + config FB_SAVAGE tristate "S3 Savage support" depends on FB && PCI && EXPERIMENTAL @@ -1056,7 +1050,6 @@ config FB_SAVAGE select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This driver supports notebooks and computers with S3 Savage PCI/AGP chips. @@ -1093,7 +1086,6 @@ config FB_SIS select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This is the frame buffer device driver for the SiS 300, 315, 330 and 340 series as well as XGI V3XT, V5, V8, Z7 graphics chipsets. @@ -1123,7 +1115,6 @@ config FB_NEOMAGIC select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This driver supports notebooks with NeoMagic PCI chips. Say Y if you have such a graphics card. @@ -1137,7 +1128,6 @@ config FB_KYRO select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help Say Y here if you have a STG4000 / Kyro / PowerVR 3 based graphics board. @@ -1151,7 +1141,6 @@ config FB_3DFX select FB_CFB_IMAGEBLIT select FB_CFB_FILLRECT select FB_CFB_COPYAREA - select FB_SOFT_CURSOR help This driver supports graphics boards with the 3Dfx Banshee/Voodoo3 chips. Say Y if you have such a graphics board. @@ -1173,7 +1162,6 @@ config FB_VOODOO1 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR ---help--- Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or Voodoo2 (cvg) based graphics card. @@ -1190,7 +1178,6 @@ config FB_CYBLA tristate "Cyberblade/i1 support" depends on FB && PCI select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR select VIDEO_SELECT ---help--- This driver is supposed to support the Trident Cyberblade/i1 @@ -1218,7 +1205,6 @@ config FB_TRIDENT select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR ---help--- This driver is supposed to support graphics boards with the Trident CyberXXXX/Image/CyberBlade chips mostly found in laptops @@ -1250,38 +1236,6 @@ config FB_PM3 similar boards, 3DLabs Permedia3 Create!, Appian Jeronimo 2000 and maybe other boards. -config FB_E1356 - tristate "Epson SED1356 framebuffer support" - depends on FB && EXPERIMENTAL && PCI && MIPS - -config PB1000_CRT - bool "Use CRT on Pb1000 (J65)" - depends on MIPS_PB1000=y && FB_E1356 - -config PB1000_NTSC - bool "Use Compsite NTSC on Pb1000 (J63)" - depends on MIPS_PB1000=y && FB_E1356 - -config PB1000_TFT - bool "Use TFT Panel on Pb1000 (J64)" - depends on MIPS_PB1000=y && FB_E1356 - -config PB1500_CRT - bool "Use CRT on Pb1500 " if MIPS_PB1500=y - depends on FB_E1356 - -config PB1500_CRT - prompt "Use CRT on Pb1100 " - depends on FB_E1356 && MIPS_PB1100=y - -config PB1500_TFT - bool "Use TFT Panel on Pb1500 " if MIPS_PB1500=y - depends on FB_E1356 - -config PB1500_TFT - prompt "Use TFT Panel on Pb1100 " - depends on FB_E1356 && MIPS_PB1100=y - config FB_AU1100 bool "Au1100 LCD Driver" depends on (FB = y) && EXPERIMENTAL && PCI && MIPS && MIPS_PB1100=y @@ -1299,7 +1253,6 @@ config FB_FFB depends on FB_SBUS && SPARC64 select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This is the frame buffer device driver for the Creator, Creator3D, and Elite3D graphics boards. @@ -1310,7 +1263,6 @@ config FB_TCX select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This is the frame buffer device driver for the TCX 24/8bit frame buffer. @@ -1321,7 +1273,6 @@ config FB_CG14 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This is the frame buffer device driver for the CGfourteen frame buffer on Desktop SPARCsystems with the SX graphics option. @@ -1332,7 +1283,6 @@ config FB_P9100 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This is the frame buffer device driver for the P9100 card supported on Sparcbook 3 machines. @@ -1343,7 +1293,6 @@ config FB_LEO select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This is the frame buffer device driver for the SBUS-based Sun ZX (leo) frame buffer cards. @@ -1358,7 +1307,6 @@ config FB_IGA select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This is the framebuffer device for the INTERGRAPHICS 1680 and successor frame buffer cards. @@ -1369,7 +1317,6 @@ config FB_HIT select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help This is the frame buffer device driver for the Hitachi HD64461 LCD frame buffer card. @@ -1380,7 +1327,6 @@ config FB_PMAG_AA select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help Support for the PMAG-AA TURBOchannel framebuffer card (1280x1024x1) used mainly in the MIPS-based DECstation series. @@ -1391,7 +1337,6 @@ config FB_PMAG_BA select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help Support for the PMAG-BA TURBOchannel framebuffer card (1024x864x8) used mainly in the MIPS-based DECstation series. @@ -1402,7 +1347,6 @@ config FB_PMAGB_B select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help Support for the PMAGB-B TURBOchannel framebuffer card used mainly in the MIPS-based DECstation series. The card is currently only @@ -1414,7 +1358,6 @@ config FB_MAXINE select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help Support for the onboard framebuffer (1024x768x8) in the Personal DECstation series (Personal DECstation 5000/20, /25, /33, /50, @@ -1426,7 +1369,6 @@ config FB_TX3912 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help The TX3912 is a Toshiba RISC processor based on the MIPS 3900 core see . @@ -1439,7 +1381,6 @@ config FB_G364 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help The G364 driver is the framebuffer used in MIPS Magnum 4000 and Olivetti M700-10 systems. @@ -1450,7 +1391,6 @@ config FB_68328 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR help Say Y here if you want to support the built-in frame buffer of the Motorola 68328 CPU family. @@ -1461,7 +1401,6 @@ config FB_PXA select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR ---help--- Frame buffer driver for the built-in LCD controller in the Intel PXA2x0 processor. @@ -1473,23 +1412,6 @@ config FB_PXA If unsure, say N. -config FB_W100 - tristate "W100 frame buffer support" - depends on FB && PXA_SHARPSL - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR - ---help--- - Frame buffer driver for the w100 as found on the Sharp SL-Cxx series. - - This driver is also available as a module ( = code which can be - inserted and removed from the running kernel whenever you want). The - module will be called vfb. If you want to compile it as a module, - say M here and read . - - If unsure, say N. - config FB_PXA_PARAMETERS bool "PXA LCD command line parameters" default n @@ -1507,17 +1429,21 @@ config FB_PXA_PARAMETERS describes the available parameters. -config FB_S1D13XXX - tristate "Epson S1D13XXX framebuffer support" - depends on FB - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR - help - Support for S1D13XXX framebuffer device family (currently only - working with S1D13806). Product specs at - +config FB_W100 + tristate "W100 frame buffer support" + depends on FB && PXA_SHARPSL + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + Frame buffer driver for the w100 as found on the Sharp SL-Cxx series. + + This driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). The + module will be called vfb. If you want to compile it as a module, + say M here and read . + + If unsure, say N. config FB_S3C2410 tristate "S3C2410 LCD framebuffer support" @@ -1525,7 +1451,6 @@ config FB_S3C2410 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR ---help--- Frame buffer driver for the built-in LCD controller in the Samsung S3C2410 processor. @@ -1549,7 +1474,6 @@ config FB_VIRTUAL select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR ---help--- This is a `virtual' frame buffer device. It operates on a chunk of unswappable kernel memory instead of on the memory of a graphics diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 97c5d03ac8d99e7d70936d90c466eb62e44ab587..aa434e725c0d844af830a0f273339d26c19d0d1b 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -16,7 +16,6 @@ fb-objs := $(fb-y) obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o -obj-$(CONFIG_FB_SOFT_CURSOR) += softcursor.o obj-$(CONFIG_FB_MACMODES) += macmodes.o # Hardware specific drivers go first diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c index 9b6a39348f81ab4415f01d8837c0990219b88efb..193b482570c7e9cc1ee41303ad67d5871b37db90 100644 --- a/drivers/video/acornfb.c +++ b/drivers/video/acornfb.c @@ -926,7 +926,6 @@ static struct fb_ops acornfb_ops = { .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, .fb_mmap = acornfb_mmap, - .fb_cursor = soft_cursor, }; /* diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index 4fc93dc2b4d3eb2e1d09536b657e9875cd5d54b7..a3c2c45e29e03e7d9e42a64036501904305ee4df 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c @@ -333,7 +333,6 @@ static struct fb_ops clcdfb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, .fb_mmap = clcdfb_mmap, }; @@ -519,7 +518,7 @@ static struct amba_driver clcd_driver = { .id_table = clcdfb_id_table, }; -int __init amba_clcdfb_init(void) +static int __init amba_clcdfb_init(void) { if (fb_get_options("ambafb", NULL)) return -ENODEV; diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index cf8bb67462dc59de02088f46429a134052d8b53a..d549e215f3c57fe944c39583baa6718d9554ee1b 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -1185,7 +1185,6 @@ static struct fb_ops amifb_ops = { .fb_fillrect = amifb_fillrect, .fb_copyarea = amifb_copyarea, .fb_imageblit = amifb_imageblit, - .fb_cursor = soft_cursor, .fb_ioctl = amifb_ioctl, }; diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c index 6aa9f824c185ce62749e276c0e05eb80755e786a..a1fc8bbb1090bfe41bfd6bc8b64e4824bc6fe748 100644 --- a/drivers/video/arcfb.c +++ b/drivers/video/arcfb.c @@ -511,7 +511,6 @@ static struct fb_ops arcfb_ops = { .fb_fillrect = arcfb_fillrect, .fb_copyarea = arcfb_copyarea, .fb_imageblit = arcfb_imageblit, - .fb_cursor = soft_cursor, .fb_ioctl = arcfb_ioctl, }; diff --git a/drivers/video/asiliantfb.c b/drivers/video/asiliantfb.c index f4729f4df8cec0f28aa8157e35c68051dc924df3..c64de59398f499e80507a3e3d582f90d8515bf19 100644 --- a/drivers/video/asiliantfb.c +++ b/drivers/video/asiliantfb.c @@ -106,7 +106,6 @@ static struct fb_ops asiliantfb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; /* Calculate the ratios for the dot clocks without using a single long long diff --git a/drivers/video/aty/ati_ids.h b/drivers/video/aty/ati_ids.h index 13321c689cf68a8937ee766e9e776f5dc0ed4581..39ab483fc25011112f7a47898c56716c3be30b43 100644 --- a/drivers/video/aty/ati_ids.h +++ b/drivers/video/aty/ati_ids.h @@ -150,6 +150,7 @@ #define PCI_CHIP_RV200_QX 0x5158 #define PCI_CHIP_RV100_QY 0x5159 #define PCI_CHIP_RV100_QZ 0x515A +#define PCI_CHIP_RN50 0x515E #define PCI_CHIP_RAGE128RE 0x5245 #define PCI_CHIP_RAGE128RF 0x5246 #define PCI_CHIP_RAGE128RG 0x5247 diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index e380ee8b0247d629ed65f62557737c2e28d58524..e686185a076d0ee52fabf164f8fa39abc9a66a0c 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -478,7 +478,6 @@ static struct fb_ops aty128fb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; #ifdef CONFIG_PMAC_BACKLIGHT diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 037fe9d32fe39bf19ed41ee1c83671565ab748b9..08edbfcfca588eaa2b6628b8eb37bcd43d4b6fde 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -292,7 +292,6 @@ static struct fb_ops atyfb_ops = { .fb_fillrect = atyfb_fillrect, .fb_copyarea = atyfb_copyarea, .fb_imageblit = atyfb_imageblit, - .fb_cursor = soft_cursor, #ifdef __sparc__ .fb_mmap = atyfb_mmap, #endif @@ -2157,11 +2156,38 @@ static void __init aty_calc_mem_refresh(struct atyfb_par *par, int xclk) static struct fb_info *fb_list = NULL; +#if defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD) +static int __devinit atyfb_get_timings_from_lcd(struct atyfb_par *par, + struct fb_var_screeninfo *var) +{ + int ret = -EINVAL; + + if (par->lcd_table != 0 && (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) { + *var = default_var; + var->xres = var->xres_virtual = par->lcd_hdisp; + var->right_margin = par->lcd_right_margin; + var->left_margin = par->lcd_hblank_len - + (par->lcd_right_margin + par->lcd_hsync_dly + + par->lcd_hsync_len); + var->hsync_len = par->lcd_hsync_len + par->lcd_hsync_dly; + var->yres = var->yres_virtual = par->lcd_vdisp; + var->lower_margin = par->lcd_lower_margin; + var->upper_margin = par->lcd_vblank_len - + (par->lcd_lower_margin + par->lcd_vsync_len); + var->vsync_len = par->lcd_vsync_len; + var->pixclock = par->lcd_pixclock; + ret = 0; + } + + return ret; +} +#endif /* defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD) */ + static int __init aty_init(struct fb_info *info, const char *name) { struct atyfb_par *par = (struct atyfb_par *) info->par; const char *ramname = NULL, *xtal; - int gtb_memsize; + int gtb_memsize, has_var = 0; struct fb_var_screeninfo var; u8 pll_ref_div; u32 i; @@ -2469,8 +2495,8 @@ static int __init aty_init(struct fb_info *info, const char *name) * applies to all Mac video cards */ if (mode) { - if (!mac_find_mode(&var, info, mode, 8)) - var = default_var; + if (mac_find_mode(&var, info, mode, 8)) + has_var = 1; } else { if (default_vmode == VMODE_CHOOSE) { if (M64_HAS(G3_PB_1024x768)) @@ -2492,20 +2518,23 @@ static int __init aty_init(struct fb_info *info, const char *name) default_vmode = VMODE_640_480_60; if (default_cmode < CMODE_8 || default_cmode > CMODE_32) default_cmode = CMODE_8; - if (mac_vmode_to_var(default_vmode, default_cmode, &var)) - var = default_var; + if (!mac_vmode_to_var(default_vmode, default_cmode, + &var)) + has_var = 1; } - } else + } + #endif /* !CONFIG_PPC */ - if ( -#if defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) - /* On Sparc, unless the user gave a specific mode - * specification, use the PROM probed values in - * default_var. - */ - !mode || + +#if defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD) + if (!atyfb_get_timings_from_lcd(par, &var)) + has_var = 1; #endif - !fb_find_mode(&var, info, mode, NULL, 0, &defmode, 8)) + + if (mode && fb_find_mode(&var, info, mode, NULL, 0, &defmode, 8)) + has_var = 1; + + if (!has_var) var = default_var; if (noaccel) diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 8a24a66d9ba8f6e7033ce0a4667c613ba8e7a183..4f01ccc02aa4c47750a22a5d338641aa86442b3e 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -69,7 +69,6 @@ #include #include #include -#include #include #include @@ -113,6 +112,7 @@ static struct pci_device_id radeonfb_pci_table[] = { /* Radeon VE/7000 */ CHIP_DEF(PCI_CHIP_RV100_QY, RV100, CHIP_HAS_CRTC2), CHIP_DEF(PCI_CHIP_RV100_QZ, RV100, CHIP_HAS_CRTC2), + CHIP_DEF(PCI_CHIP_RN50, RV100, CHIP_HAS_CRTC2), /* Radeon IGP320M (U1) */ CHIP_DEF(PCI_CHIP_RS100_4336, RS100, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY), /* Radeon IGP320 (A3) */ @@ -1874,7 +1874,6 @@ static struct fb_ops radeonfb_ops = { .fb_fillrect = radeonfb_fillrect, .fb_copyarea = radeonfb_copyarea, .fb_imageblit = radeonfb_imageblit, - .fb_cursor = soft_cursor, }; diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h index 01b8b2f785140677d249fb2d72e12cf6a4396472..217e00ab4a2d284ba899679e39727fb9b4d5dee6 100644 --- a/drivers/video/aty/radeonfb.h +++ b/drivers/video/aty/radeonfb.h @@ -10,9 +10,10 @@ #include +#ifdef CONFIG_FB_RADEON_I2C #include -#include #include +#endif #include diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c index 3d20b2d47d46cbbcfa7445453faa5ee14ec41040..f53bf3ba127898c01a480b69be8b211bf02ab561 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c @@ -51,7 +51,6 @@ static struct fb_ops bw2_ops = { .fb_imageblit = cfb_imageblit, .fb_mmap = bw2_mmap, .fb_ioctl = bw2_ioctl, - .fb_cursor = soft_cursor, }; /* OBio addresses for the bwtwo registers */ diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c index 67711f7b11b14229f6cd8604c73c05b48c966b3c..cdc71572cf356d26955ec256d42e6c1149663108 100644 --- a/drivers/video/cfbcopyarea.c +++ b/drivers/video/cfbcopyarea.c @@ -349,46 +349,10 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) unsigned long __iomem *dst = NULL, *src = NULL; int bits = BITS_PER_LONG, bytes = bits >> 3; int dst_idx = 0, src_idx = 0, rev_copy = 0; - int x2, y2, vxres, vyres; if (p->state != FBINFO_STATE_RUNNING) return; - /* We want rotation but lack hardware to do it for us. */ - if (!p->fbops->fb_rotate && p->var.rotate) { - } - - vxres = p->var.xres_virtual; - vyres = p->var.yres_virtual; - - if (area->dx > vxres || area->sx > vxres || - area->dy > vyres || area->sy > vyres) - return; - - /* clip the destination - * We could use hardware clipping but on many cards you get around - * hardware clipping by writing to framebuffer directly. - */ - x2 = area->dx + area->width; - y2 = area->dy + area->height; - dx = area->dx > 0 ? area->dx : 0; - dy = area->dy > 0 ? area->dy : 0; - x2 = x2 < vxres ? x2 : vxres; - y2 = y2 < vyres ? y2 : vyres; - width = x2 - dx; - height = y2 - dy; - - if ((width==0) ||(height==0)) - return; - - /* update sx1,sy1 */ - sx += (dx - area->dx); - sy += (dy - area->dy); - - /* the source must be completely inside the virtual screen */ - if (sx < 0 || sy < 0 || (sx + width) > vxres || (sy + height) > vyres) - return; - /* if the beginning of the target area might overlap with the end of the source area, be have to copy the area reverse. */ if ((dy == sy && dx > sx) || (dy > sy)) { diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c index e4fc42b013ebdb7f3bab16ef7f33c0d4d7a2573f..167d9314e6eb49c6ae25683e940563ef92f6ca1c 100644 --- a/drivers/video/cfbfillrect.c +++ b/drivers/video/cfbfillrect.c @@ -344,7 +344,8 @@ bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) { - unsigned long x2, y2, vxres, vyres, height, width, pat, fg; + unsigned long pat, fg; + unsigned long width = rect->width, height = rect->height; int bits = BITS_PER_LONG, bytes = bits >> 3; u32 bpp = p->var.bits_per_pixel; unsigned long __iomem *dst; @@ -353,27 +354,6 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) if (p->state != FBINFO_STATE_RUNNING) return; - /* We want rotation but lack hardware to do it for us. */ - if (!p->fbops->fb_rotate && p->var.rotate) { - } - - vxres = p->var.xres_virtual; - vyres = p->var.yres_virtual; - - if (!rect->width || !rect->height || - rect->dx > vxres || rect->dy > vyres) - return; - - /* We could use hardware clipping but on many cards you get around - * hardware clipping by writing to framebuffer directly. */ - - x2 = rect->dx + rect->width; - y2 = rect->dy + rect->height; - x2 = x2 < vxres ? x2 : vxres; - y2 = y2 < vyres ? y2 : vyres; - width = x2 - rect->dx; - height = y2 - rect->dy; - if (p->fix.visual == FB_VISUAL_TRUECOLOR || p->fix.visual == FB_VISUAL_DIRECTCOLOR ) fg = ((u32 *) (p->pseudo_palette))[rect->color]; diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c index 4c123abaa843166f43dd1ae93e77ef43fb4d1f8f..da664cea7ecac216072d5fda2aeaa05178a3e696 100644 --- a/drivers/video/cfbimgblt.c +++ b/drivers/video/cfbimgblt.c @@ -272,33 +272,13 @@ void cfb_imageblit(struct fb_info *p, const struct fb_image *image) { u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0; u32 bpl = sizeof(u32), bpp = p->var.bits_per_pixel; - u32 width = image->width, height = image->height; + u32 width = image->width; u32 dx = image->dx, dy = image->dy; - int x2, y2, vxres, vyres; u8 __iomem *dst1; if (p->state != FBINFO_STATE_RUNNING) return; - vxres = p->var.xres_virtual; - vyres = p->var.yres_virtual; - /* - * We could use hardware clipping but on many cards you get around - * hardware clipping by writing to framebuffer directly like we are - * doing here. - */ - if (image->dx > vxres || image->dy > vyres) - return; - - x2 = image->dx + image->width; - y2 = image->dy + image->height; - dx = image->dx > 0 ? image->dx : 0; - dy = image->dy > 0 ? image->dy : 0; - x2 = x2 < vxres ? x2 : vxres; - y2 = y2 < vyres ? y2 : vyres; - width = x2 - dx; - height = y2 - dy; - bitstart = (dy * p->fix.line_length * 8) + (dx * bpp); start_index = bitstart & (32 - 1); pitch_index = (p->fix.line_length & (bpl - 1)) * 8; diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c index 18e60b941e214df0311eeeb227f191775881c2d6..030d4b13b1c206a5e0ff8ec61012b00d145d8923 100644 --- a/drivers/video/cg14.c +++ b/drivers/video/cg14.c @@ -49,7 +49,6 @@ static struct fb_ops cg14_ops = { .fb_imageblit = cfb_imageblit, .fb_mmap = cg14_mmap, .fb_ioctl = cg14_ioctl, - .fb_cursor = soft_cursor, }; #define CG14_MCR_INTENABLE_SHIFT 7 diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index 6e7d8d45dc68f4e81fb29f5c1740f6c95ae23aa2..b94eee8c42d5dbacba3f2ef509d58e60726cfa2a 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c @@ -50,7 +50,6 @@ static struct fb_ops cg3_ops = { .fb_imageblit = cfb_imageblit, .fb_mmap = cg3_mmap, .fb_ioctl = cg3_ioctl, - .fb_cursor = soft_cursor, }; diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c index 49a2545671d99f92d293e66a31deb12d5bfd9d0a..414c4409e92468e0d43c68b3f5d971f84830e3cb 100644 --- a/drivers/video/cg6.c +++ b/drivers/video/cg6.c @@ -54,7 +54,6 @@ static struct fb_ops cg6_ops = { .fb_sync = cg6_sync, .fb_mmap = cg6_mmap, .fb_ioctl = cg6_ioctl, - .fb_cursor = soft_cursor, }; /* Offset of interesting structures in the OBIO space */ @@ -654,12 +653,6 @@ static void cg6_chip_init(struct fb_info *info) sbus_writel(0, &fbc->clipminy); sbus_writel(info->var.xres - 1, &fbc->clipmaxx); sbus_writel(info->var.yres - 1, &fbc->clipmaxy); - - /* Disable cursor in Brooktree DAC. */ - sbus_writel(0x06 << 24, &par->bt->addr); - tmp = sbus_readl(&par->bt->control); - tmp &= ~(0x03 << 24); - sbus_writel(tmp, &par->bt->control); } struct all_info { diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c index 4131243cfdf85e621263f547b7ebe6baf01985ca..bc061d4ec78695f70369f1276bb45b50cdd6f04f 100644 --- a/drivers/video/chipsfb.c +++ b/drivers/video/chipsfb.c @@ -91,7 +91,6 @@ static struct fb_ops chipsfb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; static int chipsfb_check_var(struct fb_var_screeninfo *var, diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index 3a26f9cc8585e796c9824bef75b7a10559d925d0..2858c5c8ba3c2fbca07c0cc4979f024d0853cd5a 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c @@ -548,7 +548,6 @@ static struct fb_ops cirrusfb_ops = { .fb_fillrect = cirrusfb_fillrect, .fb_copyarea = cirrusfb_copyarea, .fb_imageblit = cirrusfb_imageblit, - .fb_cursor = soft_cursor, }; /*--- Hardware Specific Routines -------------------------------------------*/ diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c index 8692e002986b39206d566aea80827ff859f753a9..50b78af0fa2412d4c11e5901b391f3912db55306 100644 --- a/drivers/video/clps711xfb.c +++ b/drivers/video/clps711xfb.c @@ -219,7 +219,6 @@ static struct fb_ops clps7111fb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; static int diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index 6a9ae2b3d1aba76a50a76554b5ab7ee81118e31e..fadf7c5d216e8dbae9c43c0a9eb8e91889e3dee6 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -98,6 +98,8 @@ config FRAMEBUFFER_CONSOLE tristate "Framebuffer Console support" depends on FB select CRC32 + help + Low-level framebuffer-based console driver. config STI_CONSOLE tristate "STI text console" @@ -203,5 +205,12 @@ config FONT_10x18 big letters. It fits between the sun 12x22 and the normal 8x16 font. If other fonts are too big or too small for you, say Y, otherwise say N. +config FONT_RL + bool "console Roman Large 8x16 font" if FONTS + depends on FRAMEBUFFER_CONSOLE + help + This is the visually-appealing "RL" console font that is + included with the kbd package. + endmenu diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile index 42c7b8dcd22073397da5f89bdf94ddc62dc71204..5222628accce31ca8ea63ce844909dc2a286b64a 100644 --- a/drivers/video/console/Makefile +++ b/drivers/video/console/Makefile @@ -15,6 +15,7 @@ font-objs-$(CONFIG_FONT_10x18) += font_10x18.o font-objs-$(CONFIG_FONT_PEARL_8x8) += font_pearl_8x8.o font-objs-$(CONFIG_FONT_ACORN_8x8) += font_acorn_8x8.o font-objs-$(CONFIG_FONT_MINI_4x6) += font_mini_4x6.o +font-objs-$(CONFIG_FONT_RL) += font_rl.o font-objs += $(font-objs-y) @@ -26,7 +27,7 @@ obj-$(CONFIG_PROM_CONSOLE) += promcon.o promcon_tbl.o obj-$(CONFIG_STI_CONSOLE) += sticon.o sticore.o font.o obj-$(CONFIG_VGA_CONSOLE) += vgacon.o obj-$(CONFIG_MDA_CONSOLE) += mdacon.o -obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o bitblit.o font.o +obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o bitblit.o font.o softcursor.o ifeq ($(CONFIG_FB_TILEBLITTING),y) obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += tileblit.o endif diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c index 9f70e512b88bfe0ea54e09c236ec456f5fdc05ac..67857b3cfc8b416f4fe081e940c634ee85531681 100644 --- a/drivers/video/console/bitblit.c +++ b/drivers/video/console/bitblit.c @@ -272,6 +272,7 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int w = (vc->vc_font.width + 7) >> 3, c; int y = real_y(p, vc->vc_y); int attribute, use_sw = (vc->vc_cursor_type & 0x10); + int err = 1; char *src; cursor.set = 0; @@ -408,7 +409,11 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, cursor.image.depth = 1; cursor.rop = ROP_XOR; - info->fbops->fb_cursor(info, &cursor); + if (info->fbops->fb_cursor) + err = info->fbops->fb_cursor(info, &cursor); + + if (err) + soft_cursor(info, &cursor); ops->cursor_reset = 0; } diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 0fc8bb499c3facf6f75c9ea4259cf62eaf876a13..3cf1b61ff1f8a1dfbdedade08a89cee7381e0c22 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -281,6 +281,18 @@ static inline int get_color(struct vc_data *vc, struct fb_info *info, return color; } +static void fbcon_update_softback(struct vc_data *vc) +{ + int l = fbcon_softback_size / vc->vc_size_row; + + if (l > 5) + softback_end = softback_buf + l * vc->vc_size_row; + else + /* Smaller scrollback makes no sense, and 0 would screw + the operation totally */ + softback_top = 0; +} + static void fb_flashcursor(void *private) { struct fb_info *info = private; @@ -618,6 +630,15 @@ static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo, kfree(oldinfo->fbcon_par); oldinfo->fbcon_par = NULL; module_put(oldinfo->fbops->owner); + /* + If oldinfo and newinfo are driving the same hardware, + the fb_release() method of oldinfo may attempt to + restore the hardware state. This will leave the + newinfo in an undefined state. Thus, a call to + fb_set_par() may be needed for the newinfo. + */ + if (newinfo->fbops->fb_set_par) + newinfo->fbops->fb_set_par(newinfo); } return err; @@ -1007,16 +1028,8 @@ static void fbcon_init(struct vc_data *vc, int init) if (logo) fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows); - if (vc == svc && softback_buf) { - int l = fbcon_softback_size / vc->vc_size_row; - if (l > 5) - softback_end = softback_buf + l * vc->vc_size_row; - else { - /* Smaller scrollback makes no sense, and 0 would screw - the operation totally */ - softback_top = 0; - } - } + if (vc == svc && softback_buf) + fbcon_update_softback(vc); } static void fbcon_deinit(struct vc_data *vc) @@ -1223,18 +1236,8 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, vc_resize(vc, cols, rows); if (CON_IS_VISIBLE(vc)) { update_screen(vc); - if (softback_buf) { - int l = fbcon_softback_size / vc->vc_size_row; - - if (l > 5) - softback_end = softback_buf + l * - vc->vc_size_row; - else { - /* Smaller scrollback makes no sense, and 0 - would screw the operation totally */ - softback_top = 0; - } - } + if (softback_buf) + fbcon_update_softback(vc); } } @@ -1892,24 +1895,11 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width, mode = fb_find_best_mode(&var, &info->modelist); if (mode == NULL) return -EINVAL; + display_to_var(&var, p); fb_videomode_to_var(&var, mode); + if (width > var.xres/fw || height > var.yres/fh) return -EINVAL; - /* - * The following can probably have any value... Do we need to - * set all of them? - */ - var.bits_per_pixel = p->bits_per_pixel; - var.xres_virtual = p->xres_virtual; - var.yres_virtual = p->yres_virtual; - var.accel_flags = p->accel_flags; - var.width = p->width; - var.height = p->height; - var.red = p->red; - var.green = p->green; - var.blue = p->blue; - var.transp = p->transp; - var.nonstd = p->nonstd; DPRINTK("resize now %ix%i\n", var.xres, var.yres); if (CON_IS_VISIBLE(vc)) { @@ -1933,19 +1923,11 @@ static int fbcon_switch(struct vc_data *vc) info = registered_fb[con2fb_map[vc->vc_num]]; if (softback_top) { - int l = fbcon_softback_size / vc->vc_size_row; if (softback_lines) fbcon_set_origin(vc); softback_top = softback_curr = softback_in = softback_buf; softback_lines = 0; - - if (l > 5) - softback_end = softback_buf + l * vc->vc_size_row; - else { - /* Smaller scrollback makes no sense, and 0 would screw - the operation totally */ - softback_top = 0; - } + fbcon_update_softback(vc); } if (logo_shown >= 0) { @@ -2235,17 +2217,8 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, /* reset wrap/pan */ info->var.xoffset = info->var.yoffset = p->yscroll = 0; vc_resize(vc, info->var.xres / w, info->var.yres / h); - if (CON_IS_VISIBLE(vc) && softback_buf) { - int l = fbcon_softback_size / vc->vc_size_row; - if (l > 5) - softback_end = - softback_buf + l * vc->vc_size_row; - else { - /* Smaller scrollback makes no sense, and 0 would screw - the operation totally */ - softback_top = 0; - } - } + if (CON_IS_VISIBLE(vc) && softback_buf) + fbcon_update_softback(vc); } else if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) { fbcon_clear_margins(vc, 0); @@ -2615,16 +2588,8 @@ static void fbcon_modechanged(struct fb_info *info) update_var(vc->vc_num, info); fbcon_set_palette(vc, color_table); update_screen(vc); - if (softback_buf) { - int l = fbcon_softback_size / vc->vc_size_row; - if (l > 5) - softback_end = softback_buf + l * vc->vc_size_row; - else { - /* Smaller scrollback makes no sense, and 0 - would screw the operation totally */ - softback_top = 0; - } - } + if (softback_buf) + fbcon_update_softback(vc); } } @@ -2659,16 +2624,8 @@ static void fbcon_set_all_vcs(struct fb_info *info) update_var(vc->vc_num, info); fbcon_set_palette(vc, color_table); update_screen(vc); - if (softback_buf) { - int l = fbcon_softback_size / vc->vc_size_row; - if (l > 5) - softback_end = softback_buf + l * vc->vc_size_row; - else { - /* Smaller scrollback makes no sense, and 0 - would screw the operation totally */ - softback_top = 0; - } - } + if (softback_buf) + fbcon_update_softback(vc); } } } @@ -2758,7 +2715,8 @@ static void fbcon_new_modelist(struct fb_info *info) continue; vc = vc_cons[i].d; display_to_var(&var, &fb_display[i]); - mode = fb_find_nearest_mode(&var, &info->modelist); + mode = fb_find_nearest_mode(fb_display[i].mode, + &info->modelist); fb_videomode_to_var(&var, mode); if (vc) diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h index 0738cd62def219f743c34b93586efeb9e033596d..b68e0e2c2d1657c1c4c5e1aabd2b26591404bc02 100644 --- a/drivers/video/console/fbcon.h +++ b/drivers/video/console/fbcon.h @@ -167,5 +167,5 @@ extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info, struct display *p, struct fbcon_ops *ops); #endif extern void fbcon_set_bitops(struct fbcon_ops *ops); - +extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor); #endif /* _VIDEO_FBCON_H */ diff --git a/drivers/video/console/font_rl.c b/drivers/video/console/font_rl.c new file mode 100644 index 0000000000000000000000000000000000000000..dfecc27d8ded2c971395312b4c6131c8243b50c3 --- /dev/null +++ b/drivers/video/console/font_rl.c @@ -0,0 +1,4374 @@ + +/* This font is simply the "rl.fnt" console font from the kbd utility. + * Converted by Zack T Smith, fbui@comcast.net. + * The original binary file is covered under the GNU Public License. + */ + +#include + +#define FONTDATAMAX 4096 + +static unsigned char patterns[4096] = { +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x3c, +0x42, +0x81, +0xe7, +0xa5, +0x99, +0x81, +0x81, +0x99, +0x42, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x3c, +0x7e, +0xff, +0x99, +0xdb, +0xe7, +0xff, +0xff, +0xe7, +0x7e, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x6c, +0xfe, +0xfe, +0xfe, +0xfe, +0xfe, +0x7c, +0x38, +0x10, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x10, +0x38, +0x7c, +0xfe, +0x7c, +0x38, +0x10, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x38, +0x38, +0x10, +0xd6, +0xfe, +0xd6, +0x10, +0x10, +0x38, +0x7c, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x10, +0x38, +0x7c, +0xfe, +0xfe, +0x54, +0x10, +0x10, +0x38, +0x7c, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x18, +0x3c, +0x3c, +0x18, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0xff, +0xff, +0xff, +0xff, +0xff, +0xff, +0xe7, +0xc3, +0xc3, +0xe7, +0xff, +0xff, +0xff, +0xff, +0xff, +0xff, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x3c, +0x66, +0x42, +0x42, +0x66, +0x3c, +0x00, +0x00, +0x00, +0x00, +0x00, + +0xff, +0xff, +0xff, +0xff, +0xff, +0xc3, +0x99, +0xbd, +0xbd, +0x99, +0xc3, +0xff, +0xff, +0xff, +0xff, +0xff, + +0x00, +0x00, +0x0f, +0x07, +0x0d, +0x18, +0x78, +0xcc, +0xcc, +0xcc, +0xcc, +0x78, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x3c, +0x66, +0x66, +0x66, +0x3c, +0x18, +0x7e, +0x18, +0x18, +0x18, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x08, +0x0c, +0x0a, +0x0a, +0x0a, +0x08, +0x08, +0x08, +0x38, +0x78, +0x30, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x10, +0x18, +0x1c, +0x1e, +0x1e, +0x16, +0x12, +0x72, +0xf2, +0x62, +0x0e, +0x1e, +0x0c, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x10, +0x92, +0x54, +0x38, +0xfe, +0x38, +0x54, +0x92, +0x10, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x80, +0xc0, +0xe0, +0xb8, +0x8e, +0xb8, +0xe0, +0xc0, +0x80, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x02, +0x06, +0x0e, +0x3a, +0xe2, +0x3a, +0x0e, +0x06, +0x02, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x10, +0x38, +0x7c, +0xd6, +0x10, +0x10, +0x10, +0x10, +0xd6, +0x7c, +0x38, +0x10, +0x00, +0x00, + +0x00, +0x42, +0xe7, +0xe7, +0xe7, +0xe7, +0x42, +0x42, +0x42, +0x00, +0x66, +0x66, +0x66, +0x00, +0x00, +0x00, + +0x00, +0x7f, +0xca, +0xca, +0xca, +0xca, +0x7a, +0x0a, +0x0a, +0x0a, +0x0a, +0x0a, +0x1b, +0x00, +0x00, +0x00, + +0x00, +0x1e, +0x31, +0x78, +0xcc, +0xc6, +0xc3, +0x63, +0x33, +0x1e, +0x8c, +0x78, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xfe, +0xfe, +0xfe, +0xfe, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x10, +0x38, +0x7c, +0xd6, +0x10, +0x10, +0x10, +0x10, +0xd6, +0x7c, +0x38, +0x10, +0xfe, +0x00, + +0x00, +0x00, +0x10, +0x38, +0x7c, +0xd6, +0x10, +0x10, +0x10, +0x10, +0x10, +0x10, +0x10, +0x10, +0x00, +0x00, + +0x00, +0x00, +0x10, +0x10, +0x10, +0x10, +0x10, +0x10, +0x10, +0x10, +0xd6, +0x7c, +0x38, +0x10, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x08, +0x0c, +0x06, +0xff, +0x06, +0x0c, +0x08, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x10, +0x30, +0x60, +0xff, +0x60, +0x30, +0x10, +0x00, +0x00, +0x00, +0x00, + +0x22, +0x44, +0x88, +0xcc, +0xee, +0x44, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x24, +0x42, +0xff, +0x42, +0x24, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x10, +0x38, +0x38, +0x6c, +0x6c, +0xc6, +0xfe, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0xfe, +0xc6, +0x6c, +0x6c, +0x38, +0x38, +0x10, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x18, +0x3c, +0x3c, +0x3c, +0x3c, +0x18, +0x18, +0x18, +0x10, +0x00, +0x18, +0x18, +0x00, +0x00, +0x00, + +0x22, +0x77, +0x33, +0x11, +0x22, +0x44, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x12, +0x12, +0x12, +0x7f, +0x24, +0x24, +0x24, +0xfe, +0x48, +0x48, +0x48, +0x00, +0x00, +0x00, + +0x10, +0x10, +0x7c, +0xd2, +0xd0, +0xd0, +0xd0, +0x7c, +0x16, +0x16, +0x16, +0x96, +0x7c, +0x10, +0x10, +0x00, + +0x00, +0x42, +0xbe, +0x44, +0x0c, +0x08, +0x18, +0x10, +0x30, +0x20, +0x64, +0x4a, +0xc4, +0x00, +0x00, +0x00, + +0x00, +0x38, +0x6c, +0x6c, +0x6c, +0x38, +0x37, +0x72, +0xdc, +0xcc, +0xcc, +0xcc, +0x77, +0x00, +0x00, +0x00, + +0x10, +0x38, +0x18, +0x08, +0x10, +0x20, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x04, +0x08, +0x10, +0x10, +0x30, +0x30, +0x30, +0x30, +0x30, +0x10, +0x10, +0x08, +0x04, +0x00, +0x00, + +0x00, +0x20, +0x10, +0x08, +0x08, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x08, +0x08, +0x10, +0x20, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x44, +0x28, +0x38, +0xfe, +0x38, +0x28, +0x44, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x18, +0x18, +0x7e, +0x18, +0x18, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x10, +0x38, +0x18, +0x08, +0x10, +0x20, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x7e, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x10, +0x38, +0x10, +0x00, +0x00, +0x00, + +0x00, +0x06, +0x06, +0x0c, +0x0c, +0x18, +0x18, +0x30, +0x30, +0x60, +0x60, +0xc0, +0xc0, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x3c, +0x46, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc4, +0x78, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x08, +0x18, +0x78, +0x18, +0x18, +0x18, +0x18, +0x18, +0x7e, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x7c, +0x86, +0x06, +0x0c, +0x18, +0x20, +0x40, +0xc1, +0xfe, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x3c, +0x46, +0x04, +0x08, +0x1c, +0x06, +0x06, +0x06, +0x06, +0x0c, +0x70, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x04, +0x08, +0x10, +0x2c, +0x4c, +0x8c, +0x8c, +0xfe, +0x0c, +0x0c, +0x0c, +0x00, + +0x00, +0x00, +0x00, +0x02, +0x3c, +0x20, +0x20, +0x70, +0x0c, +0x06, +0x06, +0x06, +0x06, +0x0c, +0x70, +0x00, + +0x00, +0x00, +0x18, +0x20, +0x40, +0xc0, +0xdc, +0xc6, +0xc6, +0xc6, +0xc6, +0x44, +0x38, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x40, +0x7e, +0x82, +0x06, +0x04, +0x0c, +0x18, +0x18, +0x30, +0x30, +0x30, +0x30, +0x00, + +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0x64, +0x38, +0x4c, +0xc6, +0xc6, +0xc6, +0xc6, +0x7c, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x38, +0x44, +0xc6, +0xc6, +0x76, +0x06, +0x06, +0x06, +0x04, +0x08, +0x30, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x10, +0x38, +0x10, +0x00, +0x00, +0x00, +0x10, +0x38, +0x10, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x10, +0x38, +0x10, +0x00, +0x00, +0x00, +0x10, +0x38, +0x18, +0x08, +0x10, +0x20, + +0x00, +0x06, +0x0c, +0x18, +0x30, +0x60, +0xa0, +0xa0, +0x60, +0x30, +0x18, +0x0c, +0x06, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x7e, +0x00, +0x00, +0x7e, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x60, +0x30, +0x18, +0x0c, +0x06, +0x05, +0x05, +0x06, +0x0c, +0x18, +0x30, +0x60, +0x00, +0x00, +0x00, + +0x00, +0x7c, +0x86, +0xc6, +0x06, +0x04, +0x08, +0x10, +0x10, +0x18, +0x00, +0x18, +0x18, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x3c, +0x46, +0xc6, +0xce, +0xd6, +0xd6, +0xd6, +0xdc, +0xc0, +0xc4, +0x78, +0x00, +0x00, +0x00, + +0x00, +0x18, +0x18, +0x18, +0x3c, +0x2c, +0x2c, +0x2c, +0x7e, +0x46, +0x46, +0x46, +0xef, +0x00, +0x00, +0x00, + +0x00, +0xfc, +0x66, +0x66, +0x66, +0x66, +0x7c, +0x66, +0x66, +0x66, +0x66, +0x66, +0xfc, +0x00, +0x00, +0x00, + +0x00, +0x3a, +0x66, +0xc2, +0xc0, +0xc0, +0xc0, +0xc0, +0xc0, +0xc0, +0xc0, +0x62, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0xfc, +0x66, +0x63, +0x63, +0x63, +0x63, +0x63, +0x63, +0x63, +0x63, +0x66, +0xfc, +0x00, +0x00, +0x00, + +0x00, +0xff, +0x61, +0x60, +0x60, +0x64, +0x7c, +0x64, +0x60, +0x60, +0x60, +0x61, +0xfe, +0x00, +0x00, +0x00, + +0x00, +0xff, +0x61, +0x61, +0x60, +0x64, +0x7c, +0x64, +0x60, +0x60, +0x60, +0x60, +0xf0, +0x00, +0x00, +0x00, + +0x00, +0x3a, +0x66, +0xc2, +0xc0, +0xc0, +0xc0, +0xcf, +0xc6, +0xc6, +0xc6, +0x66, +0x38, +0x00, +0x00, +0x00, + +0x00, +0xf7, +0x62, +0x62, +0x62, +0x62, +0x7e, +0x62, +0x62, +0x62, +0x62, +0x62, +0xf7, +0x00, +0x00, +0x00, + +0x00, +0x3c, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x1e, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x08, +0xf0, + +0x00, +0xf7, +0x64, +0x6c, +0x68, +0x68, +0x78, +0x6c, +0x6c, +0x6c, +0x66, +0x66, +0xf7, +0x00, +0x00, +0x00, + +0x00, +0xf8, +0x60, +0x60, +0x60, +0x60, +0x60, +0x60, +0x60, +0x60, +0x60, +0x61, +0xfe, +0x00, +0x00, +0x00, + +0x00, +0xc3, +0x66, +0x76, +0x7e, +0x56, +0x56, +0x46, +0x46, +0x46, +0x46, +0x46, +0xef, +0x00, +0x00, +0x00, + +0x00, +0xe7, +0x62, +0x62, +0x72, +0x52, +0x5a, +0x4a, +0x4e, +0x46, +0x46, +0x42, +0xe2, +0x00, +0x00, +0x00, + +0x00, +0x3c, +0x66, +0xc3, +0xc3, +0xc3, +0xc3, +0xc3, +0xc3, +0xc3, +0xc3, +0x66, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0xfc, +0x66, +0x66, +0x66, +0x66, +0x6c, +0x60, +0x60, +0x60, +0x60, +0x60, +0xf0, +0x00, +0x00, +0x00, + +0x00, +0x3c, +0x66, +0xc3, +0xc3, +0xc3, +0xc3, +0xc3, +0xc3, +0xc3, +0xc3, +0x66, +0x3c, +0x10, +0x39, +0x0e, + +0x00, +0xfc, +0x66, +0x66, +0x66, +0x66, +0x7c, +0x6c, +0x66, +0x66, +0x66, +0x66, +0xf3, +0x00, +0x00, +0x00, + +0x00, +0x7a, +0xc6, +0xc2, +0xc0, +0x70, +0x3c, +0x0e, +0x06, +0x06, +0x86, +0xc6, +0xbc, +0x00, +0x00, +0x00, + +0x00, +0xff, +0x99, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0xf7, +0x62, +0x62, +0x62, +0x62, +0x62, +0x62, +0x62, +0x62, +0x62, +0x62, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0xf7, +0x62, +0x62, +0x62, +0x76, +0x34, +0x34, +0x34, +0x3c, +0x18, +0x18, +0x18, +0x00, +0x00, +0x00, + +0x00, +0xf7, +0x62, +0x62, +0x62, +0x62, +0x6a, +0x6a, +0x6a, +0x6a, +0x7e, +0x7e, +0x34, +0x00, +0x00, +0x00, + +0x00, +0xf7, +0x62, +0x62, +0x34, +0x34, +0x18, +0x18, +0x2c, +0x2c, +0x46, +0x46, +0xef, +0x00, +0x00, +0x00, + +0x00, +0xf7, +0x62, +0x62, +0x62, +0x34, +0x34, +0x18, +0x18, +0x18, +0x18, +0x18, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x7f, +0x46, +0x86, +0x0c, +0x0c, +0x18, +0x18, +0x30, +0x30, +0x61, +0x62, +0xfe, +0x00, +0x00, +0x00, + +0x00, +0x3c, +0x30, +0x30, +0x30, +0x30, +0x30, +0x30, +0x30, +0x30, +0x30, +0x30, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0xc0, +0xc0, +0x60, +0x60, +0x30, +0x30, +0x18, +0x18, +0x0c, +0x0c, +0x06, +0x06, +0x00, +0x00, +0x00, + +0x00, +0x3c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x10, +0x38, +0x4c, +0x86, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xff, +0x00, +0x00, + +0x00, +0x18, +0x20, +0x30, +0x38, +0x10, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x78, +0x8c, +0x0c, +0x3c, +0xcc, +0xcc, +0xcd, +0x76, +0x00, +0x00, +0x00, + +0x00, +0x20, +0xe0, +0x60, +0x60, +0x6c, +0x76, +0x66, +0x66, +0x66, +0x66, +0x76, +0x6c, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x3c, +0x66, +0x60, +0x60, +0x60, +0x60, +0x62, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x04, +0x1c, +0x0c, +0x0c, +0x6c, +0xdc, +0xcc, +0xcc, +0xcc, +0xcc, +0xdc, +0x66, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x3c, +0x66, +0x7e, +0x60, +0x60, +0x60, +0x62, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x1e, +0x31, +0x33, +0x30, +0x30, +0x78, +0x30, +0x30, +0x30, +0x30, +0x30, +0x78, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x7b, +0xce, +0xcc, +0xcc, +0xcc, +0x78, +0x60, +0x7c, +0x86, +0xc6, +0x7c, + +0x00, +0x20, +0xe0, +0x60, +0x60, +0x6c, +0x76, +0x66, +0x66, +0x66, +0x66, +0x66, +0xf7, +0x00, +0x00, +0x00, + +0x00, +0x10, +0x38, +0x10, +0x00, +0x18, +0x38, +0x18, +0x18, +0x18, +0x18, +0x18, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x08, +0x1c, +0x08, +0x00, +0x0c, +0x1c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x6c, +0x4c, +0x38, +0x00, + +0x00, +0x20, +0xe0, +0x60, +0x60, +0x67, +0x66, +0x6c, +0x78, +0x6c, +0x6c, +0x66, +0xe7, +0x00, +0x00, +0x00, + +0x00, +0x08, +0x38, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x6a, +0xfe, +0x6a, +0x6a, +0x6a, +0x62, +0x62, +0xf7, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x5c, +0xf6, +0x66, +0x66, +0x66, +0x66, +0x66, +0xf7, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x3c, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x5c, +0xe6, +0x66, +0x66, +0x66, +0x66, +0x66, +0x7c, +0x60, +0x60, +0xf0, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x76, +0xcc, +0xcc, +0xcc, +0xcc, +0xcc, +0xcc, +0x7c, +0x0c, +0x0c, +0x1e, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x5e, +0xf6, +0x60, +0x60, +0x60, +0x60, +0x60, +0xf0, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x7a, +0xc6, +0x72, +0x1c, +0x06, +0x86, +0xc6, +0xbc, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x10, +0x30, +0x7c, +0x30, +0x30, +0x30, +0x30, +0x30, +0x34, +0x18, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0xee, +0x66, +0x66, +0x66, +0x66, +0x66, +0x67, +0x3a, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0xf7, +0x62, +0x76, +0x34, +0x34, +0x3c, +0x18, +0x18, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0xf7, +0x62, +0x6a, +0x6a, +0x6a, +0x6a, +0x7e, +0x24, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0xf7, +0x62, +0x34, +0x18, +0x2c, +0x46, +0x46, +0xef, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0xf7, +0x62, +0x62, +0x34, +0x34, +0x18, +0x18, +0x18, +0x10, +0xb0, +0xe0, + +0x00, +0x00, +0x00, +0x00, +0x00, +0xfe, +0x8c, +0x18, +0x30, +0x30, +0x60, +0xc2, +0xfe, +0x00, +0x00, +0x00, + +0x00, +0x0e, +0x18, +0x10, +0x10, +0x08, +0x70, +0x70, +0x08, +0x10, +0x10, +0x18, +0x0e, +0x00, +0x00, +0x00, + +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x00, +0x00, + +0x00, +0x70, +0x18, +0x08, +0x08, +0x10, +0x0e, +0x0e, +0x10, +0x08, +0x08, +0x18, +0x70, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x76, +0xdc, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x10, +0x38, +0x6c, +0xc6, +0xc6, +0xc6, +0xfe, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x3a, +0x66, +0xc2, +0xc0, +0xc0, +0xc0, +0xc0, +0xc0, +0x62, +0x3c, +0x18, +0x0c, +0x24, +0x18, + +0x00, +0x00, +0x66, +0x00, +0x00, +0xee, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x3b, +0x00, +0x00, +0x00, + +0x00, +0x0c, +0x18, +0x20, +0x00, +0x3c, +0x66, +0x7e, +0x60, +0x60, +0x60, +0x62, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x30, +0x58, +0x8c, +0x00, +0x78, +0x8c, +0x0c, +0x3c, +0xcc, +0xcc, +0xcd, +0x76, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x66, +0x00, +0x00, +0x78, +0x8c, +0x0c, +0x3c, +0xcc, +0xcc, +0xcd, +0x76, +0x00, +0x00, +0x00, + +0x00, +0x30, +0x18, +0x04, +0x00, +0x78, +0x8c, +0x0c, +0x3c, +0xcc, +0xcc, +0xcd, +0x76, +0x00, +0x00, +0x00, + +0x38, +0x44, +0x44, +0x38, +0x00, +0x78, +0x8c, +0x0c, +0x3c, +0xcc, +0xcc, +0xcd, +0x76, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x3c, +0x66, +0x60, +0x60, +0x60, +0x60, +0x62, +0x3c, +0x08, +0x24, +0x18, + +0x00, +0x18, +0x2c, +0x46, +0x00, +0x3c, +0x66, +0x7e, +0x60, +0x60, +0x60, +0x62, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x66, +0x00, +0x00, +0x3c, +0x66, +0x7e, +0x60, +0x60, +0x60, +0x62, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x30, +0x18, +0x04, +0x00, +0x3c, +0x66, +0x7e, +0x60, +0x60, +0x60, +0x62, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x66, +0x00, +0x00, +0x38, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x18, +0x2c, +0x46, +0x00, +0x38, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x60, +0x30, +0x08, +0x00, +0x38, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x3c, +0x00, +0x00, +0x00, + +0x66, +0x18, +0x18, +0x18, +0x3c, +0x2c, +0x2c, +0x2c, +0x7e, +0x46, +0x46, +0x46, +0xef, +0x00, +0x00, +0x00, + +0x18, +0x24, +0x18, +0x18, +0x3c, +0x2c, +0x2c, +0x2c, +0x7e, +0x46, +0x46, +0x46, +0xef, +0x00, +0x00, +0x00, + +0x0c, +0x18, +0xff, +0x61, +0x60, +0x60, +0x64, +0x7c, +0x64, +0x60, +0x60, +0x61, +0xfe, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x76, +0x9b, +0x1b, +0x3f, +0xd8, +0xd8, +0xd9, +0x6e, +0x00, +0x00, +0x00, + +0x00, +0x1f, +0x1d, +0x1d, +0x3c, +0x2c, +0x2e, +0x2c, +0x7c, +0x4c, +0x4c, +0x4d, +0xef, +0x00, +0x00, +0x00, + +0x00, +0x18, +0x2c, +0x46, +0x00, +0x3c, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x66, +0x00, +0x00, +0x3c, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x30, +0x18, +0x04, +0x00, +0x3c, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x18, +0x2c, +0x46, +0x00, +0xee, +0x66, +0x66, +0x66, +0x66, +0x66, +0x67, +0x3a, +0x00, +0x00, +0x00, + +0x00, +0x30, +0x18, +0x04, +0x00, +0xee, +0x66, +0x66, +0x66, +0x66, +0x66, +0x67, +0x3a, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x66, +0x00, +0x00, +0xf7, +0x62, +0x62, +0x34, +0x34, +0x18, +0x18, +0x18, +0x10, +0xb0, +0xe0, + +0x66, +0x00, +0x3c, +0x66, +0xc3, +0xc3, +0xc3, +0xc3, +0xc3, +0xc3, +0xc3, +0x66, +0x3c, +0x00, +0x00, +0x00, + +0x66, +0x00, +0xf7, +0x62, +0x62, +0x62, +0x62, +0x62, +0x62, +0x62, +0x62, +0x62, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x10, +0x10, +0x10, +0x7c, +0xc6, +0xc0, +0xc0, +0xc0, +0xc0, +0xc2, +0x7c, +0x10, +0x10, +0x00, + +0x00, +0x38, +0x64, +0x6c, +0x60, +0x60, +0xf0, +0x60, +0x60, +0x60, +0x60, +0x66, +0xfc, +0x00, +0x00, +0x00, + +0x00, +0x81, +0xc3, +0x66, +0x3c, +0x18, +0xff, +0x18, +0x18, +0xff, +0x18, +0x18, +0x18, +0x00, +0x00, +0x00, + +0x00, +0xfe, +0x63, +0x63, +0x63, +0x63, +0x6e, +0x60, +0x64, +0x6e, +0x64, +0x64, +0xf5, +0x06, +0x00, +0x00, + +0x00, +0x0e, +0x19, +0x1b, +0x18, +0x18, +0x3c, +0x18, +0x18, +0x18, +0x18, +0xd8, +0x98, +0x70, +0x00, +0x00, + +0x00, +0x0c, +0x18, +0x20, +0x00, +0x78, +0x8c, +0x0c, +0x3c, +0xcc, +0xcc, +0xcd, +0x76, +0x00, +0x00, +0x00, + +0x00, +0x06, +0x0c, +0x10, +0x00, +0x38, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x0c, +0x18, +0x20, +0x00, +0x3c, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x0c, +0x18, +0x20, +0x00, +0xee, +0x66, +0x66, +0x66, +0x66, +0x66, +0x67, +0x3a, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x32, +0x4c, +0x00, +0x5c, +0xf6, +0x66, +0x66, +0x66, +0x66, +0x66, +0xf7, +0x00, +0x00, +0x00, + +0x32, +0x4c, +0x00, +0xe7, +0x72, +0x52, +0x5a, +0x4a, +0x4e, +0x46, +0x46, +0x42, +0xe2, +0x00, +0x00, +0x00, + +0x00, +0x78, +0x8c, +0x0c, +0x3c, +0xcc, +0xcc, +0xcd, +0x76, +0x00, +0xfe, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x3c, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x3c, +0x00, +0x7e, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x30, +0x30, +0x00, +0x30, +0x10, +0x10, +0x20, +0x40, +0xc0, +0xc6, +0xc2, +0x7c, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xfe, +0xc0, +0xc0, +0xc0, +0xc0, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xfe, +0x06, +0x06, +0x06, +0x06, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x20, +0xe0, +0x63, +0x66, +0xfc, +0x18, +0x30, +0x60, +0xce, +0x93, +0x06, +0x0c, +0x1f, +0x00, +0x00, + +0x00, +0x20, +0xe0, +0x63, +0x66, +0xfc, +0x18, +0x30, +0x64, +0xc8, +0x96, +0x3f, +0x06, +0x06, +0x00, +0x00, + +0x00, +0x18, +0x18, +0x00, +0x08, +0x18, +0x18, +0x18, +0x3c, +0x3c, +0x3c, +0x3c, +0x18, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x36, +0x6c, +0xd8, +0xd8, +0x6c, +0x36, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0xd8, +0x6c, +0x36, +0x36, +0x6c, +0xd8, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x82, +0x10, +0x82, +0x10, +0x82, +0x10, +0x82, +0x10, +0x82, +0x10, +0x82, +0x10, +0x82, +0x10, +0x82, +0x10, + +0x00, +0x95, +0x00, +0xa9, +0x00, +0x95, +0x00, +0xa9, +0x00, +0x95, +0x00, +0xa9, +0x00, +0x95, +0x00, +0xa9, + +0x92, +0x49, +0x92, +0x49, +0x92, +0x49, +0x92, +0x49, +0x92, +0x49, +0x92, +0x49, +0x92, +0x49, +0x92, +0x49, + +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, + +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0xf8, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, + +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0xf8, +0x18, +0x18, +0xf8, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, + +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0xe6, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xfe, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xf8, +0x18, +0x18, +0xf8, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, + +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0xe6, +0x06, +0x06, +0xe6, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, + +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xfe, +0x06, +0x06, +0xe6, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, + +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0xe6, +0x06, +0x06, +0xfe, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0xfe, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0xf8, +0x18, +0x18, +0xf8, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xf8, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, + +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x1f, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0xff, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xff, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, + +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x1f, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xff, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0xff, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, + +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x1f, +0x18, +0x18, +0x1f, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, + +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x67, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, + +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x67, +0x60, +0x60, +0x7f, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x7f, +0x60, +0x60, +0x67, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, + +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0xe7, +0x00, +0x00, +0xff, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xff, +0x00, +0x00, +0xe7, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, + +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x67, +0x60, +0x60, +0x67, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xff, +0x00, +0x00, +0xff, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0xe7, +0x00, +0x00, +0xe7, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, + +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0xff, +0x00, +0x00, +0xff, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0xff, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xff, +0x00, +0x00, +0xff, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xff, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, + +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x7f, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x1f, +0x18, +0x18, +0x1f, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x1f, +0x18, +0x18, +0x1f, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x7f, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, + +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0xff, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, + +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0xff, +0x00, +0x00, +0xff, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, + +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0xf8, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x1f, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, + +0xff, +0xff, +0xff, +0xff, +0xff, +0xff, +0xff, +0xff, +0xff, +0xff, +0xff, +0xff, +0xff, +0xff, +0xff, +0xff, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xff, +0xff, +0xff, +0xff, +0xff, +0xff, +0xff, +0xff, + +0xf0, +0xf0, +0xf0, +0xf0, +0xf0, +0xf0, +0xf0, +0xf0, +0xf0, +0xf0, +0xf0, +0xf0, +0xf0, +0xf0, +0xf0, +0xf0, + +0x0f, +0x0f, +0x0f, +0x0f, +0x0f, +0x0f, +0x0f, +0x0f, +0x0f, +0x0f, +0x0f, +0x0f, +0x0f, +0x0f, +0x0f, +0x0f, + +0xff, +0xff, +0xff, +0xff, +0xff, +0xff, +0xff, +0xff, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x77, +0xcc, +0xcc, +0xcc, +0xcc, +0xde, +0x73, +0x00, +0x00, +0x00, + +0x00, +0x7c, +0xc6, +0xc6, +0xc6, +0xc4, +0xc8, +0xc4, +0xc6, +0xc6, +0xc6, +0xc6, +0xdc, +0xc0, +0xc0, +0x00, + +0x00, +0xff, +0x61, +0x60, +0x60, +0x60, +0x60, +0x60, +0x60, +0x60, +0x60, +0x60, +0xf0, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x01, +0x7e, +0xa4, +0x24, +0x2c, +0x6c, +0x6c, +0x6c, +0x48, +0x00, +0x00, +0x00, + +0x00, +0xff, +0xc1, +0x60, +0x30, +0x18, +0x0c, +0x18, +0x30, +0x60, +0xc0, +0xc1, +0xfe, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x7f, +0xc8, +0xc8, +0xc8, +0xc8, +0xc8, +0xc8, +0x70, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x22, +0x66, +0x66, +0x66, +0x66, +0x66, +0x7c, +0x60, +0x60, +0x60, +0xc0, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x76, +0xdc, +0x18, +0x18, +0x18, +0x18, +0x18, +0x10, +0x00, +0x00, +0x00, + +0x00, +0x38, +0x10, +0x7c, +0xd6, +0xd6, +0xd6, +0xd6, +0xd6, +0xd6, +0x7c, +0x10, +0x38, +0x00, +0x00, +0x00, + +0x00, +0x38, +0x6c, +0xc6, +0xc6, +0xc6, +0xfe, +0xc6, +0xc6, +0xc6, +0xc6, +0x6c, +0x38, +0x00, +0x00, +0x00, + +0x00, +0x3c, +0x66, +0xc3, +0xc3, +0xc3, +0xc3, +0xc3, +0x66, +0x24, +0x24, +0xa5, +0xe7, +0x00, +0x00, +0x00, + +0x00, +0x1e, +0x31, +0x30, +0x18, +0x0c, +0x3e, +0x66, +0x66, +0x66, +0x66, +0x66, +0x3c, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x6e, +0xff, +0x99, +0x99, +0x99, +0x99, +0xff, +0x76, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x02, +0x04, +0x7c, +0xca, +0x92, +0xa6, +0x7c, +0x40, +0x80, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x1c, +0x30, +0x60, +0x60, +0x60, +0x7c, +0x60, +0x60, +0x60, +0x60, +0x30, +0x1c, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0xfe, +0x00, +0x00, +0x00, +0x7c, +0x00, +0x00, +0x00, +0xfe, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x18, +0x18, +0x7e, +0x18, +0x18, +0x00, +0x00, +0x7e, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x30, +0x18, +0x0c, +0x06, +0x0c, +0x18, +0x30, +0x00, +0x7e, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x0c, +0x18, +0x30, +0x60, +0x30, +0x18, +0x0c, +0x00, +0x7e, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x0e, +0x19, +0x1b, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, + +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0xd8, +0x98, +0x70, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x18, +0x18, +0x00, +0x7e, +0x00, +0x18, +0x18, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x76, +0xdc, +0x00, +0x00, +0x76, +0xdc, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x38, +0x44, +0x44, +0x44, +0x38, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x18, +0x18, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x18, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x07, +0x06, +0x06, +0x0c, +0x0c, +0x08, +0x98, +0xd0, +0xf0, +0x60, +0x20, +0x00, +0x00, +0x00, + +0x00, +0xcc, +0x76, +0x66, +0x66, +0x66, +0x66, +0xf7, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x70, +0x98, +0x18, +0x30, +0x60, +0x88, +0xf8, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x7c, +0x64, +0x64, +0x64, +0x64, +0x64, +0x7c, +0x00, +0x00, +0x00, +0x00, + +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +}; + + +const struct font_desc font_rl = { + RL_IDX, + "RomanLarge", + 8, + 16, + patterns, + -1 +}; diff --git a/drivers/video/console/fonts.c b/drivers/video/console/fonts.c index 4fd07d9eca039d062c9968c452757f952b962a7e..9be83bed19597dd45bfec2736b51b2d8c7b0c1fa 100644 --- a/drivers/video/console/fonts.c +++ b/drivers/video/console/fonts.c @@ -64,6 +64,10 @@ static const struct font_desc *fonts[] = { #undef NO_FONTS &font_mini_4x6, #endif +#ifdef CONFIG_FONT_RL +#undef NO_FONTS + &font_rl, +#endif }; #define num_fonts (sizeof(fonts)/sizeof(*fonts)) diff --git a/drivers/video/softcursor.c b/drivers/video/console/softcursor.c similarity index 97% rename from drivers/video/softcursor.c rename to drivers/video/console/softcursor.c index 229c4bc350798c45f103a475f11f80a5e3f16dfe..8529bf08db28a92807b4e2f5d404be56917ff412 100644 --- a/drivers/video/softcursor.c +++ b/drivers/video/console/softcursor.c @@ -1,7 +1,7 @@ /* * linux/drivers/video/softcursor.c -- Generic software cursor for frame buffer devices * - * Created 14 Nov 2002 by James Simmons + * Created 14 Nov 2002 by James Simmons * * 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 @@ -55,9 +55,9 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor) src[i] = image->data[i] & cursor->mask[i]; break; } - } else + } else memcpy(src, image->data, dsize); - + fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, image->height); image->data = dst; info->fbops->fb_imageblit(info, image); @@ -66,7 +66,7 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor) } EXPORT_SYMBOL(soft_cursor); - + MODULE_AUTHOR("James Simmons "); MODULE_DESCRIPTION("Generic software cursor"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index 989e700159e011fd6a42a798d3d7a22982c78288..403d17377f8db67fce024dbf52e4091225e6a743 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c @@ -176,7 +176,6 @@ static struct fb_ops controlfb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index 3894b2a501d6e7a4636e5f5382c22741cd75ca6c..c589d23e7f914e6301bc39b7ed0d91f4c30ee7a3 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c @@ -1064,7 +1064,6 @@ static struct fb_ops cyber2000fb_ops = { .fb_fillrect = cyber2000fb_fillrect, .fb_copyarea = cyber2000fb_copyarea, .fb_imageblit = cyber2000fb_imageblit, - .fb_cursor = soft_cursor, .fb_sync = cyber2000fb_sync, }; diff --git a/drivers/video/cyblafb.c b/drivers/video/cyblafb.c index 6992100a508c09175cd527bcb9d10d977f3a769e..03fbe83d71a840660ac1486111c2707d71db3ba2 100644 --- a/drivers/video/cyblafb.c +++ b/drivers/video/cyblafb.c @@ -968,7 +968,6 @@ static struct fb_ops cyblafb_ops __devinitdata = { .fb_fillrect = cyblafb_fillrect, .fb_copyarea= cyblafb_copyarea, .fb_imageblit = cyblafb_imageblit, - .fb_cursor = soft_cursor, }; //========================================================================== diff --git a/drivers/video/dnfb.c b/drivers/video/dnfb.c index 1785686a7f11cc8a6120323a6106bc327eb6f345..957a3ada2b75487c5188b65369ae3121d8866c20 100644 --- a/drivers/video/dnfb.c +++ b/drivers/video/dnfb.c @@ -116,7 +116,6 @@ static struct fb_ops dn_fb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = dnfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; struct fb_var_screeninfo dnfb_var __devinitdata = { diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c index 7363d0b25fdfc12fda931d845e24321e346a82b4..6a81a1dd8f3d0bb357db89877bf53c8e4a745802 100644 --- a/drivers/video/epson1355fb.c +++ b/drivers/video/epson1355fb.c @@ -484,7 +484,6 @@ static struct fb_ops epson1355fb_fbops = { .fb_imageblit = cfb_imageblit, .fb_read = epson1355fb_read, .fb_write = epson1355fb_write, - .fb_cursor = soft_cursor, }; /* ------------------------------------------------------------------------- */ diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index 713226cdf3c6b7a7ce0a247447d1909d05e57396..fc7965b66775983a97d62d10ab7805c475e0eb73 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c @@ -538,25 +538,12 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize) *dbsize = 0; - DPRINTK(" Supported VESA Modes\n"); - block = edid + ESTABLISHED_TIMING_1; - num += get_est_timing(block, &mode[num]); - - DPRINTK(" Standard Timings\n"); - block = edid + STD_TIMING_DESCRIPTIONS_START; - for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE) - num += get_std_timing(block, &mode[num]); - DPRINTK(" Detailed Timings\n"); block = edid + DETAILED_TIMING_DESCRIPTIONS_START; for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) { int first = 1; - if (block[0] == 0x00 && block[1] == 0x00) { - if (block[3] == 0xfa) { - num += get_dst_timing(block + 5, &mode[num]); - } - } else { + if (!(block[0] == 0x00 && block[1] == 0x00)) { get_detailed_timing(block, &mode[num]); if (first) { mode[num].flag |= FB_MODE_IS_FIRST; @@ -565,6 +552,21 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize) num++; } } + + DPRINTK(" Supported VESA Modes\n"); + block = edid + ESTABLISHED_TIMING_1; + num += get_est_timing(block, &mode[num]); + + DPRINTK(" Standard Timings\n"); + block = edid + STD_TIMING_DESCRIPTIONS_START; + for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE) + num += get_std_timing(block, &mode[num]); + + block = edid + DETAILED_TIMING_DESCRIPTIONS_START; + for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) { + if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa) + num += get_dst_timing(block + 5, &mode[num]); + } /* Yikes, EDID data is totally useless */ if (!num) { @@ -827,7 +829,7 @@ int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) { unsigned char *block; - int i; + int i, found = 0; if (edid == NULL) return; @@ -869,6 +871,22 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) get_monspecs(edid, specs); specs->modedb = fb_create_modedb(edid, &specs->modedb_len); + + /* + * Workaround for buggy EDIDs that sets that the first + * detailed timing is preferred but has not detailed + * timing specified + */ + for (i = 0; i < specs->modedb_len; i++) { + if (specs->modedb[i].flag & FB_MODE_IS_DETAILED) { + found = 1; + break; + } + } + + if (!found) + specs->misc &= ~FB_MISC_1ST_DETAIL; + DPRINTK("========================================\n"); } diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c index 10cd05059fe9d2e995f0b03a2c25b6687474c09d..04417dc16c2e3572084a9edaad40a7af3982d71b 100644 --- a/drivers/video/ffb.c +++ b/drivers/video/ffb.c @@ -57,9 +57,6 @@ static struct fb_ops ffb_ops = { .fb_sync = ffb_sync, .fb_mmap = ffb_mmap, .fb_ioctl = ffb_ioctl, - - /* XXX Use FFB hw cursor once fb cursor API is better understood... */ - .fb_cursor = soft_cursor, }; /* Register layout and definitions */ diff --git a/drivers/video/fm2fb.c b/drivers/video/fm2fb.c index a0763283d77651219cacab89273061004c2cd1fb..998374cfae6d0686f992cc00938bf4d460a436ec 100644 --- a/drivers/video/fm2fb.c +++ b/drivers/video/fm2fb.c @@ -172,7 +172,6 @@ static struct fb_ops fm2fb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; /* diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c index ed853bef19e9d85ccf4532f8251d00321b28c814..9d5e4f342110acb4dbf34b3f8a835a2d1daaaf69 100644 --- a/drivers/video/gbefb.c +++ b/drivers/video/gbefb.c @@ -1038,7 +1038,6 @@ static struct fb_ops gbefb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; /* diff --git a/drivers/video/geode/Kconfig b/drivers/video/geode/Kconfig index 5a9b89c3831b1f7e254be8e047a24a2b4be3f904..42fb9a89a7927f833c8ecf24fc34c465a8d24da9 100644 --- a/drivers/video/geode/Kconfig +++ b/drivers/video/geode/Kconfig @@ -14,7 +14,6 @@ config FB_GEODE_GX1 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - select FB_SOFT_CURSOR ---help--- Framebuffer driver for the display controller integrated into the AMD Geode GX1 processor. diff --git a/drivers/video/geode/gx1fb_core.c b/drivers/video/geode/gx1fb_core.c index 74a5fca86b8ac505c32f9041523fbe04c0082e9f..8e8da743399416eafa71a730f50cca80a4b1f1e8 100644 --- a/drivers/video/geode/gx1fb_core.c +++ b/drivers/video/geode/gx1fb_core.c @@ -275,7 +275,6 @@ static struct fb_ops gx1fb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; static struct fb_info * __init gx1fb_init_fbinfo(struct device *dev) diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c index 0d376ba54814f94ea4ed0625a82121cb5a30a0e5..f04ca721f94c53895f19f72b23e2998b48d2ffc7 100644 --- a/drivers/video/hitfb.c +++ b/drivers/video/hitfb.c @@ -262,7 +262,6 @@ static struct fb_ops hitfb_ops = { .fb_fillrect = hitfb_fillrect, .fb_copyarea = hitfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; int __init hitfb_init(void) diff --git a/drivers/video/hpfb.c b/drivers/video/hpfb.c index e97fe8481d59f5b52c17b052dcebd24783c7ca3b..bebdac59d231330c353940a009ba612807f4de37 100644 --- a/drivers/video/hpfb.c +++ b/drivers/video/hpfb.c @@ -193,7 +193,6 @@ static struct fb_ops hpfb_ops = { .fb_fillrect = hpfb_fillrect, .fb_copyarea = hpfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, .fb_sync = hpfb_sync, }; diff --git a/drivers/video/i810/i810-i2c.c b/drivers/video/i810/i810-i2c.c index 689d2586366d7ffafbdb7c55741580f6f858f277..c61bad0da20f942c46c537a7107f27074467f8f8 100644 --- a/drivers/video/i810/i810-i2c.c +++ b/drivers/video/i810/i810-i2c.c @@ -46,92 +46,45 @@ static void i810i2c_setscl(void *data, int state) struct i810fb_par *par = chan->par; u8 __iomem *mmio = par->mmio_start_virtual; - i810_writel(mmio, GPIOB, (state ? SCL_VAL_OUT : 0) | SCL_DIR | + i810_writel(mmio, chan->ddc_base, (state ? SCL_VAL_OUT : 0) | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK); - i810_readl(mmio, GPIOB); /* flush posted write */ + i810_readl(mmio, chan->ddc_base); /* flush posted write */ } static void i810i2c_setsda(void *data, int state) { - struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; + struct i810fb_i2c_chan *chan = data; struct i810fb_par *par = chan->par; u8 __iomem *mmio = par->mmio_start_virtual; - i810_writel(mmio, GPIOB, (state ? SDA_VAL_OUT : 0) | SDA_DIR | + i810_writel(mmio, chan->ddc_base, (state ? SDA_VAL_OUT : 0) | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK); - i810_readl(mmio, GPIOB); /* flush posted write */ + i810_readl(mmio, chan->ddc_base); /* flush posted write */ } static int i810i2c_getscl(void *data) { - struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; + struct i810fb_i2c_chan *chan = data; struct i810fb_par *par = chan->par; u8 __iomem *mmio = par->mmio_start_virtual; - i810_writel(mmio, GPIOB, SCL_DIR_MASK); - i810_writel(mmio, GPIOB, 0); - return (0 != (i810_readl(mmio, GPIOB) & SCL_VAL_IN)); + i810_writel(mmio, chan->ddc_base, SCL_DIR_MASK); + i810_writel(mmio, chan->ddc_base, 0); + return ((i810_readl(mmio, chan->ddc_base) & SCL_VAL_IN) != 0); } static int i810i2c_getsda(void *data) { - struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; + struct i810fb_i2c_chan *chan = data; struct i810fb_par *par = chan->par; u8 __iomem *mmio = par->mmio_start_virtual; - i810_writel(mmio, GPIOB, SDA_DIR_MASK); - i810_writel(mmio, GPIOB, 0); - return (0 != (i810_readl(mmio, GPIOB) & SDA_VAL_IN)); -} - -static void i810ddc_setscl(void *data, int state) -{ - struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; - struct i810fb_par *par = chan->par; - u8 __iomem *mmio = par->mmio_start_virtual; - - i810_writel(mmio, GPIOA, (state ? SCL_VAL_OUT : 0) | SCL_DIR | - SCL_DIR_MASK | SCL_VAL_MASK); - i810_readl(mmio, GPIOA); /* flush posted write */ -} - -static void i810ddc_setsda(void *data, int state) -{ - struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; - struct i810fb_par *par = chan->par; - u8 __iomem *mmio = par->mmio_start_virtual; - - i810_writel(mmio, GPIOA, (state ? SDA_VAL_OUT : 0) | SDA_DIR | - SDA_DIR_MASK | SDA_VAL_MASK); - i810_readl(mmio, GPIOA); /* flush posted write */ -} - -static int i810ddc_getscl(void *data) -{ - struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; - struct i810fb_par *par = chan->par; - u8 __iomem *mmio = par->mmio_start_virtual; - - i810_writel(mmio, GPIOA, SCL_DIR_MASK); - i810_writel(mmio, GPIOA, 0); - return (0 != (i810_readl(mmio, GPIOA) & SCL_VAL_IN)); -} - -static int i810ddc_getsda(void *data) -{ - struct i810fb_i2c_chan *chan = (struct i810fb_i2c_chan *)data; - struct i810fb_par *par = chan->par; - u8 __iomem *mmio = par->mmio_start_virtual; - - i810_writel(mmio, GPIOA, SDA_DIR_MASK); - i810_writel(mmio, GPIOA, 0); - return (0 != (i810_readl(mmio, GPIOA) & SDA_VAL_IN)); + i810_writel(mmio, chan->ddc_base, SDA_DIR_MASK); + i810_writel(mmio, chan->ddc_base, 0); + return ((i810_readl(mmio, chan->ddc_base) & SDA_VAL_IN) != 0); } -#define I2C_ALGO_DDC_I810 0x0e0000 -#define I2C_ALGO_I2C_I810 0x0f0000 -static int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name, - int conn) +static int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name) { int rc; @@ -139,22 +92,11 @@ static int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name, chan->adapter.owner = THIS_MODULE; chan->adapter.algo_data = &chan->algo; chan->adapter.dev.parent = &chan->par->dev->dev; - switch (conn) { - case 1: - chan->adapter.id = I2C_ALGO_DDC_I810; - chan->algo.setsda = i810ddc_setsda; - chan->algo.setscl = i810ddc_setscl; - chan->algo.getsda = i810ddc_getsda; - chan->algo.getscl = i810ddc_getscl; - break; - case 2: - chan->adapter.id = I2C_ALGO_I2C_I810; - chan->algo.setsda = i810i2c_setsda; - chan->algo.setscl = i810i2c_setscl; - chan->algo.getsda = i810i2c_getsda; - chan->algo.getscl = i810i2c_getscl; - break; - } + chan->adapter.id = I2C_HW_B_I810; + chan->algo.setsda = i810i2c_setsda; + chan->algo.setscl = i810i2c_setscl; + chan->algo.getsda = i810i2c_getsda; + chan->algo.getscl = i810i2c_getscl; chan->algo.udelay = 10; chan->algo.mdelay = 10; chan->algo.timeout = (HZ/2); @@ -168,11 +110,15 @@ static int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name, udelay(20); rc = i2c_bit_add_bus(&chan->adapter); + if (rc == 0) dev_dbg(&chan->par->dev->dev, "I2C bus %s registered.\n",name); - else + else { dev_warn(&chan->par->dev->dev, "Failed to register I2C bus " "%s.\n", name); + chan->par = NULL; + } + return rc; } @@ -180,8 +126,14 @@ void i810_create_i2c_busses(struct i810fb_par *par) { par->chan[0].par = par; par->chan[1].par = par; - i810_setup_i2c_bus(&par->chan[0], "I810-DDC", 1); - i810_setup_i2c_bus(&par->chan[1], "I810-I2C", 2); + par->chan[2].par = par; + + par->chan[0].ddc_base = GPIOA; + i810_setup_i2c_bus(&par->chan[0], "I810-DDC"); + par->chan[1].ddc_base = GPIOB; + i810_setup_i2c_bus(&par->chan[1], "I810-I2C"); + par->chan[2].ddc_base = GPIOC; + i810_setup_i2c_bus(&par->chan[2], "I810-GPIOC"); } void i810_delete_i2c_busses(struct i810fb_par *par) @@ -189,9 +141,14 @@ void i810_delete_i2c_busses(struct i810fb_par *par) if (par->chan[0].par) i2c_bit_del_bus(&par->chan[0].adapter); par->chan[0].par = NULL; + if (par->chan[1].par) i2c_bit_del_bus(&par->chan[1].adapter); par->chan[1].par = NULL; + + if (par->chan[2].par) + i2c_bit_del_bus(&par->chan[2].adapter); + par->chan[2].par = NULL; } static u8 *i810_do_probe_i2c_edid(struct i810fb_i2c_chan *chan) @@ -221,6 +178,7 @@ static u8 *i810_do_probe_i2c_edid(struct i810fb_i2c_chan *chan) DPRINTK("i810-i2c: I2C Transfer successful\n"); return buf; } + DPRINTK("i810-i2c: Unable to read EDID block.\n"); kfree(buf); return NULL; @@ -233,7 +191,7 @@ int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, int conn) int i; DPRINTK("i810-i2c: Probe DDC%i Bus\n", conn); - if (conn < 3) { + if (conn < 4) { for (i = 0; i < 3; i++) { /* Do the real work */ edid = i810_do_probe_i2c_edid(&par->chan[conn-1]); @@ -241,11 +199,14 @@ int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, int conn) break; } } else { - DPRINTK("i810-i2c: Getting EDID from BIOS\n"); - edid = kmalloc(EDID_LENGTH, GFP_KERNEL); - if (edid) - memcpy(edid, fb_firmware_edid(info->device), - EDID_LENGTH); + const u8 *e = fb_firmware_edid(info->device); + + if (e != NULL) { + DPRINTK("i810-i2c: Getting EDID from BIOS\n"); + edid = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (edid) + memcpy(edid, e, EDID_LENGTH); + } } if (out_edid) @@ -253,5 +214,3 @@ int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, int conn) return (edid) ? 0 : 1; } - - diff --git a/drivers/video/i810/i810.h b/drivers/video/i810/i810.h index d48949ceaacc033988512bb6eb4dabf3e942a0e3..6c187d5fe95170e337ccc09f86457d993d98e207 100644 --- a/drivers/video/i810/i810.h +++ b/drivers/video/i810/i810.h @@ -249,6 +249,7 @@ struct i810fb_i2c_chan { struct i810fb_par *par; struct i2c_adapter adapter; struct i2c_algo_bit_data algo; + unsigned long ddc_base; }; struct i810fb_par { @@ -262,7 +263,7 @@ struct i810fb_par { struct heap_data iring; struct heap_data cursor_heap; struct vgastate state; - struct i810fb_i2c_chan chan[2]; + struct i810fb_i2c_chan chan[3]; atomic_t use_count; u32 pseudo_palette[17]; unsigned long mmio_start_phys; diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index 0dbc9ddb6766e78eba0b1b58f5e5eb0c57d0051b..c0c974b1afaa0285fd1cc753affc90f71c96e6f0 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c @@ -1854,7 +1854,7 @@ static void __devinit i810fb_find_init_mode(struct fb_info *info) #ifdef CONFIG_FB_I810_I2C i810_create_i2c_busses(par); - for (i = 0; i < 3; i++) { + for (i = 0; i < 4; i++) { err = i810_probe_i2c_connector(info, &par->edid, i+1); if (!err) break; @@ -1871,27 +1871,18 @@ static void __devinit i810fb_find_init_mode(struct fb_info *info) fb_videomode_to_modelist(specs->modedb, specs->modedb_len, &info->modelist); if (specs->modedb != NULL) { - if (xres && yres) { - struct fb_videomode *m; + struct fb_videomode *m; + if (xres && yres) { if ((m = fb_find_best_mode(&var, &info->modelist))) { mode = *m; found = 1; } } - if (!found && specs->misc & FB_MISC_1ST_DETAIL) { - for (i = 0; i < specs->modedb_len; i++) { - if (specs->modedb[i].flag & FB_MODE_IS_FIRST) { - mode = specs->modedb[i]; - found = 1; - break; - } - } - } - if (!found) { - mode = specs->modedb[0]; + m = fb_find_best_display(&info->monspecs, &info->modelist); + mode = *m; found = 1; } @@ -2066,8 +2057,7 @@ static void i810fb_release_resource(struct fb_info *info, iounmap(par->mmio_start_virtual); if (par->aperture.virtual) iounmap(par->aperture.virtual); - if (par->edid) - kfree(par->edid); + kfree(par->edid); if (par->res_flags & FRAMEBUFFER_REQ) release_mem_region(par->aperture.physical, par->aperture.size); diff --git a/drivers/video/i810/i810_regs.h b/drivers/video/i810/i810_regs.h index 6e4b9afa4d9805cb050d2bae68643427b324a785..91c6bd9d0d0d472c7c43cb43d3b89fb18e816c5a 100644 --- a/drivers/video/i810/i810_regs.h +++ b/drivers/video/i810/i810_regs.h @@ -70,6 +70,7 @@ #define HVSYNC 0x05000 #define GPIOA 0x05010 #define GPIOB 0x05014 +#define GPIOC 0x0501C /* Clock Control and Power Management Registers (06000h 06FFFh) */ #define DCLK_0D 0x06000 diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c index 7b9bf45ab6fe89251e59c19deeb890c9583401f5..7fbe24206b190458b8b9aeb89e123cb47b8b6aa2 100644 --- a/drivers/video/imsttfb.c +++ b/drivers/video/imsttfb.c @@ -1344,7 +1344,6 @@ static struct fb_ops imsttfb_ops = { .fb_fillrect = imsttfb_fillrect, .fb_copyarea = imsttfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, .fb_ioctl = imsttfb_ioctl, }; diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 64d9bcc38da387fee71f375a0cfde75ce2d9bc4b..e20b9f3a255fb65b99e3a0fd37d276cbbbb8957d 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -298,7 +298,6 @@ static struct fb_ops imxfb_ops = { .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, .fb_blank = imxfb_blank, - .fb_cursor = soft_cursor, /* FIXME: i.MX can do hardware cursor */ }; /* diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 011e11626558399a98890554878a3c4f6af4fa6c..f077ca34fabad6ed156a256d76908d5bc24a687b 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h @@ -10,7 +10,7 @@ /*** Version/name ***/ #define INTELFB_VERSION "0.9.2" #define INTELFB_MODULE_NAME "intelfb" -#define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G" +#define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G/915GM" /*** Debug/feature defines ***/ @@ -47,6 +47,7 @@ #define PCI_DEVICE_ID_INTEL_85XGM 0x3582 #define PCI_DEVICE_ID_INTEL_865G 0x2572 #define PCI_DEVICE_ID_INTEL_915G 0x2582 +#define PCI_DEVICE_ID_INTEL_915GM 0x2592 /* Size of MMIO region */ #define INTEL_REG_SIZE 0x80000 @@ -119,7 +120,8 @@ enum intel_chips { INTEL_855GM, INTEL_855GME, INTEL_865G, - INTEL_915G + INTEL_915G, + INTEL_915GM }; struct intelfb_hwstate { diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 80a09344f1aaedffd1e6e665dd26186fe70e84b4..0799b999b3143e361aef7cf39e0a211137ec50de 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -1,7 +1,7 @@ /* * intelfb * - * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G + * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM * integrated graphics chips. * * Copyright © 2002, 2003 David Dawes @@ -186,6 +186,7 @@ static struct pci_device_id intelfb_pci_table[] __devinitdata = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_85XGM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_85XGM }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_865G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_865G }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915G }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915GM }, { 0, } }; @@ -549,10 +550,11 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) } /* Set base addresses. */ - if (ent->device == PCI_DEVICE_ID_INTEL_915G) { + if ((ent->device == PCI_DEVICE_ID_INTEL_915G) || + (ent->device == PCI_DEVICE_ID_INTEL_915GM)) { aperture_bar = 2; mmio_bar = 0; - /* Disable HW cursor on 915G (not implemented yet) */ + /* Disable HW cursor on 915G/M (not implemented yet) */ hwcursor = 0; } dinfo->aperture.physical = pci_resource_start(pdev, aperture_bar); @@ -1483,7 +1485,7 @@ intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor) #endif if (!dinfo->hwcursor) - return soft_cursor(info, cursor); + return -ENODEV; intelfbhw_cursor_hide(dinfo); diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 5bafc3c54db767a41730105f18df9f104d8ad694..ac94c2e5ff857720161b9e7291fe10ecb54f2721 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -99,6 +99,11 @@ intelfbhw_get_chipset(struct pci_dev *pdev, const char **name, int *chipset, *chipset = INTEL_915G; *mobile = 0; return 0; + case PCI_DEVICE_ID_INTEL_915GM: + *name = "Intel(R) 915GM"; + *chipset = INTEL_915GM; + *mobile = 1; + return 0; default: return 1; } diff --git a/drivers/video/kyro/fbdev.c b/drivers/video/kyro/fbdev.c index d8bac9e978421b97dcbe09f34f2b8ec893aa6881..5eb4d5c177bd1899a5caeea3d536a7d4ec414e2b 100644 --- a/drivers/video/kyro/fbdev.c +++ b/drivers/video/kyro/fbdev.c @@ -669,7 +669,6 @@ static struct fb_ops kyrofb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; static int __devinit kyrofb_probe(struct pci_dev *pdev, diff --git a/drivers/video/leo.c b/drivers/video/leo.c index 7e1e7fb168bd3e31dd10b4ad727639389a0b5392..84a7fe435bb82bd082c770b51cbae2b511c8d361 100644 --- a/drivers/video/leo.c +++ b/drivers/video/leo.c @@ -51,7 +51,6 @@ static struct fb_ops leo_ops = { .fb_imageblit = cfb_imageblit, .fb_mmap = leo_mmap, .fb_ioctl = leo_ioctl, - .fb_cursor = soft_cursor, }; #define LEO_OFF_LC_SS0_KRN 0x00200000UL diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig index 3e9ccf370ab222cecdd59a0ceacedbac13b6af66..8cb7fb4db4418b8815b6be81d374ef65343afa35 100644 --- a/drivers/video/logo/Kconfig +++ b/drivers/video/logo/Kconfig @@ -7,6 +7,8 @@ menu "Logo configuration" config LOGO bool "Bootup logo" depends on FB || SGI_NEWPORT_CONSOLE + help + Enable and select frame buffer bootup logos. config LOGO_LINUX_MONO bool "Standard black and white Linux logo" diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c index 4945a4c02209ed6f87dc98807f03823c9b838721..cfc748e9427260037a075a0ad78ebdc8e90c4560 100644 --- a/drivers/video/macfb.c +++ b/drivers/video/macfb.c @@ -589,7 +589,6 @@ static struct fb_ops macfb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; void __init macfb_setup(char *options) diff --git a/drivers/video/matrox/matroxfb_DAC1064.c b/drivers/video/matrox/matroxfb_DAC1064.c index 149680f8bcf05e33d684d68b8e1c303a9d8bae70..0fbd9b5149f16f7632a64782c6ed3f64556f6156 100644 --- a/drivers/video/matrox/matroxfb_DAC1064.c +++ b/drivers/video/matrox/matroxfb_DAC1064.c @@ -657,7 +657,6 @@ static int MGA1064_preinit(WPMINFO2) { /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */ ACCESS_FBINFO(capable.text) = 1; ACCESS_FBINFO(capable.vxres) = vxres_mystique; - ACCESS_FBINFO(features.accel.has_cacheflush) = 1; ACCESS_FBINFO(outputs[0]).output = &m1064; ACCESS_FBINFO(outputs[0]).src = ACCESS_FBINFO(outputs[0]).default_src; @@ -842,7 +841,6 @@ static int MGAG100_preinit(WPMINFO2) { /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */ ACCESS_FBINFO(capable.text) = 1; ACCESS_FBINFO(capable.vxres) = vxres_g100; - ACCESS_FBINFO(features.accel.has_cacheflush) = 1; ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100 ? ACCESS_FBINFO(devflags.sgram) : 1; @@ -980,7 +978,7 @@ static void MGAG100_reset(WPMINFO2) { hw->MXoptionReg |= 0x40; /* FIXME... */ pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg); } - mga_setr(M_EXTVGA_INDEX, 0x06, 0x50); + mga_setr(M_EXTVGA_INDEX, 0x06, 0x00); } } if (ACCESS_FBINFO(devflags.g450dac)) { diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c index c7f3e1321224d36e582bab8298f37b54d2b5c86e..a5c825d994661090c990e6423fb6245a063902b1 100644 --- a/drivers/video/matrox/matroxfb_accel.c +++ b/drivers/video/matrox/matroxfb_accel.c @@ -122,7 +122,7 @@ void matrox_cfbX_init(WPMINFO2) { ACCESS_FBINFO(fbops).fb_copyarea = cfb_copyarea; ACCESS_FBINFO(fbops).fb_fillrect = cfb_fillrect; ACCESS_FBINFO(fbops).fb_imageblit = cfb_imageblit; - ACCESS_FBINFO(fbops).fb_cursor = soft_cursor; + ACCESS_FBINFO(fbops).fb_cursor = NULL; accel = (ACCESS_FBINFO(fbcon).var.accel_flags & FB_ACCELF_TEXT) == FB_ACCELF_TEXT; diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index e02da41f1b262b9cb780dd19d4d36767ccdbe357..1e74f4cca53b2955d02cef90f29eaf5b4df10227 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -264,7 +264,6 @@ static void matroxfb_disable_irq(WPMINFO2) { } int matroxfb_wait_for_sync(WPMINFO u_int32_t crtc) { - wait_queue_t __wait; struct matrox_vsync *vs; unsigned int cnt; int ret; @@ -286,7 +285,6 @@ int matroxfb_wait_for_sync(WPMINFO u_int32_t crtc) { if (ret) { return ret; } - init_waitqueue_entry(&__wait, current); cnt = vs->cnt; ret = wait_event_interruptible_timeout(vs->wait, cnt != vs->cnt, HZ/10); @@ -500,10 +498,6 @@ static int matroxfb_pitch_adjust(CPMINFO int xres, int bpp) { } else { xres_new = matroxfb_test_and_set_rounding(PMINFO xres, bpp); } - if (!xres_new) return 0; - if (xres != xres_new) { - printk(KERN_INFO "matroxfb: cannot set xres to %d, rounded up to %d\n", xres, xres_new); - } return xres_new; } @@ -1285,7 +1279,7 @@ static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int *realSi vaddr_t vm; unsigned int offs; unsigned int offs2; - unsigned char store, orig; + unsigned char orig; unsigned char bytes[32]; unsigned char* tmp; @@ -1301,16 +1295,12 @@ static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int *realSi orig = mga_inb(M_EXTVGA_DATA); mga_outb(M_EXTVGA_DATA, orig | 0x80); - store = mga_readb(vm, 0x1234); tmp = bytes; for (offs = 0x100000; offs < maxSize; offs += 0x200000) *tmp++ = mga_readb(vm, offs); for (offs = 0x100000; offs < maxSize; offs += 0x200000) mga_writeb(vm, offs, 0x02); - if (ACCESS_FBINFO(features.accel.has_cacheflush)) - mga_outb(M_CACHEFLUSH, 0x00); - else - mga_writeb(vm, 0x1234, 0x99); + mga_outb(M_CACHEFLUSH, 0x00); for (offs = 0x100000; offs < maxSize; offs += 0x200000) { if (mga_readb(vm, offs) != 0x02) break; @@ -1321,7 +1311,6 @@ static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int *realSi tmp = bytes; for (offs2 = 0x100000; offs2 < maxSize; offs2 += 0x200000) mga_writeb(vm, offs2, *tmp++); - mga_writeb(vm, 0x1234, store); mga_outb(M_EXTVGA_INDEX, 0x03); mga_outb(M_EXTVGA_DATA, orig); @@ -1430,6 +1419,20 @@ static struct board { MGA_1164, &vbMystique, "Mystique 220 (PCI)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS_AGP, 0x02, + 0, 0, + DEVF_VIDEO64BIT | DEVF_CROSS4MB, + 180000, + MGA_1064, + &vbMystique, + "Mystique (AGP)"}, + {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS_AGP, 0xFF, + 0, 0, + DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB, + 220000, + MGA_1164, + &vbMystique, + "Mystique 220 (AGP)"}, #endif #ifdef CONFIG_FB_MATROX_G {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_MM, 0xFF, diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h index 85a0b2558452796659c9f1fbdedd7dba2302dc4f..a8c47ad2cdb6059d63671a685247018415b8632a 100644 --- a/drivers/video/matrox/matroxfb_base.h +++ b/drivers/video/matrox/matroxfb_base.h @@ -272,10 +272,6 @@ struct matrox_DAC1064_features { u_int8_t xmiscctrl; }; -struct matrox_accel_features { - int has_cacheflush; -}; - /* current hardware status */ struct mavenregs { u_int8_t regs[256]; @@ -440,7 +436,6 @@ struct matrox_fb_info { struct { struct matrox_pll_features pll; struct matrox_DAC1064_features DAC1064; - struct matrox_accel_features accel; } features; struct { spinlock_t DAC; diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c index 429047ac615a5cf5d3c3f4a103fc1b869c1516b9..d52d7d825c41439ccb7825b0ea9be41d363ae303 100644 --- a/drivers/video/matrox/matroxfb_crtc2.c +++ b/drivers/video/matrox/matroxfb_crtc2.c @@ -576,7 +576,6 @@ static struct fb_ops matroxfb_dh_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; static struct fb_var_screeninfo matroxfb_dh_defined = { diff --git a/drivers/video/maxinefb.c b/drivers/video/maxinefb.c index f192d995d0303e64dca0bb3a765cc21690aaeb2e..743e7ad26acc3299f32e5903b9c4bc474a249fcb 100644 --- a/drivers/video/maxinefb.c +++ b/drivers/video/maxinefb.c @@ -113,7 +113,6 @@ static struct fb_ops maxinefb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; int __init maxinefb_init(void) diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 47516c44a390ac7218a3df538424553f76ac9225..1789a52d776a984ba9bec98371f7fd974157eead 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c @@ -676,6 +676,8 @@ void fb_var_to_videomode(struct fb_videomode *mode, mode->sync = var->sync; mode->vmode = var->vmode & FB_VMODE_MASK; mode->flag = FB_MODE_IS_FROM_VAR; + mode->refresh = 0; + if (!var->pixclock) return; @@ -785,39 +787,39 @@ struct fb_videomode *fb_find_best_mode(struct fb_var_screeninfo *var, } /** - * fb_find_nearest_mode - find mode closest video mode + * fb_find_nearest_mode - find closest videomode * - * @var: pointer to struct fb_var_screeninfo + * @mode: pointer to struct fb_videomode * @head: pointer to modelist * * Finds best matching videomode, smaller or greater in dimension. * If more than 1 videomode is found, will return the videomode with - * the closest refresh rate + * the closest refresh rate. */ -struct fb_videomode *fb_find_nearest_mode(struct fb_var_screeninfo *var, +struct fb_videomode *fb_find_nearest_mode(struct fb_videomode *mode, struct list_head *head) { struct list_head *pos; struct fb_modelist *modelist; - struct fb_videomode *mode, *best = NULL; + struct fb_videomode *cmode, *best = NULL; u32 diff = -1, diff_refresh = -1; list_for_each(pos, head) { u32 d; modelist = list_entry(pos, struct fb_modelist, list); - mode = &modelist->mode; + cmode = &modelist->mode; - d = abs(mode->xres - var->xres) + - abs(mode->yres - var->yres); + d = abs(cmode->xres - mode->xres) + + abs(cmode->yres - mode->yres); if (diff > d) { diff = d; - best = mode; + best = cmode; } else if (diff == d) { - d = abs(mode->refresh - best->refresh); + d = abs(cmode->refresh - mode->refresh); if (diff_refresh > d) { diff_refresh = d; - best = mode; + best = cmode; } } } @@ -942,6 +944,66 @@ void fb_videomode_to_modelist(struct fb_videomode *modedb, int num, } } +struct fb_videomode *fb_find_best_display(struct fb_monspecs *specs, + struct list_head *head) +{ + struct list_head *pos; + struct fb_modelist *modelist; + struct fb_videomode *m, *m1 = NULL, *md = NULL, *best = NULL; + int first = 0; + + if (!head->prev || !head->next || list_empty(head)) + goto finished; + + /* get the first detailed mode and the very first mode */ + list_for_each(pos, head) { + modelist = list_entry(pos, struct fb_modelist, list); + m = &modelist->mode; + + if (!first) { + m1 = m; + first = 1; + } + + if (m->flag & FB_MODE_IS_FIRST) { + md = m; + break; + } + } + + /* first detailed timing is preferred */ + if (specs->misc & FB_MISC_1ST_DETAIL) { + best = md; + goto finished; + } + + /* find best mode based on display width and height */ + if (specs->max_x && specs->max_y) { + struct fb_var_screeninfo var; + + memset(&var, 0, sizeof(struct fb_var_screeninfo)); + var.xres = (specs->max_x * 7200)/254; + var.yres = (specs->max_y * 7200)/254; + m = fb_find_best_mode(&var, head); + if (m) { + best = m; + goto finished; + } + } + + /* use first detailed mode */ + if (md) { + best = md; + goto finished; + } + + /* last resort, use the very first mode */ + best = m1; +finished: + return best; +} +EXPORT_SYMBOL(fb_find_best_display); + EXPORT_SYMBOL(fb_videomode_to_var); EXPORT_SYMBOL(fb_var_to_videomode); EXPORT_SYMBOL(fb_mode_is_equal); diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c index 5d424a30270acda396d49c204d04241244a18962..8486e77872dc0a6c1789f230ed85dc9717d1ee6d 100644 --- a/drivers/video/neofb.c +++ b/drivers/video/neofb.c @@ -1665,7 +1665,6 @@ static struct fb_ops neofb_ops = { .fb_fillrect = neofb_fillrect, .fb_copyarea = neofb_copyarea, .fb_imageblit = neofb_imageblit, - .fb_cursor = soft_cursor, }; /* --------------------------------------------------------------------- */ diff --git a/drivers/video/nvidia/nv_local.h b/drivers/video/nvidia/nv_local.h index afee284fc73c964bbc4fb2782c0fa251b13ccb28..4243d7fae972a34fc0d197956fd760bb3d77db72 100644 --- a/drivers/video/nvidia/nv_local.h +++ b/drivers/video/nvidia/nv_local.h @@ -105,7 +105,7 @@ do { \ *a = byte_rev[*a]; \ } while(0) #else -#define reverse_order(l) +#define reverse_order(l) do { } while(0) #endif /* __LITTLE_ENDIAN */ #endif /* __NV_LOCAL_H__ */ diff --git a/drivers/video/nvidia/nv_of.c b/drivers/video/nvidia/nv_of.c index 4fa2cf9a8af2adbf6e673022ea2655c9810e5de6..7a03d040b1a3255bb0d9e2a5dbc4828b49c36c42 100644 --- a/drivers/video/nvidia/nv_of.c +++ b/drivers/video/nvidia/nv_of.c @@ -27,34 +27,60 @@ #include "nv_local.h" #include "nv_proto.h" -void nvidia_create_i2c_busses(struct nvidia_par *par) {} -void nvidia_delete_i2c_busses(struct nvidia_par *par) {} +#include "../edid.h" -int nvidia_probe_i2c_connector(struct fb_info *info, int conn, u8 **out_edid) +int nvidia_probe_of_connector(struct fb_info *info, int conn, u8 **out_edid) { struct nvidia_par *par = info->par; - struct device_node *dp; + struct device_node *parent, *dp; unsigned char *pedid = NULL; - unsigned char *disptype = NULL; static char *propnames[] = { - "DFP,EDID", "LCD,EDID", "EDID", "EDID1", "EDID,B", "EDID,A", NULL }; + "DFP,EDID", "LCD,EDID", "EDID", "EDID1", + "EDID,B", "EDID,A", NULL }; int i; - dp = pci_device_to_OF_node(par->pci_dev); - for (; dp != NULL; dp = dp->child) { - disptype = (unsigned char *)get_property(dp, "display-type", NULL); - if (disptype == NULL) - continue; - if (strncmp(disptype, "LCD", 3) != 0) - continue; + parent = pci_device_to_OF_node(par->pci_dev); + if (parent == NULL) + return -1; + if (par->twoHeads) { + char *pname; + int len; + + for (dp = NULL; + (dp = of_get_next_child(parent, dp)) != NULL;) { + pname = (char *)get_property(dp, "name", NULL); + if (!pname) + continue; + len = strlen(pname); + if ((pname[len-1] == 'A' && conn == 1) || + (pname[len-1] == 'B' && conn == 2)) { + for (i = 0; propnames[i] != NULL; ++i) { + pedid = (unsigned char *) + get_property(dp, propnames[i], + NULL); + if (pedid != NULL) + break; + } + of_node_put(dp); + break; + } + } + } + if (pedid == NULL) { for (i = 0; propnames[i] != NULL; ++i) { pedid = (unsigned char *) - get_property(dp, propnames[i], NULL); - if (pedid != NULL) { - *out_edid = pedid; - return 0; - } + get_property(parent, propnames[i], NULL); + if (pedid != NULL) + break; } } - return 1; + if (pedid) { + *out_edid = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (*out_edid == NULL) + return -1; + memcpy(*out_edid, pedid, EDID_LENGTH); + printk(KERN_DEBUG "nvidiafb: Found OF EDID for head %d\n", conn); + return 0; + } + return -1; } diff --git a/drivers/video/nvidia/nv_proto.h b/drivers/video/nvidia/nv_proto.h index cac44fc7f58717be955c65c1e43c2156a6343372..f60b1f4322700d2554e729245145c9c8407714d3 100644 --- a/drivers/video/nvidia/nv_proto.h +++ b/drivers/video/nvidia/nv_proto.h @@ -31,7 +31,7 @@ int NVShowHideCursor(struct nvidia_par *par, int); void NVLockUnlock(struct nvidia_par *par, int); /* in nvidia-i2c.c */ -#if defined(CONFIG_FB_NVIDIA_I2C) || defined (CONFIG_PPC_OF) +#ifdef CONFIG_FB_NVIDIA_I2C void nvidia_create_i2c_busses(struct nvidia_par *par); void nvidia_delete_i2c_busses(struct nvidia_par *par); int nvidia_probe_i2c_connector(struct fb_info *info, int conn, @@ -39,10 +39,18 @@ int nvidia_probe_i2c_connector(struct fb_info *info, int conn, #else #define nvidia_create_i2c_busses(...) #define nvidia_delete_i2c_busses(...) -#define nvidia_probe_i2c_connector(p, c, edid) \ -do { \ - *(edid) = NULL; \ -} while(0) +#define nvidia_probe_i2c_connector(p, c, edid) (-1) +#endif + +#ifdef CONFIG_FB_OF +int nvidia_probe_of_connector(struct fb_info *info, int conn, + u8 ** out_edid); +#else +static inline int nvidia_probe_of_connector(struct fb_info *info, int conn, + u8 ** out_edid) +{ + return -1; +} #endif /* in nv_accel.c */ diff --git a/drivers/video/nvidia/nv_setup.c b/drivers/video/nvidia/nv_setup.c index 11c84178f42069c83163ea01512c39707897d249..1f06a9f1bd0f52d893e4233111174281a23f130e 100644 --- a/drivers/video/nvidia/nv_setup.c +++ b/drivers/video/nvidia/nv_setup.c @@ -190,9 +190,9 @@ static int NVIsConnected(struct nvidia_par *par, int output) present = (NV_RD32(PRAMDAC, 0x0608) & (1 << 28)) ? 1 : 0; if (present) - printk("nvidiafb: CRTC%i found\n", output); + printk("nvidiafb: CRTC%i analog found\n", output); else - printk("nvidiafb: CRTC%i not found\n", output); + printk("nvidiafb: CRTC%i analog not found\n", output); NV_WR32(par->PRAMDAC0, 0x0608, NV_RD32(par->PRAMDAC0, 0x0608) & 0x0000EFFF); @@ -305,6 +305,9 @@ void NVCommonSetup(struct fb_info *info) int FlatPanel = -1; /* really means the CRTC is slaved */ int Television = 0; + memset(&monitorA, 0, sizeof(struct fb_monspecs)); + memset(&monitorB, 0, sizeof(struct fb_monspecs)); + par->PRAMIN = par->REGS + (0x00710000 / 4); par->PCRTC0 = par->REGS + (0x00600000 / 4); par->PRAMDAC0 = par->REGS + (0x00680000 / 4); @@ -401,7 +404,8 @@ void NVCommonSetup(struct fb_info *info) nvidia_create_i2c_busses(par); if (!par->twoHeads) { par->CRTCnumber = 0; - nvidia_probe_i2c_connector(info, 1, &edidA); + if (nvidia_probe_i2c_connector(info, 1, &edidA)) + nvidia_probe_of_connector(info, 1, &edidA); if (edidA && !fb_parse_edid(edidA, &var)) { printk("nvidiafb: EDID found from BUS1\n"); monA = &monitorA; @@ -488,14 +492,16 @@ void NVCommonSetup(struct fb_info *info) oldhead = NV_RD32(par->PCRTC0, 0x00000860); NV_WR32(par->PCRTC0, 0x00000860, oldhead | 0x00000010); - nvidia_probe_i2c_connector(info, 1, &edidA); + if (nvidia_probe_i2c_connector(info, 1, &edidA)) + nvidia_probe_of_connector(info, 1, &edidA); if (edidA && !fb_parse_edid(edidA, &var)) { printk("nvidiafb: EDID found from BUS1\n"); monA = &monitorA; fb_edid_to_monspecs(edidA, monA); } - nvidia_probe_i2c_connector(info, 2, &edidB); + if (nvidia_probe_i2c_connector(info, 2, &edidB)) + nvidia_probe_of_connector(info, 2, &edidB); if (edidB && !fb_parse_edid(edidB, &var)) { printk("nvidiafb: EDID found from BUS2\n"); monB = &monitorB; diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 308defc389a263b37fa1d7e58d9b184a691765cd..0b40a2a721c180609c15b16e82e3209b195a846e 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -411,6 +411,7 @@ MODULE_DEVICE_TABLE(pci, nvidiafb_pci_tbl); /* command line data, set in nvidiafb_setup() */ static int flatpanel __devinitdata = -1; /* Autodetect later */ +static int fpdither __devinitdata = -1; static int forceCRTC __devinitdata = -1; static int hwcur __devinitdata = 0; static int noaccel __devinitdata = 0; @@ -627,41 +628,85 @@ static void nvidia_save_vga(struct nvidia_par *par, NVTRACE_LEAVE(); } +#undef DUMP_REG + static void nvidia_write_regs(struct nvidia_par *par) { struct _riva_hw_state *state = &par->ModeReg; int i; NVTRACE_ENTER(); - NVWriteCrtc(par, 0x11, 0x00); - - NVLockUnlock(par, 0); NVLoadStateExt(par, state); NVWriteMiscOut(par, state->misc_output); + for (i = 1; i < NUM_SEQ_REGS; i++) { +#ifdef DUMP_REG + printk(" SEQ[%02x] = %08x\n", i, state->seq[i]); +#endif + NVWriteSeq(par, i, state->seq[i]); + } + + /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 of CRTC[17] */ + NVWriteCrtc(par, 0x11, state->crtc[0x11] & ~0x80); + for (i = 0; i < NUM_CRT_REGS; i++) { switch (i) { case 0x19: case 0x20 ... 0x40: break; default: +#ifdef DUMP_REG + printk("CRTC[%02x] = %08x\n", i, state->crtc[i]); +#endif NVWriteCrtc(par, i, state->crtc[i]); } } - for (i = 0; i < NUM_ATC_REGS; i++) - NVWriteAttr(par, i, state->attr[i]); - - for (i = 0; i < NUM_GRC_REGS; i++) + for (i = 0; i < NUM_GRC_REGS; i++) { +#ifdef DUMP_REG + printk(" GRA[%02x] = %08x\n", i, state->gra[i]); +#endif NVWriteGr(par, i, state->gra[i]); + } + + for (i = 0; i < NUM_ATC_REGS; i++) { +#ifdef DUMP_REG + printk("ATTR[%02x] = %08x\n", i, state->attr[i]); +#endif + NVWriteAttr(par, i, state->attr[i]); + } - for (i = 0; i < NUM_SEQ_REGS; i++) - NVWriteSeq(par, i, state->seq[i]); NVTRACE_LEAVE(); } +static void nvidia_vga_protect(struct nvidia_par *par, int on) +{ + unsigned char tmp; + + if (on) { + /* + * Turn off screen and disable sequencer. + */ + tmp = NVReadSeq(par, 0x01); + + NVWriteSeq(par, 0x00, 0x01); /* Synchronous Reset */ + NVWriteSeq(par, 0x01, tmp | 0x20); /* disable the display */ + } else { + /* + * Reenable sequencer, then turn on screen. + */ + + tmp = NVReadSeq(par, 0x01); + + NVWriteSeq(par, 0x01, tmp & ~0x20); /* reenable display */ + NVWriteSeq(par, 0x00, 0x03); /* End Reset */ + } +} + + + static int nvidia_calc_regs(struct fb_info *info) { struct nvidia_par *par = info->par; @@ -868,7 +913,7 @@ static void nvidia_init_vga(struct fb_info *info) for (i = 0; i < 0x10; i++) state->attr[i] = i; state->attr[0x10] = 0x41; - state->attr[0x11] = 0x01; + state->attr[0x11] = 0xff; state->attr[0x12] = 0x0f; state->attr[0x13] = 0x00; state->attr[0x14] = 0x00; @@ -982,16 +1027,24 @@ static int nvidiafb_set_par(struct fb_info *info) NVTRACE_ENTER(); NVLockUnlock(par, 1); - if (!par->FlatPanel || (info->var.bits_per_pixel != 24) || - !par->twoHeads) + if (!par->FlatPanel || !par->twoHeads) par->FPDither = 0; + if (par->FPDither < 0) { + if ((par->Chipset & 0x0ff0) == 0x0110) + par->FPDither = !!(NV_RD32(par->PRAMDAC, 0x0528) + & 0x00010000); + else + par->FPDither = !!(NV_RD32(par->PRAMDAC, 0x083C) & 1); + printk(KERN_INFO PFX "Flat panel dithering %s\n", + par->FPDither ? "enabled" : "disabled"); + } + info->fix.visual = (info->var.bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; nvidia_init_vga(info); nvidia_calc_regs(info); - nvidia_write_regs(par); NVLockUnlock(par, 0); if (par->twoHeads) { @@ -1000,7 +1053,22 @@ static int nvidiafb_set_par(struct fb_info *info) NVLockUnlock(par, 0); } - NVWriteCrtc(par, 0x11, 0x00); + nvidia_vga_protect(par, 1); + + nvidia_write_regs(par); + +#if defined (__BIG_ENDIAN) + /* turn on LFB swapping */ + { + unsigned char tmp; + + VGA_WR08(par->PCIO, 0x3d4, 0x46); + tmp = VGA_RD08(par->PCIO, 0x3d5); + tmp |= (1 << 7); + VGA_WR08(par->PCIO, 0x3d5, tmp); + } +#endif + info->fix.line_length = (info->var.xres_virtual * info->var.bits_per_pixel) >> 3; if (info->var.accel_flags) { @@ -1022,7 +1090,7 @@ static int nvidiafb_set_par(struct fb_info *info) par->cursor_reset = 1; - NVWriteCrtc(par, 0x11, 0xff); + nvidia_vga_protect(par, 0); NVTRACE_LEAVE(); return 0; @@ -1315,22 +1383,10 @@ static int __devinit nvidia_set_fbinfo(struct fb_info *info) fb_var_to_videomode(&modedb, &nvidiafb_default_var); if (specs->modedb != NULL) { - /* get preferred timing */ - if (specs->misc & FB_MISC_1ST_DETAIL) { - int i; - - for (i = 0; i < specs->modedb_len; i++) { - if (specs->modedb[i].flag & FB_MODE_IS_FIRST) { - modedb = specs->modedb[i]; - break; - } - } - } else { - /* otherwise, get first mode in database */ - modedb = specs->modedb[0]; - } + struct fb_videomode *modedb; - fb_videomode_to_var(&nvidiafb_default_var, &modedb); + modedb = fb_find_best_display(specs, &info->modelist); + fb_videomode_to_var(&nvidiafb_default_var, modedb); nvidiafb_default_var.bits_per_pixel = 8; } else if (par->fpWidth && par->fpHeight) { char buf[16]; @@ -1365,7 +1421,7 @@ static int __devinit nvidia_set_fbinfo(struct fb_info *info) info->pixmap.flags = FB_PIXMAP_SYSTEM; if (!hwcur) - info->fbops->fb_cursor = soft_cursor; + info->fbops->fb_cursor = NULL; info->var.accel_flags = (!noaccel); @@ -1490,9 +1546,9 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd, sprintf(nvidiafb_fix.id, "NV%x", (pd->device & 0x0ff0) >> 4); par->FlatPanel = flatpanel; - if (flatpanel == 1) printk(KERN_INFO PFX "flatpanel support enabled\n"); + par->FPDither = fpdither; par->CRTCnumber = forceCRTC; par->FpScale = (!noscale); @@ -1671,6 +1727,8 @@ static int __devinit nvidiafb_setup(char *options) } else if (!strncmp(this_opt, "nomtrr", 6)) { nomtrr = 1; #endif + } else if (!strncmp(this_opt, "fpdither:", 9)) { + fpdither = simple_strtol(this_opt+9, NULL, 0); } else mode_option = this_opt; } @@ -1717,7 +1775,11 @@ module_exit(nvidiafb_exit); module_param(flatpanel, int, 0); MODULE_PARM_DESC(flatpanel, "Enables experimental flat panel support for some chipsets. " - "(0 or 1=enabled) (default=0)"); + "(0=disabled, 1=enabled, -1=autodetect) (default=-1)"); +module_param(fpdither, int, 0); +MODULE_PARM_DESC(fpdither, + "Enables dithering of flat panel for 6 bits panels. " + "(0=disabled, 1=enabled, -1=autodetect) (default=-1)"); module_param(hwcur, int, 0); MODULE_PARM_DESC(hwcur, "Enables hardware cursor implementation. (0 or 1=enabled) " diff --git a/drivers/video/offb.c b/drivers/video/offb.c index 611922c0b22fbb8e4906be82b85c446c5351a1a4..2c856838694e1c87187ebe655c418ff0a63ae651 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -85,7 +85,6 @@ static struct fb_ops offb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; /* diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c index b76a5a9a125be4dde6d77959e780aed6fa664391..9aaf65fb623ae99e0df6dc2289c1f7e7379af89d 100644 --- a/drivers/video/p9100.c +++ b/drivers/video/p9100.c @@ -48,7 +48,6 @@ static struct fb_ops p9100_ops = { .fb_imageblit = cfb_imageblit, .fb_mmap = p9100_mmap, .fb_ioctl = p9100_ioctl, - .fb_cursor = soft_cursor, }; /* P9100 control registers */ diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c index b00887e9851cf938da8fa6dca5994366ef0982ed..ca4082ae5a18d34313a3a71c7ef2b34b977a484e 100644 --- a/drivers/video/platinumfb.c +++ b/drivers/video/platinumfb.c @@ -109,7 +109,6 @@ static struct fb_ops platinumfb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; /* diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index 42c17efa9fb086befad749eb6e8f58021fef72d8..0277ce031e5e0e3b5e941c71f6d4836ac8c2de3d 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c @@ -1034,7 +1034,6 @@ static struct fb_ops pm2fb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; /* @@ -1121,6 +1120,22 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev, default_par->mem_control, default_par->boot_address, default_par->mem_config); + if(default_par->mem_control == 0 && + default_par->boot_address == 0x31 && + default_par->mem_config == 0x259fffff && + pdev->subsystem_vendor == 0x1048 && + pdev->subsystem_device == 0x0a31) { + DPRINTK("subsystem_vendor: %04x, subsystem_device: %04x\n", + pdev->subsystem_vendor, pdev->subsystem_device); + DPRINTK("We have not been initialized by VGA BIOS " + "and are running on an Elsa Winner 2000 Office\n"); + DPRINTK("Initializing card timings manually...\n"); + default_par->mem_control=0; + default_par->boot_address=0x20; + default_par->mem_config=0xe6002021; + default_par->memclock=100000; + } + /* Now work out how big lfb is going to be. */ switch(default_par->mem_config & PM2F_MEM_CONFIG_RAM_MASK) { case PM2F_MEM_BANKS_1: diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c index c98f1c8d7dc27b6127fc430ceea517772b1de11d..f3927b6cda9d4d7f6edc8c29a65be8249577e5fc 100644 --- a/drivers/video/pmag-ba-fb.c +++ b/drivers/video/pmag-ba-fb.c @@ -128,7 +128,6 @@ static struct fb_ops pmagbafb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c index a483b13e117b71f93eab7b0e042075b481adf547..25148de5fe6795799999269bd3a92cb0991a0311 100644 --- a/drivers/video/pmagb-b-fb.c +++ b/drivers/video/pmagb-b-fb.c @@ -132,7 +132,6 @@ static struct fb_ops pmagbbfb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c index 31c547fd383bf7d49484667e52a2bf779bbd4018..ec4bacf9dd2e90d2c4b0d696356bdcfff6ee9b53 100644 --- a/drivers/video/pvr2fb.c +++ b/drivers/video/pvr2fb.c @@ -230,7 +230,6 @@ static struct fb_ops pvr2fb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; static struct fb_videomode pvr2_modedb[] __initdata = { diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index efd9333b05c24001b13a8212be03a91215dbcdaf..f305a5b77b23f8db3311315349a5cb24041ad37f 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -418,7 +418,6 @@ static struct fb_ops pxafb_ops = { .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, .fb_blank = pxafb_blank, - .fb_cursor = soft_cursor, .fb_mmap = pxafb_mmap, }; diff --git a/drivers/video/q40fb.c b/drivers/video/q40fb.c index 8416b2e2b501f7cc723f95f55525f21196a429bd..bfc41f2c902a2d93576b3a86f051b927a4e692bd 100644 --- a/drivers/video/q40fb.c +++ b/drivers/video/q40fb.c @@ -84,7 +84,6 @@ static struct fb_ops q40fb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; static int __init q40fb_probe(struct device *device) diff --git a/drivers/video/radeonfb.c b/drivers/video/radeonfb.c index a78b9bd8f89752c856d05e06dc4e74c25faecdad..600318f708f294e2aafd4e2c04aa9767778735b8 100644 --- a/drivers/video/radeonfb.c +++ b/drivers/video/radeonfb.c @@ -2218,7 +2218,6 @@ static struct fb_ops radeonfb_ops = { .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, #endif - .fb_cursor = soft_cursor, }; diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c index f4437430dc5f1bf1633ebd1e00f2d152ce31f452..3edbd14c5c469565500ce970866d2ef24ee86453 100644 --- a/drivers/video/s1d13xxxfb.c +++ b/drivers/video/s1d13xxxfb.c @@ -388,7 +388,6 @@ static struct fb_ops s1d13xxxfb_fbops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor }; static int s1d13xxxfb_width_tab[2][4] __devinitdata = { diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 3cef90456a4b3fb341c10defa60043aad77404b8..855a6778b9eba115879bdbde91d4372f414b9d81 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -495,7 +495,6 @@ static struct fb_ops s3c2410fb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; @@ -885,6 +884,7 @@ static int s3c2410fb_resume(struct device *dev) static struct device_driver s3c2410fb_driver = { .name = "s3c2410-lcd", + .owner = THIS_MODULE, .bus = &platform_bus_type, .probe = s3c2410fb_probe, .suspend = s3c2410fb_suspend, diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c index 3d35b28aaac7140affeedd874c4e9e3093b82204..a5184575cfae1696da0709d7db4298d638d93c94 100644 --- a/drivers/video/sa1100fb.c +++ b/drivers/video/sa1100fb.c @@ -853,7 +853,6 @@ static struct fb_ops sa1100fb_ops = { .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, .fb_blank = sa1100fb_blank, - .fb_cursor = soft_cursor, .fb_mmap = sa1100fb_mmap, }; diff --git a/drivers/video/savage/savagefb.h b/drivers/video/savage/savagefb.h index ea17f7e0482c31be3ce8275144640a7334d769b1..58cfdfb418333dbd58c763b809e3adcb8a61c705 100644 --- a/drivers/video/savage/savagefb.h +++ b/drivers/video/savage/savagefb.h @@ -169,6 +169,7 @@ struct savagefb_par { struct savagefb_i2c_chan chan; unsigned char *edid; u32 pseudo_palette[16]; + int paletteEnabled; int pm_state; int display_type; int dvi; @@ -244,105 +245,150 @@ struct savagefb_par { /* IO functions */ +static inline u8 savage_in8(u32 addr, struct savagefb_par *par) +{ + return readb(par->mmio.vbase + addr); +} + +static inline u16 savage_in16(u32 addr, struct savagefb_par *par) +{ + return readw(par->mmio.vbase + addr); +} + +static inline u32 savage_in32(u32 addr, struct savagefb_par *par) +{ + return readl(par->mmio.vbase + addr); +} + +static inline void savage_out8(u32 addr, u8 val, struct savagefb_par *par) +{ + writeb(val, par->mmio.vbase + addr); +} + +static inline void savage_out16(u32 addr, u16 val, struct savagefb_par *par) +{ + writew(val, par->mmio.vbase + addr); +} + +static inline void savage_out32(u32 addr, u32 val, struct savagefb_par *par) +{ + writel(val, par->mmio.vbase + addr); +} + +static inline u8 vga_in8(int addr, struct savagefb_par *par) +{ + return savage_in8(0x8000 + addr, par); +} + +static inline u16 vga_in16(int addr, struct savagefb_par *par) +{ + return savage_in16(0x8000 + addr, par); +} + +static inline u8 vga_in32(int addr, struct savagefb_par *par) +{ + return savage_in32(0x8000 + addr, par); +} + +static inline void vga_out8(int addr, u8 val, struct savagefb_par *par) +{ + savage_out8(0x8000 + addr, val, par); +} + +static inline void vga_out16(int addr, u16 val, struct savagefb_par *par) +{ + savage_out16(0x8000 + addr, val, par); +} + +static inline void vga_out32(int addr, u32 val, struct savagefb_par *par) +{ + savage_out32(0x8000 + addr, val, par); +} -#define vga_in8(addr) (inb (addr)) -#define vga_in16(addr) (inw (addr)) -#define vga_in32(addr) (inl (addr)) +static inline u8 VGArCR (u8 index, struct savagefb_par *par) +{ + vga_out8(0x3d4, index, par); + return vga_in8(0x3d5, par); +} + +static inline u8 VGArGR (u8 index, struct savagefb_par *par) +{ + vga_out8(0x3ce, index, par); + return vga_in8(0x3cf, par); +} + +static inline u8 VGArSEQ (u8 index, struct savagefb_par *par) +{ + vga_out8(0x3c4, index, par); + return vga_in8(0x3c5, par); +} -#define vga_out8(addr,val) (outb ((val), (addr))) -#define vga_out16(addr,val) (outw ((val), (addr))) -#define vga_out32(addr,val) (outl ((val), (addr))) +static inline void VGAwCR(u8 index, u8 val, struct savagefb_par *par) +{ + vga_out8(0x3d4, index, par); + vga_out8(0x3d5, val, par); +} -#define savage_in16(addr) readw(par->mmio.vbase + (addr)) -#define savage_in32(addr) readl(par->mmio.vbase + (addr)) +static inline void VGAwGR(u8 index, u8 val, struct savagefb_par *par) +{ + vga_out8(0x3ce, index, par); + vga_out8(0x3cf, val, par); +} -#define savage_out16(addr,val) writew((val), par->mmio.vbase + (addr)) -#define savage_out32(addr,val) writel((val), par->mmio.vbase + (addr)) +static inline void VGAwSEQ(u8 index, u8 val, struct savagefb_par *par) +{ + vga_out8(0x3c4, index, par); + vga_out8 (0x3c5, val, par); +} -static inline u8 VGArCR (u8 index) +static inline void VGAenablePalette(struct savagefb_par *par) { - outb (index, 0x3d4); - return inb (0x3d5); + u8 tmp; + + tmp = vga_in8(0x3da, par); + vga_out8(0x3c0, 0x00, par); + par->paletteEnabled = 1; } -static inline u8 VGArGR (u8 index) +static inline void VGAdisablePalette(struct savagefb_par *par) { - outb (index, 0x3ce); - return inb (0x3cf); + u8 tmp; + + tmp = vga_in8(0x3da, par); + vga_out8(0x3c0, 0x20, par); + par->paletteEnabled = 0; } -static inline u8 VGArSEQ (u8 index) +static inline void VGAwATTR(u8 index, u8 value, struct savagefb_par *par) { - outb (index, 0x3c4); - return inb (0x3c5); + u8 tmp; + + if (par->paletteEnabled) + index &= ~0x20; + else + index |= 0x20; + + tmp = vga_in8(0x3da, par); + vga_out8(0x3c0, index, par); + vga_out8 (0x3c0, value, par); } -#define VGAwCR(index, val) \ -do { \ - vga_out8 (0x3d4, index); \ - vga_out8 (0x3d5, val); \ -} while (0) - -#define VGAwGR(index, val) \ -do { \ - vga_out8 (0x3ce, index); \ - vga_out8 (0x3cf, val); \ -} while (0) - -#define VGAwSEQ(index, val) \ -do { \ - vga_out8 (0x3c4, index); \ - vga_out8 (0x3c5, val); \ -} while (0) - -#define VGAenablePalette() \ -do { \ - u8 tmp; \ - \ - tmp = vga_in8 (0x3da); \ - vga_out8 (0x3c0, 0x00); \ - paletteEnabled = 1; \ -} while (0) - -#define VGAdisablePalette() \ -do { \ - u8 tmp; \ - \ - tmp = vga_in8 (0x3da); \ - vga_out8 (0x3c0, 0x20); \ - paletteEnabled = 0; \ -} while (0) - -#define VGAwATTR(index, value) \ -do { \ - u8 tmp; \ - \ - if (paletteEnabled) \ - index &= ~0x20; \ - else \ - index |= 0x20; \ - \ - tmp = vga_in8 (0x3da); \ - vga_out8 (0x3c0, index); \ - vga_out8 (0x3c0, value); \ -} while (0) - -#define VGAwMISC(value) \ -do { \ - vga_out8 (0x3c2, value); \ -} while (0) +static inline void VGAwMISC(u8 value, struct savagefb_par *par) +{ + vga_out8(0x3c2, value, par); +} #ifndef CONFIG_FB_SAVAGE_ACCEL #define savagefb_set_clip(x) #endif -#define VerticalRetraceWait() \ -{ \ - vga_out8 (0x3d4, 0x17); \ - if (vga_in8 (0x3d5) & 0x80) { \ - while ((vga_in8(0x3da) & 0x08) == 0x08) ; \ - while ((vga_in8(0x3da) & 0x08) == 0x00) ; \ - } \ +static inline void VerticalRetraceWait(struct savagefb_par *par) +{ + vga_out8(0x3d4, 0x17, par); + if (vga_in8(0x3d5, par) & 0x80) { + while ((vga_in8(0x3da, par) & 0x08) == 0x08); + while ((vga_in8(0x3da, par) & 0x08) == 0x00); + } } extern int savagefb_probe_i2c_connector(struct fb_info *info, diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index 7c285455c924d5c407f13b5a6b5aba55ebf6b694..f0dfb35e3191b4637e76d085927f3e41dd76e5d0 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c @@ -74,7 +74,6 @@ static char *mode_option __initdata = NULL; -static int paletteEnabled = 0; #ifdef MODULE @@ -90,9 +89,9 @@ MODULE_DESCRIPTION("FBDev driver for S3 Savage PCI/AGP Chips"); static void vgaHWSeqReset (struct savagefb_par *par, int start) { if (start) - VGAwSEQ (0x00, 0x01); /* Synchronous Reset */ + VGAwSEQ (0x00, 0x01, par); /* Synchronous Reset */ else - VGAwSEQ (0x00, 0x03); /* End Reset */ + VGAwSEQ (0x00, 0x03, par); /* End Reset */ } static void vgaHWProtect (struct savagefb_par *par, int on) @@ -103,23 +102,23 @@ static void vgaHWProtect (struct savagefb_par *par, int on) /* * Turn off screen and disable sequencer. */ - tmp = VGArSEQ (0x01); + tmp = VGArSEQ (0x01, par); vgaHWSeqReset (par, 1); /* start synchronous reset */ - VGAwSEQ (0x01, tmp | 0x20); /* disable the display */ + VGAwSEQ (0x01, tmp | 0x20, par);/* disable the display */ - VGAenablePalette(); + VGAenablePalette(par); } else { /* * Reenable sequencer, then turn on screen. */ - tmp = VGArSEQ (0x01); + tmp = VGArSEQ (0x01, par); - VGAwSEQ (0x01, tmp & ~0x20); /* reenable display */ + VGAwSEQ (0x01, tmp & ~0x20, par);/* reenable display */ vgaHWSeqReset (par, 0); /* clear synchronous reset */ - VGAdisablePalette(); + VGAdisablePalette(par); } } @@ -127,27 +126,27 @@ static void vgaHWRestore (struct savagefb_par *par) { int i; - VGAwMISC (par->MiscOutReg); + VGAwMISC (par->MiscOutReg, par); for (i = 1; i < 5; i++) - VGAwSEQ (i, par->Sequencer[i]); + VGAwSEQ (i, par->Sequencer[i], par); /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or CRTC[17] */ - VGAwCR (17, par->CRTC[17] & ~0x80); + VGAwCR (17, par->CRTC[17] & ~0x80, par); for (i = 0; i < 25; i++) - VGAwCR (i, par->CRTC[i]); + VGAwCR (i, par->CRTC[i], par); for (i = 0; i < 9; i++) - VGAwGR (i, par->Graphics[i]); + VGAwGR (i, par->Graphics[i], par); - VGAenablePalette(); + VGAenablePalette(par); for (i = 0; i < 21; i++) - VGAwATTR (i, par->Attribute[i]); + VGAwATTR (i, par->Attribute[i], par); - VGAdisablePalette(); + VGAdisablePalette(par); } static void vgaHWInit (struct fb_var_screeninfo *var, @@ -267,7 +266,7 @@ savage3D_waitfifo(struct savagefb_par *par, int space) { int slots = MAXFIFO - space; - while ((savage_in32(0x48C00) & 0x0000ffff) > slots); + while ((savage_in32(0x48C00, par) & 0x0000ffff) > slots); } static void @@ -275,7 +274,7 @@ savage4_waitfifo(struct savagefb_par *par, int space) { int slots = MAXFIFO - space; - while ((savage_in32(0x48C60) & 0x001fffff) > slots); + while ((savage_in32(0x48C60, par) & 0x001fffff) > slots); } static void @@ -283,26 +282,26 @@ savage2000_waitfifo(struct savagefb_par *par, int space) { int slots = MAXFIFO - space; - while ((savage_in32(0x48C60) & 0x0000ffff) > slots); + while ((savage_in32(0x48C60, par) & 0x0000ffff) > slots); } /* Wait for idle accelerator */ static void savage3D_waitidle(struct savagefb_par *par) { - while ((savage_in32(0x48C00) & 0x0008ffff) != 0x80000); + while ((savage_in32(0x48C00, par) & 0x0008ffff) != 0x80000); } static void savage4_waitidle(struct savagefb_par *par) { - while ((savage_in32(0x48C60) & 0x00a00000) != 0x00a00000); + while ((savage_in32(0x48C60, par) & 0x00a00000) != 0x00a00000); } static void savage2000_waitidle(struct savagefb_par *par) { - while ((savage_in32(0x48C60) & 0x009fffff)); + while ((savage_in32(0x48C60, par) & 0x009fffff)); } @@ -319,59 +318,64 @@ SavageSetup2DEngine (struct savagefb_par *par) case S3_SAVAGE3D: case S3_SAVAGE_MX: /* Disable BCI */ - savage_out32(0x48C18, savage_in32(0x48C18) & 0x3FF0); + savage_out32(0x48C18, savage_in32(0x48C18, par) & 0x3FF0, par); /* Setup BCI command overflow buffer */ - savage_out32(0x48C14, (par->cob_offset >> 11) | (par->cob_index << 29)); + savage_out32(0x48C14, + (par->cob_offset >> 11) | (par->cob_index << 29), + par); /* Program shadow status update. */ - savage_out32(0x48C10, 0x78207220); - savage_out32(0x48C0C, 0); + savage_out32(0x48C10, 0x78207220, par); + savage_out32(0x48C0C, 0, par); /* Enable BCI and command overflow buffer */ - savage_out32(0x48C18, savage_in32(0x48C18) | 0x0C); + savage_out32(0x48C18, savage_in32(0x48C18, par) | 0x0C, par); break; case S3_SAVAGE4: case S3_PROSAVAGE: case S3_SUPERSAVAGE: /* Disable BCI */ - savage_out32(0x48C18, savage_in32(0x48C18) & 0x3FF0); + savage_out32(0x48C18, savage_in32(0x48C18, par) & 0x3FF0, par); /* Program shadow status update */ - savage_out32(0x48C10, 0x00700040); - savage_out32(0x48C0C, 0); + savage_out32(0x48C10, 0x00700040, par); + savage_out32(0x48C0C, 0, par); /* Enable BCI without the COB */ - savage_out32(0x48C18, savage_in32(0x48C18) | 0x08); + savage_out32(0x48C18, savage_in32(0x48C18, par) | 0x08, par); break; case S3_SAVAGE2000: /* Disable BCI */ - savage_out32(0x48C18, 0); + savage_out32(0x48C18, 0, par); /* Setup BCI command overflow buffer */ - savage_out32(0x48C18, (par->cob_offset >> 7) | (par->cob_index)); + savage_out32(0x48C18, + (par->cob_offset >> 7) | (par->cob_index), + par); /* Disable shadow status update */ - savage_out32(0x48A30, 0); + savage_out32(0x48A30, 0, par); /* Enable BCI and command overflow buffer */ - savage_out32(0x48C18, savage_in32(0x48C18) | 0x00280000 ); + savage_out32(0x48C18, savage_in32(0x48C18, par) | 0x00280000, + par); break; default: break; } /* Turn on 16-bit register access. */ - vga_out8(0x3d4, 0x31); - vga_out8(0x3d5, 0x0c); + vga_out8(0x3d4, 0x31, par); + vga_out8(0x3d5, 0x0c, par); /* Set stride to use GBD. */ - vga_out8 (0x3d4, 0x50); - vga_out8 (0x3d5, vga_in8 (0x3d5 ) | 0xC1); + vga_out8 (0x3d4, 0x50, par); + vga_out8 (0x3d5, vga_in8(0x3d5, par) | 0xC1, par); /* Enable 2D engine. */ - vga_out8 (0x3d4, 0x40 ); - vga_out8 (0x3d5, 0x01 ); + vga_out8 (0x3d4, 0x40, par); + vga_out8 (0x3d5, 0x01, par); - savage_out32 (MONO_PAT_0, ~0); - savage_out32 (MONO_PAT_1, ~0); + savage_out32 (MONO_PAT_0, ~0, par); + savage_out32 (MONO_PAT_1, ~0, par); /* Setup plane masks */ - savage_out32 (0x8128, ~0 ); /* enable all write planes */ - savage_out32 (0x812C, ~0 ); /* enable all read planes */ - savage_out16 (0x8134, 0x27 ); - savage_out16 (0x8136, 0x07 ); + savage_out32 (0x8128, ~0, par); /* enable all write planes */ + savage_out32 (0x812C, ~0, par); /* enable all read planes */ + savage_out16 (0x8134, 0x27, par); + savage_out16 (0x8136, 0x07, par); /* Now set the GBD */ par->bci_ptr = 0; @@ -489,8 +493,8 @@ static void SavagePrintRegs(void) for( i = 0; i < 0x70; i++ ) { if( !(i % 16) ) printk(KERN_DEBUG "\nSR%xx ", i >> 4 ); - vga_out8( 0x3c4, i ); - printk(KERN_DEBUG " %02x", vga_in8(0x3c5) ); + vga_out8( 0x3c4, i, par); + printk(KERN_DEBUG " %02x", vga_in8(0x3c5, par) ); } printk(KERN_DEBUG "\n\nCR x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC " @@ -499,8 +503,8 @@ static void SavagePrintRegs(void) for( i = 0; i < 0xB7; i++ ) { if( !(i % 16) ) printk(KERN_DEBUG "\nCR%xx ", i >> 4 ); - vga_out8( vgaCRIndex, i ); - printk(KERN_DEBUG " %02x", vga_in8(vgaCRReg) ); + vga_out8( vgaCRIndex, i, par); + printk(KERN_DEBUG " %02x", vga_in8(vgaCRReg, par) ); } printk(KERN_DEBUG "\n\n"); @@ -513,152 +517,152 @@ static void savage_get_default_par(struct savagefb_par *par) { unsigned char cr3a, cr53, cr66; - vga_out16 (0x3d4, 0x4838); - vga_out16 (0x3d4, 0xa039); - vga_out16 (0x3c4, 0x0608); - - vga_out8 (0x3d4, 0x66); - cr66 = vga_in8 (0x3d5); - vga_out8 (0x3d5, cr66 | 0x80); - vga_out8 (0x3d4, 0x3a); - cr3a = vga_in8 (0x3d5); - vga_out8 (0x3d5, cr3a | 0x80); - vga_out8 (0x3d4, 0x53); - cr53 = vga_in8 (0x3d5); - vga_out8 (0x3d5, cr53 & 0x7f); - - vga_out8 (0x3d4, 0x66); - vga_out8 (0x3d5, cr66); - vga_out8 (0x3d4, 0x3a); - vga_out8 (0x3d5, cr3a); - - vga_out8 (0x3d4, 0x66); - vga_out8 (0x3d5, cr66); - vga_out8 (0x3d4, 0x3a); - vga_out8 (0x3d5, cr3a); + vga_out16 (0x3d4, 0x4838, par); + vga_out16 (0x3d4, 0xa039, par); + vga_out16 (0x3c4, 0x0608, par); + + vga_out8 (0x3d4, 0x66, par); + cr66 = vga_in8 (0x3d5, par); + vga_out8 (0x3d5, cr66 | 0x80, par); + vga_out8 (0x3d4, 0x3a, par); + cr3a = vga_in8 (0x3d5, par); + vga_out8 (0x3d5, cr3a | 0x80, par); + vga_out8 (0x3d4, 0x53, par); + cr53 = vga_in8 (0x3d5, par); + vga_out8 (0x3d5, cr53 & 0x7f, par); + + vga_out8 (0x3d4, 0x66, par); + vga_out8 (0x3d5, cr66, par); + vga_out8 (0x3d4, 0x3a, par); + vga_out8 (0x3d5, cr3a, par); + + vga_out8 (0x3d4, 0x66, par); + vga_out8 (0x3d5, cr66, par); + vga_out8 (0x3d4, 0x3a, par); + vga_out8 (0x3d5, cr3a, par); /* unlock extended seq regs */ - vga_out8 (0x3c4, 0x08); - par->SR08 = vga_in8 (0x3c5); - vga_out8 (0x3c5, 0x06); + vga_out8 (0x3c4, 0x08, par); + par->SR08 = vga_in8 (0x3c5, par); + vga_out8 (0x3c5, 0x06, par); /* now save all the extended regs we need */ - vga_out8 (0x3d4, 0x31); - par->CR31 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x32); - par->CR32 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x34); - par->CR34 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x36); - par->CR36 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x3a); - par->CR3A = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x40); - par->CR40 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x42); - par->CR42 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x45); - par->CR45 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x50); - par->CR50 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x51); - par->CR51 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x53); - par->CR53 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x58); - par->CR58 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x60); - par->CR60 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x66); - par->CR66 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x67); - par->CR67 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x68); - par->CR68 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x69); - par->CR69 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x6f); - par->CR6F = vga_in8 (0x3d5); - - vga_out8 (0x3d4, 0x33); - par->CR33 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x86); - par->CR86 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x88); - par->CR88 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x90); - par->CR90 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x91); - par->CR91 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0xb0); - par->CRB0 = vga_in8 (0x3d5) | 0x80; + vga_out8 (0x3d4, 0x31, par); + par->CR31 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x32, par); + par->CR32 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x34, par); + par->CR34 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x36, par); + par->CR36 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x3a, par); + par->CR3A = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x40, par); + par->CR40 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x42, par); + par->CR42 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x45, par); + par->CR45 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x50, par); + par->CR50 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x51, par); + par->CR51 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x53, par); + par->CR53 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x58, par); + par->CR58 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x60, par); + par->CR60 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x66, par); + par->CR66 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x67, par); + par->CR67 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x68, par); + par->CR68 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x69, par); + par->CR69 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x6f, par); + par->CR6F = vga_in8 (0x3d5, par); + + vga_out8 (0x3d4, 0x33, par); + par->CR33 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x86, par); + par->CR86 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x88, par); + par->CR88 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x90, par); + par->CR90 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x91, par); + par->CR91 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0xb0, par); + par->CRB0 = vga_in8 (0x3d5, par) | 0x80; /* extended mode timing regs */ - vga_out8 (0x3d4, 0x3b); - par->CR3B = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x3c); - par->CR3C = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x43); - par->CR43 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x5d); - par->CR5D = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x5e); - par->CR5E = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x65); - par->CR65 = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x3b, par); + par->CR3B = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x3c, par); + par->CR3C = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x43, par); + par->CR43 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x5d, par); + par->CR5D = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x5e, par); + par->CR5E = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x65, par); + par->CR65 = vga_in8 (0x3d5, par); /* save seq extended regs for DCLK PLL programming */ - vga_out8 (0x3c4, 0x0e); - par->SR0E = vga_in8 (0x3c5); - vga_out8 (0x3c4, 0x0f); - par->SR0F = vga_in8 (0x3c5); - vga_out8 (0x3c4, 0x10); - par->SR10 = vga_in8 (0x3c5); - vga_out8 (0x3c4, 0x11); - par->SR11 = vga_in8 (0x3c5); - vga_out8 (0x3c4, 0x12); - par->SR12 = vga_in8 (0x3c5); - vga_out8 (0x3c4, 0x13); - par->SR13 = vga_in8 (0x3c5); - vga_out8 (0x3c4, 0x29); - par->SR29 = vga_in8 (0x3c5); - - vga_out8 (0x3c4, 0x15); - par->SR15 = vga_in8 (0x3c5); - vga_out8 (0x3c4, 0x30); - par->SR30 = vga_in8 (0x3c5); - vga_out8 (0x3c4, 0x18); - par->SR18 = vga_in8 (0x3c5); + vga_out8 (0x3c4, 0x0e, par); + par->SR0E = vga_in8 (0x3c5, par); + vga_out8 (0x3c4, 0x0f, par); + par->SR0F = vga_in8 (0x3c5, par); + vga_out8 (0x3c4, 0x10, par); + par->SR10 = vga_in8 (0x3c5, par); + vga_out8 (0x3c4, 0x11, par); + par->SR11 = vga_in8 (0x3c5, par); + vga_out8 (0x3c4, 0x12, par); + par->SR12 = vga_in8 (0x3c5, par); + vga_out8 (0x3c4, 0x13, par); + par->SR13 = vga_in8 (0x3c5, par); + vga_out8 (0x3c4, 0x29, par); + par->SR29 = vga_in8 (0x3c5, par); + + vga_out8 (0x3c4, 0x15, par); + par->SR15 = vga_in8 (0x3c5, par); + vga_out8 (0x3c4, 0x30, par); + par->SR30 = vga_in8 (0x3c5, par); + vga_out8 (0x3c4, 0x18, par); + par->SR18 = vga_in8 (0x3c5, par); /* Save flat panel expansion regsters. */ if (par->chip == S3_SAVAGE_MX) { int i; for (i = 0; i < 8; i++) { - vga_out8 (0x3c4, 0x54+i); - par->SR54[i] = vga_in8 (0x3c5); + vga_out8 (0x3c4, 0x54+i, par); + par->SR54[i] = vga_in8 (0x3c5, par); } } - vga_out8 (0x3d4, 0x66); - cr66 = vga_in8 (0x3d5); - vga_out8 (0x3d5, cr66 | 0x80); - vga_out8 (0x3d4, 0x3a); - cr3a = vga_in8 (0x3d5); - vga_out8 (0x3d5, cr3a | 0x80); + vga_out8 (0x3d4, 0x66, par); + cr66 = vga_in8 (0x3d5, par); + vga_out8 (0x3d5, cr66 | 0x80, par); + vga_out8 (0x3d4, 0x3a, par); + cr3a = vga_in8 (0x3d5, par); + vga_out8 (0x3d5, cr3a | 0x80, par); /* now save MIU regs */ if (par->chip != S3_SAVAGE_MX) { - par->MMPR0 = savage_in32(FIFO_CONTROL_REG); - par->MMPR1 = savage_in32(MIU_CONTROL_REG); - par->MMPR2 = savage_in32(STREAMS_TIMEOUT_REG); - par->MMPR3 = savage_in32(MISC_TIMEOUT_REG); + par->MMPR0 = savage_in32(FIFO_CONTROL_REG, par); + par->MMPR1 = savage_in32(MIU_CONTROL_REG, par); + par->MMPR2 = savage_in32(STREAMS_TIMEOUT_REG, par); + par->MMPR3 = savage_in32(MISC_TIMEOUT_REG, par); } - vga_out8 (0x3d4, 0x3a); - vga_out8 (0x3d5, cr3a); - vga_out8 (0x3d4, 0x66); - vga_out8 (0x3d5, cr66); + vga_out8 (0x3d4, 0x3a, par); + vga_out8 (0x3d5, cr3a, par); + vga_out8 (0x3d4, 0x66, par); + vga_out8 (0x3d5, cr66, par); } static void savage_update_var(struct fb_var_screeninfo *var, struct fb_videomode *modedb) @@ -868,8 +872,8 @@ static int savagefb_decode_var (struct fb_var_screeninfo *var, * match. Fall back to traditional register-crunching. */ - vga_out8 (0x3d4, 0x3a); - tmp = vga_in8 (0x3d5); + vga_out8 (0x3d4, 0x3a, par); + tmp = vga_in8 (0x3d5, par); if (1 /*FIXME:psav->pci_burst*/) par->CR3A = (tmp & 0x7f) | 0x15; else @@ -879,16 +883,16 @@ static int savagefb_decode_var (struct fb_var_screeninfo *var, par->CR31 = 0x8c; par->CR66 = 0x89; - vga_out8 (0x3d4, 0x58); - par->CR58 = vga_in8 (0x3d5) & 0x80; + vga_out8 (0x3d4, 0x58, par); + par->CR58 = vga_in8 (0x3d5, par) & 0x80; par->CR58 |= 0x13; par->SR15 = 0x03 | 0x80; par->SR18 = 0x00; par->CR43 = par->CR45 = par->CR65 = 0x00; - vga_out8 (0x3d4, 0x40); - par->CR40 = vga_in8 (0x3d5) & ~0x01; + vga_out8 (0x3d4, 0x40, par); + par->CR40 = vga_in8 (0x3d5, par) & ~0x01; par->MMPR0 = 0x010400; par->MMPR1 = 0x00; @@ -992,19 +996,19 @@ static int savagefb_decode_var (struct fb_var_screeninfo *var, par->CR67 |= 1; - vga_out8(0x3d4, 0x36); - par->CR36 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x68); - par->CR68 = vga_in8 (0x3d5); + vga_out8(0x3d4, 0x36, par); + par->CR36 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x68, par); + par->CR68 = vga_in8 (0x3d5, par); par->CR69 = 0; - vga_out8 (0x3d4, 0x6f); - par->CR6F = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x86); - par->CR86 = vga_in8 (0x3d5); - vga_out8 (0x3d4, 0x88); - par->CR88 = vga_in8 (0x3d5) | 0x08; - vga_out8 (0x3d4, 0xb0); - par->CRB0 = vga_in8 (0x3d5) | 0x80; + vga_out8 (0x3d4, 0x6f, par); + par->CR6F = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x86, par); + par->CR86 = vga_in8 (0x3d5, par); + vga_out8 (0x3d4, 0x88, par); + par->CR88 = vga_in8 (0x3d5, par) | 0x08; + vga_out8 (0x3d4, 0xb0, par); + par->CRB0 = vga_in8 (0x3d5, par) | 0x80; return 0; } @@ -1033,11 +1037,11 @@ static int savagefb_setcolreg(unsigned regno, switch (info->var.bits_per_pixel) { case 8: - vga_out8 (0x3c8, regno); + vga_out8 (0x3c8, regno, par); - vga_out8 (0x3c9, red >> 10); - vga_out8 (0x3c9, green >> 10); - vga_out8 (0x3c9, blue >> 10); + vga_out8 (0x3c9, red >> 10, par); + vga_out8 (0x3c9, green >> 10, par); + vga_out8 (0x3c9, blue >> 10, par); break; case 16: @@ -1079,11 +1083,11 @@ static void savagefb_set_par_int (struct savagefb_par *par) par->SavageWaitIdle (par); - vga_out8 (0x3c2, 0x23); + vga_out8 (0x3c2, 0x23, par); - vga_out16 (0x3d4, 0x4838); - vga_out16 (0x3d4, 0xa539); - vga_out16 (0x3c4, 0x0608); + vga_out16 (0x3d4, 0x4838, par); + vga_out16 (0x3d4, 0xa539, par); + vga_out16 (0x3c4, 0x0608, par); vgaHWProtect (par, 1); @@ -1094,197 +1098,197 @@ static void savagefb_set_par_int (struct savagefb_par *par) * switch to mode 3 here seems to eliminate the issue. */ - VerticalRetraceWait(); - vga_out8 (0x3d4, 0x67); - cr67 = vga_in8 (0x3d5); - vga_out8 (0x3d5, cr67/*par->CR67*/ & ~0x0c); /* no STREAMS yet */ + VerticalRetraceWait(par); + vga_out8 (0x3d4, 0x67, par); + cr67 = vga_in8 (0x3d5, par); + vga_out8 (0x3d5, cr67/*par->CR67*/ & ~0x0c, par); /* no STREAMS yet */ - vga_out8 (0x3d4, 0x23); - vga_out8 (0x3d5, 0x00); - vga_out8 (0x3d4, 0x26); - vga_out8 (0x3d5, 0x00); + vga_out8 (0x3d4, 0x23, par); + vga_out8 (0x3d5, 0x00, par); + vga_out8 (0x3d4, 0x26, par); + vga_out8 (0x3d5, 0x00, par); /* restore extended regs */ - vga_out8 (0x3d4, 0x66); - vga_out8 (0x3d5, par->CR66); - vga_out8 (0x3d4, 0x3a); - vga_out8 (0x3d5, par->CR3A); - vga_out8 (0x3d4, 0x31); - vga_out8 (0x3d5, par->CR31); - vga_out8 (0x3d4, 0x32); - vga_out8 (0x3d5, par->CR32); - vga_out8 (0x3d4, 0x58); - vga_out8 (0x3d5, par->CR58); - vga_out8 (0x3d4, 0x53); - vga_out8 (0x3d5, par->CR53 & 0x7f); - - vga_out16 (0x3c4, 0x0608); + vga_out8 (0x3d4, 0x66, par); + vga_out8 (0x3d5, par->CR66, par); + vga_out8 (0x3d4, 0x3a, par); + vga_out8 (0x3d5, par->CR3A, par); + vga_out8 (0x3d4, 0x31, par); + vga_out8 (0x3d5, par->CR31, par); + vga_out8 (0x3d4, 0x32, par); + vga_out8 (0x3d5, par->CR32, par); + vga_out8 (0x3d4, 0x58, par); + vga_out8 (0x3d5, par->CR58, par); + vga_out8 (0x3d4, 0x53, par); + vga_out8 (0x3d5, par->CR53 & 0x7f, par); + + vga_out16 (0x3c4, 0x0608, par); /* Restore DCLK registers. */ - vga_out8 (0x3c4, 0x0e); - vga_out8 (0x3c5, par->SR0E); - vga_out8 (0x3c4, 0x0f); - vga_out8 (0x3c5, par->SR0F); - vga_out8 (0x3c4, 0x29); - vga_out8 (0x3c5, par->SR29); - vga_out8 (0x3c4, 0x15); - vga_out8 (0x3c5, par->SR15); + vga_out8 (0x3c4, 0x0e, par); + vga_out8 (0x3c5, par->SR0E, par); + vga_out8 (0x3c4, 0x0f, par); + vga_out8 (0x3c5, par->SR0F, par); + vga_out8 (0x3c4, 0x29, par); + vga_out8 (0x3c5, par->SR29, par); + vga_out8 (0x3c4, 0x15, par); + vga_out8 (0x3c5, par->SR15, par); /* Restore flat panel expansion regsters. */ if( par->chip == S3_SAVAGE_MX ) { int i; for( i = 0; i < 8; i++ ) { - vga_out8 (0x3c4, 0x54+i); - vga_out8 (0x3c5, par->SR54[i]); + vga_out8 (0x3c4, 0x54+i, par); + vga_out8 (0x3c5, par->SR54[i], par); } } vgaHWRestore (par); /* extended mode timing registers */ - vga_out8 (0x3d4, 0x53); - vga_out8 (0x3d5, par->CR53); - vga_out8 (0x3d4, 0x5d); - vga_out8 (0x3d5, par->CR5D); - vga_out8 (0x3d4, 0x5e); - vga_out8 (0x3d5, par->CR5E); - vga_out8 (0x3d4, 0x3b); - vga_out8 (0x3d5, par->CR3B); - vga_out8 (0x3d4, 0x3c); - vga_out8 (0x3d5, par->CR3C); - vga_out8 (0x3d4, 0x43); - vga_out8 (0x3d5, par->CR43); - vga_out8 (0x3d4, 0x65); - vga_out8 (0x3d5, par->CR65); + vga_out8 (0x3d4, 0x53, par); + vga_out8 (0x3d5, par->CR53, par); + vga_out8 (0x3d4, 0x5d, par); + vga_out8 (0x3d5, par->CR5D, par); + vga_out8 (0x3d4, 0x5e, par); + vga_out8 (0x3d5, par->CR5E, par); + vga_out8 (0x3d4, 0x3b, par); + vga_out8 (0x3d5, par->CR3B, par); + vga_out8 (0x3d4, 0x3c, par); + vga_out8 (0x3d5, par->CR3C, par); + vga_out8 (0x3d4, 0x43, par); + vga_out8 (0x3d5, par->CR43, par); + vga_out8 (0x3d4, 0x65, par); + vga_out8 (0x3d5, par->CR65, par); /* restore the desired video mode with cr67 */ - vga_out8 (0x3d4, 0x67); + vga_out8 (0x3d4, 0x67, par); /* following part not present in X11 driver */ - cr67 = vga_in8 (0x3d5) & 0xf; - vga_out8 (0x3d5, 0x50 | cr67); + cr67 = vga_in8 (0x3d5, par) & 0xf; + vga_out8 (0x3d5, 0x50 | cr67, par); udelay (10000); - vga_out8 (0x3d4, 0x67); + vga_out8 (0x3d4, 0x67, par); /* end of part */ - vga_out8 (0x3d5, par->CR67 & ~0x0c); + vga_out8 (0x3d5, par->CR67 & ~0x0c, par); /* other mode timing and extended regs */ - vga_out8 (0x3d4, 0x34); - vga_out8 (0x3d5, par->CR34); - vga_out8 (0x3d4, 0x40); - vga_out8 (0x3d5, par->CR40); - vga_out8 (0x3d4, 0x42); - vga_out8 (0x3d5, par->CR42); - vga_out8 (0x3d4, 0x45); - vga_out8 (0x3d5, par->CR45); - vga_out8 (0x3d4, 0x50); - vga_out8 (0x3d5, par->CR50); - vga_out8 (0x3d4, 0x51); - vga_out8 (0x3d5, par->CR51); + vga_out8 (0x3d4, 0x34, par); + vga_out8 (0x3d5, par->CR34, par); + vga_out8 (0x3d4, 0x40, par); + vga_out8 (0x3d5, par->CR40, par); + vga_out8 (0x3d4, 0x42, par); + vga_out8 (0x3d5, par->CR42, par); + vga_out8 (0x3d4, 0x45, par); + vga_out8 (0x3d5, par->CR45, par); + vga_out8 (0x3d4, 0x50, par); + vga_out8 (0x3d5, par->CR50, par); + vga_out8 (0x3d4, 0x51, par); + vga_out8 (0x3d5, par->CR51, par); /* memory timings */ - vga_out8 (0x3d4, 0x36); - vga_out8 (0x3d5, par->CR36); - vga_out8 (0x3d4, 0x60); - vga_out8 (0x3d5, par->CR60); - vga_out8 (0x3d4, 0x68); - vga_out8 (0x3d5, par->CR68); - vga_out8 (0x3d4, 0x69); - vga_out8 (0x3d5, par->CR69); - vga_out8 (0x3d4, 0x6f); - vga_out8 (0x3d5, par->CR6F); - - vga_out8 (0x3d4, 0x33); - vga_out8 (0x3d5, par->CR33); - vga_out8 (0x3d4, 0x86); - vga_out8 (0x3d5, par->CR86); - vga_out8 (0x3d4, 0x88); - vga_out8 (0x3d5, par->CR88); - vga_out8 (0x3d4, 0x90); - vga_out8 (0x3d5, par->CR90); - vga_out8 (0x3d4, 0x91); - vga_out8 (0x3d5, par->CR91); + vga_out8 (0x3d4, 0x36, par); + vga_out8 (0x3d5, par->CR36, par); + vga_out8 (0x3d4, 0x60, par); + vga_out8 (0x3d5, par->CR60, par); + vga_out8 (0x3d4, 0x68, par); + vga_out8 (0x3d5, par->CR68, par); + vga_out8 (0x3d4, 0x69, par); + vga_out8 (0x3d5, par->CR69, par); + vga_out8 (0x3d4, 0x6f, par); + vga_out8 (0x3d5, par->CR6F, par); + + vga_out8 (0x3d4, 0x33, par); + vga_out8 (0x3d5, par->CR33, par); + vga_out8 (0x3d4, 0x86, par); + vga_out8 (0x3d5, par->CR86, par); + vga_out8 (0x3d4, 0x88, par); + vga_out8 (0x3d5, par->CR88, par); + vga_out8 (0x3d4, 0x90, par); + vga_out8 (0x3d5, par->CR90, par); + vga_out8 (0x3d4, 0x91, par); + vga_out8 (0x3d5, par->CR91, par); if (par->chip == S3_SAVAGE4) { - vga_out8 (0x3d4, 0xb0); - vga_out8 (0x3d5, par->CRB0); + vga_out8 (0x3d4, 0xb0, par); + vga_out8 (0x3d5, par->CRB0, par); } - vga_out8 (0x3d4, 0x32); - vga_out8 (0x3d5, par->CR32); + vga_out8 (0x3d4, 0x32, par); + vga_out8 (0x3d5, par->CR32, par); /* unlock extended seq regs */ - vga_out8 (0x3c4, 0x08); - vga_out8 (0x3c5, 0x06); + vga_out8 (0x3c4, 0x08, par); + vga_out8 (0x3c5, 0x06, par); /* Restore extended sequencer regs for MCLK. SR10 == 255 indicates * that we should leave the default SR10 and SR11 values there. */ if (par->SR10 != 255) { - vga_out8 (0x3c4, 0x10); - vga_out8 (0x3c5, par->SR10); - vga_out8 (0x3c4, 0x11); - vga_out8 (0x3c5, par->SR11); + vga_out8 (0x3c4, 0x10, par); + vga_out8 (0x3c5, par->SR10, par); + vga_out8 (0x3c4, 0x11, par); + vga_out8 (0x3c5, par->SR11, par); } /* restore extended seq regs for dclk */ - vga_out8 (0x3c4, 0x0e); - vga_out8 (0x3c5, par->SR0E); - vga_out8 (0x3c4, 0x0f); - vga_out8 (0x3c5, par->SR0F); - vga_out8 (0x3c4, 0x12); - vga_out8 (0x3c5, par->SR12); - vga_out8 (0x3c4, 0x13); - vga_out8 (0x3c5, par->SR13); - vga_out8 (0x3c4, 0x29); - vga_out8 (0x3c5, par->SR29); - - vga_out8 (0x3c4, 0x18); - vga_out8 (0x3c5, par->SR18); + vga_out8 (0x3c4, 0x0e, par); + vga_out8 (0x3c5, par->SR0E, par); + vga_out8 (0x3c4, 0x0f, par); + vga_out8 (0x3c5, par->SR0F, par); + vga_out8 (0x3c4, 0x12, par); + vga_out8 (0x3c5, par->SR12, par); + vga_out8 (0x3c4, 0x13, par); + vga_out8 (0x3c5, par->SR13, par); + vga_out8 (0x3c4, 0x29, par); + vga_out8 (0x3c5, par->SR29, par); + + vga_out8 (0x3c4, 0x18, par); + vga_out8 (0x3c5, par->SR18, par); /* load new m, n pll values for dclk & mclk */ - vga_out8 (0x3c4, 0x15); - tmp = vga_in8 (0x3c5) & ~0x21; + vga_out8 (0x3c4, 0x15, par); + tmp = vga_in8 (0x3c5, par) & ~0x21; - vga_out8 (0x3c5, tmp | 0x03); - vga_out8 (0x3c5, tmp | 0x23); - vga_out8 (0x3c5, tmp | 0x03); - vga_out8 (0x3c5, par->SR15); + vga_out8 (0x3c5, tmp | 0x03, par); + vga_out8 (0x3c5, tmp | 0x23, par); + vga_out8 (0x3c5, tmp | 0x03, par); + vga_out8 (0x3c5, par->SR15, par); udelay (100); - vga_out8 (0x3c4, 0x30); - vga_out8 (0x3c5, par->SR30); - vga_out8 (0x3c4, 0x08); - vga_out8 (0x3c5, par->SR08); + vga_out8 (0x3c4, 0x30, par); + vga_out8 (0x3c5, par->SR30, par); + vga_out8 (0x3c4, 0x08, par); + vga_out8 (0x3c5, par->SR08, par); /* now write out cr67 in full, possibly starting STREAMS */ - VerticalRetraceWait(); - vga_out8 (0x3d4, 0x67); - vga_out8 (0x3d5, par->CR67); + VerticalRetraceWait(par); + vga_out8 (0x3d4, 0x67, par); + vga_out8 (0x3d5, par->CR67, par); - vga_out8 (0x3d4, 0x66); - cr66 = vga_in8 (0x3d5); - vga_out8 (0x3d5, cr66 | 0x80); - vga_out8 (0x3d4, 0x3a); - cr3a = vga_in8 (0x3d5); - vga_out8 (0x3d5, cr3a | 0x80); + vga_out8 (0x3d4, 0x66, par); + cr66 = vga_in8 (0x3d5, par); + vga_out8 (0x3d5, cr66 | 0x80, par); + vga_out8 (0x3d4, 0x3a, par); + cr3a = vga_in8 (0x3d5, par); + vga_out8 (0x3d5, cr3a | 0x80, par); if (par->chip != S3_SAVAGE_MX) { - VerticalRetraceWait(); - savage_out32 (FIFO_CONTROL_REG, par->MMPR0); + VerticalRetraceWait(par); + savage_out32 (FIFO_CONTROL_REG, par->MMPR0, par); par->SavageWaitIdle (par); - savage_out32 (MIU_CONTROL_REG, par->MMPR1); + savage_out32 (MIU_CONTROL_REG, par->MMPR1, par); par->SavageWaitIdle (par); - savage_out32 (STREAMS_TIMEOUT_REG, par->MMPR2); + savage_out32 (STREAMS_TIMEOUT_REG, par->MMPR2, par); par->SavageWaitIdle (par); - savage_out32 (MISC_TIMEOUT_REG, par->MMPR3); + savage_out32 (MISC_TIMEOUT_REG, par->MMPR3, par); } - vga_out8 (0x3d4, 0x66); - vga_out8 (0x3d5, cr66); - vga_out8 (0x3d4, 0x3a); - vga_out8 (0x3d5, cr3a); + vga_out8 (0x3d4, 0x66, par); + vga_out8 (0x3d5, cr66, par); + vga_out8 (0x3d4, 0x3a, par); + vga_out8 (0x3d5, cr3a, par); SavageSetup2DEngine (par); vgaHWProtect (par, 0); @@ -1299,10 +1303,10 @@ static void savagefb_update_start (struct savagefb_par *par, * ((var->bits_per_pixel+7) / 8)) >> 2; /* now program the start address registers */ - vga_out16(0x3d4, (base & 0x00ff00) | 0x0c); - vga_out16(0x3d4, ((base & 0x00ff) << 8) | 0x0d); - vga_out8 (0x3d4, 0x69); - vga_out8 (0x3d5, (base & 0x7f0000) >> 16); + vga_out16(0x3d4, (base & 0x00ff00) | 0x0c, par); + vga_out16(0x3d4, ((base & 0x00ff) << 8) | 0x0d, par); + vga_out8 (0x3d4, 0x69, par); + vga_out8 (0x3d5, (base & 0x7f0000) >> 16, par); } @@ -1406,12 +1410,12 @@ static int savagefb_blank(int blank, struct fb_info *info) u8 sr8 = 0, srd = 0; if (par->display_type == DISP_CRT) { - vga_out8(0x3c4, 0x08); - sr8 = vga_in8(0x3c5); + vga_out8(0x3c4, 0x08, par); + sr8 = vga_in8(0x3c5, par); sr8 |= 0x06; - vga_out8(0x3c5, sr8); - vga_out8(0x3c4, 0x0d); - srd = vga_in8(0x3c5); + vga_out8(0x3c5, sr8, par); + vga_out8(0x3c4, 0x0d, par); + srd = vga_in8(0x3c5, par); srd &= 0x03; switch (blank) { @@ -1429,8 +1433,8 @@ static int savagefb_blank(int blank, struct fb_info *info) break; } - vga_out8(0x3c4, 0x0d); - vga_out8(0x3c5, srd); + vga_out8(0x3c4, 0x0d, par); + vga_out8(0x3c5, srd, par); } if (par->display_type == DISP_LCD || @@ -1438,14 +1442,14 @@ static int savagefb_blank(int blank, struct fb_info *info) switch(blank) { case FB_BLANK_UNBLANK: case FB_BLANK_NORMAL: - vga_out8(0x3c4, 0x31); /* SR31 bit 4 - FP enable */ - vga_out8(0x3c5, vga_in8(0x3c5) | 0x10); + vga_out8(0x3c4, 0x31, par); /* SR31 bit 4 - FP enable */ + vga_out8(0x3c5, vga_in8(0x3c5, par) | 0x10, par); break; case FB_BLANK_VSYNC_SUSPEND: case FB_BLANK_HSYNC_SUSPEND: case FB_BLANK_POWERDOWN: - vga_out8(0x3c4, 0x31); /* SR31 bit 4 - FP enable */ - vga_out8(0x3c5, vga_in8(0x3c5) & ~0x10); + vga_out8(0x3c4, 0x31, par); /* SR31 bit 4 - FP enable */ + vga_out8(0x3c5, vga_in8(0x3c5, par) & ~0x10, par); break; } } @@ -1470,7 +1474,6 @@ static struct fb_ops savagefb_ops = { .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, #endif - .fb_cursor = soft_cursor, }; /* --------------------------------------------------------------------- */ @@ -1499,15 +1502,15 @@ static void savage_enable_mmio (struct savagefb_par *par) DBG ("savage_enable_mmio\n"); - val = vga_in8 (0x3c3); - vga_out8 (0x3c3, val | 0x01); - val = vga_in8 (0x3cc); - vga_out8 (0x3c2, val | 0x01); + val = vga_in8 (0x3c3, par); + vga_out8 (0x3c3, val | 0x01, par); + val = vga_in8 (0x3cc, par); + vga_out8 (0x3c2, val | 0x01, par); if (par->chip >= S3_SAVAGE4) { - vga_out8 (0x3d4, 0x40); - val = vga_in8 (0x3d5); - vga_out8 (0x3d5, val | 1); + vga_out8 (0x3d4, 0x40, par); + val = vga_in8 (0x3d5, par); + vga_out8 (0x3d5, val | 1, par); } } @@ -1519,9 +1522,9 @@ static void savage_disable_mmio (struct savagefb_par *par) DBG ("savage_disable_mmio\n"); if(par->chip >= S3_SAVAGE4 ) { - vga_out8 (0x3d4, 0x40); - val = vga_in8 (0x3d5); - vga_out8 (0x3d5, val | 1); + vga_out8 (0x3d4, 0x40, par); + val = vga_in8 (0x3d5, par); + vga_out8 (0x3d5, val | 1, par); } } @@ -1641,30 +1644,30 @@ static int __devinit savage_init_hw (struct savagefb_par *par) DBG("savage_init_hw"); /* unprotect CRTC[0-7] */ - vga_out8(0x3d4, 0x11); - tmp = vga_in8(0x3d5); - vga_out8(0x3d5, tmp & 0x7f); + vga_out8(0x3d4, 0x11, par); + tmp = vga_in8(0x3d5, par); + vga_out8(0x3d5, tmp & 0x7f, par); /* unlock extended regs */ - vga_out16(0x3d4, 0x4838); - vga_out16(0x3d4, 0xa039); - vga_out16(0x3c4, 0x0608); + vga_out16(0x3d4, 0x4838, par); + vga_out16(0x3d4, 0xa039, par); + vga_out16(0x3c4, 0x0608, par); - vga_out8(0x3d4, 0x40); - tmp = vga_in8(0x3d5); - vga_out8(0x3d5, tmp & ~0x01); + vga_out8(0x3d4, 0x40, par); + tmp = vga_in8(0x3d5, par); + vga_out8(0x3d5, tmp & ~0x01, par); /* unlock sys regs */ - vga_out8(0x3d4, 0x38); - vga_out8(0x3d5, 0x48); + vga_out8(0x3d4, 0x38, par); + vga_out8(0x3d5, 0x48, par); /* Unlock system registers. */ - vga_out16(0x3d4, 0x4838); + vga_out16(0x3d4, 0x4838, par); /* Next go on to detect amount of installed ram */ - vga_out8(0x3d4, 0x36); /* for register CR36 (CONFG_REG1), */ - config1 = vga_in8(0x3d5); /* get amount of vram installed */ + vga_out8(0x3d4, 0x36, par); /* for register CR36 (CONFG_REG1), */ + config1 = vga_in8(0x3d5, par); /* get amount of vram installed */ /* Compute the amount of video memory and offscreen memory. */ @@ -1680,8 +1683,8 @@ static int __devinit savage_init_hw (struct savagefb_par *par) * when it really means 8MB. Why do it the same when you * can do it different... */ - vga_out8(0x3d4, 0x68); /* memory control 1 */ - if( (vga_in8(0x3d5) & 0xC0) == (0x01 << 6) ) + vga_out8(0x3d4, 0x68, par); /* memory control 1 */ + if( (vga_in8(0x3d5, par) & 0xC0) == (0x01 << 6) ) RamSavage4[1] = 8; /*FALLTHROUGH*/ @@ -1710,13 +1713,13 @@ static int __devinit savage_init_hw (struct savagefb_par *par) printk (KERN_INFO "savagefb: probed videoram: %dk\n", videoRam); /* reset graphics engine to avoid memory corruption */ - vga_out8 (0x3d4, 0x66); - cr66 = vga_in8 (0x3d5); - vga_out8 (0x3d5, cr66 | 0x02); + vga_out8 (0x3d4, 0x66, par); + cr66 = vga_in8 (0x3d5, par); + vga_out8 (0x3d5, cr66 | 0x02, par); udelay (10000); - vga_out8 (0x3d4, 0x66); - vga_out8 (0x3d5, cr66 & ~0x02); /* clear reset flag */ + vga_out8 (0x3d4, 0x66, par); + vga_out8 (0x3d5, cr66 & ~0x02, par); /* clear reset flag */ udelay (10000); @@ -1724,13 +1727,13 @@ static int __devinit savage_init_hw (struct savagefb_par *par) * reset memory interface, 3D engine, AGP master, PCI master, * master engine unit, motion compensation/LPB */ - vga_out8 (0x3d4, 0x3f); - cr3f = vga_in8 (0x3d5); - vga_out8 (0x3d5, cr3f | 0x08); + vga_out8 (0x3d4, 0x3f, par); + cr3f = vga_in8 (0x3d5, par); + vga_out8 (0x3d5, cr3f | 0x08, par); udelay (10000); - vga_out8 (0x3d4, 0x3f); - vga_out8 (0x3d5, cr3f & ~0x08); /* clear reset flags */ + vga_out8 (0x3d4, 0x3f, par); + vga_out8 (0x3d5, cr3f & ~0x08, par); /* clear reset flags */ udelay (10000); /* Savage ramdac speeds */ @@ -1741,15 +1744,15 @@ static int __devinit savage_init_hw (struct savagefb_par *par) par->clock[3] = 220000; /* detect current mclk */ - vga_out8(0x3c4, 0x08); - sr8 = vga_in8(0x3c5); - vga_out8(0x3c5, 0x06); - vga_out8(0x3c4, 0x10); - n = vga_in8(0x3c5); - vga_out8(0x3c4, 0x11); - m = vga_in8(0x3c5); - vga_out8(0x3c4, 0x08); - vga_out8(0x3c5, sr8); + vga_out8(0x3c4, 0x08, par); + sr8 = vga_in8(0x3c5, par); + vga_out8(0x3c5, 0x06, par); + vga_out8(0x3c4, 0x10, par); + n = vga_in8(0x3c5, par); + vga_out8(0x3c4, 0x11, par); + m = vga_in8(0x3c5, par); + vga_out8(0x3c4, 0x08, par); + vga_out8(0x3c5, sr8, par); m &= 0x7f; n1 = n & 0x1f; n2 = (n >> 5) & 0x03; @@ -1763,10 +1766,10 @@ static int __devinit savage_init_hw (struct savagefb_par *par) if (par->chip == S3_SAVAGE4) { unsigned char sr30 = 0x00; - vga_out8(0x3c4, 0x30); + vga_out8(0x3c4, 0x30, par); /* clear bit 1 */ - vga_out8(0x3c5, vga_in8(0x3c5) & ~0x02); - sr30 = vga_in8(0x3c5); + vga_out8(0x3c5, vga_in8(0x3c5, par) & ~0x02, par); + sr30 = vga_in8(0x3c5, par); if (sr30 & 0x02 /*0x04 */) { dvi = 1; printk("savagefb: Digital Flat Panel Detected\n"); @@ -1783,12 +1786,12 @@ static int __devinit savage_init_hw (struct savagefb_par *par) /* Check LCD panel parrmation */ if (par->display_type == DISP_LCD) { - unsigned char cr6b = VGArCR( 0x6b ); + unsigned char cr6b = VGArCR( 0x6b, par); - int panelX = (VGArSEQ (0x61) + - ((VGArSEQ (0x66) & 0x02) << 7) + 1) * 8; - int panelY = (VGArSEQ (0x69) + - ((VGArSEQ (0x6e) & 0x70) << 4) + 1); + int panelX = (VGArSEQ (0x61, par) + + ((VGArSEQ (0x66, par) & 0x02) << 7) + 1) * 8; + int panelY = (VGArSEQ (0x69, par) + + ((VGArSEQ (0x6e, par) & 0x70) << 4) + 1); char * sTechnology = "Unknown"; @@ -1810,9 +1813,9 @@ static int __devinit savage_init_hw (struct savagefb_par *par) ActiveDUO = 0x80 }; - if ((VGArSEQ (0x39) & 0x03) == 0) { + if ((VGArSEQ (0x39, par) & 0x03) == 0) { sTechnology = "TFT"; - } else if ((VGArSEQ (0x30) & 0x01) == 0) { + } else if ((VGArSEQ (0x30, par) & 0x01) == 0) { sTechnology = "DSTN"; } else { sTechnology = "STN"; @@ -2049,24 +2052,11 @@ static int __devinit savagefb_probe (struct pci_dev* dev, info->monspecs.modedb, info->monspecs.modedb_len, NULL, 8); } else if (info->monspecs.modedb != NULL) { - struct fb_monspecs *specs = &info->monspecs; - struct fb_videomode modedb; + struct fb_videomode *modedb; - if (info->monspecs.misc & FB_MISC_1ST_DETAIL) { - int i; - - for (i = 0; i < specs->modedb_len; i++) { - if (specs->modedb[i].flag & FB_MODE_IS_FIRST) { - modedb = specs->modedb[i]; - break; - } - } - } else { - /* otherwise, get first mode in database */ - modedb = specs->modedb[0]; - } - - savage_update_var(&info->var, &modedb); + modedb = fb_find_best_display(&info->monspecs, + &info->modelist); + savage_update_var(&info->var, modedb); } /* maximize virtual vertical length */ diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c index 5ce81f44c7692f3d05421930cedc1b43e6a838b9..2e8769dd345a8ec0cedf06b3e7a0c1a857c3a19a 100644 --- a/drivers/video/sgivwfb.c +++ b/drivers/video/sgivwfb.c @@ -126,7 +126,6 @@ static struct fb_ops sgivwfb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, .fb_mmap = sgivwfb_mmap, }; diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index 42c54b69726e8b769ada57f5c90ac7eedd5bf093..dea1a46c67c4fe232e24874fd08f15f46e7702b3 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -2002,7 +2002,9 @@ static struct fb_ops sisfb_ops = { .fb_fillrect = fbcon_sis_fillrect, .fb_copyarea = fbcon_sis_copyarea, .fb_imageblit = cfb_imageblit, +#ifdef CONFIG_FB_SOFT_CURSOR .fb_cursor = soft_cursor, +#endif .fb_sync = fbcon_sis_sync, #ifdef SIS_NEW_CONFIG_COMPAT .fb_compat_ioctl= sisfb_compat_ioctl, diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c index 7b43716ab66565c7d858f6ee2da92fa8318b3f3b..a01e7ecc15ed01daf66d0bcbad8a0834f85688bd 100644 --- a/drivers/video/skeletonfb.c +++ b/drivers/video/skeletonfb.c @@ -457,11 +457,8 @@ void xxxfb_imageblit(struct fb_info *p, const struct fb_image *image) } /** - * xxxfb_cursor - REQUIRED function. If your hardware lacks support - * for a cursor you can use the default cursor whose - * function is called soft_cursor. It will always - * work since it uses xxxfb_imageblit function which - * is required. + * xxxfb_cursor - OPTIONAL. If your hardware lacks support + * for a cursor, leave this field NULL. * * @info: frame buffer structure that represents a single frame buffer * @cursor: structure defining the cursor to draw. @@ -663,7 +660,7 @@ static struct fb_ops xxxfb_ops = { .fb_fillrect = xxxfb_fillrect, /* Needed !!! */ .fb_copyarea = xxxfb_copyarea, /* Needed !!! */ .fb_imageblit = xxxfb_imageblit, /* Needed !!! */ - .fb_cursor = xxxfb_cursor, /* Needed !!! */ + .fb_cursor = xxxfb_cursor, /* Optional !!! */ .fb_rotate = xxxfb_rotate, .fb_poll = xxxfb_poll, .fb_sync = xxxfb_sync, diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c index 663d53657fa4cf7bbdf50cbe769460ac0c432795..e0f14df840d927129bf4865248c1d066b5ebc6d6 100644 --- a/drivers/video/sstfb.c +++ b/drivers/video/sstfb.c @@ -1382,7 +1382,6 @@ static struct fb_ops sstfb_ops = { .fb_fillrect = cfb_fillrect, /* sstfb_fillrect */ .fb_copyarea = cfb_copyarea, /* sstfb_copyarea */ .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, .fb_ioctl = sstfb_ioctl, }; diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c index 9e52794768e6110f21c701d3eaf9b7d95e478250..fbb17332afd7118de3ef96fc07353db72e9c1769 100644 --- a/drivers/video/stifb.c +++ b/drivers/video/stifb.c @@ -1147,7 +1147,6 @@ static struct fb_ops stifb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c index 1986a8b3833cee1c6cef12a036263abdff7fc640..59fff29bc02e528c8c4d1c845d340da1de88ee35 100644 --- a/drivers/video/tcx.c +++ b/drivers/video/tcx.c @@ -52,7 +52,6 @@ static struct fb_ops tcx_ops = { .fb_imageblit = cfb_imageblit, .fb_mmap = tcx_mmap, .fb_ioctl = tcx_ioctl, - .fb_cursor = soft_cursor, }; /* THC definitions */ diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 7044226c5d4c929e394bfcec1e9a85d61304deab..9d53387e6a666119337353c3efeb2e42a77f60fd 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -184,7 +184,6 @@ static struct fb_ops tdfxfb_ops = { .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, #endif - .fb_cursor = soft_cursor, }; /* diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c index 9d9d2009ad8caa3af457d263afa5c8717227016a..7398bd48ba6c261c1a18079b1dda976446839570 100644 --- a/drivers/video/tgafb.c +++ b/drivers/video/tgafb.c @@ -63,7 +63,6 @@ static struct fb_ops tgafb_ops = { .fb_fillrect = tgafb_fillrect, .fb_copyarea = tgafb_copyarea, .fb_imageblit = tgafb_imageblit, - .fb_cursor = soft_cursor, }; diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c index 81a6d9f188cf76ea4fb0020f71f6b75fc027c7f8..9ac2d3171187855286c7869e1ea33f5f0c7cebe2 100644 --- a/drivers/video/tridentfb.c +++ b/drivers/video/tridentfb.c @@ -1293,7 +1293,6 @@ static struct fb_ops tridentfb_ops = { .fb_fillrect = tridentfb_fillrect, .fb_copyarea= tridentfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; module_init(tridentfb_init); diff --git a/drivers/video/tx3912fb.c b/drivers/video/tx3912fb.c index 39d9ca71856b12aae581a72832287731e58c75b0..d904da44e1aacf280497bb174f4caccaf7bf4cb8 100644 --- a/drivers/video/tx3912fb.c +++ b/drivers/video/tx3912fb.c @@ -89,7 +89,6 @@ static struct fb_ops tx3912fb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; static int tx3912fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c index 31a2bbc53974e2fd785ade7f0cc8f23f4ebaceb4..ce97ec8eae9756792d150ed33e7391dfe7583c7d 100644 --- a/drivers/video/valkyriefb.c +++ b/drivers/video/valkyriefb.c @@ -135,7 +135,6 @@ static struct fb_ops valkyriefb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; /* Sets the video mode according to info->var */ diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index 3cc23106641db10e1a7787f52c5f9c3ee6d4dcf1..e25eae1a78c1de86e9f1f7f25103c12708c63a38 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c @@ -48,7 +48,7 @@ static struct fb_fix_screeninfo vesafb_fix __initdata = { }; static int inverse = 0; -static int mtrr = 3; /* default to write-combining */ +static int mtrr = 0; /* disable mtrr */ static int vram_remap __initdata = 0; /* Set amount of memory to be used */ static int vram_total __initdata = 0; /* Set total amount of memory */ static int pmi_setpal = 0; /* pmi for palette changes ??? */ @@ -166,45 +166,39 @@ static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green, if (regno >= info->cmap.len) return 1; - switch (info->var.bits_per_pixel) { - case 8: + if (info->var.bits_per_pixel == 8) vesa_setpalette(regno,red,green,blue); - break; - case 16: - if (info->var.red.offset == 10) { - /* 1:5:5:5 */ - ((u32*) (info->pseudo_palette))[regno] = + else if (regno < 16) { + switch (info->var.bits_per_pixel) { + case 16: + if (info->var.red.offset == 10) { + /* 1:5:5:5 */ + ((u32*) (info->pseudo_palette))[regno] = ((red & 0xf800) >> 1) | ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11); - } else { - /* 0:5:6:5 */ - ((u32*) (info->pseudo_palette))[regno] = + } else { + /* 0:5:6:5 */ + ((u32*) (info->pseudo_palette))[regno] = ((red & 0xf800) ) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); + } + break; + case 24: + case 32: + red >>= 8; + green >>= 8; + blue >>= 8; + ((u32 *)(info->pseudo_palette))[regno] = + (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + break; } - break; - case 24: - red >>= 8; - green >>= 8; - blue >>= 8; - ((u32 *)(info->pseudo_palette))[regno] = - (red << info->var.red.offset) | - (green << info->var.green.offset) | - (blue << info->var.blue.offset); - break; - case 32: - red >>= 8; - green >>= 8; - blue >>= 8; - ((u32 *)(info->pseudo_palette))[regno] = - (red << info->var.red.offset) | - (green << info->var.green.offset) | - (blue << info->var.blue.offset); - break; - } - return 0; + } + + return 0; } static struct fb_ops vesafb_ops = { @@ -215,7 +209,6 @@ static struct fb_ops vesafb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; static int __init vesafb_setup(char *options) diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c index 92d46555dd86e2fd02ee7985ef8ba41ca44d1b48..8794dc5d24667527fdd838481bd5f18f4b3482eb 100644 --- a/drivers/video/vfb.c +++ b/drivers/video/vfb.c @@ -92,7 +92,6 @@ static struct fb_ops vfb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, .fb_mmap = vfb_mmap, }; diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c index b46454c55c91b01767753d356c2963e9ca6b080d..690bb6fe82812082d00dc04a410531aa1e7abaef 100644 --- a/drivers/video/vga16fb.c +++ b/drivers/video/vga16fb.c @@ -1326,7 +1326,6 @@ static struct fb_ops vga16fb_ops = { .fb_fillrect = vga16fb_fillrect, .fb_copyarea = vga16fb_copyarea, .fb_imageblit = vga16fb_imageblit, - .fb_cursor = soft_cursor, }; #ifndef MODULE diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c index cf8cdb108fd95c0d1eb2f3be7e947804e6a5abb8..48e70f153c4b23857aea147451418547c431f87f 100644 --- a/drivers/video/w100fb.c +++ b/drivers/video/w100fb.c @@ -397,7 +397,6 @@ static struct fb_ops w100fb_ops = { .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, - .fb_cursor = soft_cursor, }; #ifdef CONFIG_PM diff --git a/drivers/w1/w1_ds2433.c b/drivers/w1/w1_ds2433.c index 279e0e0363d6afb7e7326da42381d6c36c5e37f4..1e3d98aac12dbc788b458a6adbb8e2bf70139889 100644 --- a/drivers/w1/w1_ds2433.c +++ b/drivers/w1/w1_ds2433.c @@ -299,10 +299,8 @@ static int w1_f23_add_slave(struct w1_slave *sl) static void w1_f23_remove_slave(struct w1_slave *sl) { #ifdef CONFIG_W1_F23_CRC - if (sl->family_data) { - kfree(sl->family_data); - sl->family_data = NULL; - } + kfree(sl->family_data); + sl->family_data = NULL; #endif /* CONFIG_W1_F23_CRC */ sysfs_remove_bin_file(&sl->dev.kobj, &w1_f23_bin_attr); } diff --git a/fs/9p/error.c b/fs/9p/error.c index fee5d19179c5f1fb8f15c0b5deaed90f42d85c51..834cb179e3888c963ae651fc34a5bf26f915b41b 100644 --- a/fs/9p/error.c +++ b/fs/9p/error.c @@ -33,6 +33,7 @@ #include #include +#include #include "debug.h" #include "error.h" diff --git a/fs/9p/trans_sock.c b/fs/9p/trans_sock.c index 01e26f0013aced186efe40992d34996999ded2da..a93c2bf94c331a7b20326caa5a36c217fab3f023 100644 --- a/fs/9p/trans_sock.c +++ b/fs/9p/trans_sock.c @@ -269,8 +269,7 @@ static void v9fs_sock_close(struct v9fs_transport *trans) dprintk(DEBUG_TRANS, "socket closed\n"); } - if (ts) - kfree(ts); + kfree(ts); trans->priv = NULL; } diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 82303f3bf76f786f4a939d47c60ba0cd73649a1e..418c3743fdee85c89452f9f6c0dda13dbb404007 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -266,7 +266,7 @@ v9fs_session_init(struct v9fs_session_info *v9ses, v9ses->remotename = __getname(); if (!v9ses->remotename) { - putname(v9ses->name); + __putname(v9ses->name); return -ENOMEM; } @@ -411,8 +411,8 @@ void v9fs_session_close(struct v9fs_session_info *v9ses) if (v9ses->transport) v9ses->transport->close(v9ses->transport); - putname(v9ses->name); - putname(v9ses->remotename); + __putname(v9ses->name); + __putname(v9ses->remotename); } /** diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 2b696ae6655a10306f5111c90f14a5af645c9220..be7288184fa9de0a580f7ec64d86f29fec5d3ce3 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -1105,7 +1105,7 @@ static int v9fs_vfs_readlink(struct dentry *dentry, char __user * buffer, } } - putname(link); + __putname(link); return retval; } @@ -1129,7 +1129,7 @@ static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd) len = v9fs_readlink(dentry, link, strlen(link)); if (len < 0) { - putname(link); + __putname(link); link = ERR_PTR(len); } else link[len] = 0; @@ -1152,7 +1152,7 @@ static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void dprintk(DEBUG_VFS, " %s %s\n", dentry->d_name.name, s); if (!IS_ERR(s)) - putname(s); + __putname(s); } /** @@ -1228,7 +1228,7 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, FreeMem: kfree(mistat); kfree(fcall); - putname(symname); + __putname(symname); return retval; } @@ -1319,7 +1319,7 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) FreeMem: kfree(mistat); kfree(fcall); - putname(symname); + __putname(symname); return retval; } diff --git a/fs/Kconfig b/fs/Kconfig index 01a295232f75dcd53ab1d5a4998e35b92fc47205..7d6ae369ce4404600489c238908087774bb424d1 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -898,6 +898,7 @@ config AFFS_FS config HFS_FS tristate "Apple Macintosh file system support (EXPERIMENTAL)" depends on EXPERIMENTAL + select NLS help If you say Y here, you will be able to mount Macintosh-formatted floppy disks and hard drive partitions with full read-write access. @@ -1050,6 +1051,19 @@ config JFFS2_FS_WRITEBUFFER - NOR flash with transparent ECC - DataFlash +config JFFS2_SUMMARY + bool "JFFS2 summary support (EXPERIMENTAL)" + depends on JFFS2_FS && EXPERIMENTAL + default n + help + This feature makes it possible to use summary information + for faster filesystem mount. + + The summary information can be inserted into a filesystem image + by the utility 'sumtool'. + + If unsure, say 'N'. + config JFFS2_COMPRESSION_OPTIONS bool "Advanced compression options for JFFS2" depends on JFFS2_FS @@ -1071,10 +1085,10 @@ config JFFS2_ZLIB default y help Zlib is designed to be a free, general-purpose, legally unencumbered, - lossless data-compression library for use on virtually any computer + lossless data-compression library for use on virtually any computer hardware and operating system. See for further information. - + Say 'Y' if unsure. config JFFS2_RTIME @@ -1096,7 +1110,7 @@ choice default JFFS2_CMODE_PRIORITY depends on JFFS2_FS help - You can set here the default compression mode of JFFS2 from + You can set here the default compression mode of JFFS2 from the available compression modes. Don't touch if unsure. config JFFS2_CMODE_NONE @@ -1107,13 +1121,13 @@ config JFFS2_CMODE_NONE config JFFS2_CMODE_PRIORITY bool "priority" help - Tries the compressors in a predefinied order and chooses the first + Tries the compressors in a predefinied order and chooses the first successful one. config JFFS2_CMODE_SIZE bool "size (EXPERIMENTAL)" help - Tries all compressors and chooses the one which has the smallest + Tries all compressors and chooses the one which has the smallest result. endchoice diff --git a/fs/Makefile b/fs/Makefile index 1972da186272906d8aa13eab878b547e44ae1398..4c26557590780afaa445a6d236847f65beae88d9 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -10,7 +10,7 @@ obj-y := open.o read_write.o file_table.o buffer.o bio.o super.o \ ioctl.o readdir.o select.o fifo.o locks.o dcache.o inode.o \ attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \ seq_file.o xattr.o libfs.o fs-writeback.o mpage.o direct-io.o \ - ioprio.o + ioprio.o pnode.o obj-$(CONFIG_INOTIFY) += inotify.o obj-$(CONFIG_EPOLL) += eventpoll.o diff --git a/fs/affs/file.c b/fs/affs/file.c index 6744924b690557342faa139b9b41ce399e1c0197..f72fb776ecdf86621f95e7e444c2d0ac54191f67 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -22,14 +22,13 @@ static int affs_grow_extcache(struct inode *inode, u32 lc_idx); static struct buffer_head *affs_alloc_extblock(struct inode *inode, struct buffer_head *bh, u32 ext); static inline struct buffer_head *affs_get_extblock(struct inode *inode, u32 ext); static struct buffer_head *affs_get_extblock_slow(struct inode *inode, u32 ext); -static ssize_t affs_file_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos); static int affs_file_open(struct inode *inode, struct file *filp); static int affs_file_release(struct inode *inode, struct file *filp); struct file_operations affs_file_operations = { .llseek = generic_file_llseek, .read = generic_file_read, - .write = affs_file_write, + .write = generic_file_write, .mmap = generic_file_mmap, .open = affs_file_open, .release = affs_file_release, @@ -473,21 +472,6 @@ affs_getemptyblk_ino(struct inode *inode, int block) return ERR_PTR(err); } -static ssize_t -affs_file_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - ssize_t retval; - - retval = generic_file_write (file, buf, count, ppos); - if (retval >0) { - struct inode *inode = file->f_dentry->d_inode; - inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; - mark_inode_dirty(inode); - } - return retval; -} - static int affs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsigned to) { diff --git a/fs/affs/super.c b/fs/affs/super.c index 9c3080716c924526a481c313e9176e093669068d..aaec015a16e4f48d5ee3c124006ac47f91e4ec33 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -35,8 +35,7 @@ affs_put_super(struct super_block *sb) mark_buffer_dirty(sbi->s_root_bh); } - if (sbi->s_prefix) - kfree(sbi->s_prefix); + kfree(sbi->s_prefix); affs_free_bitmap(sb); affs_brelse(sbi->s_root_bh); kfree(sbi); @@ -198,10 +197,9 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s *mount_opts |= SF_MUFS; break; case Opt_prefix: - if (*prefix) { /* Free any previous prefix */ - kfree(*prefix); - *prefix = NULL; - } + /* Free any previous prefix */ + kfree(*prefix); + *prefix = NULL; *prefix = match_strdup(&args[0]); if (!*prefix) return 0; @@ -462,11 +460,9 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent) out_error: if (root_inode) iput(root_inode); - if (sbi->s_bitmap) - kfree(sbi->s_bitmap); + kfree(sbi->s_bitmap); affs_brelse(root_bh); - if (sbi->s_prefix) - kfree(sbi->s_prefix); + kfree(sbi->s_prefix); kfree(sbi); sb->s_fs_info = NULL; return -EINVAL; diff --git a/fs/afs/file.c b/fs/afs/file.c index 4975c9c193dd37505cbdcfad000fdcd24793676d..150b192279228a3dfee74846a6f8f48d38e933fd 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -31,24 +31,10 @@ static int afs_file_readpage(struct file *file, struct page *page); static int afs_file_invalidatepage(struct page *page, unsigned long offset); static int afs_file_releasepage(struct page *page, gfp_t gfp_flags); -static ssize_t afs_file_write(struct file *file, const char __user *buf, - size_t size, loff_t *off); - struct inode_operations afs_file_inode_operations = { .getattr = afs_inode_getattr, }; -struct file_operations afs_file_file_operations = { - .read = generic_file_read, - .write = afs_file_write, - .mmap = generic_file_mmap, -#if 0 - .open = afs_file_open, - .release = afs_file_release, - .fsync = afs_file_fsync, -#endif -}; - struct address_space_operations afs_fs_aops = { .readpage = afs_file_readpage, .sync_page = block_sync_page, @@ -57,22 +43,6 @@ struct address_space_operations afs_fs_aops = { .invalidatepage = afs_file_invalidatepage, }; -/*****************************************************************************/ -/* - * AFS file write - */ -static ssize_t afs_file_write(struct file *file, const char __user *buf, - size_t size, loff_t *off) -{ - struct afs_vnode *vnode; - - vnode = AFS_FS_I(file->f_dentry->d_inode); - if (vnode->flags & AFS_VNODE_DELETED) - return -ESTALE; - - return -EIO; -} /* end afs_file_write() */ - /*****************************************************************************/ /* * deal with notification that a page was read from the cache @@ -295,8 +265,7 @@ static int afs_file_releasepage(struct page *page, gfp_t gfp_flags) set_page_private(page, 0); ClearPagePrivate(page); - if (pageio) - kfree(pageio); + kfree(pageio); } _leave(" = 0"); diff --git a/fs/afs/inode.c b/fs/afs/inode.c index c476fde33fbc24ab64ed26137424e8eb7b7d776a..4ebb30a50ed5a876d28c7830e0083c10a1aa26f9 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -49,7 +49,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode) case AFS_FTYPE_FILE: inode->i_mode = S_IFREG | vnode->status.mode; inode->i_op = &afs_file_inode_operations; - inode->i_fop = &afs_file_file_operations; + inode->i_fop = &generic_ro_fops; break; case AFS_FTYPE_DIR: inode->i_mode = S_IFDIR | vnode->status.mode; diff --git a/fs/afs/internal.h b/fs/afs/internal.h index f09860b45c1a303e9f0702bf2ab9636f6a26689d..ab8f87c66319bc4233444e8bcd7c3f17163e5d88 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -71,7 +71,6 @@ extern struct file_operations afs_dir_file_operations; */ extern struct address_space_operations afs_fs_aops; extern struct inode_operations afs_file_inode_operations; -extern struct file_operations afs_file_file_operations; #ifdef AFS_CACHING_SUPPORT extern int afs_cache_get_page_cookie(struct page *page, diff --git a/fs/aio.c b/fs/aio.c index edfca5b7553581c65cddc50ac14e18f84ec2826c..20bb919eb1958e6e4dbbf96f6f04812a23983a24 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -42,8 +42,9 @@ #endif /*------ sysctl variables----*/ -atomic_t aio_nr = ATOMIC_INIT(0); /* current system wide number of aio requests */ -unsigned aio_max_nr = 0x10000; /* system wide maximum number of aio requests */ +static DEFINE_SPINLOCK(aio_nr_lock); +unsigned long aio_nr; /* current system wide number of aio requests */ +unsigned long aio_max_nr = 0x10000; /* system wide maximum number of aio requests */ /*----end sysctl variables---*/ static kmem_cache_t *kiocb_cachep; @@ -208,7 +209,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) return ERR_PTR(-EINVAL); } - if (nr_events > aio_max_nr) + if ((unsigned long)nr_events > aio_max_nr) return ERR_PTR(-EAGAIN); ctx = kmem_cache_alloc(kioctx_cachep, GFP_KERNEL); @@ -233,8 +234,14 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) goto out_freectx; /* limit the number of system wide aios */ - atomic_add(ctx->max_reqs, &aio_nr); /* undone by __put_ioctx */ - if (unlikely(atomic_read(&aio_nr) > aio_max_nr)) + spin_lock(&aio_nr_lock); + if (aio_nr + ctx->max_reqs > aio_max_nr || + aio_nr + ctx->max_reqs < aio_nr) + ctx->max_reqs = 0; + else + aio_nr += ctx->max_reqs; + spin_unlock(&aio_nr_lock); + if (ctx->max_reqs == 0) goto out_cleanup; /* now link into global list. kludge. FIXME */ @@ -248,8 +255,6 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) return ctx; out_cleanup: - atomic_sub(ctx->max_reqs, &aio_nr); - ctx->max_reqs = 0; /* prevent __put_ioctx from sub'ing aio_nr */ __put_ioctx(ctx); return ERR_PTR(-EAGAIN); @@ -374,7 +379,12 @@ void fastcall __put_ioctx(struct kioctx *ctx) pr_debug("__put_ioctx: freeing %p\n", ctx); kmem_cache_free(kioctx_cachep, ctx); - atomic_sub(nr_events, &aio_nr); + if (nr_events) { + spin_lock(&aio_nr_lock); + BUG_ON(aio_nr - nr_events > aio_nr); + aio_nr -= nr_events; + spin_unlock(&aio_nr_lock); + } } /* aio_get_req @@ -1258,8 +1268,9 @@ asmlinkage long sys_io_setup(unsigned nr_events, aio_context_t __user *ctxp) goto out; ret = -EINVAL; - if (unlikely(ctx || (int)nr_events <= 0)) { - pr_debug("EINVAL: io_setup: ctx or nr_events > max\n"); + if (unlikely(ctx || nr_events == 0)) { + pr_debug("EINVAL: io_setup: ctx %lu nr_events %u\n", + ctx, nr_events); goto out; } diff --git a/fs/autofs/waitq.c b/fs/autofs/waitq.c index 1fcaa1568541c79060996da33a52cd6f6b58d189..633f628005b4a773b3e9326263b6892cdbce6b92 100644 --- a/fs/autofs/waitq.c +++ b/fs/autofs/waitq.c @@ -150,10 +150,8 @@ int autofs_wait(struct autofs_sb_info *sbi, struct qstr *name) if ( sbi->catatonic ) { /* We might have slept, so check again for catatonic mode */ wq->status = -ENOENT; - if ( wq->name ) { - kfree(wq->name); - wq->name = NULL; - } + kfree(wq->name); + wq->name = NULL; } if ( wq->name ) { diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index 0a3c05d101679ea0dd24d2794a9a66f64ab5ba10..818b37be5153f3d7508ac00c215c2f523f01999f 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c @@ -22,10 +22,8 @@ static void ino_lnkfree(struct autofs_info *ino) { - if (ino->u.symlink) { - kfree(ino->u.symlink); - ino->u.symlink = NULL; - } + kfree(ino->u.symlink); + ino->u.symlink = NULL; } struct autofs_info *autofs4_init_ino(struct autofs_info *ino, diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 3df86285a1c7e981e054d145fb134b89673336ab..394ff36ef8f19ec84a4f26a0c1a96e2badb7cb84 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c @@ -243,10 +243,8 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, if ( sbi->catatonic ) { /* We might have slept, so check again for catatonic mode */ wq->status = -ENOENT; - if ( wq->name ) { - kfree(wq->name); - wq->name = NULL; - } + kfree(wq->name); + wq->name = NULL; } if ( wq->name ) { diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index e0a6025f1d06a72a6423984ab838739ed0bf2bf6..2d365cb8eec60948e631cf7b2d0ea33e45b94219 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -73,12 +73,6 @@ static struct inode_operations befs_dir_inode_operations = { .lookup = befs_lookup, }; -static struct file_operations befs_file_operations = { - .llseek = default_llseek, - .read = generic_file_read, - .mmap = generic_file_readonly_mmap, -}; - static struct address_space_operations befs_aops = { .readpage = befs_readpage, .sync_page = block_sync_page, @@ -398,7 +392,7 @@ befs_read_inode(struct inode *inode) inode->i_mapping->a_ops = &befs_aops; if (S_ISREG(inode->i_mode)) { - inode->i_fop = &befs_file_operations; + inode->i_fop = &generic_ro_fops; } else if (S_ISDIR(inode->i_mode)) { inode->i_op = &befs_dir_inode_operations; inode->i_fop = &befs_dir_operations; @@ -731,20 +725,16 @@ parse_options(char *options, befs_mount_options * opts) static void befs_put_super(struct super_block *sb) { - if (BEFS_SB(sb)->mount_opts.iocharset) { - kfree(BEFS_SB(sb)->mount_opts.iocharset); - BEFS_SB(sb)->mount_opts.iocharset = NULL; - } + kfree(BEFS_SB(sb)->mount_opts.iocharset); + BEFS_SB(sb)->mount_opts.iocharset = NULL; if (BEFS_SB(sb)->nls) { unload_nls(BEFS_SB(sb)->nls); BEFS_SB(sb)->nls = NULL; } - if (sb->s_fs_info) { - kfree(sb->s_fs_info); - sb->s_fs_info = NULL; - } + kfree(sb->s_fs_info); + sb->s_fs_info = NULL; return; } diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 6fa6adc409726e8b79038bbdac31e510e248fed7..f36f2210204f524b2922fa69ea704295bfbe5a59 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1006,8 +1006,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) if (interpreter) fput(interpreter); out_free_interp: - if (elf_interpreter) - kfree(elf_interpreter); + kfree(elf_interpreter); out_free_file: sys_close(elf_exec_fileno); out_free_fh: diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index dda87c4c82a3c98c08109d577d98d24c70a2d5a9..e0344f69c79d971ce4fb95992ca4d3e13f32fbe5 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -411,16 +411,11 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm, struct pt_regs *regs allow_write_access(interpreter); fput(interpreter); } - if (interpreter_name) - kfree(interpreter_name); - if (exec_params.phdrs) - kfree(exec_params.phdrs); - if (exec_params.loadmap) - kfree(exec_params.loadmap); - if (interp_params.phdrs) - kfree(interp_params.phdrs); - if (interp_params.loadmap) - kfree(interp_params.loadmap); + kfree(interpreter_name); + kfree(exec_params.phdrs); + kfree(exec_params.loadmap); + kfree(interp_params.phdrs); + kfree(interp_params.loadmap); return retval; /* unrecoverable error - kill the process */ diff --git a/fs/buffer.c b/fs/buffer.c index 35fa34977e81f5477b492bc6d7694de8d2c4065a..5287be18633bc7c2b6621fc20c2f5ce97fa8e561 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -396,7 +396,7 @@ asmlinkage long sys_fdatasync(unsigned int fd) * private_lock is contended then so is mapping->tree_lock). */ static struct buffer_head * -__find_get_block_slow(struct block_device *bdev, sector_t block, int unused) +__find_get_block_slow(struct block_device *bdev, sector_t block) { struct inode *bd_inode = bdev->bd_inode; struct address_space *bd_mapping = bd_inode->i_mapping; @@ -1438,7 +1438,7 @@ __find_get_block(struct block_device *bdev, sector_t block, int size) struct buffer_head *bh = lookup_bh_lru(bdev, block, size); if (bh == NULL) { - bh = __find_get_block_slow(bdev, block, size); + bh = __find_get_block_slow(bdev, block); if (bh) bh_lru_install(bh); } @@ -1705,7 +1705,7 @@ void unmap_underlying_metadata(struct block_device *bdev, sector_t block) might_sleep(); - old_bh = __find_get_block_slow(bdev, block, 0); + old_bh = __find_get_block_slow(bdev, block); if (old_bh) { clear_buffer_dirty(old_bh); wait_on_buffer(old_bh); diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index 98539e2afe81e92494ad27c4c49789126847df8e..086ae8f4a207a22f0d1bfe2863439ed20bd88f89 100644 --- a/fs/cifs/asn1.c +++ b/fs/cifs/asn1.c @@ -553,8 +553,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, *(oid + 3))); rc = compare_oid(oid, oidlen, NTLMSSP_OID, NTLMSSP_OID_LEN); - if(oid) - kfree(oid); + kfree(oid); if (rc) use_ntlmssp = TRUE; } diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index d74367a08d513dd4cf6bb6a3aa090996972ea7f5..450ab75d654623d492c6969fc312bd041083fa2a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1265,8 +1265,7 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, the helper that resolves tcp names, mount to it, try to tcon to it unmount it if fail */ - if(referrals) - kfree(referrals); + kfree(referrals); return rc; } @@ -1535,10 +1534,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, memset(&volume_info,0,sizeof(struct smb_vol)); if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { - if(volume_info.UNC) - kfree(volume_info.UNC); - if(volume_info.password) - kfree(volume_info.password); + kfree(volume_info.UNC); + kfree(volume_info.password); FreeXid(xid); return -EINVAL; } @@ -1551,10 +1548,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, cifserror("No username specified "); /* In userspace mount helper we can get user name from alternate locations such as env variables and files on disk */ - if(volume_info.UNC) - kfree(volume_info.UNC); - if(volume_info.password) - kfree(volume_info.password); + kfree(volume_info.UNC); + kfree(volume_info.password); FreeXid(xid); return -EINVAL; } @@ -1573,10 +1568,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, if(rc <= 0) { /* we failed translating address */ - if(volume_info.UNC) - kfree(volume_info.UNC); - if(volume_info.password) - kfree(volume_info.password); + kfree(volume_info.UNC); + kfree(volume_info.password); FreeXid(xid); return -EINVAL; } @@ -1587,19 +1580,15 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, } else if (volume_info.UNCip){ /* BB using ip addr as server name connect to the DFS root below */ cERROR(1,("Connecting to DFS root not implemented yet")); - if(volume_info.UNC) - kfree(volume_info.UNC); - if(volume_info.password) - kfree(volume_info.password); + kfree(volume_info.UNC); + kfree(volume_info.password); FreeXid(xid); return -EINVAL; } else /* which servers DFS root would we conect to */ { cERROR(1, ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified ")); - if(volume_info.UNC) - kfree(volume_info.UNC); - if(volume_info.password) - kfree(volume_info.password); + kfree(volume_info.UNC); + kfree(volume_info.password); FreeXid(xid); return -EINVAL; } @@ -1612,10 +1601,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, cifs_sb->local_nls = load_nls(volume_info.iocharset); if(cifs_sb->local_nls == NULL) { cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset)); - if(volume_info.UNC) - kfree(volume_info.UNC); - if(volume_info.password) - kfree(volume_info.password); + kfree(volume_info.UNC); + kfree(volume_info.password); FreeXid(xid); return -ELIBACC; } @@ -1630,10 +1617,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, &sin_server6.sin6_addr, volume_info.username, &srvTcp); else { - if(volume_info.UNC) - kfree(volume_info.UNC); - if(volume_info.password) - kfree(volume_info.password); + kfree(volume_info.UNC); + kfree(volume_info.password); FreeXid(xid); return -EINVAL; } @@ -1654,10 +1639,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ("Error connecting to IPv4 socket. Aborting operation")); if(csocket != NULL) sock_release(csocket); - if(volume_info.UNC) - kfree(volume_info.UNC); - if(volume_info.password) - kfree(volume_info.password); + kfree(volume_info.UNC); + kfree(volume_info.password); FreeXid(xid); return rc; } @@ -1666,10 +1649,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, if (srvTcp == NULL) { rc = -ENOMEM; sock_release(csocket); - if(volume_info.UNC) - kfree(volume_info.UNC); - if(volume_info.password) - kfree(volume_info.password); + kfree(volume_info.UNC); + kfree(volume_info.password); FreeXid(xid); return rc; } else { @@ -1692,10 +1673,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, if(rc < 0) { rc = -ENOMEM; sock_release(csocket); - if(volume_info.UNC) - kfree(volume_info.UNC); - if(volume_info.password) - kfree(volume_info.password); + kfree(volume_info.UNC); + kfree(volume_info.password); FreeXid(xid); return rc; } @@ -1710,8 +1689,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, if (existingCifsSes) { pSesInfo = existingCifsSes; cFYI(1, ("Existing smb sess found ")); - if(volume_info.password) - kfree(volume_info.password); + kfree(volume_info.password); /* volume_info.UNC freed at end of function */ } else if (!rc) { cFYI(1, ("Existing smb sess not found ")); @@ -1741,8 +1719,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, if(!rc) atomic_inc(&srvTcp->socketUseCount); } else - if(volume_info.password) - kfree(volume_info.password); + kfree(volume_info.password); } /* search for existing tcon to this server share */ @@ -1821,8 +1798,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, "", cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); - if(volume_info.UNC) - kfree(volume_info.UNC); + kfree(volume_info.UNC); FreeXid(xid); return -ENODEV; } else { @@ -1925,8 +1901,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, (in which case it is not needed anymore) but when new sesion is created the password ptr is put in the new session structure (in which case the password will be freed at unmount time) */ - if(volume_info.UNC) - kfree(volume_info.UNC); + kfree(volume_info.UNC); FreeXid(xid); return rc; } @@ -3283,8 +3258,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, if ((bcc_ptr + (2 * length)) - pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { - if(tcon->nativeFileSystem) - kfree(tcon->nativeFileSystem); + kfree(tcon->nativeFileSystem); tcon->nativeFileSystem = kzalloc(length + 2, GFP_KERNEL); cifs_strfromUCS_le(tcon->nativeFileSystem, @@ -3301,8 +3275,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, if ((bcc_ptr + length) - pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { - if(tcon->nativeFileSystem) - kfree(tcon->nativeFileSystem); + kfree(tcon->nativeFileSystem); tcon->nativeFileSystem = kzalloc(length + 1, GFP_KERNEL); strncpy(tcon->nativeFileSystem, bcc_ptr, diff --git a/fs/cifs/link.c b/fs/cifs/link.c index b43e071fe1106446fc2e48fc05299a7b8fabce4a..0f99aae33162fbd68f5e08a32713db3055a418cf 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -84,10 +84,8 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode, cifsInode->time = 0; /* will force revalidate to go get info when needed */ cifs_hl_exit: - if (fromName) - kfree(fromName); - if (toName) - kfree(toName); + kfree(fromName); + kfree(toName); FreeXid(xid); return rc; } @@ -206,8 +204,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) } } - if (full_path) - kfree(full_path); + kfree(full_path); FreeXid(xid); return rc; } @@ -253,8 +250,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) len = buflen; tmpbuffer = kmalloc(len,GFP_KERNEL); if(tmpbuffer == NULL) { - if (full_path) - kfree(full_path); + kfree(full_path); FreeXid(xid); return -ENOMEM; } @@ -303,8 +299,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) strncpy(tmpbuffer, referrals, len-1); } } - if(referrals) - kfree(referrals); + kfree(referrals); kfree(tmp_path); } /* BB add code like else decode referrals then memcpy to @@ -323,12 +318,8 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) rc)); } - if (tmpbuffer) { - kfree(tmpbuffer); - } - if (full_path) { - kfree(full_path); - } + kfree(tmpbuffer); + kfree(full_path); FreeXid(xid); return rc; } diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index eba1de917f2a87c2d9d5a173978c26f4e10e06b2..34a06692e4fa9461e624e8ace35de0536d4240d9 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -98,14 +98,10 @@ sesInfoFree(struct cifsSesInfo *buf_to_free) atomic_dec(&sesInfoAllocCount); list_del(&buf_to_free->cifsSessionList); write_unlock(&GlobalSMBSeslock); - if (buf_to_free->serverOS) - kfree(buf_to_free->serverOS); - if (buf_to_free->serverDomain) - kfree(buf_to_free->serverDomain); - if (buf_to_free->serverNOS) - kfree(buf_to_free->serverNOS); - if (buf_to_free->password) - kfree(buf_to_free->password); + kfree(buf_to_free->serverOS); + kfree(buf_to_free->serverDomain); + kfree(buf_to_free->serverNOS); + kfree(buf_to_free->password); kfree(buf_to_free); } @@ -144,8 +140,7 @@ tconInfoFree(struct cifsTconInfo *buf_to_free) atomic_dec(&tconInfoAllocCount); list_del(&buf_to_free->cifsConnectionList); write_unlock(&GlobalSMBSeslock); - if (buf_to_free->nativeFileSystem) - kfree(buf_to_free->nativeFileSystem); + kfree(buf_to_free->nativeFileSystem); kfree(buf_to_free); } diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index c1e02eff1d25a222613f48b5312cb055776abc00..f375f87c7dbd3698a07290a9953e219cf49b0513 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -87,8 +87,7 @@ int cifs_removexattr(struct dentry * direntry, const char * ea_name) cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } remove_ea_exit: - if (full_path) - kfree(full_path); + kfree(full_path); FreeXid(xid); #endif return rc; @@ -132,8 +131,7 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name, returns as xattrs */ if(value_size > MAX_EA_VALUE_SIZE) { cFYI(1,("size of EA value too large")); - if(full_path) - kfree(full_path); + kfree(full_path); FreeXid(xid); return -EOPNOTSUPP; } @@ -195,8 +193,7 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name, } set_ea_exit: - if (full_path) - kfree(full_path); + kfree(full_path); FreeXid(xid); #endif return rc; @@ -298,8 +295,7 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name, rc = -EOPNOTSUPP; get_ea_exit: - if (full_path) - kfree(full_path); + kfree(full_path); FreeXid(xid); #endif return rc; @@ -345,8 +341,7 @@ ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size) cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); - if (full_path) - kfree(full_path); + kfree(full_path); FreeXid(xid); #endif return rc; diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 43dbcb0b21ebcc2ec51cfcc1052fc2879b73cbeb..4909754ea84a9873d931280c0af377d3d6abe15e 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -2235,7 +2235,8 @@ static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) if (err) err = -EFAULT; -out: if (karg) kfree(karg); +out: + kfree(karg); return err; } diff --git a/fs/dcache.c b/fs/dcache.c index e90512ed35a4eca72e839434a075d1a4b8886c24..17e4391386818d405ca0203123b9738f8b886cc8 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -644,7 +644,7 @@ void shrink_dcache_parent(struct dentry * parent) * * Prune the dentries that are anonymous * - * parsing d_hash list does not hlist_for_each_rcu() as it + * parsing d_hash list does not hlist_for_each_entry_rcu() as it * done under dcache_lock. * */ @@ -1043,15 +1043,13 @@ struct dentry * __d_lookup(struct dentry * parent, struct qstr * name) struct hlist_head *head = d_hash(parent,hash); struct dentry *found = NULL; struct hlist_node *node; + struct dentry *dentry; rcu_read_lock(); - hlist_for_each_rcu(node, head) { - struct dentry *dentry; + hlist_for_each_entry_rcu(dentry, node, head, d_hash) { struct qstr *qstr; - dentry = hlist_entry(node, struct dentry, d_hash); - if (dentry->d_name.hash != hash) continue; if (dentry->d_parent != parent) @@ -1123,7 +1121,7 @@ int d_validate(struct dentry *dentry, struct dentry *dparent) spin_lock(&dcache_lock); base = d_hash(dparent, dentry->d_name.hash); hlist_for_each(lhp,base) { - /* hlist_for_each_rcu() not required for d_hash list + /* hlist_for_each_entry_rcu() not required for d_hash list * as it is parsed under dcache_lock */ if (dentry == hlist_entry(lhp, struct dentry, d_hash)) { diff --git a/fs/devfs/base.c b/fs/devfs/base.c index 8b679b67e5e0f78e18dbd25015f7990cfa6f1f5a..1274422a5384d26e366a57c56152f8383da90677 100644 --- a/fs/devfs/base.c +++ b/fs/devfs/base.c @@ -2738,10 +2738,8 @@ static int devfsd_close(struct inode *inode, struct file *file) entry = fs_info->devfsd_first_event; fs_info->devfsd_first_event = NULL; fs_info->devfsd_last_event = NULL; - if (fs_info->devfsd_info) { - kfree(fs_info->devfsd_info); - fs_info->devfsd_info = NULL; - } + kfree(fs_info->devfsd_info); + fs_info->devfsd_info = NULL; spin_unlock(&fs_info->devfsd_buffer_lock); fs_info->devfsd_pgrp = 0; fs_info->devfsd_task = NULL; diff --git a/fs/dquot.c b/fs/dquot.c index ea7644227a65d7d393758e136d62ca7797235adb..05b60283c9c2710d65fa96ccfe20d47f1da13f64 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -77,6 +77,7 @@ #include #include #include +#include #include @@ -1320,13 +1321,11 @@ int vfs_quota_off(struct super_block *sb, int type) int cnt; struct quota_info *dqopt = sb_dqopt(sb); struct inode *toputinode[MAXQUOTAS]; - struct vfsmount *toputmnt[MAXQUOTAS]; /* We need to serialize quota_off() for device */ down(&dqopt->dqonoff_sem); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { toputinode[cnt] = NULL; - toputmnt[cnt] = NULL; if (type != -1 && cnt != type) continue; if (!sb_has_quota_enabled(sb, cnt)) @@ -1347,9 +1346,7 @@ int vfs_quota_off(struct super_block *sb, int type) put_quota_format(dqopt->info[cnt].dqi_format); toputinode[cnt] = dqopt->files[cnt]; - toputmnt[cnt] = dqopt->mnt[cnt]; dqopt->files[cnt] = NULL; - dqopt->mnt[cnt] = NULL; dqopt->info[cnt].dqi_flags = 0; dqopt->info[cnt].dqi_igrace = 0; dqopt->info[cnt].dqi_bgrace = 0; @@ -1357,10 +1354,7 @@ int vfs_quota_off(struct super_block *sb, int type) } up(&dqopt->dqonoff_sem); /* Sync the superblock so that buffers with quota data are written to - * disk (and so userspace sees correct data afterwards). - * The reference to vfsmnt we are still holding protects us from - * umount (we don't have it only when quotas are turned on/off for - * journal replay but in that case we are guarded by the fs anyway). */ + * disk (and so userspace sees correct data afterwards). */ if (sb->s_op->sync_fs) sb->s_op->sync_fs(sb, 1); sync_blockdev(sb->s_bdev); @@ -1384,10 +1378,6 @@ int vfs_quota_off(struct super_block *sb, int type) iput(toputinode[cnt]); } up(&dqopt->dqonoff_sem); - /* We don't hold the reference when we turned on quotas - * just for the journal replay... */ - if (toputmnt[cnt]) - mntput(toputmnt[cnt]); } if (sb->s_bdev) invalidate_bdev(sb->s_bdev, 0); @@ -1502,11 +1492,8 @@ int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path) /* Quota file not on the same filesystem? */ if (nd.mnt->mnt_sb != sb) error = -EXDEV; - else { + else error = vfs_quota_on_inode(nd.dentry->d_inode, type, format_id); - if (!error) - sb_dqopt(sb)->mnt[type] = mntget(nd.mnt); - } out_path: path_release(&nd); return error; diff --git a/fs/exec.c b/fs/exec.c index 10d493fea7ce6a9e4de05ff01facdf162bb9dd8b..5a4e3acc2e9fcfc549cf2d0330cb80c919e37c6a 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -589,6 +590,7 @@ static inline int de_thread(struct task_struct *tsk) struct signal_struct *sig = tsk->signal; struct sighand_struct *newsighand, *oldsighand = tsk->sighand; spinlock_t *lock = &oldsighand->siglock; + struct task_struct *leader = NULL; int count; /* @@ -664,7 +666,7 @@ static inline int de_thread(struct task_struct *tsk) * and to assume its PID: */ if (!thread_group_leader(current)) { - struct task_struct *leader = current->group_leader, *parent; + struct task_struct *parent; struct dentry *proc_dentry1, *proc_dentry2; unsigned long exit_state, ptrace; @@ -673,6 +675,7 @@ static inline int de_thread(struct task_struct *tsk) * It should already be zombie at this point, most * of the time. */ + leader = current->group_leader; while (leader->exit_state != EXIT_ZOMBIE) yield(); @@ -732,7 +735,6 @@ static inline int de_thread(struct task_struct *tsk) proc_pid_flush(proc_dentry2); BUG_ON(exit_state != EXIT_ZOMBIE); - release_task(leader); } /* @@ -742,8 +744,11 @@ static inline int de_thread(struct task_struct *tsk) sig->flags = 0; no_thread_group: - BUG_ON(atomic_read(&sig->count) != 1); exit_itimers(sig); + if (leader) + release_task(leader); + + BUG_ON(atomic_read(&sig->count) != 1); if (atomic_read(&oldsighand->count) == 1) { /* @@ -1096,6 +1101,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) fput(bprm->file); bprm->file = NULL; current->did_exec = 1; + proc_exec_connector(current); return retval; } read_lock(&binfmt_lock); @@ -1509,7 +1515,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) goto close_fail; if (!file->f_op->write) goto close_fail; - if (do_truncate(file->f_dentry, 0) != 0) + if (do_truncate(file->f_dentry, 0, file) != 0) goto close_fail; retval = binfmt->core_dump(signr, regs, file); diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c index 213148c36ebef341ae8c460af7cd2d9c095a5d3b..6af2f41302905a8e863912b8153e9d30a82911fd 100644 --- a/fs/ext2/acl.c +++ b/fs/ext2/acl.c @@ -194,8 +194,7 @@ ext2_get_acl(struct inode *inode, int type) acl = NULL; else acl = ERR_PTR(retval); - if (value) - kfree(value); + kfree(value); if (!IS_ERR(acl)) { switch(type) { @@ -262,8 +261,7 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) error = ext2_xattr_set(inode, name_index, "", value, size, 0); - if (value) - kfree(value); + kfree(value); if (!error) { switch(type) { case ACL_TYPE_ACCESS: diff --git a/fs/file_table.c b/fs/file_table.c index 4dc205546547aae35d1cd613ac27146d706e1d09..c3a5e2fd663b772d7eeb997171d6b052b82d680c 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -35,7 +35,7 @@ static DEFINE_SPINLOCK(filp_count_lock); * context and must be fully threaded - use a local spinlock * to protect files_stat.nr_files */ -void filp_ctor(void * objp, struct kmem_cache_s *cachep, unsigned long cflags) +void filp_ctor(void *objp, struct kmem_cache *cachep, unsigned long cflags) { if ((cflags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) { @@ -46,7 +46,7 @@ void filp_ctor(void * objp, struct kmem_cache_s *cachep, unsigned long cflags) } } -void filp_dtor(void * objp, struct kmem_cache_s *cachep, unsigned long dflags) +void filp_dtor(void *objp, struct kmem_cache *cachep, unsigned long dflags) { unsigned long flags; spin_lock_irqsave(&filp_count_lock, flags); diff --git a/fs/freevxfs/vxfs_extern.h b/fs/freevxfs/vxfs_extern.h index d8be917f9797f02065223b9a73e1fcb2e214f3db..927acf70c591c4b9793fc134912a9dc4363d61ea 100644 --- a/fs/freevxfs/vxfs_extern.h +++ b/fs/freevxfs/vxfs_extern.h @@ -38,7 +38,7 @@ */ -struct kmem_cache_s; +struct kmem_cache; struct super_block; struct vxfs_inode_info; struct inode; @@ -51,7 +51,7 @@ extern daddr_t vxfs_bmap1(struct inode *, long); extern int vxfs_read_fshead(struct super_block *); /* vxfs_inode.c */ -extern struct kmem_cache_s *vxfs_inode_cachep; +extern struct kmem_cache *vxfs_inode_cachep; extern void vxfs_dumpi(struct vxfs_inode_info *, ino_t); extern struct inode * vxfs_get_fake_inode(struct super_block *, struct vxfs_inode_info *); diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c index 9672d2facffeeaecc0973923b00ed116a6272134..f544aae9169fb86847a0794006dde0a73910291e 100644 --- a/fs/freevxfs/vxfs_inode.c +++ b/fs/freevxfs/vxfs_inode.c @@ -46,15 +46,6 @@ extern struct address_space_operations vxfs_immed_aops; extern struct inode_operations vxfs_immed_symlink_iops; -static struct file_operations vxfs_file_operations = { - .open = generic_file_open, - .llseek = generic_file_llseek, - .read = generic_file_read, - .mmap = generic_file_mmap, - .sendfile = generic_file_sendfile, -}; - - kmem_cache_t *vxfs_inode_cachep; @@ -318,7 +309,7 @@ vxfs_read_inode(struct inode *ip) aops = &vxfs_aops; if (S_ISREG(ip->i_mode)) { - ip->i_fop = &vxfs_file_operations; + ip->i_fop = &generic_ro_fops; ip->i_mapping->a_ops = aops; } else if (S_ISDIR(ip->i_mode)) { ip->i_op = &vxfs_dir_inode_ops; diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index c27f8d4098be3cd713b2934f6eefdc8d03bb4a68..785c7213a54f513186aa5e403a1a3066f646eb12 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -562,7 +562,7 @@ int write_inode_now(struct inode *inode, int sync) }; if (!mapping_cap_writeback_dirty(inode->i_mapping)) - return 0; + wbc.nr_to_write = 0; might_sleep(); spin_lock(&inode_lock); @@ -606,7 +606,7 @@ EXPORT_SYMBOL(sync_inode); * O_SYNC flag set, to flush dirty writes to disk. * * @what is a bitmask, specifying which part of the inode's data should be - * written and waited upon: + * written and waited upon. * * OSYNC_DATA: i_mapping's dirty data * OSYNC_METADATA: the buffers at i_mapping->private_list @@ -672,8 +672,9 @@ int writeback_acquire(struct backing_dev_info *bdi) /** * writeback_in_progress: determine whether there is writeback in progress - * against a backing device. * @bdi: the device's backing_dev_info structure. + * + * Determine whether there is writeback in progress against a backing device. */ int writeback_in_progress(struct backing_dev_info *bdi) { diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index a6f90a6c754a1b573ecdaf0eb849cbfc8e802be5..8f873e621f4107e9c3d40d00e21bfaabd848ed66 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -184,6 +184,13 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) fuse_putback_request() */ for (i = 1; i < FUSE_MAX_OUTSTANDING; i++) up(&fc->outstanding_sem); + } else if (req->in.h.opcode == FUSE_RELEASE && req->inode == NULL) { + /* Special case for failed iget in CREATE */ + u64 nodeid = req->in.h.nodeid; + __fuse_get_request(req); + fuse_reset_request(req); + fuse_send_forget(fc, req, nodeid, 1); + putback = 0; } if (putback) fuse_putback_request(fc, req); diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 70dba721acabe9992416d66bca1d0becd1411f2f..c045cc70c74931864e01763c3573eeae19c2d1e8 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -13,6 +13,7 @@ #include #include #include +#include static inline unsigned long time_to_jiffies(unsigned long sec, unsigned long nsec) @@ -134,6 +135,101 @@ static void fuse_invalidate_entry(struct dentry *entry) entry->d_time = jiffies - 1; } +static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, + struct nameidata *nd) +{ + int err; + struct inode *inode; + struct fuse_conn *fc = get_fuse_conn(dir); + struct fuse_req *req; + struct fuse_open_in inarg; + struct fuse_open_out outopen; + struct fuse_entry_out outentry; + struct fuse_inode *fi; + struct fuse_file *ff; + struct file *file; + int flags = nd->intent.open.flags - 1; + + err = -ENOSYS; + if (fc->no_create) + goto out; + + err = -ENAMETOOLONG; + if (entry->d_name.len > FUSE_NAME_MAX) + goto out; + + err = -EINTR; + req = fuse_get_request(fc); + if (!req) + goto out; + + ff = fuse_file_alloc(); + if (!ff) + goto out_put_request; + + flags &= ~O_NOCTTY; + memset(&inarg, 0, sizeof(inarg)); + inarg.flags = flags; + inarg.mode = mode; + req->in.h.opcode = FUSE_CREATE; + req->in.h.nodeid = get_node_id(dir); + req->inode = dir; + req->in.numargs = 2; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->in.args[1].size = entry->d_name.len + 1; + req->in.args[1].value = entry->d_name.name; + req->out.numargs = 2; + req->out.args[0].size = sizeof(outentry); + req->out.args[0].value = &outentry; + req->out.args[1].size = sizeof(outopen); + req->out.args[1].value = &outopen; + request_send(fc, req); + err = req->out.h.error; + if (err) { + if (err == -ENOSYS) + fc->no_create = 1; + goto out_free_ff; + } + + err = -EIO; + if (!S_ISREG(outentry.attr.mode)) + goto out_free_ff; + + inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, + &outentry.attr); + err = -ENOMEM; + if (!inode) { + flags &= ~(O_CREAT | O_EXCL | O_TRUNC); + ff->fh = outopen.fh; + fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0); + goto out_put_request; + } + fuse_put_request(fc, req); + entry->d_time = time_to_jiffies(outentry.entry_valid, + outentry.entry_valid_nsec); + fi = get_fuse_inode(inode); + fi->i_time = time_to_jiffies(outentry.attr_valid, + outentry.attr_valid_nsec); + + d_instantiate(entry, inode); + file = lookup_instantiate_filp(nd, entry, generic_file_open); + if (IS_ERR(file)) { + ff->fh = outopen.fh; + fuse_send_release(fc, ff, outentry.nodeid, inode, flags, 0); + return PTR_ERR(file); + } + fuse_finish_open(inode, file, ff, &outopen); + return 0; + + out_free_ff: + fuse_file_free(ff); + out_put_request: + fuse_put_request(fc, req); + out: + return err; +} + static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, struct inode *dir, struct dentry *entry, int mode) @@ -208,6 +304,12 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, static int fuse_create(struct inode *dir, struct dentry *entry, int mode, struct nameidata *nd) { + if (nd && (nd->flags & LOOKUP_CREATE)) { + int err = fuse_create_open(dir, entry, mode, nd); + if (err != -ENOSYS) + return err; + /* Fall back on mknod */ + } return fuse_mknod(dir, entry, mode, 0); } @@ -461,6 +563,38 @@ static int fuse_revalidate(struct dentry *entry) return fuse_do_getattr(inode); } +static int fuse_access(struct inode *inode, int mask) +{ + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_req *req; + struct fuse_access_in inarg; + int err; + + if (fc->no_access) + return 0; + + req = fuse_get_request(fc); + if (!req) + return -EINTR; + + memset(&inarg, 0, sizeof(inarg)); + inarg.mask = mask; + req->in.h.opcode = FUSE_ACCESS; + req->in.h.nodeid = get_node_id(inode); + req->inode = inode; + req->in.numargs = 1; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + request_send(fc, req); + err = req->out.h.error; + fuse_put_request(fc, req); + if (err == -ENOSYS) { + fc->no_access = 1; + err = 0; + } + return err; +} + static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) { struct fuse_conn *fc = get_fuse_conn(inode); @@ -491,11 +625,11 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) return err; } else { int mode = inode->i_mode; - if ((mask & MAY_WRITE) && IS_RDONLY(inode) && - (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) - return -EROFS; if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO)) return -EACCES; + + if (nd && (nd->flags & LOOKUP_ACCESS)) + return fuse_access(inode, mask); return 0; } } @@ -629,29 +763,29 @@ static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync) return file ? fuse_fsync_common(file, de, datasync, 1) : 0; } -static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr) +static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg) { unsigned ivalid = iattr->ia_valid; - unsigned fvalid = 0; - - memset(fattr, 0, sizeof(*fattr)); if (ivalid & ATTR_MODE) - fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode; + arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode; if (ivalid & ATTR_UID) - fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid; + arg->valid |= FATTR_UID, arg->uid = iattr->ia_uid; if (ivalid & ATTR_GID) - fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid; + arg->valid |= FATTR_GID, arg->gid = iattr->ia_gid; if (ivalid & ATTR_SIZE) - fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size; + arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size; /* You can only _set_ these together (they may change by themselves) */ if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) { - fvalid |= FATTR_ATIME | FATTR_MTIME; - fattr->atime = iattr->ia_atime.tv_sec; - fattr->mtime = iattr->ia_mtime.tv_sec; + arg->valid |= FATTR_ATIME | FATTR_MTIME; + arg->atime = iattr->ia_atime.tv_sec; + arg->mtime = iattr->ia_mtime.tv_sec; + } + if (ivalid & ATTR_FILE) { + struct fuse_file *ff = iattr->ia_file->private_data; + arg->valid |= FATTR_FH; + arg->fh = ff->fh; } - - return fvalid; } static int fuse_setattr(struct dentry *entry, struct iattr *attr) @@ -686,7 +820,7 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr) return -EINTR; memset(&inarg, 0, sizeof(inarg)); - inarg.valid = iattr_to_fattr(attr, &inarg.attr); + iattr_to_fattr(attr, &inarg); req->in.h.opcode = FUSE_SETATTR; req->in.h.nodeid = get_node_id(inode); req->inode = inode; @@ -735,7 +869,9 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd) { struct inode *inode; - int err = fuse_lookup_iget(dir, entry, &inode); + int err; + + err = fuse_lookup_iget(dir, entry, &inode); if (err) return ERR_PTR(err); if (inode && S_ISDIR(inode->i_mode)) { diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 657ab11c173b38a05678f49c05accc7313b02ede..2ca86141d13ab35f2fd4078ad682f4163ecf058c 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -14,11 +14,69 @@ static struct file_operations fuse_direct_io_file_operations; -int fuse_open_common(struct inode *inode, struct file *file, int isdir) +static int fuse_send_open(struct inode *inode, struct file *file, int isdir, + struct fuse_open_out *outargp) { struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_req *req; struct fuse_open_in inarg; + struct fuse_req *req; + int err; + + req = fuse_get_request(fc); + if (!req) + return -EINTR; + + memset(&inarg, 0, sizeof(inarg)); + inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); + req->in.h.opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN; + req->in.h.nodeid = get_node_id(inode); + req->inode = inode; + req->in.numargs = 1; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->out.numargs = 1; + req->out.args[0].size = sizeof(*outargp); + req->out.args[0].value = outargp; + request_send(fc, req); + err = req->out.h.error; + fuse_put_request(fc, req); + + return err; +} + +struct fuse_file *fuse_file_alloc(void) +{ + struct fuse_file *ff; + ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL); + if (ff) { + ff->release_req = fuse_request_alloc(); + if (!ff->release_req) { + kfree(ff); + ff = NULL; + } + } + return ff; +} + +void fuse_file_free(struct fuse_file *ff) +{ + fuse_request_free(ff->release_req); + kfree(ff); +} + +void fuse_finish_open(struct inode *inode, struct file *file, + struct fuse_file *ff, struct fuse_open_out *outarg) +{ + if (outarg->open_flags & FOPEN_DIRECT_IO) + file->f_op = &fuse_direct_io_file_operations; + if (!(outarg->open_flags & FOPEN_KEEP_CACHE)) + invalidate_inode_pages(inode->i_mapping); + ff->fh = outarg->fh; + file->private_data = ff; +} + +int fuse_open_common(struct inode *inode, struct file *file, int isdir) +{ struct fuse_open_out outarg; struct fuse_file *ff; int err; @@ -34,73 +92,53 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir) /* If opening the root node, no lookup has been performed on it, so the attributes must be refreshed */ if (get_node_id(inode) == FUSE_ROOT_ID) { - int err = fuse_do_getattr(inode); + err = fuse_do_getattr(inode); if (err) return err; } - req = fuse_get_request(fc); - if (!req) - return -EINTR; - - err = -ENOMEM; - ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL); + ff = fuse_file_alloc(); if (!ff) - goto out_put_request; + return -ENOMEM; - ff->release_req = fuse_request_alloc(); - if (!ff->release_req) { - kfree(ff); - goto out_put_request; - } - - memset(&inarg, 0, sizeof(inarg)); - inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); - req->in.h.opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN; - req->in.h.nodeid = get_node_id(inode); - req->inode = inode; - req->in.numargs = 1; - req->in.args[0].size = sizeof(inarg); - req->in.args[0].value = &inarg; - req->out.numargs = 1; - req->out.args[0].size = sizeof(outarg); - req->out.args[0].value = &outarg; - request_send(fc, req); - err = req->out.h.error; - if (err) { - fuse_request_free(ff->release_req); - kfree(ff); - } else { - if (!isdir && (outarg.open_flags & FOPEN_DIRECT_IO)) - file->f_op = &fuse_direct_io_file_operations; - if (!(outarg.open_flags & FOPEN_KEEP_CACHE)) - invalidate_inode_pages(inode->i_mapping); - ff->fh = outarg.fh; - file->private_data = ff; + err = fuse_send_open(inode, file, isdir, &outarg); + if (err) + fuse_file_free(ff); + else { + if (isdir) + outarg.open_flags &= ~FOPEN_DIRECT_IO; + fuse_finish_open(inode, file, ff, &outarg); } - out_put_request: - fuse_put_request(fc, req); return err; } -int fuse_release_common(struct inode *inode, struct file *file, int isdir) +void fuse_send_release(struct fuse_conn *fc, struct fuse_file *ff, + u64 nodeid, struct inode *inode, int flags, int isdir) { - struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_file *ff = file->private_data; - struct fuse_req *req = ff->release_req; + struct fuse_req * req = ff->release_req; struct fuse_release_in *inarg = &req->misc.release_in; inarg->fh = ff->fh; - inarg->flags = file->f_flags & ~O_EXCL; + inarg->flags = flags; req->in.h.opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE; - req->in.h.nodeid = get_node_id(inode); + req->in.h.nodeid = nodeid; req->inode = inode; req->in.numargs = 1; req->in.args[0].size = sizeof(struct fuse_release_in); req->in.args[0].value = inarg; request_send_background(fc, req); kfree(ff); +} + +int fuse_release_common(struct inode *inode, struct file *file, int isdir) +{ + struct fuse_file *ff = file->private_data; + if (ff) { + struct fuse_conn *fc = get_fuse_conn(inode); + u64 nodeid = get_node_id(inode); + fuse_send_release(fc, ff, nodeid, inode, file->f_flags, isdir); + } /* Return value is ignored by VFS */ return 0; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 5cb456f572c1c97d7bf016b1ac0493dedccbde35..0ea5301f86bee8b585d5b8b1085ac3199a674bb4 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -266,6 +266,12 @@ struct fuse_conn { /** Is removexattr not implemented by fs? */ unsigned no_removexattr : 1; + /** Is access not implemented by fs? */ + unsigned no_access : 1; + + /** Is create not implemented by fs? */ + unsigned no_create : 1; + /** Backing dev info */ struct backing_dev_info bdi; }; @@ -337,6 +343,17 @@ size_t fuse_send_read_common(struct fuse_req *req, struct file *file, */ int fuse_open_common(struct inode *inode, struct file *file, int isdir); +struct fuse_file *fuse_file_alloc(void); +void fuse_file_free(struct fuse_file *ff); +void fuse_finish_open(struct inode *inode, struct file *file, + struct fuse_file *ff, struct fuse_open_out *outarg); + +/** + * Send a RELEASE request + */ +void fuse_send_release(struct fuse_conn *fc, struct fuse_file *ff, + u64 nodeid, struct inode *inode, int flags, int isdir); + /** * Send RELEASE or RELEASEDIR request */ diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index dd7113106269992822e97e4bbf07ad2bc5ab5eca..a33fb1d91373f873d559a26e1a8494e363ecc86c 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -294,8 +294,7 @@ static void hostfs_delete_inode(struct inode *inode) static void hostfs_destroy_inode(struct inode *inode) { - if(HOSTFS_I(inode)->host_filename) - kfree(HOSTFS_I(inode)->host_filename); + kfree(HOSTFS_I(inode)->host_filename); /*XXX: This should not happen, probably. The check is here for * additional safety.*/ diff --git a/fs/hpfs/dnode.c b/fs/hpfs/dnode.c index 1d21307730a8362cd9e8a1f961bcf81e19c39dc2..229ff2fb1809f7b6276c66655b47679f013225c6 100644 --- a/fs/hpfs/dnode.c +++ b/fs/hpfs/dnode.c @@ -244,12 +244,12 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, go_up: if (namelen >= 256) { hpfs_error(i->i_sb, "hpfs_add_to_dnode: namelen == %d", namelen); - if (nd) kfree(nd); + kfree(nd); kfree(nname); return 1; } if (!(d = hpfs_map_dnode(i->i_sb, dno, &qbh))) { - if (nd) kfree(nd); + kfree(nd); kfree(nname); return 1; } @@ -257,7 +257,7 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, if (hpfs_sb(i->i_sb)->sb_chk) if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "hpfs_add_to_dnode")) { hpfs_brelse4(&qbh); - if (nd) kfree(nd); + kfree(nd); kfree(nname); return 1; } @@ -270,7 +270,7 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, for_all_poss(i, hpfs_pos_subst, 5, t + 1); hpfs_mark_4buffers_dirty(&qbh); hpfs_brelse4(&qbh); - if (nd) kfree(nd); + kfree(nd); kfree(nname); return 0; } diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 8eefa6366db748ae145dde7bfb8ca6b4325a81f4..63e88d7e2c3b56842fb38d12a9bebb2d6d837724 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -75,7 +75,7 @@ void hpfs_error(struct super_block *s, char *m,...) } else if (s->s_flags & MS_RDONLY) printk("; going on - but anything won't be destroyed because it's read-only\n"); else printk("; corrupted filesystem mounted read/write - your computer will explode within 20 seconds ... but you wanted it so!\n"); } else printk("\n"); - if (buf) kfree(buf); + kfree(buf); hpfs_sb(s)->sb_was_error = 1; } @@ -102,8 +102,8 @@ int hpfs_stop_cycles(struct super_block *s, int key, int *c1, int *c2, static void hpfs_put_super(struct super_block *s) { struct hpfs_sb_info *sbi = hpfs_sb(s); - if (sbi->sb_cp_table) kfree(sbi->sb_cp_table); - if (sbi->sb_bmp_dir) kfree(sbi->sb_bmp_dir); + kfree(sbi->sb_cp_table); + kfree(sbi->sb_bmp_dir); unmark_dirty(s); s->s_fs_info = NULL; kfree(sbi); @@ -654,8 +654,8 @@ bail3: brelse(bh1); bail2: brelse(bh0); bail1: bail0: - if (sbi->sb_bmp_dir) kfree(sbi->sb_bmp_dir); - if (sbi->sb_cp_table) kfree(sbi->sb_cp_table); + kfree(sbi->sb_bmp_dir); + kfree(sbi->sb_cp_table); s->s_fs_info = NULL; kfree(sbi); return -EINVAL; diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 1652de1b6cb9e0a57bb9d33f6dff568b3f84196d..298f08be22d46ceb2e8a0d11121d9e3de7ecd594 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -855,8 +855,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) if (opt.check == 'r') table++; s->s_root->d_op = &isofs_dentry_ops[table]; - if (opt.iocharset) - kfree(opt.iocharset); + kfree(opt.iocharset); return 0; @@ -895,8 +894,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) out_freebh: brelse(bh); out_freesbi: - if (opt.iocharset) - kfree(opt.iocharset); + kfree(opt.iocharset); kfree(sbi); s->s_fs_info = NULL; return -EINVAL; @@ -1164,8 +1162,7 @@ static int isofs_read_level3_size(struct inode *inode) out_noread: printk(KERN_INFO "ISOFS: unable to read i-node block %lu\n", block); - if (tmpde) - kfree(tmpde); + kfree(tmpde); return -EIO; out_toomany: @@ -1334,8 +1331,7 @@ static void isofs_read_inode(struct inode *inode) init_special_inode(inode, inode->i_mode, inode->i_rdev); out: - if (tmpde) - kfree(tmpde); + kfree(tmpde); if (bh) brelse(bh); return; diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index 2a3e310f79efa7c3665dd037dd572ca35780677f..002ad2bbc76992b6acda52def147799886147693 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c @@ -261,10 +261,8 @@ void journal_commit_transaction(journal_t *journal) struct buffer_head *bh = jh2bh(jh); jbd_lock_bh_state(bh); - if (jh->b_committed_data) { - kfree(jh->b_committed_data); - jh->b_committed_data = NULL; - } + kfree(jh->b_committed_data); + jh->b_committed_data = NULL; jbd_unlock_bh_state(bh); } journal_refile_buffer(journal, jh); diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c index 103c34e4fb280978873cd811ef06d34c01bab2c2..80d7f53fd0a759dec8a019c60bb96badf7f927bb 100644 --- a/fs/jbd/recovery.c +++ b/fs/jbd/recovery.c @@ -210,7 +210,7 @@ do { \ } while (0) /** - * int journal_recover(journal_t *journal) - recovers a on-disk journal + * journal_recover - recovers a on-disk journal * @journal: the journal to recover * * The primary function for recovering the log contents when mounting a @@ -266,7 +266,7 @@ int journal_recover(journal_t *journal) } /** - * int journal_skip_recovery() - Start journal and wipe exiting records + * journal_skip_recovery - Start journal and wipe exiting records * @journal: journal to startup * * Locate any valid recovery information from the journal and set up the diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index 13cb05bf60489e0005d635d66a63b47692ed72a6..429f4b263cf1198bf179af4377ff8b1c21af3d5e 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c @@ -227,8 +227,7 @@ static int start_this_handle(journal_t *journal, handle_t *handle) spin_unlock(&transaction->t_handle_lock); spin_unlock(&journal->j_state_lock); out: - if (new_transaction) - kfree(new_transaction); + kfree(new_transaction); return ret; } @@ -725,8 +724,7 @@ do_get_write_access(handle_t *handle, struct journal_head *jh, journal_cancel_revoke(handle, jh); out: - if (frozen_buffer) - kfree(frozen_buffer); + kfree(frozen_buffer); JBUFFER_TRACE(jh, "exit"); return error; @@ -905,8 +903,7 @@ int journal_get_undo_access(handle_t *handle, struct buffer_head *bh) jbd_unlock_bh_state(bh); out: journal_put_journal_head(jh); - if (committed_data) - kfree(committed_data); + kfree(committed_data); return err; } diff --git a/fs/jffs/intrep.c b/fs/jffs/intrep.c index 27f199e94cfc8edd369775b4e962eee517dc3a14..b2e95421d932025407f758bb590d49b165a0a05a 100644 --- a/fs/jffs/intrep.c +++ b/fs/jffs/intrep.c @@ -462,7 +462,7 @@ jffs_checksum_flash(struct mtd_info *mtd, loff_t start, int size, __u32 *result) } /* Free read buffer */ - kfree (read_buf); + kfree(read_buf); /* Return result */ D3(printk("checksum result: 0x%08x\n", sum)); @@ -1011,12 +1011,12 @@ jffs_scan_flash(struct jffs_control *c) offset , fmc->sector_size); flash_safe_release(fmc->mtd); - kfree (read_buf); + kfree(read_buf); return -1; /* bad, bad, bad! */ } flash_safe_release(fmc->mtd); - kfree (read_buf); + kfree(read_buf); return -EAGAIN; /* erased offending sector. Try mount one more time please. */ } @@ -1112,7 +1112,7 @@ jffs_scan_flash(struct jffs_control *c) if (!node) { if (!(node = jffs_alloc_node())) { /* Free read buffer */ - kfree (read_buf); + kfree(read_buf); /* Release the flash device */ flash_safe_release(fmc->mtd); @@ -1269,7 +1269,7 @@ jffs_scan_flash(struct jffs_control *c) DJM(no_jffs_node--); /* Free read buffer */ - kfree (read_buf); + kfree(read_buf); /* Release the flash device */ flash_safe_release(fmc->mtd); @@ -1296,7 +1296,7 @@ jffs_scan_flash(struct jffs_control *c) flash_safe_release(fmc->flash_part); /* Free read buffer */ - kfree (read_buf); + kfree(read_buf); return -ENOMEM; } @@ -1324,7 +1324,7 @@ jffs_scan_flash(struct jffs_control *c) jffs_build_end(fmc); /* Free read buffer */ - kfree (read_buf); + kfree(read_buf); if(!num_free_space){ printk(KERN_WARNING "jffs_scan_flash(): Did not find even a single " @@ -1747,9 +1747,7 @@ jffs_find_child(struct jffs_file *dir, const char *name, int len) } printk("jffs_find_child(): Didn't find the file \"%s\".\n", (copy ? copy : "")); - if (copy) { - kfree(copy); - } + kfree(copy); }); return f; diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile index f1afe681ecd6a950f685476905b24b0e164a881e..77dc5561a04e7def0490e1fa3af3634945726bf0 100644 --- a/fs/jffs2/Makefile +++ b/fs/jffs2/Makefile @@ -1,7 +1,7 @@ # # Makefile for the Linux Journalling Flash File System v2 (JFFS2) # -# $Id: Makefile.common,v 1.9 2005/02/09 09:23:53 pavlov Exp $ +# $Id: Makefile.common,v 1.11 2005/09/07 08:34:53 havasi Exp $ # obj-$(CONFIG_JFFS2_FS) += jffs2.o @@ -9,9 +9,10 @@ obj-$(CONFIG_JFFS2_FS) += jffs2.o jffs2-y := compr.o dir.o file.o ioctl.o nodelist.o malloc.o jffs2-y += read.o nodemgmt.o readinode.o write.o scan.o gc.o jffs2-y += symlink.o build.o erase.o background.o fs.o writev.o -jffs2-y += super.o +jffs2-y += super.o debug.o jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER) += wbuf.o jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o +jffs2-$(CONFIG_JFFS2_SUMMARY) += summary.o diff --git a/fs/jffs2/TODO b/fs/jffs2/TODO index 2bff82fd221f7095aa691305382a21b2f346a79e..d0e23b26fa505a0c47a8a2e09cfef039016fc8fc 100644 --- a/fs/jffs2/TODO +++ b/fs/jffs2/TODO @@ -1,5 +1,11 @@ -$Id: TODO,v 1.10 2002/09/09 16:31:21 dwmw2 Exp $ +$Id: TODO,v 1.18 2005/09/22 11:24:56 dedekind Exp $ + - support asynchronous operation -- add a per-fs 'reserved_space' count, + let each outstanding write reserve the _maximum_ amount of physical + space it could take. Let GC flush the outstanding writes because the + reservations will necessarily be pessimistic. With this we could even + do shared writable mmap, if we can have a fs hook for do_wp_page() to + make the reservation. - disable compression in commit_write()? - fine-tune the allocation / GC thresholds - chattr support - turning on/off and tuning compression per-inode @@ -11,26 +17,15 @@ $Id: TODO,v 1.10 2002/09/09 16:31:21 dwmw2 Exp $ - test, test, test - NAND flash support: - - flush_wbuf using GC to fill it, don't just pad. - - Deal with write errors. Data don't get lost - we just have to write - the affected node(s) out again somewhere else. - - make fsync flush only if actually required - - make sys_sync() work. - - reboot notifier - - timed flush of old wbuf - - fix magical second arg of jffs2_flush_wbuf(). Split into two or more functions instead. - + - almost done :) + - use bad block check instead of the hardwired byte check - Optimisations: - - Stop GC from decompressing and immediately recompressing nodes which could - just be copied intact. (We now keep track of REF_PRISTINE flag. Easy now.) - - Furthermore, in the case where it could be copied intact we don't even need - to call iget() for it -- if we use (raw_node_raw->flash_offset & 2) as a flag - to show a node can be copied intact and it's _not_ in icache, we could just do - it, fix up the next_in_ino list and move on. We would need a way to find out - _whether_ it's in icache though -- if it's in icache we also need to do the - fragment lists, etc. P'raps a flag or pointer in the jffs2_inode_cache could - help. (We have half of this now.) + - Split writes so they go to two separate blocks rather than just c->nextblock. + By writing _new_ nodes to one block, and garbage-collected REF_PRISTINE + nodes to a different one, we can separate clean nodes from those which + are likely to become dirty, and end up with blocks which are each far + closer to 100% or 0% clean, hence speeding up later GC progress dramatically. - Stop keeping name in-core with struct jffs2_full_dirent. If we keep the hash in the full dirent, we only need to go to the flash in lookup() when we think we've got a match, and in readdir(). @@ -38,3 +33,8 @@ $Id: TODO,v 1.10 2002/09/09 16:31:21 dwmw2 Exp $ - Remove totlen from jffs2_raw_node_ref? Need to have totlen passed into jffs2_mark_node_obsolete(). Can all callers work it out? - Remove size from jffs2_raw_node_frag. + +dedekind: +1. __jffs2_flush_wbuf() has a strange 'pad' parameter. Eliminate. +2. get_sb()->build_fs()->scan() path... Why get_sb() removes scan()'s crap in + case of failure? scan() does not clean everything. Fix. diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 8210ac16a36827df97a8ae43e04a4efe979892a7..7b77a9541125b7b62aa01d0cf3961f45cb1ca47c 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c @@ -51,7 +51,7 @@ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c) D1(printk(KERN_DEBUG "JFFS2: Garbage collect thread is pid %d\n", pid)); wait_for_completion(&c->gc_thread_start); } - + return ret; } @@ -101,7 +101,7 @@ static int jffs2_garbage_collect_thread(void *_c) cond_resched(); - /* Put_super will send a SIGKILL and then wait on the sem. + /* Put_super will send a SIGKILL and then wait on the sem. */ while (signal_pending(current)) { siginfo_t info; diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index 97dc39796e2cc1f59aa4ad2edea8d275e93a4be3..fff108bb118b14db6a4ca927b62320a4cf4f2b19 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: build.c,v 1.71 2005/07/12 16:37:08 dedekind Exp $ + * $Id: build.c,v 1.85 2005/11/07 11:14:38 gleixner Exp $ * */ @@ -18,7 +18,8 @@ #include #include "nodelist.h" -static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *, struct jffs2_full_dirent **); +static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, + struct jffs2_inode_cache *, struct jffs2_full_dirent **); static inline struct jffs2_inode_cache * first_inode_chain(int *i, struct jffs2_sb_info *c) @@ -46,11 +47,12 @@ next_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c) ic = next_inode(&i, ic, (c))) -static inline void jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) +static inline void jffs2_build_inode_pass1(struct jffs2_sb_info *c, + struct jffs2_inode_cache *ic) { struct jffs2_full_dirent *fd; - D1(printk(KERN_DEBUG "jffs2_build_inode building directory inode #%u\n", ic->ino)); + dbg_fsbuild("building directory inode #%u\n", ic->ino); /* For each child, increase nlink */ for(fd = ic->scan_dents; fd; fd = fd->next) { @@ -58,26 +60,23 @@ static inline void jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2 if (!fd->ino) continue; - /* XXX: Can get high latency here with huge directories */ + /* we can get high latency here with huge directories */ child_ic = jffs2_get_ino_cache(c, fd->ino); if (!child_ic) { - printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n", + dbg_fsbuild("child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n", fd->name, fd->ino, ic->ino); jffs2_mark_node_obsolete(c, fd->raw); continue; } if (child_ic->nlink++ && fd->type == DT_DIR) { - printk(KERN_NOTICE "Child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", fd->name, fd->ino, ic->ino); - if (fd->ino == 1 && ic->ino == 1) { - printk(KERN_NOTICE "This is mostly harmless, and probably caused by creating a JFFS2 image\n"); - printk(KERN_NOTICE "using a buggy version of mkfs.jffs2. Use at least v1.17.\n"); - } - /* What do we do about it? */ + JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", + fd->name, fd->ino, ic->ino); + /* TODO: What do we do about it? */ } - D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino)); - /* Can't free them. We might need them in pass 2 */ + dbg_fsbuild("increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino); + /* Can't free scan_dents so far. We might need them in pass 2 */ } } @@ -94,6 +93,8 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) struct jffs2_full_dirent *fd; struct jffs2_full_dirent *dead_fds = NULL; + dbg_fsbuild("build FS data structures\n"); + /* First, scan the medium and build all the inode caches with lists of physical nodes */ @@ -103,60 +104,54 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) if (ret) goto exit; - D1(printk(KERN_DEBUG "Scanned flash completely\n")); - D2(jffs2_dump_block_lists(c)); + dbg_fsbuild("scanned flash completely\n"); + jffs2_dbg_dump_block_lists_nolock(c); + dbg_fsbuild("pass 1 starting\n"); c->flags |= JFFS2_SB_FLAG_BUILDING; /* Now scan the directory tree, increasing nlink according to every dirent found. */ for_each_inode(i, c, ic) { - D1(printk(KERN_DEBUG "Pass 1: ino #%u\n", ic->ino)); - - D1(BUG_ON(ic->ino > c->highest_ino)); - if (ic->scan_dents) { jffs2_build_inode_pass1(c, ic); cond_resched(); } } - D1(printk(KERN_DEBUG "Pass 1 complete\n")); + dbg_fsbuild("pass 1 complete\n"); /* Next, scan for inodes with nlink == 0 and remove them. If they were directories, then decrement the nlink of their children too, and repeat the scan. As that's going to be a fairly uncommon occurrence, it's not so evil to do it this way. Recursion bad. */ - D1(printk(KERN_DEBUG "Pass 2 starting\n")); + dbg_fsbuild("pass 2 starting\n"); for_each_inode(i, c, ic) { - D1(printk(KERN_DEBUG "Pass 2: ino #%u, nlink %d, ic %p, nodes %p\n", ic->ino, ic->nlink, ic, ic->nodes)); if (ic->nlink) continue; - + jffs2_build_remove_unlinked_inode(c, ic, &dead_fds); cond_resched(); - } + } - D1(printk(KERN_DEBUG "Pass 2a starting\n")); + dbg_fsbuild("pass 2a starting\n"); while (dead_fds) { fd = dead_fds; dead_fds = fd->next; ic = jffs2_get_ino_cache(c, fd->ino); - D1(printk(KERN_DEBUG "Removing dead_fd ino #%u (\"%s\"), ic at %p\n", fd->ino, fd->name, ic)); if (ic) jffs2_build_remove_unlinked_inode(c, ic, &dead_fds); jffs2_free_full_dirent(fd); } - D1(printk(KERN_DEBUG "Pass 2 complete\n")); - + dbg_fsbuild("pass 2a complete\n"); + dbg_fsbuild("freeing temporary data structures\n"); + /* Finally, we can scan again and free the dirent structs */ for_each_inode(i, c, ic) { - D1(printk(KERN_DEBUG "Pass 3: ino #%u, ic %p, nodes %p\n", ic->ino, ic, ic->nodes)); - while(ic->scan_dents) { fd = ic->scan_dents; ic->scan_dents = fd->next; @@ -166,9 +161,8 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) cond_resched(); } c->flags &= ~JFFS2_SB_FLAG_BUILDING; - - D1(printk(KERN_DEBUG "Pass 3 complete\n")); - D2(jffs2_dump_block_lists(c)); + + dbg_fsbuild("FS build complete\n"); /* Rotate the lists by some number to ensure wear levelling */ jffs2_rotate_lists(c); @@ -189,24 +183,26 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) return ret; } -static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, struct jffs2_full_dirent **dead_fds) +static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, + struct jffs2_inode_cache *ic, + struct jffs2_full_dirent **dead_fds) { struct jffs2_raw_node_ref *raw; struct jffs2_full_dirent *fd; - D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino)); - + dbg_fsbuild("removing ino #%u with nlink == zero.\n", ic->ino); + raw = ic->nodes; while (raw != (void *)ic) { struct jffs2_raw_node_ref *next = raw->next_in_ino; - D1(printk(KERN_DEBUG "obsoleting node at 0x%08x\n", ref_offset(raw))); + dbg_fsbuild("obsoleting node at 0x%08x\n", ref_offset(raw)); jffs2_mark_node_obsolete(c, raw); raw = next; } if (ic->scan_dents) { int whinged = 0; - D1(printk(KERN_DEBUG "Inode #%u was a directory which may have children...\n", ic->ino)); + dbg_fsbuild("inode #%u was a directory which may have children...\n", ic->ino); while(ic->scan_dents) { struct jffs2_inode_cache *child_ic; @@ -216,45 +212,43 @@ static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jf if (!fd->ino) { /* It's a deletion dirent. Ignore it */ - D1(printk(KERN_DEBUG "Child \"%s\" is a deletion dirent, skipping...\n", fd->name)); + dbg_fsbuild("child \"%s\" is a deletion dirent, skipping...\n", fd->name); jffs2_free_full_dirent(fd); continue; } - if (!whinged) { + if (!whinged) whinged = 1; - printk(KERN_NOTICE "Inode #%u was a directory with children - removing those too...\n", ic->ino); - } - D1(printk(KERN_DEBUG "Removing child \"%s\", ino #%u\n", - fd->name, fd->ino)); - + dbg_fsbuild("removing child \"%s\", ino #%u\n", fd->name, fd->ino); + child_ic = jffs2_get_ino_cache(c, fd->ino); if (!child_ic) { - printk(KERN_NOTICE "Cannot remove child \"%s\", ino #%u, because it doesn't exist\n", fd->name, fd->ino); + dbg_fsbuild("cannot remove child \"%s\", ino #%u, because it doesn't exist\n", + fd->name, fd->ino); jffs2_free_full_dirent(fd); continue; } - /* Reduce nlink of the child. If it's now zero, stick it on the + /* Reduce nlink of the child. If it's now zero, stick it on the dead_fds list to be cleaned up later. Else just free the fd */ child_ic->nlink--; - + if (!child_ic->nlink) { - D1(printk(KERN_DEBUG "Inode #%u (\"%s\") has now got zero nlink. Adding to dead_fds list.\n", - fd->ino, fd->name)); + dbg_fsbuild("inode #%u (\"%s\") has now got zero nlink, adding to dead_fds list.\n", + fd->ino, fd->name); fd->next = *dead_fds; *dead_fds = fd; } else { - D1(printk(KERN_DEBUG "Inode #%u (\"%s\") has now got nlink %d. Ignoring.\n", - fd->ino, fd->name, child_ic->nlink)); + dbg_fsbuild("inode #%u (\"%s\") has now got nlink %d. Ignoring.\n", + fd->ino, fd->name, child_ic->nlink); jffs2_free_full_dirent(fd); } } } /* - We don't delete the inocache from the hash list and free it yet. + We don't delete the inocache from the hash list and free it yet. The erase code will do that, when all the nodes are completely gone. */ } @@ -268,7 +262,7 @@ static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c) because there's not enough free space... */ c->resv_blocks_deletion = 2; - /* Be conservative about how much space we need before we allow writes. + /* Be conservative about how much space we need before we allow writes. On top of that which is required for deletia, require an extra 2% of the medium to be available, for overhead caused by nodes being split across blocks, etc. */ @@ -283,7 +277,7 @@ static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c) c->resv_blocks_gctrigger = c->resv_blocks_write + 1; - /* When do we allow garbage collection to merge nodes to make + /* When do we allow garbage collection to merge nodes to make long-term progress at the expense of short-term space exhaustion? */ c->resv_blocks_gcmerge = c->resv_blocks_deletion + 1; @@ -295,45 +289,45 @@ static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c) trying to GC to make more space. It'll be a fruitless task */ c->nospc_dirty_size = c->sector_size + (c->flash_size / 100); - D1(printk(KERN_DEBUG "JFFS2 trigger levels (size %d KiB, block size %d KiB, %d blocks)\n", - c->flash_size / 1024, c->sector_size / 1024, c->nr_blocks)); - D1(printk(KERN_DEBUG "Blocks required to allow deletion: %d (%d KiB)\n", - c->resv_blocks_deletion, c->resv_blocks_deletion*c->sector_size/1024)); - D1(printk(KERN_DEBUG "Blocks required to allow writes: %d (%d KiB)\n", - c->resv_blocks_write, c->resv_blocks_write*c->sector_size/1024)); - D1(printk(KERN_DEBUG "Blocks required to quiesce GC thread: %d (%d KiB)\n", - c->resv_blocks_gctrigger, c->resv_blocks_gctrigger*c->sector_size/1024)); - D1(printk(KERN_DEBUG "Blocks required to allow GC merges: %d (%d KiB)\n", - c->resv_blocks_gcmerge, c->resv_blocks_gcmerge*c->sector_size/1024)); - D1(printk(KERN_DEBUG "Blocks required to GC bad blocks: %d (%d KiB)\n", - c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024)); - D1(printk(KERN_DEBUG "Amount of dirty space required to GC: %d bytes\n", - c->nospc_dirty_size)); -} + dbg_fsbuild("JFFS2 trigger levels (size %d KiB, block size %d KiB, %d blocks)\n", + c->flash_size / 1024, c->sector_size / 1024, c->nr_blocks); + dbg_fsbuild("Blocks required to allow deletion: %d (%d KiB)\n", + c->resv_blocks_deletion, c->resv_blocks_deletion*c->sector_size/1024); + dbg_fsbuild("Blocks required to allow writes: %d (%d KiB)\n", + c->resv_blocks_write, c->resv_blocks_write*c->sector_size/1024); + dbg_fsbuild("Blocks required to quiesce GC thread: %d (%d KiB)\n", + c->resv_blocks_gctrigger, c->resv_blocks_gctrigger*c->sector_size/1024); + dbg_fsbuild("Blocks required to allow GC merges: %d (%d KiB)\n", + c->resv_blocks_gcmerge, c->resv_blocks_gcmerge*c->sector_size/1024); + dbg_fsbuild("Blocks required to GC bad blocks: %d (%d KiB)\n", + c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024); + dbg_fsbuild("Amount of dirty space required to GC: %d bytes\n", + c->nospc_dirty_size); +} int jffs2_do_mount_fs(struct jffs2_sb_info *c) { + int ret; int i; + int size; c->free_size = c->flash_size; c->nr_blocks = c->flash_size / c->sector_size; - if (c->mtd->flags & MTD_NO_VIRTBLOCKS) - c->blocks = vmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks); + size = sizeof(struct jffs2_eraseblock) * c->nr_blocks; +#ifndef __ECOS + if (jffs2_blocks_use_vmalloc(c)) + c->blocks = vmalloc(size); else - c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL); +#endif + c->blocks = kmalloc(size, GFP_KERNEL); if (!c->blocks) return -ENOMEM; + + memset(c->blocks, 0, size); for (i=0; inr_blocks; i++) { INIT_LIST_HEAD(&c->blocks[i].list); c->blocks[i].offset = i * c->sector_size; c->blocks[i].free_size = c->sector_size; - c->blocks[i].dirty_size = 0; - c->blocks[i].wasted_size = 0; - c->blocks[i].unchecked_size = 0; - c->blocks[i].used_size = 0; - c->blocks[i].first_node = NULL; - c->blocks[i].last_node = NULL; - c->blocks[i].bad_count = 0; } INIT_LIST_HEAD(&c->clean_list); @@ -348,16 +342,23 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c) INIT_LIST_HEAD(&c->bad_list); INIT_LIST_HEAD(&c->bad_used_list); c->highest_ino = 1; + c->summary = NULL; + + ret = jffs2_sum_init(c); + if (ret) + return ret; if (jffs2_build_filesystem(c)) { - D1(printk(KERN_DEBUG "build_fs failed\n")); + dbg_fsbuild("build_fs failed\n"); jffs2_free_ino_caches(c); jffs2_free_raw_node_refs(c); - if (c->mtd->flags & MTD_NO_VIRTBLOCKS) { +#ifndef __ECOS + if (jffs2_blocks_use_vmalloc(c)) vfree(c->blocks); - } else { + else +#endif kfree(c->blocks); - } + return -EIO; } diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c index af922a9618ac0af62795addcc1e7cdfd990e134f..e7944e665b9fc9245135c0c455b959f47cc721a3 100644 --- a/fs/jffs2/compr.c +++ b/fs/jffs2/compr.c @@ -9,7 +9,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: compr.c,v 1.42 2004/08/07 21:56:08 dwmw2 Exp $ + * $Id: compr.c,v 1.46 2005/11/07 11:14:38 gleixner Exp $ * */ @@ -36,16 +36,16 @@ static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_co * data. * * Returns: Lower byte to be stored with data indicating compression type used. - * Zero is used to show that the data could not be compressed - the + * Zero is used to show that the data could not be compressed - the * compressed version was actually larger than the original. * Upper byte will be used later. (soon) * * If the cdata buffer isn't large enough to hold all the uncompressed data, - * jffs2_compress should compress as much as will fit, and should set + * jffs2_compress should compress as much as will fit, and should set * *datalen accordingly to show the amount of data which were compressed. */ uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, - unsigned char *data_in, unsigned char **cpage_out, + unsigned char *data_in, unsigned char **cpage_out, uint32_t *datalen, uint32_t *cdatalen) { int ret = JFFS2_COMPR_NONE; @@ -164,7 +164,7 @@ uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, } int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, - uint16_t comprtype, unsigned char *cdata_in, + uint16_t comprtype, unsigned char *cdata_in, unsigned char *data_out, uint32_t cdatalen, uint32_t datalen) { struct jffs2_compressor *this; @@ -298,7 +298,7 @@ char *jffs2_stats(void) act_buf += sprintf(act_buf,"JFFS2 compressor statistics:\n"); act_buf += sprintf(act_buf,"%10s ","none"); - act_buf += sprintf(act_buf,"compr: %d blocks (%d) decompr: %d blocks\n", none_stat_compr_blocks, + act_buf += sprintf(act_buf,"compr: %d blocks (%d) decompr: %d blocks\n", none_stat_compr_blocks, none_stat_compr_size, none_stat_decompr_blocks); spin_lock(&jffs2_compressor_list_lock); list_for_each_entry(this, &jffs2_compressor_list, list) { @@ -307,8 +307,8 @@ char *jffs2_stats(void) act_buf += sprintf(act_buf,"- "); else act_buf += sprintf(act_buf,"+ "); - act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d) decompr: %d blocks ", this->stat_compr_blocks, - this->stat_compr_new_size, this->stat_compr_orig_size, + act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d) decompr: %d blocks ", this->stat_compr_blocks, + this->stat_compr_new_size, this->stat_compr_orig_size, this->stat_decompr_blocks); act_buf += sprintf(act_buf,"\n"); } @@ -317,7 +317,7 @@ char *jffs2_stats(void) return buf; } -char *jffs2_get_compression_mode_name(void) +char *jffs2_get_compression_mode_name(void) { switch (jffs2_compression_mode) { case JFFS2_COMPR_MODE_NONE: @@ -330,7 +330,7 @@ char *jffs2_get_compression_mode_name(void) return "unkown"; } -int jffs2_set_compression_mode_name(const char *name) +int jffs2_set_compression_mode_name(const char *name) { if (!strcmp("none",name)) { jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; @@ -355,7 +355,7 @@ static int jffs2_compressor_Xable(const char *name, int disabled) if (!strcmp(this->name, name)) { this->disabled = disabled; spin_unlock(&jffs2_compressor_list_lock); - return 0; + return 0; } } spin_unlock(&jffs2_compressor_list_lock); @@ -385,7 +385,7 @@ int jffs2_set_compressor_priority(const char *name, int priority) } } spin_unlock(&jffs2_compressor_list_lock); - printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name); + printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name); return 1; reinsert: /* list is sorted in the order of priority, so if @@ -412,7 +412,7 @@ void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig) kfree(comprbuf); } -int jffs2_compressors_init(void) +int jffs2_compressors_init(void) { /* Registering compressors */ #ifdef CONFIG_JFFS2_ZLIB @@ -425,12 +425,6 @@ int jffs2_compressors_init(void) jffs2_rubinmips_init(); jffs2_dynrubin_init(); #endif -#ifdef CONFIG_JFFS2_LZARI - jffs2_lzari_init(); -#endif -#ifdef CONFIG_JFFS2_LZO - jffs2_lzo_init(); -#endif /* Setting default compression mode */ #ifdef CONFIG_JFFS2_CMODE_NONE jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; @@ -446,15 +440,9 @@ int jffs2_compressors_init(void) return 0; } -int jffs2_compressors_exit(void) +int jffs2_compressors_exit(void) { /* Unregistering compressors */ -#ifdef CONFIG_JFFS2_LZO - jffs2_lzo_exit(); -#endif -#ifdef CONFIG_JFFS2_LZARI - jffs2_lzari_exit(); -#endif #ifdef CONFIG_JFFS2_RUBIN jffs2_dynrubin_exit(); jffs2_rubinmips_exit(); diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h index 89ceeed201eb8e5a00c745ed35d2196b3137fcd0..a77e830d85c5fb0cd230dba36670422554bcb398 100644 --- a/fs/jffs2/compr.h +++ b/fs/jffs2/compr.h @@ -4,10 +4,10 @@ * Copyright (C) 2004 Ferenc Havasi , * University of Szeged, Hungary * - * For licensing information, see the file 'LICENCE' in the + * For licensing information, see the file 'LICENCE' in the * jffs2 directory. * - * $Id: compr.h,v 1.6 2004/07/16 15:17:57 dwmw2 Exp $ + * $Id: compr.h,v 1.9 2005/11/07 11:14:38 gleixner Exp $ * */ @@ -103,13 +103,5 @@ void jffs2_rtime_exit(void); int jffs2_zlib_init(void); void jffs2_zlib_exit(void); #endif -#ifdef CONFIG_JFFS2_LZARI -int jffs2_lzari_init(void); -void jffs2_lzari_exit(void); -#endif -#ifdef CONFIG_JFFS2_LZO -int jffs2_lzo_init(void); -void jffs2_lzo_exit(void); -#endif #endif /* __JFFS2_COMPR_H__ */ diff --git a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c index 39312941866682e2627e2fd62d71b47650ae23f5..2eb1b7428d1628104cda0403ef1c1dbebcca3ee8 100644 --- a/fs/jffs2/compr_rtime.c +++ b/fs/jffs2/compr_rtime.c @@ -24,8 +24,8 @@ #include #include #include -#include -#include +#include +#include #include "compr.h" /* _compress returns the compressed size, -1 if bigger */ @@ -38,19 +38,19 @@ static int jffs2_rtime_compress(unsigned char *data_in, int outpos = 0; int pos=0; - memset(positions,0,sizeof(positions)); - + memset(positions,0,sizeof(positions)); + while (pos < (*sourcelen) && outpos <= (*dstlen)-2) { int backpos, runlen=0; unsigned char value; - + value = data_in[pos]; cpage_out[outpos++] = data_in[pos++]; - + backpos = positions[value]; positions[value]=pos; - + while ((backpos < pos) && (pos < (*sourcelen)) && (data_in[pos]==data_in[backpos++]) && (runlen<255)) { pos++; @@ -63,12 +63,12 @@ static int jffs2_rtime_compress(unsigned char *data_in, /* We failed */ return -1; } - + /* Tell the caller how much we managed to compress, and how much space it took */ *sourcelen = pos; *dstlen = outpos; return 0; -} +} static int jffs2_rtime_decompress(unsigned char *data_in, @@ -79,19 +79,19 @@ static int jffs2_rtime_decompress(unsigned char *data_in, short positions[256]; int outpos = 0; int pos=0; - - memset(positions,0,sizeof(positions)); - + + memset(positions,0,sizeof(positions)); + while (outpos= outpos) { @@ -101,12 +101,12 @@ static int jffs2_rtime_decompress(unsigned char *data_in, } } else { memcpy(&cpage_out[outpos],&cpage_out[backoffs],repeat); - outpos+=repeat; + outpos+=repeat; } } } return 0; -} +} static struct jffs2_compressor jffs2_rtime_comp = { .priority = JFFS2_RTIME_PRIORITY, diff --git a/fs/jffs2/compr_rubin.c b/fs/jffs2/compr_rubin.c index 09422388fb96716681b151871144eed992b72be7..e792e675d624eecb5fcabfd4dc33cebf7c527bfa 100644 --- a/fs/jffs2/compr_rubin.c +++ b/fs/jffs2/compr_rubin.c @@ -11,7 +11,6 @@ * */ - #include #include #include @@ -20,7 +19,7 @@ #include "compr.h" static void init_rubin(struct rubin_state *rs, int div, int *bits) -{ +{ int c; rs->q = 0; @@ -40,7 +39,7 @@ static int encode(struct rubin_state *rs, long A, long B, int symbol) while ((rs->q >= UPPER_BIT_RUBIN) || ((rs->p + rs->q) <= UPPER_BIT_RUBIN)) { rs->bit_number++; - + ret = pushbit(&rs->pp, (rs->q & UPPER_BIT_RUBIN) ? 1 : 0, 0); if (ret) return ret; @@ -68,7 +67,7 @@ static int encode(struct rubin_state *rs, long A, long B, int symbol) static void end_rubin(struct rubin_state *rs) -{ +{ int i; @@ -82,7 +81,7 @@ static void end_rubin(struct rubin_state *rs) static void init_decode(struct rubin_state *rs, int div, int *bits) { - init_rubin(rs, div, bits); + init_rubin(rs, div, bits); /* behalve lower */ rs->rec_q = 0; @@ -188,7 +187,7 @@ static int in_byte(struct rubin_state *rs) -static int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in, +static int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen) { int outpos = 0; @@ -198,31 +197,31 @@ static int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in, init_pushpull(&rs.pp, cpage_out, *dstlen * 8, 0, 32); init_rubin(&rs, bit_divider, bits); - + while (pos < (*sourcelen) && !out_byte(&rs, data_in[pos])) pos++; - + end_rubin(&rs); if (outpos > pos) { /* We failed */ return -1; } - - /* Tell the caller how much we managed to compress, + + /* Tell the caller how much we managed to compress, * and how much space it took */ - + outpos = (pushedbits(&rs.pp)+7)/8; - + if (outpos >= pos) return -1; /* We didn't actually compress */ *sourcelen = pos; *dstlen = outpos; return 0; -} +} #if 0 /* _compress returns the compressed size, -1 if bigger */ -int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, +int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen, void *model) { return rubin_do_compress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen); @@ -277,7 +276,7 @@ static int jffs2_dynrubin_compress(unsigned char *data_in, } ret = rubin_do_compress(256, bits, data_in, cpage_out+8, &mysrclen, &mydstlen); - if (ret) + if (ret) return ret; /* Add back the 8 bytes we took for the probabilities */ @@ -293,19 +292,19 @@ static int jffs2_dynrubin_compress(unsigned char *data_in, return 0; } -static void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata_in, +static void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata_in, unsigned char *page_out, uint32_t srclen, uint32_t destlen) { int outpos = 0; struct rubin_state rs; - + init_pushpull(&rs.pp, cdata_in, srclen, 0, 0); init_decode(&rs, bit_divider, bits); - + while (outpos < destlen) { page_out[outpos++] = in_byte(&rs); } -} +} static int jffs2_rubinmips_decompress(unsigned char *data_in, diff --git a/fs/jffs2/compr_rubin.h b/fs/jffs2/compr_rubin.h index cf51e34f657458edb817015f1a093f86c8bb0e22..bf1a934516210608229241e14e1ace0329d9c0fa 100644 --- a/fs/jffs2/compr_rubin.h +++ b/fs/jffs2/compr_rubin.h @@ -1,7 +1,7 @@ /* Rubin encoder/decoder header */ /* work started at : aug 3, 1994 */ /* last modification : aug 15, 1994 */ -/* $Id: compr_rubin.h,v 1.6 2002/01/25 01:49:26 dwmw2 Exp $ */ +/* $Id: compr_rubin.h,v 1.7 2005/11/07 11:14:38 gleixner Exp $ */ #include "pushpull.h" @@ -11,8 +11,8 @@ struct rubin_state { - unsigned long p; - unsigned long q; + unsigned long p; + unsigned long q; unsigned long rec_q; long bit_number; struct pushpull pp; diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c index 83f7e0788fd0a551ad715b2ad2ea380fa07d7a33..4db8be8e90cc09dea0f71d09d55048d612bbb17a 100644 --- a/fs/jffs2/compr_zlib.c +++ b/fs/jffs2/compr_zlib.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: compr_zlib.c,v 1.31 2005/05/20 19:30:06 gleixner Exp $ + * $Id: compr_zlib.c,v 1.32 2005/11/07 11:14:38 gleixner Exp $ * */ @@ -24,11 +24,11 @@ #include "nodelist.h" #include "compr.h" - /* Plan: call deflate() with avail_in == *sourcelen, - avail_out = *dstlen - 12 and flush == Z_FINISH. + /* Plan: call deflate() with avail_in == *sourcelen, + avail_out = *dstlen - 12 and flush == Z_FINISH. If it doesn't manage to finish, call it again with avail_in == 0 and avail_out set to the remaining 12 - bytes for it to clean up. + bytes for it to clean up. Q: Is 12 bytes sufficient? */ #define STREAM_END_SPACE 12 @@ -89,7 +89,7 @@ static int jffs2_zlib_compress(unsigned char *data_in, def_strm.next_in = data_in; def_strm.total_in = 0; - + def_strm.next_out = cpage_out; def_strm.total_out = 0; @@ -99,7 +99,7 @@ static int jffs2_zlib_compress(unsigned char *data_in, D1(printk(KERN_DEBUG "calling deflate with avail_in %d, avail_out %d\n", def_strm.avail_in, def_strm.avail_out)); ret = zlib_deflate(&def_strm, Z_PARTIAL_FLUSH); - D1(printk(KERN_DEBUG "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n", + D1(printk(KERN_DEBUG "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n", def_strm.avail_in, def_strm.avail_out, def_strm.total_in, def_strm.total_out)); if (ret != Z_OK) { D1(printk(KERN_DEBUG "deflate in loop returned %d\n", ret)); @@ -150,7 +150,7 @@ static int jffs2_zlib_decompress(unsigned char *data_in, inf_strm.next_in = data_in; inf_strm.avail_in = srclen; inf_strm.total_in = 0; - + inf_strm.next_out = cpage_out; inf_strm.avail_out = destlen; inf_strm.total_out = 0; diff --git a/fs/jffs2/comprtest.c b/fs/jffs2/comprtest.c index cf51f091d0e7325f741b2c2dcc7b874c726e0021..f0fb8be7740cc760243cc45b04799ccfba3867c7 100644 --- a/fs/jffs2/comprtest.c +++ b/fs/jffs2/comprtest.c @@ -1,4 +1,4 @@ -/* $Id: comprtest.c,v 1.5 2002/01/03 15:20:44 dwmw2 Exp $ */ +/* $Id: comprtest.c,v 1.6 2005/11/07 11:14:38 gleixner Exp $ */ #include #include @@ -265,9 +265,9 @@ static unsigned char testdata[TESTDATA_LEN] = { static unsigned char comprbuf[TESTDATA_LEN]; static unsigned char decomprbuf[TESTDATA_LEN]; -int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in, +int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in, unsigned char *data_out, uint32_t cdatalen, uint32_t datalen); -unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out, +unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *datalen, uint32_t *cdatalen); int init_module(void ) { @@ -276,10 +276,10 @@ int init_module(void ) { int ret; printk("Original data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - testdata[0],testdata[1],testdata[2],testdata[3], - testdata[4],testdata[5],testdata[6],testdata[7], - testdata[8],testdata[9],testdata[10],testdata[11], - testdata[12],testdata[13],testdata[14],testdata[15]); + testdata[0],testdata[1],testdata[2],testdata[3], + testdata[4],testdata[5],testdata[6],testdata[7], + testdata[8],testdata[9],testdata[10],testdata[11], + testdata[12],testdata[13],testdata[14],testdata[15]); d = TESTDATA_LEN; c = TESTDATA_LEN; comprtype = jffs2_compress(testdata, comprbuf, &d, &c); @@ -287,18 +287,18 @@ int init_module(void ) { printk("jffs2_compress used compression type %d. Compressed size %d, uncompressed size %d\n", comprtype, c, d); printk("Compressed data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - comprbuf[0],comprbuf[1],comprbuf[2],comprbuf[3], - comprbuf[4],comprbuf[5],comprbuf[6],comprbuf[7], - comprbuf[8],comprbuf[9],comprbuf[10],comprbuf[11], - comprbuf[12],comprbuf[13],comprbuf[14],comprbuf[15]); + comprbuf[0],comprbuf[1],comprbuf[2],comprbuf[3], + comprbuf[4],comprbuf[5],comprbuf[6],comprbuf[7], + comprbuf[8],comprbuf[9],comprbuf[10],comprbuf[11], + comprbuf[12],comprbuf[13],comprbuf[14],comprbuf[15]); ret = jffs2_decompress(comprtype, comprbuf, decomprbuf, c, d); printk("jffs2_decompress returned %d\n", ret); printk("Decompressed data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - decomprbuf[0],decomprbuf[1],decomprbuf[2],decomprbuf[3], - decomprbuf[4],decomprbuf[5],decomprbuf[6],decomprbuf[7], - decomprbuf[8],decomprbuf[9],decomprbuf[10],decomprbuf[11], - decomprbuf[12],decomprbuf[13],decomprbuf[14],decomprbuf[15]); + decomprbuf[0],decomprbuf[1],decomprbuf[2],decomprbuf[3], + decomprbuf[4],decomprbuf[5],decomprbuf[6],decomprbuf[7], + decomprbuf[8],decomprbuf[9],decomprbuf[10],decomprbuf[11], + decomprbuf[12],decomprbuf[13],decomprbuf[14],decomprbuf[15]); if (memcmp(decomprbuf, testdata, d)) printk("Compression and decompression corrupted data\n"); else diff --git a/fs/jffs2/debug.c b/fs/jffs2/debug.c new file mode 100644 index 0000000000000000000000000000000000000000..1fe17de713e86dabb250a5a471d8d57d0eec2f2a --- /dev/null +++ b/fs/jffs2/debug.c @@ -0,0 +1,705 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2001-2003 Red Hat, Inc. + * + * Created by David Woodhouse + * + * For licensing information, see the file 'LICENCE' in this directory. + * + * $Id: debug.c,v 1.12 2005/11/07 11:14:39 gleixner Exp $ + * + */ +#include +#include +#include +#include +#include +#include +#include "nodelist.h" +#include "debug.h" + +#ifdef JFFS2_DBG_SANITY_CHECKS + +void +__jffs2_dbg_acct_sanity_check_nolock(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb) +{ + if (unlikely(jeb && jeb->used_size + jeb->dirty_size + + jeb->free_size + jeb->wasted_size + + jeb->unchecked_size != c->sector_size)) { + JFFS2_ERROR("eeep, space accounting for block at 0x%08x is screwed.\n", jeb->offset); + JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n", + jeb->free_size, jeb->dirty_size, jeb->used_size, + jeb->wasted_size, jeb->unchecked_size, c->sector_size); + BUG(); + } + + if (unlikely(c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size + + c->wasted_size + c->unchecked_size != c->flash_size)) { + JFFS2_ERROR("eeep, space accounting superblock info is screwed.\n"); + JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + erasing %#08x + bad %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n", + c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size, + c->wasted_size, c->unchecked_size, c->flash_size); + BUG(); + } +} + +void +__jffs2_dbg_acct_sanity_check(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb) +{ + spin_lock(&c->erase_completion_lock); + jffs2_dbg_acct_sanity_check_nolock(c, jeb); + spin_unlock(&c->erase_completion_lock); +} + +#endif /* JFFS2_DBG_SANITY_CHECKS */ + +#ifdef JFFS2_DBG_PARANOIA_CHECKS +/* + * Check the fragtree. + */ +void +__jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f) +{ + down(&f->sem); + __jffs2_dbg_fragtree_paranoia_check_nolock(f); + up(&f->sem); +} + +void +__jffs2_dbg_fragtree_paranoia_check_nolock(struct jffs2_inode_info *f) +{ + struct jffs2_node_frag *frag; + int bitched = 0; + + for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) { + struct jffs2_full_dnode *fn = frag->node; + + if (!fn || !fn->raw) + continue; + + if (ref_flags(fn->raw) == REF_PRISTINE) { + if (fn->frags > 1) { + JFFS2_ERROR("REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2.\n", + ref_offset(fn->raw), fn->frags); + bitched = 1; + } + + /* A hole node which isn't multi-page should be garbage-collected + and merged anyway, so we just check for the frag size here, + rather than mucking around with actually reading the node + and checking the compression type, which is the real way + to tell a hole node. */ + if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) + && frag_prev(frag)->size < PAGE_CACHE_SIZE && frag_prev(frag)->node) { + JFFS2_ERROR("REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2.\n", + ref_offset(fn->raw)); + bitched = 1; + } + + if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) + && frag_next(frag)->size < PAGE_CACHE_SIZE && frag_next(frag)->node) { + JFFS2_ERROR("REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2.\n", + ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size); + bitched = 1; + } + } + } + + if (bitched) { + JFFS2_ERROR("fragtree is corrupted.\n"); + __jffs2_dbg_dump_fragtree_nolock(f); + BUG(); + } +} + +/* + * Check if the flash contains all 0xFF before we start writing. + */ +void +__jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c, + uint32_t ofs, int len) +{ + size_t retlen; + int ret, i; + unsigned char *buf; + + buf = kmalloc(len, GFP_KERNEL); + if (!buf) + return; + + ret = jffs2_flash_read(c, ofs, len, &retlen, buf); + if (ret || (retlen != len)) { + JFFS2_WARNING("read %d bytes failed or short. ret %d, retlen %zd.\n", + len, ret, retlen); + kfree(buf); + return; + } + + ret = 0; + for (i = 0; i < len; i++) + if (buf[i] != 0xff) + ret = 1; + + if (ret) { + JFFS2_ERROR("argh, about to write node to %#08x on flash, but there are data already there. The first corrupted byte is at %#08x offset.\n", + ofs, ofs + i); + __jffs2_dbg_dump_buffer(buf, len, ofs); + kfree(buf); + BUG(); + } + + kfree(buf); +} + +/* + * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'. + */ +void +__jffs2_dbg_acct_paranoia_check(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb) +{ + spin_lock(&c->erase_completion_lock); + __jffs2_dbg_acct_paranoia_check_nolock(c, jeb); + spin_unlock(&c->erase_completion_lock); +} + +void +__jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb) +{ + uint32_t my_used_size = 0; + uint32_t my_unchecked_size = 0; + uint32_t my_dirty_size = 0; + struct jffs2_raw_node_ref *ref2 = jeb->first_node; + + while (ref2) { + uint32_t totlen = ref_totlen(c, jeb, ref2); + + if (ref2->flash_offset < jeb->offset || + ref2->flash_offset > jeb->offset + c->sector_size) { + JFFS2_ERROR("node_ref %#08x shouldn't be in block at %#08x.\n", + ref_offset(ref2), jeb->offset); + goto error; + + } + if (ref_flags(ref2) == REF_UNCHECKED) + my_unchecked_size += totlen; + else if (!ref_obsolete(ref2)) + my_used_size += totlen; + else + my_dirty_size += totlen; + + if ((!ref2->next_phys) != (ref2 == jeb->last_node)) { + JFFS2_ERROR("node_ref for node at %#08x (mem %p) has next_phys at %#08x (mem %p), last_node is at %#08x (mem %p).\n", + ref_offset(ref2), ref2, ref_offset(ref2->next_phys), ref2->next_phys, + ref_offset(jeb->last_node), jeb->last_node); + goto error; + } + ref2 = ref2->next_phys; + } + + if (my_used_size != jeb->used_size) { + JFFS2_ERROR("Calculated used size %#08x != stored used size %#08x.\n", + my_used_size, jeb->used_size); + goto error; + } + + if (my_unchecked_size != jeb->unchecked_size) { + JFFS2_ERROR("Calculated unchecked size %#08x != stored unchecked size %#08x.\n", + my_unchecked_size, jeb->unchecked_size); + goto error; + } + +#if 0 + /* This should work when we implement ref->__totlen elemination */ + if (my_dirty_size != jeb->dirty_size + jeb->wasted_size) { + JFFS2_ERROR("Calculated dirty+wasted size %#08x != stored dirty + wasted size %#08x\n", + my_dirty_size, jeb->dirty_size + jeb->wasted_size); + goto error; + } + + if (jeb->free_size == 0 + && my_used_size + my_unchecked_size + my_dirty_size != c->sector_size) { + JFFS2_ERROR("The sum of all nodes in block (%#x) != size of block (%#x)\n", + my_used_size + my_unchecked_size + my_dirty_size, + c->sector_size); + goto error; + } +#endif + + return; + +error: + __jffs2_dbg_dump_node_refs_nolock(c, jeb); + __jffs2_dbg_dump_jeb_nolock(jeb); + __jffs2_dbg_dump_block_lists_nolock(c); + BUG(); + +} +#endif /* JFFS2_DBG_PARANOIA_CHECKS */ + +#if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS) +/* + * Dump the node_refs of the 'jeb' JFFS2 eraseblock. + */ +void +__jffs2_dbg_dump_node_refs(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb) +{ + spin_lock(&c->erase_completion_lock); + __jffs2_dbg_dump_node_refs_nolock(c, jeb); + spin_unlock(&c->erase_completion_lock); +} + +void +__jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb) +{ + struct jffs2_raw_node_ref *ref; + int i = 0; + + printk(JFFS2_DBG_MSG_PREFIX " Dump node_refs of the eraseblock %#08x\n", jeb->offset); + if (!jeb->first_node) { + printk(JFFS2_DBG_MSG_PREFIX " no nodes in the eraseblock %#08x\n", jeb->offset); + return; + } + + printk(JFFS2_DBG); + for (ref = jeb->first_node; ; ref = ref->next_phys) { + printk("%#08x(%#x)", ref_offset(ref), ref->__totlen); + if (ref->next_phys) + printk("->"); + else + break; + if (++i == 4) { + i = 0; + printk("\n" JFFS2_DBG); + } + } + printk("\n"); +} + +/* + * Dump an eraseblock's space accounting. + */ +void +__jffs2_dbg_dump_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) +{ + spin_lock(&c->erase_completion_lock); + __jffs2_dbg_dump_jeb_nolock(jeb); + spin_unlock(&c->erase_completion_lock); +} + +void +__jffs2_dbg_dump_jeb_nolock(struct jffs2_eraseblock *jeb) +{ + if (!jeb) + return; + + printk(JFFS2_DBG_MSG_PREFIX " dump space accounting for the eraseblock at %#08x:\n", + jeb->offset); + + printk(JFFS2_DBG "used_size: %#08x\n", jeb->used_size); + printk(JFFS2_DBG "dirty_size: %#08x\n", jeb->dirty_size); + printk(JFFS2_DBG "wasted_size: %#08x\n", jeb->wasted_size); + printk(JFFS2_DBG "unchecked_size: %#08x\n", jeb->unchecked_size); + printk(JFFS2_DBG "free_size: %#08x\n", jeb->free_size); +} + +void +__jffs2_dbg_dump_block_lists(struct jffs2_sb_info *c) +{ + spin_lock(&c->erase_completion_lock); + __jffs2_dbg_dump_block_lists_nolock(c); + spin_unlock(&c->erase_completion_lock); +} + +void +__jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c) +{ + printk(JFFS2_DBG_MSG_PREFIX " dump JFFS2 blocks lists:\n"); + + printk(JFFS2_DBG "flash_size: %#08x\n", c->flash_size); + printk(JFFS2_DBG "used_size: %#08x\n", c->used_size); + printk(JFFS2_DBG "dirty_size: %#08x\n", c->dirty_size); + printk(JFFS2_DBG "wasted_size: %#08x\n", c->wasted_size); + printk(JFFS2_DBG "unchecked_size: %#08x\n", c->unchecked_size); + printk(JFFS2_DBG "free_size: %#08x\n", c->free_size); + printk(JFFS2_DBG "erasing_size: %#08x\n", c->erasing_size); + printk(JFFS2_DBG "bad_size: %#08x\n", c->bad_size); + printk(JFFS2_DBG "sector_size: %#08x\n", c->sector_size); + printk(JFFS2_DBG "jffs2_reserved_blocks size: %#08x\n", + c->sector_size * c->resv_blocks_write); + + if (c->nextblock) + printk(JFFS2_DBG "nextblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", + c->nextblock->offset, c->nextblock->used_size, + c->nextblock->dirty_size, c->nextblock->wasted_size, + c->nextblock->unchecked_size, c->nextblock->free_size); + else + printk(JFFS2_DBG "nextblock: NULL\n"); + + if (c->gcblock) + printk(JFFS2_DBG "gcblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", + c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size, + c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size); + else + printk(JFFS2_DBG "gcblock: NULL\n"); + + if (list_empty(&c->clean_list)) { + printk(JFFS2_DBG "clean_list: empty\n"); + } else { + struct list_head *this; + int numblocks = 0; + uint32_t dirty = 0; + + list_for_each(this, &c->clean_list) { + struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); + numblocks ++; + dirty += jeb->wasted_size; + if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { + printk(JFFS2_DBG "clean_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", + jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, + jeb->unchecked_size, jeb->free_size); + } + } + + printk (JFFS2_DBG "Contains %d blocks with total wasted size %u, average wasted size: %u\n", + numblocks, dirty, dirty / numblocks); + } + + if (list_empty(&c->very_dirty_list)) { + printk(JFFS2_DBG "very_dirty_list: empty\n"); + } else { + struct list_head *this; + int numblocks = 0; + uint32_t dirty = 0; + + list_for_each(this, &c->very_dirty_list) { + struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); + + numblocks ++; + dirty += jeb->dirty_size; + if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { + printk(JFFS2_DBG "very_dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", + jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, + jeb->unchecked_size, jeb->free_size); + } + } + + printk (JFFS2_DBG "Contains %d blocks with total dirty size %u, average dirty size: %u\n", + numblocks, dirty, dirty / numblocks); + } + + if (list_empty(&c->dirty_list)) { + printk(JFFS2_DBG "dirty_list: empty\n"); + } else { + struct list_head *this; + int numblocks = 0; + uint32_t dirty = 0; + + list_for_each(this, &c->dirty_list) { + struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); + + numblocks ++; + dirty += jeb->dirty_size; + if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { + printk(JFFS2_DBG "dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", + jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, + jeb->unchecked_size, jeb->free_size); + } + } + + printk (JFFS2_DBG "contains %d blocks with total dirty size %u, average dirty size: %u\n", + numblocks, dirty, dirty / numblocks); + } + + if (list_empty(&c->erasable_list)) { + printk(JFFS2_DBG "erasable_list: empty\n"); + } else { + struct list_head *this; + + list_for_each(this, &c->erasable_list) { + struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); + + if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { + printk(JFFS2_DBG "erasable_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", + jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, + jeb->unchecked_size, jeb->free_size); + } + } + } + + if (list_empty(&c->erasing_list)) { + printk(JFFS2_DBG "erasing_list: empty\n"); + } else { + struct list_head *this; + + list_for_each(this, &c->erasing_list) { + struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); + + if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { + printk(JFFS2_DBG "erasing_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", + jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, + jeb->unchecked_size, jeb->free_size); + } + } + } + + if (list_empty(&c->erase_pending_list)) { + printk(JFFS2_DBG "erase_pending_list: empty\n"); + } else { + struct list_head *this; + + list_for_each(this, &c->erase_pending_list) { + struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); + + if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { + printk(JFFS2_DBG "erase_pending_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", + jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, + jeb->unchecked_size, jeb->free_size); + } + } + } + + if (list_empty(&c->erasable_pending_wbuf_list)) { + printk(JFFS2_DBG "erasable_pending_wbuf_list: empty\n"); + } else { + struct list_head *this; + + list_for_each(this, &c->erasable_pending_wbuf_list) { + struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); + + if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { + printk(JFFS2_DBG "erasable_pending_wbuf_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", + jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, + jeb->unchecked_size, jeb->free_size); + } + } + } + + if (list_empty(&c->free_list)) { + printk(JFFS2_DBG "free_list: empty\n"); + } else { + struct list_head *this; + + list_for_each(this, &c->free_list) { + struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); + + if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { + printk(JFFS2_DBG "free_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", + jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, + jeb->unchecked_size, jeb->free_size); + } + } + } + + if (list_empty(&c->bad_list)) { + printk(JFFS2_DBG "bad_list: empty\n"); + } else { + struct list_head *this; + + list_for_each(this, &c->bad_list) { + struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); + + if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { + printk(JFFS2_DBG "bad_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", + jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, + jeb->unchecked_size, jeb->free_size); + } + } + } + + if (list_empty(&c->bad_used_list)) { + printk(JFFS2_DBG "bad_used_list: empty\n"); + } else { + struct list_head *this; + + list_for_each(this, &c->bad_used_list) { + struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); + + if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { + printk(JFFS2_DBG "bad_used_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", + jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, + jeb->unchecked_size, jeb->free_size); + } + } + } +} + +void +__jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f) +{ + down(&f->sem); + jffs2_dbg_dump_fragtree_nolock(f); + up(&f->sem); +} + +void +__jffs2_dbg_dump_fragtree_nolock(struct jffs2_inode_info *f) +{ + struct jffs2_node_frag *this = frag_first(&f->fragtree); + uint32_t lastofs = 0; + int buggy = 0; + + printk(JFFS2_DBG_MSG_PREFIX " dump fragtree of ino #%u\n", f->inocache->ino); + while(this) { + if (this->node) + printk(JFFS2_DBG "frag %#04x-%#04x: %#08x(%d) on flash (*%p), left (%p), right (%p), parent (%p)\n", + this->ofs, this->ofs+this->size, ref_offset(this->node->raw), + ref_flags(this->node->raw), this, frag_left(this), frag_right(this), + frag_parent(this)); + else + printk(JFFS2_DBG "frag %#04x-%#04x: hole (*%p). left (%p), right (%p), parent (%p)\n", + this->ofs, this->ofs+this->size, this, frag_left(this), + frag_right(this), frag_parent(this)); + if (this->ofs != lastofs) + buggy = 1; + lastofs = this->ofs + this->size; + this = frag_next(this); + } + + if (f->metadata) + printk(JFFS2_DBG "metadata at 0x%08x\n", ref_offset(f->metadata->raw)); + + if (buggy) { + JFFS2_ERROR("frag tree got a hole in it.\n"); + BUG(); + } +} + +#define JFFS2_BUFDUMP_BYTES_PER_LINE 32 +void +__jffs2_dbg_dump_buffer(unsigned char *buf, int len, uint32_t offs) +{ + int skip; + int i; + + printk(JFFS2_DBG_MSG_PREFIX " dump from offset %#08x to offset %#08x (%x bytes).\n", + offs, offs + len, len); + i = skip = offs % JFFS2_BUFDUMP_BYTES_PER_LINE; + offs = offs & ~(JFFS2_BUFDUMP_BYTES_PER_LINE - 1); + + if (skip != 0) + printk(JFFS2_DBG "%#08x: ", offs); + + while (skip--) + printk(" "); + + while (i < len) { + if ((i % JFFS2_BUFDUMP_BYTES_PER_LINE) == 0 && i != len -1) { + if (i != 0) + printk("\n"); + offs += JFFS2_BUFDUMP_BYTES_PER_LINE; + printk(JFFS2_DBG "%0#8x: ", offs); + } + + printk("%02x ", buf[i]); + + i += 1; + } + + printk("\n"); +} + +/* + * Dump a JFFS2 node. + */ +void +__jffs2_dbg_dump_node(struct jffs2_sb_info *c, uint32_t ofs) +{ + union jffs2_node_union node; + int len = sizeof(union jffs2_node_union); + size_t retlen; + uint32_t crc; + int ret; + + printk(JFFS2_DBG_MSG_PREFIX " dump node at offset %#08x.\n", ofs); + + ret = jffs2_flash_read(c, ofs, len, &retlen, (unsigned char *)&node); + if (ret || (retlen != len)) { + JFFS2_ERROR("read %d bytes failed or short. ret %d, retlen %zd.\n", + len, ret, retlen); + return; + } + + printk(JFFS2_DBG "magic:\t%#04x\n", je16_to_cpu(node.u.magic)); + printk(JFFS2_DBG "nodetype:\t%#04x\n", je16_to_cpu(node.u.nodetype)); + printk(JFFS2_DBG "totlen:\t%#08x\n", je32_to_cpu(node.u.totlen)); + printk(JFFS2_DBG "hdr_crc:\t%#08x\n", je32_to_cpu(node.u.hdr_crc)); + + crc = crc32(0, &node.u, sizeof(node.u) - 4); + if (crc != je32_to_cpu(node.u.hdr_crc)) { + JFFS2_ERROR("wrong common header CRC.\n"); + return; + } + + if (je16_to_cpu(node.u.magic) != JFFS2_MAGIC_BITMASK && + je16_to_cpu(node.u.magic) != JFFS2_OLD_MAGIC_BITMASK) + { + JFFS2_ERROR("wrong node magic: %#04x instead of %#04x.\n", + je16_to_cpu(node.u.magic), JFFS2_MAGIC_BITMASK); + return; + } + + switch(je16_to_cpu(node.u.nodetype)) { + + case JFFS2_NODETYPE_INODE: + + printk(JFFS2_DBG "the node is inode node\n"); + printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.i.ino)); + printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.i.version)); + printk(JFFS2_DBG "mode:\t%#08x\n", node.i.mode.m); + printk(JFFS2_DBG "uid:\t%#04x\n", je16_to_cpu(node.i.uid)); + printk(JFFS2_DBG "gid:\t%#04x\n", je16_to_cpu(node.i.gid)); + printk(JFFS2_DBG "isize:\t%#08x\n", je32_to_cpu(node.i.isize)); + printk(JFFS2_DBG "atime:\t%#08x\n", je32_to_cpu(node.i.atime)); + printk(JFFS2_DBG "mtime:\t%#08x\n", je32_to_cpu(node.i.mtime)); + printk(JFFS2_DBG "ctime:\t%#08x\n", je32_to_cpu(node.i.ctime)); + printk(JFFS2_DBG "offset:\t%#08x\n", je32_to_cpu(node.i.offset)); + printk(JFFS2_DBG "csize:\t%#08x\n", je32_to_cpu(node.i.csize)); + printk(JFFS2_DBG "dsize:\t%#08x\n", je32_to_cpu(node.i.dsize)); + printk(JFFS2_DBG "compr:\t%#02x\n", node.i.compr); + printk(JFFS2_DBG "usercompr:\t%#02x\n", node.i.usercompr); + printk(JFFS2_DBG "flags:\t%#04x\n", je16_to_cpu(node.i.flags)); + printk(JFFS2_DBG "data_crc:\t%#08x\n", je32_to_cpu(node.i.data_crc)); + printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.i.node_crc)); + + crc = crc32(0, &node.i, sizeof(node.i) - 8); + if (crc != je32_to_cpu(node.i.node_crc)) { + JFFS2_ERROR("wrong node header CRC.\n"); + return; + } + break; + + case JFFS2_NODETYPE_DIRENT: + + printk(JFFS2_DBG "the node is dirent node\n"); + printk(JFFS2_DBG "pino:\t%#08x\n", je32_to_cpu(node.d.pino)); + printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.d.version)); + printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.d.ino)); + printk(JFFS2_DBG "mctime:\t%#08x\n", je32_to_cpu(node.d.mctime)); + printk(JFFS2_DBG "nsize:\t%#02x\n", node.d.nsize); + printk(JFFS2_DBG "type:\t%#02x\n", node.d.type); + printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.d.node_crc)); + printk(JFFS2_DBG "name_crc:\t%#08x\n", je32_to_cpu(node.d.name_crc)); + + node.d.name[node.d.nsize] = '\0'; + printk(JFFS2_DBG "name:\t\"%s\"\n", node.d.name); + + crc = crc32(0, &node.d, sizeof(node.d) - 8); + if (crc != je32_to_cpu(node.d.node_crc)) { + JFFS2_ERROR("wrong node header CRC.\n"); + return; + } + break; + + default: + printk(JFFS2_DBG "node type is unknown\n"); + break; + } +} +#endif /* JFFS2_DBG_DUMPS || JFFS2_DBG_PARANOIA_CHECKS */ diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h new file mode 100644 index 0000000000000000000000000000000000000000..f193d43a8a595a14dbe2bbe67b5815365357e452 --- /dev/null +++ b/fs/jffs2/debug.h @@ -0,0 +1,279 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2001-2003 Red Hat, Inc. + * + * Created by David Woodhouse + * + * For licensing information, see the file 'LICENCE' in this directory. + * + * $Id: debug.h,v 1.21 2005/11/07 11:14:39 gleixner Exp $ + * + */ +#ifndef _JFFS2_DEBUG_H_ +#define _JFFS2_DEBUG_H_ + +#include + +#ifndef CONFIG_JFFS2_FS_DEBUG +#define CONFIG_JFFS2_FS_DEBUG 0 +#endif + +#if CONFIG_JFFS2_FS_DEBUG > 0 +/* Enable "paranoia" checks and dumps */ +#define JFFS2_DBG_PARANOIA_CHECKS +#define JFFS2_DBG_DUMPS + +/* + * By defining/undefining the below macros one may select debugging messages + * fro specific JFFS2 subsystems. + */ +#define JFFS2_DBG_READINODE_MESSAGES +#define JFFS2_DBG_FRAGTREE_MESSAGES +#define JFFS2_DBG_DENTLIST_MESSAGES +#define JFFS2_DBG_NODEREF_MESSAGES +#define JFFS2_DBG_INOCACHE_MESSAGES +#define JFFS2_DBG_SUMMARY_MESSAGES +#define JFFS2_DBG_FSBUILD_MESSAGES +#endif + +#if CONFIG_JFFS2_FS_DEBUG > 1 +#define JFFS2_DBG_FRAGTREE2_MESSAGES +#define JFFS2_DBG_MEMALLOC_MESSAGES +#endif + +/* Sanity checks are supposed to be light-weight and enabled by default */ +#define JFFS2_DBG_SANITY_CHECKS + +/* + * Dx() are mainly used for debugging messages, they must go away and be + * superseded by nicer dbg_xxx() macros... + */ +#if CONFIG_JFFS2_FS_DEBUG > 0 +#define D1(x) x +#else +#define D1(x) +#endif + +#if CONFIG_JFFS2_FS_DEBUG > 1 +#define D2(x) x +#else +#define D2(x) +#endif + +/* The prefixes of JFFS2 messages */ +#define JFFS2_DBG_PREFIX "[JFFS2 DBG]" +#define JFFS2_ERR_PREFIX "JFFS2 error:" +#define JFFS2_WARN_PREFIX "JFFS2 warning:" +#define JFFS2_NOTICE_PREFIX "JFFS2 notice:" + +#define JFFS2_ERR KERN_ERR +#define JFFS2_WARN KERN_WARNING +#define JFFS2_NOT KERN_NOTICE +#define JFFS2_DBG KERN_DEBUG + +#define JFFS2_DBG_MSG_PREFIX JFFS2_DBG JFFS2_DBG_PREFIX +#define JFFS2_ERR_MSG_PREFIX JFFS2_ERR JFFS2_ERR_PREFIX +#define JFFS2_WARN_MSG_PREFIX JFFS2_WARN JFFS2_WARN_PREFIX +#define JFFS2_NOTICE_MSG_PREFIX JFFS2_NOT JFFS2_NOTICE_PREFIX + +/* JFFS2 message macros */ +#define JFFS2_ERROR(fmt, ...) \ + do { \ + printk(JFFS2_ERR_MSG_PREFIX \ + " (%d) %s: " fmt, current->pid, \ + __FUNCTION__, ##__VA_ARGS__); \ + } while(0) + +#define JFFS2_WARNING(fmt, ...) \ + do { \ + printk(JFFS2_WARN_MSG_PREFIX \ + " (%d) %s: " fmt, current->pid, \ + __FUNCTION__, ##__VA_ARGS__); \ + } while(0) + +#define JFFS2_NOTICE(fmt, ...) \ + do { \ + printk(JFFS2_NOTICE_MSG_PREFIX \ + " (%d) %s: " fmt, current->pid, \ + __FUNCTION__, ##__VA_ARGS__); \ + } while(0) + +#define JFFS2_DEBUG(fmt, ...) \ + do { \ + printk(JFFS2_DBG_MSG_PREFIX \ + " (%d) %s: " fmt, current->pid, \ + __FUNCTION__, ##__VA_ARGS__); \ + } while(0) + +/* + * We split our debugging messages on several parts, depending on the JFFS2 + * subsystem the message belongs to. + */ +/* Read inode debugging messages */ +#ifdef JFFS2_DBG_READINODE_MESSAGES +#define dbg_readinode(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) +#else +#define dbg_readinode(fmt, ...) +#endif + +/* Fragtree build debugging messages */ +#ifdef JFFS2_DBG_FRAGTREE_MESSAGES +#define dbg_fragtree(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) +#else +#define dbg_fragtree(fmt, ...) +#endif +#ifdef JFFS2_DBG_FRAGTREE2_MESSAGES +#define dbg_fragtree2(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) +#else +#define dbg_fragtree2(fmt, ...) +#endif + +/* Directory entry list manilulation debugging messages */ +#ifdef JFFS2_DBG_DENTLIST_MESSAGES +#define dbg_dentlist(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) +#else +#define dbg_dentlist(fmt, ...) +#endif + +/* Print the messages about manipulating node_refs */ +#ifdef JFFS2_DBG_NODEREF_MESSAGES +#define dbg_noderef(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) +#else +#define dbg_noderef(fmt, ...) +#endif + +/* Manipulations with the list of inodes (JFFS2 inocache) */ +#ifdef JFFS2_DBG_INOCACHE_MESSAGES +#define dbg_inocache(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) +#else +#define dbg_inocache(fmt, ...) +#endif + +/* Summary debugging messages */ +#ifdef JFFS2_DBG_SUMMARY_MESSAGES +#define dbg_summary(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) +#else +#define dbg_summary(fmt, ...) +#endif + +/* File system build messages */ +#ifdef JFFS2_DBG_FSBUILD_MESSAGES +#define dbg_fsbuild(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) +#else +#define dbg_fsbuild(fmt, ...) +#endif + +/* Watch the object allocations */ +#ifdef JFFS2_DBG_MEMALLOC_MESSAGES +#define dbg_memalloc(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) +#else +#define dbg_memalloc(fmt, ...) +#endif + + +/* "Sanity" checks */ +void +__jffs2_dbg_acct_sanity_check_nolock(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb); +void +__jffs2_dbg_acct_sanity_check(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb); + +/* "Paranoia" checks */ +void +__jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f); +void +__jffs2_dbg_fragtree_paranoia_check_nolock(struct jffs2_inode_info *f); +void +__jffs2_dbg_acct_paranoia_check(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb); +void +__jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb); +void +__jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c, + uint32_t ofs, int len); + +/* "Dump" functions */ +void +__jffs2_dbg_dump_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); +void +__jffs2_dbg_dump_jeb_nolock(struct jffs2_eraseblock *jeb); +void +__jffs2_dbg_dump_block_lists(struct jffs2_sb_info *c); +void +__jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c); +void +__jffs2_dbg_dump_node_refs(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb); +void +__jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb); +void +__jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f); +void +__jffs2_dbg_dump_fragtree_nolock(struct jffs2_inode_info *f); +void +__jffs2_dbg_dump_buffer(unsigned char *buf, int len, uint32_t offs); +void +__jffs2_dbg_dump_node(struct jffs2_sb_info *c, uint32_t ofs); + +#ifdef JFFS2_DBG_PARANOIA_CHECKS +#define jffs2_dbg_fragtree_paranoia_check(f) \ + __jffs2_dbg_fragtree_paranoia_check(f) +#define jffs2_dbg_fragtree_paranoia_check_nolock(f) \ + __jffs2_dbg_fragtree_paranoia_check_nolock(f) +#define jffs2_dbg_acct_paranoia_check(c, jeb) \ + __jffs2_dbg_acct_paranoia_check(c,jeb) +#define jffs2_dbg_acct_paranoia_check_nolock(c, jeb) \ + __jffs2_dbg_acct_paranoia_check_nolock(c,jeb) +#define jffs2_dbg_prewrite_paranoia_check(c, ofs, len) \ + __jffs2_dbg_prewrite_paranoia_check(c, ofs, len) +#else +#define jffs2_dbg_fragtree_paranoia_check(f) +#define jffs2_dbg_fragtree_paranoia_check_nolock(f) +#define jffs2_dbg_acct_paranoia_check(c, jeb) +#define jffs2_dbg_acct_paranoia_check_nolock(c, jeb) +#define jffs2_dbg_prewrite_paranoia_check(c, ofs, len) +#endif /* !JFFS2_PARANOIA_CHECKS */ + +#ifdef JFFS2_DBG_DUMPS +#define jffs2_dbg_dump_jeb(c, jeb) \ + __jffs2_dbg_dump_jeb(c, jeb); +#define jffs2_dbg_dump_jeb_nolock(jeb) \ + __jffs2_dbg_dump_jeb_nolock(jeb); +#define jffs2_dbg_dump_block_lists(c) \ + __jffs2_dbg_dump_block_lists(c) +#define jffs2_dbg_dump_block_lists_nolock(c) \ + __jffs2_dbg_dump_block_lists_nolock(c) +#define jffs2_dbg_dump_fragtree(f) \ + __jffs2_dbg_dump_fragtree(f); +#define jffs2_dbg_dump_fragtree_nolock(f) \ + __jffs2_dbg_dump_fragtree_nolock(f); +#define jffs2_dbg_dump_buffer(buf, len, offs) \ + __jffs2_dbg_dump_buffer(*buf, len, offs); +#define jffs2_dbg_dump_node(c, ofs) \ + __jffs2_dbg_dump_node(c, ofs); +#else +#define jffs2_dbg_dump_jeb(c, jeb) +#define jffs2_dbg_dump_jeb_nolock(jeb) +#define jffs2_dbg_dump_block_lists(c) +#define jffs2_dbg_dump_block_lists_nolock(c) +#define jffs2_dbg_dump_fragtree(f) +#define jffs2_dbg_dump_fragtree_nolock(f) +#define jffs2_dbg_dump_buffer(buf, len, offs) +#define jffs2_dbg_dump_node(c, ofs) +#endif /* !JFFS2_DBG_DUMPS */ + +#ifdef JFFS2_DBG_SANITY_CHECKS +#define jffs2_dbg_acct_sanity_check(c, jeb) \ + __jffs2_dbg_acct_sanity_check(c, jeb) +#define jffs2_dbg_acct_sanity_check_nolock(c, jeb) \ + __jffs2_dbg_acct_sanity_check_nolock(c, jeb) +#else +#define jffs2_dbg_acct_sanity_check(c, jeb) +#define jffs2_dbg_acct_sanity_check_nolock(c, jeb) +#endif /* !JFFS2_DBG_SANITY_CHECKS */ + +#endif /* _JFFS2_DEBUG_H_ */ diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 3ca0d25eef1d529f82da3ec83d1644c331d629f6..a7bf9cb2567fc20b763354d5abd4a8e197c63373 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: dir.c,v 1.86 2005/07/06 12:13:09 dwmw2 Exp $ + * $Id: dir.c,v 1.90 2005/11/07 11:14:39 gleixner Exp $ * */ @@ -64,7 +64,7 @@ struct inode_operations jffs2_dir_inode_operations = /* We keep the dirent list sorted in increasing order of name hash, - and we use the same hash function as the dentries. Makes this + and we use the same hash function as the dentries. Makes this nice and simple */ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, @@ -85,7 +85,7 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, /* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */ for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= target->d_name.hash; fd_list = fd_list->next) { - if (fd_list->nhash == target->d_name.hash && + if (fd_list->nhash == target->d_name.hash && (!fd || fd_list->version > fd->version) && strlen(fd_list->name) == target->d_name.len && !strncmp(fd_list->name, target->d_name.name, target->d_name.len)) { @@ -147,7 +147,7 @@ static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir) curofs++; /* First loop: curofs = 2; offset = 2 */ if (curofs < offset) { - D2(printk(KERN_DEBUG "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n", + D2(printk(KERN_DEBUG "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n", fd->name, fd->ino, fd->type, curofs, offset)); continue; } @@ -182,7 +182,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, ri = jffs2_alloc_raw_inode(); if (!ri) return -ENOMEM; - + c = JFFS2_SB_INFO(dir_i->i_sb); D1(printk(KERN_DEBUG "jffs2_create()\n")); @@ -203,7 +203,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, f = JFFS2_INODE_INFO(inode); dir_f = JFFS2_INODE_INFO(dir_i); - ret = jffs2_do_create(c, dir_f, f, ri, + ret = jffs2_do_create(c, dir_f, f, ri, dentry->d_name.name, dentry->d_name.len); if (ret) { @@ -232,11 +232,14 @@ static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry) struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(dentry->d_inode); int ret; + uint32_t now = get_seconds(); - ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name, - dentry->d_name.len, dead_f); + ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name, + dentry->d_name.len, dead_f, now); if (dead_f->inocache) dentry->d_inode->i_nlink = dead_f->inocache->nlink; + if (!ret) + dir_i->i_mtime = dir_i->i_ctime = ITIME(now); return ret; } /***********************************************************************/ @@ -249,6 +252,7 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); int ret; uint8_t type; + uint32_t now; /* Don't let people make hard links to bad inodes. */ if (!f->inocache) @@ -261,13 +265,15 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; if (!type) type = DT_REG; - ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len); + now = get_seconds(); + ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len, now); if (!ret) { down(&f->sem); old_dentry->d_inode->i_nlink = ++f->inocache->nlink; up(&f->sem); d_instantiate(dentry, old_dentry->d_inode); + dir_i->i_mtime = dir_i->i_ctime = ITIME(now); atomic_inc(&old_dentry->d_inode->i_count); } return ret; @@ -297,14 +303,15 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char if (!ri) return -ENOMEM; - + c = JFFS2_SB_INFO(dir_i->i_sb); - - /* Try to reserve enough space for both node and dirent. - * Just the node will do for now, though + + /* Try to reserve enough space for both node and dirent. + * Just the node will do for now, though */ namelen = dentry->d_name.len; - ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen, ALLOC_NORMAL); + ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen, + ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); if (ret) { jffs2_free_raw_inode(ri); @@ -331,7 +338,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char ri->compr = JFFS2_COMPR_NONE; ri->data_crc = cpu_to_je32(crc32(0, target, targetlen)); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); - + fn = jffs2_write_dnode(c, f, ri, target, targetlen, phys_ofs, ALLOC_NORMAL); jffs2_free_raw_inode(ri); @@ -344,9 +351,9 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char return PTR_ERR(fn); } - /* We use f->dents field to store the target path. */ - f->dents = kmalloc(targetlen + 1, GFP_KERNEL); - if (!f->dents) { + /* We use f->target field to store the target path. */ + f->target = kmalloc(targetlen + 1, GFP_KERNEL); + if (!f->target) { printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1); up(&f->sem); jffs2_complete_reservation(c); @@ -354,17 +361,18 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char return -ENOMEM; } - memcpy(f->dents, target, targetlen + 1); - D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->dents)); + memcpy(f->target, target, targetlen + 1); + D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->target)); - /* No data here. Only a metadata node, which will be + /* No data here. Only a metadata node, which will be obsoleted by the first data write */ f->metadata = fn; up(&f->sem); jffs2_complete_reservation(c); - ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); + ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, + ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); if (ret) { /* Eep. */ jffs2_clear_inode(inode); @@ -399,7 +407,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL); if (IS_ERR(fd)) { - /* dirent failed to write. Delete the inode normally + /* dirent failed to write. Delete the inode normally as if it were the final unlink() */ jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); @@ -442,14 +450,15 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) ri = jffs2_alloc_raw_inode(); if (!ri) return -ENOMEM; - + c = JFFS2_SB_INFO(dir_i->i_sb); - /* Try to reserve enough space for both node and dirent. - * Just the node will do for now, though + /* Try to reserve enough space for both node and dirent. + * Just the node will do for now, though */ namelen = dentry->d_name.len; - ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL); + ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL, + JFFS2_SUMMARY_INODE_SIZE); if (ret) { jffs2_free_raw_inode(ri); @@ -473,7 +482,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) ri->data_crc = cpu_to_je32(0); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); - + fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL); jffs2_free_raw_inode(ri); @@ -485,20 +494,21 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) jffs2_clear_inode(inode); return PTR_ERR(fn); } - /* No data here. Only a metadata node, which will be + /* No data here. Only a metadata node, which will be obsoleted by the first data write */ f->metadata = fn; up(&f->sem); jffs2_complete_reservation(c); - ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); + ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, + ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); if (ret) { /* Eep. */ jffs2_clear_inode(inode); return ret; } - + rd = jffs2_alloc_raw_dirent(); if (!rd) { /* Argh. Now we treat it like a normal delete */ @@ -525,9 +535,9 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL); - + if (IS_ERR(fd)) { - /* dirent failed to write. Delete the inode normally + /* dirent failed to write. Delete the inode normally as if it were the final unlink() */ jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); @@ -589,19 +599,20 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de ri = jffs2_alloc_raw_inode(); if (!ri) return -ENOMEM; - + c = JFFS2_SB_INFO(dir_i->i_sb); - + if (S_ISBLK(mode) || S_ISCHR(mode)) { dev = cpu_to_je16(old_encode_dev(rdev)); devlen = sizeof(dev); } - - /* Try to reserve enough space for both node and dirent. - * Just the node will do for now, though + + /* Try to reserve enough space for both node and dirent. + * Just the node will do for now, though */ namelen = dentry->d_name.len; - ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &phys_ofs, &alloclen, ALLOC_NORMAL); + ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &phys_ofs, &alloclen, + ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); if (ret) { jffs2_free_raw_inode(ri); @@ -627,7 +638,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de ri->compr = JFFS2_COMPR_NONE; ri->data_crc = cpu_to_je32(crc32(0, &dev, devlen)); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); - + fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, phys_ofs, ALLOC_NORMAL); jffs2_free_raw_inode(ri); @@ -639,14 +650,15 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de jffs2_clear_inode(inode); return PTR_ERR(fn); } - /* No data here. Only a metadata node, which will be + /* No data here. Only a metadata node, which will be obsoleted by the first data write */ f->metadata = fn; up(&f->sem); jffs2_complete_reservation(c); - ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); + ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, + ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); if (ret) { /* Eep. */ jffs2_clear_inode(inode); @@ -682,9 +694,9 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL); - + if (IS_ERR(fd)) { - /* dirent failed to write. Delete the inode normally + /* dirent failed to write. Delete the inode normally as if it were the final unlink() */ jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); @@ -716,8 +728,9 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); struct jffs2_inode_info *victim_f = NULL; uint8_t type; + uint32_t now; - /* The VFS will check for us and prevent trying to rename a + /* The VFS will check for us and prevent trying to rename a * file over a directory and vice versa, but if it's a directory, * the VFS can't check whether the victim is empty. The filesystem * needs to do that for itself. @@ -739,19 +752,20 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, } /* XXX: We probably ought to alloc enough space for - both nodes at the same time. Writing the new link, + both nodes at the same time. Writing the new link, then getting -ENOSPC, is quite bad :) */ /* Make a hard link */ - + /* XXX: This is ugly */ type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; if (!type) type = DT_REG; - ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), + now = get_seconds(); + ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), old_dentry->d_inode->i_ino, type, - new_dentry->d_name.name, new_dentry->d_name.len); + new_dentry->d_name.name, new_dentry->d_name.len, now); if (ret) return ret; @@ -768,14 +782,14 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, } } - /* If it was a directory we moved, and there was no victim, + /* If it was a directory we moved, and there was no victim, increase i_nlink on its new parent */ if (S_ISDIR(old_dentry->d_inode->i_mode) && !victim_f) new_dir_i->i_nlink++; /* Unlink the original */ - ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), - old_dentry->d_name.name, old_dentry->d_name.len, NULL); + ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), + old_dentry->d_name.name, old_dentry->d_name.len, NULL, now); /* We don't touch inode->i_nlink */ @@ -792,12 +806,15 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, /* Might as well let the VFS know */ d_instantiate(new_dentry, old_dentry->d_inode); atomic_inc(&old_dentry->d_inode->i_count); + new_dir_i->i_mtime = new_dir_i->i_ctime = ITIME(now); return ret; } if (S_ISDIR(old_dentry->d_inode->i_mode)) old_dir_i->i_nlink--; + new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now); + return 0; } diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index 787d84ac2bcdaf580b9f9134124a09702aacdfd8..dad68fdffe9e3e3ac8662fcc1a98dd19126b0152 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: erase.c,v 1.80 2005/07/14 19:46:24 joern Exp $ + * $Id: erase.c,v 1.85 2005/09/20 14:53:15 dedekind Exp $ * */ @@ -24,7 +24,7 @@ struct erase_priv_struct { struct jffs2_eraseblock *jeb; struct jffs2_sb_info *c; }; - + #ifndef __ECOS static void jffs2_erase_callback(struct erase_info *); #endif @@ -48,7 +48,8 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, #else /* Linux */ struct erase_info *instr; - D1(printk(KERN_DEBUG "jffs2_erase_block(): erase block %#x (range %#x-%#x)\n", jeb->offset, jeb->offset, jeb->offset + c->sector_size)); + D1(printk(KERN_DEBUG "jffs2_erase_block(): erase block %#08x (range %#08x-%#08x)\n", + jeb->offset, jeb->offset, jeb->offset + c->sector_size)); instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); if (!instr) { printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); @@ -70,7 +71,7 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, instr->callback = jffs2_erase_callback; instr->priv = (unsigned long)(&instr[1]); instr->fail_addr = 0xffffffff; - + ((struct erase_priv_struct *)instr->priv)->jeb = jeb; ((struct erase_priv_struct *)instr->priv)->c = c; @@ -95,7 +96,7 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, return; } - if (ret == -EROFS) + if (ret == -EROFS) printk(KERN_WARNING "Erase at 0x%08x failed immediately: -EROFS. Is the sector locked?\n", jeb->offset); else printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %d\n", jeb->offset, ret); @@ -196,7 +197,7 @@ static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock c->nr_erasing_blocks--; spin_unlock(&c->erase_completion_lock); wake_up(&c->erase_wait); -} +} #ifndef __ECOS static void jffs2_erase_callback(struct erase_info *instr) @@ -208,7 +209,7 @@ static void jffs2_erase_callback(struct erase_info *instr) jffs2_erase_failed(priv->c, priv->jeb, instr->fail_addr); } else { jffs2_erase_succeeded(priv->c, priv->jeb); - } + } kfree(instr); } #endif /* !__ECOS */ @@ -226,13 +227,13 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, /* Walk the inode's list once, removing any nodes from this eraseblock */ while (1) { if (!(*prev)->next_in_ino) { - /* We're looking at the jffs2_inode_cache, which is + /* We're looking at the jffs2_inode_cache, which is at the end of the linked list. Stash it and continue from the beginning of the list */ ic = (struct jffs2_inode_cache *)(*prev); prev = &ic->nodes; continue; - } + } if (SECTOR_ADDR((*prev)->flash_offset) == jeb->offset) { /* It's in the block we're erasing */ @@ -266,7 +267,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, printk(KERN_DEBUG "After remove_node_refs_from_ino_list: \n" KERN_DEBUG); this = ic->nodes; - + while(this) { printk( "0x%08x(%d)->", ref_offset(this), ref_flags(this)); if (++i == 5) { @@ -289,7 +290,7 @@ static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_erase while(jeb->first_node) { ref = jeb->first_node; jeb->first_node = ref->next_phys; - + /* Remove from the inode-list */ if (ref->next_in_ino) jffs2_remove_node_refs_from_ino_list(c, ref, jeb); @@ -306,7 +307,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl uint32_t ofs; size_t retlen; int ret = -EIO; - + ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!ebuf) { printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Refiling\n", jeb->offset); @@ -360,7 +361,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb case -EIO: goto filebad; } - /* Write the erase complete marker */ + /* Write the erase complete marker */ D1(printk(KERN_DEBUG "Writing erased marker to block at 0x%08x\n", jeb->offset)); bad_offset = jeb->offset; @@ -398,7 +399,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb vecs[0].iov_base = (unsigned char *) ▮ vecs[0].iov_len = sizeof(marker); ret = jffs2_flash_direct_writev(c, vecs, 1, jeb->offset, &retlen); - + if (ret || retlen != sizeof(marker)) { if (ret) printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n", @@ -415,9 +416,9 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb marker_ref->next_phys = NULL; marker_ref->flash_offset = jeb->offset | REF_NORMAL; marker_ref->__totlen = c->cleanmarker_size; - + jeb->first_node = jeb->last_node = marker_ref; - + jeb->free_size = c->sector_size - c->cleanmarker_size; jeb->used_size = c->cleanmarker_size; jeb->dirty_size = 0; @@ -429,8 +430,8 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb c->free_size += jeb->free_size; c->used_size += jeb->used_size; - ACCT_SANITY_CHECK(c,jeb); - D1(ACCT_PARANOIA_CHECK(jeb)); + jffs2_dbg_acct_sanity_check_nolock(c,jeb); + jffs2_dbg_acct_paranoia_check_nolock(c, jeb); list_add_tail(&jeb->list, &c->free_list); c->nr_erasing_blocks--; diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 8279bf0133ff573549c0570b707a447042fa4cf9..935f273dc57b834bcb7491d8a099522653f19ce7 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: file.c,v 1.102 2005/07/06 12:13:09 dwmw2 Exp $ + * $Id: file.c,v 1.104 2005/10/18 23:29:35 tpoynor Exp $ * */ @@ -34,8 +34,8 @@ int jffs2_fsync(struct file *filp, struct dentry *dentry, int datasync) /* Trigger GC to flush any pending writes for this inode */ jffs2_flush_wbuf_gc(c, inode->i_ino); - - return 0; + + return 0; } struct file_operations jffs2_file_operations = @@ -107,7 +107,7 @@ static int jffs2_readpage (struct file *filp, struct page *pg) { struct jffs2_inode_info *f = JFFS2_INODE_INFO(pg->mapping->host); int ret; - + down(&f->sem); ret = jffs2_do_readpage_unlock(pg->mapping->host, pg); up(&f->sem); @@ -130,11 +130,12 @@ static int jffs2_prepare_write (struct file *filp, struct page *pg, struct jffs2_raw_inode ri; struct jffs2_full_dnode *fn; uint32_t phys_ofs, alloc_len; - + D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n", (unsigned int)inode->i_size, pageofs)); - ret = jffs2_reserve_space(c, sizeof(ri), &phys_ofs, &alloc_len, ALLOC_NORMAL); + ret = jffs2_reserve_space(c, sizeof(ri), &phys_ofs, &alloc_len, + ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); if (ret) return ret; @@ -159,7 +160,7 @@ static int jffs2_prepare_write (struct file *filp, struct page *pg, ri.compr = JFFS2_COMPR_ZERO; ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); ri.data_crc = cpu_to_je32(0); - + fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, ALLOC_NORMAL); if (IS_ERR(fn)) { @@ -186,7 +187,7 @@ static int jffs2_prepare_write (struct file *filp, struct page *pg, inode->i_size = pageofs; up(&f->sem); } - + /* Read in the page if it wasn't already present, unless it's a whole page */ if (!PageUptodate(pg) && (start || end < PAGE_CACHE_SIZE)) { down(&f->sem); @@ -217,7 +218,7 @@ static int jffs2_commit_write (struct file *filp, struct page *pg, if (!start && end == PAGE_CACHE_SIZE) { /* We need to avoid deadlock with page_cache_read() in jffs2_garbage_collect_pass(). So we have to mark the - page up to date, to prevent page_cache_read() from + page up to date, to prevent page_cache_read() from trying to re-lock it. */ SetPageUptodate(pg); } @@ -251,7 +252,7 @@ static int jffs2_commit_write (struct file *filp, struct page *pg, /* There was an error writing. */ SetPageError(pg); } - + /* Adjust writtenlen for the padding we did, so we don't confuse our caller */ if (writtenlen < (start&3)) writtenlen = 0; @@ -262,7 +263,7 @@ static int jffs2_commit_write (struct file *filp, struct page *pg, if (inode->i_size < (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen) { inode->i_size = (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen; inode->i_blocks = (inode->i_size + 511) >> 9; - + inode->i_ctime = inode->i_mtime = ITIME(je32_to_cpu(ri->ctime)); } } @@ -271,13 +272,13 @@ static int jffs2_commit_write (struct file *filp, struct page *pg, if (start+writtenlen < end) { /* generic_file_write has written more to the page cache than we've - actually written to the medium. Mark the page !Uptodate so that + actually written to the medium. Mark the page !Uptodate so that it gets reread */ D1(printk(KERN_DEBUG "jffs2_commit_write(): Not all bytes written. Marking page !uptodate\n")); SetPageError(pg); ClearPageUptodate(pg); } - D1(printk(KERN_DEBUG "jffs2_commit_write() returning %d\n",writtenlen?writtenlen:ret)); - return writtenlen?writtenlen:ret; + D1(printk(KERN_DEBUG "jffs2_commit_write() returning %d\n",start+writtenlen==end?0:ret)); + return start+writtenlen==end?0:ret; } diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 5687c3f42002bf83e63b1caa95cbb354aa214bd5..543420665c5be2f641eacc6fa52062b15b4bcd0f 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: fs.c,v 1.56 2005/07/06 12:13:09 dwmw2 Exp $ + * $Id: fs.c,v 1.66 2005/09/27 13:17:29 dedekind Exp $ * */ @@ -40,7 +40,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) int ret; D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino)); ret = inode_change_ok(inode, iattr); - if (ret) + if (ret) return ret; /* Special cases - we don't want more than one data node @@ -73,8 +73,9 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) kfree(mdata); return -ENOMEM; } - - ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL); + + ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, + ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); if (ret) { jffs2_free_raw_inode(ri); if (S_ISLNK(inode->i_mode & S_IFMT)) @@ -83,7 +84,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) } down(&f->sem); ivalid = iattr->ia_valid; - + ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); ri->totlen = cpu_to_je32(sizeof(*ri) + mdatalen); @@ -99,7 +100,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) if (iattr->ia_mode & S_ISGID && !in_group_p(je16_to_cpu(ri->gid)) && !capable(CAP_FSETID)) ri->mode = cpu_to_jemode(iattr->ia_mode & ~S_ISGID); - else + else ri->mode = cpu_to_jemode(iattr->ia_mode); else ri->mode = cpu_to_jemode(inode->i_mode); @@ -128,7 +129,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, phys_ofs, ALLOC_NORMAL); if (S_ISLNK(inode->i_mode)) kfree(mdata); - + if (IS_ERR(new_metadata)) { jffs2_complete_reservation(c); jffs2_free_raw_inode(ri); @@ -147,7 +148,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) old_metadata = f->metadata; if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) - jffs2_truncate_fraglist (c, &f->fragtree, iattr->ia_size); + jffs2_truncate_fragtree (c, &f->fragtree, iattr->ia_size); if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) { jffs2_add_full_dnode_to_inode(c, f, new_metadata); @@ -166,7 +167,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) jffs2_complete_reservation(c); /* We have to do the vmtruncate() without f->sem held, since - some pages may be locked and waiting for it in readpage(). + some pages may be locked and waiting for it in readpage(). We are protected from a simultaneous write() extending i_size back past iattr->ia_size, because do_truncate() holds the generic inode semaphore. */ @@ -194,31 +195,27 @@ int jffs2_statfs(struct super_block *sb, struct kstatfs *buf) buf->f_namelen = JFFS2_MAX_NAME_LEN; spin_lock(&c->erase_completion_lock); - avail = c->dirty_size + c->free_size; if (avail > c->sector_size * c->resv_blocks_write) avail -= c->sector_size * c->resv_blocks_write; else avail = 0; + spin_unlock(&c->erase_completion_lock); buf->f_bavail = buf->f_bfree = avail >> PAGE_SHIFT; - D2(jffs2_dump_block_lists(c)); - - spin_unlock(&c->erase_completion_lock); - return 0; } void jffs2_clear_inode (struct inode *inode) { - /* We can forget about this inode for now - drop all + /* We can forget about this inode for now - drop all * the nodelists associated with it, etc. */ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - + D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode)); jffs2_do_clear_inode(c, f); @@ -237,7 +234,7 @@ void jffs2_read_inode (struct inode *inode) c = JFFS2_SB_INFO(inode->i_sb); jffs2_init_inode_info(f); - + ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node); if (ret) { @@ -257,14 +254,14 @@ void jffs2_read_inode (struct inode *inode) inode->i_blksize = PAGE_SIZE; inode->i_blocks = (inode->i_size + 511) >> 9; - + switch (inode->i_mode & S_IFMT) { jint16_t rdev; case S_IFLNK: inode->i_op = &jffs2_symlink_inode_operations; break; - + case S_IFDIR: { struct jffs2_full_dirent *fd; @@ -301,7 +298,7 @@ void jffs2_read_inode (struct inode *inode) jffs2_do_clear_inode(c, f); make_bad_inode(inode); return; - } + } case S_IFSOCK: case S_IFIFO: @@ -357,11 +354,11 @@ int jffs2_remount_fs (struct super_block *sb, int *flags, char *data) down(&c->alloc_sem); jffs2_flush_wbuf_pad(c); up(&c->alloc_sem); - } + } if (!(*flags & MS_RDONLY)) jffs2_start_garbage_collect_thread(c); - + *flags |= MS_NOATIME; return 0; @@ -395,9 +392,9 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode)); c = JFFS2_SB_INFO(sb); - + inode = new_inode(sb); - + if (!inode) return ERR_PTR(-ENOMEM); @@ -461,40 +458,24 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) #endif c->flash_size = c->mtd->size; - - /* - * Check, if we have to concatenate physical blocks to larger virtual blocks - * to reduce the memorysize for c->blocks. (kmalloc allows max. 128K allocation) - */ - c->sector_size = c->mtd->erasesize; + c->sector_size = c->mtd->erasesize; blocks = c->flash_size / c->sector_size; - if (!(c->mtd->flags & MTD_NO_VIRTBLOCKS)) { - while ((blocks * sizeof (struct jffs2_eraseblock)) > (128 * 1024)) { - blocks >>= 1; - c->sector_size <<= 1; - } - } /* * Size alignment check */ if ((c->sector_size * blocks) != c->flash_size) { - c->flash_size = c->sector_size * blocks; + c->flash_size = c->sector_size * blocks; printk(KERN_INFO "jffs2: Flash size not aligned to erasesize, reducing to %dKiB\n", c->flash_size / 1024); } - if (c->sector_size != c->mtd->erasesize) - printk(KERN_INFO "jffs2: Erase block size too small (%dKiB). Using virtual blocks size (%dKiB) instead\n", - c->mtd->erasesize / 1024, c->sector_size / 1024); - if (c->flash_size < 5*c->sector_size) { printk(KERN_ERR "jffs2: Too few erase blocks (%d)\n", c->flash_size / c->sector_size); return -EINVAL; } c->cleanmarker_size = sizeof(struct jffs2_unknown_node); - /* Joern -- stick alignment for weird 8-byte-page flash here */ /* NAND (or other bizarre) flash... do setup accordingly */ ret = jffs2_flash_setup(c); @@ -517,7 +498,7 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) root_i = iget(sb, 1); if (is_bad_inode(root_i)) { D1(printk(KERN_WARNING "get root inode failed\n")); - goto out_nodes; + goto out_root_i; } D1(printk(KERN_DEBUG "jffs2_do_fill_super(): d_alloc_root()\n")); @@ -535,10 +516,9 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) out_root_i: iput(root_i); - out_nodes: jffs2_free_ino_caches(c); jffs2_free_raw_node_refs(c); - if (c->mtd->flags & MTD_NO_VIRTBLOCKS) + if (jffs2_blocks_use_vmalloc(c)) vfree(c->blocks); else kfree(c->blocks); @@ -563,16 +543,16 @@ struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic; if (!nlink) { /* The inode has zero nlink but its nodes weren't yet marked - obsolete. This has to be because we're still waiting for + obsolete. This has to be because we're still waiting for the final (close() and) iput() to happen. - There's a possibility that the final iput() could have + There's a possibility that the final iput() could have happened while we were contemplating. In order to ensure that we don't cause a new read_inode() (which would fail) for the inode in question, we use ilookup() in this case instead of iget(). - The nlink can't _become_ zero at this point because we're + The nlink can't _become_ zero at this point because we're holding the alloc_sem, and jffs2_do_unlink() would also need that while decrementing nlink on any inode. */ @@ -619,19 +599,19 @@ struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, return JFFS2_INODE_INFO(inode); } -unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, - struct jffs2_inode_info *f, +unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, + struct jffs2_inode_info *f, unsigned long offset, unsigned long *priv) { struct inode *inode = OFNI_EDONI_2SFFJ(f); struct page *pg; - pg = read_cache_page(inode->i_mapping, offset >> PAGE_CACHE_SHIFT, + pg = read_cache_page(inode->i_mapping, offset >> PAGE_CACHE_SHIFT, (void *)jffs2_do_readpage_unlock, inode); if (IS_ERR(pg)) return (void *)pg; - + *priv = (unsigned long)pg; return kmap(pg); } @@ -648,7 +628,7 @@ void jffs2_gc_release_page(struct jffs2_sb_info *c, static int jffs2_flash_setup(struct jffs2_sb_info *c) { int ret = 0; - + if (jffs2_cleanmarker_oob(c)) { /* NAND flash... do setup accordingly */ ret = jffs2_nand_flash_setup(c); @@ -662,14 +642,21 @@ static int jffs2_flash_setup(struct jffs2_sb_info *c) { if (ret) return ret; } - + /* and Dataflash */ if (jffs2_dataflash(c)) { ret = jffs2_dataflash_setup(c); if (ret) return ret; } - + + /* and Intel "Sibley" flash */ + if (jffs2_nor_wbuf_flash(c)) { + ret = jffs2_nor_wbuf_flash_setup(c); + if (ret) + return ret; + } + return ret; } @@ -683,9 +670,14 @@ void jffs2_flash_cleanup(struct jffs2_sb_info *c) { if (jffs2_nor_ecc(c)) { jffs2_nor_ecc_flash_cleanup(c); } - + /* and DataFlash */ if (jffs2_dataflash(c)) { jffs2_dataflash_cleanup(c); } + + /* and Intel "Sibley" flash */ + if (jffs2_nor_wbuf_flash(c)) { + jffs2_nor_wbuf_flash_cleanup(c); + } } diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 7086cd6345038cbc9015dacb4b23dcaf7f4f081f..f9ffece453a38e65542db843701749f943a71283 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: gc.c,v 1.148 2005/04/09 10:47:00 dedekind Exp $ + * $Id: gc.c,v 1.155 2005/11/07 11:14:39 gleixner Exp $ * */ @@ -21,14 +21,14 @@ #include "nodelist.h" #include "compr.h" -static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, +static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, struct jffs2_raw_node_ref *raw); -static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, +static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_inode_info *f, struct jffs2_full_dnode *fd); -static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, +static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_inode_info *f, struct jffs2_full_dirent *fd); -static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, +static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_inode_info *f, struct jffs2_full_dirent *fd); static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, @@ -55,7 +55,7 @@ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c) D1(printk(KERN_DEBUG "Picking block from bad_used_list to GC next\n")); nextlist = &c->bad_used_list; } else if (n < 50 && !list_empty(&c->erasable_list)) { - /* Note that most of them will have gone directly to be erased. + /* Note that most of them will have gone directly to be erased. So don't favour the erasable_list _too_ much. */ D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next\n")); nextlist = &c->erasable_list; @@ -101,7 +101,7 @@ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c) printk(KERN_WARNING "Eep. ret->gc_node for block at 0x%08x is NULL\n", ret->offset); BUG(); } - + /* Have we accidentally picked a clean block with wasted space ? */ if (ret->wasted_size) { D1(printk(KERN_DEBUG "Converting wasted_size %08x to dirty_size\n", ret->wasted_size)); @@ -111,7 +111,6 @@ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c) ret->wasted_size = 0; } - D2(jffs2_dump_block_lists(c)); return ret; } @@ -137,12 +136,12 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) /* We can't start doing GC yet. We haven't finished checking the node CRCs etc. Do it now. */ - + /* checked_ino is protected by the alloc_sem */ if (c->checked_ino > c->highest_ino) { printk(KERN_CRIT "Checked all inodes but still 0x%x bytes of unchecked space?\n", c->unchecked_size); - D2(jffs2_dump_block_lists(c)); + jffs2_dbg_dump_block_lists_nolock(c); spin_unlock(&c->erase_completion_lock); BUG(); } @@ -179,7 +178,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) case INO_STATE_READING: /* We need to wait for it to finish, lest we move on - and trigger the BUG() above while we haven't yet + and trigger the BUG() above while we haven't yet finished checking all its nodes */ D1(printk(KERN_DEBUG "Waiting for ino #%u to finish reading\n", ic->ino)); up(&c->alloc_sem); @@ -229,13 +228,13 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) } raw = jeb->gc_node; - + while(ref_obsolete(raw)) { D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw))); raw = raw->next_phys; if (unlikely(!raw)) { printk(KERN_WARNING "eep. End of raw list while still supposedly nodes to GC\n"); - printk(KERN_WARNING "erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x\n", + printk(KERN_WARNING "erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x\n", jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size); jeb->gc_node = raw; spin_unlock(&c->erase_completion_lock); @@ -260,7 +259,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) ic = jffs2_raw_ref_to_ic(raw); /* We need to hold the inocache. Either the erase_completion_lock or - the inocache_lock are sufficient; we trade down since the inocache_lock + the inocache_lock are sufficient; we trade down since the inocache_lock causes less contention. */ spin_lock(&c->inocache_lock); @@ -279,14 +278,14 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) switch(ic->state) { case INO_STATE_CHECKEDABSENT: - /* It's been checked, but it's not currently in-core. + /* It's been checked, but it's not currently in-core. We can just copy any pristine nodes, but have to prevent anyone else from doing read_inode() while we're at it, so we set the state accordingly */ if (ref_flags(raw) == REF_PRISTINE) ic->state = INO_STATE_GC; else { - D1(printk(KERN_DEBUG "Ino #%u is absent but node not REF_PRISTINE. Reading.\n", + D1(printk(KERN_DEBUG "Ino #%u is absent but node not REF_PRISTINE. Reading.\n", ic->ino)); } break; @@ -299,8 +298,8 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) case INO_STATE_CHECKING: case INO_STATE_GC: /* Should never happen. We should have finished checking - by the time we actually start doing any GC, and since - we're holding the alloc_sem, no other garbage collection + by the time we actually start doing any GC, and since + we're holding the alloc_sem, no other garbage collection can happen. */ printk(KERN_CRIT "Inode #%u already in state %d in jffs2_garbage_collect_pass()!\n", @@ -320,21 +319,21 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() waiting for ino #%u in state %d\n", ic->ino, ic->state)); sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); - /* And because we dropped the alloc_sem we must start again from the + /* And because we dropped the alloc_sem we must start again from the beginning. Ponder chance of livelock here -- we're returning success without actually making any progress. - Q: What are the chances that the inode is back in INO_STATE_READING + Q: What are the chances that the inode is back in INO_STATE_READING again by the time we next enter this function? And that this happens enough times to cause a real delay? - A: Small enough that I don't care :) + A: Small enough that I don't care :) */ return 0; } /* OK. Now if the inode is in state INO_STATE_GC, we are going to copy the - node intact, and we don't have to muck about with the fragtree etc. + node intact, and we don't have to muck about with the fragtree etc. because we know it's not in-core. If it _was_ in-core, we go through all the iget() crap anyway */ @@ -454,7 +453,7 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_era if (!ret) { /* Urgh. Return it sensibly. */ frag->node->raw = f->inocache->nodes; - } + } if (ret != -EBADFD) goto upnout; } @@ -468,7 +467,7 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_era } goto upnout; } - + /* Wasn't a dnode. Try dirent */ for (fd = f->dents; fd; fd=fd->next) { if (fd->raw == raw) @@ -485,7 +484,8 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_era if (ref_obsolete(raw)) { printk(KERN_WARNING "But it's obsolete so we don't mind too much\n"); } else { - ret = -EIO; + jffs2_dbg_dump_node(c, ref_offset(raw)); + BUG(); } } upnout: @@ -494,7 +494,7 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_era return ret; } -static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, +static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, struct jffs2_raw_node_ref *raw) { @@ -513,8 +513,11 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, /* Ask for a small amount of space (or the totlen if smaller) because we don't want to force wastage of the end of a block if splitting would work. */ - ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN, - rawlen), &phys_ofs, &alloclen); + ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + + JFFS2_MIN_DATA_LEN, rawlen), &phys_ofs, &alloclen, rawlen); + /* this is not the exact summary size of it, + it is only an upper estimation */ + if (ret) return ret; @@ -577,7 +580,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, } break; default: - printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n", + printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n", ref_offset(raw), je16_to_cpu(node->u.nodetype)); goto bail; } @@ -618,17 +621,19 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, retried = 1; D1(printk(KERN_DEBUG "Retrying failed write of REF_PRISTINE node.\n")); - - ACCT_SANITY_CHECK(c,jeb); - D1(ACCT_PARANOIA_CHECK(jeb)); - ret = jffs2_reserve_space_gc(c, rawlen, &phys_ofs, &dummy); + jffs2_dbg_acct_sanity_check(c,jeb); + jffs2_dbg_acct_paranoia_check(c, jeb); + + ret = jffs2_reserve_space_gc(c, rawlen, &phys_ofs, &dummy, rawlen); + /* this is not the exact summary size of it, + it is only an upper estimation */ if (!ret) { D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", phys_ofs)); - ACCT_SANITY_CHECK(c,jeb); - D1(ACCT_PARANOIA_CHECK(jeb)); + jffs2_dbg_acct_sanity_check(c,jeb); + jffs2_dbg_acct_paranoia_check(c, jeb); goto retry; } @@ -664,7 +669,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, goto out_node; } -static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, +static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) { struct jffs2_full_dnode *new_fn; @@ -679,7 +684,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ S_ISCHR(JFFS2_F_I_MODE(f)) ) { /* For these, we don't actually need to read the old node */ /* FIXME: for minor or major > 255. */ - dev = cpu_to_je16(((JFFS2_F_I_RDEV_MAJ(f) << 8) | + dev = cpu_to_je16(((JFFS2_F_I_RDEV_MAJ(f) << 8) | JFFS2_F_I_RDEV_MIN(f))); mdata = (char *)&dev; mdatalen = sizeof(dev); @@ -700,14 +705,15 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bites of symlink target\n", mdatalen)); } - - ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &phys_ofs, &alloclen); + + ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &phys_ofs, &alloclen, + JFFS2_SUMMARY_INODE_SIZE); if (ret) { printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_metadata failed: %d\n", sizeof(ri)+ mdatalen, ret); goto out; } - + last_frag = frag_last(&f->fragtree); if (last_frag) /* Fetch the inode length from the fragtree rather then @@ -715,7 +721,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ ilen = last_frag->ofs + last_frag->size; else ilen = JFFS2_F_I_SIZE(f); - + memset(&ri, 0, sizeof(ri)); ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); @@ -754,7 +760,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ return ret; } -static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, +static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_inode_info *f, struct jffs2_full_dirent *fd) { struct jffs2_full_dirent *new_fd; @@ -771,12 +777,18 @@ static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_er rd.pino = cpu_to_je32(f->inocache->ino); rd.version = cpu_to_je32(++f->highest_version); rd.ino = cpu_to_je32(fd->ino); - rd.mctime = cpu_to_je32(max(JFFS2_F_I_MTIME(f), JFFS2_F_I_CTIME(f))); + /* If the times on this inode were set by explicit utime() they can be different, + so refrain from splatting them. */ + if (JFFS2_F_I_MTIME(f) == JFFS2_F_I_CTIME(f)) + rd.mctime = cpu_to_je32(JFFS2_F_I_MTIME(f)); + else + rd.mctime = cpu_to_je32(0); rd.type = fd->type; rd.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd)-8)); rd.name_crc = cpu_to_je32(crc32(0, fd->name, rd.nsize)); - - ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen); + + ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen, + JFFS2_SUMMARY_DIRENT_SIZE(rd.nsize)); if (ret) { printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dirent failed: %d\n", sizeof(rd)+rd.nsize, ret); @@ -792,7 +804,7 @@ static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_er return 0; } -static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, +static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_inode_info *f, struct jffs2_full_dirent *fd) { struct jffs2_full_dirent **fdp = &f->dents; @@ -831,7 +843,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct if (ref_totlen(c, NULL, raw) != rawlen) continue; - /* Doesn't matter if there's one in the same erase block. We're going to + /* Doesn't matter if there's one in the same erase block. We're going to delete it too at the same time. */ if (SECTOR_ADDR(raw->flash_offset) == SECTOR_ADDR(fd->raw->flash_offset)) continue; @@ -883,6 +895,9 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct kfree(rd); } + /* FIXME: If we're deleting a dirent which contains the current mtime and ctime, + we should update the metadata node with those times accordingly */ + /* No need for it any more. Just mark it obsolete and remove it from the list */ while (*fdp) { if ((*fdp) == fd) { @@ -912,13 +927,13 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%u from offset 0x%x to 0x%x\n", f->inocache->ino, start, end)); - + memset(&ri, 0, sizeof(ri)); if(fn->frags > 1) { size_t readlen; uint32_t crc; - /* It's partially obsoleted by a later write. So we have to + /* It's partially obsoleted by a later write. So we have to write it out again with the _same_ version as before */ ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(ri), &readlen, (char *)&ri); if (readlen != sizeof(ri) || ret) { @@ -940,16 +955,16 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras crc = crc32(0, &ri, sizeof(ri)-8); if (crc != je32_to_cpu(ri.node_crc)) { printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had CRC 0x%08x which doesn't match calculated CRC 0x%08x\n", - ref_offset(fn->raw), + ref_offset(fn->raw), je32_to_cpu(ri.node_crc), crc); /* FIXME: We could possibly deal with this by writing new holes for each frag */ - printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n", + printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n", start, end, f->inocache->ino); goto fill; } if (ri.compr != JFFS2_COMPR_ZERO) { printk(KERN_WARNING "jffs2_garbage_collect_hole: Node 0x%08x wasn't a hole node!\n", ref_offset(fn->raw)); - printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n", + printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n", start, end, f->inocache->ino); goto fill; } @@ -967,7 +982,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras ri.csize = cpu_to_je32(0); ri.compr = JFFS2_COMPR_ZERO; } - + frag = frag_last(&f->fragtree); if (frag) /* Fetch the inode length from the fragtree rather then @@ -986,7 +1001,8 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras ri.data_crc = cpu_to_je32(0); ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); - ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen); + ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen, + JFFS2_SUMMARY_INODE_SIZE); if (ret) { printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_hole failed: %d\n", sizeof(ri), ret); @@ -1008,10 +1024,10 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras return 0; } - /* + /* * We should only get here in the case where the node we are * replacing had more than one frag, so we kept the same version - * number as before. (Except in case of error -- see 'goto fill;' + * number as before. (Except in case of error -- see 'goto fill;' * above.) */ D1(if(unlikely(fn->frags <= 1)) { @@ -1023,7 +1039,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras /* This is a partially-overlapped hole node. Mark it REF_NORMAL not REF_PRISTINE */ mark_ref_normal(new_fn->raw); - for (frag = jffs2_lookup_node_frag(&f->fragtree, fn->ofs); + for (frag = jffs2_lookup_node_frag(&f->fragtree, fn->ofs); frag; frag = frag_next(frag)) { if (frag->ofs > fn->size + fn->ofs) break; @@ -1041,10 +1057,10 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras printk(KERN_WARNING "jffs2_garbage_collect_hole: New node has no frags!\n"); BUG(); } - + jffs2_mark_node_obsolete(c, fn->raw); jffs2_free_full_dnode(fn); - + return 0; } @@ -1054,12 +1070,12 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era { struct jffs2_full_dnode *new_fn; struct jffs2_raw_inode ri; - uint32_t alloclen, phys_ofs, offset, orig_end, orig_start; + uint32_t alloclen, phys_ofs, offset, orig_end, orig_start; int ret = 0; unsigned char *comprbuf = NULL, *writebuf; unsigned long pg; unsigned char *pg_ptr; - + memset(&ri, 0, sizeof(ri)); D1(printk(KERN_DEBUG "Writing replacement dnode for ino #%u from offset 0x%x to 0x%x\n", @@ -1071,8 +1087,8 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era if (c->nr_free_blocks + c->nr_erasing_blocks > c->resv_blocks_gcmerge) { /* Attempt to do some merging. But only expand to cover logically adjacent frags if the block containing them is already considered - to be dirty. Otherwise we end up with GC just going round in - circles dirtying the nodes it already wrote out, especially + to be dirty. Otherwise we end up with GC just going round in + circles dirtying the nodes it already wrote out, especially on NAND where we have small eraseblocks and hence a much higher chance of nodes having to be split to cross boundaries. */ @@ -1106,7 +1122,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era break; } else { - /* OK, it's a frag which extends to the beginning of the page. Does it live + /* OK, it's a frag which extends to the beginning of the page. Does it live in a block which is still considered clean? If so, don't obsolete it. If not, cover it anyway. */ @@ -1156,7 +1172,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era break; } else { - /* OK, it's a frag which extends to the beginning of the page. Does it live + /* OK, it's a frag which extends to the beginning of the page. Does it live in a block which is still considered clean? If so, don't obsolete it. If not, cover it anyway. */ @@ -1183,14 +1199,14 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era break; } } - D1(printk(KERN_DEBUG "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n", + D1(printk(KERN_DEBUG "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n", orig_start, orig_end, start, end)); D1(BUG_ON(end > frag_last(&f->fragtree)->ofs + frag_last(&f->fragtree)->size)); BUG_ON(end < orig_end); BUG_ON(start > orig_start); } - + /* First, use readpage() to read the appropriate page into the page cache */ /* Q: What happens if we actually try to GC the _same_ page for which commit_write() * triggered garbage collection in the first place? @@ -1211,7 +1227,8 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era uint32_t cdatalen; uint16_t comprtype = JFFS2_COMPR_NONE; - ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen); + ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, + &alloclen, JFFS2_SUMMARY_INODE_SIZE); if (ret) { printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dnode failed: %d\n", @@ -1246,7 +1263,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era ri.usercompr = (comprtype >> 8) & 0xff; ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); ri.data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen)); - + new_fn = jffs2_write_dnode(c, f, &ri, comprbuf, cdatalen, phys_ofs, ALLOC_GC); jffs2_free_comprbuf(comprbuf, writebuf); @@ -1268,4 +1285,3 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era jffs2_gc_release_page(c, pg_ptr, &pg); return ret; } - diff --git a/fs/jffs2/histo.h b/fs/jffs2/histo.h index 84f184f0836f2aab1b9514336f5d3bb75aea6fd5..22a93a08210c060f47dd2b71674b391b4ea27897 100644 --- a/fs/jffs2/histo.h +++ b/fs/jffs2/histo.h @@ -1,3 +1,3 @@ /* This file provides the bit-probabilities for the input file */ -#define BIT_DIVIDER 629 +#define BIT_DIVIDER 629 static int bits[9] = { 179,167,183,165,159,198,178,119,}; /* ia32 .so files */ diff --git a/fs/jffs2/histo_mips.h b/fs/jffs2/histo_mips.h index 9a443268d88576da92819a2a013464b33d45395b..fa3dac19a109eeb2cb1a1c481dda948979e6946a 100644 --- a/fs/jffs2/histo_mips.h +++ b/fs/jffs2/histo_mips.h @@ -1,2 +1,2 @@ -#define BIT_DIVIDER_MIPS 1043 +#define BIT_DIVIDER_MIPS 1043 static int bits_mips[8] = { 277,249,290,267,229,341,212,241}; /* mips32 */ diff --git a/fs/jffs2/ioctl.c b/fs/jffs2/ioctl.c index 238c7992064cfbeb001f834096d425b60c3a40c9..69099835de1c3e8ed140a86eaee30d42fa682973 100644 --- a/fs/jffs2/ioctl.c +++ b/fs/jffs2/ioctl.c @@ -7,17 +7,17 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: ioctl.c,v 1.9 2004/11/16 20:36:11 dwmw2 Exp $ + * $Id: ioctl.c,v 1.10 2005/11/07 11:14:40 gleixner Exp $ * */ #include -int jffs2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, +int jffs2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { /* Later, this will provide for lsattr.jffs2 and chattr.jffs2, which will include compression support etc. */ return -ENOTTY; } - + diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c index 5abb431c2a00fcf1ccfa24d84474f20e9045a5a8..036cbd11c00449d6755481b8a51e53bbf0f7fb4f 100644 --- a/fs/jffs2/malloc.c +++ b/fs/jffs2/malloc.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: malloc.c,v 1.28 2004/11/16 20:36:11 dwmw2 Exp $ + * $Id: malloc.c,v 1.31 2005/11/07 11:14:40 gleixner Exp $ * */ @@ -17,15 +17,6 @@ #include #include "nodelist.h" -#if 0 -#define JFFS2_SLAB_POISON SLAB_POISON -#else -#define JFFS2_SLAB_POISON 0 -#endif - -// replace this by #define D3 (x) x for cache debugging -#define D3(x) - /* These are initialised to NULL in the kernel startup code. If you're porting to other operating systems, beware */ static kmem_cache_t *full_dnode_slab; @@ -38,45 +29,45 @@ static kmem_cache_t *inode_cache_slab; int __init jffs2_create_slab_caches(void) { - full_dnode_slab = kmem_cache_create("jffs2_full_dnode", + full_dnode_slab = kmem_cache_create("jffs2_full_dnode", sizeof(struct jffs2_full_dnode), - 0, JFFS2_SLAB_POISON, NULL, NULL); + 0, 0, NULL, NULL); if (!full_dnode_slab) goto err; raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent", sizeof(struct jffs2_raw_dirent), - 0, JFFS2_SLAB_POISON, NULL, NULL); + 0, 0, NULL, NULL); if (!raw_dirent_slab) goto err; raw_inode_slab = kmem_cache_create("jffs2_raw_inode", sizeof(struct jffs2_raw_inode), - 0, JFFS2_SLAB_POISON, NULL, NULL); + 0, 0, NULL, NULL); if (!raw_inode_slab) goto err; tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode", sizeof(struct jffs2_tmp_dnode_info), - 0, JFFS2_SLAB_POISON, NULL, NULL); + 0, 0, NULL, NULL); if (!tmp_dnode_info_slab) goto err; raw_node_ref_slab = kmem_cache_create("jffs2_raw_node_ref", sizeof(struct jffs2_raw_node_ref), - 0, JFFS2_SLAB_POISON, NULL, NULL); + 0, 0, NULL, NULL); if (!raw_node_ref_slab) goto err; node_frag_slab = kmem_cache_create("jffs2_node_frag", sizeof(struct jffs2_node_frag), - 0, JFFS2_SLAB_POISON, NULL, NULL); + 0, 0, NULL, NULL); if (!node_frag_slab) goto err; inode_cache_slab = kmem_cache_create("jffs2_inode_cache", sizeof(struct jffs2_inode_cache), - 0, JFFS2_SLAB_POISON, NULL, NULL); + 0, 0, NULL, NULL); if (inode_cache_slab) return 0; err: @@ -104,102 +95,113 @@ void jffs2_destroy_slab_caches(void) struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize) { - return kmalloc(sizeof(struct jffs2_full_dirent) + namesize, GFP_KERNEL); + struct jffs2_full_dirent *ret; + ret = kmalloc(sizeof(struct jffs2_full_dirent) + namesize, GFP_KERNEL); + dbg_memalloc("%p\n", ret); + return ret; } void jffs2_free_full_dirent(struct jffs2_full_dirent *x) { + dbg_memalloc("%p\n", x); kfree(x); } struct jffs2_full_dnode *jffs2_alloc_full_dnode(void) { - struct jffs2_full_dnode *ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL); - D3 (printk (KERN_DEBUG "alloc_full_dnode at %p\n", ret)); + struct jffs2_full_dnode *ret; + ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL); + dbg_memalloc("%p\n", ret); return ret; } void jffs2_free_full_dnode(struct jffs2_full_dnode *x) { - D3 (printk (KERN_DEBUG "free full_dnode at %p\n", x)); + dbg_memalloc("%p\n", x); kmem_cache_free(full_dnode_slab, x); } struct jffs2_raw_dirent *jffs2_alloc_raw_dirent(void) { - struct jffs2_raw_dirent *ret = kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL); - D3 (printk (KERN_DEBUG "alloc_raw_dirent\n", ret)); + struct jffs2_raw_dirent *ret; + ret = kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL); + dbg_memalloc("%p\n", ret); return ret; } void jffs2_free_raw_dirent(struct jffs2_raw_dirent *x) { - D3 (printk (KERN_DEBUG "free_raw_dirent at %p\n", x)); + dbg_memalloc("%p\n", x); kmem_cache_free(raw_dirent_slab, x); } struct jffs2_raw_inode *jffs2_alloc_raw_inode(void) { - struct jffs2_raw_inode *ret = kmem_cache_alloc(raw_inode_slab, GFP_KERNEL); - D3 (printk (KERN_DEBUG "alloc_raw_inode at %p\n", ret)); + struct jffs2_raw_inode *ret; + ret = kmem_cache_alloc(raw_inode_slab, GFP_KERNEL); + dbg_memalloc("%p\n", ret); return ret; } void jffs2_free_raw_inode(struct jffs2_raw_inode *x) { - D3 (printk (KERN_DEBUG "free_raw_inode at %p\n", x)); + dbg_memalloc("%p\n", x); kmem_cache_free(raw_inode_slab, x); } struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void) { - struct jffs2_tmp_dnode_info *ret = kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL); - D3 (printk (KERN_DEBUG "alloc_tmp_dnode_info at %p\n", ret)); + struct jffs2_tmp_dnode_info *ret; + ret = kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL); + dbg_memalloc("%p\n", + ret); return ret; } void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x) { - D3 (printk (KERN_DEBUG "free_tmp_dnode_info at %p\n", x)); + dbg_memalloc("%p\n", x); kmem_cache_free(tmp_dnode_info_slab, x); } struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void) { - struct jffs2_raw_node_ref *ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); - D3 (printk (KERN_DEBUG "alloc_raw_node_ref at %p\n", ret)); + struct jffs2_raw_node_ref *ret; + ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); + dbg_memalloc("%p\n", ret); return ret; } void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x) { - D3 (printk (KERN_DEBUG "free_raw_node_ref at %p\n", x)); + dbg_memalloc("%p\n", x); kmem_cache_free(raw_node_ref_slab, x); } struct jffs2_node_frag *jffs2_alloc_node_frag(void) { - struct jffs2_node_frag *ret = kmem_cache_alloc(node_frag_slab, GFP_KERNEL); - D3 (printk (KERN_DEBUG "alloc_node_frag at %p\n", ret)); + struct jffs2_node_frag *ret; + ret = kmem_cache_alloc(node_frag_slab, GFP_KERNEL); + dbg_memalloc("%p\n", ret); return ret; } void jffs2_free_node_frag(struct jffs2_node_frag *x) { - D3 (printk (KERN_DEBUG "free_node_frag at %p\n", x)); + dbg_memalloc("%p\n", x); kmem_cache_free(node_frag_slab, x); } struct jffs2_inode_cache *jffs2_alloc_inode_cache(void) { - struct jffs2_inode_cache *ret = kmem_cache_alloc(inode_cache_slab, GFP_KERNEL); - D3 (printk(KERN_DEBUG "Allocated inocache at %p\n", ret)); + struct jffs2_inode_cache *ret; + ret = kmem_cache_alloc(inode_cache_slab, GFP_KERNEL); + dbg_memalloc("%p\n", ret); return ret; } void jffs2_free_inode_cache(struct jffs2_inode_cache *x) { - D3 (printk(KERN_DEBUG "Freeing inocache at %p\n", x)); + dbg_memalloc("%p\n", x); kmem_cache_free(inode_cache_slab, x); } - diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 4991c348f6ec36ee82f2525e2ae4c86aeed82bfb..c79eebb8ab32caeeb0f3527ed54af5e37c8eff89 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodelist.c,v 1.98 2005/07/10 15:15:32 dedekind Exp $ + * $Id: nodelist.c,v 1.115 2005/11/07 11:14:40 gleixner Exp $ * */ @@ -24,469 +24,832 @@ void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list) { struct jffs2_full_dirent **prev = list; - D1(printk(KERN_DEBUG "jffs2_add_fd_to_list( %p, %p (->%p))\n", new, list, *list)); + + dbg_dentlist("add dirent \"%s\", ino #%u\n", new->name, new->ino); while ((*prev) && (*prev)->nhash <= new->nhash) { if ((*prev)->nhash == new->nhash && !strcmp((*prev)->name, new->name)) { /* Duplicate. Free one */ if (new->version < (*prev)->version) { - D1(printk(KERN_DEBUG "Eep! Marking new dirent node obsolete\n")); - D1(printk(KERN_DEBUG "New dirent is \"%s\"->ino #%u. Old is \"%s\"->ino #%u\n", new->name, new->ino, (*prev)->name, (*prev)->ino)); + dbg_dentlist("Eep! Marking new dirent node is obsolete, old is \"%s\", ino #%u\n", + (*prev)->name, (*prev)->ino); jffs2_mark_node_obsolete(c, new->raw); jffs2_free_full_dirent(new); } else { - D1(printk(KERN_DEBUG "Marking old dirent node (ino #%u) obsolete\n", (*prev)->ino)); + dbg_dentlist("marking old dirent \"%s\", ino #%u bsolete\n", + (*prev)->name, (*prev)->ino); new->next = (*prev)->next; jffs2_mark_node_obsolete(c, ((*prev)->raw)); jffs2_free_full_dirent(*prev); *prev = new; } - goto out; + return; } prev = &((*prev)->next); } new->next = *prev; *prev = new; +} + +void jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, uint32_t size) +{ + struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size); + + dbg_fragtree("truncating fragtree to 0x%08x bytes\n", size); + + /* We know frag->ofs <= size. That's what lookup does for us */ + if (frag && frag->ofs != size) { + if (frag->ofs+frag->size > size) { + frag->size = size - frag->ofs; + } + frag = frag_next(frag); + } + while (frag && frag->ofs >= size) { + struct jffs2_node_frag *next = frag_next(frag); + + frag_erase(frag, list); + jffs2_obsolete_node_frag(c, frag); + frag = next; + } - out: - D2(while(*list) { - printk(KERN_DEBUG "Dirent \"%s\" (hash 0x%08x, ino #%u\n", (*list)->name, (*list)->nhash, (*list)->ino); - list = &(*list)->next; - }); + if (size == 0) + return; + + /* + * If the last fragment starts at the RAM page boundary, it is + * REF_PRISTINE irrespective of its size. + */ + frag = frag_last(list); + if (frag->node && (frag->ofs & (PAGE_CACHE_SIZE - 1)) == 0) { + dbg_fragtree2("marking the last fragment 0x%08x-0x%08x REF_PRISTINE.\n", + frag->ofs, frag->ofs + frag->size); + frag->node->raw->flash_offset = ref_offset(frag->node->raw) | REF_PRISTINE; + } } -/* - * Put a new tmp_dnode_info into the temporaty RB-tree, keeping the list in - * order of increasing version. - */ -static void jffs2_add_tn_to_tree(struct jffs2_tmp_dnode_info *tn, struct rb_root *list) +void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this) { - struct rb_node **p = &list->rb_node; - struct rb_node * parent = NULL; - struct jffs2_tmp_dnode_info *this; - - while (*p) { - parent = *p; - this = rb_entry(parent, struct jffs2_tmp_dnode_info, rb); - - /* There may actually be a collision here, but it doesn't - actually matter. As long as the two nodes with the same - version are together, it's all fine. */ - if (tn->version < this->version) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } + if (this->node) { + this->node->frags--; + if (!this->node->frags) { + /* The node has no valid frags left. It's totally obsoleted */ + dbg_fragtree2("marking old node @0x%08x (0x%04x-0x%04x) obsolete\n", + ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size); + jffs2_mark_node_obsolete(c, this->node->raw); + jffs2_free_full_dnode(this->node); + } else { + dbg_fragtree2("marking old node @0x%08x (0x%04x-0x%04x) REF_NORMAL. frags is %d\n", + ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size, this->node->frags); + mark_ref_normal(this->node->raw); + } - rb_link_node(&tn->rb, parent, p); - rb_insert_color(&tn->rb, list); + } + jffs2_free_node_frag(this); } -static void jffs2_free_tmp_dnode_info_list(struct rb_root *list) +static void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base) { - struct rb_node *this; - struct jffs2_tmp_dnode_info *tn; + struct rb_node *parent = &base->rb; + struct rb_node **link = &parent; - this = list->rb_node; + dbg_fragtree2("insert frag (0x%04x-0x%04x)\n", newfrag->ofs, newfrag->ofs + newfrag->size); - /* Now at bottom of tree */ - while (this) { - if (this->rb_left) - this = this->rb_left; - else if (this->rb_right) - this = this->rb_right; + while (*link) { + parent = *link; + base = rb_entry(parent, struct jffs2_node_frag, rb); + + if (newfrag->ofs > base->ofs) + link = &base->rb.rb_right; + else if (newfrag->ofs < base->ofs) + link = &base->rb.rb_left; else { - tn = rb_entry(this, struct jffs2_tmp_dnode_info, rb); - jffs2_free_full_dnode(tn->fn); - jffs2_free_tmp_dnode_info(tn); - - this = this->rb_parent; - if (!this) - break; - - if (this->rb_left == &tn->rb) - this->rb_left = NULL; - else if (this->rb_right == &tn->rb) - this->rb_right = NULL; - else BUG(); + JFFS2_ERROR("duplicate frag at %08x (%p,%p)\n", newfrag->ofs, newfrag, base); + BUG(); } } - list->rb_node = NULL; + + rb_link_node(&newfrag->rb, &base->rb, link); } -static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd) +/* + * Allocate and initializes a new fragment. + */ +static inline struct jffs2_node_frag * new_fragment(struct jffs2_full_dnode *fn, uint32_t ofs, uint32_t size) { - struct jffs2_full_dirent *next; - - while (fd) { - next = fd->next; - jffs2_free_full_dirent(fd); - fd = next; + struct jffs2_node_frag *newfrag; + + newfrag = jffs2_alloc_node_frag(); + if (likely(newfrag)) { + newfrag->ofs = ofs; + newfrag->size = size; + newfrag->node = fn; + } else { + JFFS2_ERROR("cannot allocate a jffs2_node_frag object\n"); } + + return newfrag; } -/* Returns first valid node after 'ref'. May return 'ref' */ -static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_ref *ref) +/* + * Called when there is no overlapping fragment exist. Inserts a hole before the new + * fragment and inserts the new fragment to the fragtree. + */ +static int no_overlapping_node(struct jffs2_sb_info *c, struct rb_root *root, + struct jffs2_node_frag *newfrag, + struct jffs2_node_frag *this, uint32_t lastend) { - while (ref && ref->next_in_ino) { - if (!ref_obsolete(ref)) - return ref; - D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref_offset(ref))); - ref = ref->next_in_ino; + if (lastend < newfrag->node->ofs) { + /* put a hole in before the new fragment */ + struct jffs2_node_frag *holefrag; + + holefrag= new_fragment(NULL, lastend, newfrag->node->ofs - lastend); + if (unlikely(!holefrag)) { + jffs2_free_node_frag(newfrag); + return -ENOMEM; + } + + if (this) { + /* By definition, the 'this' node has no right-hand child, + because there are no frags with offset greater than it. + So that's where we want to put the hole */ + dbg_fragtree2("add hole frag %#04x-%#04x on the right of the new frag.\n", + holefrag->ofs, holefrag->ofs + holefrag->size); + rb_link_node(&holefrag->rb, &this->rb, &this->rb.rb_right); + } else { + dbg_fragtree2("Add hole frag %#04x-%#04x to the root of the tree.\n", + holefrag->ofs, holefrag->ofs + holefrag->size); + rb_link_node(&holefrag->rb, NULL, &root->rb_node); + } + rb_insert_color(&holefrag->rb, root); + this = holefrag; + } + + if (this) { + /* By definition, the 'this' node has no right-hand child, + because there are no frags with offset greater than it. + So that's where we want to put new fragment */ + dbg_fragtree2("add the new node at the right\n"); + rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right); + } else { + dbg_fragtree2("insert the new node at the root of the tree\n"); + rb_link_node(&newfrag->rb, NULL, &root->rb_node); } - return NULL; + rb_insert_color(&newfrag->rb, root); + + return 0; } -/* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated - with this ino, returning the former in order of version */ +/* Doesn't set inode->i_size */ +static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *root, struct jffs2_node_frag *newfrag) +{ + struct jffs2_node_frag *this; + uint32_t lastend; + + /* Skip all the nodes which are completed before this one starts */ + this = jffs2_lookup_node_frag(root, newfrag->node->ofs); + + if (this) { + dbg_fragtree2("lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n", + this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this); + lastend = this->ofs + this->size; + } else { + dbg_fragtree2("lookup gave no frag\n"); + lastend = 0; + } + + /* See if we ran off the end of the fragtree */ + if (lastend <= newfrag->ofs) { + /* We did */ + + /* Check if 'this' node was on the same page as the new node. + If so, both 'this' and the new node get marked REF_NORMAL so + the GC can take a look. + */ + if (lastend && (lastend-1) >> PAGE_CACHE_SHIFT == newfrag->ofs >> PAGE_CACHE_SHIFT) { + if (this->node) + mark_ref_normal(this->node->raw); + mark_ref_normal(newfrag->node->raw); + } + + return no_overlapping_node(c, root, newfrag, this, lastend); + } -int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, - struct rb_root *tnp, struct jffs2_full_dirent **fdp, - uint32_t *highest_version, uint32_t *latest_mctime, - uint32_t *mctime_ver) + if (this->node) + dbg_fragtree2("dealing with frag %u-%u, phys %#08x(%d).\n", + this->ofs, this->ofs + this->size, + ref_offset(this->node->raw), ref_flags(this->node->raw)); + else + dbg_fragtree2("dealing with hole frag %u-%u.\n", + this->ofs, this->ofs + this->size); + + /* OK. 'this' is pointing at the first frag that newfrag->ofs at least partially obsoletes, + * - i.e. newfrag->ofs < this->ofs+this->size && newfrag->ofs >= this->ofs + */ + if (newfrag->ofs > this->ofs) { + /* This node isn't completely obsoleted. The start of it remains valid */ + + /* Mark the new node and the partially covered node REF_NORMAL -- let + the GC take a look at them */ + mark_ref_normal(newfrag->node->raw); + if (this->node) + mark_ref_normal(this->node->raw); + + if (this->ofs + this->size > newfrag->ofs + newfrag->size) { + /* The new node splits 'this' frag into two */ + struct jffs2_node_frag *newfrag2; + + if (this->node) + dbg_fragtree2("split old frag 0x%04x-0x%04x, phys 0x%08x\n", + this->ofs, this->ofs+this->size, ref_offset(this->node->raw)); + else + dbg_fragtree2("split old hole frag 0x%04x-0x%04x\n", + this->ofs, this->ofs+this->size); + + /* New second frag pointing to this's node */ + newfrag2 = new_fragment(this->node, newfrag->ofs + newfrag->size, + this->ofs + this->size - newfrag->ofs - newfrag->size); + if (unlikely(!newfrag2)) + return -ENOMEM; + if (this->node) + this->node->frags++; + + /* Adjust size of original 'this' */ + this->size = newfrag->ofs - this->ofs; + + /* Now, we know there's no node with offset + greater than this->ofs but smaller than + newfrag2->ofs or newfrag->ofs, for obvious + reasons. So we can do a tree insert from + 'this' to insert newfrag, and a tree insert + from newfrag to insert newfrag2. */ + jffs2_fragtree_insert(newfrag, this); + rb_insert_color(&newfrag->rb, root); + + jffs2_fragtree_insert(newfrag2, newfrag); + rb_insert_color(&newfrag2->rb, root); + + return 0; + } + /* New node just reduces 'this' frag in size, doesn't split it */ + this->size = newfrag->ofs - this->ofs; + + /* Again, we know it lives down here in the tree */ + jffs2_fragtree_insert(newfrag, this); + rb_insert_color(&newfrag->rb, root); + } else { + /* New frag starts at the same point as 'this' used to. Replace + it in the tree without doing a delete and insertion */ + dbg_fragtree2("inserting newfrag (*%p),%d-%d in before 'this' (*%p),%d-%d\n", + newfrag, newfrag->ofs, newfrag->ofs+newfrag->size, this, this->ofs, this->ofs+this->size); + + rb_replace_node(&this->rb, &newfrag->rb, root); + + if (newfrag->ofs + newfrag->size >= this->ofs+this->size) { + dbg_fragtree2("obsoleting node frag %p (%x-%x)\n", this, this->ofs, this->ofs+this->size); + jffs2_obsolete_node_frag(c, this); + } else { + this->ofs += newfrag->size; + this->size -= newfrag->size; + + jffs2_fragtree_insert(this, newfrag); + rb_insert_color(&this->rb, root); + return 0; + } + } + /* OK, now we have newfrag added in the correct place in the tree, but + frag_next(newfrag) may be a fragment which is overlapped by it + */ + while ((this = frag_next(newfrag)) && newfrag->ofs + newfrag->size >= this->ofs + this->size) { + /* 'this' frag is obsoleted completely. */ + dbg_fragtree2("obsoleting node frag %p (%x-%x) and removing from tree\n", + this, this->ofs, this->ofs+this->size); + rb_erase(&this->rb, root); + jffs2_obsolete_node_frag(c, this); + } + /* Now we're pointing at the first frag which isn't totally obsoleted by + the new frag */ + + if (!this || newfrag->ofs + newfrag->size == this->ofs) + return 0; + + /* Still some overlap but we don't need to move it in the tree */ + this->size = (this->ofs + this->size) - (newfrag->ofs + newfrag->size); + this->ofs = newfrag->ofs + newfrag->size; + + /* And mark them REF_NORMAL so the GC takes a look at them */ + if (this->node) + mark_ref_normal(this->node->raw); + mark_ref_normal(newfrag->node->raw); + + return 0; +} + +/* + * Given an inode, probably with existing tree of fragments, add the new node + * to the fragment tree. + */ +int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) { - struct jffs2_raw_node_ref *ref, *valid_ref; - struct jffs2_tmp_dnode_info *tn; - struct rb_root ret_tn = RB_ROOT; - struct jffs2_full_dirent *fd, *ret_fd = NULL; - union jffs2_node_union node; - size_t retlen; - int err; - - *mctime_ver = 0; - - D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%u\n", f->inocache->ino)); + int ret; + struct jffs2_node_frag *newfrag; - spin_lock(&c->erase_completion_lock); + if (unlikely(!fn->size)) + return 0; - valid_ref = jffs2_first_valid_node(f->inocache->nodes); + newfrag = new_fragment(fn, fn->ofs, fn->size); + if (unlikely(!newfrag)) + return -ENOMEM; + newfrag->node->frags = 1; - if (!valid_ref && (f->inocache->ino != 1)) - printk(KERN_WARNING "Eep. No valid nodes for ino #%u\n", f->inocache->ino); + dbg_fragtree("adding node %#04x-%#04x @0x%08x on flash, newfrag *%p\n", + fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag); - while (valid_ref) { - /* We can hold a pointer to a non-obsolete node without the spinlock, - but _obsolete_ nodes may disappear at any time, if the block - they're in gets erased. So if we mark 'ref' obsolete while we're - not holding the lock, it can go away immediately. For that reason, - we find the next valid node first, before processing 'ref'. - */ - ref = valid_ref; - valid_ref = jffs2_first_valid_node(ref->next_in_ino); - spin_unlock(&c->erase_completion_lock); + ret = jffs2_add_frag_to_fragtree(c, &f->fragtree, newfrag); + if (unlikely(ret)) + return ret; - cond_resched(); + /* If we now share a page with other nodes, mark either previous + or next node REF_NORMAL, as appropriate. */ + if (newfrag->ofs & (PAGE_CACHE_SIZE-1)) { + struct jffs2_node_frag *prev = frag_prev(newfrag); + + mark_ref_normal(fn->raw); + /* If we don't start at zero there's _always_ a previous */ + if (prev->node) + mark_ref_normal(prev->node->raw); + } + + if ((newfrag->ofs+newfrag->size) & (PAGE_CACHE_SIZE-1)) { + struct jffs2_node_frag *next = frag_next(newfrag); + + if (next) { + mark_ref_normal(fn->raw); + if (next->node) + mark_ref_normal(next->node->raw); + } + } + jffs2_dbg_fragtree_paranoia_check_nolock(f); + + return 0; +} + +/* + * Check the data CRC of the node. + * + * Returns: 0 if the data CRC is correct; + * 1 - if incorrect; + * error code if an error occured. + */ +static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn) +{ + struct jffs2_raw_node_ref *ref = tn->fn->raw; + int err = 0, pointed = 0; + struct jffs2_eraseblock *jeb; + unsigned char *buffer; + uint32_t crc, ofs, retlen, len; + + BUG_ON(tn->csize == 0); + + if (!jffs2_is_writebuffered(c)) + goto adj_acc; + + /* Calculate how many bytes were already checked */ + ofs = ref_offset(ref) + sizeof(struct jffs2_raw_inode); + len = ofs % c->wbuf_pagesize; + if (likely(len)) + len = c->wbuf_pagesize - len; + + if (len >= tn->csize) { + dbg_readinode("no need to check node at %#08x, data length %u, data starts at %#08x - it has already been checked.\n", + ref_offset(ref), tn->csize, ofs); + goto adj_acc; + } + + ofs += len; + len = tn->csize - len; + + dbg_readinode("check node at %#08x, data length %u, partial CRC %#08x, correct CRC %#08x, data starts at %#08x, start checking from %#08x - %u bytes.\n", + ref_offset(ref), tn->csize, tn->partial_crc, tn->data_crc, ofs - len, ofs, len); + +#ifndef __ECOS + /* TODO: instead, incapsulate point() stuff to jffs2_flash_read(), + * adding and jffs2_flash_read_end() interface. */ + if (c->mtd->point) { + err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer); + if (!err && retlen < tn->csize) { + JFFS2_WARNING("MTD point returned len too short: %u instead of %u.\n", retlen, tn->csize); + c->mtd->unpoint(c->mtd, buffer, ofs, len); + } else if (err) + JFFS2_WARNING("MTD point failed: error code %d.\n", err); + else + pointed = 1; /* succefully pointed to device */ + } +#endif + + if (!pointed) { + buffer = kmalloc(len, GFP_KERNEL); + if (unlikely(!buffer)) + return -ENOMEM; - /* FIXME: point() */ - err = jffs2_flash_read(c, (ref_offset(ref)), - min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node)), - &retlen, (void *)&node); + /* TODO: this is very frequent pattern, make it a separate + * routine */ + err = jffs2_flash_read(c, ofs, len, &retlen, buffer); if (err) { - printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, ref_offset(ref)); + JFFS2_ERROR("can not read %d bytes from 0x%08x, error code: %d.\n", len, ofs, err); goto free_out; } - - /* Check we've managed to read at least the common node header */ - if (retlen < min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node.u))) { - printk(KERN_WARNING "short read in get_inode_nodes()\n"); + if (retlen != len) { + JFFS2_ERROR("short read at %#08x: %d instead of %d.\n", ofs, retlen, len); err = -EIO; goto free_out; } - - switch (je16_to_cpu(node.u.nodetype)) { - case JFFS2_NODETYPE_DIRENT: - D1(printk(KERN_DEBUG "Node at %08x (%d) is a dirent node\n", ref_offset(ref), ref_flags(ref))); - if (ref_flags(ref) == REF_UNCHECKED) { - printk(KERN_WARNING "BUG: Dirent node at 0x%08x never got checked? How?\n", ref_offset(ref)); - BUG(); - } - if (retlen < sizeof(node.d)) { - printk(KERN_WARNING "short read in get_inode_nodes()\n"); - err = -EIO; - goto free_out; - } - /* sanity check */ - if (PAD((node.d.nsize + sizeof (node.d))) != PAD(je32_to_cpu (node.d.totlen))) { - printk(KERN_NOTICE "jffs2_get_inode_nodes(): Illegal nsize in node at 0x%08x: nsize 0x%02x, totlen %04x\n", - ref_offset(ref), node.d.nsize, je32_to_cpu(node.d.totlen)); - jffs2_mark_node_obsolete(c, ref); - spin_lock(&c->erase_completion_lock); - continue; - } - if (je32_to_cpu(node.d.version) > *highest_version) - *highest_version = je32_to_cpu(node.d.version); - if (ref_obsolete(ref)) { - /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ - printk(KERN_ERR "Dirent node at 0x%08x became obsolete while we weren't looking\n", - ref_offset(ref)); - BUG(); - } - - fd = jffs2_alloc_full_dirent(node.d.nsize+1); - if (!fd) { - err = -ENOMEM; - goto free_out; - } - fd->raw = ref; - fd->version = je32_to_cpu(node.d.version); - fd->ino = je32_to_cpu(node.d.ino); - fd->type = node.d.type; - - /* Pick out the mctime of the latest dirent */ - if(fd->version > *mctime_ver) { - *mctime_ver = fd->version; - *latest_mctime = je32_to_cpu(node.d.mctime); - } + } - /* memcpy as much of the name as possible from the raw - dirent we've already read from the flash - */ - if (retlen > sizeof(struct jffs2_raw_dirent)) - memcpy(&fd->name[0], &node.d.name[0], min_t(uint32_t, node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent)))); - - /* Do we need to copy any more of the name directly - from the flash? - */ - if (node.d.nsize + sizeof(struct jffs2_raw_dirent) > retlen) { - /* FIXME: point() */ - int already = retlen - sizeof(struct jffs2_raw_dirent); - - err = jffs2_flash_read(c, (ref_offset(ref)) + retlen, - node.d.nsize - already, &retlen, &fd->name[already]); - if (!err && retlen != node.d.nsize - already) - err = -EIO; - - if (err) { - printk(KERN_WARNING "Read remainder of name in jffs2_get_inode_nodes(): error %d\n", err); - jffs2_free_full_dirent(fd); - goto free_out; - } - } - fd->nhash = full_name_hash(fd->name, node.d.nsize); - fd->next = NULL; - fd->name[node.d.nsize] = '\0'; - /* Wheee. We now have a complete jffs2_full_dirent structure, with - the name in it and everything. Link it into the list - */ - D1(printk(KERN_DEBUG "Adding fd \"%s\", ino #%u\n", fd->name, fd->ino)); - jffs2_add_fd_to_list(c, fd, &ret_fd); - break; - - case JFFS2_NODETYPE_INODE: - D1(printk(KERN_DEBUG "Node at %08x (%d) is a data node\n", ref_offset(ref), ref_flags(ref))); - if (retlen < sizeof(node.i)) { - printk(KERN_WARNING "read too short for dnode\n"); - err = -EIO; - goto free_out; - } - if (je32_to_cpu(node.i.version) > *highest_version) - *highest_version = je32_to_cpu(node.i.version); - D1(printk(KERN_DEBUG "version %d, highest_version now %d\n", je32_to_cpu(node.i.version), *highest_version)); - - if (ref_obsolete(ref)) { - /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ - printk(KERN_ERR "Inode node at 0x%08x became obsolete while we weren't looking\n", - ref_offset(ref)); - BUG(); - } + /* Continue calculating CRC */ + crc = crc32(tn->partial_crc, buffer, len); + if(!pointed) + kfree(buffer); +#ifndef __ECOS + else + c->mtd->unpoint(c->mtd, buffer, ofs, len); +#endif - /* If we've never checked the CRCs on this node, check them now. */ - if (ref_flags(ref) == REF_UNCHECKED) { - uint32_t crc, len; - struct jffs2_eraseblock *jeb; - - crc = crc32(0, &node, sizeof(node.i)-8); - if (crc != je32_to_cpu(node.i.node_crc)) { - printk(KERN_NOTICE "jffs2_get_inode_nodes(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", - ref_offset(ref), je32_to_cpu(node.i.node_crc), crc); - jffs2_mark_node_obsolete(c, ref); - spin_lock(&c->erase_completion_lock); - continue; - } - - /* sanity checks */ - if ( je32_to_cpu(node.i.offset) > je32_to_cpu(node.i.isize) || - PAD(je32_to_cpu(node.i.csize) + sizeof (node.i)) != PAD(je32_to_cpu(node.i.totlen))) { - printk(KERN_NOTICE "jffs2_get_inode_nodes(): Inode corrupted at 0x%08x, totlen %d, #ino %d, version %d, isize %d, csize %d, dsize %d \n", - ref_offset(ref), je32_to_cpu(node.i.totlen), je32_to_cpu(node.i.ino), - je32_to_cpu(node.i.version), je32_to_cpu(node.i.isize), - je32_to_cpu(node.i.csize), je32_to_cpu(node.i.dsize)); - jffs2_mark_node_obsolete(c, ref); - spin_lock(&c->erase_completion_lock); - continue; - } + if (crc != tn->data_crc) { + JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n", + ofs, tn->data_crc, crc); + return 1; + } - if (node.i.compr != JFFS2_COMPR_ZERO && je32_to_cpu(node.i.csize)) { - unsigned char *buf=NULL; - uint32_t pointed = 0; -#ifndef __ECOS - if (c->mtd->point) { - err = c->mtd->point (c->mtd, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize), - &retlen, &buf); - if (!err && retlen < je32_to_cpu(node.i.csize)) { - D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen)); - c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize)); - } else if (err){ - D1(printk(KERN_DEBUG "MTD point failed %d\n", err)); - } else - pointed = 1; /* succefully pointed to device */ - } -#endif - if(!pointed){ - buf = kmalloc(je32_to_cpu(node.i.csize), GFP_KERNEL); - if (!buf) - return -ENOMEM; - - err = jffs2_flash_read(c, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize), - &retlen, buf); - if (!err && retlen != je32_to_cpu(node.i.csize)) - err = -EIO; - if (err) { - kfree(buf); - return err; - } - } - crc = crc32(0, buf, je32_to_cpu(node.i.csize)); - if(!pointed) - kfree(buf); +adj_acc: + jeb = &c->blocks[ref->flash_offset / c->sector_size]; + len = ref_totlen(c, jeb, ref); + + /* + * Mark the node as having been checked and fix the + * accounting accordingly. + */ + spin_lock(&c->erase_completion_lock); + jeb->used_size += len; + jeb->unchecked_size -= len; + c->used_size += len; + c->unchecked_size -= len; + spin_unlock(&c->erase_completion_lock); + + return 0; + +free_out: + if(!pointed) + kfree(buffer); #ifndef __ECOS - else - c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize)); + else + c->mtd->unpoint(c->mtd, buffer, ofs, len); #endif + return err; +} - if (crc != je32_to_cpu(node.i.data_crc)) { - printk(KERN_NOTICE "jffs2_get_inode_nodes(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", - ref_offset(ref), je32_to_cpu(node.i.data_crc), crc); - jffs2_mark_node_obsolete(c, ref); - spin_lock(&c->erase_completion_lock); - continue; - } - - } +/* + * Helper function for jffs2_add_older_frag_to_fragtree(). + * + * Checks the node if we are in the checking stage. + */ +static inline int check_node(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn) +{ + int ret; - /* Mark the node as having been checked and fix the accounting accordingly */ - spin_lock(&c->erase_completion_lock); - jeb = &c->blocks[ref->flash_offset / c->sector_size]; - len = ref_totlen(c, jeb, ref); - - jeb->used_size += len; - jeb->unchecked_size -= len; - c->used_size += len; - c->unchecked_size -= len; - - /* If node covers at least a whole page, or if it starts at the - beginning of a page and runs to the end of the file, or if - it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. - - If it's actually overlapped, it'll get made NORMAL (or OBSOLETE) - when the overlapping node(s) get added to the tree anyway. - */ - if ((je32_to_cpu(node.i.dsize) >= PAGE_CACHE_SIZE) || - ( ((je32_to_cpu(node.i.offset)&(PAGE_CACHE_SIZE-1))==0) && - (je32_to_cpu(node.i.dsize)+je32_to_cpu(node.i.offset) == je32_to_cpu(node.i.isize)))) { - D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_PRISTINE\n", ref_offset(ref))); - ref->flash_offset = ref_offset(ref) | REF_PRISTINE; - } else { - D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_NORMAL\n", ref_offset(ref))); - ref->flash_offset = ref_offset(ref) | REF_NORMAL; - } - spin_unlock(&c->erase_completion_lock); + BUG_ON(ref_obsolete(tn->fn->raw)); + + /* We only check the data CRC of unchecked nodes */ + if (ref_flags(tn->fn->raw) != REF_UNCHECKED) + return 0; + + dbg_fragtree2("check node %#04x-%#04x, phys offs %#08x.\n", + tn->fn->ofs, tn->fn->ofs + tn->fn->size, ref_offset(tn->fn->raw)); + + ret = check_node_data(c, tn); + if (unlikely(ret < 0)) { + JFFS2_ERROR("check_node_data() returned error: %d.\n", + ret); + } else if (unlikely(ret > 0)) { + dbg_fragtree2("CRC error, mark it obsolete.\n"); + jffs2_mark_node_obsolete(c, tn->fn->raw); + } + + return ret; +} + +/* + * Helper function for jffs2_add_older_frag_to_fragtree(). + * + * Called when the new fragment that is being inserted + * splits a hole fragment. + */ +static int split_hole(struct jffs2_sb_info *c, struct rb_root *root, + struct jffs2_node_frag *newfrag, struct jffs2_node_frag *hole) +{ + dbg_fragtree2("fragment %#04x-%#04x splits the hole %#04x-%#04x\n", + newfrag->ofs, newfrag->ofs + newfrag->size, hole->ofs, hole->ofs + hole->size); + + if (hole->ofs == newfrag->ofs) { + /* + * Well, the new fragment actually starts at the same offset as + * the hole. + */ + if (hole->ofs + hole->size > newfrag->ofs + newfrag->size) { + /* + * We replace the overlapped left part of the hole by + * the new node. + */ + + dbg_fragtree2("insert fragment %#04x-%#04x and cut the left part of the hole\n", + newfrag->ofs, newfrag->ofs + newfrag->size); + rb_replace_node(&hole->rb, &newfrag->rb, root); + + hole->ofs += newfrag->size; + hole->size -= newfrag->size; + + /* + * We know that 'hole' should be the right hand + * fragment. + */ + jffs2_fragtree_insert(hole, newfrag); + rb_insert_color(&hole->rb, root); + } else { + /* + * Ah, the new fragment is of the same size as the hole. + * Relace the hole by it. + */ + dbg_fragtree2("insert fragment %#04x-%#04x and overwrite hole\n", + newfrag->ofs, newfrag->ofs + newfrag->size); + rb_replace_node(&hole->rb, &newfrag->rb, root); + jffs2_free_node_frag(hole); + } + } else { + /* The new fragment lefts some hole space at the left */ + + struct jffs2_node_frag * newfrag2 = NULL; + + if (hole->ofs + hole->size > newfrag->ofs + newfrag->size) { + /* The new frag also lefts some space at the right */ + newfrag2 = new_fragment(NULL, newfrag->ofs + + newfrag->size, hole->ofs + hole->size + - newfrag->ofs - newfrag->size); + if (unlikely(!newfrag2)) { + jffs2_free_node_frag(newfrag); + return -ENOMEM; } + } + + hole->size = newfrag->ofs - hole->ofs; + dbg_fragtree2("left the hole %#04x-%#04x at the left and inserd fragment %#04x-%#04x\n", + hole->ofs, hole->ofs + hole->size, newfrag->ofs, newfrag->ofs + newfrag->size); + + jffs2_fragtree_insert(newfrag, hole); + rb_insert_color(&newfrag->rb, root); + + if (newfrag2) { + dbg_fragtree2("left the hole %#04x-%#04x at the right\n", + newfrag2->ofs, newfrag2->ofs + newfrag2->size); + jffs2_fragtree_insert(newfrag2, newfrag); + rb_insert_color(&newfrag2->rb, root); + } + } + + return 0; +} + +/* + * This function is used when we build inode. It expects the nodes are passed + * in the decreasing version order. The whole point of this is to improve the + * inodes checking on NAND: we check the nodes' data CRC only when they are not + * obsoleted. Previously, add_frag_to_fragtree() function was used and + * nodes were passed to it in the increasing version ordes and CRCs of all + * nodes were checked. + * + * Note: tn->fn->size shouldn't be zero. + * + * Returns 0 if the node was inserted + * 1 if it wasn't inserted (since it is obsolete) + * < 0 an if error occured + */ +int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode_info *f, + struct jffs2_tmp_dnode_info *tn) +{ + struct jffs2_node_frag *this, *newfrag; + uint32_t lastend; + struct jffs2_full_dnode *fn = tn->fn; + struct rb_root *root = &f->fragtree; + uint32_t fn_size = fn->size, fn_ofs = fn->ofs; + int err, checked = 0; + int ref_flag; + + dbg_fragtree("insert fragment %#04x-%#04x, ver %u\n", fn_ofs, fn_ofs + fn_size, tn->version); + + /* Skip all the nodes which are completed before this one starts */ + this = jffs2_lookup_node_frag(root, fn_ofs); + if (this) + dbg_fragtree2("'this' found %#04x-%#04x (%s)\n", this->ofs, this->ofs + this->size, this->node ? "data" : "hole"); + + if (this) + lastend = this->ofs + this->size; + else + lastend = 0; + + /* Detect the preliminary type of node */ + if (fn->size >= PAGE_CACHE_SIZE) + ref_flag = REF_PRISTINE; + else + ref_flag = REF_NORMAL; + + /* See if we ran off the end of the root */ + if (lastend <= fn_ofs) { + /* We did */ + + /* + * We are going to insert the new node into the + * fragment tree, so check it. + */ + err = check_node(c, f, tn); + if (err != 0) + return err; + + fn->frags = 1; + + newfrag = new_fragment(fn, fn_ofs, fn_size); + if (unlikely(!newfrag)) + return -ENOMEM; + + err = no_overlapping_node(c, root, newfrag, this, lastend); + if (unlikely(err != 0)) { + jffs2_free_node_frag(newfrag); + return err; + } + + goto out_ok; + } - tn = jffs2_alloc_tmp_dnode_info(); - if (!tn) { - D1(printk(KERN_DEBUG "alloc tn failed\n")); - err = -ENOMEM; - goto free_out; + fn->frags = 0; + + while (1) { + /* + * Here we have: + * fn_ofs < this->ofs + this->size && fn_ofs >= this->ofs. + * + * Remember, 'this' has higher version, any non-hole node + * which is already in the fragtree is newer then the newly + * inserted. + */ + if (!this->node) { + /* + * 'this' is the hole fragment, so at least the + * beginning of the new fragment is valid. + */ + + /* + * We are going to insert the new node into the + * fragment tree, so check it. + */ + if (!checked) { + err = check_node(c, f, tn); + if (unlikely(err != 0)) + return err; + checked = 1; } - tn->fn = jffs2_alloc_full_dnode(); - if (!tn->fn) { - D1(printk(KERN_DEBUG "alloc fn failed\n")); - err = -ENOMEM; - jffs2_free_tmp_dnode_info(tn); - goto free_out; + if (this->ofs + this->size >= fn_ofs + fn_size) { + /* We split the hole on two parts */ + + fn->frags += 1; + newfrag = new_fragment(fn, fn_ofs, fn_size); + if (unlikely(!newfrag)) + return -ENOMEM; + + err = split_hole(c, root, newfrag, this); + if (unlikely(err)) + return err; + goto out_ok; } - tn->version = je32_to_cpu(node.i.version); - tn->fn->ofs = je32_to_cpu(node.i.offset); - /* There was a bug where we wrote hole nodes out with - csize/dsize swapped. Deal with it */ - if (node.i.compr == JFFS2_COMPR_ZERO && !je32_to_cpu(node.i.dsize) && je32_to_cpu(node.i.csize)) - tn->fn->size = je32_to_cpu(node.i.csize); - else // normal case... - tn->fn->size = je32_to_cpu(node.i.dsize); - tn->fn->raw = ref; - D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %04x, dsize %04x\n", - ref_offset(ref), je32_to_cpu(node.i.version), - je32_to_cpu(node.i.offset), je32_to_cpu(node.i.dsize))); - jffs2_add_tn_to_tree(tn, &ret_tn); - break; - - default: - if (ref_flags(ref) == REF_UNCHECKED) { - struct jffs2_eraseblock *jeb; - uint32_t len; - - printk(KERN_ERR "Eep. Unknown node type %04x at %08x was marked REF_UNCHECKED\n", - je16_to_cpu(node.u.nodetype), ref_offset(ref)); - - /* Mark the node as having been checked and fix the accounting accordingly */ - spin_lock(&c->erase_completion_lock); - jeb = &c->blocks[ref->flash_offset / c->sector_size]; - len = ref_totlen(c, jeb, ref); - - jeb->used_size += len; - jeb->unchecked_size -= len; - c->used_size += len; - c->unchecked_size -= len; - - mark_ref_normal(ref); - spin_unlock(&c->erase_completion_lock); + + /* + * The beginning of the new fragment is valid since it + * overlaps the hole node. + */ + + ref_flag = REF_NORMAL; + + fn->frags += 1; + newfrag = new_fragment(fn, fn_ofs, + this->ofs + this->size - fn_ofs); + if (unlikely(!newfrag)) + return -ENOMEM; + + if (fn_ofs == this->ofs) { + /* + * The new node starts at the same offset as + * the hole and supersieds the hole. + */ + dbg_fragtree2("add the new fragment instead of hole %#04x-%#04x, refcnt %d\n", + fn_ofs, fn_ofs + this->ofs + this->size - fn_ofs, fn->frags); + + rb_replace_node(&this->rb, &newfrag->rb, root); + jffs2_free_node_frag(this); + } else { + /* + * The hole becomes shorter as its right part + * is supersieded by the new fragment. + */ + dbg_fragtree2("reduce size of hole %#04x-%#04x to %#04x-%#04x\n", + this->ofs, this->ofs + this->size, this->ofs, this->ofs + this->size - newfrag->size); + + dbg_fragtree2("add new fragment %#04x-%#04x, refcnt %d\n", fn_ofs, + fn_ofs + this->ofs + this->size - fn_ofs, fn->frags); + + this->size -= newfrag->size; + jffs2_fragtree_insert(newfrag, this); + rb_insert_color(&newfrag->rb, root); } - node.u.nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(node.u.nodetype)); - if (crc32(0, &node, sizeof(struct jffs2_unknown_node)-4) != je32_to_cpu(node.u.hdr_crc)) { - /* Hmmm. This should have been caught at scan time. */ - printk(KERN_ERR "Node header CRC failed at %08x. But it must have been OK earlier.\n", - ref_offset(ref)); - printk(KERN_ERR "Node was: { %04x, %04x, %08x, %08x }\n", - je16_to_cpu(node.u.magic), je16_to_cpu(node.u.nodetype), je32_to_cpu(node.u.totlen), - je32_to_cpu(node.u.hdr_crc)); - jffs2_mark_node_obsolete(c, ref); - } else switch(je16_to_cpu(node.u.nodetype) & JFFS2_COMPAT_MASK) { - case JFFS2_FEATURE_INCOMPAT: - printk(KERN_NOTICE "Unknown INCOMPAT nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref)); - /* EEP */ - BUG(); - break; - case JFFS2_FEATURE_ROCOMPAT: - printk(KERN_NOTICE "Unknown ROCOMPAT nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref)); - if (!(c->flags & JFFS2_SB_FLAG_RO)) - BUG(); - break; - case JFFS2_FEATURE_RWCOMPAT_COPY: - printk(KERN_NOTICE "Unknown RWCOMPAT_COPY nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref)); - break; - case JFFS2_FEATURE_RWCOMPAT_DELETE: - printk(KERN_NOTICE "Unknown RWCOMPAT_DELETE nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref)); - jffs2_mark_node_obsolete(c, ref); - break; + + fn_ofs += newfrag->size; + fn_size -= newfrag->size; + this = rb_entry(rb_next(&newfrag->rb), + struct jffs2_node_frag, rb); + + dbg_fragtree2("switch to the next 'this' fragment: %#04x-%#04x %s\n", + this->ofs, this->ofs + this->size, this->node ? "(data)" : "(hole)"); + } + + /* + * 'This' node is not the hole so it obsoletes the new fragment + * either fully or partially. + */ + if (this->ofs + this->size >= fn_ofs + fn_size) { + /* The new node is obsolete, drop it */ + if (fn->frags == 0) { + dbg_fragtree2("%#04x-%#04x is obsolete, mark it obsolete\n", fn_ofs, fn_ofs + fn_size); + ref_flag = REF_OBSOLETE; } + goto out_ok; + } else { + struct jffs2_node_frag *new_this; + + /* 'This' node obsoletes the beginning of the new node */ + dbg_fragtree2("the beginning %#04x-%#04x is obsolete\n", fn_ofs, this->ofs + this->size); + + ref_flag = REF_NORMAL; + + fn_size -= this->ofs + this->size - fn_ofs; + fn_ofs = this->ofs + this->size; + dbg_fragtree2("now considering %#04x-%#04x\n", fn_ofs, fn_ofs + fn_size); + + new_this = rb_entry(rb_next(&this->rb), struct jffs2_node_frag, rb); + if (!new_this) { + /* + * There is no next fragment. Add the rest of + * the new node as the right-hand child. + */ + if (!checked) { + err = check_node(c, f, tn); + if (unlikely(err != 0)) + return err; + checked = 1; + } + fn->frags += 1; + newfrag = new_fragment(fn, fn_ofs, fn_size); + if (unlikely(!newfrag)) + return -ENOMEM; + + dbg_fragtree2("there are no more fragments, insert %#04x-%#04x\n", + newfrag->ofs, newfrag->ofs + newfrag->size); + rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right); + rb_insert_color(&newfrag->rb, root); + goto out_ok; + } else { + this = new_this; + dbg_fragtree2("switch to the next 'this' fragment: %#04x-%#04x %s\n", + this->ofs, this->ofs + this->size, this->node ? "(data)" : "(hole)"); + } } - spin_lock(&c->erase_completion_lock); + } + +out_ok: + BUG_ON(fn->size < PAGE_CACHE_SIZE && ref_flag == REF_PRISTINE); + if (ref_flag == REF_OBSOLETE) { + dbg_fragtree2("the node is obsolete now\n"); + /* jffs2_mark_node_obsolete() will adjust space accounting */ + jffs2_mark_node_obsolete(c, fn->raw); + return 1; } + + dbg_fragtree2("the node is \"%s\" now\n", ref_flag == REF_NORMAL ? "REF_NORMAL" : "REF_PRISTINE"); + + /* Space accounting was adjusted at check_node_data() */ + spin_lock(&c->erase_completion_lock); + fn->raw->flash_offset = ref_offset(fn->raw) | ref_flag; spin_unlock(&c->erase_completion_lock); - *tnp = ret_tn; - *fdp = ret_fd; return 0; - - free_out: - jffs2_free_tmp_dnode_info_list(&ret_tn); - jffs2_free_full_dirent_list(ret_fd); - return err; } void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state) @@ -499,24 +862,21 @@ void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache /* During mount, this needs no locking. During normal operation, its callers want to do other stuff while still holding the inocache_lock. - Rather than introducing special case get_ino_cache functions or + Rather than introducing special case get_ino_cache functions or callbacks, we just let the caller do the locking itself. */ - + struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino) { struct jffs2_inode_cache *ret; - D2(printk(KERN_DEBUG "jffs2_get_ino_cache(): ino %u\n", ino)); - ret = c->inocache_list[ino % INOCACHE_HASHSIZE]; while (ret && ret->ino < ino) { ret = ret->next; } - + if (ret && ret->ino != ino) ret = NULL; - D2(printk(KERN_DEBUG "jffs2_get_ino_cache found %p for ino %u\n", ret, ino)); return ret; } @@ -528,7 +888,7 @@ void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new if (!new->ino) new->ino = ++c->highest_ino; - D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino)); + dbg_inocache("add %p (ino #%u)\n", new, new->ino); prev = &c->inocache_list[new->ino % INOCACHE_HASHSIZE]; @@ -544,11 +904,12 @@ void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old) { struct jffs2_inode_cache **prev; - D1(printk(KERN_DEBUG "jffs2_del_ino_cache: Del %p (ino #%u)\n", old, old->ino)); + + dbg_inocache("del %p (ino #%u)\n", old, old->ino); spin_lock(&c->inocache_lock); - + prev = &c->inocache_list[old->ino % INOCACHE_HASHSIZE]; - + while ((*prev) && (*prev)->ino < old->ino) { prev = &(*prev)->next; } @@ -558,7 +919,7 @@ void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old) /* Free it now unless it's in READING or CLEARING state, which are the transitions upon read_inode() and clear_inode(). The - rest of the time we know nobody else is looking at it, and + rest of the time we know nobody else is looking at it, and if it's held by read_inode() or clear_inode() they'll free it for themselves. */ if (old->state != INO_STATE_READING && old->state != INO_STATE_CLEARING) @@ -571,7 +932,7 @@ void jffs2_free_ino_caches(struct jffs2_sb_info *c) { int i; struct jffs2_inode_cache *this, *next; - + for (i=0; iinocache_list[i]; while (this) { @@ -598,38 +959,30 @@ void jffs2_free_raw_node_refs(struct jffs2_sb_info *c) c->blocks[i].first_node = c->blocks[i].last_node = NULL; } } - + struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset) { - /* The common case in lookup is that there will be a node + /* The common case in lookup is that there will be a node which precisely matches. So we go looking for that first */ struct rb_node *next; struct jffs2_node_frag *prev = NULL; struct jffs2_node_frag *frag = NULL; - D2(printk(KERN_DEBUG "jffs2_lookup_node_frag(%p, %d)\n", fragtree, offset)); + dbg_fragtree2("root %p, offset %d\n", fragtree, offset); next = fragtree->rb_node; while(next) { frag = rb_entry(next, struct jffs2_node_frag, rb); - D2(printk(KERN_DEBUG "Considering frag %d-%d (%p). left %p, right %p\n", - frag->ofs, frag->ofs+frag->size, frag, frag->rb.rb_left, frag->rb.rb_right)); if (frag->ofs + frag->size <= offset) { - D2(printk(KERN_DEBUG "Going right from frag %d-%d, before the region we care about\n", - frag->ofs, frag->ofs+frag->size)); /* Remember the closest smaller match on the way down */ if (!prev || frag->ofs > prev->ofs) prev = frag; next = frag->rb.rb_right; } else if (frag->ofs > offset) { - D2(printk(KERN_DEBUG "Going left from frag %d-%d, after the region we care about\n", - frag->ofs, frag->ofs+frag->size)); next = frag->rb.rb_left; } else { - D2(printk(KERN_DEBUG "Returning frag %d,%d, matched\n", - frag->ofs, frag->ofs+frag->size)); return frag; } } @@ -638,11 +991,11 @@ struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_ and return the closest smaller one */ if (prev) - D2(printk(KERN_DEBUG "No match. Returning frag %d,%d, closest previous\n", - prev->ofs, prev->ofs+prev->size)); - else - D2(printk(KERN_DEBUG "Returning NULL, empty fragtree\n")); - + dbg_fragtree2("no match. Returning frag %#04x-%#04x, closest previous\n", + prev->ofs, prev->ofs+prev->size); + else + dbg_fragtree2("returning NULL, empty fragtree\n"); + return prev; } @@ -656,39 +1009,32 @@ void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c) if (!root->rb_node) return; - frag = (rb_entry(root->rb_node, struct jffs2_node_frag, rb)); + dbg_fragtree("killing\n"); + frag = (rb_entry(root->rb_node, struct jffs2_node_frag, rb)); while(frag) { if (frag->rb.rb_left) { - D2(printk(KERN_DEBUG "Going left from frag (%p) %d-%d\n", - frag, frag->ofs, frag->ofs+frag->size)); frag = frag_left(frag); continue; } if (frag->rb.rb_right) { - D2(printk(KERN_DEBUG "Going right from frag (%p) %d-%d\n", - frag, frag->ofs, frag->ofs+frag->size)); frag = frag_right(frag); continue; } - D2(printk(KERN_DEBUG "jffs2_kill_fragtree: frag at 0x%x-0x%x: node %p, frags %d--\n", - frag->ofs, frag->ofs+frag->size, frag->node, - frag->node?frag->node->frags:0)); - if (frag->node && !(--frag->node->frags)) { - /* Not a hole, and it's the final remaining frag + /* Not a hole, and it's the final remaining frag of this node. Free the node */ if (c) jffs2_mark_node_obsolete(c, frag->node->raw); - + jffs2_free_full_dnode(frag->node); } parent = frag_parent(frag); if (parent) { if (frag_left(parent) == frag) parent->rb.rb_left = NULL; - else + else parent->rb.rb_right = NULL; } @@ -698,29 +1044,3 @@ void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c) cond_resched(); } } - -void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base) -{ - struct rb_node *parent = &base->rb; - struct rb_node **link = &parent; - - D2(printk(KERN_DEBUG "jffs2_fragtree_insert(%p; %d-%d, %p)\n", newfrag, - newfrag->ofs, newfrag->ofs+newfrag->size, base)); - - while (*link) { - parent = *link; - base = rb_entry(parent, struct jffs2_node_frag, rb); - - D2(printk(KERN_DEBUG "fragtree_insert considering frag at 0x%x\n", base->ofs)); - if (newfrag->ofs > base->ofs) - link = &base->rb.rb_right; - else if (newfrag->ofs < base->ofs) - link = &base->rb.rb_left; - else { - printk(KERN_CRIT "Duplicate frag at %08x (%p,%p)\n", newfrag->ofs, newfrag, base); - BUG(); - } - } - - rb_link_node(&newfrag->rb, &base->rb, link); -} diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index b34c397909efd0ae3f53beca3c6dd69c6c49ff56..23a67bb3052f916fb60aee403aa48cf802c0c517 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodelist.h,v 1.131 2005/07/05 21:03:07 dwmw2 Exp $ + * $Id: nodelist.h,v 1.140 2005/09/07 08:34:54 havasi Exp $ * */ @@ -20,30 +20,15 @@ #include #include #include +#include "summary.h" #ifdef __ECOS #include "os-ecos.h" #else -#include /* For min/max in older kernels */ +#include /* For compatibility with older kernels */ #include "os-linux.h" #endif -#ifndef CONFIG_JFFS2_FS_DEBUG -#define CONFIG_JFFS2_FS_DEBUG 1 -#endif - -#if CONFIG_JFFS2_FS_DEBUG > 0 -#define D1(x) x -#else -#define D1(x) -#endif - -#if CONFIG_JFFS2_FS_DEBUG > 1 -#define D2(x) x -#else -#define D2(x) -#endif - #define JFFS2_NATIVE_ENDIAN /* Note we handle mode bits conversion from JFFS2 (i.e. Linux) to/from @@ -73,14 +58,17 @@ #define je16_to_cpu(x) (le16_to_cpu(x.v16)) #define je32_to_cpu(x) (le32_to_cpu(x.v32)) #define jemode_to_cpu(x) (le32_to_cpu(jffs2_to_os_mode((x).m))) -#else +#else #error wibble #endif +/* The minimal node header size */ +#define JFFS2_MIN_NODE_HEADER sizeof(struct jffs2_raw_dirent) + /* This is all we need to keep in-core for each raw node during normal operation. As and when we do read_inode on a particular inode, we can - scan the nodes which are listed for it and build up a proper map of + scan the nodes which are listed for it and build up a proper map of which nodes are currently valid. JFFSv1 always used to keep that whole map in core for each inode. */ @@ -97,7 +85,7 @@ struct jffs2_raw_node_ref /* flash_offset & 3 always has to be zero, because nodes are always aligned at 4 bytes. So we have a couple of extra bits - to play with, which indicate the node's status; see below: */ + to play with, which indicate the node's status; see below: */ #define REF_UNCHECKED 0 /* We haven't yet checked the CRC or built its inode */ #define REF_OBSOLETE 1 /* Obsolete, can be completely ignored */ #define REF_PRISTINE 2 /* Completely clean. GC without looking */ @@ -110,7 +98,7 @@ struct jffs2_raw_node_ref /* For each inode in the filesystem, we need to keep a record of nlink, because it would be a PITA to scan the whole directory tree at read_inode() time to calculate it, and to keep sufficient information - in the raw_node_ref (basically both parent and child inode number for + in the raw_node_ref (basically both parent and child inode number for dirent nodes) would take more space than this does. We also keep a pointer to the first physical node which is part of this inode, too. */ @@ -140,7 +128,7 @@ struct jffs2_inode_cache { #define INOCACHE_HASHSIZE 128 /* - Larger representation of a raw node, kept in-core only when the + Larger representation of a raw node, kept in-core only when the struct inode for this particular ino is instantiated. */ @@ -150,11 +138,11 @@ struct jffs2_full_dnode uint32_t ofs; /* The offset to which the data of this node belongs */ uint32_t size; uint32_t frags; /* Number of fragments which currently refer - to this node. When this reaches zero, + to this node. When this reaches zero, the node is obsolete. */ }; -/* +/* Even larger representation of a raw node, kept in-core only while we're actually building up the original map of which nodes go where, in read_inode() @@ -164,7 +152,10 @@ struct jffs2_tmp_dnode_info struct rb_node rb; struct jffs2_full_dnode *fn; uint32_t version; -}; + uint32_t data_crc; + uint32_t partial_crc; + uint32_t csize; +}; struct jffs2_full_dirent { @@ -178,7 +169,7 @@ struct jffs2_full_dirent }; /* - Fragments - used to build a map of which raw node to obtain + Fragments - used to build a map of which raw node to obtain data from for each part of the ino */ struct jffs2_node_frag @@ -207,86 +198,18 @@ struct jffs2_eraseblock struct jffs2_raw_node_ref *gc_node; /* Next node to be garbage collected */ }; -#define ACCT_SANITY_CHECK(c, jeb) do { \ - struct jffs2_eraseblock *___j = jeb; \ - if ((___j) && ___j->used_size + ___j->dirty_size + ___j->free_size + ___j->wasted_size + ___j->unchecked_size != c->sector_size) { \ - printk(KERN_NOTICE "Eeep. Space accounting for block at 0x%08x is screwed\n", ___j->offset); \ - printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + wasted %08x + unchecked %08x != total %08x\n", \ - ___j->free_size, ___j->dirty_size, ___j->used_size, ___j->wasted_size, ___j->unchecked_size, c->sector_size); \ - BUG(); \ - } \ - if (c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size + c->wasted_size + c->unchecked_size != c->flash_size) { \ - printk(KERN_NOTICE "Eeep. Space accounting superblock info is screwed\n"); \ - printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + erasing %08x + bad %08x + wasted %08x + unchecked %08x != total %08x\n", \ - c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size, c->wasted_size, c->unchecked_size, c->flash_size); \ - BUG(); \ - } \ -} while(0) - -static inline void paranoia_failed_dump(struct jffs2_eraseblock *jeb) +static inline int jffs2_blocks_use_vmalloc(struct jffs2_sb_info *c) { - struct jffs2_raw_node_ref *ref; - int i=0; - - printk(KERN_NOTICE); - for (ref = jeb->first_node; ref; ref = ref->next_phys) { - printk("%08x->", ref_offset(ref)); - if (++i == 8) { - i = 0; - printk("\n" KERN_NOTICE); - } - } - printk("\n"); + return ((c->flash_size / c->sector_size) * sizeof (struct jffs2_eraseblock)) > (128 * 1024); } - -#define ACCT_PARANOIA_CHECK(jeb) do { \ - uint32_t my_used_size = 0; \ - uint32_t my_unchecked_size = 0; \ - struct jffs2_raw_node_ref *ref2 = jeb->first_node; \ - while (ref2) { \ - if (unlikely(ref2->flash_offset < jeb->offset || \ - ref2->flash_offset > jeb->offset + c->sector_size)) { \ - printk(KERN_NOTICE "Node %08x shouldn't be in block at %08x!\n", \ - ref_offset(ref2), jeb->offset); \ - paranoia_failed_dump(jeb); \ - BUG(); \ - } \ - if (ref_flags(ref2) == REF_UNCHECKED) \ - my_unchecked_size += ref_totlen(c, jeb, ref2); \ - else if (!ref_obsolete(ref2)) \ - my_used_size += ref_totlen(c, jeb, ref2); \ - if (unlikely((!ref2->next_phys) != (ref2 == jeb->last_node))) { \ - if (!ref2->next_phys) \ - printk("ref for node at %p (phys %08x) has next_phys->%p (----), last_node->%p (phys %08x)\n", \ - ref2, ref_offset(ref2), ref2->next_phys, \ - jeb->last_node, ref_offset(jeb->last_node)); \ - else \ - printk("ref for node at %p (phys %08x) has next_phys->%p (%08x), last_node->%p (phys %08x)\n", \ - ref2, ref_offset(ref2), ref2->next_phys, ref_offset(ref2->next_phys), \ - jeb->last_node, ref_offset(jeb->last_node)); \ - paranoia_failed_dump(jeb); \ - BUG(); \ - } \ - ref2 = ref2->next_phys; \ - } \ - if (my_used_size != jeb->used_size) { \ - printk(KERN_NOTICE "Calculated used size %08x != stored used size %08x\n", my_used_size, jeb->used_size); \ - BUG(); \ - } \ - if (my_unchecked_size != jeb->unchecked_size) { \ - printk(KERN_NOTICE "Calculated unchecked size %08x != stored unchecked size %08x\n", my_unchecked_size, jeb->unchecked_size); \ - BUG(); \ - } \ - } while(0) - /* Calculate totlen from surrounding nodes or eraseblock */ static inline uint32_t __ref_totlen(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_node_ref *ref) { uint32_t ref_end; - + if (ref->next_phys) ref_end = ref_offset(ref->next_phys); else { @@ -306,11 +229,13 @@ static inline uint32_t ref_totlen(struct jffs2_sb_info *c, { uint32_t ret; - D1(if (jeb && jeb != &c->blocks[ref->flash_offset / c->sector_size]) { +#if CONFIG_JFFS2_FS_DEBUG > 0 + if (jeb && jeb != &c->blocks[ref->flash_offset / c->sector_size]) { printk(KERN_CRIT "ref_totlen called with wrong block -- at 0x%08x instead of 0x%08x; ref 0x%08x\n", jeb->offset, c->blocks[ref->flash_offset / c->sector_size].offset, ref_offset(ref)); BUG(); - }) + } +#endif #if 1 ret = ref->__totlen; @@ -323,14 +248,13 @@ static inline uint32_t ref_totlen(struct jffs2_sb_info *c, ret, ref->__totlen); if (!jeb) jeb = &c->blocks[ref->flash_offset / c->sector_size]; - paranoia_failed_dump(jeb); + jffs2_dbg_dump_node_refs_nolock(c, jeb); BUG(); } #endif return ret; } - #define ALLOC_NORMAL 0 /* Normal allocation */ #define ALLOC_DELETION 1 /* Deletion node. Best to allow it */ #define ALLOC_GC 2 /* Space requested for GC. Give it or die */ @@ -340,7 +264,7 @@ static inline uint32_t ref_totlen(struct jffs2_sb_info *c, #define VERYDIRTY(c, size) ((size) >= ((c)->sector_size / 2)) /* check if dirty space is more than 255 Byte */ -#define ISDIRTY(size) ((size) > sizeof (struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN) +#define ISDIRTY(size) ((size) > sizeof (struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN) #define PAD(x) (((x)+3)&~3) @@ -384,12 +308,7 @@ static inline struct jffs2_node_frag *frag_last(struct rb_root *root) #define frag_erase(frag, list) rb_erase(&frag->rb, list); /* nodelist.c */ -D2(void jffs2_print_frag_list(struct jffs2_inode_info *f)); void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list); -int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, - struct rb_root *tnp, struct jffs2_full_dirent **fdp, - uint32_t *highest_version, uint32_t *latest_mctime, - uint32_t *mctime_ver); void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state); struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino); void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new); @@ -398,19 +317,23 @@ void jffs2_free_ino_caches(struct jffs2_sb_info *c); void jffs2_free_raw_node_refs(struct jffs2_sb_info *c); struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset); void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c_delete); -void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base); struct rb_node *rb_next(struct rb_node *); struct rb_node *rb_prev(struct rb_node *); void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root); +void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this); +int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn); +void jffs2_truncate_fragtree (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size); +int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn); /* nodemgmt.c */ int jffs2_thread_should_wake(struct jffs2_sb_info *c); -int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio); -int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len); +int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, + uint32_t *len, int prio, uint32_t sumsize); +int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, + uint32_t *len, uint32_t sumsize); int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new); void jffs2_complete_reservation(struct jffs2_sb_info *c); void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *raw); -void jffs2_dump_block_lists(struct jffs2_sb_info *c); /* write.c */ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri); @@ -418,17 +341,15 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs, int alloc_mode); struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_dirent *rd, const unsigned char *name, uint32_t namelen, uint32_t flash_ofs, int alloc_mode); int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, - struct jffs2_raw_inode *ri, unsigned char *buf, + struct jffs2_raw_inode *ri, unsigned char *buf, uint32_t offset, uint32_t writelen, uint32_t *retlen); int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const char *name, int namelen); -int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, const char *name, int namelen, struct jffs2_inode_info *dead_f); -int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen); +int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, const char *name, int namelen, struct jffs2_inode_info *dead_f, uint32_t time); +int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen, uint32_t time); /* readinode.c */ -void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size); -int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn); -int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, +int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t ino, struct jffs2_raw_inode *latest_node); int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic); void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f); @@ -468,6 +389,10 @@ char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f); /* scan.c */ int jffs2_scan_medium(struct jffs2_sb_info *c); void jffs2_rotate_lists(struct jffs2_sb_info *c); +int jffs2_fill_scan_buf(struct jffs2_sb_info *c, void *buf, + uint32_t ofs, uint32_t len); +struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino); +int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); /* build.c */ int jffs2_do_mount_fs(struct jffs2_sb_info *c); @@ -483,4 +408,6 @@ int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); #endif +#include "debug.h" + #endif /* __JFFS2_NODELIST_H__ */ diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index c1d8b5ed9ab95221b89b2af4bbcdd985de16775f..49127a1f045861324bab8e79570b895b7b1ab4c5 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodemgmt.c,v 1.122 2005/05/06 09:30:27 dedekind Exp $ + * $Id: nodemgmt.c,v 1.127 2005/09/20 15:49:12 dedekind Exp $ * */ @@ -17,6 +17,7 @@ #include #include /* For cond_resched() */ #include "nodelist.h" +#include "debug.h" /** * jffs2_reserve_space - request physical space to write nodes to flash @@ -38,9 +39,11 @@ * for the requested allocation. */ -static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len); +static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, + uint32_t *ofs, uint32_t *len, uint32_t sumsize); -int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio) +int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, + uint32_t *len, int prio, uint32_t sumsize) { int ret = -EAGAIN; int blocksneeded = c->resv_blocks_write; @@ -85,12 +88,12 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs up(&c->alloc_sem); return -ENOSPC; } - + /* Calc possibly available space. Possibly available means that we * don't know, if unchecked size contains obsoleted nodes, which could give us some * more usable space. This will affect the sum only once, as gc first finishes checking * of nodes. - + Return -ENOSPC, if the maximum possibly available space is less or equal than + + Return -ENOSPC, if the maximum possibly available space is less or equal than * blocksneeded * sector_size. * This blocks endless gc looping on a filesystem, which is nearly full, even if * the check above passes. @@ -115,7 +118,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->wasted_size, c->used_size, c->erasing_size, c->bad_size, c->free_size + c->dirty_size + c->wasted_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size)); spin_unlock(&c->erase_completion_lock); - + ret = jffs2_garbage_collect_pass(c); if (ret) return ret; @@ -129,7 +132,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs spin_lock(&c->erase_completion_lock); } - ret = jffs2_do_reserve_space(c, minsize, ofs, len); + ret = jffs2_do_reserve_space(c, minsize, ofs, len, sumsize); if (ret) { D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret)); } @@ -140,7 +143,8 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs return ret; } -int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len) +int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, + uint32_t *len, uint32_t sumsize) { int ret = -EAGAIN; minsize = PAD(minsize); @@ -149,7 +153,7 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t * spin_lock(&c->erase_completion_lock); while(ret == -EAGAIN) { - ret = jffs2_do_reserve_space(c, minsize, ofs, len); + ret = jffs2_do_reserve_space(c, minsize, ofs, len, sumsize); if (ret) { D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret)); } @@ -158,105 +162,185 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t * return ret; } -/* Called with alloc sem _and_ erase_completion_lock */ -static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len) + +/* Classify nextblock (clean, dirty of verydirty) and force to select an other one */ + +static void jffs2_close_nextblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { - struct jffs2_eraseblock *jeb = c->nextblock; - - restart: - if (jeb && minsize > jeb->free_size) { - /* Skip the end of this block and file it as having some dirty space */ - /* If there's a pending write to it, flush now */ - if (jffs2_wbuf_dirty(c)) { + + /* Check, if we have a dirty block now, or if it was dirty already */ + if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) { + c->dirty_size += jeb->wasted_size; + c->wasted_size -= jeb->wasted_size; + jeb->dirty_size += jeb->wasted_size; + jeb->wasted_size = 0; + if (VERYDIRTY(c, jeb->dirty_size)) { + D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", + jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); + list_add_tail(&jeb->list, &c->very_dirty_list); + } else { + D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", + jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); + list_add_tail(&jeb->list, &c->dirty_list); + } + } else { + D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", + jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); + list_add_tail(&jeb->list, &c->clean_list); + } + c->nextblock = NULL; + +} + +/* Select a new jeb for nextblock */ + +static int jffs2_find_nextblock(struct jffs2_sb_info *c) +{ + struct list_head *next; + + /* Take the next block off the 'free' list */ + + if (list_empty(&c->free_list)) { + + if (!c->nr_erasing_blocks && + !list_empty(&c->erasable_list)) { + struct jffs2_eraseblock *ejeb; + + ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list); + list_del(&ejeb->list); + list_add_tail(&ejeb->list, &c->erase_pending_list); + c->nr_erasing_blocks++; + jffs2_erase_pending_trigger(c); + D1(printk(KERN_DEBUG "jffs2_find_nextblock: Triggering erase of erasable block at 0x%08x\n", + ejeb->offset)); + } + + if (!c->nr_erasing_blocks && + !list_empty(&c->erasable_pending_wbuf_list)) { + D1(printk(KERN_DEBUG "jffs2_find_nextblock: Flushing write buffer\n")); + /* c->nextblock is NULL, no update to c->nextblock allowed */ spin_unlock(&c->erase_completion_lock); - D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n")); jffs2_flush_wbuf_pad(c); spin_lock(&c->erase_completion_lock); - jeb = c->nextblock; - goto restart; + /* Have another go. It'll be on the erasable_list now */ + return -EAGAIN; } - c->wasted_size += jeb->free_size; - c->free_size -= jeb->free_size; - jeb->wasted_size += jeb->free_size; - jeb->free_size = 0; - - /* Check, if we have a dirty block now, or if it was dirty already */ - if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) { - c->dirty_size += jeb->wasted_size; - c->wasted_size -= jeb->wasted_size; - jeb->dirty_size += jeb->wasted_size; - jeb->wasted_size = 0; - if (VERYDIRTY(c, jeb->dirty_size)) { - D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", - jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); - list_add_tail(&jeb->list, &c->very_dirty_list); - } else { - D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", - jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); - list_add_tail(&jeb->list, &c->dirty_list); - } - } else { - D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", - jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); - list_add_tail(&jeb->list, &c->clean_list); + + if (!c->nr_erasing_blocks) { + /* Ouch. We're in GC, or we wouldn't have got here. + And there's no space left. At all. */ + printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n", + c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasable_list)?"yes":"no", + list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no"); + return -ENOSPC; } - c->nextblock = jeb = NULL; + + spin_unlock(&c->erase_completion_lock); + /* Don't wait for it; just erase one right now */ + jffs2_erase_pending_blocks(c, 1); + spin_lock(&c->erase_completion_lock); + + /* An erase may have failed, decreasing the + amount of free space available. So we must + restart from the beginning */ + return -EAGAIN; } - - if (!jeb) { - struct list_head *next; - /* Take the next block off the 'free' list */ - if (list_empty(&c->free_list)) { + next = c->free_list.next; + list_del(next); + c->nextblock = list_entry(next, struct jffs2_eraseblock, list); + c->nr_free_blocks--; - if (!c->nr_erasing_blocks && - !list_empty(&c->erasable_list)) { - struct jffs2_eraseblock *ejeb; + jffs2_sum_reset_collected(c->summary); /* reset collected summary */ - ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list); - list_del(&ejeb->list); - list_add_tail(&ejeb->list, &c->erase_pending_list); - c->nr_erasing_blocks++; - jffs2_erase_pending_trigger(c); - D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Triggering erase of erasable block at 0x%08x\n", - ejeb->offset)); + D1(printk(KERN_DEBUG "jffs2_find_nextblock(): new nextblock = 0x%08x\n", c->nextblock->offset)); + + return 0; +} + +/* Called with alloc sem _and_ erase_completion_lock */ +static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, uint32_t sumsize) +{ + struct jffs2_eraseblock *jeb = c->nextblock; + uint32_t reserved_size; /* for summary information at the end of the jeb */ + int ret; + + restart: + reserved_size = 0; + + if (jffs2_sum_active() && (sumsize != JFFS2_SUMMARY_NOSUM_SIZE)) { + /* NOSUM_SIZE means not to generate summary */ + + if (jeb) { + reserved_size = PAD(sumsize + c->summary->sum_size + JFFS2_SUMMARY_FRAME_SIZE); + dbg_summary("minsize=%d , jeb->free=%d ," + "summary->size=%d , sumsize=%d\n", + minsize, jeb->free_size, + c->summary->sum_size, sumsize); + } + + /* Is there enough space for writing out the current node, or we have to + write out summary information now, close this jeb and select new nextblock? */ + if (jeb && (PAD(minsize) + PAD(c->summary->sum_size + sumsize + + JFFS2_SUMMARY_FRAME_SIZE) > jeb->free_size)) { + + /* Has summary been disabled for this jeb? */ + if (jffs2_sum_is_disabled(c->summary)) { + sumsize = JFFS2_SUMMARY_NOSUM_SIZE; + goto restart; } - if (!c->nr_erasing_blocks && - !list_empty(&c->erasable_pending_wbuf_list)) { - D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n")); - /* c->nextblock is NULL, no update to c->nextblock allowed */ + /* Writing out the collected summary information */ + dbg_summary("generating summary for 0x%08x.\n", jeb->offset); + ret = jffs2_sum_write_sumnode(c); + + if (ret) + return ret; + + if (jffs2_sum_is_disabled(c->summary)) { + /* jffs2_write_sumnode() couldn't write out the summary information + diabling summary for this jeb and free the collected information + */ + sumsize = JFFS2_SUMMARY_NOSUM_SIZE; + goto restart; + } + + jffs2_close_nextblock(c, jeb); + jeb = NULL; + /* keep always valid value in reserved_size */ + reserved_size = PAD(sumsize + c->summary->sum_size + JFFS2_SUMMARY_FRAME_SIZE); + } + } else { + if (jeb && minsize > jeb->free_size) { + /* Skip the end of this block and file it as having some dirty space */ + /* If there's a pending write to it, flush now */ + + if (jffs2_wbuf_dirty(c)) { spin_unlock(&c->erase_completion_lock); + D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n")); jffs2_flush_wbuf_pad(c); spin_lock(&c->erase_completion_lock); - /* Have another go. It'll be on the erasable_list now */ - return -EAGAIN; + jeb = c->nextblock; + goto restart; } - if (!c->nr_erasing_blocks) { - /* Ouch. We're in GC, or we wouldn't have got here. - And there's no space left. At all. */ - printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n", - c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasable_list)?"yes":"no", - list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no"); - return -ENOSPC; - } - - spin_unlock(&c->erase_completion_lock); - /* Don't wait for it; just erase one right now */ - jffs2_erase_pending_blocks(c, 1); - spin_lock(&c->erase_completion_lock); + c->wasted_size += jeb->free_size; + c->free_size -= jeb->free_size; + jeb->wasted_size += jeb->free_size; + jeb->free_size = 0; - /* An erase may have failed, decreasing the - amount of free space available. So we must - restart from the beginning */ - return -EAGAIN; + jffs2_close_nextblock(c, jeb); + jeb = NULL; } + } + + if (!jeb) { - next = c->free_list.next; - list_del(next); - c->nextblock = jeb = list_entry(next, struct jffs2_eraseblock, list); - c->nr_free_blocks--; + ret = jffs2_find_nextblock(c); + if (ret) + return ret; + + jeb = c->nextblock; if (jeb->free_size != c->sector_size - c->cleanmarker_size) { printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size); @@ -266,13 +350,13 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui /* OK, jeb (==c->nextblock) is now pointing at a block which definitely has enough space */ *ofs = jeb->offset + (c->sector_size - jeb->free_size); - *len = jeb->free_size; + *len = jeb->free_size - reserved_size; if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size && !jeb->first_node->next_in_ino) { - /* Only node in it beforehand was a CLEANMARKER node (we think). + /* Only node in it beforehand was a CLEANMARKER node (we think). So mark it obsolete now that there's going to be another node - in the block. This will reduce used_size to zero but We've + in the block. This will reduce used_size to zero but We've already set c->nextblock so that jffs2_mark_node_obsolete() won't try to refile it to the dirty_list. */ @@ -292,12 +376,12 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui * @len: length of this physical node * @dirty: dirty flag for new node * - * Should only be used to report nodes for which space has been allocated + * Should only be used to report nodes for which space has been allocated * by jffs2_reserve_space. * * Must be called with the alloc_sem held. */ - + int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new) { struct jffs2_eraseblock *jeb; @@ -349,8 +433,8 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r list_add_tail(&jeb->list, &c->clean_list); c->nextblock = NULL; } - ACCT_SANITY_CHECK(c,jeb); - D1(ACCT_PARANOIA_CHECK(jeb)); + jffs2_dbg_acct_sanity_check_nolock(c,jeb); + jffs2_dbg_acct_paranoia_check_nolock(c, jeb); spin_unlock(&c->erase_completion_lock); @@ -404,8 +488,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref if (jffs2_can_mark_obsolete(c) && !jffs2_is_readonly(c) && !(c->flags & (JFFS2_SB_FLAG_SCANNING | JFFS2_SB_FLAG_BUILDING))) { - /* Hm. This may confuse static lock analysis. If any of the above - three conditions is false, we're going to return from this + /* Hm. This may confuse static lock analysis. If any of the above + three conditions is false, we're going to return from this function without actually obliterating any nodes or freeing any jffs2_raw_node_refs. So we don't need to stop erases from happening, or protect against people holding an obsolete @@ -430,7 +514,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref ref_totlen(c, jeb, ref), blocknr, ref->flash_offset, jeb->used_size); BUG(); }) - D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %x: ", ref_offset(ref), ref_totlen(c, jeb, ref))); + D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %#x: ", ref_offset(ref), ref_totlen(c, jeb, ref))); jeb->used_size -= ref_totlen(c, jeb, ref); c->used_size -= ref_totlen(c, jeb, ref); } @@ -462,18 +546,17 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref D1(printk(KERN_DEBUG "Wasting\n")); addedsize = 0; jeb->wasted_size += ref_totlen(c, jeb, ref); - c->wasted_size += ref_totlen(c, jeb, ref); + c->wasted_size += ref_totlen(c, jeb, ref); } ref->flash_offset = ref_offset(ref) | REF_OBSOLETE; - - ACCT_SANITY_CHECK(c, jeb); - D1(ACCT_PARANOIA_CHECK(jeb)); + jffs2_dbg_acct_sanity_check_nolock(c, jeb); + jffs2_dbg_acct_paranoia_check_nolock(c, jeb); if (c->flags & JFFS2_SB_FLAG_SCANNING) { /* Flash scanning is in progress. Don't muck about with the block lists because they're not ready yet, and don't actually - obliterate nodes that look obsolete. If they weren't + obliterate nodes that look obsolete. If they weren't marked obsolete on the flash at the time they _became_ obsolete, there was probably a reason for that. */ spin_unlock(&c->erase_completion_lock); @@ -507,7 +590,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref immediately reused, and we spread the load a bit. */ D1(printk(KERN_DEBUG "...and adding to erasable_list\n")); list_add_tail(&jeb->list, &c->erasable_list); - } + } } D1(printk(KERN_DEBUG "Done OK\n")); } else if (jeb == c->gcblock) { @@ -525,8 +608,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref list_add_tail(&jeb->list, &c->very_dirty_list); } else { D1(printk(KERN_DEBUG "Eraseblock at 0x%08x not moved anywhere. (free 0x%08x, dirty 0x%08x, used 0x%08x)\n", - jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); - } + jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); + } spin_unlock(&c->erase_completion_lock); @@ -573,11 +656,11 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref /* Nodes which have been marked obsolete no longer need to be associated with any inode. Remove them from the per-inode list. - - Note we can't do this for NAND at the moment because we need + + Note we can't do this for NAND at the moment because we need obsolete dirent nodes to stay on the lists, because of the horridness in jffs2_garbage_collect_deletion_dirent(). Also - because we delete the inocache, and on NAND we need that to + because we delete the inocache, and on NAND we need that to stay around until all the nodes are actually erased, in order to stop us from giving the same inode number to another newly created inode. */ @@ -606,7 +689,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref if (ref->next_phys && ref_obsolete(ref->next_phys) && !ref->next_phys->next_in_ino) { struct jffs2_raw_node_ref *n = ref->next_phys; - + spin_lock(&c->erase_completion_lock); ref->__totlen += n->__totlen; @@ -620,7 +703,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref jffs2_free_raw_node_ref(n); } - + /* Also merge with the previous node in the list, if there is one and that one is obsolete */ if (ref != jeb->first_node ) { @@ -630,7 +713,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref while (p->next_phys != ref) p = p->next_phys; - + if (ref_obsolete(p) && !ref->next_in_ino) { p->__totlen += ref->__totlen; if (jeb->last_node == ref) { @@ -649,164 +732,6 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref up(&c->erase_free_sem); } -#if CONFIG_JFFS2_FS_DEBUG >= 2 -void jffs2_dump_block_lists(struct jffs2_sb_info *c) -{ - - - printk(KERN_DEBUG "jffs2_dump_block_lists:\n"); - printk(KERN_DEBUG "flash_size: %08x\n", c->flash_size); - printk(KERN_DEBUG "used_size: %08x\n", c->used_size); - printk(KERN_DEBUG "dirty_size: %08x\n", c->dirty_size); - printk(KERN_DEBUG "wasted_size: %08x\n", c->wasted_size); - printk(KERN_DEBUG "unchecked_size: %08x\n", c->unchecked_size); - printk(KERN_DEBUG "free_size: %08x\n", c->free_size); - printk(KERN_DEBUG "erasing_size: %08x\n", c->erasing_size); - printk(KERN_DEBUG "bad_size: %08x\n", c->bad_size); - printk(KERN_DEBUG "sector_size: %08x\n", c->sector_size); - printk(KERN_DEBUG "jffs2_reserved_blocks size: %08x\n",c->sector_size * c->resv_blocks_write); - - if (c->nextblock) { - printk(KERN_DEBUG "nextblock: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", - c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->unchecked_size, c->nextblock->free_size); - } else { - printk(KERN_DEBUG "nextblock: NULL\n"); - } - if (c->gcblock) { - printk(KERN_DEBUG "gcblock: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", - c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size, c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size); - } else { - printk(KERN_DEBUG "gcblock: NULL\n"); - } - if (list_empty(&c->clean_list)) { - printk(KERN_DEBUG "clean_list: empty\n"); - } else { - struct list_head *this; - int numblocks = 0; - uint32_t dirty = 0; - - list_for_each(this, &c->clean_list) { - struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); - numblocks ++; - dirty += jeb->wasted_size; - printk(KERN_DEBUG "clean_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); - } - printk (KERN_DEBUG "Contains %d blocks with total wasted size %u, average wasted size: %u\n", numblocks, dirty, dirty / numblocks); - } - if (list_empty(&c->very_dirty_list)) { - printk(KERN_DEBUG "very_dirty_list: empty\n"); - } else { - struct list_head *this; - int numblocks = 0; - uint32_t dirty = 0; - - list_for_each(this, &c->very_dirty_list) { - struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); - numblocks ++; - dirty += jeb->dirty_size; - printk(KERN_DEBUG "very_dirty_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", - jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); - } - printk (KERN_DEBUG "Contains %d blocks with total dirty size %u, average dirty size: %u\n", - numblocks, dirty, dirty / numblocks); - } - if (list_empty(&c->dirty_list)) { - printk(KERN_DEBUG "dirty_list: empty\n"); - } else { - struct list_head *this; - int numblocks = 0; - uint32_t dirty = 0; - - list_for_each(this, &c->dirty_list) { - struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); - numblocks ++; - dirty += jeb->dirty_size; - printk(KERN_DEBUG "dirty_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", - jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); - } - printk (KERN_DEBUG "Contains %d blocks with total dirty size %u, average dirty size: %u\n", - numblocks, dirty, dirty / numblocks); - } - if (list_empty(&c->erasable_list)) { - printk(KERN_DEBUG "erasable_list: empty\n"); - } else { - struct list_head *this; - - list_for_each(this, &c->erasable_list) { - struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); - printk(KERN_DEBUG "erasable_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", - jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); - } - } - if (list_empty(&c->erasing_list)) { - printk(KERN_DEBUG "erasing_list: empty\n"); - } else { - struct list_head *this; - - list_for_each(this, &c->erasing_list) { - struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); - printk(KERN_DEBUG "erasing_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", - jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); - } - } - if (list_empty(&c->erase_pending_list)) { - printk(KERN_DEBUG "erase_pending_list: empty\n"); - } else { - struct list_head *this; - - list_for_each(this, &c->erase_pending_list) { - struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); - printk(KERN_DEBUG "erase_pending_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", - jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); - } - } - if (list_empty(&c->erasable_pending_wbuf_list)) { - printk(KERN_DEBUG "erasable_pending_wbuf_list: empty\n"); - } else { - struct list_head *this; - - list_for_each(this, &c->erasable_pending_wbuf_list) { - struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); - printk(KERN_DEBUG "erasable_pending_wbuf_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", - jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); - } - } - if (list_empty(&c->free_list)) { - printk(KERN_DEBUG "free_list: empty\n"); - } else { - struct list_head *this; - - list_for_each(this, &c->free_list) { - struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); - printk(KERN_DEBUG "free_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", - jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); - } - } - if (list_empty(&c->bad_list)) { - printk(KERN_DEBUG "bad_list: empty\n"); - } else { - struct list_head *this; - - list_for_each(this, &c->bad_list) { - struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); - printk(KERN_DEBUG "bad_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", - jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); - } - } - if (list_empty(&c->bad_used_list)) { - printk(KERN_DEBUG "bad_used_list: empty\n"); - } else { - struct list_head *this; - - list_for_each(this, &c->bad_used_list) { - struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); - printk(KERN_DEBUG "bad_used_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", - jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size); - } - } -} -#endif /* CONFIG_JFFS2_FS_DEBUG */ - int jffs2_thread_should_wake(struct jffs2_sb_info *c) { int ret = 0; @@ -828,11 +753,11 @@ int jffs2_thread_should_wake(struct jffs2_sb_info *c) */ dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size; - if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger && - (dirty > c->nospc_dirty_size)) + if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger && + (dirty > c->nospc_dirty_size)) ret = 1; - D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n", + D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n", c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, ret?"yes":"no")); return ret; diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index d900c8929b09983cca227d2deeb1658ac0913b0b..59e7a393200c6877c99a7a2dc87303045b1e2644 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: os-linux.h,v 1.58 2005/07/12 02:34:35 tpoynor Exp $ + * $Id: os-linux.h,v 1.64 2005/09/30 13:59:13 dedekind Exp $ * */ @@ -57,6 +57,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) f->fragtree = RB_ROOT; f->metadata = NULL; f->dents = NULL; + f->target = NULL; f->flags = 0; f->usercompr = 0; } @@ -64,17 +65,24 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY) +#define SECTOR_ADDR(x) ( (((unsigned long)(x) / c->sector_size) * c->sector_size) ) #ifndef CONFIG_JFFS2_FS_WRITEBUFFER -#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) ) + + +#ifdef CONFIG_JFFS2_SUMMARY +#define jffs2_can_mark_obsolete(c) (0) +#else #define jffs2_can_mark_obsolete(c) (1) +#endif + #define jffs2_is_writebuffered(c) (0) #define jffs2_cleanmarker_oob(c) (0) #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) -#define jffs2_flash_write(c, ofs, len, retlen, buf) ((c)->mtd->write((c)->mtd, ofs, len, retlen, buf)) +#define jffs2_flash_write(c, ofs, len, retlen, buf) jffs2_flash_direct_write(c, ofs, len, retlen, buf) #define jffs2_flash_read(c, ofs, len, retlen, buf) ((c)->mtd->read((c)->mtd, ofs, len, retlen, buf)) -#define jffs2_flush_wbuf_pad(c) ({ (void)(c), 0; }) -#define jffs2_flush_wbuf_gc(c, i) ({ (void)(c), (void) i, 0; }) +#define jffs2_flush_wbuf_pad(c) ({ do{} while(0); (void)(c), 0; }) +#define jffs2_flush_wbuf_gc(c, i) ({ do{} while(0); (void)(c), (void) i, 0; }) #define jffs2_write_nand_badblock(c,jeb,bad_offset) (1) #define jffs2_nand_flash_setup(c) (0) #define jffs2_nand_flash_cleanup(c) do {} while(0) @@ -84,16 +92,26 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) #define jffs2_wbuf_process NULL #define jffs2_nor_ecc(c) (0) #define jffs2_dataflash(c) (0) +#define jffs2_nor_wbuf_flash(c) (0) #define jffs2_nor_ecc_flash_setup(c) (0) #define jffs2_nor_ecc_flash_cleanup(c) do {} while (0) #define jffs2_dataflash_setup(c) (0) #define jffs2_dataflash_cleanup(c) do {} while (0) +#define jffs2_nor_wbuf_flash_setup(c) (0) +#define jffs2_nor_wbuf_flash_cleanup(c) do {} while (0) #else /* NAND and/or ECC'd NOR support present */ #define jffs2_is_writebuffered(c) (c->wbuf != NULL) -#define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size ) -#define jffs2_can_mark_obsolete(c) ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & MTD_ECC)) || c->mtd->type == MTD_RAM) + +#ifdef CONFIG_JFFS2_SUMMARY +#define jffs2_can_mark_obsolete(c) (0) +#else +#define jffs2_can_mark_obsolete(c) \ + ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & (MTD_ECC|MTD_PROGRAM_REGIONS))) || \ + c->mtd->type == MTD_RAM) +#endif + #define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH) #define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf)) @@ -123,6 +141,10 @@ void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c); int jffs2_dataflash_setup(struct jffs2_sb_info *c); void jffs2_dataflash_cleanup(struct jffs2_sb_info *c); +#define jffs2_nor_wbuf_flash(c) (c->mtd->type == MTD_NORFLASH && (c->mtd->flags & MTD_PROGRAM_REGIONS)) +int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c); +void jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c); + #endif /* WRITEBUFFER */ /* erase.c */ @@ -169,20 +191,21 @@ void jffs2_gc_release_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, int inum, int nlink); -unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, - struct jffs2_inode_info *f, +unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, + struct jffs2_inode_info *f, unsigned long offset, unsigned long *priv); void jffs2_gc_release_page(struct jffs2_sb_info *c, unsigned char *pg, unsigned long *priv); void jffs2_flash_cleanup(struct jffs2_sb_info *c); - + /* writev.c */ -int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs, +int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen); - +int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, + size_t *retlen, const u_char *buf); #endif /* __JFFS2_OS_LINUX_H__ */ diff --git a/fs/jffs2/read.c b/fs/jffs2/read.c index c7f9068907cfa6a6f4b13e2694b788ed389cdd11..f3b86da833baedc2e206d4ba85d25e4a65069fe8 100644 --- a/fs/jffs2/read.c +++ b/fs/jffs2/read.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: read.c,v 1.39 2005/03/01 10:34:03 dedekind Exp $ + * $Id: read.c,v 1.42 2005/11/07 11:14:41 gleixner Exp $ * */ @@ -43,7 +43,7 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, } if (readlen != sizeof(*ri)) { jffs2_free_raw_inode(ri); - printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%zx bytes, got 0x%zx\n", + printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%zx bytes, got 0x%zx\n", ref_offset(fd->raw), sizeof(*ri), readlen); return -EIO; } @@ -61,7 +61,7 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, } /* There was a bug where we wrote hole nodes out with csize/dsize swapped. Deal with it */ - if (ri->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(ri->dsize) && + if (ri->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(ri->dsize) && je32_to_cpu(ri->csize)) { ri->dsize = ri->csize; ri->csize = cpu_to_je32(0); @@ -74,7 +74,7 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, goto out_ri; }); - + if (ri->compr == JFFS2_COMPR_ZERO) { memset(buf, 0, len); goto out_ri; @@ -82,8 +82,8 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, /* Cases: Reading whole node and it's uncompressed - read directly to buffer provided, check CRC. - Reading whole node and it's compressed - read into comprbuf, check CRC and decompress to buffer provided - Reading partial node and it's uncompressed - read into readbuf, check CRC, and copy + Reading whole node and it's compressed - read into comprbuf, check CRC and decompress to buffer provided + Reading partial node and it's uncompressed - read into readbuf, check CRC, and copy Reading partial node and it's compressed - read into readbuf, check checksum, decompress to decomprbuf and copy */ if (ri->compr == JFFS2_COMPR_NONE && len == je32_to_cpu(ri->dsize)) { @@ -129,7 +129,7 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, D2(printk(KERN_DEBUG "Data CRC matches calculated CRC %08x\n", crc)); if (ri->compr != JFFS2_COMPR_NONE) { D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n", - je32_to_cpu(ri->csize), readbuf, je32_to_cpu(ri->dsize), decomprbuf)); + je32_to_cpu(ri->csize), readbuf, je32_to_cpu(ri->dsize), decomprbuf)); ret = jffs2_decompress(c, f, ri->compr | (ri->usercompr << 8), readbuf, decomprbuf, je32_to_cpu(ri->csize), je32_to_cpu(ri->dsize)); if (ret) { printk(KERN_WARNING "Error: jffs2_decompress returned %d\n", ret); @@ -174,7 +174,6 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, if (frag) { D1(printk(KERN_NOTICE "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", f->inocache->ino, frag->ofs, offset)); holesize = min(holesize, frag->ofs - offset); - D2(jffs2_print_frag_list(f)); } D1(printk(KERN_DEBUG "Filling non-frag hole from %d-%d\n", offset, offset+holesize)); memset(buf, 0, holesize); @@ -192,7 +191,7 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, } else { uint32_t readlen; uint32_t fragofs; /* offset within the frag to start reading */ - + fragofs = offset - frag->ofs; readlen = min(frag->size - fragofs, end - offset); D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%08x (%d)\n", diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 5b2a83599d73c6649130c161293505384e60e114..5f0652df5d47dab051839cf88218e2c353c28733 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -7,11 +7,12 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: readinode.c,v 1.125 2005/07/10 13:13:55 dedekind Exp $ + * $Id: readinode.c,v 1.143 2005/11/07 11:14:41 gleixner Exp $ * */ #include +#include #include #include #include @@ -20,502 +21,631 @@ #include #include "nodelist.h" -static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag); - -#if CONFIG_JFFS2_FS_DEBUG >= 2 -static void jffs2_print_fragtree(struct rb_root *list, int permitbug) +/* + * Put a new tmp_dnode_info into the temporaty RB-tree, keeping the list in + * order of increasing version. + */ +static void jffs2_add_tn_to_tree(struct jffs2_tmp_dnode_info *tn, struct rb_root *list) { - struct jffs2_node_frag *this = frag_first(list); - uint32_t lastofs = 0; - int buggy = 0; - - while(this) { - if (this->node) - printk(KERN_DEBUG "frag %04x-%04x: 0x%08x(%d) on flash (*%p). left (%p), right (%p), parent (%p)\n", - this->ofs, this->ofs+this->size, ref_offset(this->node->raw), ref_flags(this->node->raw), - this, frag_left(this), frag_right(this), frag_parent(this)); - else - printk(KERN_DEBUG "frag %04x-%04x: hole (*%p). left (%p} right (%p), parent (%p)\n", this->ofs, - this->ofs+this->size, this, frag_left(this), frag_right(this), frag_parent(this)); - if (this->ofs != lastofs) - buggy = 1; - lastofs = this->ofs+this->size; - this = frag_next(this); + struct rb_node **p = &list->rb_node; + struct rb_node * parent = NULL; + struct jffs2_tmp_dnode_info *this; + + while (*p) { + parent = *p; + this = rb_entry(parent, struct jffs2_tmp_dnode_info, rb); + + /* There may actually be a collision here, but it doesn't + actually matter. As long as the two nodes with the same + version are together, it's all fine. */ + if (tn->version > this->version) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; } - if (buggy && !permitbug) { - printk(KERN_CRIT "Frag tree got a hole in it\n"); - BUG(); + + rb_link_node(&tn->rb, parent, p); + rb_insert_color(&tn->rb, list); +} + +static void jffs2_free_tmp_dnode_info_list(struct rb_root *list) +{ + struct rb_node *this; + struct jffs2_tmp_dnode_info *tn; + + this = list->rb_node; + + /* Now at bottom of tree */ + while (this) { + if (this->rb_left) + this = this->rb_left; + else if (this->rb_right) + this = this->rb_right; + else { + tn = rb_entry(this, struct jffs2_tmp_dnode_info, rb); + jffs2_free_full_dnode(tn->fn); + jffs2_free_tmp_dnode_info(tn); + + this = this->rb_parent; + if (!this) + break; + + if (this->rb_left == &tn->rb) + this->rb_left = NULL; + else if (this->rb_right == &tn->rb) + this->rb_right = NULL; + else BUG(); + } } + list->rb_node = NULL; } -void jffs2_print_frag_list(struct jffs2_inode_info *f) +static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd) { - jffs2_print_fragtree(&f->fragtree, 0); + struct jffs2_full_dirent *next; - if (f->metadata) { - printk(KERN_DEBUG "metadata at 0x%08x\n", ref_offset(f->metadata->raw)); + while (fd) { + next = fd->next; + jffs2_free_full_dirent(fd); + fd = next; } } -#endif -#if CONFIG_JFFS2_FS_DEBUG >= 1 -static int jffs2_sanitycheck_fragtree(struct jffs2_inode_info *f) +/* Returns first valid node after 'ref'. May return 'ref' */ +static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_ref *ref) { - struct jffs2_node_frag *frag; - int bitched = 0; - - for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) { + while (ref && ref->next_in_ino) { + if (!ref_obsolete(ref)) + return ref; + dbg_noderef("node at 0x%08x is obsoleted. Ignoring.\n", ref_offset(ref)); + ref = ref->next_in_ino; + } + return NULL; +} - struct jffs2_full_dnode *fn = frag->node; - if (!fn || !fn->raw) - continue; +/* + * Helper function for jffs2_get_inode_nodes(). + * It is called every time an directory entry node is found. + * + * Returns: 0 on succes; + * 1 if the node should be marked obsolete; + * negative error code on failure. + */ +static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, + struct jffs2_raw_dirent *rd, uint32_t read, struct jffs2_full_dirent **fdp, + uint32_t *latest_mctime, uint32_t *mctime_ver) +{ + struct jffs2_full_dirent *fd; + + /* The direntry nodes are checked during the flash scanning */ + BUG_ON(ref_flags(ref) == REF_UNCHECKED); + /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ + BUG_ON(ref_obsolete(ref)); + + /* Sanity check */ + if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) { + JFFS2_ERROR("illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n", + ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen)); + return 1; + } - if (ref_flags(fn->raw) == REF_PRISTINE) { + fd = jffs2_alloc_full_dirent(rd->nsize + 1); + if (unlikely(!fd)) + return -ENOMEM; - if (fn->frags > 1) { - printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2\n", ref_offset(fn->raw), fn->frags); - bitched = 1; - } - /* A hole node which isn't multi-page should be garbage-collected - and merged anyway, so we just check for the frag size here, - rather than mucking around with actually reading the node - and checking the compression type, which is the real way - to tell a hole node. */ - if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) && frag_prev(frag)->size < PAGE_CACHE_SIZE && frag_prev(frag)->node) { - printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2\n", - ref_offset(fn->raw)); - bitched = 1; - } + fd->raw = ref; + fd->version = je32_to_cpu(rd->version); + fd->ino = je32_to_cpu(rd->ino); + fd->type = rd->type; - if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) && frag_next(frag)->size < PAGE_CACHE_SIZE && frag_next(frag)->node) { - printk(KERN_WARNING "REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2\n", - ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size); - bitched = 1; - } - } + /* Pick out the mctime of the latest dirent */ + if(fd->version > *mctime_ver && je32_to_cpu(rd->mctime)) { + *mctime_ver = fd->version; + *latest_mctime = je32_to_cpu(rd->mctime); } - - if (bitched) { - struct jffs2_node_frag *thisfrag; - - printk(KERN_WARNING "Inode is #%u\n", f->inocache->ino); - thisfrag = frag_first(&f->fragtree); - while (thisfrag) { - if (!thisfrag->node) { - printk("Frag @0x%x-0x%x; node-less hole\n", - thisfrag->ofs, thisfrag->size + thisfrag->ofs); - } else if (!thisfrag->node->raw) { - printk("Frag @0x%x-0x%x; raw-less hole\n", - thisfrag->ofs, thisfrag->size + thisfrag->ofs); - } else { - printk("Frag @0x%x-0x%x; raw at 0x%08x(%d) (0x%x-0x%x)\n", - thisfrag->ofs, thisfrag->size + thisfrag->ofs, - ref_offset(thisfrag->node->raw), ref_flags(thisfrag->node->raw), - thisfrag->node->ofs, thisfrag->node->ofs+thisfrag->node->size); - } - thisfrag = frag_next(thisfrag); - } - } - return bitched; -} -#endif /* D1 */ -static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this) -{ - if (this->node) { - this->node->frags--; - if (!this->node->frags) { - /* The node has no valid frags left. It's totally obsoleted */ - D2(printk(KERN_DEBUG "Marking old node @0x%08x (0x%04x-0x%04x) obsolete\n", - ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size)); - jffs2_mark_node_obsolete(c, this->node->raw); - jffs2_free_full_dnode(this->node); - } else { - D2(printk(KERN_DEBUG "Marking old node @0x%08x (0x%04x-0x%04x) REF_NORMAL. frags is %d\n", - ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size, - this->node->frags)); - mark_ref_normal(this->node->raw); + /* + * Copy as much of the name as possible from the raw + * dirent we've already read from the flash. + */ + if (read > sizeof(*rd)) + memcpy(&fd->name[0], &rd->name[0], + min_t(uint32_t, rd->nsize, (read - sizeof(*rd)) )); + + /* Do we need to copy any more of the name directly from the flash? */ + if (rd->nsize + sizeof(*rd) > read) { + /* FIXME: point() */ + int err; + int already = read - sizeof(*rd); + + err = jffs2_flash_read(c, (ref_offset(ref)) + read, + rd->nsize - already, &read, &fd->name[already]); + if (unlikely(read != rd->nsize - already) && likely(!err)) + return -EIO; + + if (unlikely(err)) { + JFFS2_ERROR("read remainder of name: error %d\n", err); + jffs2_free_full_dirent(fd); + return -EIO; } - } - jffs2_free_node_frag(this); + + fd->nhash = full_name_hash(fd->name, rd->nsize); + fd->next = NULL; + fd->name[rd->nsize] = '\0'; + + /* + * Wheee. We now have a complete jffs2_full_dirent structure, with + * the name in it and everything. Link it into the list + */ + jffs2_add_fd_to_list(c, fd, fdp); + + return 0; } -/* Given an inode, probably with existing list of fragments, add the new node - * to the fragment list. +/* + * Helper function for jffs2_get_inode_nodes(). + * It is called every time an inode node is found. + * + * Returns: 0 on succes; + * 1 if the node should be marked obsolete; + * negative error code on failure. */ -int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) +static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, + struct jffs2_raw_inode *rd, struct rb_root *tnp, int rdlen, + uint32_t *latest_mctime, uint32_t *mctime_ver) { - int ret; - struct jffs2_node_frag *newfrag; - - D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn)); + struct jffs2_tmp_dnode_info *tn; + uint32_t len, csize; + int ret = 1; - if (unlikely(!fn->size)) - return 0; + /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ + BUG_ON(ref_obsolete(ref)); - newfrag = jffs2_alloc_node_frag(); - if (unlikely(!newfrag)) + tn = jffs2_alloc_tmp_dnode_info(); + if (!tn) { + JFFS2_ERROR("failed to allocate tn (%d bytes).\n", sizeof(*tn)); return -ENOMEM; + } - D2(printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n", - fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag)); - - newfrag->ofs = fn->ofs; - newfrag->size = fn->size; - newfrag->node = fn; - newfrag->node->frags = 1; + tn->partial_crc = 0; + csize = je32_to_cpu(rd->csize); - ret = jffs2_add_frag_to_fragtree(c, &f->fragtree, newfrag); - if (ret) - return ret; + /* If we've never checked the CRCs on this node, check them now */ + if (ref_flags(ref) == REF_UNCHECKED) { + uint32_t crc; - /* If we now share a page with other nodes, mark either previous - or next node REF_NORMAL, as appropriate. */ - if (newfrag->ofs & (PAGE_CACHE_SIZE-1)) { - struct jffs2_node_frag *prev = frag_prev(newfrag); + crc = crc32(0, rd, sizeof(*rd) - 8); + if (unlikely(crc != je32_to_cpu(rd->node_crc))) { + JFFS2_NOTICE("header CRC failed on node at %#08x: read %#08x, calculated %#08x\n", + ref_offset(ref), je32_to_cpu(rd->node_crc), crc); + goto free_out; + } - mark_ref_normal(fn->raw); - /* If we don't start at zero there's _always_ a previous */ - if (prev->node) - mark_ref_normal(prev->node->raw); - } + /* Sanity checks */ + if (unlikely(je32_to_cpu(rd->offset) > je32_to_cpu(rd->isize)) || + unlikely(PAD(je32_to_cpu(rd->csize) + sizeof(*rd)) != PAD(je32_to_cpu(rd->totlen)))) { + JFFS2_WARNING("inode node header CRC is corrupted at %#08x\n", ref_offset(ref)); + jffs2_dbg_dump_node(c, ref_offset(ref)); + goto free_out; + } - if ((newfrag->ofs+newfrag->size) & (PAGE_CACHE_SIZE-1)) { - struct jffs2_node_frag *next = frag_next(newfrag); - - if (next) { - mark_ref_normal(fn->raw); - if (next->node) - mark_ref_normal(next->node->raw); + if (jffs2_is_writebuffered(c) && csize != 0) { + /* At this point we are supposed to check the data CRC + * of our unchecked node. But thus far, we do not + * know whether the node is valid or obsolete. To + * figure this out, we need to walk all the nodes of + * the inode and build the inode fragtree. We don't + * want to spend time checking data of nodes which may + * later be found to be obsolete. So we put off the full + * data CRC checking until we have read all the inode + * nodes and have started building the fragtree. + * + * The fragtree is being built starting with nodes + * having the highest version number, so we'll be able + * to detect whether a node is valid (i.e., it is not + * overlapped by a node with higher version) or not. + * And we'll be able to check only those nodes, which + * are not obsolete. + * + * Of course, this optimization only makes sense in case + * of NAND flashes (or other flashes whith + * !jffs2_can_mark_obsolete()), since on NOR flashes + * nodes are marked obsolete physically. + * + * Since NAND flashes (or other flashes with + * jffs2_is_writebuffered(c)) are anyway read by + * fractions of c->wbuf_pagesize, and we have just read + * the node header, it is likely that the starting part + * of the node data is also read when we read the + * header. So we don't mind to check the CRC of the + * starting part of the data of the node now, and check + * the second part later (in jffs2_check_node_data()). + * Of course, we will not need to re-read and re-check + * the NAND page which we have just read. This is why we + * read the whole NAND page at jffs2_get_inode_nodes(), + * while we needed only the node header. + */ + unsigned char *buf; + + /* 'buf' will point to the start of data */ + buf = (unsigned char *)rd + sizeof(*rd); + /* len will be the read data length */ + len = min_t(uint32_t, rdlen - sizeof(*rd), csize); + tn->partial_crc = crc32(0, buf, len); + + dbg_readinode("Calculates CRC (%#08x) for %d bytes, csize %d\n", tn->partial_crc, len, csize); + + /* If we actually calculated the whole data CRC + * and it is wrong, drop the node. */ + if (len >= csize && unlikely(tn->partial_crc != je32_to_cpu(rd->data_crc))) { + JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n", + ref_offset(ref), tn->partial_crc, je32_to_cpu(rd->data_crc)); + goto free_out; + } + + } else if (csize == 0) { + /* + * We checked the header CRC. If the node has no data, adjust + * the space accounting now. For other nodes this will be done + * later either when the node is marked obsolete or when its + * data is checked. + */ + struct jffs2_eraseblock *jeb; + + dbg_readinode("the node has no data.\n"); + jeb = &c->blocks[ref->flash_offset / c->sector_size]; + len = ref_totlen(c, jeb, ref); + + spin_lock(&c->erase_completion_lock); + jeb->used_size += len; + jeb->unchecked_size -= len; + c->used_size += len; + c->unchecked_size -= len; + ref->flash_offset = ref_offset(ref) | REF_NORMAL; + spin_unlock(&c->erase_completion_lock); } } - D2(if (jffs2_sanitycheck_fragtree(f)) { - printk(KERN_WARNING "Just added node %04x-%04x @0x%08x on flash, newfrag *%p\n", - fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag); - return 0; - }) - D2(jffs2_print_frag_list(f)); + + tn->fn = jffs2_alloc_full_dnode(); + if (!tn->fn) { + JFFS2_ERROR("alloc fn failed\n"); + ret = -ENOMEM; + goto free_out; + } + + tn->version = je32_to_cpu(rd->version); + tn->fn->ofs = je32_to_cpu(rd->offset); + tn->data_crc = je32_to_cpu(rd->data_crc); + tn->csize = csize; + tn->fn->raw = ref; + + /* There was a bug where we wrote hole nodes out with + csize/dsize swapped. Deal with it */ + if (rd->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(rd->dsize) && csize) + tn->fn->size = csize; + else // normal case... + tn->fn->size = je32_to_cpu(rd->dsize); + + dbg_readinode("dnode @%08x: ver %u, offset %#04x, dsize %#04x, csize %#04x\n", + ref_offset(ref), je32_to_cpu(rd->version), je32_to_cpu(rd->offset), je32_to_cpu(rd->dsize), csize); + + jffs2_add_tn_to_tree(tn, tnp); + return 0; + +free_out: + jffs2_free_tmp_dnode_info(tn); + return ret; } -/* Doesn't set inode->i_size */ -static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag) +/* + * Helper function for jffs2_get_inode_nodes(). + * It is called every time an unknown node is found. + * + * Returns: 0 on succes; + * 1 if the node should be marked obsolete; + * negative error code on failure. + */ +static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, struct jffs2_unknown_node *un) { - struct jffs2_node_frag *this; - uint32_t lastend; + /* We don't mark unknown nodes as REF_UNCHECKED */ + BUG_ON(ref_flags(ref) == REF_UNCHECKED); - /* Skip all the nodes which are completed before this one starts */ - this = jffs2_lookup_node_frag(list, newfrag->node->ofs); + un->nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(un->nodetype)); - if (this) { - D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n", - this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this)); - lastend = this->ofs + this->size; + if (crc32(0, un, sizeof(struct jffs2_unknown_node) - 4) != je32_to_cpu(un->hdr_crc)) { + /* Hmmm. This should have been caught at scan time. */ + JFFS2_NOTICE("node header CRC failed at %#08x. But it must have been OK earlier.\n", ref_offset(ref)); + jffs2_dbg_dump_node(c, ref_offset(ref)); + return 1; } else { - D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave no frag\n")); - lastend = 0; - } - - /* See if we ran off the end of the list */ - if (lastend <= newfrag->ofs) { - /* We did */ - - /* Check if 'this' node was on the same page as the new node. - If so, both 'this' and the new node get marked REF_NORMAL so - the GC can take a look. - */ - if (lastend && (lastend-1) >> PAGE_CACHE_SHIFT == newfrag->ofs >> PAGE_CACHE_SHIFT) { - if (this->node) - mark_ref_normal(this->node->raw); - mark_ref_normal(newfrag->node->raw); - } + switch(je16_to_cpu(un->nodetype) & JFFS2_COMPAT_MASK) { - if (lastend < newfrag->node->ofs) { - /* ... and we need to put a hole in before the new node */ - struct jffs2_node_frag *holefrag = jffs2_alloc_node_frag(); - if (!holefrag) { - jffs2_free_node_frag(newfrag); - return -ENOMEM; - } - holefrag->ofs = lastend; - holefrag->size = newfrag->node->ofs - lastend; - holefrag->node = NULL; - if (this) { - /* By definition, the 'this' node has no right-hand child, - because there are no frags with offset greater than it. - So that's where we want to put the hole */ - D2(printk(KERN_DEBUG "Adding hole frag (%p) on right of node at (%p)\n", holefrag, this)); - rb_link_node(&holefrag->rb, &this->rb, &this->rb.rb_right); - } else { - D2(printk(KERN_DEBUG "Adding hole frag (%p) at root of tree\n", holefrag)); - rb_link_node(&holefrag->rb, NULL, &list->rb_node); - } - rb_insert_color(&holefrag->rb, list); - this = holefrag; - } - if (this) { - /* By definition, the 'this' node has no right-hand child, - because there are no frags with offset greater than it. - So that's where we want to put the hole */ - D2(printk(KERN_DEBUG "Adding new frag (%p) on right of node at (%p)\n", newfrag, this)); - rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right); - } else { - D2(printk(KERN_DEBUG "Adding new frag (%p) at root of tree\n", newfrag)); - rb_link_node(&newfrag->rb, NULL, &list->rb_node); + case JFFS2_FEATURE_INCOMPAT: + JFFS2_ERROR("unknown INCOMPAT nodetype %#04X at %#08x\n", + je16_to_cpu(un->nodetype), ref_offset(ref)); + /* EEP */ + BUG(); + break; + + case JFFS2_FEATURE_ROCOMPAT: + JFFS2_ERROR("unknown ROCOMPAT nodetype %#04X at %#08x\n", + je16_to_cpu(un->nodetype), ref_offset(ref)); + BUG_ON(!(c->flags & JFFS2_SB_FLAG_RO)); + break; + + case JFFS2_FEATURE_RWCOMPAT_COPY: + JFFS2_NOTICE("unknown RWCOMPAT_COPY nodetype %#04X at %#08x\n", + je16_to_cpu(un->nodetype), ref_offset(ref)); + break; + + case JFFS2_FEATURE_RWCOMPAT_DELETE: + JFFS2_NOTICE("unknown RWCOMPAT_DELETE nodetype %#04X at %#08x\n", + je16_to_cpu(un->nodetype), ref_offset(ref)); + return 1; } - rb_insert_color(&newfrag->rb, list); - return 0; } - D2(printk(KERN_DEBUG "j_a_f_d_t_f: dealing with frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n", - this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this)); + return 0; +} - /* OK. 'this' is pointing at the first frag that newfrag->ofs at least partially obsoletes, - * - i.e. newfrag->ofs < this->ofs+this->size && newfrag->ofs >= this->ofs - */ - if (newfrag->ofs > this->ofs) { - /* This node isn't completely obsoleted. The start of it remains valid */ - - /* Mark the new node and the partially covered node REF_NORMAL -- let - the GC take a look at them */ - mark_ref_normal(newfrag->node->raw); - if (this->node) - mark_ref_normal(this->node->raw); - - if (this->ofs + this->size > newfrag->ofs + newfrag->size) { - /* The new node splits 'this' frag into two */ - struct jffs2_node_frag *newfrag2 = jffs2_alloc_node_frag(); - if (!newfrag2) { - jffs2_free_node_frag(newfrag); - return -ENOMEM; - } - D2(printk(KERN_DEBUG "split old frag 0x%04x-0x%04x -->", this->ofs, this->ofs+this->size); - if (this->node) - printk("phys 0x%08x\n", ref_offset(this->node->raw)); - else - printk("hole\n"); - ) - - /* New second frag pointing to this's node */ - newfrag2->ofs = newfrag->ofs + newfrag->size; - newfrag2->size = (this->ofs+this->size) - newfrag2->ofs; - newfrag2->node = this->node; - if (this->node) - this->node->frags++; - - /* Adjust size of original 'this' */ - this->size = newfrag->ofs - this->ofs; - - /* Now, we know there's no node with offset - greater than this->ofs but smaller than - newfrag2->ofs or newfrag->ofs, for obvious - reasons. So we can do a tree insert from - 'this' to insert newfrag, and a tree insert - from newfrag to insert newfrag2. */ - jffs2_fragtree_insert(newfrag, this); - rb_insert_color(&newfrag->rb, list); - - jffs2_fragtree_insert(newfrag2, newfrag); - rb_insert_color(&newfrag2->rb, list); - - return 0; - } - /* New node just reduces 'this' frag in size, doesn't split it */ - this->size = newfrag->ofs - this->ofs; +/* + * Helper function for jffs2_get_inode_nodes(). + * The function detects whether more data should be read and reads it if yes. + * + * Returns: 0 on succes; + * negative error code on failure. + */ +static int read_more(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, + int right_size, int *rdlen, unsigned char *buf, unsigned char *bufstart) +{ + int right_len, err, len; + size_t retlen; + uint32_t offs; - /* Again, we know it lives down here in the tree */ - jffs2_fragtree_insert(newfrag, this); - rb_insert_color(&newfrag->rb, list); - } else { - /* New frag starts at the same point as 'this' used to. Replace - it in the tree without doing a delete and insertion */ - D2(printk(KERN_DEBUG "Inserting newfrag (*%p),%d-%d in before 'this' (*%p),%d-%d\n", - newfrag, newfrag->ofs, newfrag->ofs+newfrag->size, - this, this->ofs, this->ofs+this->size)); - - rb_replace_node(&this->rb, &newfrag->rb, list); - - if (newfrag->ofs + newfrag->size >= this->ofs+this->size) { - D2(printk(KERN_DEBUG "Obsoleting node frag %p (%x-%x)\n", this, this->ofs, this->ofs+this->size)); - jffs2_obsolete_node_frag(c, this); - } else { - this->ofs += newfrag->size; - this->size -= newfrag->size; + if (jffs2_is_writebuffered(c)) { + right_len = c->wbuf_pagesize - (bufstart - buf); + if (right_size + (int)(bufstart - buf) > c->wbuf_pagesize) + right_len += c->wbuf_pagesize; + } else + right_len = right_size; - jffs2_fragtree_insert(this, newfrag); - rb_insert_color(&this->rb, list); - return 0; - } + if (*rdlen == right_len) + return 0; + + /* We need to read more data */ + offs = ref_offset(ref) + *rdlen; + if (jffs2_is_writebuffered(c)) { + bufstart = buf + c->wbuf_pagesize; + len = c->wbuf_pagesize; + } else { + bufstart = buf + *rdlen; + len = right_size - *rdlen; } - /* OK, now we have newfrag added in the correct place in the tree, but - frag_next(newfrag) may be a fragment which is overlapped by it - */ - while ((this = frag_next(newfrag)) && newfrag->ofs + newfrag->size >= this->ofs + this->size) { - /* 'this' frag is obsoleted completely. */ - D2(printk(KERN_DEBUG "Obsoleting node frag %p (%x-%x) and removing from tree\n", this, this->ofs, this->ofs+this->size)); - rb_erase(&this->rb, list); - jffs2_obsolete_node_frag(c, this); + + dbg_readinode("read more %d bytes\n", len); + + err = jffs2_flash_read(c, offs, len, &retlen, bufstart); + if (err) { + JFFS2_ERROR("can not read %d bytes from 0x%08x, " + "error code: %d.\n", len, offs, err); + return err; } - /* Now we're pointing at the first frag which isn't totally obsoleted by - the new frag */ - if (!this || newfrag->ofs + newfrag->size == this->ofs) { - return 0; + if (retlen < len) { + JFFS2_ERROR("short read at %#08x: %d instead of %d.\n", + offs, retlen, len); + return -EIO; } - /* Still some overlap but we don't need to move it in the tree */ - this->size = (this->ofs + this->size) - (newfrag->ofs + newfrag->size); - this->ofs = newfrag->ofs + newfrag->size; - /* And mark them REF_NORMAL so the GC takes a look at them */ - if (this->node) - mark_ref_normal(this->node->raw); - mark_ref_normal(newfrag->node->raw); + *rdlen = right_len; return 0; } -void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size) +/* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated + with this ino, returning the former in order of version */ +static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, + struct rb_root *tnp, struct jffs2_full_dirent **fdp, + uint32_t *highest_version, uint32_t *latest_mctime, + uint32_t *mctime_ver) { - struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size); + struct jffs2_raw_node_ref *ref, *valid_ref; + struct rb_root ret_tn = RB_ROOT; + struct jffs2_full_dirent *ret_fd = NULL; + unsigned char *buf = NULL; + union jffs2_node_union *node; + size_t retlen; + int len, err; + + *mctime_ver = 0; + + dbg_readinode("ino #%u\n", f->inocache->ino); + + if (jffs2_is_writebuffered(c)) { + /* + * If we have the write buffer, we assume the minimal I/O unit + * is c->wbuf_pagesize. We implement some optimizations which in + * this case and we need a temporary buffer of size = + * 2*c->wbuf_pagesize bytes (see comments in read_dnode()). + * Basically, we want to read not only the node header, but the + * whole wbuf (NAND page in case of NAND) or 2, if the node + * header overlaps the border between the 2 wbufs. + */ + len = 2*c->wbuf_pagesize; + } else { + /* + * When there is no write buffer, the size of the temporary + * buffer is the size of the larges node header. + */ + len = sizeof(union jffs2_node_union); + } - D1(printk(KERN_DEBUG "Truncating fraglist to 0x%08x bytes\n", size)); + /* FIXME: in case of NOR and available ->point() this + * needs to be fixed. */ + buf = kmalloc(len, GFP_KERNEL); + if (!buf) + return -ENOMEM; - /* We know frag->ofs <= size. That's what lookup does for us */ - if (frag && frag->ofs != size) { - if (frag->ofs+frag->size >= size) { - D1(printk(KERN_DEBUG "Truncating frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size)); - frag->size = size - frag->ofs; + spin_lock(&c->erase_completion_lock); + valid_ref = jffs2_first_valid_node(f->inocache->nodes); + if (!valid_ref && f->inocache->ino != 1) + JFFS2_WARNING("Eep. No valid nodes for ino #%u.\n", f->inocache->ino); + while (valid_ref) { + unsigned char *bufstart; + + /* We can hold a pointer to a non-obsolete node without the spinlock, + but _obsolete_ nodes may disappear at any time, if the block + they're in gets erased. So if we mark 'ref' obsolete while we're + not holding the lock, it can go away immediately. For that reason, + we find the next valid node first, before processing 'ref'. + */ + ref = valid_ref; + valid_ref = jffs2_first_valid_node(ref->next_in_ino); + spin_unlock(&c->erase_completion_lock); + + cond_resched(); + + /* + * At this point we don't know the type of the node we're going + * to read, so we do not know the size of its header. In order + * to minimize the amount of flash IO we assume the node has + * size = JFFS2_MIN_NODE_HEADER. + */ + if (jffs2_is_writebuffered(c)) { + /* + * We treat 'buf' as 2 adjacent wbufs. We want to + * adjust bufstart such as it points to the + * beginning of the node within this wbuf. + */ + bufstart = buf + (ref_offset(ref) % c->wbuf_pagesize); + /* We will read either one wbuf or 2 wbufs. */ + len = c->wbuf_pagesize - (bufstart - buf); + if (JFFS2_MIN_NODE_HEADER + (int)(bufstart - buf) > c->wbuf_pagesize) { + /* The header spans the border of the first wbuf */ + len += c->wbuf_pagesize; + } + } else { + bufstart = buf; + len = JFFS2_MIN_NODE_HEADER; } - frag = frag_next(frag); - } - while (frag && frag->ofs >= size) { - struct jffs2_node_frag *next = frag_next(frag); - D1(printk(KERN_DEBUG "Removing frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size)); - frag_erase(frag, list); - jffs2_obsolete_node_frag(c, frag); - frag = next; - } -} + dbg_readinode("read %d bytes at %#08x(%d).\n", len, ref_offset(ref), ref_flags(ref)); -/* Scan the list of all nodes present for this ino, build map of versions, etc. */ + /* FIXME: point() */ + err = jffs2_flash_read(c, ref_offset(ref), len, + &retlen, bufstart); + if (err) { + JFFS2_ERROR("can not read %d bytes from 0x%08x, " "error code: %d.\n", len, ref_offset(ref), err); + goto free_out; + } -static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, - struct jffs2_inode_info *f, - struct jffs2_raw_inode *latest_node); + if (retlen < len) { + JFFS2_ERROR("short read at %#08x: %d instead of %d.\n", ref_offset(ref), retlen, len); + err = -EIO; + goto free_out; + } -int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, - uint32_t ino, struct jffs2_raw_inode *latest_node) -{ - D2(printk(KERN_DEBUG "jffs2_do_read_inode(): getting inocache\n")); + node = (union jffs2_node_union *)bufstart; - retry_inocache: - spin_lock(&c->inocache_lock); - f->inocache = jffs2_get_ino_cache(c, ino); + switch (je16_to_cpu(node->u.nodetype)) { - D2(printk(KERN_DEBUG "jffs2_do_read_inode(): Got inocache at %p\n", f->inocache)); + case JFFS2_NODETYPE_DIRENT: + + if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_dirent)) { + err = read_more(c, ref, sizeof(struct jffs2_raw_dirent), &len, buf, bufstart); + if (unlikely(err)) + goto free_out; + } + + err = read_direntry(c, ref, &node->d, retlen, &ret_fd, latest_mctime, mctime_ver); + if (err == 1) { + jffs2_mark_node_obsolete(c, ref); + break; + } else if (unlikely(err)) + goto free_out; + + if (je32_to_cpu(node->d.version) > *highest_version) + *highest_version = je32_to_cpu(node->d.version); - if (f->inocache) { - /* Check its state. We may need to wait before we can use it */ - switch(f->inocache->state) { - case INO_STATE_UNCHECKED: - case INO_STATE_CHECKEDABSENT: - f->inocache->state = INO_STATE_READING; break; - - case INO_STATE_CHECKING: - case INO_STATE_GC: - /* If it's in either of these states, we need - to wait for whoever's got it to finish and - put it back. */ - D1(printk(KERN_DEBUG "jffs2_get_ino_cache_read waiting for ino #%u in state %d\n", - ino, f->inocache->state)); - sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); - goto retry_inocache; - case INO_STATE_READING: - case INO_STATE_PRESENT: - /* Eep. This should never happen. It can - happen if Linux calls read_inode() again - before clear_inode() has finished though. */ - printk(KERN_WARNING "Eep. Trying to read_inode #%u when it's already in state %d!\n", ino, f->inocache->state); - /* Fail. That's probably better than allowing it to succeed */ - f->inocache = NULL; + case JFFS2_NODETYPE_INODE: + + if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_inode)) { + err = read_more(c, ref, sizeof(struct jffs2_raw_inode), &len, buf, bufstart); + if (unlikely(err)) + goto free_out; + } + + err = read_dnode(c, ref, &node->i, &ret_tn, len, latest_mctime, mctime_ver); + if (err == 1) { + jffs2_mark_node_obsolete(c, ref); + break; + } else if (unlikely(err)) + goto free_out; + + if (je32_to_cpu(node->i.version) > *highest_version) + *highest_version = je32_to_cpu(node->i.version); + break; default: - BUG(); - } - } - spin_unlock(&c->inocache_lock); + if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_unknown_node)) { + err = read_more(c, ref, sizeof(struct jffs2_unknown_node), &len, buf, bufstart); + if (unlikely(err)) + goto free_out; + } + + err = read_unknown(c, ref, &node->u); + if (err == 1) { + jffs2_mark_node_obsolete(c, ref); + break; + } else if (unlikely(err)) + goto free_out; - if (!f->inocache && ino == 1) { - /* Special case - no root inode on medium */ - f->inocache = jffs2_alloc_inode_cache(); - if (!f->inocache) { - printk(KERN_CRIT "jffs2_do_read_inode(): Cannot allocate inocache for root inode\n"); - return -ENOMEM; } - D1(printk(KERN_DEBUG "jffs2_do_read_inode(): Creating inocache for root inode\n")); - memset(f->inocache, 0, sizeof(struct jffs2_inode_cache)); - f->inocache->ino = f->inocache->nlink = 1; - f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; - f->inocache->state = INO_STATE_READING; - jffs2_add_ino_cache(c, f->inocache); - } - if (!f->inocache) { - printk(KERN_WARNING "jffs2_do_read_inode() on nonexistent ino %u\n", ino); - return -ENOENT; + spin_lock(&c->erase_completion_lock); } - return jffs2_do_read_inode_internal(c, f, latest_node); -} - -int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) -{ - struct jffs2_raw_inode n; - struct jffs2_inode_info *f = kmalloc(sizeof(*f), GFP_KERNEL); - int ret; - - if (!f) - return -ENOMEM; + spin_unlock(&c->erase_completion_lock); + *tnp = ret_tn; + *fdp = ret_fd; + kfree(buf); - memset(f, 0, sizeof(*f)); - init_MUTEX_LOCKED(&f->sem); - f->inocache = ic; + dbg_readinode("nodes of inode #%u were read, the highest version is %u, latest_mctime %u, mctime_ver %u.\n", + f->inocache->ino, *highest_version, *latest_mctime, *mctime_ver); + return 0; - ret = jffs2_do_read_inode_internal(c, f, &n); - if (!ret) { - up(&f->sem); - jffs2_do_clear_inode(c, f); - } - kfree (f); - return ret; + free_out: + jffs2_free_tmp_dnode_info_list(&ret_tn); + jffs2_free_full_dirent_list(ret_fd); + kfree(buf); + return err; } -static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, +static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *latest_node) { - struct jffs2_tmp_dnode_info *tn = NULL; + struct jffs2_tmp_dnode_info *tn; struct rb_root tn_list; struct rb_node *rb, *repl_rb; struct jffs2_full_dirent *fd_list; - struct jffs2_full_dnode *fn = NULL; + struct jffs2_full_dnode *fn, *first_fn = NULL; uint32_t crc; uint32_t latest_mctime, mctime_ver; - uint32_t mdata_ver = 0; size_t retlen; int ret; - D1(printk(KERN_DEBUG "jffs2_do_read_inode_internal(): ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink)); + dbg_readinode("ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink); /* Grab all nodes relevant to this ino */ ret = jffs2_get_inode_nodes(c, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver); if (ret) { - printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %u returned %d\n", f->inocache->ino, ret); + JFFS2_ERROR("cannot read nodes for ino %u, returned error is %d\n", f->inocache->ino, ret); if (f->inocache->state == INO_STATE_READING) jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); return ret; @@ -525,42 +655,33 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, rb = rb_first(&tn_list); while (rb) { + cond_resched(); tn = rb_entry(rb, struct jffs2_tmp_dnode_info, rb); fn = tn->fn; - - if (f->metadata) { - if (likely(tn->version >= mdata_ver)) { - D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", ref_offset(f->metadata->raw))); - jffs2_mark_node_obsolete(c, f->metadata->raw); - jffs2_free_full_dnode(f->metadata); - f->metadata = NULL; - - mdata_ver = 0; - } else { - /* This should never happen. */ - printk(KERN_WARNING "Er. New metadata at 0x%08x with ver %d is actually older than previous ver %d at 0x%08x\n", - ref_offset(fn->raw), tn->version, mdata_ver, ref_offset(f->metadata->raw)); - jffs2_mark_node_obsolete(c, fn->raw); - jffs2_free_full_dnode(fn); - /* Fill in latest_node from the metadata, not this one we're about to free... */ - fn = f->metadata; - goto next_tn; - } - } + ret = 1; + dbg_readinode("consider node ver %u, phys offset " + "%#08x(%d), range %u-%u.\n", tn->version, + ref_offset(fn->raw), ref_flags(fn->raw), + fn->ofs, fn->ofs + fn->size); if (fn->size) { - jffs2_add_full_dnode_to_inode(c, f, fn); - } else { - /* Zero-sized node at end of version list. Just a metadata update */ - D1(printk(KERN_DEBUG "metadata @%08x: ver %d\n", ref_offset(fn->raw), tn->version)); + ret = jffs2_add_older_frag_to_fragtree(c, f, tn); + /* TODO: the error code isn't checked, check it */ + jffs2_dbg_fragtree_paranoia_check_nolock(f); + BUG_ON(ret < 0); + if (!first_fn && ret == 0) + first_fn = fn; + } else if (!first_fn) { + first_fn = fn; f->metadata = fn; - mdata_ver = tn->version; - } - next_tn: + ret = 0; /* Prevent freeing the metadata update node */ + } else + jffs2_mark_node_obsolete(c, fn->raw); + BUG_ON(rb->rb_left); if (rb->rb_parent && rb->rb_parent->rb_left == rb) { /* We were then left-hand child of our parent. We need - to move our own right-hand child into our place. */ + * to move our own right-hand child into our place. */ repl_rb = rb->rb_right; if (repl_rb) repl_rb->rb_parent = rb->rb_parent; @@ -570,7 +691,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, rb = rb_next(rb); /* Remove the spent tn from the tree; don't bother rebalancing - but put our right-hand child in our own place. */ + * but put our right-hand child in our own place. */ if (tn->rb.rb_parent) { if (tn->rb.rb_parent->rb_left == &tn->rb) tn->rb.rb_parent->rb_left = repl_rb; @@ -581,19 +702,27 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, tn->rb.rb_right->rb_parent = NULL; jffs2_free_tmp_dnode_info(tn); + if (ret) { + dbg_readinode("delete dnode %u-%u.\n", + fn->ofs, fn->ofs + fn->size); + jffs2_free_full_dnode(fn); + } } - D1(jffs2_sanitycheck_fragtree(f)); + jffs2_dbg_fragtree_paranoia_check_nolock(f); - if (!fn) { + BUG_ON(first_fn && ref_obsolete(first_fn->raw)); + + fn = first_fn; + if (unlikely(!first_fn)) { /* No data nodes for this inode. */ if (f->inocache->ino != 1) { - printk(KERN_WARNING "jffs2_do_read_inode(): No data nodes found for ino #%u\n", f->inocache->ino); + JFFS2_WARNING("no data nodes found for ino #%u\n", f->inocache->ino); if (!fd_list) { if (f->inocache->state == INO_STATE_READING) jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); return -EIO; } - printk(KERN_WARNING "jffs2_do_read_inode(): But it has children so we fake some modes for it\n"); + JFFS2_NOTICE("but it has children so we fake some modes for it\n"); } latest_node->mode = cpu_to_jemode(S_IFDIR|S_IRUGO|S_IWUSR|S_IXUGO); latest_node->version = cpu_to_je32(0); @@ -608,8 +737,8 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(*latest_node), &retlen, (void *)latest_node); if (ret || retlen != sizeof(*latest_node)) { - printk(KERN_NOTICE "MTD read in jffs2_do_read_inode() failed: Returned %d, %zd of %zd bytes read\n", - ret, retlen, sizeof(*latest_node)); + JFFS2_ERROR("failed to read from flash: error %d, %zd of %zd bytes read\n", + ret, retlen, sizeof(*latest_node)); /* FIXME: If this fails, there seems to be a memory leak. Find it. */ up(&f->sem); jffs2_do_clear_inode(c, f); @@ -618,7 +747,8 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, crc = crc32(0, latest_node, sizeof(*latest_node)-8); if (crc != je32_to_cpu(latest_node->node_crc)) { - printk(KERN_NOTICE "CRC failed for read_inode of inode %u at physical location 0x%x\n", f->inocache->ino, ref_offset(fn->raw)); + JFFS2_ERROR("CRC failed for read_inode of inode %u at physical location 0x%x\n", + f->inocache->ino, ref_offset(fn->raw)); up(&f->sem); jffs2_do_clear_inode(c, f); return -EIO; @@ -633,10 +763,10 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, } break; - + case S_IFREG: /* If it was a regular file, truncate it to the latest node's isize */ - jffs2_truncate_fraglist(c, &f->fragtree, je32_to_cpu(latest_node->isize)); + jffs2_truncate_fragtree(c, &f->fragtree, je32_to_cpu(latest_node->isize)); break; case S_IFLNK: @@ -649,37 +779,33 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, if (f->inocache->state != INO_STATE_CHECKING) { /* Symlink's inode data is the target path. Read it and - * keep in RAM to facilitate quick follow symlink operation. - * We use f->dents field to store the target path, which - * is somewhat ugly. */ - f->dents = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL); - if (!f->dents) { - printk(KERN_WARNING "Can't allocate %d bytes of memory " - "for the symlink target path cache\n", - je32_to_cpu(latest_node->csize)); + * keep in RAM to facilitate quick follow symlink + * operation. */ + f->target = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL); + if (!f->target) { + JFFS2_ERROR("can't allocate %d bytes of memory for the symlink target path cache\n", je32_to_cpu(latest_node->csize)); up(&f->sem); jffs2_do_clear_inode(c, f); return -ENOMEM; } - + ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node), - je32_to_cpu(latest_node->csize), &retlen, (char *)f->dents); - + je32_to_cpu(latest_node->csize), &retlen, (char *)f->target); + if (ret || retlen != je32_to_cpu(latest_node->csize)) { if (retlen != je32_to_cpu(latest_node->csize)) ret = -EIO; - kfree(f->dents); - f->dents = NULL; + kfree(f->target); + f->target = NULL; up(&f->sem); jffs2_do_clear_inode(c, f); return -ret; } - ((char *)f->dents)[je32_to_cpu(latest_node->csize)] = '\0'; - D1(printk(KERN_DEBUG "jffs2_do_read_inode(): symlink's target '%s' cached\n", - (char *)f->dents)); + f->target[je32_to_cpu(latest_node->csize)] = '\0'; + dbg_readinode("symlink's target '%s' cached\n", f->target); } - + /* fall through... */ case S_IFBLK: @@ -687,14 +813,14 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, /* Certain inode types should have only one data node, and it's kept as the metadata node */ if (f->metadata) { - printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o had metadata node\n", + JFFS2_ERROR("Argh. Special inode #%u with mode 0%o had metadata node\n", f->inocache->ino, jemode_to_cpu(latest_node->mode)); up(&f->sem); jffs2_do_clear_inode(c, f); return -EIO; } if (!frag_first(&f->fragtree)) { - printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o has no fragments\n", + JFFS2_ERROR("Argh. Special inode #%u with mode 0%o has no fragments\n", f->inocache->ino, jemode_to_cpu(latest_node->mode)); up(&f->sem); jffs2_do_clear_inode(c, f); @@ -702,7 +828,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, } /* ASSERT: f->fraglist != NULL */ if (frag_next(frag_first(&f->fragtree))) { - printk(KERN_WARNING "Argh. Special inode #%u with mode 0x%x had more than one node\n", + JFFS2_ERROR("Argh. Special inode #%u with mode 0x%x had more than one node\n", f->inocache->ino, jemode_to_cpu(latest_node->mode)); /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */ up(&f->sem); @@ -721,6 +847,93 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, return 0; } +/* Scan the list of all nodes present for this ino, build map of versions, etc. */ +int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, + uint32_t ino, struct jffs2_raw_inode *latest_node) +{ + dbg_readinode("read inode #%u\n", ino); + + retry_inocache: + spin_lock(&c->inocache_lock); + f->inocache = jffs2_get_ino_cache(c, ino); + + if (f->inocache) { + /* Check its state. We may need to wait before we can use it */ + switch(f->inocache->state) { + case INO_STATE_UNCHECKED: + case INO_STATE_CHECKEDABSENT: + f->inocache->state = INO_STATE_READING; + break; + + case INO_STATE_CHECKING: + case INO_STATE_GC: + /* If it's in either of these states, we need + to wait for whoever's got it to finish and + put it back. */ + dbg_readinode("waiting for ino #%u in state %d\n", ino, f->inocache->state); + sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); + goto retry_inocache; + + case INO_STATE_READING: + case INO_STATE_PRESENT: + /* Eep. This should never happen. It can + happen if Linux calls read_inode() again + before clear_inode() has finished though. */ + JFFS2_ERROR("Eep. Trying to read_inode #%u when it's already in state %d!\n", ino, f->inocache->state); + /* Fail. That's probably better than allowing it to succeed */ + f->inocache = NULL; + break; + + default: + BUG(); + } + } + spin_unlock(&c->inocache_lock); + + if (!f->inocache && ino == 1) { + /* Special case - no root inode on medium */ + f->inocache = jffs2_alloc_inode_cache(); + if (!f->inocache) { + JFFS2_ERROR("cannot allocate inocache for root inode\n"); + return -ENOMEM; + } + dbg_readinode("creating inocache for root inode\n"); + memset(f->inocache, 0, sizeof(struct jffs2_inode_cache)); + f->inocache->ino = f->inocache->nlink = 1; + f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; + f->inocache->state = INO_STATE_READING; + jffs2_add_ino_cache(c, f->inocache); + } + if (!f->inocache) { + JFFS2_ERROR("requestied to read an nonexistent ino %u\n", ino); + return -ENOENT; + } + + return jffs2_do_read_inode_internal(c, f, latest_node); +} + +int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) +{ + struct jffs2_raw_inode n; + struct jffs2_inode_info *f = kmalloc(sizeof(*f), GFP_KERNEL); + int ret; + + if (!f) + return -ENOMEM; + + memset(f, 0, sizeof(*f)); + init_MUTEX_LOCKED(&f->sem); + f->inocache = ic; + + ret = jffs2_do_read_inode_internal(c, f, &n); + if (!ret) { + up(&f->sem); + jffs2_do_clear_inode(c, f); + } + kfree (f); + return ret; +} + void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) { struct jffs2_full_dirent *fd, *fds; @@ -740,20 +953,16 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); - /* For symlink inodes we us f->dents to store the target path name */ - if (S_ISLNK(OFNI_EDONI_2SFFJ(f)->i_mode)) { - if (f->dents) { - kfree(f->dents); - f->dents = NULL; - } - } else { - fds = f->dents; + if (f->target) { + kfree(f->target); + f->target = NULL; + } - while(fds) { - fd = fds; - fds = fd->next; - jffs2_free_full_dirent(fd); - } + fds = f->dents; + while(fds) { + fd = fds; + fds = fd->next; + jffs2_free_full_dirent(fd); } if (f->inocache && f->inocache->state != INO_STATE_CHECKING) { diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index b63160f83bab8fe693d23025f275157840b0f2d6..0e7456ec99fd05a778738da5ab69ec57cd1629a4 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: scan.c,v 1.119 2005/02/17 17:51:13 dedekind Exp $ + * $Id: scan.c,v 1.125 2005/09/30 13:59:13 dedekind Exp $ * */ #include @@ -18,22 +18,11 @@ #include #include #include "nodelist.h" +#include "summary.h" +#include "debug.h" #define DEFAULT_EMPTY_SCAN_SIZE 1024 -#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \ - c->free_size -= _x; c->dirty_size += _x; \ - jeb->free_size -= _x ; jeb->dirty_size += _x; \ - }while(0) -#define USED_SPACE(x) do { typeof(x) _x = (x); \ - c->free_size -= _x; c->used_size += _x; \ - jeb->free_size -= _x ; jeb->used_size += _x; \ - }while(0) -#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \ - c->free_size -= _x; c->unchecked_size += _x; \ - jeb->free_size -= _x ; jeb->unchecked_size += _x; \ - }while(0) - #define noisy_printk(noise, args...) do { \ if (*(noise)) { \ printk(KERN_NOTICE args); \ @@ -47,23 +36,16 @@ static uint32_t pseudo_random; static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - unsigned char *buf, uint32_t buf_size); + unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s); -/* These helper functions _must_ increase ofs and also do the dirty/used space accounting. +/* These helper functions _must_ increase ofs and also do the dirty/used space accounting. * Returning an error will abort the mount - bad checksums etc. should just mark the space * as dirty. */ -static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - struct jffs2_raw_inode *ri, uint32_t ofs); +static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_inode *ri, uint32_t ofs, struct jffs2_summary *s); static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - struct jffs2_raw_dirent *rd, uint32_t ofs); - -#define BLK_STATE_ALLFF 0 -#define BLK_STATE_CLEAN 1 -#define BLK_STATE_PARTDIRTY 2 -#define BLK_STATE_CLEANMARKER 3 -#define BLK_STATE_ALLDIRTY 4 -#define BLK_STATE_BADBLOCK 5 + struct jffs2_raw_dirent *rd, uint32_t ofs, struct jffs2_summary *s); static inline int min_free(struct jffs2_sb_info *c) { @@ -89,6 +71,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) uint32_t empty_blocks = 0, bad_blocks = 0; unsigned char *flashbuf = NULL; uint32_t buf_size = 0; + struct jffs2_summary *s = NULL; /* summary info collected by the scan process */ #ifndef __ECOS size_t pointlen; @@ -122,21 +105,34 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) return -ENOMEM; } + if (jffs2_sum_active()) { + s = kmalloc(sizeof(struct jffs2_summary), GFP_KERNEL); + if (!s) { + JFFS2_WARNING("Can't allocate memory for summary\n"); + return -ENOMEM; + } + memset(s, 0, sizeof(struct jffs2_summary)); + } + for (i=0; inr_blocks; i++) { struct jffs2_eraseblock *jeb = &c->blocks[i]; - ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), buf_size); + /* reset summary info for next eraseblock scan */ + jffs2_sum_reset_collected(s); + + ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), + buf_size, s); if (ret < 0) goto out; - ACCT_PARANOIA_CHECK(jeb); + jffs2_dbg_acct_paranoia_check_nolock(c, jeb); /* Now decide which list to put it on */ switch(ret) { case BLK_STATE_ALLFF: - /* - * Empty block. Since we can't be sure it + /* + * Empty block. Since we can't be sure it * was entirely erased, we just queue it for erase * again. It will be marked as such when the erase * is complete. Meanwhile we still count it as empty @@ -162,18 +158,18 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) break; case BLK_STATE_CLEAN: - /* Full (or almost full) of clean data. Clean list */ - list_add(&jeb->list, &c->clean_list); + /* Full (or almost full) of clean data. Clean list */ + list_add(&jeb->list, &c->clean_list); break; case BLK_STATE_PARTDIRTY: - /* Some data, but not full. Dirty list. */ - /* We want to remember the block with most free space - and stick it in the 'nextblock' position to start writing to it. */ - if (jeb->free_size > min_free(c) && - (!c->nextblock || c->nextblock->free_size < jeb->free_size)) { - /* Better candidate for the next writes to go to */ - if (c->nextblock) { + /* Some data, but not full. Dirty list. */ + /* We want to remember the block with most free space + and stick it in the 'nextblock' position to start writing to it. */ + if (jeb->free_size > min_free(c) && + (!c->nextblock || c->nextblock->free_size < jeb->free_size)) { + /* Better candidate for the next writes to go to */ + if (c->nextblock) { c->nextblock->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size; c->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size; c->free_size -= c->nextblock->free_size; @@ -184,9 +180,14 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) } else { list_add(&c->nextblock->list, &c->dirty_list); } + /* deleting summary information of the old nextblock */ + jffs2_sum_reset_collected(c->summary); } - c->nextblock = jeb; - } else { + /* update collected summary infromation for the current nextblock */ + jffs2_sum_move_collected(c, s); + D1(printk(KERN_DEBUG "jffs2_scan_medium(): new nextblock = 0x%08x\n", jeb->offset)); + c->nextblock = jeb; + } else { jeb->dirty_size += jeb->free_size + jeb->wasted_size; c->dirty_size += jeb->free_size + jeb->wasted_size; c->free_size -= jeb->free_size; @@ -197,30 +198,33 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) } else { list_add(&jeb->list, &c->dirty_list); } - } + } break; case BLK_STATE_ALLDIRTY: /* Nothing valid - not even a clean marker. Needs erasing. */ - /* For now we just put it on the erasing list. We'll start the erases later */ + /* For now we just put it on the erasing list. We'll start the erases later */ D1(printk(KERN_NOTICE "JFFS2: Erase block at 0x%08x is not formatted. It will be erased\n", jeb->offset)); - list_add(&jeb->list, &c->erase_pending_list); + list_add(&jeb->list, &c->erase_pending_list); c->nr_erasing_blocks++; break; - + case BLK_STATE_BADBLOCK: D1(printk(KERN_NOTICE "JFFS2: Block at 0x%08x is bad\n", jeb->offset)); - list_add(&jeb->list, &c->bad_list); + list_add(&jeb->list, &c->bad_list); c->bad_size += c->sector_size; c->free_size -= c->sector_size; bad_blocks++; break; default: printk(KERN_WARNING "jffs2_scan_medium(): unknown block state\n"); - BUG(); + BUG(); } } - + + if (jffs2_sum_active() && s) + kfree(s); + /* Nextblock dirty is always seen as wasted, because we cannot recycle it now */ if (c->nextblock && (c->nextblock->dirty_size)) { c->nextblock->wasted_size += c->nextblock->dirty_size; @@ -229,12 +233,12 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) c->nextblock->dirty_size = 0; } #ifdef CONFIG_JFFS2_FS_WRITEBUFFER - if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) { - /* If we're going to start writing into a block which already + if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size % c->wbuf_pagesize)) { + /* If we're going to start writing into a block which already contains data, and the end of the data isn't page-aligned, skip a little and align it. */ - uint32_t skip = c->nextblock->free_size & (c->wbuf_pagesize-1); + uint32_t skip = c->nextblock->free_size % c->wbuf_pagesize; D1(printk(KERN_DEBUG "jffs2_scan_medium(): Skipping %d bytes in nextblock to ensure page alignment\n", skip)); @@ -246,7 +250,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) } #endif if (c->nr_erasing_blocks) { - if ( !c->used_size && ((c->nr_free_blocks+empty_blocks+bad_blocks)!= c->nr_blocks || bad_blocks == c->nr_blocks) ) { + if ( !c->used_size && ((c->nr_free_blocks+empty_blocks+bad_blocks)!= c->nr_blocks || bad_blocks == c->nr_blocks) ) { printk(KERN_NOTICE "Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes\n"); printk(KERN_NOTICE "empty_blocks %d, bad_blocks %d, c->nr_blocks %d\n",empty_blocks,bad_blocks,c->nr_blocks); ret = -EIO; @@ -259,13 +263,13 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) if (buf_size) kfree(flashbuf); #ifndef __ECOS - else + else c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size); #endif return ret; } -static int jffs2_fill_scan_buf (struct jffs2_sb_info *c, unsigned char *buf, +int jffs2_fill_scan_buf (struct jffs2_sb_info *c, void *buf, uint32_t ofs, uint32_t len) { int ret; @@ -286,14 +290,36 @@ static int jffs2_fill_scan_buf (struct jffs2_sb_info *c, unsigned char *buf, return 0; } +int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) +{ + if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size + && (!jeb->first_node || !jeb->first_node->next_phys) ) + return BLK_STATE_CLEANMARKER; + + /* move blocks with max 4 byte dirty space to cleanlist */ + else if (!ISDIRTY(c->sector_size - (jeb->used_size + jeb->unchecked_size))) { + c->dirty_size -= jeb->dirty_size; + c->wasted_size += jeb->dirty_size; + jeb->wasted_size += jeb->dirty_size; + jeb->dirty_size = 0; + return BLK_STATE_CLEAN; + } else if (jeb->used_size || jeb->unchecked_size) + return BLK_STATE_PARTDIRTY; + else + return BLK_STATE_ALLDIRTY; +} + static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - unsigned char *buf, uint32_t buf_size) { + unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) { struct jffs2_unknown_node *node; struct jffs2_unknown_node crcnode; + struct jffs2_sum_marker *sm; uint32_t ofs, prevofs; uint32_t hdr_crc, buf_ofs, buf_len; int err; int noise = 0; + + #ifdef CONFIG_JFFS2_FS_WRITEBUFFER int cleanmarkerfound = 0; #endif @@ -319,17 +345,53 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo } } #endif + + if (jffs2_sum_active()) { + sm = kmalloc(sizeof(struct jffs2_sum_marker), GFP_KERNEL); + if (!sm) { + return -ENOMEM; + } + + err = jffs2_fill_scan_buf(c, (unsigned char *) sm, jeb->offset + c->sector_size - + sizeof(struct jffs2_sum_marker), sizeof(struct jffs2_sum_marker)); + if (err) { + kfree(sm); + return err; + } + + if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC ) { + err = jffs2_sum_scan_sumnode(c, jeb, je32_to_cpu(sm->offset), &pseudo_random); + if (err) { + kfree(sm); + return err; + } + } + + kfree(sm); + + ofs = jeb->offset; + prevofs = jeb->offset - 1; + } + buf_ofs = jeb->offset; if (!buf_size) { buf_len = c->sector_size; + + if (jffs2_sum_active()) { + /* must reread because of summary test */ + err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len); + if (err) + return err; + } + } else { buf_len = EMPTY_SCAN_SIZE(c->sector_size); err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len); if (err) return err; } - + /* We temporarily use 'ofs' as a pointer into the buffer/jeb */ ofs = 0; @@ -367,10 +429,12 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo noise = 10; -scan_more: + dbg_summary("no summary found in jeb 0x%08x. Apply original scan.\n",jeb->offset); + +scan_more: while(ofs < jeb->offset + c->sector_size) { - D1(ACCT_PARANOIA_CHECK(jeb)); + jffs2_dbg_acct_paranoia_check_nolock(c, jeb); cond_resched(); @@ -432,7 +496,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo /* If we're only checking the beginning of a block with a cleanmarker, bail now */ - if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && + if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_phys) { D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size))); return BLK_STATE_CLEANMARKER; @@ -441,7 +505,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo /* See how much more there is to read in this eraseblock... */ buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); if (!buf_len) { - /* No more to read. Break out of main loop without marking + /* No more to read. Break out of main loop without marking this range of empty space as dirty (because it's not) */ D1(printk(KERN_DEBUG "Empty flash at %08x runs to end of block. Treating as free_space\n", empty_start)); @@ -476,8 +540,8 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo } if (je16_to_cpu(node->magic) != JFFS2_MAGIC_BITMASK) { /* OK. We're out of possibilities. Whinge and move on */ - noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n", - JFFS2_MAGIC_BITMASK, ofs, + noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n", + JFFS2_MAGIC_BITMASK, ofs, je16_to_cpu(node->magic)); DIRTY_SPACE(4); ofs += 4; @@ -492,7 +556,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo if (hdr_crc != je32_to_cpu(node->hdr_crc)) { noisy_printk(&noise, "jffs2_scan_eraseblock(): Node at 0x%08x {0x%04x, 0x%04x, 0x%08x) has invalid CRC 0x%08x (calculated 0x%08x)\n", ofs, je16_to_cpu(node->magic), - je16_to_cpu(node->nodetype), + je16_to_cpu(node->nodetype), je32_to_cpu(node->totlen), je32_to_cpu(node->hdr_crc), hdr_crc); @@ -501,7 +565,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo continue; } - if (ofs + je32_to_cpu(node->totlen) > + if (ofs + je32_to_cpu(node->totlen) > jeb->offset + c->sector_size) { /* Eep. Node goes over the end of the erase block. */ printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n", @@ -532,11 +596,11 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo buf_ofs = ofs; node = (void *)buf; } - err = jffs2_scan_inode_node(c, jeb, (void *)node, ofs); + err = jffs2_scan_inode_node(c, jeb, (void *)node, ofs, s); if (err) return err; ofs += PAD(je32_to_cpu(node->totlen)); break; - + case JFFS2_NODETYPE_DIRENT: if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) { buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); @@ -548,7 +612,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo buf_ofs = ofs; node = (void *)buf; } - err = jffs2_scan_dirent_node(c, jeb, (void *)node, ofs); + err = jffs2_scan_dirent_node(c, jeb, (void *)node, ofs, s); if (err) return err; ofs += PAD(je32_to_cpu(node->totlen)); break; @@ -556,7 +620,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo case JFFS2_NODETYPE_CLEANMARKER: D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs)); if (je32_to_cpu(node->totlen) != c->cleanmarker_size) { - printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%x\n", + printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%x\n", ofs, je32_to_cpu(node->totlen), c->cleanmarker_size); DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node))); ofs += PAD(sizeof(struct jffs2_unknown_node)); @@ -575,13 +639,15 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo marker_ref->flash_offset = ofs | REF_NORMAL; marker_ref->__totlen = c->cleanmarker_size; jeb->first_node = jeb->last_node = marker_ref; - + USED_SPACE(PAD(c->cleanmarker_size)); ofs += PAD(c->cleanmarker_size); } break; case JFFS2_NODETYPE_PADDING: + if (jffs2_sum_active()) + jffs2_sum_add_padding_mem(s, je32_to_cpu(node->totlen)); DIRTY_SPACE(PAD(je32_to_cpu(node->totlen))); ofs += PAD(je32_to_cpu(node->totlen)); break; @@ -616,8 +682,15 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo } } + if (jffs2_sum_active()) { + if (PAD(s->sum_size + JFFS2_SUMMARY_FRAME_SIZE) > jeb->free_size) { + dbg_summary("There is not enough space for " + "summary information, disabling for this jeb!\n"); + jffs2_sum_disable_collecting(s); + } + } - D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x\n", jeb->offset, + D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x\n", jeb->offset, jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size)); /* mark_node_obsolete can add to wasted !! */ @@ -628,24 +701,10 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo jeb->wasted_size = 0; } - if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size - && (!jeb->first_node || !jeb->first_node->next_phys) ) - return BLK_STATE_CLEANMARKER; - - /* move blocks with max 4 byte dirty space to cleanlist */ - else if (!ISDIRTY(c->sector_size - (jeb->used_size + jeb->unchecked_size))) { - c->dirty_size -= jeb->dirty_size; - c->wasted_size += jeb->dirty_size; - jeb->wasted_size += jeb->dirty_size; - jeb->dirty_size = 0; - return BLK_STATE_CLEAN; - } else if (jeb->used_size || jeb->unchecked_size) - return BLK_STATE_PARTDIRTY; - else - return BLK_STATE_ALLDIRTY; + return jffs2_scan_classify_jeb(c, jeb); } -static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino) +struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino) { struct jffs2_inode_cache *ic; @@ -671,8 +730,8 @@ static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info return ic; } -static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - struct jffs2_raw_inode *ri, uint32_t ofs) +static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_inode *ri, uint32_t ofs, struct jffs2_summary *s) { struct jffs2_raw_node_ref *raw; struct jffs2_inode_cache *ic; @@ -681,11 +740,11 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", ofs)); /* We do very little here now. Just check the ino# to which we should attribute - this node; we can do all the CRC checking etc. later. There's a tradeoff here -- + this node; we can do all the CRC checking etc. later. There's a tradeoff here -- we used to scan the flash once only, reading everything we want from it into memory, then building all our in-core data structures and freeing the extra information. Now we allow the first part of the mount to complete a lot quicker, - but we have to go _back_ to the flash in order to finish the CRC checking, etc. + but we have to go _back_ to the flash in order to finish the CRC checking, etc. Which means that the _full_ amount of time to get to proper write mode with GC operational may actually be _longer_ than before. Sucks to be me. */ @@ -731,7 +790,7 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc jeb->last_node->next_phys = raw; jeb->last_node = raw; - D1(printk(KERN_DEBUG "Node is ino #%u, version %d. Range 0x%x-0x%x\n", + D1(printk(KERN_DEBUG "Node is ino #%u, version %d. Range 0x%x-0x%x\n", je32_to_cpu(ri->ino), je32_to_cpu(ri->version), je32_to_cpu(ri->offset), je32_to_cpu(ri->offset)+je32_to_cpu(ri->dsize))); @@ -739,11 +798,16 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc pseudo_random += je32_to_cpu(ri->version); UNCHECKED_SPACE(PAD(je32_to_cpu(ri->totlen))); + + if (jffs2_sum_active()) { + jffs2_sum_add_inode_mem(s, ri, ofs - jeb->offset); + } + return 0; } -static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - struct jffs2_raw_dirent *rd, uint32_t ofs) +static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_dirent *rd, uint32_t ofs, struct jffs2_summary *s) { struct jffs2_raw_node_ref *raw; struct jffs2_full_dirent *fd; @@ -776,7 +840,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo crc = crc32(0, fd->name, rd->nsize); if (crc != je32_to_cpu(rd->name_crc)) { printk(KERN_NOTICE "jffs2_scan_dirent_node(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", - ofs, je32_to_cpu(rd->name_crc), crc); + ofs, je32_to_cpu(rd->name_crc), crc); D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, je32_to_cpu(rd->ino))); jffs2_free_full_dirent(fd); /* FIXME: Why do we believe totlen? */ @@ -796,7 +860,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo jffs2_free_raw_node_ref(raw); return -ENOMEM; } - + raw->__totlen = PAD(je32_to_cpu(rd->totlen)); raw->flash_offset = ofs | REF_PRISTINE; raw->next_phys = NULL; @@ -817,6 +881,10 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo USED_SPACE(PAD(je32_to_cpu(rd->totlen))); jffs2_add_fd_to_list(c, fd, &ic->scan_dents); + if (jffs2_sum_active()) { + jffs2_sum_add_dirent_mem(s, rd, ofs - jeb->offset); + } + return 0; } @@ -852,76 +920,34 @@ void jffs2_rotate_lists(struct jffs2_sb_info *c) x = count_list(&c->clean_list); if (x) { rotateby = pseudo_random % x; - D1(printk(KERN_DEBUG "Rotating clean_list by %d\n", rotateby)); - rotate_list((&c->clean_list), rotateby); - - D1(printk(KERN_DEBUG "Erase block at front of clean_list is at %08x\n", - list_entry(c->clean_list.next, struct jffs2_eraseblock, list)->offset)); - } else { - D1(printk(KERN_DEBUG "Not rotating empty clean_list\n")); } x = count_list(&c->very_dirty_list); if (x) { rotateby = pseudo_random % x; - D1(printk(KERN_DEBUG "Rotating very_dirty_list by %d\n", rotateby)); - rotate_list((&c->very_dirty_list), rotateby); - - D1(printk(KERN_DEBUG "Erase block at front of very_dirty_list is at %08x\n", - list_entry(c->very_dirty_list.next, struct jffs2_eraseblock, list)->offset)); - } else { - D1(printk(KERN_DEBUG "Not rotating empty very_dirty_list\n")); } x = count_list(&c->dirty_list); if (x) { rotateby = pseudo_random % x; - D1(printk(KERN_DEBUG "Rotating dirty_list by %d\n", rotateby)); - rotate_list((&c->dirty_list), rotateby); - - D1(printk(KERN_DEBUG "Erase block at front of dirty_list is at %08x\n", - list_entry(c->dirty_list.next, struct jffs2_eraseblock, list)->offset)); - } else { - D1(printk(KERN_DEBUG "Not rotating empty dirty_list\n")); } x = count_list(&c->erasable_list); if (x) { rotateby = pseudo_random % x; - D1(printk(KERN_DEBUG "Rotating erasable_list by %d\n", rotateby)); - rotate_list((&c->erasable_list), rotateby); - - D1(printk(KERN_DEBUG "Erase block at front of erasable_list is at %08x\n", - list_entry(c->erasable_list.next, struct jffs2_eraseblock, list)->offset)); - } else { - D1(printk(KERN_DEBUG "Not rotating empty erasable_list\n")); } if (c->nr_erasing_blocks) { rotateby = pseudo_random % c->nr_erasing_blocks; - D1(printk(KERN_DEBUG "Rotating erase_pending_list by %d\n", rotateby)); - rotate_list((&c->erase_pending_list), rotateby); - - D1(printk(KERN_DEBUG "Erase block at front of erase_pending_list is at %08x\n", - list_entry(c->erase_pending_list.next, struct jffs2_eraseblock, list)->offset)); - } else { - D1(printk(KERN_DEBUG "Not rotating empty erase_pending_list\n")); } if (c->nr_free_blocks) { rotateby = pseudo_random % c->nr_free_blocks; - D1(printk(KERN_DEBUG "Rotating free_list by %d\n", rotateby)); - rotate_list((&c->free_list), rotateby); - - D1(printk(KERN_DEBUG "Erase block at front of free_list is at %08x\n", - list_entry(c->free_list.next, struct jffs2_eraseblock, list)->offset)); - } else { - D1(printk(KERN_DEBUG "Not rotating empty free_list\n")); } } diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c new file mode 100644 index 0000000000000000000000000000000000000000..fb9cec61fcf2ebbe050d58669551ca311b6c7e70 --- /dev/null +++ b/fs/jffs2/summary.c @@ -0,0 +1,730 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2004 Ferenc Havasi , + * Zoltan Sogor , + * Patrik Kluba , + * University of Szeged, Hungary + * + * For licensing information, see the file 'LICENCE' in this directory. + * + * $Id: summary.c,v 1.4 2005/09/26 11:37:21 havasi Exp $ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "nodelist.h" +#include "debug.h" + +int jffs2_sum_init(struct jffs2_sb_info *c) +{ + c->summary = kmalloc(sizeof(struct jffs2_summary), GFP_KERNEL); + + if (!c->summary) { + JFFS2_WARNING("Can't allocate memory for summary information!\n"); + return -ENOMEM; + } + + memset(c->summary, 0, sizeof(struct jffs2_summary)); + + c->summary->sum_buf = vmalloc(c->sector_size); + + if (!c->summary->sum_buf) { + JFFS2_WARNING("Can't allocate buffer for writing out summary information!\n"); + kfree(c->summary); + return -ENOMEM; + } + + dbg_summary("returned succesfully\n"); + + return 0; +} + +void jffs2_sum_exit(struct jffs2_sb_info *c) +{ + dbg_summary("called\n"); + + jffs2_sum_disable_collecting(c->summary); + + vfree(c->summary->sum_buf); + c->summary->sum_buf = NULL; + + kfree(c->summary); + c->summary = NULL; +} + +static int jffs2_sum_add_mem(struct jffs2_summary *s, union jffs2_sum_mem *item) +{ + if (!s->sum_list_head) + s->sum_list_head = (union jffs2_sum_mem *) item; + if (s->sum_list_tail) + s->sum_list_tail->u.next = (union jffs2_sum_mem *) item; + s->sum_list_tail = (union jffs2_sum_mem *) item; + + switch (je16_to_cpu(item->u.nodetype)) { + case JFFS2_NODETYPE_INODE: + s->sum_size += JFFS2_SUMMARY_INODE_SIZE; + s->sum_num++; + dbg_summary("inode (%u) added to summary\n", + je32_to_cpu(item->i.inode)); + break; + case JFFS2_NODETYPE_DIRENT: + s->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize); + s->sum_num++; + dbg_summary("dirent (%u) added to summary\n", + je32_to_cpu(item->d.ino)); + break; + default: + JFFS2_WARNING("UNKNOWN node type %u\n", + je16_to_cpu(item->u.nodetype)); + return 1; + } + return 0; +} + + +/* The following 3 functions are called from scan.c to collect summary info for not closed jeb */ + +int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size) +{ + dbg_summary("called with %u\n", size); + s->sum_padded += size; + return 0; +} + +int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri, + uint32_t ofs) +{ + struct jffs2_sum_inode_mem *temp = kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL); + + if (!temp) + return -ENOMEM; + + temp->nodetype = ri->nodetype; + temp->inode = ri->ino; + temp->version = ri->version; + temp->offset = cpu_to_je32(ofs); /* relative offset from the begining of the jeb */ + temp->totlen = ri->totlen; + temp->next = NULL; + + return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp); +} + +int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd, + uint32_t ofs) +{ + struct jffs2_sum_dirent_mem *temp = + kmalloc(sizeof(struct jffs2_sum_dirent_mem) + rd->nsize, GFP_KERNEL); + + if (!temp) + return -ENOMEM; + + temp->nodetype = rd->nodetype; + temp->totlen = rd->totlen; + temp->offset = cpu_to_je32(ofs); /* relative from the begining of the jeb */ + temp->pino = rd->pino; + temp->version = rd->version; + temp->ino = rd->ino; + temp->nsize = rd->nsize; + temp->type = rd->type; + temp->next = NULL; + + memcpy(temp->name, rd->name, rd->nsize); + + return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp); +} + +/* Cleanup every collected summary information */ + +static void jffs2_sum_clean_collected(struct jffs2_summary *s) +{ + union jffs2_sum_mem *temp; + + if (!s->sum_list_head) { + dbg_summary("already empty\n"); + } + while (s->sum_list_head) { + temp = s->sum_list_head; + s->sum_list_head = s->sum_list_head->u.next; + kfree(temp); + } + s->sum_list_tail = NULL; + s->sum_padded = 0; + s->sum_num = 0; +} + +void jffs2_sum_reset_collected(struct jffs2_summary *s) +{ + dbg_summary("called\n"); + jffs2_sum_clean_collected(s); + s->sum_size = 0; +} + +void jffs2_sum_disable_collecting(struct jffs2_summary *s) +{ + dbg_summary("called\n"); + jffs2_sum_clean_collected(s); + s->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; +} + +int jffs2_sum_is_disabled(struct jffs2_summary *s) +{ + return (s->sum_size == JFFS2_SUMMARY_NOSUM_SIZE); +} + +/* Move the collected summary information into sb (called from scan.c) */ + +void jffs2_sum_move_collected(struct jffs2_sb_info *c, struct jffs2_summary *s) +{ + dbg_summary("oldsize=0x%x oldnum=%u => newsize=0x%x newnum=%u\n", + c->summary->sum_size, c->summary->sum_num, + s->sum_size, s->sum_num); + + c->summary->sum_size = s->sum_size; + c->summary->sum_num = s->sum_num; + c->summary->sum_padded = s->sum_padded; + c->summary->sum_list_head = s->sum_list_head; + c->summary->sum_list_tail = s->sum_list_tail; + + s->sum_list_head = s->sum_list_tail = NULL; +} + +/* Called from wbuf.c to collect writed node info */ + +int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs, + unsigned long count, uint32_t ofs) +{ + union jffs2_node_union *node; + struct jffs2_eraseblock *jeb; + + node = invecs[0].iov_base; + jeb = &c->blocks[ofs / c->sector_size]; + ofs -= jeb->offset; + + switch (je16_to_cpu(node->u.nodetype)) { + case JFFS2_NODETYPE_INODE: { + struct jffs2_sum_inode_mem *temp = + kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL); + + if (!temp) + goto no_mem; + + temp->nodetype = node->i.nodetype; + temp->inode = node->i.ino; + temp->version = node->i.version; + temp->offset = cpu_to_je32(ofs); + temp->totlen = node->i.totlen; + temp->next = NULL; + + return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp); + } + + case JFFS2_NODETYPE_DIRENT: { + struct jffs2_sum_dirent_mem *temp = + kmalloc(sizeof(struct jffs2_sum_dirent_mem) + node->d.nsize, GFP_KERNEL); + + if (!temp) + goto no_mem; + + temp->nodetype = node->d.nodetype; + temp->totlen = node->d.totlen; + temp->offset = cpu_to_je32(ofs); + temp->pino = node->d.pino; + temp->version = node->d.version; + temp->ino = node->d.ino; + temp->nsize = node->d.nsize; + temp->type = node->d.type; + temp->next = NULL; + + switch (count) { + case 1: + memcpy(temp->name,node->d.name,node->d.nsize); + break; + + case 2: + memcpy(temp->name,invecs[1].iov_base,node->d.nsize); + break; + + default: + BUG(); /* impossible count value */ + break; + } + + return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp); + } + + case JFFS2_NODETYPE_PADDING: + dbg_summary("node PADDING\n"); + c->summary->sum_padded += je32_to_cpu(node->u.totlen); + break; + + case JFFS2_NODETYPE_CLEANMARKER: + dbg_summary("node CLEANMARKER\n"); + break; + + case JFFS2_NODETYPE_SUMMARY: + dbg_summary("node SUMMARY\n"); + break; + + default: + /* If you implement a new node type you should also implement + summary support for it or disable summary. + */ + BUG(); + break; + } + + return 0; + +no_mem: + JFFS2_WARNING("MEMORY ALLOCATION ERROR!"); + return -ENOMEM; +} + + +/* Process the stored summary information - helper function for jffs2_sum_scan_sumnode() */ + +static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_summary *summary, uint32_t *pseudo_random) +{ + struct jffs2_raw_node_ref *raw; + struct jffs2_inode_cache *ic; + struct jffs2_full_dirent *fd; + void *sp; + int i, ino; + + sp = summary->sum; + + for (i=0; isum_num); i++) { + dbg_summary("processing summary index %d\n", i); + + switch (je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) { + case JFFS2_NODETYPE_INODE: { + struct jffs2_sum_inode_flash *spi; + spi = sp; + + ino = je32_to_cpu(spi->inode); + + dbg_summary("Inode at 0x%08x\n", + jeb->offset + je32_to_cpu(spi->offset)); + + raw = jffs2_alloc_raw_node_ref(); + if (!raw) { + JFFS2_NOTICE("allocation of node reference failed\n"); + kfree(summary); + return -ENOMEM; + } + + ic = jffs2_scan_make_ino_cache(c, ino); + if (!ic) { + JFFS2_NOTICE("scan_make_ino_cache failed\n"); + jffs2_free_raw_node_ref(raw); + kfree(summary); + return -ENOMEM; + } + + raw->flash_offset = (jeb->offset + je32_to_cpu(spi->offset)) | REF_UNCHECKED; + raw->__totlen = PAD(je32_to_cpu(spi->totlen)); + raw->next_phys = NULL; + raw->next_in_ino = ic->nodes; + + ic->nodes = raw; + if (!jeb->first_node) + jeb->first_node = raw; + if (jeb->last_node) + jeb->last_node->next_phys = raw; + jeb->last_node = raw; + *pseudo_random += je32_to_cpu(spi->version); + + UNCHECKED_SPACE(PAD(je32_to_cpu(spi->totlen))); + + sp += JFFS2_SUMMARY_INODE_SIZE; + + break; + } + + case JFFS2_NODETYPE_DIRENT: { + struct jffs2_sum_dirent_flash *spd; + spd = sp; + + dbg_summary("Dirent at 0x%08x\n", + jeb->offset + je32_to_cpu(spd->offset)); + + fd = jffs2_alloc_full_dirent(spd->nsize+1); + if (!fd) { + kfree(summary); + return -ENOMEM; + } + + memcpy(&fd->name, spd->name, spd->nsize); + fd->name[spd->nsize] = 0; + + raw = jffs2_alloc_raw_node_ref(); + if (!raw) { + jffs2_free_full_dirent(fd); + JFFS2_NOTICE("allocation of node reference failed\n"); + kfree(summary); + return -ENOMEM; + } + + ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino)); + if (!ic) { + jffs2_free_full_dirent(fd); + jffs2_free_raw_node_ref(raw); + kfree(summary); + return -ENOMEM; + } + + raw->__totlen = PAD(je32_to_cpu(spd->totlen)); + raw->flash_offset = (jeb->offset + je32_to_cpu(spd->offset)) | REF_PRISTINE; + raw->next_phys = NULL; + raw->next_in_ino = ic->nodes; + ic->nodes = raw; + if (!jeb->first_node) + jeb->first_node = raw; + if (jeb->last_node) + jeb->last_node->next_phys = raw; + jeb->last_node = raw; + + fd->raw = raw; + fd->next = NULL; + fd->version = je32_to_cpu(spd->version); + fd->ino = je32_to_cpu(spd->ino); + fd->nhash = full_name_hash(fd->name, spd->nsize); + fd->type = spd->type; + USED_SPACE(PAD(je32_to_cpu(spd->totlen))); + jffs2_add_fd_to_list(c, fd, &ic->scan_dents); + + *pseudo_random += je32_to_cpu(spd->version); + + sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize); + + break; + } + + default : { + JFFS2_WARNING("Unsupported node type found in summary! Exiting..."); + kfree(summary); + return -EIO; + } + } + } + + kfree(summary); + return 0; +} + +/* Process the summary node - called from jffs2_scan_eraseblock() */ + +int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + uint32_t ofs, uint32_t *pseudo_random) +{ + struct jffs2_unknown_node crcnode; + struct jffs2_raw_node_ref *cache_ref; + struct jffs2_raw_summary *summary; + int ret, sumsize; + uint32_t crc; + + sumsize = c->sector_size - ofs; + ofs += jeb->offset; + + dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n", + jeb->offset, ofs, sumsize); + + summary = kmalloc(sumsize, GFP_KERNEL); + + if (!summary) { + return -ENOMEM; + } + + ret = jffs2_fill_scan_buf(c, (unsigned char *)summary, ofs, sumsize); + + if (ret) { + kfree(summary); + return ret; + } + + /* OK, now check for node validity and CRC */ + crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + crcnode.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY); + crcnode.totlen = summary->totlen; + crc = crc32(0, &crcnode, sizeof(crcnode)-4); + + if (je32_to_cpu(summary->hdr_crc) != crc) { + dbg_summary("Summary node header is corrupt (bad CRC or " + "no summary at all)\n"); + goto crc_err; + } + + if (je32_to_cpu(summary->totlen) != sumsize) { + dbg_summary("Summary node is corrupt (wrong erasesize?)\n"); + goto crc_err; + } + + crc = crc32(0, summary, sizeof(struct jffs2_raw_summary)-8); + + if (je32_to_cpu(summary->node_crc) != crc) { + dbg_summary("Summary node is corrupt (bad CRC)\n"); + goto crc_err; + } + + crc = crc32(0, summary->sum, sumsize - sizeof(struct jffs2_raw_summary)); + + if (je32_to_cpu(summary->sum_crc) != crc) { + dbg_summary("Summary node data is corrupt (bad CRC)\n"); + goto crc_err; + } + + if ( je32_to_cpu(summary->cln_mkr) ) { + + dbg_summary("Summary : CLEANMARKER node \n"); + + if (je32_to_cpu(summary->cln_mkr) != c->cleanmarker_size) { + dbg_summary("CLEANMARKER node has totlen 0x%x != normal 0x%x\n", + je32_to_cpu(summary->cln_mkr), c->cleanmarker_size); + UNCHECKED_SPACE(PAD(je32_to_cpu(summary->cln_mkr))); + } else if (jeb->first_node) { + dbg_summary("CLEANMARKER node not first node in block " + "(0x%08x)\n", jeb->offset); + UNCHECKED_SPACE(PAD(je32_to_cpu(summary->cln_mkr))); + } else { + struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref(); + + if (!marker_ref) { + JFFS2_NOTICE("Failed to allocate node ref for clean marker\n"); + kfree(summary); + return -ENOMEM; + } + + marker_ref->next_in_ino = NULL; + marker_ref->next_phys = NULL; + marker_ref->flash_offset = jeb->offset | REF_NORMAL; + marker_ref->__totlen = je32_to_cpu(summary->cln_mkr); + jeb->first_node = jeb->last_node = marker_ref; + + USED_SPACE( PAD(je32_to_cpu(summary->cln_mkr)) ); + } + } + + if (je32_to_cpu(summary->padded)) { + DIRTY_SPACE(je32_to_cpu(summary->padded)); + } + + ret = jffs2_sum_process_sum_data(c, jeb, summary, pseudo_random); + if (ret) + return ret; + + /* for PARANOIA_CHECK */ + cache_ref = jffs2_alloc_raw_node_ref(); + + if (!cache_ref) { + JFFS2_NOTICE("Failed to allocate node ref for cache\n"); + return -ENOMEM; + } + + cache_ref->next_in_ino = NULL; + cache_ref->next_phys = NULL; + cache_ref->flash_offset = ofs | REF_NORMAL; + cache_ref->__totlen = sumsize; + + if (!jeb->first_node) + jeb->first_node = cache_ref; + if (jeb->last_node) + jeb->last_node->next_phys = cache_ref; + jeb->last_node = cache_ref; + + USED_SPACE(sumsize); + + jeb->wasted_size += jeb->free_size; + c->wasted_size += jeb->free_size; + c->free_size -= jeb->free_size; + jeb->free_size = 0; + + return jffs2_scan_classify_jeb(c, jeb); + +crc_err: + JFFS2_WARNING("Summary node crc error, skipping summary information.\n"); + + return 0; +} + +/* Write summary data to flash - helper function for jffs2_sum_write_sumnode() */ + +static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + uint32_t infosize, uint32_t datasize, int padsize) +{ + struct jffs2_raw_summary isum; + union jffs2_sum_mem *temp; + struct jffs2_sum_marker *sm; + struct kvec vecs[2]; + void *wpage; + int ret; + size_t retlen; + + memset(c->summary->sum_buf, 0xff, datasize); + memset(&isum, 0, sizeof(isum)); + + isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY); + isum.totlen = cpu_to_je32(infosize); + isum.hdr_crc = cpu_to_je32(crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4)); + isum.padded = cpu_to_je32(c->summary->sum_padded); + isum.cln_mkr = cpu_to_je32(c->cleanmarker_size); + isum.sum_num = cpu_to_je32(c->summary->sum_num); + wpage = c->summary->sum_buf; + + while (c->summary->sum_num) { + + switch (je16_to_cpu(c->summary->sum_list_head->u.nodetype)) { + case JFFS2_NODETYPE_INODE: { + struct jffs2_sum_inode_flash *sino_ptr = wpage; + + sino_ptr->nodetype = c->summary->sum_list_head->i.nodetype; + sino_ptr->inode = c->summary->sum_list_head->i.inode; + sino_ptr->version = c->summary->sum_list_head->i.version; + sino_ptr->offset = c->summary->sum_list_head->i.offset; + sino_ptr->totlen = c->summary->sum_list_head->i.totlen; + + wpage += JFFS2_SUMMARY_INODE_SIZE; + + break; + } + + case JFFS2_NODETYPE_DIRENT: { + struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage; + + sdrnt_ptr->nodetype = c->summary->sum_list_head->d.nodetype; + sdrnt_ptr->totlen = c->summary->sum_list_head->d.totlen; + sdrnt_ptr->offset = c->summary->sum_list_head->d.offset; + sdrnt_ptr->pino = c->summary->sum_list_head->d.pino; + sdrnt_ptr->version = c->summary->sum_list_head->d.version; + sdrnt_ptr->ino = c->summary->sum_list_head->d.ino; + sdrnt_ptr->nsize = c->summary->sum_list_head->d.nsize; + sdrnt_ptr->type = c->summary->sum_list_head->d.type; + + memcpy(sdrnt_ptr->name, c->summary->sum_list_head->d.name, + c->summary->sum_list_head->d.nsize); + + wpage += JFFS2_SUMMARY_DIRENT_SIZE(c->summary->sum_list_head->d.nsize); + + break; + } + + default : { + BUG(); /* unknown node in summary information */ + } + } + + temp = c->summary->sum_list_head; + c->summary->sum_list_head = c->summary->sum_list_head->u.next; + kfree(temp); + + c->summary->sum_num--; + } + + jffs2_sum_reset_collected(c->summary); + + wpage += padsize; + + sm = wpage; + sm->offset = cpu_to_je32(c->sector_size - jeb->free_size); + sm->magic = cpu_to_je32(JFFS2_SUM_MAGIC); + + isum.sum_crc = cpu_to_je32(crc32(0, c->summary->sum_buf, datasize)); + isum.node_crc = cpu_to_je32(crc32(0, &isum, sizeof(isum) - 8)); + + vecs[0].iov_base = &isum; + vecs[0].iov_len = sizeof(isum); + vecs[1].iov_base = c->summary->sum_buf; + vecs[1].iov_len = datasize; + + dbg_summary("JFFS2: writing out data to flash to pos : 0x%08x\n", + jeb->offset + c->sector_size - jeb->free_size); + + spin_unlock(&c->erase_completion_lock); + ret = jffs2_flash_writev(c, vecs, 2, jeb->offset + c->sector_size - + jeb->free_size, &retlen, 0); + spin_lock(&c->erase_completion_lock); + + + if (ret || (retlen != infosize)) { + JFFS2_WARNING("Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", + infosize, jeb->offset + c->sector_size - jeb->free_size, ret, retlen); + + c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; + WASTED_SPACE(infosize); + + return 1; + } + + return 0; +} + +/* Write out summary information - called from jffs2_do_reserve_space */ + +int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) +{ + struct jffs2_raw_node_ref *summary_ref; + int datasize, infosize, padsize, ret; + struct jffs2_eraseblock *jeb; + + dbg_summary("called\n"); + + jeb = c->nextblock; + + if (!c->summary->sum_num || !c->summary->sum_list_head) { + JFFS2_WARNING("Empty summary info!!!\n"); + BUG(); + } + + datasize = c->summary->sum_size + sizeof(struct jffs2_sum_marker); + infosize = sizeof(struct jffs2_raw_summary) + datasize; + padsize = jeb->free_size - infosize; + infosize += padsize; + datasize += padsize; + + /* Is there enough space for summary? */ + if (padsize < 0) { + /* don't try to write out summary for this jeb */ + jffs2_sum_disable_collecting(c->summary); + + JFFS2_WARNING("Not enough space for summary, padsize = %d\n", padsize); + return 0; + } + + ret = jffs2_sum_write_data(c, jeb, infosize, datasize, padsize); + if (ret) + return 0; /* can't write out summary, block is marked as NOSUM_SIZE */ + + /* for ACCT_PARANOIA_CHECK */ + spin_unlock(&c->erase_completion_lock); + summary_ref = jffs2_alloc_raw_node_ref(); + spin_lock(&c->erase_completion_lock); + + if (!summary_ref) { + JFFS2_NOTICE("Failed to allocate node ref for summary\n"); + return -ENOMEM; + } + + summary_ref->next_in_ino = NULL; + summary_ref->next_phys = NULL; + summary_ref->flash_offset = (jeb->offset + c->sector_size - jeb->free_size) | REF_NORMAL; + summary_ref->__totlen = infosize; + + if (!jeb->first_node) + jeb->first_node = summary_ref; + if (jeb->last_node) + jeb->last_node->next_phys = summary_ref; + jeb->last_node = summary_ref; + + USED_SPACE(infosize); + + return 0; +} diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h new file mode 100644 index 0000000000000000000000000000000000000000..b7a678be170972fa68f0ef9423f0781971ab68ce --- /dev/null +++ b/fs/jffs2/summary.h @@ -0,0 +1,183 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2004 Ferenc Havasi , + * Zoltan Sogor , + * Patrik Kluba , + * University of Szeged, Hungary + * + * For licensing information, see the file 'LICENCE' in this directory. + * + * $Id: summary.h,v 1.2 2005/09/26 11:37:21 havasi Exp $ + * + */ + +#ifndef JFFS2_SUMMARY_H +#define JFFS2_SUMMARY_H + +#include +#include + +#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \ + c->free_size -= _x; c->dirty_size += _x; \ + jeb->free_size -= _x ; jeb->dirty_size += _x; \ + }while(0) +#define USED_SPACE(x) do { typeof(x) _x = (x); \ + c->free_size -= _x; c->used_size += _x; \ + jeb->free_size -= _x ; jeb->used_size += _x; \ + }while(0) +#define WASTED_SPACE(x) do { typeof(x) _x = (x); \ + c->free_size -= _x; c->wasted_size += _x; \ + jeb->free_size -= _x ; jeb->wasted_size += _x; \ + }while(0) +#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \ + c->free_size -= _x; c->unchecked_size += _x; \ + jeb->free_size -= _x ; jeb->unchecked_size += _x; \ + }while(0) + +#define BLK_STATE_ALLFF 0 +#define BLK_STATE_CLEAN 1 +#define BLK_STATE_PARTDIRTY 2 +#define BLK_STATE_CLEANMARKER 3 +#define BLK_STATE_ALLDIRTY 4 +#define BLK_STATE_BADBLOCK 5 + +#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff +#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash)) +#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x)) + +/* Summary structures used on flash */ + +struct jffs2_sum_unknown_flash +{ + jint16_t nodetype; /* node type */ +}; + +struct jffs2_sum_inode_flash +{ + jint16_t nodetype; /* node type */ + jint32_t inode; /* inode number */ + jint32_t version; /* inode version */ + jint32_t offset; /* offset on jeb */ + jint32_t totlen; /* record length */ +} __attribute__((packed)); + +struct jffs2_sum_dirent_flash +{ + jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */ + jint32_t totlen; /* record length */ + jint32_t offset; /* offset on jeb */ + jint32_t pino; /* parent inode */ + jint32_t version; /* dirent version */ + jint32_t ino; /* == zero for unlink */ + uint8_t nsize; /* dirent name size */ + uint8_t type; /* dirent type */ + uint8_t name[0]; /* dirent name */ +} __attribute__((packed)); + +union jffs2_sum_flash +{ + struct jffs2_sum_unknown_flash u; + struct jffs2_sum_inode_flash i; + struct jffs2_sum_dirent_flash d; +}; + +/* Summary structures used in the memory */ + +struct jffs2_sum_unknown_mem +{ + union jffs2_sum_mem *next; + jint16_t nodetype; /* node type */ +}; + +struct jffs2_sum_inode_mem +{ + union jffs2_sum_mem *next; + jint16_t nodetype; /* node type */ + jint32_t inode; /* inode number */ + jint32_t version; /* inode version */ + jint32_t offset; /* offset on jeb */ + jint32_t totlen; /* record length */ +} __attribute__((packed)); + +struct jffs2_sum_dirent_mem +{ + union jffs2_sum_mem *next; + jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */ + jint32_t totlen; /* record length */ + jint32_t offset; /* ofset on jeb */ + jint32_t pino; /* parent inode */ + jint32_t version; /* dirent version */ + jint32_t ino; /* == zero for unlink */ + uint8_t nsize; /* dirent name size */ + uint8_t type; /* dirent type */ + uint8_t name[0]; /* dirent name */ +} __attribute__((packed)); + +union jffs2_sum_mem +{ + struct jffs2_sum_unknown_mem u; + struct jffs2_sum_inode_mem i; + struct jffs2_sum_dirent_mem d; +}; + +/* Summary related information stored in superblock */ + +struct jffs2_summary +{ + uint32_t sum_size; /* collected summary information for nextblock */ + uint32_t sum_num; + uint32_t sum_padded; + union jffs2_sum_mem *sum_list_head; + union jffs2_sum_mem *sum_list_tail; + + jint32_t *sum_buf; /* buffer for writing out summary */ +}; + +/* Summary marker is stored at the end of every sumarized erase block */ + +struct jffs2_sum_marker +{ + jint32_t offset; /* offset of the summary node in the jeb */ + jint32_t magic; /* == JFFS2_SUM_MAGIC */ +}; + +#define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_raw_summary) + sizeof(struct jffs2_sum_marker)) + +#ifdef CONFIG_JFFS2_SUMMARY /* SUMMARY SUPPORT ENABLED */ + +#define jffs2_sum_active() (1) +int jffs2_sum_init(struct jffs2_sb_info *c); +void jffs2_sum_exit(struct jffs2_sb_info *c); +void jffs2_sum_disable_collecting(struct jffs2_summary *s); +int jffs2_sum_is_disabled(struct jffs2_summary *s); +void jffs2_sum_reset_collected(struct jffs2_summary *s); +void jffs2_sum_move_collected(struct jffs2_sb_info *c, struct jffs2_summary *s); +int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs, + unsigned long count, uint32_t to); +int jffs2_sum_write_sumnode(struct jffs2_sb_info *c); +int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size); +int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri, uint32_t ofs); +int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd, uint32_t ofs); +int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + uint32_t ofs, uint32_t *pseudo_random); + +#else /* SUMMARY DISABLED */ + +#define jffs2_sum_active() (0) +#define jffs2_sum_init(a) (0) +#define jffs2_sum_exit(a) +#define jffs2_sum_disable_collecting(a) +#define jffs2_sum_is_disabled(a) (0) +#define jffs2_sum_reset_collected(a) +#define jffs2_sum_add_kvec(a,b,c,d) (0) +#define jffs2_sum_move_collected(a,b) +#define jffs2_sum_write_sumnode(a) (0) +#define jffs2_sum_add_padding_mem(a,b) +#define jffs2_sum_add_inode_mem(a,b,c) +#define jffs2_sum_add_dirent_mem(a,b,c) +#define jffs2_sum_scan_sumnode(a,b,c,d) (0) + +#endif /* CONFIG_JFFS2_SUMMARY */ + +#endif /* JFFS2_SUMMARY_H */ diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index aaf9475cfb6ad866e05660121fd1a516650345b0..9e0b5458d9c072bc76e4fa6825e2b02163e4e0c4 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: super.c,v 1.107 2005/07/12 16:37:08 dedekind Exp $ + * $Id: super.c,v 1.110 2005/11/07 11:14:42 gleixner Exp $ * */ @@ -62,7 +62,7 @@ static int jffs2_sync_fs(struct super_block *sb, int wait) down(&c->alloc_sem); jffs2_flush_wbuf_pad(c); - up(&c->alloc_sem); + up(&c->alloc_sem); return 0; } @@ -112,7 +112,7 @@ static int jffs2_sb_set(struct super_block *sb, void *data) } static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type, - int flags, const char *dev_name, + int flags, const char *dev_name, void *data, struct mtd_info *mtd) { struct super_block *sb; @@ -172,7 +172,7 @@ static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type, } static struct super_block *jffs2_get_sb_mtdnr(struct file_system_type *fs_type, - int flags, const char *dev_name, + int flags, const char *dev_name, void *data, int mtdnr) { struct mtd_info *mtd; @@ -201,7 +201,7 @@ static struct super_block *jffs2_get_sb(struct file_system_type *fs_type, /* The preferred way of mounting in future; especially when CONFIG_BLK_DEV is implemented - we specify the underlying - MTD device by number or by name, so that we don't require + MTD device by number or by name, so that we don't require block device support to be present in the kernel. */ /* FIXME: How to do the root fs this way? */ @@ -225,7 +225,7 @@ static struct super_block *jffs2_get_sb(struct file_system_type *fs_type, } else if (isdigit(dev_name[3])) { /* Mount by MTD device number name */ char *endptr; - + mtdnr = simple_strtoul(dev_name+3, &endptr, 0); if (!*endptr) { /* It was a valid number */ @@ -235,7 +235,7 @@ static struct super_block *jffs2_get_sb(struct file_system_type *fs_type, } } - /* Try the old way - the hack where we allowed users to mount + /* Try the old way - the hack where we allowed users to mount /dev/mtdblock$(n) but didn't actually _use_ the blkdev */ err = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); @@ -282,9 +282,12 @@ static void jffs2_put_super (struct super_block *sb) down(&c->alloc_sem); jffs2_flush_wbuf_pad(c); up(&c->alloc_sem); + + jffs2_sum_exit(c); + jffs2_free_ino_caches(c); jffs2_free_raw_node_refs(c); - if (c->mtd->flags & MTD_NO_VIRTBLOCKS) + if (jffs2_blocks_use_vmalloc(c)) vfree(c->blocks); else kfree(c->blocks); @@ -320,6 +323,9 @@ static int __init init_jffs2_fs(void) printk(KERN_INFO "JFFS2 version 2.2." #ifdef CONFIG_JFFS2_FS_WRITEBUFFER " (NAND)" +#endif +#ifdef CONFIG_JFFS2_SUMMARY + " (SUMMARY) " #endif " (C) 2001-2003 Red Hat, Inc.\n"); @@ -370,5 +376,5 @@ module_exit(exit_jffs2_fs); MODULE_DESCRIPTION("The Journalling Flash File System, v2"); MODULE_AUTHOR("Red Hat, Inc."); -MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for +MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for // the sake of this tag. It's Free Software. diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c index 82ef484f5e12337ba1cc190e30275e0ebe7a9e16..d55754fe8925c537ac2ff5e117007c0370a41ee0 100644 --- a/fs/jffs2/symlink.c +++ b/fs/jffs2/symlink.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: symlink.c,v 1.16 2005/03/01 10:50:48 dedekind Exp $ + * $Id: symlink.c,v 1.19 2005/11/07 11:14:42 gleixner Exp $ * */ @@ -21,7 +21,7 @@ static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd); struct inode_operations jffs2_symlink_inode_operations = -{ +{ .readlink = generic_readlink, .follow_link = jffs2_follow_link, .setattr = jffs2_setattr @@ -30,35 +30,33 @@ struct inode_operations jffs2_symlink_inode_operations = static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) { struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode); - char *p = (char *)f->dents; - + char *p = (char *)f->target; + /* * We don't acquire the f->sem mutex here since the only data we - * use is f->dents which in case of the symlink inode points to the - * symlink's target path. + * use is f->target. * - * 1. If we are here the inode has already built and f->dents has + * 1. If we are here the inode has already built and f->target has * to point to the target path. - * 2. Nobody uses f->dents (if the inode is symlink's inode). The - * exception is inode freeing function which frees f->dents. But + * 2. Nobody uses f->target (if the inode is symlink's inode). The + * exception is inode freeing function which frees f->target. But * it can't be called while we are here and before VFS has - * stopped using our f->dents string which we provide by means of + * stopped using our f->target string which we provide by means of * nd_set_link() call. */ - + if (!p) { printk(KERN_ERR "jffs2_follow_link(): can't find symlink taerget\n"); p = ERR_PTR(-EIO); - } else { - D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->dents)); } + D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->target)); nd_set_link(nd, p); - + /* - * We unlock the f->sem mutex but VFS will use the f->dents string. This is safe - * since the only way that may cause f->dents to be changed is iput() operation. - * But VFS will not use f->dents after iput() has been called. + * We will unlock the f->sem mutex but VFS will use the f->target string. This is safe + * since the only way that may cause f->target to be changed is iput() operation. + * But VFS will not use f->target after iput() has been called. */ return NULL; } diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 316133c626b7424fc68ccfce9043c5d92c6e359d..4cebf0e57c465bbf130b7077ea667ded3bac0b08 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -9,7 +9,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: wbuf.c,v 1.92 2005/04/05 12:51:54 dedekind Exp $ + * $Id: wbuf.c,v 1.100 2005/09/30 13:59:13 dedekind Exp $ * */ @@ -30,12 +30,12 @@ static unsigned char *brokenbuf; #endif +#define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) ) +#define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) ) + /* max. erase failures before we mark a block bad */ #define MAX_ERASE_FAILURES 2 -/* two seconds timeout for timed wbuf-flushing */ -#define WBUF_FLUSH_TIMEOUT 2 * HZ - struct jffs2_inodirty { uint32_t ino; struct jffs2_inodirty *next; @@ -139,7 +139,6 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock { D1(printk("About to refile bad block at %08x\n", jeb->offset)); - D2(jffs2_dump_block_lists(c)); /* File the existing block on the bad_used_list.... */ if (c->nextblock == jeb) c->nextblock = NULL; @@ -156,7 +155,6 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock c->nr_erasing_blocks++; jffs2_erase_pending_trigger(c); } - D2(jffs2_dump_block_lists(c)); /* Adjust its size counts accordingly */ c->wasted_size += jeb->free_size; @@ -164,8 +162,9 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock jeb->wasted_size += jeb->free_size; jeb->free_size = 0; - ACCT_SANITY_CHECK(c,jeb); - D1(ACCT_PARANOIA_CHECK(jeb)); + jffs2_dbg_dump_block_lists_nolock(c); + jffs2_dbg_acct_sanity_check_nolock(c,jeb); + jffs2_dbg_acct_paranoia_check_nolock(c, jeb); } /* Recover from failure to write wbuf. Recover the nodes up to the @@ -189,7 +188,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) /* Find the first node to be recovered, by skipping over every node which ends before the wbuf starts, or which is obsolete. */ first_raw = &jeb->first_node; - while (*first_raw && + while (*first_raw && (ref_obsolete(*first_raw) || (ref_offset(*first_raw)+ref_totlen(c, jeb, *first_raw)) < c->wbuf_ofs)) { D1(printk(KERN_DEBUG "Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n", @@ -238,7 +237,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) ret = c->mtd->read_ecc(c->mtd, start, c->wbuf_ofs - start, &retlen, buf, NULL, c->oobinfo); else ret = c->mtd->read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf); - + if (ret == -EBADMSG && retlen == c->wbuf_ofs - start) { /* ECC recovered */ ret = 0; @@ -266,7 +265,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) /* ... and get an allocation of space from a shiny new block instead */ - ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len); + ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len, JFFS2_SUMMARY_NOSUM_SIZE); if (ret) { printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n"); kfree(buf); @@ -275,15 +274,15 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) if (end-start >= c->wbuf_pagesize) { /* Need to do another write immediately, but it's possible that this is just because the wbuf itself is completely - full, and there's nothing earlier read back from the - flash. Hence 'buf' isn't necessarily what we're writing + full, and there's nothing earlier read back from the + flash. Hence 'buf' isn't necessarily what we're writing from. */ unsigned char *rewrite_buf = buf?:c->wbuf; uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize); D1(printk(KERN_DEBUG "Write 0x%x bytes at 0x%08x in wbuf recover\n", towrite, ofs)); - + #ifdef BREAKMEHEADER static int breakme; if (breakme++ == 20) { @@ -327,8 +326,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) c->wbuf_ofs = ofs + towrite; memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len); /* Don't muck about with c->wbuf_inodes. False positives are harmless. */ - if (buf) - kfree(buf); + kfree(buf); } else { /* OK, now we're left with the dregs in whichever buffer we're using */ if (buf) { @@ -392,11 +390,11 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) else jeb->last_node = container_of(first_raw, struct jffs2_raw_node_ref, next_phys); - ACCT_SANITY_CHECK(c,jeb); - D1(ACCT_PARANOIA_CHECK(jeb)); + jffs2_dbg_acct_sanity_check_nolock(c, jeb); + jffs2_dbg_acct_paranoia_check_nolock(c, jeb); - ACCT_SANITY_CHECK(c,new_jeb); - D1(ACCT_PARANOIA_CHECK(new_jeb)); + jffs2_dbg_acct_sanity_check_nolock(c, new_jeb); + jffs2_dbg_acct_paranoia_check_nolock(c, new_jeb); spin_unlock(&c->erase_completion_lock); @@ -435,15 +433,15 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) this happens, if we have a change to a new block, or if fsync forces us to flush the writebuffer. if we have a switch to next page, we will not have - enough remaining space for this. + enough remaining space for this. */ - if (pad && !jffs2_dataflash(c)) { + if (pad ) { c->wbuf_len = PAD(c->wbuf_len); /* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR with 8 byte page size */ memset(c->wbuf + c->wbuf_len, 0, c->wbuf_pagesize - c->wbuf_len); - + if ( c->wbuf_len + sizeof(struct jffs2_unknown_node) < c->wbuf_pagesize) { struct jffs2_unknown_node *padnode = (void *)(c->wbuf + c->wbuf_len); padnode->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); @@ -454,7 +452,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) } /* else jffs2_flash_writev has actually filled in the rest of the buffer for us, and will deal with the node refs etc. later. */ - + #ifdef BREAKME static int breakme; if (breakme++ == 20) { @@ -463,9 +461,9 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, brokenbuf, NULL, c->oobinfo); ret = -EIO; - } else + } else #endif - + if (jffs2_cleanmarker_oob(c)) ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo); else @@ -488,7 +486,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) spin_lock(&c->erase_completion_lock); /* Adjust free size of the block if we padded. */ - if (pad && !jffs2_dataflash(c)) { + if (pad) { struct jffs2_eraseblock *jeb; jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; @@ -496,7 +494,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n", (jeb==c->nextblock)?"next":"", jeb->offset)); - /* wbuf_pagesize - wbuf_len is the amount of space that's to be + /* wbuf_pagesize - wbuf_len is the amount of space that's to be padded. If there is less free space in the block than that, something screwed up */ if (jeb->free_size < (c->wbuf_pagesize - c->wbuf_len)) { @@ -524,9 +522,9 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) return 0; } -/* Trigger garbage collection to flush the write-buffer. +/* Trigger garbage collection to flush the write-buffer. If ino arg is zero, do it if _any_ real (i.e. not GC) writes are - outstanding. If ino arg non-zero, do it only if a write for the + outstanding. If ino arg non-zero, do it only if a write for the given inode is outstanding. */ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) { @@ -605,15 +603,6 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c) return ret; } - -#ifdef CONFIG_JFFS2_FS_WRITEBUFFER -#define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) ) -#define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) ) -#else -#define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) ) -#define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) ) -#endif - int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino) { struct kvec outvecs[3]; @@ -630,13 +619,13 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig /* If not NAND flash, don't bother */ if (!jffs2_is_writebuffered(c)) return jffs2_flash_direct_writev(c, invecs, count, to, retlen); - + down_write(&c->wbuf_sem); /* If wbuf_ofs is not initialized, set it to target address */ if (c->wbuf_ofs == 0xFFFFFFFF) { c->wbuf_ofs = PAGE_DIV(to); - c->wbuf_len = PAGE_MOD(to); + c->wbuf_len = PAGE_MOD(to); memset(c->wbuf,0xff,c->wbuf_pagesize); } @@ -650,10 +639,10 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig memset(c->wbuf,0xff,c->wbuf_pagesize); } } - - /* Sanity checks on target address. - It's permitted to write at PAD(c->wbuf_len+c->wbuf_ofs), - and it's permitted to write at the beginning of a new + + /* Sanity checks on target address. + It's permitted to write at PAD(c->wbuf_len+c->wbuf_ofs), + and it's permitted to write at the beginning of a new erase block. Anything else, and you die. New block starts at xxx000c (0-b = block header) */ @@ -671,8 +660,8 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig } /* set pointer to new block */ c->wbuf_ofs = PAGE_DIV(to); - c->wbuf_len = PAGE_MOD(to); - } + c->wbuf_len = PAGE_MOD(to); + } if (to != PAD(c->wbuf_ofs + c->wbuf_len)) { /* We're not writing immediately after the writebuffer. Bad. */ @@ -692,21 +681,21 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig invec = 0; outvec = 0; - /* Fill writebuffer first, if already in use */ + /* Fill writebuffer first, if already in use */ if (c->wbuf_len) { uint32_t invec_ofs = 0; - /* adjust alignment offset */ + /* adjust alignment offset */ if (c->wbuf_len != PAGE_MOD(to)) { c->wbuf_len = PAGE_MOD(to); /* take care of alignment to next page */ if (!c->wbuf_len) c->wbuf_len = c->wbuf_pagesize; } - + while(c->wbuf_len < c->wbuf_pagesize) { uint32_t thislen; - + if (invec == count) goto alldone; @@ -714,17 +703,17 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig if (thislen >= invecs[invec].iov_len) thislen = invecs[invec].iov_len; - + invec_ofs = thislen; memcpy(c->wbuf + c->wbuf_len, invecs[invec].iov_base, thislen); c->wbuf_len += thislen; donelen += thislen; /* Get next invec, if actual did not fill the buffer */ - if (c->wbuf_len < c->wbuf_pagesize) + if (c->wbuf_len < c->wbuf_pagesize) invec++; - } - + } + /* write buffer is full, flush buffer */ ret = __jffs2_flush_wbuf(c, NOPAD); if (ret) { @@ -783,10 +772,10 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig /* We did cross a page boundary, so we write some now */ if (jffs2_cleanmarker_oob(c)) - ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo); + ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo); else ret = jffs2_flash_direct_writev(c, outvecs, splitvec+1, outvec_to, &wbuf_retlen); - + if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) { /* At this point we have no problem, c->wbuf is empty. However refile nextblock to avoid @@ -803,7 +792,7 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig spin_unlock(&c->erase_completion_lock); goto exit; } - + donelen += wbuf_retlen; c->wbuf_ofs = PAGE_DIV(outvec_to) + PAGE_DIV(totlen); @@ -837,11 +826,17 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig alldone: *retlen = donelen; + if (jffs2_sum_active()) { + int res = jffs2_sum_add_kvec(c, invecs, count, (uint32_t) to); + if (res) + return res; + } + if (c->wbuf_len && ino) jffs2_wbuf_dirties_inode(c, ino); ret = 0; - + exit: up_write(&c->wbuf_sem); return ret; @@ -856,7 +851,7 @@ int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *r struct kvec vecs[1]; if (!jffs2_is_writebuffered(c)) - return c->mtd->write(c->mtd, ofs, len, retlen, buf); + return jffs2_flash_direct_write(c, ofs, len, retlen, buf); vecs[0].iov_base = (unsigned char *) buf; vecs[0].iov_len = len; @@ -884,18 +879,18 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re if ( (ret == -EBADMSG) && (*retlen == len) ) { printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", len, ofs); - /* - * We have the raw data without ECC correction in the buffer, maybe + /* + * We have the raw data without ECC correction in the buffer, maybe * we are lucky and all data or parts are correct. We check the node. * If data are corrupted node check will sort it out. * We keep this block, it will fail on write or erase and the we * mark it bad. Or should we do that now? But we should give him a chance. - * Maybe we had a system crash or power loss before the ecc write or + * Maybe we had a system crash or power loss before the ecc write or * a erase was completed. * So we return success. :) */ ret = 0; - } + } /* if no writebuffer available or write buffer empty, return */ if (!c->wbuf_pagesize || !c->wbuf_len) @@ -910,16 +905,16 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re if (owbf > c->wbuf_len) /* is read beyond write buffer ? */ goto exit; lwbf = c->wbuf_len - owbf; /* number of bytes to copy */ - if (lwbf > len) + if (lwbf > len) lwbf = len; - } else { + } else { orbf = (c->wbuf_ofs - ofs); /* offset in read buffer */ if (orbf > len) /* is write beyond write buffer ? */ goto exit; lwbf = len - orbf; /* number of bytes to copy */ - if (lwbf > c->wbuf_len) + if (lwbf > c->wbuf_len) lwbf = c->wbuf_len; - } + } if (lwbf > 0) memcpy(buf+orbf,c->wbuf+owbf,lwbf); @@ -947,7 +942,7 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb printk(KERN_NOTICE "jffs2_check_oob_empty(): allocation of temporary data buffer for oob check failed\n"); return -ENOMEM; } - /* + /* * if mode = 0, we scan for a total empty oob area, else we have * to take care of the cleanmarker in the first page of the block */ @@ -956,41 +951,41 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB failed %d for block at %08x\n", ret, jeb->offset)); goto out; } - + if (retlen < len) { D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB return short read " "(%zd bytes not %d) for block at %08x\n", retlen, len, jeb->offset)); ret = -EIO; goto out; } - + /* Special check for first page */ for(i = 0; i < oob_size ; i++) { /* Yeah, we know about the cleanmarker. */ - if (mode && i >= c->fsdata_pos && + if (mode && i >= c->fsdata_pos && i < c->fsdata_pos + c->fsdata_len) continue; if (buf[i] != 0xFF) { D2(printk(KERN_DEBUG "Found %02x at %x in OOB for %08x\n", - buf[page+i], page+i, jeb->offset)); - ret = 1; + buf[i], i, jeb->offset)); + ret = 1; goto out; } } - /* we know, we are aligned :) */ + /* we know, we are aligned :) */ for (page = oob_size; page < len; page += sizeof(long)) { unsigned long dat = *(unsigned long *)(&buf[page]); if(dat != -1) { - ret = 1; + ret = 1; goto out; } } out: - kfree(buf); - + kfree(buf); + return ret; } @@ -1072,7 +1067,7 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc n.totlen = cpu_to_je32(8); ret = jffs2_flash_write_oob(c, jeb->offset + c->fsdata_pos, c->fsdata_len, &retlen, (unsigned char *)&n); - + if (ret) { D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Write failed for block at %08x: error %d\n", jeb->offset, ret)); return ret; @@ -1084,7 +1079,7 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc return 0; } -/* +/* * On NAND we try to mark this block bad. If the block was erased more * than MAX_ERASE_FAILURES we mark it finaly bad. * Don't care about failures. This block remains on the erase-pending @@ -1105,7 +1100,7 @@ int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock * D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Marking bad block at %08x\n", bad_offset)); ret = c->mtd->block_markbad(c->mtd, bad_offset); - + if (ret) { D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Write failed for block at %08x: error %d\n", jeb->offset, ret)); return ret; @@ -1129,7 +1124,7 @@ static int jffs2_nand_set_oobinfo(struct jffs2_sb_info *c) /* Do this only, if we have an oob buffer */ if (!c->mtd->oobsize) return 0; - + /* Cleanmarker is out-of-band, so inline size zero */ c->cleanmarker_size = 0; @@ -1155,7 +1150,7 @@ static int jffs2_nand_set_oobinfo(struct jffs2_sb_info *c) c->fsdata_len = NAND_JFFS2_OOB16_FSDALEN; c->badblock_pos = 15; break; - + default: D1(printk(KERN_DEBUG "JFFS2 on NAND. No autoplacment info found\n")); return -EINVAL; @@ -1172,7 +1167,7 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c) init_rwsem(&c->wbuf_sem); c->wbuf_pagesize = c->mtd->oobblock; c->wbuf_ofs = 0xFFFFFFFF; - + c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); if (!c->wbuf) return -ENOMEM; @@ -1198,17 +1193,41 @@ void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) int jffs2_dataflash_setup(struct jffs2_sb_info *c) { c->cleanmarker_size = 0; /* No cleanmarkers needed */ - + /* Initialize write buffer */ init_rwsem(&c->wbuf_sem); - c->wbuf_pagesize = c->sector_size; - c->wbuf_ofs = 0xFFFFFFFF; + + c->wbuf_pagesize = c->mtd->erasesize; + + /* Find a suitable c->sector_size + * - Not too much sectors + * - Sectors have to be at least 4 K + some bytes + * - All known dataflashes have erase sizes of 528 or 1056 + * - we take at least 8 eraseblocks and want to have at least 8K size + * - The concatenation should be a power of 2 + */ + + c->sector_size = 8 * c->mtd->erasesize; + + while (c->sector_size < 8192) { + c->sector_size *= 2; + } + + /* It may be necessary to adjust the flash size */ + c->flash_size = c->mtd->size; + + if ((c->flash_size % c->sector_size) != 0) { + c->flash_size = (c->flash_size / c->sector_size) * c->sector_size; + printk(KERN_WARNING "JFFS2 flash size adjusted to %dKiB\n", c->flash_size); + }; + + c->wbuf_ofs = 0xFFFFFFFF; c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); if (!c->wbuf) return -ENOMEM; - printk(KERN_INFO "JFFS2 write-buffering enabled (%i)\n", c->wbuf_pagesize); + printk(KERN_INFO "JFFS2 write-buffering enabled buffer (%d) erasesize (%d)\n", c->wbuf_pagesize, c->sector_size); return 0; } @@ -1236,3 +1255,23 @@ int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) { void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c) { kfree(c->wbuf); } + +int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c) { + /* Cleanmarker currently occupies a whole programming region */ + c->cleanmarker_size = MTD_PROGREGION_SIZE(c->mtd); + + /* Initialize write buffer */ + init_rwsem(&c->wbuf_sem); + c->wbuf_pagesize = MTD_PROGREGION_SIZE(c->mtd); + c->wbuf_ofs = 0xFFFFFFFF; + + c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); + if (!c->wbuf) + return -ENOMEM; + + return 0; +} + +void jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c) { + kfree(c->wbuf); +} diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index 69100615d9aef17535f808ed6e5e805b404f6eb2..1342f0158e9b0d0da2565c99c18eb5f088c501a5 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: write.c,v 1.92 2005/04/13 13:22:35 dwmw2 Exp $ + * $Id: write.c,v 1.97 2005/11/07 11:14:42 gleixner Exp $ * */ @@ -54,35 +54,7 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint return 0; } -#if CONFIG_JFFS2_FS_DEBUG > 0 -static void writecheck(struct jffs2_sb_info *c, uint32_t ofs) -{ - unsigned char buf[16]; - size_t retlen; - int ret, i; - - ret = jffs2_flash_read(c, ofs, 16, &retlen, buf); - if (ret || (retlen != 16)) { - D1(printk(KERN_DEBUG "read failed or short in writecheck(). ret %d, retlen %zd\n", ret, retlen)); - return; - } - ret = 0; - for (i=0; i<16; i++) { - if (buf[i] != 0xff) - ret = 1; - } - if (ret) { - printk(KERN_WARNING "ARGH. About to write node to 0x%08x on flash, but there are data already there:\n", ofs); - printk(KERN_WARNING "0x%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - ofs, - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], - buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); - } -} -#endif - - -/* jffs2_write_dnode - given a raw_inode, allocate a full_dnode for it, +/* jffs2_write_dnode - given a raw_inode, allocate a full_dnode for it, write it to the flash, link it into the existing inode/fragment list */ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs, int alloc_mode) @@ -106,7 +78,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 vecs[1].iov_base = (unsigned char *)data; vecs[1].iov_len = datalen; - D1(writecheck(c, flash_ofs)); + jffs2_dbg_prewrite_paranoia_check(c, flash_ofs, vecs[0].iov_len + vecs[1].iov_len); if (je32_to_cpu(ri->totlen) != sizeof(*ri) + datalen) { printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08zx) + datalen (0x%08x)\n", je32_to_cpu(ri->totlen), sizeof(*ri), datalen); @@ -114,7 +86,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 raw = jffs2_alloc_raw_node_ref(); if (!raw) return ERR_PTR(-ENOMEM); - + fn = jffs2_alloc_full_dnode(); if (!fn) { jffs2_free_raw_node_ref(raw); @@ -138,7 +110,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(ri->version) < f->highest_version)) { BUG_ON(!retried); D1(printk(KERN_DEBUG "jffs2_write_dnode : dnode_version %d, " - "highest version %d -> updating dnode\n", + "highest version %d -> updating dnode\n", je32_to_cpu(ri->version), f->highest_version)); ri->version = cpu_to_je32(++f->highest_version); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); @@ -148,7 +120,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 (alloc_mode==ALLOC_GC)?0:f->inocache->ino); if (ret || (retlen != sizeof(*ri) + datalen)) { - printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", + printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", sizeof(*ri)+datalen, flash_ofs, ret, retlen); /* Mark the space as dirtied */ @@ -156,10 +128,10 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 /* Doesn't belong to any inode */ raw->next_in_ino = NULL; - /* Don't change raw->size to match retlen. We may have + /* Don't change raw->size to match retlen. We may have written the node header already, and only the data will seem corrupted, in which case the scan would skip over - any node we write before the original intended end of + any node we write before the original intended end of this node */ raw->flash_offset |= REF_OBSOLETE; jffs2_add_physical_node_ref(c, raw); @@ -176,26 +148,28 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 retried = 1; D1(printk(KERN_DEBUG "Retrying failed write.\n")); - - ACCT_SANITY_CHECK(c,jeb); - D1(ACCT_PARANOIA_CHECK(jeb)); + + jffs2_dbg_acct_sanity_check(c,jeb); + jffs2_dbg_acct_paranoia_check(c, jeb); if (alloc_mode == ALLOC_GC) { - ret = jffs2_reserve_space_gc(c, sizeof(*ri) + datalen, &flash_ofs, &dummy); + ret = jffs2_reserve_space_gc(c, sizeof(*ri) + datalen, &flash_ofs, + &dummy, JFFS2_SUMMARY_INODE_SIZE); } else { /* Locking pain */ up(&f->sem); jffs2_complete_reservation(c); - - ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &flash_ofs, &dummy, alloc_mode); + + ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &flash_ofs, + &dummy, alloc_mode, JFFS2_SUMMARY_INODE_SIZE); down(&f->sem); } if (!ret) { D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs)); - ACCT_SANITY_CHECK(c,jeb); - D1(ACCT_PARANOIA_CHECK(jeb)); + jffs2_dbg_acct_sanity_check(c,jeb); + jffs2_dbg_acct_paranoia_check(c, jeb); goto retry; } @@ -207,9 +181,9 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 return ERR_PTR(ret?ret:-EIO); } /* Mark the space used */ - /* If node covers at least a whole page, or if it starts at the - beginning of a page and runs to the end of the file, or if - it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. + /* If node covers at least a whole page, or if it starts at the + beginning of a page and runs to the end of the file, or if + it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. */ if ((je32_to_cpu(ri->dsize) >= PAGE_CACHE_SIZE) || ( ((je32_to_cpu(ri->offset)&(PAGE_CACHE_SIZE-1))==0) && @@ -227,12 +201,12 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 spin_unlock(&c->erase_completion_lock); D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x(%d) with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n", - flash_ofs, ref_flags(raw), je32_to_cpu(ri->dsize), + flash_ofs, ref_flags(raw), je32_to_cpu(ri->dsize), je32_to_cpu(ri->csize), je32_to_cpu(ri->node_crc), je32_to_cpu(ri->data_crc), je32_to_cpu(ri->totlen))); if (retried) { - ACCT_SANITY_CHECK(c,NULL); + jffs2_dbg_acct_sanity_check(c,NULL); } return fn; @@ -247,10 +221,9 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff int retried = 0; int ret; - D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n", + D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n", je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino), je32_to_cpu(rd->name_crc))); - D1(writecheck(c, flash_ofs)); D1(if(je32_to_cpu(rd->hdr_crc) != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) { printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dirent()\n"); @@ -262,7 +235,9 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff vecs[0].iov_len = sizeof(*rd); vecs[1].iov_base = (unsigned char *)name; vecs[1].iov_len = namelen; - + + jffs2_dbg_prewrite_paranoia_check(c, flash_ofs, vecs[0].iov_len + vecs[1].iov_len); + raw = jffs2_alloc_raw_node_ref(); if (!raw) @@ -301,7 +276,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen, (alloc_mode==ALLOC_GC)?0:je32_to_cpu(rd->pino)); if (ret || (retlen != sizeof(*rd) + namelen)) { - printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", + printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", sizeof(*rd)+namelen, flash_ofs, ret, retlen); /* Mark the space as dirtied */ if (retlen) { @@ -322,24 +297,26 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff D1(printk(KERN_DEBUG "Retrying failed write.\n")); - ACCT_SANITY_CHECK(c,jeb); - D1(ACCT_PARANOIA_CHECK(jeb)); + jffs2_dbg_acct_sanity_check(c,jeb); + jffs2_dbg_acct_paranoia_check(c, jeb); if (alloc_mode == ALLOC_GC) { - ret = jffs2_reserve_space_gc(c, sizeof(*rd) + namelen, &flash_ofs, &dummy); + ret = jffs2_reserve_space_gc(c, sizeof(*rd) + namelen, &flash_ofs, + &dummy, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); } else { /* Locking pain */ up(&f->sem); jffs2_complete_reservation(c); - - ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &flash_ofs, &dummy, alloc_mode); + + ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &flash_ofs, + &dummy, alloc_mode, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); down(&f->sem); } if (!ret) { D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs)); - ACCT_SANITY_CHECK(c,jeb); - D1(ACCT_PARANOIA_CHECK(jeb)); + jffs2_dbg_acct_sanity_check(c,jeb); + jffs2_dbg_acct_paranoia_check(c, jeb); goto retry; } D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret)); @@ -359,7 +336,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff spin_unlock(&c->erase_completion_lock); if (retried) { - ACCT_SANITY_CHECK(c,NULL); + jffs2_dbg_acct_sanity_check(c,NULL); } return fd; @@ -369,7 +346,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff we don't have to go digging in struct inode or its equivalent. It should set: mode, uid, gid, (starting)isize, atime, ctime, mtime */ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, - struct jffs2_raw_inode *ri, unsigned char *buf, + struct jffs2_raw_inode *ri, unsigned char *buf, uint32_t offset, uint32_t writelen, uint32_t *retlen) { int ret = 0; @@ -377,7 +354,7 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, D1(printk(KERN_DEBUG "jffs2_write_inode_range(): Ino #%u, ofs 0x%x, len 0x%x\n", f->inocache->ino, offset, writelen)); - + while(writelen) { struct jffs2_full_dnode *fn; unsigned char *comprbuf = NULL; @@ -389,7 +366,8 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, retry: D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, offset)); - ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen, ALLOC_NORMAL); + ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, + &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); if (ret) { D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret)); break; @@ -473,10 +451,11 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str uint32_t alloclen, phys_ofs; int ret; - /* Try to reserve enough space for both node and dirent. - * Just the node will do for now, though + /* Try to reserve enough space for both node and dirent. + * Just the node will do for now, though */ - ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL); + ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL, + JFFS2_SUMMARY_INODE_SIZE); D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen)); if (ret) { up(&f->sem); @@ -498,15 +477,16 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str jffs2_complete_reservation(c); return PTR_ERR(fn); } - /* No data here. Only a metadata node, which will be + /* No data here. Only a metadata node, which will be obsoleted by the first data write */ f->metadata = fn; up(&f->sem); jffs2_complete_reservation(c); - ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); - + ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, + ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); + if (ret) { /* Eep. */ D1(printk(KERN_DEBUG "jffs2_reserve_space() for dirent failed\n")); @@ -539,9 +519,9 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL); jffs2_free_raw_dirent(rd); - + if (IS_ERR(fd)) { - /* dirent failed to write. Delete the inode normally + /* dirent failed to write. Delete the inode normally as if it were the final unlink() */ jffs2_complete_reservation(c); up(&dir_f->sem); @@ -560,14 +540,15 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, - const char *name, int namelen, struct jffs2_inode_info *dead_f) + const char *name, int namelen, struct jffs2_inode_info *dead_f, + uint32_t time) { struct jffs2_raw_dirent *rd; struct jffs2_full_dirent *fd; uint32_t alloclen, phys_ofs; int ret; - if (1 /* alternative branch needs testing */ || + if (1 /* alternative branch needs testing */ || !jffs2_can_mark_obsolete(c)) { /* We can't mark stuff obsolete on the medium. We need to write a deletion dirent */ @@ -575,7 +556,8 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, if (!rd) return -ENOMEM; - ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_DELETION); + ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, + ALLOC_DELETION, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); if (ret) { jffs2_free_raw_dirent(rd); return ret; @@ -588,18 +570,18 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); - + rd->pino = cpu_to_je32(dir_f->inocache->ino); rd->version = cpu_to_je32(++dir_f->highest_version); rd->ino = cpu_to_je32(0); - rd->mctime = cpu_to_je32(get_seconds()); + rd->mctime = cpu_to_je32(time); rd->nsize = namelen; rd->type = DT_UNKNOWN; rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); rd->name_crc = cpu_to_je32(crc32(0, name, namelen)); fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_DELETION); - + jffs2_free_raw_dirent(rd); if (IS_ERR(fd)) { @@ -618,7 +600,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, down(&dir_f->sem); while ((*prev) && (*prev)->nhash <= nhash) { - if ((*prev)->nhash == nhash && + if ((*prev)->nhash == nhash && !memcmp((*prev)->name, name, namelen) && !(*prev)->name[namelen]) { struct jffs2_full_dirent *this = *prev; @@ -639,7 +621,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, /* dead_f is NULL if this was a rename not a real unlink */ /* Also catch the !f->inocache case, where there was a dirent pointing to an inode which didn't exist. */ - if (dead_f && dead_f->inocache) { + if (dead_f && dead_f->inocache) { down(&dead_f->sem); @@ -647,9 +629,9 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, while (dead_f->dents) { /* There can be only deleted ones */ fd = dead_f->dents; - + dead_f->dents = fd->next; - + if (fd->ino) { printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n", dead_f->inocache->ino, fd->name, fd->ino); @@ -673,7 +655,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, } -int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen) +int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen, uint32_t time) { struct jffs2_raw_dirent *rd; struct jffs2_full_dirent *fd; @@ -684,12 +666,13 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint if (!rd) return -ENOMEM; - ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); + ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, + ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); if (ret) { jffs2_free_raw_dirent(rd); return ret; } - + down(&dir_f->sem); /* Build a deletion node */ @@ -701,7 +684,7 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint rd->pino = cpu_to_je32(dir_f->inocache->ino); rd->version = cpu_to_je32(++dir_f->highest_version); rd->ino = cpu_to_je32(ino); - rd->mctime = cpu_to_je32(get_seconds()); + rd->mctime = cpu_to_je32(time); rd->nsize = namelen; rd->type = type; @@ -710,7 +693,7 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint rd->name_crc = cpu_to_je32(crc32(0, name, namelen)); fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL); - + jffs2_free_raw_dirent(rd); if (IS_ERR(fd)) { diff --git a/fs/jffs2/writev.c b/fs/jffs2/writev.c index f079f83885663386703666df657a7466264ed5ff..c638ae1008de74bc022ecf4cb5faf1ef8de0b692 100644 --- a/fs/jffs2/writev.c +++ b/fs/jffs2/writev.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: writev.c,v 1.6 2004/11/16 20:36:12 dwmw2 Exp $ + * $Id: writev.c,v 1.8 2005/09/09 15:11:58 havasi Exp $ * */ @@ -42,9 +42,40 @@ static inline int mtd_fake_writev(struct mtd_info *mtd, const struct kvec *vecs, int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen) { + if (!jffs2_is_writebuffered(c)) { + if (jffs2_sum_active()) { + int res; + res = jffs2_sum_add_kvec(c, vecs, count, (uint32_t) to); + if (res) { + return res; + } + } + } + if (c->mtd->writev) return c->mtd->writev(c->mtd, vecs, count, to, retlen); - else + else { return mtd_fake_writev(c->mtd, vecs, count, to, retlen); + } } +int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, + size_t *retlen, const u_char *buf) +{ + int ret; + ret = c->mtd->write(c->mtd, ofs, len, retlen, buf); + + if (jffs2_sum_active()) { + struct kvec vecs[1]; + int res; + + vecs[0].iov_base = (unsigned char *) buf; + vecs[0].iov_len = len; + + res = jffs2_sum_add_kvec(c, vecs, 1, (uint32_t) ofs); + if (res) { + return res; + } + } + return ret; +} diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 87332f30141b621b7478f3faacfac6e4c226d991..c5a33648e9fd5b6d88e50c42f9252d48f87cc57d 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -112,8 +112,7 @@ static struct nlm_lockowner *nlm_find_lockowner(struct nlm_host *host, fl_owner_ } } spin_unlock(&host->h_lock); - if (new != NULL) - kfree(new); + kfree(new); return res; } diff --git a/fs/mbcache.c b/fs/mbcache.c index 298997f174755649a7b3ca5b72bb9e2613a53464..0f1e4530670f18567cc788b39af3ebbced8388ed 100644 --- a/fs/mbcache.c +++ b/fs/mbcache.c @@ -301,8 +301,7 @@ mb_cache_create(const char *name, struct mb_cache_op *cache_op, if (cache) { while (--m >= 0) kfree(cache->c_indexes_hash[m]); - if (cache->c_block_hash) - kfree(cache->c_block_hash); + kfree(cache->c_block_hash); kfree(cache); } return NULL; diff --git a/fs/namei.c b/fs/namei.c index c5769c4fcab185ea1996e947c5b910abfd155dd5..b3f8a1966c9cafe0113370bb5843a9b91b96758f 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1459,7 +1459,7 @@ int may_open(struct nameidata *nd, int acc_mode, int flag) if (!error) { DQUOT_INIT(inode); - error = do_truncate(dentry, 0); + error = do_truncate(dentry, 0, NULL); } put_write_access(inode); if (error) diff --git a/fs/namespace.c b/fs/namespace.c index 2fa9fdf7d6f573f1f6b004ab82d9a0945d9a6f9c..caa9187f67e5e639cba914edb10fabeb66016f7b 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -24,6 +24,7 @@ #include #include #include +#include "pnode.h" extern int __init init_rootfs(void); @@ -37,33 +38,39 @@ static inline int sysfs_init(void) #endif /* spinlock for vfsmount related operations, inplace of dcache_lock */ - __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); +__cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); + +static int event; static struct list_head *mount_hashtable; static int hash_mask __read_mostly, hash_bits __read_mostly; -static kmem_cache_t *mnt_cache; +static kmem_cache_t *mnt_cache; +static struct rw_semaphore namespace_sem; static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) { - unsigned long tmp = ((unsigned long) mnt / L1_CACHE_BYTES); - tmp += ((unsigned long) dentry / L1_CACHE_BYTES); + unsigned long tmp = ((unsigned long)mnt / L1_CACHE_BYTES); + tmp += ((unsigned long)dentry / L1_CACHE_BYTES); tmp = tmp + (tmp >> hash_bits); return tmp & hash_mask; } struct vfsmount *alloc_vfsmnt(const char *name) { - struct vfsmount *mnt = kmem_cache_alloc(mnt_cache, GFP_KERNEL); + struct vfsmount *mnt = kmem_cache_alloc(mnt_cache, GFP_KERNEL); if (mnt) { memset(mnt, 0, sizeof(struct vfsmount)); - atomic_set(&mnt->mnt_count,1); + atomic_set(&mnt->mnt_count, 1); INIT_LIST_HEAD(&mnt->mnt_hash); INIT_LIST_HEAD(&mnt->mnt_child); INIT_LIST_HEAD(&mnt->mnt_mounts); INIT_LIST_HEAD(&mnt->mnt_list); INIT_LIST_HEAD(&mnt->mnt_expire); + INIT_LIST_HEAD(&mnt->mnt_share); + INIT_LIST_HEAD(&mnt->mnt_slave_list); + INIT_LIST_HEAD(&mnt->mnt_slave); if (name) { - int size = strlen(name)+1; + int size = strlen(name) + 1; char *newname = kmalloc(size, GFP_KERNEL); if (newname) { memcpy(newname, name, size); @@ -81,36 +88,65 @@ void free_vfsmnt(struct vfsmount *mnt) } /* - * Now, lookup_mnt increments the ref count before returning - * the vfsmount struct. + * find the first or last mount at @dentry on vfsmount @mnt depending on + * @dir. If @dir is set return the first mount else return the last mount. */ -struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry) +struct vfsmount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry, + int dir) { - struct list_head * head = mount_hashtable + hash(mnt, dentry); - struct list_head * tmp = head; + struct list_head *head = mount_hashtable + hash(mnt, dentry); + struct list_head *tmp = head; struct vfsmount *p, *found = NULL; - spin_lock(&vfsmount_lock); for (;;) { - tmp = tmp->next; + tmp = dir ? tmp->next : tmp->prev; p = NULL; if (tmp == head) break; p = list_entry(tmp, struct vfsmount, mnt_hash); if (p->mnt_parent == mnt && p->mnt_mountpoint == dentry) { - found = mntget(p); + found = p; break; } } - spin_unlock(&vfsmount_lock); return found; } +/* + * lookup_mnt increments the ref count before returning + * the vfsmount struct. + */ +struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry) +{ + struct vfsmount *child_mnt; + spin_lock(&vfsmount_lock); + if ((child_mnt = __lookup_mnt(mnt, dentry, 1))) + mntget(child_mnt); + spin_unlock(&vfsmount_lock); + return child_mnt; +} + static inline int check_mnt(struct vfsmount *mnt) { return mnt->mnt_namespace == current->namespace; } +static void touch_namespace(struct namespace *ns) +{ + if (ns) { + ns->event = ++event; + wake_up_interruptible(&ns->poll); + } +} + +static void __touch_namespace(struct namespace *ns) +{ + if (ns && ns->event != event) { + ns->event = event; + wake_up_interruptible(&ns->poll); + } +} + static void detach_mnt(struct vfsmount *mnt, struct nameidata *old_nd) { old_nd->dentry = mnt->mnt_mountpoint; @@ -122,13 +158,43 @@ static void detach_mnt(struct vfsmount *mnt, struct nameidata *old_nd) old_nd->dentry->d_mounted--; } +void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry, + struct vfsmount *child_mnt) +{ + child_mnt->mnt_parent = mntget(mnt); + child_mnt->mnt_mountpoint = dget(dentry); + dentry->d_mounted++; +} + static void attach_mnt(struct vfsmount *mnt, struct nameidata *nd) { - mnt->mnt_parent = mntget(nd->mnt); - mnt->mnt_mountpoint = dget(nd->dentry); - list_add(&mnt->mnt_hash, mount_hashtable+hash(nd->mnt, nd->dentry)); + mnt_set_mountpoint(nd->mnt, nd->dentry, mnt); + list_add_tail(&mnt->mnt_hash, mount_hashtable + + hash(nd->mnt, nd->dentry)); list_add_tail(&mnt->mnt_child, &nd->mnt->mnt_mounts); - nd->dentry->d_mounted++; +} + +/* + * the caller must hold vfsmount_lock + */ +static void commit_tree(struct vfsmount *mnt) +{ + struct vfsmount *parent = mnt->mnt_parent; + struct vfsmount *m; + LIST_HEAD(head); + struct namespace *n = parent->mnt_namespace; + + BUG_ON(parent == mnt); + + list_add_tail(&head, &mnt->mnt_list); + list_for_each_entry(m, &head, mnt_list) + m->mnt_namespace = n; + list_splice(&head, n->list.prev); + + list_add_tail(&mnt->mnt_hash, mount_hashtable + + hash(parent, mnt->mnt_mountpoint)); + list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); + touch_namespace(n); } static struct vfsmount *next_mnt(struct vfsmount *p, struct vfsmount *root) @@ -147,8 +213,18 @@ static struct vfsmount *next_mnt(struct vfsmount *p, struct vfsmount *root) return list_entry(next, struct vfsmount, mnt_child); } -static struct vfsmount * -clone_mnt(struct vfsmount *old, struct dentry *root) +static struct vfsmount *skip_mnt_tree(struct vfsmount *p) +{ + struct list_head *prev = p->mnt_mounts.prev; + while (prev != &p->mnt_mounts) { + p = list_entry(prev, struct vfsmount, mnt_child); + prev = p->mnt_mounts.prev; + } + return p; +} + +static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root, + int flag) { struct super_block *sb = old->mnt_sb; struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname); @@ -160,19 +236,34 @@ clone_mnt(struct vfsmount *old, struct dentry *root) mnt->mnt_root = dget(root); mnt->mnt_mountpoint = mnt->mnt_root; mnt->mnt_parent = mnt; - mnt->mnt_namespace = current->namespace; + + if (flag & CL_SLAVE) { + list_add(&mnt->mnt_slave, &old->mnt_slave_list); + mnt->mnt_master = old; + CLEAR_MNT_SHARED(mnt); + } else { + if ((flag & CL_PROPAGATION) || IS_MNT_SHARED(old)) + list_add(&mnt->mnt_share, &old->mnt_share); + if (IS_MNT_SLAVE(old)) + list_add(&mnt->mnt_slave, &old->mnt_slave); + mnt->mnt_master = old->mnt_master; + } + if (flag & CL_MAKE_SHARED) + set_mnt_shared(mnt); /* stick the duplicate mount on the same expiry list * as the original if that was on one */ - spin_lock(&vfsmount_lock); - if (!list_empty(&old->mnt_expire)) - list_add(&mnt->mnt_expire, &old->mnt_expire); - spin_unlock(&vfsmount_lock); + if (flag & CL_EXPIRE) { + spin_lock(&vfsmount_lock); + if (!list_empty(&old->mnt_expire)) + list_add(&mnt->mnt_expire, &old->mnt_expire); + spin_unlock(&vfsmount_lock); + } } return mnt; } -void __mntput(struct vfsmount *mnt) +static inline void __mntput(struct vfsmount *mnt) { struct super_block *sb = mnt->mnt_sb; dput(mnt->mnt_root); @@ -180,7 +271,46 @@ void __mntput(struct vfsmount *mnt) deactivate_super(sb); } -EXPORT_SYMBOL(__mntput); +void mntput_no_expire(struct vfsmount *mnt) +{ +repeat: + if (atomic_dec_and_lock(&mnt->mnt_count, &vfsmount_lock)) { + if (likely(!mnt->mnt_pinned)) { + spin_unlock(&vfsmount_lock); + __mntput(mnt); + return; + } + atomic_add(mnt->mnt_pinned + 1, &mnt->mnt_count); + mnt->mnt_pinned = 0; + spin_unlock(&vfsmount_lock); + acct_auto_close_mnt(mnt); + security_sb_umount_close(mnt); + goto repeat; + } +} + +EXPORT_SYMBOL(mntput_no_expire); + +void mnt_pin(struct vfsmount *mnt) +{ + spin_lock(&vfsmount_lock); + mnt->mnt_pinned++; + spin_unlock(&vfsmount_lock); +} + +EXPORT_SYMBOL(mnt_pin); + +void mnt_unpin(struct vfsmount *mnt) +{ + spin_lock(&vfsmount_lock); + if (mnt->mnt_pinned) { + atomic_inc(&mnt->mnt_count); + mnt->mnt_pinned--; + } + spin_unlock(&vfsmount_lock); +} + +EXPORT_SYMBOL(mnt_unpin); /* iterator */ static void *m_start(struct seq_file *m, loff_t *pos) @@ -189,7 +319,7 @@ static void *m_start(struct seq_file *m, loff_t *pos) struct list_head *p; loff_t l = *pos; - down_read(&n->sem); + down_read(&namespace_sem); list_for_each(p, &n->list) if (!l--) return list_entry(p, struct vfsmount, mnt_list); @@ -201,13 +331,12 @@ static void *m_next(struct seq_file *m, void *v, loff_t *pos) struct namespace *n = m->private; struct list_head *p = ((struct vfsmount *)v)->mnt_list.next; (*pos)++; - return p==&n->list ? NULL : list_entry(p, struct vfsmount, mnt_list); + return p == &n->list ? NULL : list_entry(p, struct vfsmount, mnt_list); } static void m_stop(struct seq_file *m, void *v) { - struct namespace *n = m->private; - up_read(&n->sem); + up_read(&namespace_sem); } static inline void mangle(struct seq_file *m, const char *s) @@ -275,35 +404,14 @@ struct seq_operations mounts_op = { */ int may_umount_tree(struct vfsmount *mnt) { - struct list_head *next; - struct vfsmount *this_parent = mnt; - int actual_refs; - int minimum_refs; + int actual_refs = 0; + int minimum_refs = 0; + struct vfsmount *p; spin_lock(&vfsmount_lock); - actual_refs = atomic_read(&mnt->mnt_count); - minimum_refs = 2; -repeat: - next = this_parent->mnt_mounts.next; -resume: - while (next != &this_parent->mnt_mounts) { - struct vfsmount *p = list_entry(next, struct vfsmount, mnt_child); - - next = next->next; - + for (p = mnt; p; p = next_mnt(p, mnt)) { actual_refs += atomic_read(&p->mnt_count); minimum_refs += 2; - - if (!list_empty(&p->mnt_mounts)) { - this_parent = p; - goto repeat; - } - } - - if (this_parent != mnt) { - next = this_parent->mnt_child.next; - this_parent = this_parent->mnt_parent; - goto resume; } spin_unlock(&vfsmount_lock); @@ -330,45 +438,67 @@ EXPORT_SYMBOL(may_umount_tree); */ int may_umount(struct vfsmount *mnt) { - if (atomic_read(&mnt->mnt_count) > 2) - return -EBUSY; - return 0; + int ret = 0; + spin_lock(&vfsmount_lock); + if (propagate_mount_busy(mnt, 2)) + ret = -EBUSY; + spin_unlock(&vfsmount_lock); + return ret; } EXPORT_SYMBOL(may_umount); -static void umount_tree(struct vfsmount *mnt) +void release_mounts(struct list_head *head) +{ + struct vfsmount *mnt; + while(!list_empty(head)) { + mnt = list_entry(head->next, struct vfsmount, mnt_hash); + list_del_init(&mnt->mnt_hash); + if (mnt->mnt_parent != mnt) { + struct dentry *dentry; + struct vfsmount *m; + spin_lock(&vfsmount_lock); + dentry = mnt->mnt_mountpoint; + m = mnt->mnt_parent; + mnt->mnt_mountpoint = mnt->mnt_root; + mnt->mnt_parent = mnt; + spin_unlock(&vfsmount_lock); + dput(dentry); + mntput(m); + } + mntput(mnt); + } +} + +void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) { struct vfsmount *p; - LIST_HEAD(kill); for (p = mnt; p; p = next_mnt(p, mnt)) { - list_del(&p->mnt_list); - list_add(&p->mnt_list, &kill); - p->mnt_namespace = NULL; + list_del(&p->mnt_hash); + list_add(&p->mnt_hash, kill); } - while (!list_empty(&kill)) { - mnt = list_entry(kill.next, struct vfsmount, mnt_list); - list_del_init(&mnt->mnt_list); - list_del_init(&mnt->mnt_expire); - if (mnt->mnt_parent == mnt) { - spin_unlock(&vfsmount_lock); - } else { - struct nameidata old_nd; - detach_mnt(mnt, &old_nd); - spin_unlock(&vfsmount_lock); - path_release(&old_nd); - } - mntput(mnt); - spin_lock(&vfsmount_lock); + if (propagate) + propagate_umount(kill); + + list_for_each_entry(p, kill, mnt_hash) { + list_del_init(&p->mnt_expire); + list_del_init(&p->mnt_list); + __touch_namespace(p->mnt_namespace); + p->mnt_namespace = NULL; + list_del_init(&p->mnt_child); + if (p->mnt_parent != p) + mnt->mnt_mountpoint->d_mounted--; + change_mnt_propagation(p, MS_PRIVATE); } } static int do_umount(struct vfsmount *mnt, int flags) { - struct super_block * sb = mnt->mnt_sb; + struct super_block *sb = mnt->mnt_sb; int retval; + LIST_HEAD(umount_list); retval = security_sb_umount(mnt, flags); if (retval) @@ -403,7 +533,7 @@ static int do_umount(struct vfsmount *mnt, int flags) */ lock_kernel(); - if( (flags&MNT_FORCE) && sb->s_op->umount_begin) + if ((flags & MNT_FORCE) && sb->s_op->umount_begin) sb->s_op->umount_begin(sb); unlock_kernel(); @@ -432,29 +562,21 @@ static int do_umount(struct vfsmount *mnt, int flags) return retval; } - down_write(¤t->namespace->sem); + down_write(&namespace_sem); spin_lock(&vfsmount_lock); + event++; - if (atomic_read(&sb->s_active) == 1) { - /* last instance - try to be smart */ - spin_unlock(&vfsmount_lock); - lock_kernel(); - DQUOT_OFF(sb); - acct_auto_close(sb); - unlock_kernel(); - security_sb_umount_close(mnt); - spin_lock(&vfsmount_lock); - } retval = -EBUSY; - if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) { + if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) { if (!list_empty(&mnt->mnt_list)) - umount_tree(mnt); + umount_tree(mnt, 1, &umount_list); retval = 0; } spin_unlock(&vfsmount_lock); if (retval) security_sb_umount_busy(mnt); - up_write(¤t->namespace->sem); + up_write(&namespace_sem); + release_mounts(&umount_list); return retval; } @@ -494,12 +616,11 @@ asmlinkage long sys_umount(char __user * name, int flags) #ifdef __ARCH_WANT_SYS_OLDUMOUNT /* - * The 2.0 compatible umount. No flags. + * The 2.0 compatible umount. No flags. */ - asmlinkage long sys_oldumount(char __user * name) { - return sys_umount(name,0); + return sys_umount(name, 0); } #endif @@ -522,8 +643,7 @@ static int mount_is_safe(struct nameidata *nd) #endif } -static int -lives_below_in_same_fs(struct dentry *d, struct dentry *dentry) +static int lives_below_in_same_fs(struct dentry *d, struct dentry *dentry) { while (1) { if (d == dentry) @@ -534,12 +654,16 @@ lives_below_in_same_fs(struct dentry *d, struct dentry *dentry) } } -static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry) +struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry, + int flag) { struct vfsmount *res, *p, *q, *r, *s; struct nameidata nd; - res = q = clone_mnt(mnt, dentry); + if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(mnt)) + return NULL; + + res = q = clone_mnt(mnt, dentry, flag); if (!q) goto Enomem; q->mnt_mountpoint = mnt->mnt_mountpoint; @@ -550,6 +674,10 @@ static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry) continue; for (s = r; s; s = next_mnt(s, r)) { + if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(s)) { + s = skip_mnt_tree(s); + continue; + } while (p != s->mnt_parent) { p = p->mnt_parent; q = q->mnt_parent; @@ -557,7 +685,7 @@ static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry) p = s; nd.mnt = q; nd.dentry = p->mnt_mountpoint; - q = clone_mnt(p, p->mnt_root); + q = clone_mnt(p, p->mnt_root, flag); if (!q) goto Enomem; spin_lock(&vfsmount_lock); @@ -567,15 +695,114 @@ static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry) } } return res; - Enomem: +Enomem: if (res) { + LIST_HEAD(umount_list); spin_lock(&vfsmount_lock); - umount_tree(res); + umount_tree(res, 0, &umount_list); spin_unlock(&vfsmount_lock); + release_mounts(&umount_list); } return NULL; } +/* + * @source_mnt : mount tree to be attached + * @nd : place the mount tree @source_mnt is attached + * @parent_nd : if non-null, detach the source_mnt from its parent and + * store the parent mount and mountpoint dentry. + * (done when source_mnt is moved) + * + * NOTE: in the table below explains the semantics when a source mount + * of a given type is attached to a destination mount of a given type. + * --------------------------------------------------------------------------- + * | BIND MOUNT OPERATION | + * |************************************************************************** + * | source-->| shared | private | slave | unbindable | + * | dest | | | | | + * | | | | | | | + * | v | | | | | + * |************************************************************************** + * | shared | shared (++) | shared (+) | shared(+++)| invalid | + * | | | | | | + * |non-shared| shared (+) | private | slave (*) | invalid | + * *************************************************************************** + * A bind operation clones the source mount and mounts the clone on the + * destination mount. + * + * (++) the cloned mount is propagated to all the mounts in the propagation + * tree of the destination mount and the cloned mount is added to + * the peer group of the source mount. + * (+) the cloned mount is created under the destination mount and is marked + * as shared. The cloned mount is added to the peer group of the source + * mount. + * (+++) the mount is propagated to all the mounts in the propagation tree + * of the destination mount and the cloned mount is made slave + * of the same master as that of the source mount. The cloned mount + * is marked as 'shared and slave'. + * (*) the cloned mount is made a slave of the same master as that of the + * source mount. + * + * --------------------------------------------------------------------------- + * | MOVE MOUNT OPERATION | + * |************************************************************************** + * | source-->| shared | private | slave | unbindable | + * | dest | | | | | + * | | | | | | | + * | v | | | | | + * |************************************************************************** + * | shared | shared (+) | shared (+) | shared(+++) | invalid | + * | | | | | | + * |non-shared| shared (+*) | private | slave (*) | unbindable | + * *************************************************************************** + * + * (+) the mount is moved to the destination. And is then propagated to + * all the mounts in the propagation tree of the destination mount. + * (+*) the mount is moved to the destination. + * (+++) the mount is moved to the destination and is then propagated to + * all the mounts belonging to the destination mount's propagation tree. + * the mount is marked as 'shared and slave'. + * (*) the mount continues to be a slave at the new location. + * + * if the source mount is a tree, the operations explained above is + * applied to each mount in the tree. + * Must be called without spinlocks held, since this function can sleep + * in allocations. + */ +static int attach_recursive_mnt(struct vfsmount *source_mnt, + struct nameidata *nd, struct nameidata *parent_nd) +{ + LIST_HEAD(tree_list); + struct vfsmount *dest_mnt = nd->mnt; + struct dentry *dest_dentry = nd->dentry; + struct vfsmount *child, *p; + + if (propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list)) + return -EINVAL; + + if (IS_MNT_SHARED(dest_mnt)) { + for (p = source_mnt; p; p = next_mnt(p, source_mnt)) + set_mnt_shared(p); + } + + spin_lock(&vfsmount_lock); + if (parent_nd) { + detach_mnt(source_mnt, parent_nd); + attach_mnt(source_mnt, nd); + touch_namespace(current->namespace); + } else { + mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt); + commit_tree(source_mnt); + } + + list_for_each_entry_safe(child, p, &tree_list, mnt_hash) { + list_del_init(&child->mnt_hash); + commit_tree(child); + } + spin_unlock(&vfsmount_lock); + return 0; +} + static int graft_tree(struct vfsmount *mnt, struct nameidata *nd) { int err; @@ -596,17 +823,8 @@ static int graft_tree(struct vfsmount *mnt, struct nameidata *nd) goto out_unlock; err = -ENOENT; - spin_lock(&vfsmount_lock); - if (IS_ROOT(nd->dentry) || !d_unhashed(nd->dentry)) { - struct list_head head; - - attach_mnt(mnt, nd); - list_add_tail(&head, &mnt->mnt_list); - list_splice(&head, current->namespace->list.prev); - mntget(mnt); - err = 0; - } - spin_unlock(&vfsmount_lock); + if (IS_ROOT(nd->dentry) || !d_unhashed(nd->dentry)) + err = attach_recursive_mnt(mnt, nd, NULL); out_unlock: up(&nd->dentry->d_inode->i_sem); if (!err) @@ -614,6 +832,27 @@ static int graft_tree(struct vfsmount *mnt, struct nameidata *nd) return err; } +/* + * recursively change the type of the mountpoint. + */ +static int do_change_type(struct nameidata *nd, int flag) +{ + struct vfsmount *m, *mnt = nd->mnt; + int recurse = flag & MS_REC; + int type = flag & ~MS_REC; + + if (nd->dentry != nd->mnt->mnt_root) + return -EINVAL; + + down_write(&namespace_sem); + spin_lock(&vfsmount_lock); + for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL)) + change_mnt_propagation(m, type); + spin_unlock(&vfsmount_lock); + up_write(&namespace_sem); + return 0; +} + /* * do loopback mount. */ @@ -630,32 +869,34 @@ static int do_loopback(struct nameidata *nd, char *old_name, int recurse) if (err) return err; - down_write(¤t->namespace->sem); + down_write(&namespace_sem); err = -EINVAL; - if (check_mnt(nd->mnt) && (!recurse || check_mnt(old_nd.mnt))) { - err = -ENOMEM; - if (recurse) - mnt = copy_tree(old_nd.mnt, old_nd.dentry); - else - mnt = clone_mnt(old_nd.mnt, old_nd.dentry); - } + if (IS_MNT_UNBINDABLE(old_nd.mnt)) + goto out; - if (mnt) { - /* stop bind mounts from expiring */ + if (!check_mnt(nd->mnt) || !check_mnt(old_nd.mnt)) + goto out; + + err = -ENOMEM; + if (recurse) + mnt = copy_tree(old_nd.mnt, old_nd.dentry, 0); + else + mnt = clone_mnt(old_nd.mnt, old_nd.dentry, 0); + + if (!mnt) + goto out; + + err = graft_tree(mnt, nd); + if (err) { + LIST_HEAD(umount_list); spin_lock(&vfsmount_lock); - list_del_init(&mnt->mnt_expire); + umount_tree(mnt, 0, &umount_list); spin_unlock(&vfsmount_lock); - - err = graft_tree(mnt, nd); - if (err) { - spin_lock(&vfsmount_lock); - umount_tree(mnt); - spin_unlock(&vfsmount_lock); - } else - mntput(mnt); + release_mounts(&umount_list); } - up_write(¤t->namespace->sem); +out: + up_write(&namespace_sem); path_release(&old_nd); return err; } @@ -665,12 +906,11 @@ static int do_loopback(struct nameidata *nd, char *old_name, int recurse) * If you've mounted a non-root directory somewhere and want to do remount * on it - tough luck. */ - static int do_remount(struct nameidata *nd, int flags, int mnt_flags, void *data) { int err; - struct super_block * sb = nd->mnt->mnt_sb; + struct super_block *sb = nd->mnt->mnt_sb; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -684,13 +924,23 @@ static int do_remount(struct nameidata *nd, int flags, int mnt_flags, down_write(&sb->s_umount); err = do_remount_sb(sb, flags, data, 0); if (!err) - nd->mnt->mnt_flags=mnt_flags; + nd->mnt->mnt_flags = mnt_flags; up_write(&sb->s_umount); if (!err) security_sb_post_remount(nd->mnt, flags, data); return err; } +static inline int tree_contains_unbindable(struct vfsmount *mnt) +{ + struct vfsmount *p; + for (p = mnt; p; p = next_mnt(p, mnt)) { + if (IS_MNT_UNBINDABLE(p)) + return 1; + } + return 0; +} + static int do_move_mount(struct nameidata *nd, char *old_name) { struct nameidata old_nd, parent_nd; @@ -704,8 +954,8 @@ static int do_move_mount(struct nameidata *nd, char *old_name) if (err) return err; - down_write(¤t->namespace->sem); - while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry)) + down_write(&namespace_sem); + while (d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry)) ; err = -EINVAL; if (!check_mnt(nd->mnt) || !check_mnt(old_nd.mnt)) @@ -716,39 +966,47 @@ static int do_move_mount(struct nameidata *nd, char *old_name) if (IS_DEADDIR(nd->dentry->d_inode)) goto out1; - spin_lock(&vfsmount_lock); if (!IS_ROOT(nd->dentry) && d_unhashed(nd->dentry)) - goto out2; + goto out1; err = -EINVAL; if (old_nd.dentry != old_nd.mnt->mnt_root) - goto out2; + goto out1; if (old_nd.mnt == old_nd.mnt->mnt_parent) - goto out2; + goto out1; if (S_ISDIR(nd->dentry->d_inode->i_mode) != S_ISDIR(old_nd.dentry->d_inode->i_mode)) - goto out2; - + goto out1; + /* + * Don't move a mount residing in a shared parent. + */ + if (old_nd.mnt->mnt_parent && IS_MNT_SHARED(old_nd.mnt->mnt_parent)) + goto out1; + /* + * Don't move a mount tree containing unbindable mounts to a destination + * mount which is shared. + */ + if (IS_MNT_SHARED(nd->mnt) && tree_contains_unbindable(old_nd.mnt)) + goto out1; err = -ELOOP; - for (p = nd->mnt; p->mnt_parent!=p; p = p->mnt_parent) + for (p = nd->mnt; p->mnt_parent != p; p = p->mnt_parent) if (p == old_nd.mnt) - goto out2; - err = 0; + goto out1; - detach_mnt(old_nd.mnt, &parent_nd); - attach_mnt(old_nd.mnt, nd); + if ((err = attach_recursive_mnt(old_nd.mnt, nd, &parent_nd))) + goto out1; + spin_lock(&vfsmount_lock); /* if the mount is moved, it should no longer be expire * automatically */ list_del_init(&old_nd.mnt->mnt_expire); -out2: spin_unlock(&vfsmount_lock); out1: up(&nd->dentry->d_inode->i_sem); out: - up_write(¤t->namespace->sem); + up_write(&namespace_sem); if (!err) path_release(&parent_nd); path_release(&old_nd); @@ -787,9 +1045,9 @@ int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd, { int err; - down_write(¤t->namespace->sem); + down_write(&namespace_sem); /* Something was mounted here while we slept */ - while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry)) + while (d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry)) ; err = -EINVAL; if (!check_mnt(nd->mnt)) @@ -806,25 +1064,28 @@ int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd, goto unlock; newmnt->mnt_flags = mnt_flags; - newmnt->mnt_namespace = current->namespace; - err = graft_tree(newmnt, nd); + if ((err = graft_tree(newmnt, nd))) + goto unlock; - if (err == 0 && fslist) { + if (fslist) { /* add to the specified expiration list */ spin_lock(&vfsmount_lock); list_add_tail(&newmnt->mnt_expire, fslist); spin_unlock(&vfsmount_lock); } + up_write(&namespace_sem); + return 0; unlock: - up_write(¤t->namespace->sem); + up_write(&namespace_sem); mntput(newmnt); return err; } EXPORT_SYMBOL_GPL(do_add_mount); -static void expire_mount(struct vfsmount *mnt, struct list_head *mounts) +static void expire_mount(struct vfsmount *mnt, struct list_head *mounts, + struct list_head *umounts) { spin_lock(&vfsmount_lock); @@ -841,27 +1102,13 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts) * Check that it is still dead: the count should now be 2 - as * contributed by the vfsmount parent and the mntget above */ - if (atomic_read(&mnt->mnt_count) == 2) { - struct nameidata old_nd; - + if (!propagate_mount_busy(mnt, 2)) { /* delete from the namespace */ + touch_namespace(mnt->mnt_namespace); list_del_init(&mnt->mnt_list); mnt->mnt_namespace = NULL; - detach_mnt(mnt, &old_nd); + umount_tree(mnt, 1, umounts); spin_unlock(&vfsmount_lock); - path_release(&old_nd); - - /* - * Now lay it to rest if this was the last ref on the superblock - */ - if (atomic_read(&mnt->mnt_sb->s_active) == 1) { - /* last instance - try to be smart */ - lock_kernel(); - DQUOT_OFF(mnt->mnt_sb); - acct_auto_close(mnt->mnt_sb); - unlock_kernel(); - } - mntput(mnt); } else { /* * Someone brought it back to life whilst we didn't have any @@ -910,6 +1157,7 @@ void mark_mounts_for_expiry(struct list_head *mounts) * - dispose of the corpse */ while (!list_empty(&graveyard)) { + LIST_HEAD(umounts); mnt = list_entry(graveyard.next, struct vfsmount, mnt_expire); list_del_init(&mnt->mnt_expire); @@ -921,13 +1169,12 @@ void mark_mounts_for_expiry(struct list_head *mounts) get_namespace(namespace); spin_unlock(&vfsmount_lock); - down_write(&namespace->sem); - expire_mount(mnt, mounts); - up_write(&namespace->sem); - + down_write(&namespace_sem); + expire_mount(mnt, mounts, &umounts); + up_write(&namespace_sem); + release_mounts(&umounts); mntput(mnt); put_namespace(namespace); - spin_lock(&vfsmount_lock); } @@ -942,8 +1189,8 @@ EXPORT_SYMBOL_GPL(mark_mounts_for_expiry); * Note that this function differs from copy_from_user() in that it will oops * on bad values of `to', rather than returning a short copy. */ -static long -exact_copy_from_user(void *to, const void __user *from, unsigned long n) +static long exact_copy_from_user(void *to, const void __user * from, + unsigned long n) { char *t = to; const char __user *f = from; @@ -964,12 +1211,12 @@ exact_copy_from_user(void *to, const void __user *from, unsigned long n) return n; } -int copy_mount_options(const void __user *data, unsigned long *where) +int copy_mount_options(const void __user * data, unsigned long *where) { int i; unsigned long page; unsigned long size; - + *where = 0; if (!data) return 0; @@ -988,7 +1235,7 @@ int copy_mount_options(const void __user *data, unsigned long *where) i = size - exact_copy_from_user((void *)page, data, size); if (!i) { - free_page(page); + free_page(page); return -EFAULT; } if (i != PAGE_SIZE) @@ -1011,7 +1258,7 @@ int copy_mount_options(const void __user *data, unsigned long *where) * Therefore, if this magic number is present, it carries no information * and must be discarded. */ -long do_mount(char * dev_name, char * dir_name, char *type_page, +long do_mount(char *dev_name, char *dir_name, char *type_page, unsigned long flags, void *data_page) { struct nameidata nd; @@ -1039,7 +1286,7 @@ long do_mount(char * dev_name, char * dir_name, char *type_page, mnt_flags |= MNT_NODEV; if (flags & MS_NOEXEC) mnt_flags |= MNT_NOEXEC; - flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_ACTIVE); + flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE); /* ... and get the mountpoint */ retval = path_lookup(dir_name, LOOKUP_FOLLOW, &nd); @@ -1055,6 +1302,8 @@ long do_mount(char * dev_name, char * dir_name, char *type_page, data_page); else if (flags & MS_BIND) retval = do_loopback(&nd, dev_name, flags & MS_REC); + else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) + retval = do_change_type(&nd, flags); else if (flags & MS_MOVE) retval = do_move_mount(&nd, dev_name); else @@ -1091,14 +1340,16 @@ int copy_namespace(int flags, struct task_struct *tsk) goto out; atomic_set(&new_ns->count, 1); - init_rwsem(&new_ns->sem); INIT_LIST_HEAD(&new_ns->list); + init_waitqueue_head(&new_ns->poll); + new_ns->event = 0; - down_write(&tsk->namespace->sem); + down_write(&namespace_sem); /* First pass: copy the tree topology */ - new_ns->root = copy_tree(namespace->root, namespace->root->mnt_root); + new_ns->root = copy_tree(namespace->root, namespace->root->mnt_root, + CL_COPY_ALL | CL_EXPIRE); if (!new_ns->root) { - up_write(&tsk->namespace->sem); + up_write(&namespace_sem); kfree(new_ns); goto out; } @@ -1132,7 +1383,7 @@ int copy_namespace(int flags, struct task_struct *tsk) p = next_mnt(p, namespace->root); q = next_mnt(q, new_ns->root); } - up_write(&tsk->namespace->sem); + up_write(&namespace_sem); tsk->namespace = new_ns; @@ -1161,7 +1412,7 @@ asmlinkage long sys_mount(char __user * dev_name, char __user * dir_name, unsigned long dev_page; char *dir_page; - retval = copy_mount_options (type, &type_page); + retval = copy_mount_options(type, &type_page); if (retval < 0) return retval; @@ -1170,17 +1421,17 @@ asmlinkage long sys_mount(char __user * dev_name, char __user * dir_name, if (IS_ERR(dir_page)) goto out1; - retval = copy_mount_options (dev_name, &dev_page); + retval = copy_mount_options(dev_name, &dev_page); if (retval < 0) goto out2; - retval = copy_mount_options (data, &data_page); + retval = copy_mount_options(data, &data_page); if (retval < 0) goto out3; lock_kernel(); - retval = do_mount((char*)dev_page, dir_page, (char*)type_page, - flags, (void*)data_page); + retval = do_mount((char *)dev_page, dir_page, (char *)type_page, + flags, (void *)data_page); unlock_kernel(); free_page(data_page); @@ -1249,9 +1500,11 @@ static void chroot_fs_refs(struct nameidata *old_nd, struct nameidata *new_nd) if (fs) { atomic_inc(&fs->count); task_unlock(p); - if (fs->root==old_nd->dentry&&fs->rootmnt==old_nd->mnt) + if (fs->root == old_nd->dentry + && fs->rootmnt == old_nd->mnt) set_fs_root(fs, new_nd->mnt, new_nd->dentry); - if (fs->pwd==old_nd->dentry&&fs->pwdmnt==old_nd->mnt) + if (fs->pwd == old_nd->dentry + && fs->pwdmnt == old_nd->mnt) set_fs_pwd(fs, new_nd->mnt, new_nd->dentry); put_fs_struct(fs); } else @@ -1281,8 +1534,8 @@ static void chroot_fs_refs(struct nameidata *old_nd, struct nameidata *new_nd) * though, so you may need to say mount --bind /nfs/my_root /nfs/my_root * first. */ - -asmlinkage long sys_pivot_root(const char __user *new_root, const char __user *put_old) +asmlinkage long sys_pivot_root(const char __user * new_root, + const char __user * put_old) { struct vfsmount *tmp; struct nameidata new_nd, old_nd, parent_nd, root_parent, user_nd; @@ -1293,14 +1546,15 @@ asmlinkage long sys_pivot_root(const char __user *new_root, const char __user *p lock_kernel(); - error = __user_walk(new_root, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &new_nd); + error = __user_walk(new_root, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, + &new_nd); if (error) goto out0; error = -EINVAL; if (!check_mnt(new_nd.mnt)) goto out1; - error = __user_walk(put_old, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &old_nd); + error = __user_walk(put_old, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &old_nd); if (error) goto out1; @@ -1314,9 +1568,13 @@ asmlinkage long sys_pivot_root(const char __user *new_root, const char __user *p user_nd.mnt = mntget(current->fs->rootmnt); user_nd.dentry = dget(current->fs->root); read_unlock(¤t->fs->lock); - down_write(¤t->namespace->sem); + down_write(&namespace_sem); down(&old_nd.dentry->d_inode->i_sem); error = -EINVAL; + if (IS_MNT_SHARED(old_nd.mnt) || + IS_MNT_SHARED(new_nd.mnt->mnt_parent) || + IS_MNT_SHARED(user_nd.mnt->mnt_parent)) + goto out2; if (!check_mnt(user_nd.mnt)) goto out2; error = -ENOENT; @@ -1356,6 +1614,7 @@ asmlinkage long sys_pivot_root(const char __user *new_root, const char __user *p detach_mnt(user_nd.mnt, &root_parent); attach_mnt(user_nd.mnt, &old_nd); /* mount old root on put_old */ attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */ + touch_namespace(current->namespace); spin_unlock(&vfsmount_lock); chroot_fs_refs(&user_nd, &new_nd); security_sb_post_pivotroot(&user_nd, &new_nd); @@ -1364,7 +1623,7 @@ asmlinkage long sys_pivot_root(const char __user *new_root, const char __user *p path_release(&parent_nd); out2: up(&old_nd.dentry->d_inode->i_sem); - up_write(¤t->namespace->sem); + up_write(&namespace_sem); path_release(&user_nd); path_release(&old_nd); out1: @@ -1391,7 +1650,8 @@ static void __init init_mount_tree(void) panic("Can't allocate initial namespace"); atomic_set(&namespace->count, 1); INIT_LIST_HEAD(&namespace->list); - init_rwsem(&namespace->sem); + init_waitqueue_head(&namespace->poll); + namespace->event = 0; list_add(&mnt->mnt_list, &namespace->list); namespace->root = mnt; mnt->mnt_namespace = namespace; @@ -1414,11 +1674,12 @@ void __init mnt_init(unsigned long mempages) unsigned int nr_hash; int i; + init_rwsem(&namespace_sem); + mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct vfsmount), - 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); + 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL, NULL); - mount_hashtable = (struct list_head *) - __get_free_page(GFP_ATOMIC); + mount_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC); if (!mount_hashtable) panic("Failed to allocate mount hash table\n"); @@ -1440,7 +1701,7 @@ void __init mnt_init(unsigned long mempages) * from the number of bits we can fit. */ nr_hash = 1UL << hash_bits; - hash_mask = nr_hash-1; + hash_mask = nr_hash - 1; printk("Mount-cache hash table entries: %d\n", nr_hash); @@ -1460,12 +1721,14 @@ void __init mnt_init(unsigned long mempages) void __put_namespace(struct namespace *namespace) { struct vfsmount *root = namespace->root; + LIST_HEAD(umount_list); namespace->root = NULL; spin_unlock(&vfsmount_lock); - down_write(&namespace->sem); + down_write(&namespace_sem); spin_lock(&vfsmount_lock); - umount_tree(root); + umount_tree(root, 0, &umount_list); spin_unlock(&vfsmount_lock); - up_write(&namespace->sem); + up_write(&namespace_sem); + release_mounts(&umount_list); kfree(namespace); } diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 3976c177a7d0ed25b87dbf6e26014f25027a3cb7..618a327027b3a1215e6d0cfd720d7d1813e18c88 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -149,8 +149,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct } } spin_unlock(&clp->cl_lock); - if (delegation != NULL) - kfree(delegation); + kfree(delegation); return status; } diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 24d2fbf549bda5ee2f468fd3278e1695958270ac..6391d89642144366591df7e7c0e6733b12916899 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1688,8 +1688,7 @@ static void nfs_kill_super(struct super_block *s) rpciod_down(); /* release rpciod */ - if (server->hostname != NULL) - kfree(server->hostname); + kfree(server->hostname); kfree(server); } @@ -1908,8 +1907,7 @@ nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen) return ERR_PTR(-ENOMEM); } if (copy_from_user(dst, src->data, maxlen)) { - if (p != NULL) - kfree(p); + kfree(p); return ERR_PTR(-EFAULT); } dst[maxlen] = '\0'; @@ -2000,10 +1998,8 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, out_err: s = (struct super_block *)p; out_free: - if (server->mnt_path) - kfree(server->mnt_path); - if (server->hostname) - kfree(server->hostname); + kfree(server->mnt_path); + kfree(server->hostname); kfree(server); return s; } @@ -2023,8 +2019,7 @@ static void nfs4_kill_super(struct super_block *sb) destroy_nfsv4_state(server); - if (server->hostname != NULL) - kfree(server->hostname); + kfree(server->hostname); kfree(server); } diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 52a26baa114c2110bd196b40ac5116a547570130..0675f3215e0a4fb7512f4950b007dfcb98420489 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -69,10 +69,8 @@ init_nfsv4_state(struct nfs_server *server) void destroy_nfsv4_state(struct nfs_server *server) { - if (server->mnt_path) { - kfree(server->mnt_path); - server->mnt_path = NULL; - } + kfree(server->mnt_path); + server->mnt_path = NULL; if (server->nfs4_state) { nfs4_put_client(server->nfs4_state); server->nfs4_state = NULL; @@ -311,8 +309,7 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct new = NULL; } spin_unlock(&clp->cl_lock); - if (new) - kfree(new); + kfree(new); if (sp != NULL) return sp; put_rpccred(cred); diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index f732541a33329fa2886ad2b56101704f62146cab..d639d172d568fac861124a4e43c8d8f946741438 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -52,8 +52,7 @@ nfs_put_unlinkdata(struct nfs_unlinkdata *data) { if (--data->count == 0) { nfs_detach_unlinkdata(data); - if (data->name.name != NULL) - kfree(data->name.name); + kfree(data->name.name); kfree(data); } } diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 057aff745506da64d5ca6b61d00f0eb41c597029..417ec02df44f33145504eabd72c940ea6efb3662 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -190,8 +190,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) out: if (dom) auth_domain_put(dom); - if (buf) - kfree(buf); + kfree(buf); return err; } @@ -428,8 +427,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) path_release(&nd); if (dom) auth_domain_put(dom); - if (buf) - kfree(buf); + kfree(buf); return err; } diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index e0e134d6baba0013af5918f0dd0a4f9c3405b246..9147b8524d05262bd9f28b77c0e7636854367f09 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -366,7 +366,8 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p, len = args->len = ntohl(*p++); hdr = (void*)p - rqstp->rq_arg.head[0].iov_base; - if (rqstp->rq_arg.len < len + hdr) + if (rqstp->rq_arg.len < hdr || + rqstp->rq_arg.len - hdr < len) return 0; args->vec[0].iov_base = (void*)p; diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 4c4146350236be796c83072bd01e3913e344db71..dcd673186944a22f48317c3ecf52e889d1357b86 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -151,8 +151,7 @@ static u32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes) if (nbytes <= sizeof(argp->tmp)) p = argp->tmp; else { - if (argp->tmpp) - kfree(argp->tmpp); + kfree(argp->tmpp); p = argp->tmpp = kmalloc(nbytes, GFP_KERNEL); if (!p) return NULL; @@ -2476,10 +2475,8 @@ void nfsd4_release_compoundargs(struct nfsd4_compoundargs *args) kfree(args->ops); args->ops = args->iops; } - if (args->tmpp) { - kfree(args->tmpp); - args->tmpp = NULL; - } + kfree(args->tmpp); + args->tmpp = NULL; while (args->to_free) { struct tmpbuf *tb = args->to_free; args->to_free = tb->next; diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index 119e4d4495b8909f41555d6f40386d4663f4207a..d852ebb538e397b83e90aa504a105dcbc50ba98f 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c @@ -93,8 +93,7 @@ nfsd_cache_shutdown(void) cache_disabled = 1; - if (hash_list) - kfree (hash_list); + kfree (hash_list); hash_list = NULL; } diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 841c562991e8fdb051b12d18a3a8c88c1f528e16..a0871b3efeb7e35f1c80608ec3dd871d9e663d3f 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -35,6 +36,8 @@ #include +unsigned int nfsd_versbits = ~0; + /* * We have a single directory with 9 nodes in it. */ @@ -50,8 +53,15 @@ enum { NFSD_List, NFSD_Fh, NFSD_Threads, + NFSD_Versions, + /* + * The below MUST come last. Otherwise we leave a hole in nfsd_files[] + * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops + */ +#ifdef CONFIG_NFSD_V4 NFSD_Leasetime, NFSD_RecoveryDir, +#endif }; /* @@ -66,8 +76,11 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size); static ssize_t write_getfs(struct file *file, char *buf, size_t size); static ssize_t write_filehandle(struct file *file, char *buf, size_t size); static ssize_t write_threads(struct file *file, char *buf, size_t size); +static ssize_t write_versions(struct file *file, char *buf, size_t size); +#ifdef CONFIG_NFSD_V4 static ssize_t write_leasetime(struct file *file, char *buf, size_t size); static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); +#endif static ssize_t (*write_op[])(struct file *, char *, size_t) = { [NFSD_Svc] = write_svc, @@ -79,8 +92,11 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = { [NFSD_Getfs] = write_getfs, [NFSD_Fh] = write_filehandle, [NFSD_Threads] = write_threads, + [NFSD_Versions] = write_versions, +#ifdef CONFIG_NFSD_V4 [NFSD_Leasetime] = write_leasetime, [NFSD_RecoveryDir] = write_recoverydir, +#endif }; static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) @@ -104,9 +120,23 @@ static ssize_t nfsctl_transaction_write(struct file *file, const char __user *bu return rv; } +static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos) +{ + if (! file->private_data) { + /* An attempt to read a transaction file without writing + * causes a 0-byte write so that the file can return + * state information + */ + ssize_t rv = nfsctl_transaction_write(file, buf, 0, pos); + if (rv < 0) + return rv; + } + return simple_transaction_read(file, buf, size, pos); +} + static struct file_operations transaction_ops = { .write = nfsctl_transaction_write, - .read = simple_transaction_read, + .read = nfsctl_transaction_read, .release = simple_transaction_release, }; @@ -329,6 +359,70 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size) return strlen(buf); } +static ssize_t write_versions(struct file *file, char *buf, size_t size) +{ + /* + * Format: + * [-/+]vers [-/+]vers ... + */ + char *mesg = buf; + char *vers, sign; + int len, num; + ssize_t tlen = 0; + char *sep; + + if (size>0) { + if (nfsd_serv) + return -EBUSY; + if (buf[size-1] != '\n') + return -EINVAL; + buf[size-1] = 0; + + vers = mesg; + len = qword_get(&mesg, vers, size); + if (len <= 0) return -EINVAL; + do { + sign = *vers; + if (sign == '+' || sign == '-') + num = simple_strtol((vers+1), NULL, 0); + else + num = simple_strtol(vers, NULL, 0); + switch(num) { + case 2: + case 3: + case 4: + if (sign != '-') + NFSCTL_VERSET(nfsd_versbits, num); + else + NFSCTL_VERUNSET(nfsd_versbits, num); + break; + default: + return -EINVAL; + } + vers += len + 1; + tlen += len; + } while ((len = qword_get(&mesg, vers, size)) > 0); + /* If all get turned off, turn them back on, as + * having no versions is BAD + */ + if ((nfsd_versbits & NFSCTL_VERALL)==0) + nfsd_versbits = NFSCTL_VERALL; + } + /* Now write current state into reply buffer */ + len = 0; + sep = ""; + for (num=2 ; num <= 4 ; num++) + if (NFSCTL_VERISSET(NFSCTL_VERALL, num)) { + len += sprintf(buf+len, "%s%c%d", sep, + NFSCTL_VERISSET(nfsd_versbits, num)?'+':'-', + num); + sep = " "; + } + len += sprintf(buf+len, "\n"); + return len; +} + +#ifdef CONFIG_NFSD_V4 extern time_t nfs4_leasetime(void); static ssize_t write_leasetime(struct file *file, char *buf, size_t size) @@ -370,6 +464,7 @@ static ssize_t write_recoverydir(struct file *file, char *buf, size_t size) status = nfs4_reset_recoverydir(recdir); return strlen(buf); } +#endif /*----------------------------------------------------------------------------*/ /* @@ -389,6 +484,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent) [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, + [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR}, #ifdef CONFIG_NFSD_V4 [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR}, diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 1697539a7171777815cf6e54bd7738e3e3fdacde..89ed04696865a9595d67a2922ec33c55786862c2 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -52,7 +53,7 @@ extern struct svc_program nfsd_program; static void nfsd(struct svc_rqst *rqstp); struct timeval nfssvc_boot; -static struct svc_serv *nfsd_serv; + struct svc_serv *nfsd_serv; static atomic_t nfsd_busy; static unsigned long nfsd_last_call; static DEFINE_SPINLOCK(nfsd_call_lock); @@ -63,6 +64,31 @@ struct nfsd_list { }; static struct list_head nfsd_list = LIST_HEAD_INIT(nfsd_list); +static struct svc_version * nfsd_version[] = { + [2] = &nfsd_version2, +#if defined(CONFIG_NFSD_V3) + [3] = &nfsd_version3, +#endif +#if defined(CONFIG_NFSD_V4) + [4] = &nfsd_version4, +#endif +}; + +#define NFSD_MINVERS 2 +#define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0])) +static struct svc_version *nfsd_versions[NFSD_NRVERS]; + +struct svc_program nfsd_program = { + .pg_prog = NFS_PROGRAM, /* program number */ + .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */ + .pg_vers = nfsd_versions, /* version table */ + .pg_name = "nfsd", /* program name */ + .pg_class = "nfsd", /* authentication class */ + .pg_stats = &nfsd_svcstats, /* version table */ + .pg_authenticate = &svc_set_client, /* export authentication */ + +}; + /* * Maximum number of nfsd processes */ @@ -80,11 +106,12 @@ int nfsd_svc(unsigned short port, int nrservs) { int error; - int none_left; + int none_left, found_one, i; struct list_head *victim; lock_kernel(); - dprintk("nfsd: creating service\n"); + dprintk("nfsd: creating service: vers 0x%x\n", + nfsd_versbits); error = -EINVAL; if (nrservs <= 0) nrservs = 0; @@ -99,6 +126,27 @@ nfsd_svc(unsigned short port, int nrservs) if (error<0) goto out; if (!nfsd_serv) { + /* + * Use the nfsd_ctlbits to define which + * versions that will be advertised. + * If nfsd_ctlbits doesn't list any version, + * export them all. + */ + found_one = 0; + + for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) { + if (NFSCTL_VERISSET(nfsd_versbits, i)) { + nfsd_program.pg_vers[i] = nfsd_version[i]; + found_one = 1; + } else + nfsd_program.pg_vers[i] = NULL; + } + + if (!found_one) { + for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) + nfsd_program.pg_vers[i] = nfsd_version[i]; + } + atomic_set(&nfsd_busy, 0); error = -ENOMEM; nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE); @@ -379,6 +427,7 @@ static struct svc_program nfsd_acl_program = { .pg_name = "nfsd", .pg_class = "nfsd", .pg_stats = &nfsd_acl_svcstats, + .pg_authenticate = &svc_set_client, }; static struct svc_stat nfsd_acl_svcstats = { @@ -389,28 +438,3 @@ static struct svc_stat nfsd_acl_svcstats = { #else #define nfsd_acl_program_p NULL #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */ - -extern struct svc_version nfsd_version2, nfsd_version3, nfsd_version4; - -static struct svc_version * nfsd_version[] = { - [2] = &nfsd_version2, -#if defined(CONFIG_NFSD_V3) - [3] = &nfsd_version3, -#endif -#if defined(CONFIG_NFSD_V4) - [4] = &nfsd_version4, -#endif -}; - -#define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0])) -struct svc_program nfsd_program = { - .pg_next = nfsd_acl_program_p, - .pg_prog = NFS_PROGRAM, /* program number */ - .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */ - .pg_vers = nfsd_version, /* version table */ - .pg_name = "nfsd", /* program name */ - .pg_class = "nfsd", /* authentication class */ - .pg_stats = &nfsd_svcstats, /* version table */ - .pg_authenticate = &svc_set_client, /* export authentication */ - -}; diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 4f2cd3d2756665a1f600f8bcac96b4f2756b1ded..af7c3c3074b0075243a5850743a07ede58ebd863 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -254,12 +254,19 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, /* Get inode */ err = fh_verify(rqstp, fhp, ftype, accmode); - if (err || !iap->ia_valid) + if (err) goto out; dentry = fhp->fh_dentry; inode = dentry->d_inode; + /* Ignore any mode updates on symlinks */ + if (S_ISLNK(inode->i_mode)) + iap->ia_valid &= ~ATTR_MODE; + + if (!iap->ia_valid) + goto out; + /* NFSv2 does not differentiate between "set-[ac]time-to-now" * which only requires access, and "set-[ac]time-to-X" which * requires ownership. diff --git a/fs/open.c b/fs/open.c index 8d06ec911fd9df99762741ecb2ae7cf6b75ab8b0..6e8136751e9a49e1c89f47eb1957ed9f635281a7 100644 --- a/fs/open.c +++ b/fs/open.c @@ -194,7 +194,7 @@ asmlinkage long sys_fstatfs64(unsigned int fd, size_t sz, struct statfs64 __user return error; } -int do_truncate(struct dentry *dentry, loff_t length) +int do_truncate(struct dentry *dentry, loff_t length, struct file *filp) { int err; struct iattr newattrs; @@ -205,6 +205,10 @@ int do_truncate(struct dentry *dentry, loff_t length) newattrs.ia_size = length; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; + if (filp) { + newattrs.ia_file = filp; + newattrs.ia_valid |= ATTR_FILE; + } down(&dentry->d_inode->i_sem); err = notify_change(dentry, &newattrs); @@ -262,7 +266,7 @@ static inline long do_sys_truncate(const char __user * path, loff_t length) error = locks_verify_truncate(inode, NULL, length); if (!error) { DQUOT_INIT(inode); - error = do_truncate(nd.dentry, length); + error = do_truncate(nd.dentry, length, NULL); } put_write_access(inode); @@ -314,7 +318,7 @@ static inline long do_sys_ftruncate(unsigned int fd, loff_t length, int small) error = locks_verify_truncate(inode, file, length); if (!error) - error = do_truncate(dentry, length); + error = do_truncate(dentry, length, file); out_putf: fput(file); out: @@ -887,6 +891,10 @@ struct file *nameidata_to_filp(struct nameidata *nd, int flags) return filp; } +/* + * dentry_open() will have done dput(dentry) and mntput(mnt) if it returns an + * error. + */ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) { int error; @@ -894,8 +902,11 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) error = -ENFILE; f = get_empty_filp(); - if (f == NULL) + if (f == NULL) { + dput(dentry); + mntput(mnt); return ERR_PTR(error); + } return __dentry_open(dentry, mnt, flags, f, NULL); } diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c index 1be11ce96b0f915f4ebc2ea2ba1deba8068eb4e5..aeb0106890e4f1db6dc903f3d5e94f3724278ab0 100644 --- a/fs/openpromfs/inode.c +++ b/fs/openpromfs/inode.c @@ -1088,8 +1088,7 @@ static void __exit exit_openprom_fs(void) unregister_filesystem(&openprom_fs_type); free_pages ((unsigned long)nodes, alloced); for (i = 0; i < aliases_nodes; i++) - if (alias_names [i]) - kfree (alias_names [i]); + kfree (alias_names [i]); nodes = NULL; } diff --git a/fs/partitions/ibm.c b/fs/partitions/ibm.c index d59dcbf2bd4a33dadaff4098cf39b24f0cb65aa1..6327bcb2d73df0d99b90dbde3a14e7958e7de330 100644 --- a/fs/partitions/ibm.c +++ b/fs/partitions/ibm.c @@ -29,7 +29,7 @@ * cyl-cyl-head-head structure */ static inline int -cchh2blk (cchh_t *ptr, struct hd_geometry *geo) { +cchh2blk (struct vtoc_cchh *ptr, struct hd_geometry *geo) { return ptr->cc * geo->heads * geo->sectors + ptr->hh * geo->sectors; } @@ -40,7 +40,7 @@ cchh2blk (cchh_t *ptr, struct hd_geometry *geo) { * cyl-cyl-head-head-block structure */ static inline int -cchhb2blk (cchhb_t *ptr, struct hd_geometry *geo) { +cchhb2blk (struct vtoc_cchhb *ptr, struct hd_geometry *geo) { return ptr->cc * geo->heads * geo->sectors + ptr->hh * geo->sectors + ptr->b; @@ -56,7 +56,7 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev) struct hd_geometry *geo; char type[5] = {0,}; char name[7] = {0,}; - volume_label_t *vlabel; + struct vtoc_volume_label *vlabel; unsigned char *data; Sector sect; @@ -64,7 +64,8 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev) goto out_noinfo; if ((geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL)) == NULL) goto out_nogeo; - if ((vlabel = kmalloc(sizeof(volume_label_t), GFP_KERNEL)) == NULL) + if ((vlabel = kmalloc(sizeof(struct vtoc_volume_label), + GFP_KERNEL)) == NULL) goto out_novlab; if (ioctl_by_bdev(bdev, BIODASDINFO, (unsigned long)info) != 0 || @@ -86,7 +87,7 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev) strncpy(name, data + 8, 6); else strncpy(name, data + 4, 6); - memcpy (vlabel, data, sizeof(volume_label_t)); + memcpy (vlabel, data, sizeof(struct vtoc_volume_label)); put_dev_sector(sect); EBCASC(type, 4); @@ -129,9 +130,9 @@ ibm_partition(struct parsed_partitions *state, struct block_device *bdev) counter = 0; while ((data = read_dev_sector(bdev, blk*(blocksize/512), §)) != NULL) { - format1_label_t f1; + struct vtoc_format1_label f1; - memcpy(&f1, data, sizeof(format1_label_t)); + memcpy(&f1, data, sizeof(struct vtoc_format1_label)); put_dev_sector(sect); /* skip FMT4 / FMT5 / FMT7 labels */ diff --git a/fs/pnode.c b/fs/pnode.c new file mode 100644 index 0000000000000000000000000000000000000000..aeeec8ba8dd28b9ac4a77ee513fb23423b55d458 --- /dev/null +++ b/fs/pnode.c @@ -0,0 +1,305 @@ +/* + * linux/fs/pnode.c + * + * (C) Copyright IBM Corporation 2005. + * Released under GPL v2. + * Author : Ram Pai (linuxram@us.ibm.com) + * + */ +#include +#include +#include +#include "pnode.h" + +/* return the next shared peer mount of @p */ +static inline struct vfsmount *next_peer(struct vfsmount *p) +{ + return list_entry(p->mnt_share.next, struct vfsmount, mnt_share); +} + +static inline struct vfsmount *first_slave(struct vfsmount *p) +{ + return list_entry(p->mnt_slave_list.next, struct vfsmount, mnt_slave); +} + +static inline struct vfsmount *next_slave(struct vfsmount *p) +{ + return list_entry(p->mnt_slave.next, struct vfsmount, mnt_slave); +} + +static int do_make_slave(struct vfsmount *mnt) +{ + struct vfsmount *peer_mnt = mnt, *master = mnt->mnt_master; + struct vfsmount *slave_mnt; + + /* + * slave 'mnt' to a peer mount that has the + * same root dentry. If none is available than + * slave it to anything that is available. + */ + while ((peer_mnt = next_peer(peer_mnt)) != mnt && + peer_mnt->mnt_root != mnt->mnt_root) ; + + if (peer_mnt == mnt) { + peer_mnt = next_peer(mnt); + if (peer_mnt == mnt) + peer_mnt = NULL; + } + list_del_init(&mnt->mnt_share); + + if (peer_mnt) + master = peer_mnt; + + if (master) { + list_for_each_entry(slave_mnt, &mnt->mnt_slave_list, mnt_slave) + slave_mnt->mnt_master = master; + list_del(&mnt->mnt_slave); + list_add(&mnt->mnt_slave, &master->mnt_slave_list); + list_splice(&mnt->mnt_slave_list, master->mnt_slave_list.prev); + INIT_LIST_HEAD(&mnt->mnt_slave_list); + } else { + struct list_head *p = &mnt->mnt_slave_list; + while (!list_empty(p)) { + slave_mnt = list_entry(p->next, + struct vfsmount, mnt_slave); + list_del_init(&slave_mnt->mnt_slave); + slave_mnt->mnt_master = NULL; + } + } + mnt->mnt_master = master; + CLEAR_MNT_SHARED(mnt); + INIT_LIST_HEAD(&mnt->mnt_slave_list); + return 0; +} + +void change_mnt_propagation(struct vfsmount *mnt, int type) +{ + if (type == MS_SHARED) { + set_mnt_shared(mnt); + return; + } + do_make_slave(mnt); + if (type != MS_SLAVE) { + list_del_init(&mnt->mnt_slave); + mnt->mnt_master = NULL; + if (type == MS_UNBINDABLE) + mnt->mnt_flags |= MNT_UNBINDABLE; + } +} + +/* + * get the next mount in the propagation tree. + * @m: the mount seen last + * @origin: the original mount from where the tree walk initiated + */ +static struct vfsmount *propagation_next(struct vfsmount *m, + struct vfsmount *origin) +{ + /* are there any slaves of this mount? */ + if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list)) + return first_slave(m); + + while (1) { + struct vfsmount *next; + struct vfsmount *master = m->mnt_master; + + if ( master == origin->mnt_master ) { + next = next_peer(m); + return ((next == origin) ? NULL : next); + } else if (m->mnt_slave.next != &master->mnt_slave_list) + return next_slave(m); + + /* back at master */ + m = master; + } +} + +/* + * return the source mount to be used for cloning + * + * @dest the current destination mount + * @last_dest the last seen destination mount + * @last_src the last seen source mount + * @type return CL_SLAVE if the new mount has to be + * cloned as a slave. + */ +static struct vfsmount *get_source(struct vfsmount *dest, + struct vfsmount *last_dest, + struct vfsmount *last_src, + int *type) +{ + struct vfsmount *p_last_src = NULL; + struct vfsmount *p_last_dest = NULL; + *type = CL_PROPAGATION;; + + if (IS_MNT_SHARED(dest)) + *type |= CL_MAKE_SHARED; + + while (last_dest != dest->mnt_master) { + p_last_dest = last_dest; + p_last_src = last_src; + last_dest = last_dest->mnt_master; + last_src = last_src->mnt_master; + } + + if (p_last_dest) { + do { + p_last_dest = next_peer(p_last_dest); + } while (IS_MNT_NEW(p_last_dest)); + } + + if (dest != p_last_dest) { + *type |= CL_SLAVE; + return last_src; + } else + return p_last_src; +} + +/* + * mount 'source_mnt' under the destination 'dest_mnt' at + * dentry 'dest_dentry'. And propagate that mount to + * all the peer and slave mounts of 'dest_mnt'. + * Link all the new mounts into a propagation tree headed at + * source_mnt. Also link all the new mounts using ->mnt_list + * headed at source_mnt's ->mnt_list + * + * @dest_mnt: destination mount. + * @dest_dentry: destination dentry. + * @source_mnt: source mount. + * @tree_list : list of heads of trees to be attached. + */ +int propagate_mnt(struct vfsmount *dest_mnt, struct dentry *dest_dentry, + struct vfsmount *source_mnt, struct list_head *tree_list) +{ + struct vfsmount *m, *child; + int ret = 0; + struct vfsmount *prev_dest_mnt = dest_mnt; + struct vfsmount *prev_src_mnt = source_mnt; + LIST_HEAD(tmp_list); + LIST_HEAD(umount_list); + + for (m = propagation_next(dest_mnt, dest_mnt); m; + m = propagation_next(m, dest_mnt)) { + int type; + struct vfsmount *source; + + if (IS_MNT_NEW(m)) + continue; + + source = get_source(m, prev_dest_mnt, prev_src_mnt, &type); + + if (!(child = copy_tree(source, source->mnt_root, type))) { + ret = -ENOMEM; + list_splice(tree_list, tmp_list.prev); + goto out; + } + + if (is_subdir(dest_dentry, m->mnt_root)) { + mnt_set_mountpoint(m, dest_dentry, child); + list_add_tail(&child->mnt_hash, tree_list); + } else { + /* + * This can happen if the parent mount was bind mounted + * on some subdirectory of a shared/slave mount. + */ + list_add_tail(&child->mnt_hash, &tmp_list); + } + prev_dest_mnt = m; + prev_src_mnt = child; + } +out: + spin_lock(&vfsmount_lock); + while (!list_empty(&tmp_list)) { + child = list_entry(tmp_list.next, struct vfsmount, mnt_hash); + list_del_init(&child->mnt_hash); + umount_tree(child, 0, &umount_list); + } + spin_unlock(&vfsmount_lock); + release_mounts(&umount_list); + return ret; +} + +/* + * return true if the refcount is greater than count + */ +static inline int do_refcount_check(struct vfsmount *mnt, int count) +{ + int mycount = atomic_read(&mnt->mnt_count); + return (mycount > count); +} + +/* + * check if the mount 'mnt' can be unmounted successfully. + * @mnt: the mount to be checked for unmount + * NOTE: unmounting 'mnt' would naturally propagate to all + * other mounts its parent propagates to. + * Check if any of these mounts that **do not have submounts** + * have more references than 'refcnt'. If so return busy. + */ +int propagate_mount_busy(struct vfsmount *mnt, int refcnt) +{ + struct vfsmount *m, *child; + struct vfsmount *parent = mnt->mnt_parent; + int ret = 0; + + if (mnt == parent) + return do_refcount_check(mnt, refcnt); + + /* + * quickly check if the current mount can be unmounted. + * If not, we don't have to go checking for all other + * mounts + */ + if (!list_empty(&mnt->mnt_mounts) || do_refcount_check(mnt, refcnt)) + return 1; + + for (m = propagation_next(parent, parent); m; + m = propagation_next(m, parent)) { + child = __lookup_mnt(m, mnt->mnt_mountpoint, 0); + if (child && list_empty(&child->mnt_mounts) && + (ret = do_refcount_check(child, 1))) + break; + } + return ret; +} + +/* + * NOTE: unmounting 'mnt' naturally propagates to all other mounts its + * parent propagates to. + */ +static void __propagate_umount(struct vfsmount *mnt) +{ + struct vfsmount *parent = mnt->mnt_parent; + struct vfsmount *m; + + BUG_ON(parent == mnt); + + for (m = propagation_next(parent, parent); m; + m = propagation_next(m, parent)) { + + struct vfsmount *child = __lookup_mnt(m, + mnt->mnt_mountpoint, 0); + /* + * umount the child only if the child has no + * other children + */ + if (child && list_empty(&child->mnt_mounts)) { + list_del(&child->mnt_hash); + list_add_tail(&child->mnt_hash, &mnt->mnt_hash); + } + } +} + +/* + * collect all mounts that receive propagation from the mount in @list, + * and return these additional mounts in the same list. + * @list: the list of mounts to be unmounted. + */ +int propagate_umount(struct list_head *list) +{ + struct vfsmount *mnt; + + list_for_each_entry(mnt, list, mnt_hash) + __propagate_umount(mnt); + return 0; +} diff --git a/fs/pnode.h b/fs/pnode.h new file mode 100644 index 0000000000000000000000000000000000000000..020e1bb60fdb6b3e4601727a273bad4e2d322331 --- /dev/null +++ b/fs/pnode.h @@ -0,0 +1,37 @@ +/* + * linux/fs/pnode.h + * + * (C) Copyright IBM Corporation 2005. + * Released under GPL v2. + * + */ +#ifndef _LINUX_PNODE_H +#define _LINUX_PNODE_H + +#include +#include + +#define IS_MNT_SHARED(mnt) (mnt->mnt_flags & MNT_SHARED) +#define IS_MNT_SLAVE(mnt) (mnt->mnt_master) +#define IS_MNT_NEW(mnt) (!mnt->mnt_namespace) +#define CLEAR_MNT_SHARED(mnt) (mnt->mnt_flags &= ~MNT_SHARED) +#define IS_MNT_UNBINDABLE(mnt) (mnt->mnt_flags & MNT_UNBINDABLE) + +#define CL_EXPIRE 0x01 +#define CL_SLAVE 0x02 +#define CL_COPY_ALL 0x04 +#define CL_MAKE_SHARED 0x08 +#define CL_PROPAGATION 0x10 + +static inline void set_mnt_shared(struct vfsmount *mnt) +{ + mnt->mnt_flags &= ~MNT_PNODE_MASK; + mnt->mnt_flags |= MNT_SHARED; +} + +void change_mnt_propagation(struct vfsmount *, int); +int propagate_mnt(struct vfsmount *, struct dentry *, struct vfsmount *, + struct list_head *); +int propagate_umount(struct list_head *); +int propagate_mount_busy(struct vfsmount *, int); +#endif /* _LINUX_PNODE_H */ diff --git a/fs/proc/base.c b/fs/proc/base.c index a170450aadb1adc0ef3f81b595b0eacd9978ede7..634355e169869c3369959acbe5261542bb4cacb6 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -70,6 +70,7 @@ #include #include #include +#include #include "internal.h" /* @@ -660,26 +661,38 @@ static struct file_operations proc_smaps_operations = { #endif extern struct seq_operations mounts_op; +struct proc_mounts { + struct seq_file m; + int event; +}; + static int mounts_open(struct inode *inode, struct file *file) { struct task_struct *task = proc_task(inode); - int ret = seq_open(file, &mounts_op); + struct namespace *namespace; + struct proc_mounts *p; + int ret = -EINVAL; - if (!ret) { - struct seq_file *m = file->private_data; - struct namespace *namespace; - task_lock(task); - namespace = task->namespace; - if (namespace) - get_namespace(namespace); - task_unlock(task); - - if (namespace) - m->private = namespace; - else { - seq_release(inode, file); - ret = -EINVAL; + task_lock(task); + namespace = task->namespace; + if (namespace) + get_namespace(namespace); + task_unlock(task); + + if (namespace) { + ret = -ENOMEM; + p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); + if (p) { + file->private_data = &p->m; + ret = seq_open(file, &mounts_op); + if (!ret) { + p->m.private = namespace; + p->event = namespace->event; + return 0; + } + kfree(p); } + put_namespace(namespace); } return ret; } @@ -692,11 +705,30 @@ static int mounts_release(struct inode *inode, struct file *file) return seq_release(inode, file); } +static unsigned mounts_poll(struct file *file, poll_table *wait) +{ + struct proc_mounts *p = file->private_data; + struct namespace *ns = p->m.private; + unsigned res = 0; + + poll_wait(file, &ns->poll, wait); + + spin_lock(&vfsmount_lock); + if (p->event != ns->event) { + p->event = ns->event; + res = POLLERR; + } + spin_unlock(&vfsmount_lock); + + return res; +} + static struct file_operations proc_mounts_operations = { .open = mounts_open, .read = seq_read, .llseek = seq_lseek, .release = mounts_release, + .poll = mounts_poll, }; #define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */ diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c index 6fd57f1541972cfb182e325d39df30c02850690a..fb117b74809eca5169b8805a1c83437cd5033105 100644 --- a/fs/proc/proc_devtree.c +++ b/fs/proc/proc_devtree.c @@ -48,6 +48,39 @@ static int property_read_proc(char *page, char **start, off_t off, * and "@10" to it. */ +/* + * Add a property to a node + */ +static struct proc_dir_entry * +__proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp) +{ + struct proc_dir_entry *ent; + + /* + * Unfortunately proc_register puts each new entry + * at the beginning of the list. So we rearrange them. + */ + ent = create_proc_read_entry(pp->name, + strncmp(pp->name, "security-", 9) + ? S_IRUGO : S_IRUSR, de, + property_read_proc, pp); + if (ent == NULL) + return NULL; + + if (!strncmp(pp->name, "security-", 9)) + ent->size = 0; /* don't leak number of password chars */ + else + ent->size = pp->length; + + return ent; +} + + +void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop) +{ + __proc_device_tree_add_prop(pde, prop); +} + /* * Process a node, adding entries for its children and its properties. */ @@ -57,11 +90,9 @@ void proc_device_tree_add_node(struct device_node *np, struct property *pp; struct proc_dir_entry *ent; struct device_node *child; - struct proc_dir_entry *list = NULL, **lastp; const char *p; set_node_proc_entry(np, de); - lastp = &list; for (child = NULL; (child = of_get_next_child(np, child));) { p = strrchr(child->full_name, '/'); if (!p) @@ -71,9 +102,6 @@ void proc_device_tree_add_node(struct device_node *np, ent = proc_mkdir(p, de); if (ent == 0) break; - *lastp = ent; - ent->next = NULL; - lastp = &ent->next; proc_device_tree_add_node(child, ent); } of_node_put(child); @@ -84,7 +112,7 @@ void proc_device_tree_add_node(struct device_node *np, * properties are quite unimportant for us though, thus we * simply "skip" them here, but we do have to check. */ - for (ent = list; ent != NULL; ent = ent->next) + for (ent = de->subdir; ent != NULL; ent = ent->next) if (!strcmp(ent->name, pp->name)) break; if (ent != NULL) { @@ -94,25 +122,10 @@ void proc_device_tree_add_node(struct device_node *np, continue; } - /* - * Unfortunately proc_register puts each new entry - * at the beginning of the list. So we rearrange them. - */ - ent = create_proc_read_entry(pp->name, - strncmp(pp->name, "security-", 9) - ? S_IRUGO : S_IRUSR, de, - property_read_proc, pp); + ent = __proc_device_tree_add_prop(de, pp); if (ent == 0) break; - if (!strncmp(pp->name, "security-", 9)) - ent->size = 0; /* don't leak number of password chars */ - else - ent->size = pp->length; - ent->next = NULL; - *lastp = ent; - lastp = &ent->next; } - de->subdir = list; } /* diff --git a/fs/quota.c b/fs/quota.c index 1df7832b4e087460876251bf7b70d79566264f1a..612e04db4b939189721f35182c2dd1793804ae89 100644 --- a/fs/quota.c +++ b/fs/quota.c @@ -15,6 +15,7 @@ #include #include #include +#include /* Check validity of generic quotactl commands */ static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id) diff --git a/fs/seq_file.c b/fs/seq_file.c index 38ef913767ffd3f839df2d27f2c581d6071c05cd..7c40570b71dc02317a6963a1beed8d983700669a 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -28,13 +28,17 @@ */ int seq_open(struct file *file, struct seq_operations *op) { - struct seq_file *p = kmalloc(sizeof(*p), GFP_KERNEL); - if (!p) - return -ENOMEM; + struct seq_file *p = file->private_data; + + if (!p) { + p = kmalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + file->private_data = p; + } memset(p, 0, sizeof(*p)); sema_init(&p->sem, 1); p->op = op; - file->private_data = p; /* * Wrappers around seq_open(e.g. swaps_open) need to be diff --git a/fs/smbfs/request.c b/fs/smbfs/request.c index 2d85dd7415bb2a487d35f6ddc96fb52e653bef1f..a0f296d9928ad39d1044597553c36f9c75ac0b55 100644 --- a/fs/smbfs/request.c +++ b/fs/smbfs/request.c @@ -786,8 +786,7 @@ int smb_request_recv(struct smb_sb_info *server) /* We should never be called with any of these states */ case SMB_RECV_END: case SMB_RECV_REQUEST: - server->rstate = SMB_RECV_END; - break; + BUG(); } if (result < 0) { diff --git a/fs/smbfs/symlink.c b/fs/smbfs/symlink.c index 0c64bc3a0127e9c15c6f76921ea688f7eee73b6f..cdc53c4fb3813448ef6c7c0dba700b7ad38c4752 100644 --- a/fs/smbfs/symlink.c +++ b/fs/smbfs/symlink.c @@ -45,7 +45,7 @@ static void *smb_follow_link(struct dentry *dentry, struct nameidata *nd) int len = smb_proc_read_link(server_from_dentry(dentry), dentry, link, PATH_MAX - 1); if (len < 0) { - putname(link); + __putname(link); link = ERR_PTR(len); } else { link[len] = 0; @@ -59,7 +59,7 @@ static void smb_put_link(struct dentry *dentry, struct nameidata *nd, void *p) { char *s = nd_get_link(nd); if (!IS_ERR(s)) - putname(s); + __putname(s); } struct inode_operations smb_link_inode_operations = diff --git a/fs/super.c b/fs/super.c index f60155ec778010c6468b432fa60b9ebc96b98495..6689dded3c8483469b788c6334351ad1a72bccc8 100644 --- a/fs/super.c +++ b/fs/super.c @@ -171,6 +171,7 @@ void deactivate_super(struct super_block *s) if (atomic_dec_and_lock(&s->s_active, &sb_lock)) { s->s_count -= S_BIAS-1; spin_unlock(&sb_lock); + DQUOT_OFF(s); down_write(&s->s_umount); fs->kill_sb(s); put_filesystem(fs); @@ -474,8 +475,6 @@ struct super_block * user_get_super(dev_t dev) return NULL; } -EXPORT_SYMBOL(user_get_super); - asmlinkage long sys_ustat(unsigned dev, struct ustat __user * ubuf) { struct super_block *s; diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h index 0e54922daa0917ef802a73edf998f467c7b09c9d..663669810be60afbae65f2a262a657f98bfa7f64 100644 --- a/fs/udf/udf_sb.h +++ b/fs/udf/udf_sb.h @@ -39,8 +39,7 @@ static inline struct udf_sb_info *UDF_SB(struct super_block *sb) {\ if (UDF_SB(X))\ {\ - if (UDF_SB_PARTMAPS(X))\ - kfree(UDF_SB_PARTMAPS(X));\ + kfree(UDF_SB_PARTMAPS(X));\ UDF_SB_PARTMAPS(X) = NULL;\ }\ } diff --git a/fs/ufs/super.c b/fs/ufs/super.c index f036d694ba5afe75263862b30870c4ff6794c590..54828ebcf1bacda4d1c94dc4461cd99d8264234d 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -472,13 +472,14 @@ static int ufs_read_cylinder_structures (struct super_block *sb) { return 1; failed: - if (base) kfree (base); + kfree (base); if (sbi->s_ucg) { for (i = 0; i < uspi->s_ncg; i++) - if (sbi->s_ucg[i]) brelse (sbi->s_ucg[i]); + if (sbi->s_ucg[i]) + brelse (sbi->s_ucg[i]); kfree (sbi->s_ucg); for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) - if (sbi->s_ucpi[i]) kfree (sbi->s_ucpi[i]); + kfree (sbi->s_ucpi[i]); } UFSD(("EXIT (FAILED)\n")) return 0; @@ -981,9 +982,10 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) dalloc_failed: iput(inode); failed: - if (ubh) ubh_brelse_uspi (uspi); - if (uspi) kfree (uspi); - if (sbi) kfree(sbi); + if (ubh) + ubh_brelse_uspi (uspi); + kfree (uspi); + kfree(sbi); sb->s_fs_info = NULL; UFSD(("EXIT (FAILED)\n")) return -EINVAL; diff --git a/fs/xattr.c b/fs/xattr.c index f6e00c0e114f6225d1f7af66517dd537aa0724bf..a9db225579983b4babe40ac4c47a9eef0a3250cb 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -74,8 +74,7 @@ setxattr(struct dentry *d, char __user *name, void __user *value, } out: up(&d->d_inode->i_sem); - if (kvalue) - kfree(kvalue); + kfree(kvalue); return error; } @@ -173,8 +172,7 @@ getxattr(struct dentry *d, char __user *name, void __user *value, size_t size) error = -E2BIG; } out: - if (kvalue) - kfree(kvalue); + kfree(kvalue); return error; } @@ -259,8 +257,7 @@ listxattr(struct dentry *d, char __user *list, size_t size) error = -E2BIG; } out: - if (klist) - kfree(klist); + kfree(klist); return error; } diff --git a/fs/xfs/linux-2.6/kmem.h b/fs/xfs/linux-2.6/kmem.h index 8f82c1a20dc5311e38c641bb0aa230747649545a..c64a29cdfff3446835da2e29ed3774840a551b97 100644 --- a/fs/xfs/linux-2.6/kmem.h +++ b/fs/xfs/linux-2.6/kmem.h @@ -30,8 +30,8 @@ #define KM_NOFS 0x0004u #define KM_MAYFAIL 0x0008u -#define kmem_zone kmem_cache_s -#define kmem_zone_t kmem_cache_t +#define kmem_zone kmem_cache +#define kmem_zone_t struct kmem_cache typedef unsigned long xfs_pflags_t; diff --git a/include/asm-alpha/pgtable.h b/include/asm-alpha/pgtable.h index 8393bf374b2b59c85bd90c60440322bacd4c8426..a985cd29b6db2f5dc013d7313cf92b4f40c7b7e2 100644 --- a/include/asm-alpha/pgtable.h +++ b/include/asm-alpha/pgtable.h @@ -17,6 +17,9 @@ #include /* For TASK_SIZE */ #include +struct mm_struct; +struct vm_area_struct; + /* Certain architectures need to do special things when PTEs * within a page table are directly modified. Thus, the following * hook is made available. diff --git a/include/asm-alpha/ptrace.h b/include/asm-alpha/ptrace.h index d462c5e14c13e4d227c76df4099cbb904650ea53..072375c135b4a008799173b655837fb39c3d2b91 100644 --- a/include/asm-alpha/ptrace.h +++ b/include/asm-alpha/ptrace.h @@ -67,6 +67,9 @@ struct switch_stack { }; #ifdef __KERNEL__ + +#define __ARCH_SYS_PTRACE 1 + #define user_mode(regs) (((regs)->ps & 8) != 0) #define instruction_pointer(regs) ((regs)->pc) #define profile_pc(regs) instruction_pointer(regs) diff --git a/include/asm-arm/arch-realview/entry-macro.S b/include/asm-arm/arch-realview/entry-macro.S index 2712ba77bb3a6db51f729e0d0aa33f2f43498e51..4df469bf42e2809b84bddce343728b08af3488af 100644 --- a/include/asm-arm/arch-realview/entry-macro.S +++ b/include/asm-arm/arch-realview/entry-macro.S @@ -47,3 +47,17 @@ cmpcs \irqnr, \irqnr .endm + + /* We assume that irqstat (the raw value of the IRQ acknowledge + * register) is preserved from the macro above. + * If there is an IPI, we immediately signal end of interrupt on the + * controller, since this requires the original irqstat value which + * we won't easily be able to recreate later. + */ + + .macro test_for_ipi, irqnr, irqstat, base, tmp + bic \irqnr, \irqstat, #0x1c00 + cmp \irqnr, #16 + strcc \irqstat, [\base, #GIC_CPU_EOI] + cmpcs \irqnr, \irqnr + .endm diff --git a/include/asm-arm/arch-realview/platform.h b/include/asm-arm/arch-realview/platform.h index 4b6de13a6b9a91cca202441ff41f08e83d2b9088..aef9b36b3c3771d891e5d199a1daf817c8033b1a 100644 --- a/include/asm-arm/arch-realview/platform.h +++ b/include/asm-arm/arch-realview/platform.h @@ -203,8 +203,14 @@ /* Reserved 0x1001A000 - 0x1001FFFF */ #define REALVIEW_CLCD_BASE 0x10020000 /* CLCD */ #define REALVIEW_DMAC_BASE 0x10030000 /* DMA controller */ +#ifndef CONFIG_REALVIEW_MPCORE #define REALVIEW_GIC_CPU_BASE 0x10040000 /* Generic interrupt controller CPU interface */ #define REALVIEW_GIC_DIST_BASE 0x10041000 /* Generic interrupt controller distributor */ +#else +#define REALVIEW_MPCORE_SCU_BASE 0x10100000 /* SCU registers */ +#define REALVIEW_GIC_CPU_BASE 0x10100100 /* Generic interrupt controller CPU interface */ +#define REALVIEW_GIC_DIST_BASE 0x10101000 /* Generic interrupt controller distributor */ +#endif #define REALVIEW_SMC_BASE 0x10080000 /* SMC */ /* Reserved 0x10090000 - 0x100EFFFF */ @@ -265,6 +271,7 @@ * Interrupts - bit assignment (primary) * ------------------------------------------------------------------------ */ +#ifndef CONFIG_REALVIEW_MPCORE #define INT_WDOGINT 0 /* Watchdog timer */ #define INT_SOFTINT 1 /* Software interrupt */ #define INT_COMMRx 2 /* Debug Comm Rx interrupt */ @@ -297,6 +304,55 @@ #define INT_USB 29 /* USB controller */ #define INT_TSPENINT 30 /* Touchscreen pen */ #define INT_TSKPADINT 31 /* Touchscreen keypad */ +#else +#define INT_LOCALTIMER 29 +#define INT_LOCALWDOG 30 + +#define INT_AACI 0 +#define INT_TIMERINT0_1 1 +#define INT_TIMERINT2_3 2 +#define INT_USB 3 +#define INT_UARTINT0 4 +#define INT_UARTINT1 5 +#define INT_RTCINT 6 +#define INT_KMI0 7 +#define INT_KMI1 8 +#define INT_ETH 9 +#define INT_EB_IRQ1 10 /* main GIC */ +#define INT_EB_IRQ2 11 /* tile GIC */ +#define INT_EB_FIQ1 12 /* main GIC */ +#define INT_EB_FIQ2 13 /* tile GIC */ +#define INT_MMCI0A 14 +#define INT_MMCI0B 15 + +#define INT_PMU_CPU0 17 +#define INT_PMU_CPU1 18 +#define INT_PMU_CPU2 19 +#define INT_PMU_CPU3 20 +#define INT_PMU_SCU0 21 +#define INT_PMU_SCU1 22 +#define INT_PMU_SCU2 23 +#define INT_PMU_SCU3 24 +#define INT_PMU_SCU4 25 +#define INT_PMU_SCU5 26 +#define INT_PMU_SCU6 27 +#define INT_PMU_SCU7 28 + +#define INT_L220_EVENT 29 +#define INT_L220_SLAVE 30 +#define INT_L220_DECODE 31 + +#define INT_UARTINT2 -1 +#define INT_UARTINT3 -1 +#define INT_CLCDINT -1 +#define INT_DMAINT -1 +#define INT_WDOGINT -1 +#define INT_GPIOINT0 -1 +#define INT_GPIOINT1 -1 +#define INT_GPIOINT2 -1 +#define INT_SCIINT -1 +#define INT_SSPINT -1 +#endif /* * Interrupt bit positions diff --git a/include/asm-arm/arch-realview/smp.h b/include/asm-arm/arch-realview/smp.h new file mode 100644 index 0000000000000000000000000000000000000000..fc87783e8e8b7a308812e7cc9b76c13a16050346 --- /dev/null +++ b/include/asm-arm/arch-realview/smp.h @@ -0,0 +1,31 @@ +#ifndef ASMARM_ARCH_SMP_H +#define ASMARM_ARCH_SMP_H + +#include + +#include + +#define hard_smp_processor_id() \ + ({ \ + unsigned int cpunum; \ + __asm__("mrc p15, 0, %0, c0, c0, 5" \ + : "=r" (cpunum)); \ + cpunum &= 0x0F; \ + }) + +/* + * We use IRQ1 as the IPI + */ +static inline void smp_cross_call(cpumask_t callmap) +{ + gic_raise_softirq(callmap, 1); +} + +/* + * Do nothing on MPcore. + */ +static inline void smp_cross_call_done(cpumask_t callmap) +{ +} + +#endif diff --git a/include/asm-arm/arch-s3c2410/uncompress.h b/include/asm-arm/arch-s3c2410/uncompress.h index d7a4a8354fa9854be8a2bc23203a0336b57b93fa..ddd1578a7ee0a40d2877434176f7718797c9b1a4 100644 --- a/include/asm-arm/arch-s3c2410/uncompress.h +++ b/include/asm-arm/arch-s3c2410/uncompress.h @@ -116,6 +116,8 @@ putstr(const char *ptr) } } +#define __raw_writel(d,ad) do { *((volatile unsigned int *)(ad)) = (d); } while(0) + /* CONFIG_S3C2410_BOOT_WATCHDOG * * Simple boot-time watchdog setup, to reboot the system if there is @@ -126,8 +128,6 @@ putstr(const char *ptr) #define WDOG_COUNT (0xff00) -#define __raw_writel(d,ad) do { *((volatile unsigned int *)(ad)) = (d); } while(0) - static inline void arch_decomp_wdog(void) { __raw_writel(WDOG_COUNT, S3C2410_WTCNT); @@ -145,6 +145,24 @@ static void arch_decomp_wdog_start(void) #define arch_decomp_wdog() #endif +#ifdef CONFIG_S3C2410_BOOT_ERROR_RESET + +static void arch_decomp_error(const char *x) +{ + putstr("\n\n"); + putstr(x); + putstr("\n\n -- System resetting\n"); + + __raw_writel(0x4000, S3C2410_WTDAT); + __raw_writel(0x4000, S3C2410_WTCNT); + __raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x40), S3C2410_WTCON); + + while(1); +} + +#define arch_error arch_decomp_error +#endif + static void error(char *err); static void diff --git a/include/asm-arm/hardirq.h b/include/asm-arm/hardirq.h index e5ccb6b8ff83c60700f57db2279de77fac382454..1cbb173bf5b108b2d136a78961ed7ffc873dc276 100644 --- a/include/asm-arm/hardirq.h +++ b/include/asm-arm/hardirq.h @@ -8,6 +8,7 @@ typedef struct { unsigned int __softirq_pending; + unsigned int local_timer_irqs; } ____cacheline_aligned irq_cpustat_t; #include /* Standard mappings for irq_cpustat_t above */ diff --git a/include/asm-arm/hardware/arm_scu.h b/include/asm-arm/hardware/arm_scu.h new file mode 100644 index 0000000000000000000000000000000000000000..9903f60c84b713fdde431f61e33c87ba8f683be4 --- /dev/null +++ b/include/asm-arm/hardware/arm_scu.h @@ -0,0 +1,13 @@ +#ifndef ASMARM_HARDWARE_ARM_SCU_H +#define ASMARM_HARDWARE_ARM_SCU_H + +/* + * SCU registers + */ +#define SCU_CTRL 0x00 +#define SCU_CONFIG 0x04 +#define SCU_CPU_STATUS 0x08 +#define SCU_INVALIDATE 0x0c +#define SCU_FPGA_REVISION 0x10 + +#endif diff --git a/include/asm-arm/hardware/scoop.h b/include/asm-arm/hardware/scoop.h index a8f1013930e363140381c9f9385b63885b0dd774..d37bf7443264c347141ae9550dfbda9d59dedd85 100644 --- a/include/asm-arm/hardware/scoop.h +++ b/include/asm-arm/hardware/scoop.h @@ -52,8 +52,14 @@ struct scoop_pcmcia_dev { unsigned char keep_rd; }; -extern int scoop_num; -extern struct scoop_pcmcia_dev *scoop_devs; +struct scoop_pcmcia_config { + struct scoop_pcmcia_dev *devs; + int num_devs; + void (*pcmcia_init)(void); + void (*power_ctrl)(struct device *scoop, unsigned short cpr, int nr); +}; + +extern struct scoop_pcmcia_config *platform_scoop_config; void reset_scoop(struct device *dev); unsigned short set_scoop_gpio(struct device *dev, unsigned short bit); diff --git a/include/asm-arm/smp.h b/include/asm-arm/smp.h index 551cd3c3093cd8bde19f3a435e46ca4a86d446a4..5a72e50ca9fc0ab5f1640d5ba975ee155851e14e 100644 --- a/include/asm-arm/smp.h +++ b/include/asm-arm/smp.h @@ -36,6 +36,11 @@ struct seq_file; */ extern void show_ipi_list(struct seq_file *p); +/* + * Called from assembly code, this handles an IPI. + */ +asmlinkage void do_IPI(struct pt_regs *regs); + /* * Move global data into per-processor storage. */ @@ -46,12 +51,23 @@ extern void smp_store_cpu_info(unsigned int cpuid); */ extern void smp_cross_call(cpumask_t callmap); +/* + * Broadcast a timer interrupt to the other CPUs. + */ +extern void smp_send_timer(void); + /* * Boot a secondary CPU, and assign it the specified idle task. * This also gives us the initial stack to use for this CPU. */ extern int boot_secondary(unsigned int cpu, struct task_struct *); +/* + * Called from platform specific assembly code, this is the + * secondary CPU entry point. + */ +asmlinkage void secondary_start_kernel(void); + /* * Perform platform specific initialisation of the specified CPU. */ @@ -76,4 +92,42 @@ extern void platform_cpu_die(unsigned int cpu); extern int platform_cpu_kill(unsigned int cpu); extern void platform_cpu_enable(unsigned int cpu); +#ifdef CONFIG_LOCAL_TIMERS +/* + * Setup a local timer interrupt for a CPU. + */ +extern void local_timer_setup(unsigned int cpu); + +/* + * Stop a local timer interrupt. + */ +extern void local_timer_stop(unsigned int cpu); + +/* + * Platform provides this to acknowledge a local timer IRQ + */ +extern int local_timer_ack(void); + +#else + +static inline void local_timer_setup(unsigned int cpu) +{ +} + +static inline void local_timer_stop(unsigned int cpu) +{ +} + +#endif + +/* + * show local interrupt info + */ +extern void show_local_irqs(struct seq_file *); + +/* + * Called from assembly, this is the local timer IRQ handler + */ +asmlinkage void do_local_timer(struct pt_regs *); + #endif /* ifndef __ASM_ARM_SMP_H */ diff --git a/include/asm-cris/arch-v10/byteorder.h b/include/asm-cris/arch-v10/byteorder.h index e24465d1f40dda439795dcab869f43182ee01d7f..255b646b7fa8dbe6a586d88e4d7136ee5a12c75d 100644 --- a/include/asm-cris/arch-v10/byteorder.h +++ b/include/asm-cris/arch-v10/byteorder.h @@ -9,14 +9,14 @@ * them together into ntohl etc. */ -extern __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x) +static inline __attribute_const__ __u32 ___arch__swab32(__u32 x) { __asm__ ("swapwb %0" : "=r" (x) : "0" (x)); return(x); } -extern __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 x) +static inline __attribute_const__ __u16 ___arch__swab16(__u16 x) { __asm__ ("swapb %0" : "=r" (x) : "0" (x)); diff --git a/include/asm-cris/arch-v10/checksum.h b/include/asm-cris/arch-v10/checksum.h index fde1d00aaa903ad4cfaf614a1a2e8e975f7e8517..633f234f336b4cd86003209f67c622e4f6c85458 100644 --- a/include/asm-cris/arch-v10/checksum.h +++ b/include/asm-cris/arch-v10/checksum.h @@ -8,7 +8,7 @@ * to split all of those into 16-bit components, then add. */ -extern inline unsigned int +static inline unsigned int csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, unsigned short len, unsigned short proto, unsigned int sum) { diff --git a/include/asm-cris/arch-v10/delay.h b/include/asm-cris/arch-v10/delay.h index cfedae0d2f53dd5316e008513f57b85f795fe052..39481f6e0c3018e58a1bc06bc4627738a7753f61 100644 --- a/include/asm-cris/arch-v10/delay.h +++ b/include/asm-cris/arch-v10/delay.h @@ -1,7 +1,7 @@ #ifndef _CRIS_ARCH_DELAY_H #define _CRIS_ARCH_DELAY_H -extern __inline__ void __delay(int loops) +static inline void __delay(int loops) { __asm__ __volatile__ ( "move.d %0,$r9\n\t" diff --git a/include/asm-cris/arch-v10/ide.h b/include/asm-cris/arch-v10/ide.h index 8cf2d7cb22ac3bd7fe3ac0f2ab60d709635f8774..78b301ed7b126961fe4554f6a16a3d81e70596e3 100644 --- a/include/asm-cris/arch-v10/ide.h +++ b/include/asm-cris/arch-v10/ide.h @@ -25,7 +25,7 @@ #define MAX_HWIFS 4 -extern __inline__ int ide_default_irq(unsigned long base) +static inline int ide_default_irq(unsigned long base) { /* all IDE busses share the same IRQ, number 4. * this has the side-effect that ide-probe.c will cluster our 4 interfaces @@ -35,7 +35,7 @@ extern __inline__ int ide_default_irq(unsigned long base) return 4; } -extern __inline__ unsigned long ide_default_io_base(int index) +static inline unsigned long ide_default_io_base(int index) { /* we have no real I/O base address per interface, since all go through the * same register. but in a bitfield in that register, we have the i/f number. @@ -54,7 +54,7 @@ extern __inline__ unsigned long ide_default_io_base(int index) * of the ide_default_io_base call above. ctrl_port will be 0, but that is don't care for us. */ -extern __inline__ void ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, unsigned long ctrl_port, int *irq) +static inline void ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port, unsigned long ctrl_port, int *irq) { int i; @@ -77,7 +77,7 @@ extern __inline__ void ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_por hw->io_ports[IDE_IRQ_OFFSET] = 0; } -extern __inline__ void ide_init_default_hwifs(void) +static inline void ide_init_default_hwifs(void) { hw_regs_t hw; int index; diff --git a/include/asm-cris/arch-v10/system.h b/include/asm-cris/arch-v10/system.h index 6cc35642b8ab0d08c6182ba6256f8a642fe85299..1ac7b639b1b01670c59dca8323c5e17556b65987 100644 --- a/include/asm-cris/arch-v10/system.h +++ b/include/asm-cris/arch-v10/system.h @@ -5,7 +5,7 @@ /* read the CPU version register */ -extern inline unsigned long rdvr(void) { +static inline unsigned long rdvr(void) { unsigned char vr; __asm__ volatile ("move $vr,%0" : "=rm" (vr)); return vr; @@ -15,7 +15,7 @@ extern inline unsigned long rdvr(void) { /* read/write the user-mode stackpointer */ -extern inline unsigned long rdusp(void) { +static inline unsigned long rdusp(void) { unsigned long usp; __asm__ __volatile__("move $usp,%0" : "=rm" (usp)); return usp; @@ -26,13 +26,13 @@ extern inline unsigned long rdusp(void) { /* read the current stackpointer */ -extern inline unsigned long rdsp(void) { +static inline unsigned long rdsp(void) { unsigned long sp; __asm__ __volatile__("move.d $sp,%0" : "=rm" (sp)); return sp; } -extern inline unsigned long _get_base(char * addr) +static inline unsigned long _get_base(char * addr) { return 0; } diff --git a/include/asm-cris/arch-v10/thread_info.h b/include/asm-cris/arch-v10/thread_info.h index 357f5df0c9076c6bf21b95bfa9beeb5506f22ad5..218f4152d3e594f303ce1f9b386eb2ac5c41289e 100644 --- a/include/asm-cris/arch-v10/thread_info.h +++ b/include/asm-cris/arch-v10/thread_info.h @@ -2,7 +2,7 @@ #define _ASM_ARCH_THREAD_INFO_H /* how to get the thread information struct from C */ -extern inline struct thread_info *current_thread_info(void) +static inline struct thread_info *current_thread_info(void) { struct thread_info *ti; __asm__("and.d $sp,%0; ":"=r" (ti) : "0" (~8191UL)); diff --git a/include/asm-cris/arch-v10/timex.h b/include/asm-cris/arch-v10/timex.h index ecfc553c06a5f77f818fcf45cfb1bac0f0f510a0..e48447d94faf093f380dfa2f6e944099f8d316d5 100644 --- a/include/asm-cris/arch-v10/timex.h +++ b/include/asm-cris/arch-v10/timex.h @@ -22,7 +22,7 @@ unsigned long get_ns_in_jiffie(void); -extern inline unsigned long get_us_in_jiffie_highres(void) +static inline unsigned long get_us_in_jiffie_highres(void) { return get_ns_in_jiffie()/1000; } diff --git a/include/asm-cris/arch-v10/uaccess.h b/include/asm-cris/arch-v10/uaccess.h index 787d2e60c83c20382a6154654e119e824484dfc7..65b02d9b605af168fa619463e43b9ab0636aee76 100644 --- a/include/asm-cris/arch-v10/uaccess.h +++ b/include/asm-cris/arch-v10/uaccess.h @@ -87,7 +87,7 @@ * bytes copied if we hit a null byte * (without the null byte) */ -extern inline long +static inline long __do_strncpy_from_user(char *dst, const char *src, long count) { long res; @@ -602,7 +602,7 @@ __do_strncpy_from_user(char *dst, const char *src, long count) * or 0 for error. Return a value greater than N if too long. */ -extern inline long +static inline long strnlen_user(const char *s, long n) { long res, tmp1; diff --git a/include/asm-cris/arch-v32/bitops.h b/include/asm-cris/arch-v32/bitops.h index e40a58d3b862ab01db41bbe9f9a76095e2f23d7b..147689d6b624bc806ccfe5e2603506ac7672b00a 100644 --- a/include/asm-cris/arch-v32/bitops.h +++ b/include/asm-cris/arch-v32/bitops.h @@ -8,7 +8,7 @@ * inverts all bits in the input. */ -extern inline unsigned long +static inline unsigned long cris_swapnwbrlz(unsigned long w) { unsigned long res; @@ -20,7 +20,7 @@ cris_swapnwbrlz(unsigned long w) return res; } -extern inline unsigned long +static inline unsigned long cris_swapwbrlz(unsigned long w) { unsigned long res; @@ -36,7 +36,7 @@ cris_swapwbrlz(unsigned long w) * Find First Zero in word. Undefined if no zero exist, so the caller should * check against ~0 first. */ -extern inline unsigned long +static inline unsigned long ffz(unsigned long w) { return cris_swapnwbrlz(w); @@ -46,7 +46,7 @@ ffz(unsigned long w) * Find First Set bit in word. Undefined if no 1 exist, so the caller * should check against 0 first. */ -extern inline unsigned long +static inline unsigned long __ffs(unsigned long w) { return cris_swapnwbrlz(~w); @@ -55,7 +55,7 @@ __ffs(unsigned long w) /* * Find First Bit that is set. */ -extern inline unsigned long +static inline unsigned long kernel_ffs(unsigned long w) { return w ? cris_swapwbrlz (w) + 1 : 0; diff --git a/include/asm-cris/arch-v32/byteorder.h b/include/asm-cris/arch-v32/byteorder.h index 74846ee6cf99e36c62b7beda482df9c7adb91f20..6ef8fb4a35f270fd8afdc85c2348393aed269468 100644 --- a/include/asm-cris/arch-v32/byteorder.h +++ b/include/asm-cris/arch-v32/byteorder.h @@ -3,14 +3,14 @@ #include -extern __inline__ __const__ __u32 +static inline __const__ __u32 ___arch__swab32(__u32 x) { __asm__ __volatile__ ("swapwb %0" : "=r" (x) : "0" (x)); return (x); } -extern __inline__ __const__ __u16 +static inline __const__ __u16 ___arch__swab16(__u16 x) { __asm__ __volatile__ ("swapb %0" : "=r" (x) : "0" (x)); diff --git a/include/asm-cris/arch-v32/checksum.h b/include/asm-cris/arch-v32/checksum.h index a1d6b2a6cc447d95201dca7479d4134ebf0cae71..97ef89efea62ca9636fffc50f09aa52d7dac8dbe 100644 --- a/include/asm-cris/arch-v32/checksum.h +++ b/include/asm-cris/arch-v32/checksum.h @@ -9,7 +9,7 @@ * checksum. Which means it would be necessary to split all those into * 16-bit components and then add. */ -extern inline unsigned int +static inline unsigned int csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, unsigned short len, unsigned short proto, unsigned int sum) { diff --git a/include/asm-cris/arch-v32/delay.h b/include/asm-cris/arch-v32/delay.h index f36f7f760e891b9e1e6384e51f207b895813485d..b6e941e637de10935d0be469c4ab7346d8d7b8ef 100644 --- a/include/asm-cris/arch-v32/delay.h +++ b/include/asm-cris/arch-v32/delay.h @@ -1,7 +1,7 @@ #ifndef _ASM_CRIS_ARCH_DELAY_H #define _ASM_CRIS_ARCH_DELAY_H -extern __inline__ void +static inline void __delay(int loops) { __asm__ __volatile__ ( diff --git a/include/asm-cris/arch-v32/ide.h b/include/asm-cris/arch-v32/ide.h index 24f5604f566ac28b780d7daa87c44532c7beae3e..6590f657500dc1c6e7b1d3cd5e6eec265471dacb 100644 --- a/include/asm-cris/arch-v32/ide.h +++ b/include/asm-cris/arch-v32/ide.h @@ -26,7 +26,7 @@ #define MAX_HWIFS 4 -extern __inline__ int ide_default_irq(unsigned long base) +static inline int ide_default_irq(unsigned long base) { /* all IDE busses share the same IRQ, * this has the side-effect that ide-probe.c will cluster our 4 interfaces @@ -36,7 +36,7 @@ extern __inline__ int ide_default_irq(unsigned long base) return ATA_INTR_VECT; } -extern __inline__ unsigned long ide_default_io_base(int index) +static inline unsigned long ide_default_io_base(int index) { reg_ata_rw_ctrl2 ctrl2 = {.sel = index}; /* we have no real I/O base address per interface, since all go through the diff --git a/include/asm-cris/arch-v32/io.h b/include/asm-cris/arch-v32/io.h index 4c80263ec634fd948bb0e7db404577ea593ea071..043c9ce5294e9192ee00e0aa75edf9eb94f4c33e 100644 --- a/include/asm-cris/arch-v32/io.h +++ b/include/asm-cris/arch-v32/io.h @@ -35,7 +35,7 @@ extern struct crisv32_iopin crisv32_led2_red; extern struct crisv32_iopin crisv32_led3_green; extern struct crisv32_iopin crisv32_led3_red; -extern inline void crisv32_io_set(struct crisv32_iopin* iopin, +static inline void crisv32_io_set(struct crisv32_iopin* iopin, int val) { if (val) @@ -44,7 +44,7 @@ extern inline void crisv32_io_set(struct crisv32_iopin* iopin, *iopin->port->data &= ~iopin->bit; } -extern inline void crisv32_io_set_dir(struct crisv32_iopin* iopin, +static inline void crisv32_io_set_dir(struct crisv32_iopin* iopin, enum crisv32_io_dir dir) { if (dir == crisv32_io_dir_in) @@ -53,7 +53,7 @@ extern inline void crisv32_io_set_dir(struct crisv32_iopin* iopin, *iopin->port->oe |= iopin->bit; } -extern inline int crisv32_io_rd(struct crisv32_iopin* iopin) +static inline int crisv32_io_rd(struct crisv32_iopin* iopin) { return ((*iopin->port->data_in & iopin->bit) ? 1 : 0); } diff --git a/include/asm-cris/arch-v32/system.h b/include/asm-cris/arch-v32/system.h index b9afbb95e0bb35f74e9c88e9374efd6953dd958c..a3d75d581e2f5d20942eeee48df4dde3a3737409 100644 --- a/include/asm-cris/arch-v32/system.h +++ b/include/asm-cris/arch-v32/system.h @@ -4,7 +4,7 @@ #include /* Read the CPU version register. */ -extern inline unsigned long rdvr(void) +static inline unsigned long rdvr(void) { unsigned char vr; @@ -15,7 +15,7 @@ extern inline unsigned long rdvr(void) #define cris_machine_name "crisv32" /* Read the user-mode stack pointer. */ -extern inline unsigned long rdusp(void) +static inline unsigned long rdusp(void) { unsigned long usp; @@ -24,7 +24,7 @@ extern inline unsigned long rdusp(void) } /* Read the current stack pointer. */ -extern inline unsigned long rdsp(void) +static inline unsigned long rdsp(void) { unsigned long sp; diff --git a/include/asm-cris/arch-v32/thread_info.h b/include/asm-cris/arch-v32/thread_info.h index a7a182307da0d2ac7c9fd9f9d0fabe07b9a2bf0e..d6936956a3c6c073fe7e47c5da9399c597d783d1 100644 --- a/include/asm-cris/arch-v32/thread_info.h +++ b/include/asm-cris/arch-v32/thread_info.h @@ -2,7 +2,7 @@ #define _ASM_CRIS_ARCH_THREAD_INFO_H /* Return a thread_info struct. */ -extern inline struct thread_info *current_thread_info(void) +static inline struct thread_info *current_thread_info(void) { struct thread_info *ti; diff --git a/include/asm-cris/arch-v32/timex.h b/include/asm-cris/arch-v32/timex.h index 4d0fd23b21e998084b3dc516adab7ce79c04afcf..5a4aa285d5fdb0c7ffa0a047263c70988979b4f0 100644 --- a/include/asm-cris/arch-v32/timex.h +++ b/include/asm-cris/arch-v32/timex.h @@ -22,7 +22,7 @@ extern unsigned long get_ns_in_jiffie(void); -extern inline unsigned long get_us_in_jiffie_highres(void) +static inline unsigned long get_us_in_jiffie_highres(void) { return get_ns_in_jiffie() / 1000; } diff --git a/include/asm-cris/arch-v32/uaccess.h b/include/asm-cris/arch-v32/uaccess.h index 055a0bdbe835e1bb9c5533a9a53f16819055260a..6b207f1b66227e73e82b22a9712409049a465409 100644 --- a/include/asm-cris/arch-v32/uaccess.h +++ b/include/asm-cris/arch-v32/uaccess.h @@ -93,7 +93,7 @@ * bytes copied if we hit a null byte * (without the null byte) */ -extern inline long +static inline long __do_strncpy_from_user(char *dst, const char *src, long count) { long res; @@ -695,7 +695,7 @@ __do_strncpy_from_user(char *dst, const char *src, long count) * or 0 for error. Return a value greater than N if too long. */ -extern inline long +static inline long strnlen_user(const char *s, long n) { long res, tmp1; diff --git a/include/asm-cris/atomic.h b/include/asm-cris/atomic.h index 70605b09e8b73a324affede0a8887807275fe1c1..8c2e78304523c24da5904dc9b3d85d2988383979 100644 --- a/include/asm-cris/atomic.h +++ b/include/asm-cris/atomic.h @@ -20,7 +20,7 @@ typedef struct { volatile int counter; } atomic_t; /* These should be written in asm but we do it in C for now. */ -extern __inline__ void atomic_add(int i, volatile atomic_t *v) +static inline void atomic_add(int i, volatile atomic_t *v) { unsigned long flags; cris_atomic_save(v, flags); @@ -28,7 +28,7 @@ extern __inline__ void atomic_add(int i, volatile atomic_t *v) cris_atomic_restore(v, flags); } -extern __inline__ void atomic_sub(int i, volatile atomic_t *v) +static inline void atomic_sub(int i, volatile atomic_t *v) { unsigned long flags; cris_atomic_save(v, flags); @@ -36,7 +36,7 @@ extern __inline__ void atomic_sub(int i, volatile atomic_t *v) cris_atomic_restore(v, flags); } -extern __inline__ int atomic_add_return(int i, volatile atomic_t *v) +static inline int atomic_add_return(int i, volatile atomic_t *v) { unsigned long flags; int retval; @@ -48,7 +48,7 @@ extern __inline__ int atomic_add_return(int i, volatile atomic_t *v) #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) -extern __inline__ int atomic_sub_return(int i, volatile atomic_t *v) +static inline int atomic_sub_return(int i, volatile atomic_t *v) { unsigned long flags; int retval; @@ -58,7 +58,7 @@ extern __inline__ int atomic_sub_return(int i, volatile atomic_t *v) return retval; } -extern __inline__ int atomic_sub_and_test(int i, volatile atomic_t *v) +static inline int atomic_sub_and_test(int i, volatile atomic_t *v) { int retval; unsigned long flags; @@ -68,7 +68,7 @@ extern __inline__ int atomic_sub_and_test(int i, volatile atomic_t *v) return retval; } -extern __inline__ void atomic_inc(volatile atomic_t *v) +static inline void atomic_inc(volatile atomic_t *v) { unsigned long flags; cris_atomic_save(v, flags); @@ -76,7 +76,7 @@ extern __inline__ void atomic_inc(volatile atomic_t *v) cris_atomic_restore(v, flags); } -extern __inline__ void atomic_dec(volatile atomic_t *v) +static inline void atomic_dec(volatile atomic_t *v) { unsigned long flags; cris_atomic_save(v, flags); @@ -84,7 +84,7 @@ extern __inline__ void atomic_dec(volatile atomic_t *v) cris_atomic_restore(v, flags); } -extern __inline__ int atomic_inc_return(volatile atomic_t *v) +static inline int atomic_inc_return(volatile atomic_t *v) { unsigned long flags; int retval; @@ -94,7 +94,7 @@ extern __inline__ int atomic_inc_return(volatile atomic_t *v) return retval; } -extern __inline__ int atomic_dec_return(volatile atomic_t *v) +static inline int atomic_dec_return(volatile atomic_t *v) { unsigned long flags; int retval; @@ -103,7 +103,7 @@ extern __inline__ int atomic_dec_return(volatile atomic_t *v) cris_atomic_restore(v, flags); return retval; } -extern __inline__ int atomic_dec_and_test(volatile atomic_t *v) +static inline int atomic_dec_and_test(volatile atomic_t *v) { int retval; unsigned long flags; @@ -113,7 +113,7 @@ extern __inline__ int atomic_dec_and_test(volatile atomic_t *v) return retval; } -extern __inline__ int atomic_inc_and_test(volatile atomic_t *v) +static inline int atomic_inc_and_test(volatile atomic_t *v) { int retval; unsigned long flags; diff --git a/include/asm-cris/bitops.h b/include/asm-cris/bitops.h index e3da57f97964fac5d2141ed8684c6cd9ed45a63f..1bddb3f3a289eddfa320a4519689c3081d9d1c0e 100644 --- a/include/asm-cris/bitops.h +++ b/include/asm-cris/bitops.h @@ -89,7 +89,7 @@ struct __dummy { unsigned long a[100]; }; * It also implies a memory barrier. */ -extern inline int test_and_set_bit(int nr, volatile unsigned long *addr) +static inline int test_and_set_bit(int nr, volatile unsigned long *addr) { unsigned int mask, retval; unsigned long flags; @@ -105,7 +105,7 @@ extern inline int test_and_set_bit(int nr, volatile unsigned long *addr) return retval; } -extern inline int __test_and_set_bit(int nr, volatile unsigned long *addr) +static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) { unsigned int mask, retval; unsigned int *adr = (unsigned int *)addr; @@ -132,7 +132,7 @@ extern inline int __test_and_set_bit(int nr, volatile unsigned long *addr) * It also implies a memory barrier. */ -extern inline int test_and_clear_bit(int nr, volatile unsigned long *addr) +static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) { unsigned int mask, retval; unsigned long flags; @@ -157,7 +157,7 @@ extern inline int test_and_clear_bit(int nr, volatile unsigned long *addr) * but actually fail. You must protect multiple accesses with a lock. */ -extern inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) +static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) { unsigned int mask, retval; unsigned int *adr = (unsigned int *)addr; @@ -177,7 +177,7 @@ extern inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) * It also implies a memory barrier. */ -extern inline int test_and_change_bit(int nr, volatile unsigned long *addr) +static inline int test_and_change_bit(int nr, volatile unsigned long *addr) { unsigned int mask, retval; unsigned long flags; @@ -193,7 +193,7 @@ extern inline int test_and_change_bit(int nr, volatile unsigned long *addr) /* WARNING: non atomic and it can be reordered! */ -extern inline int __test_and_change_bit(int nr, volatile unsigned long *addr) +static inline int __test_and_change_bit(int nr, volatile unsigned long *addr) { unsigned int mask, retval; unsigned int *adr = (unsigned int *)addr; @@ -214,7 +214,7 @@ extern inline int __test_and_change_bit(int nr, volatile unsigned long *addr) * This routine doesn't need to be atomic. */ -extern inline int test_bit(int nr, const volatile unsigned long *addr) +static inline int test_bit(int nr, const volatile unsigned long *addr) { unsigned int mask; unsigned int *adr = (unsigned int *)addr; @@ -258,7 +258,7 @@ extern inline int test_bit(int nr, const volatile unsigned long *addr) * @offset: The bitnumber to start searching at * @size: The maximum size to search */ -extern inline int find_next_zero_bit (const unsigned long * addr, int size, int offset) +static inline int find_next_zero_bit (const unsigned long * addr, int size, int offset) { unsigned long *p = ((unsigned long *) addr) + (offset >> 5); unsigned long result = offset & ~31UL; @@ -366,7 +366,7 @@ static __inline__ int find_next_bit(const unsigned long *addr, int size, int off #define minix_test_bit(nr,addr) test_bit(nr,addr) #define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size) -extern inline int sched_find_first_bit(const unsigned long *b) +static inline int sched_find_first_bit(const unsigned long *b) { if (unlikely(b[0])) return __ffs(b[0]); diff --git a/include/asm-cris/checksum.h b/include/asm-cris/checksum.h index 15ca8aec5c633551af75701419917c8162006516..26a7719bbb840543250a2e4394375409c7a9b849 100644 --- a/include/asm-cris/checksum.h +++ b/include/asm-cris/checksum.h @@ -34,7 +34,7 @@ unsigned int csum_partial_copy_nocheck(const char *src, char *dst, * Fold a partial checksum into a word */ -extern inline unsigned int csum_fold(unsigned int sum) +static inline unsigned int csum_fold(unsigned int sum) { /* the while loop is unnecessary really, it's always enough with two iterations */ @@ -55,7 +55,7 @@ extern unsigned int csum_partial_copy_from_user(const char *src, char *dst, * */ -extern inline unsigned short ip_fast_csum(unsigned char * iph, +static inline unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl) { return csum_fold(csum_partial(iph, ihl * 4, 0)); @@ -66,7 +66,7 @@ extern inline unsigned short ip_fast_csum(unsigned char * iph, * returns a 16-bit checksum, already complemented */ -extern inline unsigned short int csum_tcpudp_magic(unsigned long saddr, +static inline unsigned short int csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, unsigned short len, unsigned short proto, @@ -80,7 +80,7 @@ extern inline unsigned short int csum_tcpudp_magic(unsigned long saddr, * in icmp.c */ -extern inline unsigned short ip_compute_csum(unsigned char * buff, int len) { +static inline unsigned short ip_compute_csum(unsigned char * buff, int len) { return csum_fold (csum_partial(buff, len, 0)); } diff --git a/include/asm-cris/current.h b/include/asm-cris/current.h index dce69c99da39088de75bad41a8a8ca073a75bde1..5f5c0efd00be4a962b2381e02a89a264efd0e737 100644 --- a/include/asm-cris/current.h +++ b/include/asm-cris/current.h @@ -5,7 +5,7 @@ struct task_struct; -extern inline struct task_struct * get_current(void) +static inline struct task_struct * get_current(void) { return current_thread_info()->task; } diff --git a/include/asm-cris/delay.h b/include/asm-cris/delay.h index efc41aad48459aedb07975fbcc623ce32f71909e..d3a39780371993eabf5503b63ffe4432256f35fb 100644 --- a/include/asm-cris/delay.h +++ b/include/asm-cris/delay.h @@ -13,7 +13,7 @@ extern unsigned long loops_per_usec; /* arch/cris/mm/init.c */ -extern __inline__ void udelay(unsigned long usecs) +static inline void udelay(unsigned long usecs) { __delay(usecs * loops_per_usec); } diff --git a/include/asm-cris/io.h b/include/asm-cris/io.h index 16e791b3c721978deb68c56e5ebb17d66b5dac7c..716c69bc58f89be19545b55d13a4d6d4cbe32614 100644 --- a/include/asm-cris/io.h +++ b/include/asm-cris/io.h @@ -23,12 +23,12 @@ extern struct cris_io_operations *cris_iops; * Change virtual addresses to physical addresses and vv. */ -extern inline unsigned long virt_to_phys(volatile void * address) +static inline unsigned long virt_to_phys(volatile void * address) { return __pa(address); } -extern inline void * phys_to_virt(unsigned long address) +static inline void * phys_to_virt(unsigned long address) { return __va(address); } @@ -36,7 +36,7 @@ extern inline void * phys_to_virt(unsigned long address) extern void __iomem * __ioremap(unsigned long offset, unsigned long size, unsigned long flags); extern void __iomem * __ioremap_prot(unsigned long phys_addr, unsigned long size, pgprot_t prot); -extern inline void __iomem * ioremap (unsigned long offset, unsigned long size) +static inline void __iomem * ioremap (unsigned long offset, unsigned long size) { return __ioremap(offset, size, 0); } diff --git a/include/asm-cris/irq.h b/include/asm-cris/irq.h index 4fab5c3b2e15ca4ee294346535d14456145c520e..4b338792218b045ce9593af9f5bac2329f686986 100644 --- a/include/asm-cris/irq.h +++ b/include/asm-cris/irq.h @@ -8,7 +8,7 @@ #include -extern __inline__ int irq_canonicalize(int irq) +static inline int irq_canonicalize(int irq) { return irq; } diff --git a/include/asm-cris/pgalloc.h b/include/asm-cris/pgalloc.h index a131776edf416142874f5c2d5dcd8d6eb9b455cd..deaddfe79bbcd6527f968bc6bc3c4c1087e11440 100644 --- a/include/asm-cris/pgalloc.h +++ b/include/asm-cris/pgalloc.h @@ -11,35 +11,35 @@ * Allocate and free page tables. */ -extern inline pgd_t *pgd_alloc (struct mm_struct *mm) +static inline pgd_t *pgd_alloc (struct mm_struct *mm) { return (pgd_t *)get_zeroed_page(GFP_KERNEL); } -extern inline void pgd_free (pgd_t *pgd) +static inline void pgd_free (pgd_t *pgd) { free_page((unsigned long)pgd); } -extern inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) +static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) { pte_t *pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO); return pte; } -extern inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) +static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) { struct page *pte; pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0); return pte; } -extern inline void pte_free_kernel(pte_t *pte) +static inline void pte_free_kernel(pte_t *pte) { free_page((unsigned long)pte); } -extern inline void pte_free(struct page *pte) +static inline void pte_free(struct page *pte) { __free_page(pte); } diff --git a/include/asm-cris/pgtable.h b/include/asm-cris/pgtable.h index a9143bed99db6908c6f63dfe32c8e00b97887058..70a832514f62ba7cda4097e5de7b49c1e73d3f0d 100644 --- a/include/asm-cris/pgtable.h +++ b/include/asm-cris/pgtable.h @@ -112,44 +112,44 @@ extern unsigned long empty_zero_page; * Undefined behaviour if not.. */ -extern inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_READ; } -extern inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; } -extern inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_READ; } -extern inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_MODIFIED; } -extern inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } -extern inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } - -extern inline pte_t pte_wrprotect(pte_t pte) +static inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_READ; } +static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; } +static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_READ; } +static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_MODIFIED; } +static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } +static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } + +static inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) &= ~(_PAGE_WRITE | _PAGE_SILENT_WRITE); return pte; } -extern inline pte_t pte_rdprotect(pte_t pte) +static inline pte_t pte_rdprotect(pte_t pte) { pte_val(pte) &= ~(_PAGE_READ | _PAGE_SILENT_READ); return pte; } -extern inline pte_t pte_exprotect(pte_t pte) +static inline pte_t pte_exprotect(pte_t pte) { pte_val(pte) &= ~(_PAGE_READ | _PAGE_SILENT_READ); return pte; } -extern inline pte_t pte_mkclean(pte_t pte) +static inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~(_PAGE_MODIFIED | _PAGE_SILENT_WRITE); return pte; } -extern inline pte_t pte_mkold(pte_t pte) +static inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~(_PAGE_ACCESSED | _PAGE_SILENT_READ); return pte; } -extern inline pte_t pte_mkwrite(pte_t pte) +static inline pte_t pte_mkwrite(pte_t pte) { pte_val(pte) |= _PAGE_WRITE; if (pte_val(pte) & _PAGE_MODIFIED) @@ -157,7 +157,7 @@ extern inline pte_t pte_mkwrite(pte_t pte) return pte; } -extern inline pte_t pte_mkread(pte_t pte) +static inline pte_t pte_mkread(pte_t pte) { pte_val(pte) |= _PAGE_READ; if (pte_val(pte) & _PAGE_ACCESSED) @@ -165,7 +165,7 @@ extern inline pte_t pte_mkread(pte_t pte) return pte; } -extern inline pte_t pte_mkexec(pte_t pte) +static inline pte_t pte_mkexec(pte_t pte) { pte_val(pte) |= _PAGE_READ; if (pte_val(pte) & _PAGE_ACCESSED) @@ -173,7 +173,7 @@ extern inline pte_t pte_mkexec(pte_t pte) return pte; } -extern inline pte_t pte_mkdirty(pte_t pte) +static inline pte_t pte_mkdirty(pte_t pte) { pte_val(pte) |= _PAGE_MODIFIED; if (pte_val(pte) & _PAGE_WRITE) @@ -181,7 +181,7 @@ extern inline pte_t pte_mkdirty(pte_t pte) return pte; } -extern inline pte_t pte_mkyoung(pte_t pte) +static inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= _PAGE_ACCESSED; if (pte_val(pte) & _PAGE_READ) @@ -205,7 +205,7 @@ extern inline pte_t pte_mkyoung(pte_t pte) * addresses (the 0xc0xxxxxx's) goes as void *'s. */ -extern inline pte_t __mk_pte(void * page, pgprot_t pgprot) +static inline pte_t __mk_pte(void * page, pgprot_t pgprot) { pte_t pte; /* the PTE needs a physical address */ @@ -223,7 +223,7 @@ extern inline pte_t __mk_pte(void * page, pgprot_t pgprot) __pte; \ }) -extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; } @@ -232,7 +232,7 @@ extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot) * pte_pagenr refers to the page-number counted starting from the virtual DRAM start */ -extern inline unsigned long __pte_page(pte_t pte) +static inline unsigned long __pte_page(pte_t pte) { /* the PTE contains a physical address */ return (unsigned long)__va(pte_val(pte) & PAGE_MASK); @@ -250,7 +250,7 @@ extern inline unsigned long __pte_page(pte_t pte) * don't need the __pa and __va transformations. */ -extern inline void pmd_set(pmd_t * pmdp, pte_t * ptep) +static inline void pmd_set(pmd_t * pmdp, pte_t * ptep) { pmd_val(*pmdp) = _PAGE_TABLE | (unsigned long) ptep; } #define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)) @@ -260,7 +260,7 @@ extern inline void pmd_set(pmd_t * pmdp, pte_t * ptep) #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) /* to find an entry in a page-table-directory */ -extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address) +static inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address) { return mm->pgd + pgd_index(address); } @@ -296,7 +296,7 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; /* defined in head.S */ * * Actually I am not sure on what this could be used for. */ -extern inline void update_mmu_cache(struct vm_area_struct * vma, +static inline void update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte) { } diff --git a/include/asm-cris/processor.h b/include/asm-cris/processor.h index 0dc218117bd83df881c93c51942e75d8a49e11a3..dce41009eeb086a17811c7e1095709672ddedac4 100644 --- a/include/asm-cris/processor.h +++ b/include/asm-cris/processor.h @@ -16,6 +16,8 @@ #include #include +struct task_struct; + /* This decides where the kernel will search for a free chunk of vm * space during mmap's. */ @@ -45,7 +47,7 @@ #define current_regs() user_regs(current->thread_info) -extern inline void prepare_to_copy(struct task_struct *tsk) +static inline void prepare_to_copy(struct task_struct *tsk) { } @@ -58,7 +60,7 @@ unsigned long get_wchan(struct task_struct *p); extern unsigned long thread_saved_pc(struct task_struct *tsk); /* Free all resources held by a thread. */ -extern inline void release_thread(struct task_struct *dead_task) +static inline void release_thread(struct task_struct *dead_task) { /* Nothing needs to be done. */ } diff --git a/include/asm-cris/semaphore.h b/include/asm-cris/semaphore.h index 39faf69bcf766523a7ad34e019b9ce63e40de2c5..53f548b791c18ebb8456c1b593a0f38b95e557cb 100644 --- a/include/asm-cris/semaphore.h +++ b/include/asm-cris/semaphore.h @@ -18,8 +18,6 @@ * CRIS semaphores, implemented in C-only so far. */ -int printk(const char *fmt, ...); - struct semaphore { atomic_t count; atomic_t waking; @@ -39,17 +37,17 @@ struct semaphore { #define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) #define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0) -extern inline void sema_init(struct semaphore *sem, int val) +static inline void sema_init(struct semaphore *sem, int val) { *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val); } -extern inline void init_MUTEX (struct semaphore *sem) +static inline void init_MUTEX (struct semaphore *sem) { sema_init(sem, 1); } -extern inline void init_MUTEX_LOCKED (struct semaphore *sem) +static inline void init_MUTEX_LOCKED (struct semaphore *sem) { sema_init(sem, 0); } @@ -61,7 +59,7 @@ extern void __up(struct semaphore * sem); /* notice - we probably can do cli/sti here instead of saving */ -extern inline void down(struct semaphore * sem) +static inline void down(struct semaphore * sem) { unsigned long flags; int failed; @@ -83,7 +81,7 @@ extern inline void down(struct semaphore * sem) * returns negative for signalled and zero for semaphore acquired. */ -extern inline int down_interruptible(struct semaphore * sem) +static inline int down_interruptible(struct semaphore * sem) { unsigned long flags; int failed; @@ -99,7 +97,7 @@ extern inline int down_interruptible(struct semaphore * sem) return(failed); } -extern inline int down_trylock(struct semaphore * sem) +static inline int down_trylock(struct semaphore * sem) { unsigned long flags; int failed; @@ -119,7 +117,7 @@ extern inline int down_trylock(struct semaphore * sem) * The default case (no contention) will result in NO * jumps for both down() and up(). */ -extern inline void up(struct semaphore * sem) +static inline void up(struct semaphore * sem) { unsigned long flags; int wakeup; diff --git a/include/asm-cris/system.h b/include/asm-cris/system.h index e06739806d4e4928e1c55094196899e7cacfe158..d48670107a85ffe05c0e1257a94678f6f3389e6f 100644 --- a/include/asm-cris/system.h +++ b/include/asm-cris/system.h @@ -41,7 +41,7 @@ extern struct task_struct *resume(struct task_struct *prev, struct task_struct * void disable_hlt(void); void enable_hlt(void); -extern inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) +static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) { /* since Etrax doesn't have any atomic xchg instructions, we need to disable irq's (if enabled) and do it with move.d's */ diff --git a/include/asm-cris/timex.h b/include/asm-cris/timex.h index 3fb069a3771761314edc9de8d1a08ffe9f55d367..b92e0e80fe86fdfcd2cbe2f42b8036d9492e63c2 100644 --- a/include/asm-cris/timex.h +++ b/include/asm-cris/timex.h @@ -16,7 +16,7 @@ typedef unsigned long long cycles_t; -extern inline cycles_t get_cycles(void) +static inline cycles_t get_cycles(void) { return 0; } diff --git a/include/asm-cris/tlbflush.h b/include/asm-cris/tlbflush.h index 6ed7d9ae90db5497d03cb2e31e17e3e2dc38c7e7..c52238005b5592539be59892b8ef61a4bf1a3380 100644 --- a/include/asm-cris/tlbflush.h +++ b/include/asm-cris/tlbflush.h @@ -39,14 +39,14 @@ static inline void flush_tlb_range(struct vm_area_struct * vma, unsigned long st flush_tlb_mm(vma->vm_mm); } -extern inline void flush_tlb_pgtables(struct mm_struct *mm, +static inline void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start, unsigned long end) { /* CRIS does not keep any page table caches in TLB */ } -extern inline void flush_tlb(void) +static inline void flush_tlb(void) { flush_tlb_mm(current->mm); } diff --git a/include/asm-cris/uaccess.h b/include/asm-cris/uaccess.h index 7d50086eb5ea08a6de01e4f4f4f7735a2ec4eee0..69d48a2dc8e13ee15fa7c493fbe89eadc9bbaac9 100644 --- a/include/asm-cris/uaccess.h +++ b/include/asm-cris/uaccess.h @@ -213,7 +213,7 @@ extern unsigned long __copy_user(void *to, const void *from, unsigned long n); extern unsigned long __copy_user_zeroing(void *to, const void *from, unsigned long n); extern unsigned long __do_clear_user(void *to, unsigned long n); -extern inline unsigned long +static inline unsigned long __generic_copy_to_user(void __user *to, const void *from, unsigned long n) { if (access_ok(VERIFY_WRITE, to, n)) @@ -221,7 +221,7 @@ __generic_copy_to_user(void __user *to, const void *from, unsigned long n) return n; } -extern inline unsigned long +static inline unsigned long __generic_copy_from_user(void *to, const void __user *from, unsigned long n) { if (access_ok(VERIFY_READ, from, n)) @@ -229,7 +229,7 @@ __generic_copy_from_user(void *to, const void __user *from, unsigned long n) return n; } -extern inline unsigned long +static inline unsigned long __generic_clear_user(void __user *to, unsigned long n) { if (access_ok(VERIFY_WRITE, to, n)) @@ -237,13 +237,13 @@ __generic_clear_user(void __user *to, unsigned long n) return n; } -extern inline long +static inline long __strncpy_from_user(char *dst, const char __user *src, long count) { return __do_strncpy_from_user(dst, src, count); } -extern inline long +static inline long strncpy_from_user(char *dst, const char __user *src, long count) { long res = -EFAULT; @@ -256,7 +256,7 @@ strncpy_from_user(char *dst, const char __user *src, long count) /* Note that if these expand awfully if made into switch constructs, so don't do that. */ -extern inline unsigned long +static inline unsigned long __constant_copy_from_user(void *to, const void __user *from, unsigned long n) { unsigned long ret = 0; @@ -306,7 +306,7 @@ __constant_copy_from_user(void *to, const void __user *from, unsigned long n) /* Ditto, don't make a switch out of this. */ -extern inline unsigned long +static inline unsigned long __constant_copy_to_user(void __user *to, const void *from, unsigned long n) { unsigned long ret = 0; @@ -356,7 +356,7 @@ __constant_copy_to_user(void __user *to, const void *from, unsigned long n) /* No switch, please. */ -extern inline unsigned long +static inline unsigned long __constant_clear_user(void __user *to, unsigned long n) { unsigned long ret = 0; @@ -406,19 +406,19 @@ __constant_clear_user(void __user *to, unsigned long n) * used in fast paths and have only a small space overhead. */ -extern inline unsigned long +static inline unsigned long __generic_copy_from_user_nocheck(void *to, const void *from, unsigned long n) { return __copy_user_zeroing(to,from,n); } -extern inline unsigned long +static inline unsigned long __generic_copy_to_user_nocheck(void *to, const void *from, unsigned long n) { return __copy_user(to,from,n); } -extern inline unsigned long +static inline unsigned long __generic_clear_user_nocheck(void *to, unsigned long n) { return __do_clear_user(to,n); diff --git a/include/asm-cris/unistd.h b/include/asm-cris/unistd.h index 156a34bfc583b853b1d2970171602e592665c972..2627bbdf8a1144e78c5a85584f86a152640ddb43 100644 --- a/include/asm-cris/unistd.h +++ b/include/asm-cris/unistd.h @@ -343,14 +343,14 @@ * some others too. */ #define __NR__exit __NR_exit -extern inline _syscall0(pid_t,setsid) -extern inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) -extern inline _syscall3(int,read,int,fd,char *,buf,off_t,count) -extern inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) -extern inline _syscall1(int,dup,int,fd) -extern inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) -extern inline _syscall3(int,open,const char *,file,int,flag,int,mode) -extern inline _syscall1(int,close,int,fd) +static inline _syscall0(pid_t,setsid) +static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) +static inline _syscall3(int,read,int,fd,char *,buf,off_t,count) +static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) +static inline _syscall1(int,dup,int,fd) +static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) +static inline _syscall3(int,open,const char *,file,int,flag,int,mode) +static inline _syscall1(int,close,int,fd) struct pt_regs; asmlinkage long sys_mmap2( @@ -382,8 +382,8 @@ asmlinkage long sys_rt_sigaction(int sig, #ifdef __KERNEL__ #define _exit kernel_syscall_exit #endif -extern inline _syscall1(int,_exit,int,exitcode) -extern inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) +static inline _syscall1(int,_exit,int,exitcode) +static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) #endif diff --git a/include/asm-frv/pgtable.h b/include/asm-frv/pgtable.h index b247e99dff49a830ee3af8d3e833d80e6087acde..844666377dcbfc45db86c4b33d5c9ec431fb4907 100644 --- a/include/asm-frv/pgtable.h +++ b/include/asm-frv/pgtable.h @@ -26,6 +26,8 @@ #include #include #include +struct mm_struct; +struct vm_area_struct; #endif #ifndef __ASSEMBLY__ diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h index 7dca30a26c536305e6ad75dde33c9a9d35801b68..358e4d309ceb179776f2a7036dabce02cdfad1d2 100644 --- a/include/asm-generic/pgtable.h +++ b/include/asm-generic/pgtable.h @@ -128,6 +128,7 @@ do { \ #endif #ifndef __HAVE_ARCH_PTEP_SET_WRPROTECT +struct mm_struct; static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long address, pte_t *ptep) { pte_t old_pte = *ptep; diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index a9c55490fb8238e78584176bdb6002a6bd38432e..094d4917c1a9a908b9416eba618aa24217112e7a 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -35,6 +35,13 @@ VMLINUX_SYMBOL(__end_pci_fixups_enable) = .; \ } \ \ + /* RapidIO route ops */ \ + .rio_route : AT(ADDR(.rio_route) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start_rio_route_ops) = .; \ + *(.rio_route_ops) \ + VMLINUX_SYMBOL(__end_rio_route_ops) = .; \ + } \ + \ /* Kernel symbol table: Normal symbols */ \ __ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___ksymtab) = .; \ diff --git a/include/asm-i386/elf.h b/include/asm-i386/elf.h index fa11117d3cfac32de2b2e6b3694c8d65f56b5ac5..4153d80e4d2b86535a6e55a6e72a30ba7b5b5699 100644 --- a/include/asm-i386/elf.h +++ b/include/asm-i386/elf.h @@ -119,6 +119,8 @@ typedef struct user_fxsr_struct elf_fpxregset_t; */ #define elf_read_implies_exec(ex, executable_stack) (executable_stack != EXSTACK_DISABLE_X) +struct task_struct; + extern int dump_task_regs (struct task_struct *, elf_gregset_t *); extern int dump_task_fpu (struct task_struct *, elf_fpregset_t *); extern int dump_task_extended_fpu (struct task_struct *, struct user_fxsr_struct *); diff --git a/include/asm-i386/kprobes.h b/include/asm-i386/kprobes.h index 8b6d3a90cd78942f1a48bf1e0625f6df22e77e53..ca916a892877edaddd26d048f74a33352dc6cd8f 100644 --- a/include/asm-i386/kprobes.h +++ b/include/asm-i386/kprobes.h @@ -49,6 +49,23 @@ struct arch_specific_insn { kprobe_opcode_t insn[MAX_INSN_SIZE]; }; +struct prev_kprobe { + struct kprobe *kp; + unsigned long status; + unsigned long old_eflags; + unsigned long saved_eflags; +}; + +/* per-cpu kprobe control block */ +struct kprobe_ctlblk { + unsigned long kprobe_status; + unsigned long kprobe_old_eflags; + unsigned long kprobe_saved_eflags; + long *jprobe_saved_esp; + struct pt_regs jprobe_saved_regs; + kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE]; + struct prev_kprobe prev_kprobe; +}; /* trap3/1 are intr gates for kprobes. So, restore the status of IF, * if necessary, before executing the original int3/1 (trap) handler. diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h index 03f3c8ac6383a4d7f874e12869b56f7ba45f1414..088a945bf26bdb5ef02f8b5a0397e32ee3955214 100644 --- a/include/asm-i386/pgtable.h +++ b/include/asm-i386/pgtable.h @@ -25,6 +25,9 @@ #include #include +struct mm_struct; +struct vm_area_struct; + /* * ZERO_PAGE is a global shared page that is always zero: used * for zero-mapped memory areas etc.. diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h index 0a4ec764377ca1aa0db8c607a35e9ddfd586d297..8c02b0318703b4c9cf8d68e665949215f97455d6 100644 --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h @@ -718,4 +718,10 @@ extern void mtrr_bp_init(void); #define mtrr_bp_init() do {} while (0) #endif +#ifdef CONFIG_X86_MCE +extern void mcheck_init(struct cpuinfo_x86 *c); +#else +#define mcheck_init(c) do {} while(0) +#endif + #endif /* __ASM_I386_PROCESSOR_H */ diff --git a/include/asm-ia64/dma-mapping.h b/include/asm-ia64/dma-mapping.h index 6347c9845642658031649d9eada3de509c888455..df67d40801de9ac9dc2041145927c251e7e5c7c5 100644 --- a/include/asm-ia64/dma-mapping.h +++ b/include/asm-ia64/dma-mapping.h @@ -48,12 +48,7 @@ dma_set_mask (struct device *dev, u64 mask) return 0; } -static inline int -dma_get_cache_alignment (void) -{ - extern int ia64_max_cacheline_size; - return ia64_max_cacheline_size; -} +extern int dma_get_cache_alignment(void); static inline void dma_cache_sync (void *vaddr, size_t size, enum dma_data_direction dir) diff --git a/include/asm-ia64/kprobes.h b/include/asm-ia64/kprobes.h index 573a3574a24fe86ebcd4ecb5be7800c3057b4df5..592abb000e29bc9260257a5f9fb806eae367a21d 100644 --- a/include/asm-ia64/kprobes.h +++ b/include/asm-ia64/kprobes.h @@ -26,6 +26,7 @@ */ #include #include +#include #include #define MAX_INSN_SIZE 16 @@ -62,6 +63,18 @@ typedef struct _bundle { } quad1; } __attribute__((__aligned__(16))) bundle_t; +struct prev_kprobe { + struct kprobe *kp; + unsigned long status; +}; + +/* per-cpu kprobe control block */ +struct kprobe_ctlblk { + unsigned long kprobe_status; + struct pt_regs jprobe_saved_regs; + struct prev_kprobe prev_kprobe; +}; + #define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry #define ARCH_SUPPORTS_KRETPROBES diff --git a/include/asm-ia64/page.h b/include/asm-ia64/page.h index ef436b9d06ad4580923f65c78c9ceac3a14e8942..9d41548b7fef43d1f98abbbb1a5dfaa371c9a031 100644 --- a/include/asm-ia64/page.h +++ b/include/asm-ia64/page.h @@ -120,6 +120,7 @@ extern unsigned long max_low_pfn; #define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) +#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) typedef union ia64_va { struct { diff --git a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h index 21e32a06bc82c110e4870358b0d5e913a588ae1a..c34ba80c1c31fcdd80c94cf7ec32981348f3c609 100644 --- a/include/asm-ia64/pgtable.h +++ b/include/asm-ia64/pgtable.h @@ -127,6 +127,7 @@ # ifndef __ASSEMBLY__ +#include /* for mm_struct */ #include #include #include diff --git a/include/asm-ia64/ptrace.h b/include/asm-ia64/ptrace.h index a79d1a7ecc77e758c1e187facf736b1e39441fbb..2c703d6e0c8630aa234039d0ebdca4d9ce04dc09 100644 --- a/include/asm-ia64/ptrace.h +++ b/include/asm-ia64/ptrace.h @@ -229,6 +229,9 @@ struct switch_stack { }; #ifdef __KERNEL__ + +#define __ARCH_SYS_PTRACE 1 + /* * We use the ia64_psr(regs)->ri to determine which of the three * instructions in bundle (16 bytes) took the sample. Generate diff --git a/include/asm-m32r/pgtable.h b/include/asm-m32r/pgtable.h index 1cd5fd4a5b2cea4813f9e58e13db466b114baa4d..75740debcd01e0c46842c6aee002e0d28fb216b7 100644 --- a/include/asm-m32r/pgtable.h +++ b/include/asm-m32r/pgtable.h @@ -27,6 +27,9 @@ #include #include +struct mm_struct; +struct vm_area_struct; + extern pgd_t swapper_pg_dir[1024]; extern void paging_init(void); diff --git a/include/asm-m32r/ptrace.h b/include/asm-m32r/ptrace.h index 976417126b2d96812c2824a431bc9e256f702b30..55cd7ecfde4370c6f34c1e88bef4df48e18b6643 100644 --- a/include/asm-m32r/ptrace.h +++ b/include/asm-m32r/ptrace.h @@ -145,6 +145,9 @@ struct pt_regs { #define PTRACE_O_TRACESYSGOOD 0x00000001 #ifdef __KERNEL__ + +#define __ARCH_SYS_PTRACE 1 + #if defined(CONFIG_ISA_M32R2) || defined(CONFIG_CHIP_VDEC2) #define user_mode(regs) ((M32R_PSW_BPM & (regs)->psw) != 0) #elif defined(CONFIG_ISA_M32R) diff --git a/include/asm-m68k/kbio.h b/include/asm-m68k/kbio.h deleted file mode 100644 index e1fbf8fba3e88d92fb575f44136498fef149f27b..0000000000000000000000000000000000000000 --- a/include/asm-m68k/kbio.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/include/asm-m68k/vuid_event.h b/include/asm-m68k/vuid_event.h deleted file mode 100644 index 52ecb521a3958acf94fd8ca5cfe332aa0fc89f86..0000000000000000000000000000000000000000 --- a/include/asm-m68k/vuid_event.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef _M68K_VUID_EVENT_H -#define _M68K_VUID_EVENT_H -#include -#endif diff --git a/include/asm-m68knommu/cacheflush.h b/include/asm-m68knommu/cacheflush.h index 026bbc9565b428b4270ae0d759268ab0a4f36fd0..49925e91e89ce341b40a0f98eb863e6a767949e4 100644 --- a/include/asm-m68knommu/cacheflush.h +++ b/include/asm-m68knommu/cacheflush.h @@ -25,7 +25,7 @@ #define copy_from_user_page(vma, page, vaddr, dst, src, len) \ memcpy(dst, src, len) -extern inline void __flush_cache_all(void) +static inline void __flush_cache_all(void) { #ifdef CONFIG_M5407 /* @@ -64,7 +64,7 @@ extern inline void __flush_cache_all(void) "nop\n\t" : : : "d0" ); #endif /* CONFIG_M5272 */ -#if CONFIG_M5249 +#ifdef CONFIG_M5249 __asm__ __volatile__ ( "movel #0xa1000200, %%d0\n\t" "movec %%d0, %%CACR\n\t" diff --git a/include/asm-m68knommu/irq.h b/include/asm-m68knommu/irq.h index 208ccd969e4bd39ce9af1d39efc464a9c20dcab3..a08fa9b958dab2cc122a5ca5e755454c5bd34495 100644 --- a/include/asm-m68knommu/irq.h +++ b/include/asm-m68knommu/irq.h @@ -2,7 +2,6 @@ #define _M68K_IRQ_H_ #include -#include #include #ifdef CONFIG_COLDFIRE @@ -82,36 +81,6 @@ extern void (*mach_disable_irq)(unsigned int); #endif /* CONFIG_M68360 */ -/* - * This structure is used to chain together the ISRs for a particular - * interrupt source (if it supports chaining). - */ -typedef struct irq_node { - irqreturn_t (*handler)(int, void *, struct pt_regs *); - unsigned long flags; - void *dev_id; - const char *devname; - struct irq_node *next; -} irq_node_t; - -/* - * This structure has only 4 elements for speed reasons - */ -typedef struct irq_handler { - irqreturn_t (*handler)(int, void *, struct pt_regs *); - unsigned long flags; - void *dev_id; - const char *devname; -} irq_handler_t; - -/* count of spurious interrupts */ -extern volatile unsigned int num_spurious; - -/* - * This function returns a new irq_node_t - */ -extern irq_node_t *new_irq_node(void); - /* * Some drivers want these entry points */ diff --git a/include/asm-m68knommu/irqnode.h b/include/asm-m68knommu/irqnode.h new file mode 100644 index 0000000000000000000000000000000000000000..a2503dfc554c59dbc60cbed803d1f464062463de --- /dev/null +++ b/include/asm-m68knommu/irqnode.h @@ -0,0 +1,36 @@ +#ifndef _M68K_IRQNODE_H_ +#define _M68K_IRQNODE_H_ + +#include + +/* + * This structure is used to chain together the ISRs for a particular + * interrupt source (if it supports chaining). + */ +typedef struct irq_node { + irqreturn_t (*handler)(int, void *, struct pt_regs *); + unsigned long flags; + void *dev_id; + const char *devname; + struct irq_node *next; +} irq_node_t; + +/* + * This structure has only 4 elements for speed reasons + */ +typedef struct irq_handler { + irqreturn_t (*handler)(int, void *, struct pt_regs *); + unsigned long flags; + void *dev_id; + const char *devname; +} irq_handler_t; + +/* count of spurious interrupts */ +extern volatile unsigned int num_spurious; + +/* + * This function returns a new irq_node_t + */ +extern irq_node_t *new_irq_node(void); + +#endif /* _M68K_IRQNODE_H_ */ diff --git a/include/asm-mips/.gitignore b/include/asm-mips/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..4ec57ad5bc3cd85fa9cdd27f8f90bec1b06da2e3 --- /dev/null +++ b/include/asm-mips/.gitignore @@ -0,0 +1 @@ +asm_offsets.h diff --git a/include/asm-mips/delay.h b/include/asm-mips/delay.h index 85435a8d4e52d4287f2328a2cff093437ccbae96..48d00cccdafa9a5f490b47c1407a7ce14fa0a1a0 100644 --- a/include/asm-mips/delay.h +++ b/include/asm-mips/delay.h @@ -84,4 +84,13 @@ static inline void __udelay(unsigned long usecs, unsigned long lpj) #define udelay(usecs) __udelay((usecs),__udelay_val) +/* make sure "usecs *= ..." in udelay do not overflow. */ +#if HZ >= 1000 +#define MAX_UDELAY_MS 1 +#elif HZ <= 200 +#define MAX_UDELAY_MS 5 +#else +#define MAX_UDELAY_MS (1000 / HZ) +#endif + #endif /* _ASM_DELAY_H */ diff --git a/include/asm-mips/elf.h b/include/asm-mips/elf.h index 7420f12742bb92c5d6d41068d8b2f1e8f772e51b..d2c9a25f8459cab60a6a3e86438ab7c5ad43f2fc 100644 --- a/include/asm-mips/elf.h +++ b/include/asm-mips/elf.h @@ -275,6 +275,8 @@ do { \ #endif /* CONFIG_64BIT */ +struct task_struct; + extern void dump_regs(elf_greg_t *, struct pt_regs *regs); extern int dump_task_regs (struct task_struct *, elf_gregset_t *); extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *); diff --git a/include/asm-mips/errno.h b/include/asm-mips/errno.h index 9d3e6e7cdb9212db444705b88b8e2faa9c6e4f1a..3c0d840e45773e867980116affb51aae255273f5 100644 --- a/include/asm-mips/errno.h +++ b/include/asm-mips/errno.h @@ -119,10 +119,6 @@ #define EOWNERDEAD 165 /* Owner died */ #define ENOTRECOVERABLE 166 /* State not recoverable */ -/* for robust mutexes */ -#define EOWNERDEAD 165 /* Owner died */ -#define ENOTRECOVERABLE 166 /* State not recoverable */ - #define EDQUOT 1133 /* Quota exceeded */ #ifdef __KERNEL__ diff --git a/include/asm-mips/ip32/mace.h b/include/asm-mips/ip32/mace.h index 432011b16c2671eb51af1a5493af229b13cf1e02..5bdc51d85b6c2d5f7d792ee63b76624116daa085 100644 --- a/include/asm-mips/ip32/mace.h +++ b/include/asm-mips/ip32/mace.h @@ -147,6 +147,29 @@ struct mace_audio { } chan[3]; }; + +/* register definitions for parallel port DMA */ +struct mace_parport { +/* 0 - do nothing, 1 - pulse terminal count to the device after buffer is drained */ +#define MACEPAR_CONTEXT_LASTFLAG BIT(63) +/* Should not cross 4K page boundary */ +#define MACEPAR_CONTEXT_DATALEN_MASK 0xfff00000000 +/* Can be arbitrarily aligned on any byte boundary on output, 64 byte aligned on input */ +#define MACEPAR_CONTEXT_BASEADDR_MASK 0xffffffff + volatile u64 context_a; + volatile u64 context_b; +#define MACEPAR_CTLSTAT_DIRECTION BIT(0) /* 0 - mem->device, 1 - device->mem */ +#define MACEPAR_CTLSTAT_ENABLE BIT(1) /* 0 - channel frozen, 1 - channel enabled */ +#define MACEPAR_CTLSTAT_RESET BIT(2) /* 0 - channel active, 1 - complete channel reset */ +#define MACEPAR_CTLSTAT_CTXB_VALID BIT(3) +#define MACEPAR_CTLSTAT_CTXA_VALID BIT(4) + volatile u64 cntlstat; /* Control/Status register */ +#define MACEPAR_DIAG_CTXINUSE BIT(1) +#define MACEPAR_DIAG_DMACTIVE BIT(2) /* 1 - Dma engine is enabled and processing something */ +#define MACEPAR_DIAG_CTRMASK 0x3ffc /* Counter of bytes left */ + volatile u64 diagnostic; /* RO: diagnostic register */ +}; + /* ISA Control and DMA registers */ struct mace_isactrl { volatile unsigned long ringbase; @@ -199,6 +222,7 @@ struct mace_isactrl { volatile unsigned long _pad[0x2000/8 - 4]; volatile unsigned long dp_ram[0x400]; + struct mace_parport parport; }; /* Keyboard & Mouse registers @@ -277,7 +301,7 @@ struct mace_perif { */ /* Parallel port */ -struct mace_parallel { /* later... */ +struct mace_parallel { }; struct mace_ecp1284 { /* later... */ diff --git a/include/asm-mips/mach-generic/ide.h b/include/asm-mips/mach-generic/ide.h index 961006948c7c9d5172fde3e7e6479ecd07e11239..550979a9ea9d21432fe0a8570f73d9cf294df4be 100644 --- a/include/asm-mips/mach-generic/ide.h +++ b/include/asm-mips/mach-generic/ide.h @@ -168,8 +168,12 @@ static inline void __ide_mm_outsl(void __iomem * port, void *addr, u32 count) /* ide_insw calls insw, not __ide_insw. Why? */ #undef insw #undef insl +#undef outsw +#undef outsl #define insw(port, addr, count) __ide_insw(port, addr, count) #define insl(port, addr, count) __ide_insl(port, addr, count) +#define outsw(port, addr, count) __ide_outsw(port, addr, count) +#define outsl(port, addr, count) __ide_outsl(port, addr, count) #endif /* __KERNEL__ */ diff --git a/include/asm-mips/mc146818-time.h b/include/asm-mips/mc146818-time.h index a2c2d2c2430329050b1bde7bf6b2d43f8cc5d1e0..47214861093be33cca0822da379e4aff54a274d8 100644 --- a/include/asm-mips/mc146818-time.h +++ b/include/asm-mips/mc146818-time.h @@ -33,7 +33,9 @@ static inline int mc146818_set_rtc_mmss(unsigned long nowtime) int real_seconds, real_minutes, cmos_minutes; unsigned char save_control, save_freq_select; int retval = 0; + unsigned long flags; + spin_lock_irqsave(&rtc_lock, flags); save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); @@ -79,14 +81,30 @@ static inline int mc146818_set_rtc_mmss(unsigned long nowtime) */ CMOS_WRITE(save_control, RTC_CONTROL); CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + spin_unlock_irqrestore(&rtc_lock, flags); return retval; } +/* + * Returns true if a clock update is in progress + */ +static inline unsigned char rtc_is_updating(void) +{ + unsigned char uip; + unsigned long flags; + + spin_lock_irqsave(&rtc_lock, flags); + uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); + spin_unlock_irqrestore(&rtc_lock, flags); + return uip; +} + static inline unsigned long mc146818_get_cmos_time(void) { unsigned int year, mon, day, hour, min, sec; int i; + unsigned long flags; /* * The Linux interpretation of the CMOS clock register contents: @@ -97,12 +115,13 @@ static inline unsigned long mc146818_get_cmos_time(void) /* read RTC exactly on falling edge of update flag */ for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ - if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) + if (rtc_is_updating()) break; for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ - if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) + if (!rtc_is_updating()) break; + spin_lock_irqsave(&rtc_lock, flags); do { /* Isn't this overkill ? UIP above should guarantee consistency */ sec = CMOS_READ(RTC_SECONDS); min = CMOS_READ(RTC_MINUTES); @@ -120,6 +139,7 @@ static inline unsigned long mc146818_get_cmos_time(void) BCD_TO_BIN(mon); BCD_TO_BIN(year); } + spin_unlock_irqrestore(&rtc_lock, flags); year = mc146818_decode_year(year); return mktime(year, mon, day, hour, min, sec); diff --git a/include/asm-mips/module.h b/include/asm-mips/module.h index 2be399311eecd83c0168ff8db589bc1f18732563..2af496c78c12a08f72d103070be8cd928f1e0d17 100644 --- a/include/asm-mips/module.h +++ b/include/asm-mips/module.h @@ -76,43 +76,43 @@ search_module_dbetables(unsigned long addr) #endif #ifdef CONFIG_CPU_MIPS32_R1 -#define MODULE_PROC_FAMILY "MIPS32_R1" +#define MODULE_PROC_FAMILY "MIPS32_R1 " #elif defined CONFIG_CPU_MIPS32_R2 -#define MODULE_PROC_FAMILY "MIPS32_R2" +#define MODULE_PROC_FAMILY "MIPS32_R2 " #elif defined CONFIG_CPU_MIPS64_R1 -#define MODULE_PROC_FAMILY "MIPS64_R1" +#define MODULE_PROC_FAMILY "MIPS64_R1 " #elif defined CONFIG_CPU_MIPS64_R2 -#define MODULE_PROC_FAMILY "MIPS64_R2" +#define MODULE_PROC_FAMILY "MIPS64_R2 " #elif defined CONFIG_CPU_R3000 -#define MODULE_PROC_FAMILY "R3000" +#define MODULE_PROC_FAMILY "R3000 " #elif defined CONFIG_CPU_TX39XX -#define MODULE_PROC_FAMILY "TX39XX" +#define MODULE_PROC_FAMILY "TX39XX " #elif defined CONFIG_CPU_VR41XX -#define MODULE_PROC_FAMILY "VR41XX" +#define MODULE_PROC_FAMILY "VR41XX " #elif defined CONFIG_CPU_R4300 -#define MODULE_PROC_FAMILY "R4300" +#define MODULE_PROC_FAMILY "R4300 " #elif defined CONFIG_CPU_R4X00 -#define MODULE_PROC_FAMILY "R4X00" +#define MODULE_PROC_FAMILY "R4X00 " #elif defined CONFIG_CPU_TX49XX -#define MODULE_PROC_FAMILY "TX49XX" +#define MODULE_PROC_FAMILY "TX49XX " #elif defined CONFIG_CPU_R5000 -#define MODULE_PROC_FAMILY "R5000" +#define MODULE_PROC_FAMILY "R5000 " #elif defined CONFIG_CPU_R5432 -#define MODULE_PROC_FAMILY "R5432" +#define MODULE_PROC_FAMILY "R5432 " #elif defined CONFIG_CPU_R6000 -#define MODULE_PROC_FAMILY "R6000" +#define MODULE_PROC_FAMILY "R6000 " #elif defined CONFIG_CPU_NEVADA -#define MODULE_PROC_FAMILY "NEVADA" +#define MODULE_PROC_FAMILY "NEVADA " #elif defined CONFIG_CPU_R8000 -#define MODULE_PROC_FAMILY "R8000" +#define MODULE_PROC_FAMILY "R8000 " #elif defined CONFIG_CPU_R10000 -#define MODULE_PROC_FAMILY "R10000" +#define MODULE_PROC_FAMILY "R10000 " #elif defined CONFIG_CPU_RM7000 -#define MODULE_PROC_FAMILY "RM7000" +#define MODULE_PROC_FAMILY "RM7000 " #elif defined CONFIG_CPU_RM9000 -#define MODULE_PROC_FAMILY "RM9000" +#define MODULE_PROC_FAMILY "RM9000 " #elif defined CONFIG_CPU_SB1 -#define MODULE_PROC_FAMILY "SB1" +#define MODULE_PROC_FAMILY "SB1 " #else #error MODULE_PROC_FAMILY undefined for your processor configuration #endif diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h index 34facd9965034d354eb72ea91bc71586759083f6..702a28fa7a3489d01c2ff986c7dfd0adefebe0bc 100644 --- a/include/asm-mips/pgtable.h +++ b/include/asm-mips/pgtable.h @@ -19,6 +19,9 @@ #include #include +struct mm_struct; +struct vm_area_struct; + #define PAGE_NONE __pgprot(_PAGE_PRESENT | _CACHE_CACHABLE_NONCOHERENT) #define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ PAGE_CACHABLE_DEFAULT) diff --git a/include/asm-mips/rtc.h b/include/asm-mips/rtc.h index a60e0dc7c9b9406f19efb3e4bf9eb98ddb7b34a0..a2abc4572b638e5bf33cd59f3bdcb121c1d42865 100644 --- a/include/asm-mips/rtc.h +++ b/include/asm-mips/rtc.h @@ -14,7 +14,6 @@ #ifdef __KERNEL__ -#include #include #include @@ -29,17 +28,13 @@ #define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */ #define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */ -static DEFINE_SPINLOCK(mips_rtc_lock); - static inline unsigned int get_rtc_time(struct rtc_time *time) { unsigned long nowtime; - spin_lock(&mips_rtc_lock); nowtime = rtc_get_time(); to_tm(nowtime, time); time->tm_year -= 1900; - spin_unlock(&mips_rtc_lock); return RTC_24H; } @@ -49,12 +44,10 @@ static inline int set_rtc_time(struct rtc_time *time) unsigned long nowtime; int ret; - spin_lock(&mips_rtc_lock); nowtime = mktime(time->tm_year+1900, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec); ret = rtc_set_time(nowtime); - spin_unlock(&mips_rtc_lock); return ret; } diff --git a/include/asm-mips/rtlx.h b/include/asm-mips/rtlx.h index 83cdf6ab0d1fbc82d601f9290f775e04360ce460..1298c3fdf6c99b393dbaf118dd429d22672e4cb3 100644 --- a/include/asm-mips/rtlx.h +++ b/include/asm-mips/rtlx.h @@ -16,21 +16,19 @@ #define RTLX_ID (RTLX_xID | RTLX_VERSION) #define RTLX_CHANNELS 8 -enum rtlx_state { - RTLX_STATE_UNUSED = 0, - RTLX_STATE_INITIALISED, - RTLX_STATE_REMOTE_READY, - RTLX_STATE_OPENED -}; - #define RTLX_BUFFER_SIZE 1024 + +/* + * lx_state bits + */ +#define RTLX_STATE_OPENED 1UL + /* each channel supports read and write. linux (vpe0) reads lx_buffer and writes rt_buffer SP (vpe1) reads rt_buffer and writes lx_buffer */ -typedef struct rtlx_channel { - enum rtlx_state rt_state; - enum rtlx_state lx_state; +struct rtlx_channel { + unsigned long lx_state; int buffer_size; @@ -43,14 +41,12 @@ typedef struct rtlx_channel { void *queues; -} rtlx_channel_t; +}; -typedef struct rtlx_info { +struct rtlx_info { unsigned long id; - enum rtlx_state state; struct rtlx_channel channel[RTLX_CHANNELS]; +}; -} rtlx_info_t; - -#endif +#endif /* _RTLX_H_ */ diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h index e22a2066587160d519892bdc3797b8abf3ba91c1..9cc3564cc2c9a0842b85bddf8f3f5d2eaf20c0b9 100644 --- a/include/asm-mips/time.h +++ b/include/asm-mips/time.h @@ -20,6 +20,9 @@ #include #include #include +#include + +extern spinlock_t rtc_lock; /* * RTC ops. By default, they point to no-RTC functions. diff --git a/include/asm-parisc/pgtable.h b/include/asm-parisc/pgtable.h index c28fb6f48c6c482471cc9e7df01a8a12e56fb1b5..b4554711c3e739d126be89721006cf6f3375540a 100644 --- a/include/asm-parisc/pgtable.h +++ b/include/asm-parisc/pgtable.h @@ -12,6 +12,7 @@ */ #include +#include /* for vm_area_struct */ #include #include #include @@ -418,7 +419,6 @@ extern void paging_init (void); #define PG_dcache_dirty PG_arch_1 -struct vm_area_struct; /* forward declaration (include/linux/mm.h) */ extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t); /* Encode and de-code a swap entry */ @@ -464,6 +464,7 @@ static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned extern spinlock_t pa_dbit_lock; +struct mm_struct; static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { pte_t old_pte; diff --git a/include/asm-powerpc/elf.h b/include/asm-powerpc/elf.h index d140577d0a05b4cd4ff62becef0de5677b810876..feac3458d71f693a9a31b31f263f5b0106978fc8 100644 --- a/include/asm-powerpc/elf.h +++ b/include/asm-powerpc/elf.h @@ -1,11 +1,13 @@ #ifndef _ASM_POWERPC_ELF_H #define _ASM_POWERPC_ELF_H +#include /* for task_struct */ #include #include #include #include #include +#include /* PowerPC relocations defined by the ABIs */ #define R_PPC_NONE 0 diff --git a/include/asm-ppc/ide.h b/include/asm-powerpc/ide.h similarity index 83% rename from include/asm-ppc/ide.h rename to include/asm-powerpc/ide.h index 7d6e6599fac4172e2459161268111ce3951d0605..da5f640480cf3eb89a064e42bcba728c6ec6e856 100644 --- a/include/asm-ppc/ide.h +++ b/include/asm-powerpc/ide.h @@ -1,24 +1,27 @@ /* - * linux/include/asm-ppc/ide.h + * Copyright (C) 1994-1996 Linus Torvalds & authors * - * Copyright (C) 1994-1996 Linus Torvalds & authors */ - -/* - * This file contains the ppc architecture specific IDE code. + * This file contains the powerpc architecture specific IDE code. */ - -#ifndef __ASMPPC_IDE_H -#define __ASMPPC_IDE_H +#ifndef _ASM_POWERPC_IDE_H +#define _ASM_POWERPC_IDE_H #ifdef __KERNEL__ +#ifndef __powerpc64__ #include #include +#endif #ifndef MAX_HWIFS +#ifdef __powerpc64__ +#define MAX_HWIFS 10 +#else #define MAX_HWIFS 8 #endif +#endif +#ifndef __powerpc64__ #include #include #include @@ -59,9 +62,6 @@ static __inline__ unsigned long ide_default_io_base(int index) return 0; } -#define IDE_ARCH_OBSOLETE_INIT -#define ide_default_io_ctl(base) ((base) + 0x206) /* obsolete */ - #ifdef CONFIG_PCI #define ide_init_default_irq(base) (0) #else @@ -73,6 +73,11 @@ static __inline__ unsigned long ide_default_io_base(int index) #define ide_ack_intr(hwif) (hwif->hw.ack_intr ? hwif->hw.ack_intr(hwif) : 1) #endif +#endif /* __powerpc64__ */ + +#define IDE_ARCH_OBSOLETE_INIT +#define ide_default_io_ctl(base) ((base) + 0x206) /* obsolete */ + #endif /* __KERNEL__ */ -#endif /* __ASMPPC_IDE_H */ +#endif /* _ASM_POWERPC_IDE_H */ diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h index b2f09f17fbe03fbdea816ccd0aec77ce3e7651cf..6cd0a3bfa28033a67dd6da3997aff32c6e46127a 100644 --- a/include/asm-powerpc/kprobes.h +++ b/include/asm-powerpc/kprobes.h @@ -27,6 +27,7 @@ */ #include #include +#include struct pt_regs; @@ -53,6 +54,20 @@ struct arch_specific_insn { kprobe_opcode_t *insn; }; +struct prev_kprobe { + struct kprobe *kp; + unsigned long status; + unsigned long saved_msr; +}; + +/* per-cpu kprobe control block */ +struct kprobe_ctlblk { + unsigned long kprobe_status; + unsigned long kprobe_saved_msr; + struct pt_regs jprobe_saved_regs; + struct prev_kprobe prev_kprobe; +}; + #ifdef CONFIG_KPROBES extern int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *data); diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h index fa03864d06eb0d69c528ffa4f25e110d102ca44c..5670f0cd61433e69b1bcb05aff5dd7ea3c7e9f9e 100644 --- a/include/asm-powerpc/machdep.h +++ b/include/asm-powerpc/machdep.h @@ -82,7 +82,6 @@ struct machdep_calls { void (*iommu_dev_setup)(struct pci_dev *dev); void (*iommu_bus_setup)(struct pci_bus *bus); void (*irq_bus_setup)(struct pci_bus *bus); - int (*set_dabr)(unsigned long dabr); #endif int (*probe)(int platform); @@ -158,6 +157,9 @@ struct machdep_calls { platform, called once per cpu. */ void (*enable_pmcs)(void); + /* Set DABR for this platform, leave empty for default implemenation */ + int (*set_dabr)(unsigned long dabr); + #ifdef CONFIG_PPC32 /* XXX for now */ /* A general init function, called by ppc_init in init/main.c. May be NULL. */ diff --git a/include/asm-powerpc/ppc-pci.h b/include/asm-powerpc/ppc-pci.h index a88728fba8f68953e81ccef575ea27d67afb8e7d..13aacff755f383ab21c2f7c997fdf10187a21f25 100644 --- a/include/asm-powerpc/ppc-pci.h +++ b/include/asm-powerpc/ppc-pci.h @@ -34,6 +34,7 @@ void *traverse_pci_devices(struct device_node *start, traverse_func pre, void pci_devs_phb_init(void); void pci_devs_phb_init_dynamic(struct pci_controller *phb); +void __devinit scan_phb(struct pci_controller *hose); /* PCI address cache management routines */ void pci_addr_cache_insert_device(struct pci_dev *dev); diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h index 7587bf5f38c6eb71aeef5ab518c1563241d622f8..f999df1c5c90bc18c994fe4e83b3b2cb4b1f9e57 100644 --- a/include/asm-powerpc/prom.h +++ b/include/asm-powerpc/prom.h @@ -203,7 +203,7 @@ extern int prom_n_addr_cells(struct device_node* np); extern int prom_n_size_cells(struct device_node* np); extern int prom_n_intr_cells(struct device_node* np); extern void prom_get_irq_senses(unsigned char *senses, int off, int max); -extern void prom_add_property(struct device_node* np, struct property* prop); +extern int prom_add_property(struct device_node* np, struct property* prop); #ifdef CONFIG_PPC32 /* diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h index da848412f11b1dd73d4d72ae672d3cb4a18bcba3..489cf4c99c21470c7856856aa6f4a8c3377a4083 100644 --- a/include/asm-powerpc/reg.h +++ b/include/asm-powerpc/reg.h @@ -396,6 +396,9 @@ #define SPRN_VRSAVE 0x100 /* Vector Register Save Register */ #define SPRN_XER 0x001 /* Fixed Point Exception Register */ +#define SPRN_SCOMC 0x114 /* SCOM Access Control */ +#define SPRN_SCOMD 0x115 /* SCOM Access DATA */ + /* Performance monitor SPRs */ #ifdef CONFIG_PPC64 #define SPRN_MMCR0 795 @@ -594,7 +597,11 @@ static inline void ppc64_runlatch_off(void) mtspr(SPRN_CTRLT, ctrl); } } -#endif + +extern unsigned long scom970_read(unsigned int address); +extern void scom970_write(unsigned int address, unsigned long value); + +#endif /* CONFIG_PPC64 */ #define __get_SP() ({unsigned long sp; \ asm volatile("mr %0,1": "=r" (sp)); sp;}) diff --git a/include/asm-powerpc/smp.h b/include/asm-powerpc/smp.h index 8bcdd0faefea83515934bf141bbb524f95158e82..98581e5a827957712599d215aa8ba7077e494187 100644 --- a/include/asm-powerpc/smp.h +++ b/include/asm-powerpc/smp.h @@ -86,7 +86,6 @@ extern void __cpu_die(unsigned int cpu); #else /* for UP */ #define smp_setup_cpu_maps() -#define smp_release_cpus() #endif /* CONFIG_SMP */ @@ -94,6 +93,9 @@ extern void __cpu_die(unsigned int cpu); #define get_hard_smp_processor_id(CPU) (paca[(CPU)].hw_cpu_id) #define set_hard_smp_processor_id(CPU, VAL) \ do { (paca[(CPU)].hw_cpu_id = (VAL)); } while (0) + +extern void smp_release_cpus(void); + #else /* 32-bit */ #ifndef CONFIG_SMP diff --git a/include/asm-powerpc/smu.h b/include/asm-powerpc/smu.h index dee8eefe47bc88bc038991527668c170c4e1215c..76c29a9784ddb3ece86c1718f0edf56c1e034470 100644 --- a/include/asm-powerpc/smu.h +++ b/include/asm-powerpc/smu.h @@ -20,16 +20,52 @@ /* * Partition info commands * - * I do not know what those are for at this point + * These commands are used to retreive the sdb-partition-XX datas from + * the SMU. The lenght is always 2. First byte is the subcommand code + * and second byte is the partition ID. + * + * The reply is 6 bytes: + * + * - 0..1 : partition address + * - 2 : a byte containing the partition ID + * - 3 : length (maybe other bits are rest of header ?) + * + * The data must then be obtained with calls to another command: + * SMU_CMD_MISC_ee_GET_DATABLOCK_REC (described below). */ #define SMU_CMD_PARTITION_COMMAND 0x3e +#define SMU_CMD_PARTITION_LATEST 0x01 +#define SMU_CMD_PARTITION_BASE 0x02 +#define SMU_CMD_PARTITION_UPDATE 0x03 /* * Fan control * - * This is a "mux" for fan control commands, first byte is the - * "sub" command. + * This is a "mux" for fan control commands. The command seem to + * act differently based on the number of arguments. With 1 byte + * of argument, this seem to be queries for fans status, setpoint, + * etc..., while with 0xe arguments, we will set the fans speeds. + * + * Queries (1 byte arg): + * --------------------- + * + * arg=0x01: read RPM fans status + * arg=0x02: read RPM fans setpoint + * arg=0x11: read PWM fans status + * arg=0x12: read PWM fans setpoint + * + * the "status" queries return the current speed while the "setpoint" ones + * return the programmed/target speed. It _seems_ that the result is a bit + * mask in the first byte of active/available fans, followed by 6 words (16 + * bits) containing the requested speed. + * + * Setpoint (14 bytes arg): + * ------------------------ + * + * first arg byte is 0 for RPM fans and 0x10 for PWM. Second arg byte is the + * mask of fans affected by the command. Followed by 6 words containing the + * setpoint value for selected fans in the mask (or 0 if mask value is 0) */ #define SMU_CMD_FAN_COMMAND 0x4a @@ -144,7 +180,11 @@ * - lenght 8 ("VSLEWxyz") has 3 additional bytes appended, and is * used to set the voltage slewing point. The SMU replies with "DONE" * I yet have to figure out their exact meaning of those 3 bytes in - * both cases. + * both cases. They seem to be: + * x = processor mask + * y = op. point index + * z = processor freq. step index + * I haven't yet decyphered result codes * */ #define SMU_CMD_POWER_COMMAND 0xaa @@ -152,6 +192,14 @@ #define SMU_CMD_POWER_SHUTDOWN "SHUTDOWN" #define SMU_CMD_POWER_VOLTAGE_SLEW "VSLEW" +/* + * Read ADC sensors + * + * This command takes one byte of parameter: the sensor ID (or "reg" + * value in the device-tree) and returns a 16 bits value + */ +#define SMU_CMD_READ_ADC 0xd8 + /* Misc commands * * This command seem to be a grab bag of various things @@ -172,6 +220,25 @@ * Misc commands * * This command seem to be a grab bag of various things + * + * SMU_CMD_MISC_ee_GET_DATABLOCK_REC is used, among others, to + * transfer blocks of data from the SMU. So far, I've decrypted it's + * usage to retreive partition data. In order to do that, you have to + * break your transfer in "chunks" since that command cannot transfer + * more than a chunk at a time. The chunk size used by OF is 0xe bytes, + * but it seems that the darwin driver will let you do 0x1e bytes if + * your "PMU" version is >= 0x30. You can get the "PMU" version apparently + * either in the last 16 bits of property "smu-version-pmu" or as the 16 + * bytes at offset 1 of "smu-version-info" + * + * For each chunk, the command takes 7 bytes of arguments: + * byte 0: subcommand code (0x02) + * byte 1: 0x04 (always, I don't know what it means, maybe the address + * space to use or some other nicety. It's hard coded in OF) + * byte 2..5: SMU address of the chunk (big endian 32 bits) + * byte 6: size to transfer (up to max chunk size) + * + * The data is returned directly */ #define SMU_CMD_MISC_ee_COMMAND 0xee #define SMU_CMD_MISC_ee_GET_DATABLOCK_REC 0x02 @@ -333,6 +400,128 @@ extern int smu_queue_i2c(struct smu_i2c_cmd *cmd); #endif /* __KERNEL__ */ + +/* + * - SMU "sdb" partitions informations - + */ + + +/* + * Partition header format + */ +struct smu_sdbp_header { + __u8 id; + __u8 len; + __u8 version; + __u8 flags; +}; + + + /* + * demangle 16 and 32 bits integer in some SMU partitions + * (currently, afaik, this concerns only the FVT partition + * (0x12) + */ +#define SMU_U16_MIX(x) le16_to_cpu(x); +#define SMU_U32_MIX(x) ((((x) & 0xff00ff00u) >> 8)|(((x) & 0x00ff00ffu) << 8)) + + +/* This is the definition of the SMU sdb-partition-0x12 table (called + * CPU F/V/T operating points in Darwin). The definition for all those + * SMU tables should be moved to some separate file + */ +#define SMU_SDB_FVT_ID 0x12 + +struct smu_sdbp_fvt { + __u32 sysclk; /* Base SysClk frequency in Hz for + * this operating point. Value need to + * be unmixed with SMU_U32_MIX() + */ + __u8 pad; + __u8 maxtemp; /* Max temp. supported by this + * operating point + */ + + __u16 volts[3]; /* CPU core voltage for the 3 + * PowerTune modes, a mode with + * 0V = not supported. Value need + * to be unmixed with SMU_U16_MIX() + */ +}; + +/* This partition contains voltage & current sensor calibration + * informations + */ +#define SMU_SDB_CPUVCP_ID 0x21 + +struct smu_sdbp_cpuvcp { + __u16 volt_scale; /* u4.12 fixed point */ + __s16 volt_offset; /* s4.12 fixed point */ + __u16 curr_scale; /* u4.12 fixed point */ + __s16 curr_offset; /* s4.12 fixed point */ + __s32 power_quads[3]; /* s4.28 fixed point */ +}; + +/* This partition contains CPU thermal diode calibration + */ +#define SMU_SDB_CPUDIODE_ID 0x18 + +struct smu_sdbp_cpudiode { + __u16 m_value; /* u1.15 fixed point */ + __s16 b_value; /* s10.6 fixed point */ + +}; + +/* This partition contains Slots power calibration + */ +#define SMU_SDB_SLOTSPOW_ID 0x78 + +struct smu_sdbp_slotspow { + __u16 pow_scale; /* u4.12 fixed point */ + __s16 pow_offset; /* s4.12 fixed point */ +}; + +/* This partition contains machine specific version information about + * the sensor/control layout + */ +#define SMU_SDB_SENSORTREE_ID 0x25 + +struct smu_sdbp_sensortree { + u8 model_id; + u8 unknown[3]; +}; + +/* This partition contains CPU thermal control PID informations. So far + * only single CPU machines have been seen with an SMU, so we assume this + * carries only informations for those + */ +#define SMU_SDB_CPUPIDDATA_ID 0x17 + +struct smu_sdbp_cpupiddata { + u8 unknown1; + u8 target_temp_delta; + u8 unknown2; + u8 history_len; + s16 power_adj; + u16 max_power; + s32 gp,gr,gd; +}; + + +/* Other partitions without known structures */ +#define SMU_SDB_DEBUG_SWITCHES_ID 0x05 + +#ifdef __KERNEL__ +/* + * This returns the pointer to an SMU "sdb" partition data or NULL + * if not found. The data format is described below + */ +extern struct smu_sdbp_header *smu_get_sdb_partition(int id, + unsigned int *size); + +#endif /* __KERNEL__ */ + + /* * - Userland interface - */ @@ -365,8 +554,10 @@ struct smu_user_cmd_hdr __u32 cmdtype; #define SMU_CMDTYPE_SMU 0 /* SMU command */ #define SMU_CMDTYPE_WANTS_EVENTS 1 /* switch fd to events mode */ +#define SMU_CMDTYPE_GET_PARTITION 2 /* retreive an sdb partition */ __u8 cmd; /* SMU command byte */ + __u8 pad[3]; /* padding */ __u32 data_len; /* Lenght of data following */ }; diff --git a/include/asm-powerpc/xmon.h b/include/asm-powerpc/xmon.h index 43f7129984c723312c3ca394ccf32fe53d52a4e8..ace2072d4a833fd331ded2e13be7cf7bd1d8a556 100644 --- a/include/asm-powerpc/xmon.h +++ b/include/asm-powerpc/xmon.h @@ -7,6 +7,7 @@ struct pt_regs; extern int xmon(struct pt_regs *excp); extern void xmon_printf(const char *fmt, ...); extern void xmon_init(int); +extern void xmon_map_scc(void); #endif #endif diff --git a/include/asm-ppc/btext.h b/include/asm-ppc/btext.h index 36c7640d00f2d88d5ec176070004c702710e4adc..ccaefabe0bf5a5442eebbc41758a06a6935ea3ac 100644 --- a/include/asm-ppc/btext.h +++ b/include/asm-ppc/btext.h @@ -17,18 +17,18 @@ extern unsigned long disp_BAT[2]; extern boot_infos_t disp_bi; extern int boot_text_mapped; -void btext_init(boot_infos_t *bi); -void btext_welcome(void); -void btext_prepare_BAT(void); -void btext_setup_display(int width, int height, int depth, int pitch, - unsigned long address); -void map_boot_text(void); -void btext_update_display(unsigned long phys, int width, int height, - int depth, int pitch); +extern void init_boot_display(void); +extern void btext_welcome(void); +extern void btext_prepare_BAT(void); +extern void btext_setup_display(int width, int height, int depth, int pitch, + unsigned long address); +extern void map_boot_text(void); +extern void btext_update_display(unsigned long phys, int width, int height, + int depth, int pitch); -void btext_drawchar(char c); -void btext_drawstring(const char *str); -void btext_drawhex(unsigned long v); +extern void btext_drawchar(char c); +extern void btext_drawstring(const char *str); +extern void btext_drawhex(unsigned long v); #endif /* __KERNEL__ */ #endif /* __PPC_BTEXT_H */ diff --git a/include/asm-ppc/ibm44x.h b/include/asm-ppc/ibm44x.h index e5374be86aefb90a39e608ef09ed002eab7decfe..f835066fb3cad431ff7a259df2b0f4a25c2b5e6e 100644 --- a/include/asm-ppc/ibm44x.h +++ b/include/asm-ppc/ibm44x.h @@ -34,12 +34,20 @@ /* Lowest TLB slot consumed by the default pinned TLBs */ #define PPC44x_LOW_SLOT 63 -/* LS 32-bits of UART0 physical address location for early serial text debug */ +/* + * Least significant 32-bits and extended real page number (ERPN) of + * UART0 physical address location for early serial text debug + */ #if defined(CONFIG_440SP) +#define UART0_PHYS_ERPN 1 +#define UART0_PHYS_IO_BASE 0xf0000200 +#elif defined(CONFIG_440SPE) +#define UART0_PHYS_ERPN 4 #define UART0_PHYS_IO_BASE 0xf0000200 #elif defined(CONFIG_440EP) #define UART0_PHYS_IO_BASE 0xe0000000 #else +#define UART0_PHYS_ERPN 1 #define UART0_PHYS_IO_BASE 0x40000200 #endif @@ -56,6 +64,11 @@ #define PPC44x_PCICFG_PAGE 0x0000000900000000ULL #define PPC44x_PCIIO_PAGE PPC44x_PCICFG_PAGE #define PPC44x_PCIMEM_PAGE 0x0000000a00000000ULL +#elif defined(CONFIG_440SPE) +#define PPC44x_IO_PAGE 0x0000000400000000ULL +#define PPC44x_PCICFG_PAGE 0x0000000c00000000ULL +#define PPC44x_PCIIO_PAGE PPC44x_PCICFG_PAGE +#define PPC44x_PCIMEM_PAGE 0x0000000d00000000ULL #elif defined(CONFIG_440EP) #define PPC44x_IO_PAGE 0x0000000000000000ULL #define PPC44x_PCICFG_PAGE 0x0000000000000000ULL @@ -71,7 +84,7 @@ /* * 36-bit trap ranges */ -#if defined(CONFIG_440SP) +#if defined(CONFIG_440SP) || defined(CONFIG_440SPE) #define PPC44x_IO_LO 0xf0000000UL #define PPC44x_IO_HI 0xf0000fffUL #define PPC44x_PCI0CFG_LO 0x0ec00000UL @@ -109,7 +122,7 @@ */ -/* CPRs (440GX and 440SP) */ +/* CPRs (440GX and 440SP/440SPe) */ #define DCRN_CPR_CONFIG_ADDR 0xc #define DCRN_CPR_CONFIG_DATA 0xd @@ -130,7 +143,7 @@ mtdcr(DCRN_CPR_CONFIG_ADDR, offset); \ mtdcr(DCRN_CPR_CONFIG_DATA, data);}) -/* SDRs (440GX and 440SP) */ +/* SDRs (440GX and 440SP/440SPe) */ #define DCRN_SDR_CONFIG_ADDR 0xe #define DCRN_SDR_CONFIG_DATA 0xf #define DCRN_SDR_PFC0 0x4100 @@ -180,7 +193,7 @@ mtdcr(DCRN_SDR_CONFIG_ADDR, offset); \ mtdcr(DCRN_SDR_CONFIG_DATA,data);}) -/* DMA (excluding 440SP) */ +/* DMA (excluding 440SP/440SPe) */ #define DCRN_DMA0_BASE 0x100 #define DCRN_DMA1_BASE 0x108 #define DCRN_DMA2_BASE 0x110 @@ -200,12 +213,20 @@ /* UIC */ #define DCRN_UIC0_BASE 0xc0 #define DCRN_UIC1_BASE 0xd0 -#define DCRN_UIC2_BASE 0x210 -#define DCRN_UICB_BASE 0x200 #define UIC0 DCRN_UIC0_BASE #define UIC1 DCRN_UIC1_BASE + +#ifdef CONFIG_440SPE +#define DCRN_UIC2_BASE 0xe0 +#define DCRN_UIC3_BASE 0xf0 +#define UIC2 DCRN_UIC2_BASE +#define UIC3 DCRN_UIC3_BASE +#else +#define DCRN_UIC2_BASE 0x210 +#define DCRN_UICB_BASE 0x200 #define UIC2 DCRN_UIC2_BASE #define UICB DCRN_UICB_BASE +#endif #define DCRN_UIC_SR(base) (base + 0x0) #define DCRN_UIC_ER(base) (base + 0x2) @@ -218,6 +239,12 @@ #define UIC0_UIC1NC 0x00000002 +#ifdef CONFIG_440SPE +#define UIC0_UIC1NC 0x00000002 +#define UIC0_UIC2NC 0x00200000 +#define UIC0_UIC3NC 0x00008000 +#endif + #define UICB_UIC0NC 0x40000000 #define UICB_UIC1NC 0x10000000 #define UICB_UIC2NC 0x04000000 @@ -297,6 +324,23 @@ #define MALOBISR_CH0 0x80000000 /* EOB channel 1 bit */ #define MALOBISR_CH2 0x40000000 /* EOB channel 2 bit */ +#if defined(CONFIG_440SP) || defined(CONFIG_440SPE) +/* 440SP/440SPe PLB Arbiter DCRs */ +#define DCRN_PLB_REVID 0x080 /* PLB Revision ID */ +#define DCRN_PLB_CCR 0x088 /* PLB Crossbar Control */ + +#define DCRN_PLB0_ACR 0x081 /* PLB Arbiter Control */ +#define DCRN_PLB0_BESRL 0x082 /* PLB Error Status */ +#define DCRN_PLB0_BESRH 0x083 /* PLB Error Status */ +#define DCRN_PLB0_BEARL 0x084 /* PLB Error Address Low */ +#define DCRN_PLB0_BEARH 0x085 /* PLB Error Address High */ + +#define DCRN_PLB1_ACR 0x089 /* PLB Arbiter Control */ +#define DCRN_PLB1_BESRL 0x08a /* PLB Error Status */ +#define DCRN_PLB1_BESRH 0x08b /* PLB Error Status */ +#define DCRN_PLB1_BEARL 0x08c /* PLB Error Address Low */ +#define DCRN_PLB1_BEARH 0x08d /* PLB Error Address High */ +#else /* 440GP/GX PLB Arbiter DCRs */ #define DCRN_PLB0_REVID 0x082 /* PLB Arbiter Revision ID */ #define DCRN_PLB0_ACR 0x083 /* PLB Arbiter Control */ @@ -304,6 +348,7 @@ #define DCRN_PLB0_BEARL 0x086 /* PLB Error Address Low */ #define DCRN_PLB0_BEAR DCRN_PLB0_BEARL /* 40x compatibility */ #define DCRN_PLB0_BEARH 0x087 /* PLB Error Address High */ +#endif /* 440GP/GX PLB to OPB bridge DCRs */ #define DCRN_POB0_BESR0 0x090 @@ -407,9 +452,13 @@ #define PPC44x_MEM_SIZE_1G 0x40000000 #define PPC44x_MEM_SIZE_2G 0x80000000 -/* 440SP memory controller DCRs */ +/* 440SP/440SPe memory controller DCRs */ #define DCRN_MQ0_BS0BAS 0x40 -#define DCRN_MQ0_BS1BAS 0x41 +#if defined(CONFIG_440SP) +#define MQ0_NUM_BANKS 2 +#elif defined(CONFIG_440SPE) +#define MQ0_NUM_BANKS 4 +#endif #define MQ0_CONFIG_SIZE_MASK 0x0000fff0 #define MQ0_CONFIG_SIZE_8M 0x0000ffc0 @@ -421,8 +470,9 @@ #define MQ0_CONFIG_SIZE_512M 0x0000f000 #define MQ0_CONFIG_SIZE_1G 0x0000e000 #define MQ0_CONFIG_SIZE_2G 0x0000c000 +#define MQ0_CONFIG_SIZE_4G 0x00008000 -/* Internal SRAM Controller 440GX/440SP */ +/* Internal SRAM Controller 440GX/440SP/440SPe */ #define DCRN_SRAM0_BASE 0x000 #define DCRN_SRAM0_SB0CR (DCRN_SRAM0_BASE + 0x020) @@ -446,7 +496,7 @@ #define DCRN_SRAM0_DPC (DCRN_SRAM0_BASE + 0x02a) #define SRAM_DPC_ENABLE 0x80000000 -/* L2 Cache Controller 440GX/440SP */ +/* L2 Cache Controller 440GX/440SP/440SPe */ #define DCRN_L2C0_CFG 0x030 #define L2C_CFG_L2M 0x80000000 #define L2C_CFG_ICU 0x40000000 @@ -610,8 +660,10 @@ #define IIC_CLOCK 50 #undef NR_UICS -#ifdef CONFIG_440GX +#if defined(CONFIG_440GX) #define NR_UICS 3 +#elif defined(CONFIG_440SPE) +#define NR_UICS 4 #else #define NR_UICS 2 #endif diff --git a/include/asm-ppc/ibm4xx.h b/include/asm-ppc/ibm4xx.h index e992369cb8e9b476fd64306bbc92a846a5bb074f..6c28ae7807f4fe20add48c793a0d84397e61bf50 100644 --- a/include/asm-ppc/ibm4xx.h +++ b/include/asm-ppc/ibm4xx.h @@ -97,6 +97,10 @@ void ppc4xx_init(unsigned long r3, unsigned long r4, unsigned long r5, #include #endif +#if defined(CONFIG_YUCCA) +#include +#endif + #if defined(CONFIG_OCOTEA) #include #endif diff --git a/include/asm-ppc/ibm_ocp.h b/include/asm-ppc/ibm_ocp.h index 6f10a25bd628c18cc2f4bd1462d79c9f61936a86..9c21de1ff4ed109805142f9d23dd45dfcdff5f6a 100644 --- a/include/asm-ppc/ibm_ocp.h +++ b/include/asm-ppc/ibm_ocp.h @@ -131,9 +131,22 @@ static inline void ibm_ocp_set_emac(int start, int end) /* Copy MAC addresses to EMAC additions */ for (i=start; i<=end; i++) { def = ocp_get_one_device(OCP_VENDOR_IBM, OCP_FUNC_EMAC, i); - memcpy(((struct ocp_func_emac_data *)def->additions)->mac_addr, - &__res.bi_enetaddr[i], - 6); + if (i == 0) + memcpy(((struct ocp_func_emac_data *)def->additions)->mac_addr, + __res.bi_enetaddr, 6); +#if defined(CONFIG_405EP) || defined(CONFIG_44x) + else if (i == 1) + memcpy(((struct ocp_func_emac_data *)def->additions)->mac_addr, + __res.bi_enet1addr, 6); +#endif +#if defined(CONFIG_440GX) + else if (i == 2) + memcpy(((struct ocp_func_emac_data *)def->additions)->mac_addr, + __res.bi_enet2addr, 6); + else if (i == 3) + memcpy(((struct ocp_func_emac_data *)def->additions)->mac_addr, + __res.bi_enet3addr, 6); +#endif } } #endif diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h index f7f614dfc648170760cc31da3284b20ffcc717b6..2bfdf9c98459e9ee28d98ccb90c3e638f0bc69be 100644 --- a/include/asm-ppc/io.h +++ b/include/asm-ppc/io.h @@ -237,9 +237,9 @@ static inline void __raw_writel(__u32 b, volatile void __iomem *addr) #define outsl(port, buf, nl) _outsl_ns((port)+___IO_BASE, (buf), (nl)) /* - * On powermacs, we will get a machine check exception if we - * try to read data from a non-existent I/O port. Because the - * machine check is an asynchronous exception, it isn't + * On powermacs and 8xx we will get a machine check exception + * if we try to read data from a non-existent I/O port. Because + * the machine check is an asynchronous exception, it isn't * well-defined which instruction SRR0 will point to when the * exception occurs. * With the sequence below (twi; isync; nop), we have found that @@ -258,7 +258,7 @@ extern __inline__ unsigned int name(unsigned int port) \ { \ unsigned int x; \ __asm__ __volatile__( \ - op " %0,0,%1\n" \ + "0:" op " %0,0,%1\n" \ "1: twi 0,%0,0\n" \ "2: isync\n" \ "3: nop\n" \ @@ -269,6 +269,7 @@ extern __inline__ unsigned int name(unsigned int port) \ ".previous\n" \ ".section __ex_table,\"a\"\n" \ " .align 2\n" \ + " .long 0b,5b\n" \ " .long 1b,5b\n" \ " .long 2b,5b\n" \ " .long 3b,5b\n" \ @@ -282,11 +283,12 @@ extern __inline__ unsigned int name(unsigned int port) \ extern __inline__ void name(unsigned int val, unsigned int port) \ { \ __asm__ __volatile__( \ - op " %0,0,%1\n" \ + "0:" op " %0,0,%1\n" \ "1: sync\n" \ "2:\n" \ ".section __ex_table,\"a\"\n" \ " .align 2\n" \ + " .long 0b,2b\n" \ " .long 1b,2b\n" \ ".previous" \ : : "r" (val), "r" (port + ___IO_BASE)); \ diff --git a/include/asm-ppc/kgdb.h b/include/asm-ppc/kgdb.h index 1d3c927ce62626a81c5f9f6ee98841f8232598d9..b617dac82969085a2217e9ee502e05e04ac9ca11 100644 --- a/include/asm-ppc/kgdb.h +++ b/include/asm-ppc/kgdb.h @@ -31,7 +31,7 @@ extern void breakpoint(void); /* For taking exceptions * these are defined in traps.c */ -extern void (*debugger)(struct pt_regs *regs); +extern int (*debugger)(struct pt_regs *regs); extern int (*debugger_bpt)(struct pt_regs *regs); extern int (*debugger_sstep)(struct pt_regs *regs); extern int (*debugger_iabr_match)(struct pt_regs *regs); diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h index b28a713ba862e48754afc3d409060d50153ad1a2..6d1c39e8a6afef09a47c503b7bd734aa0e9acf28 100644 --- a/include/asm-ppc/pgtable.h +++ b/include/asm-ppc/pgtable.h @@ -12,6 +12,7 @@ #include /* For TASK_SIZE */ #include #include +struct mm_struct; extern unsigned long va_to_phys(unsigned long address); extern pte_t *va_to_pte(unsigned long address); diff --git a/include/asm-ppc/ppcboot.h b/include/asm-ppc/ppcboot.h index fe24e4520208bdfd31b58baf507295231ac24185..6b7b63f71daae2d41c125b9b84ba92404b172b44 100644 --- a/include/asm-ppc/ppcboot.h +++ b/include/asm-ppc/ppcboot.h @@ -73,8 +73,8 @@ typedef struct bd_info { #if defined(CONFIG_HYMOD) hymod_conf_t bi_hymod_conf; /* hymod configuration information */ #endif -#if defined(CONFIG_EVB64260) || defined(CONFIG_44x) || defined(CONFIG_85xx) ||\ - defined(CONFIG_83xx) +#if defined(CONFIG_EVB64260) || defined(CONFIG_405EP) || defined(CONFIG_44x) || \ + defined(CONFIG_85xx) || defined(CONFIG_83xx) /* second onboard ethernet port */ unsigned char bi_enet1addr[6]; #endif @@ -96,5 +96,7 @@ typedef struct bd_info { #endif } bd_t; +#define bi_tbfreq bi_intfreq + #endif /* __ASSEMBLY__ */ #endif /* __ASM_PPCBOOT_H__ */ diff --git a/include/asm-ppc/prom.h b/include/asm-ppc/prom.h index 75c0637acdc8ad2e7615be70f3819b71905befb2..3e39827ed56690bace2991437a6082fdddd88f34 100644 --- a/include/asm-ppc/prom.h +++ b/include/asm-ppc/prom.h @@ -93,7 +93,7 @@ extern int device_is_compatible(struct device_node *device, const char *); extern int machine_is_compatible(const char *compat); extern unsigned char *get_property(struct device_node *node, const char *name, int *lenp); -extern void prom_add_property(struct device_node* np, struct property* prop); +extern int prom_add_property(struct device_node* np, struct property* prop); extern void prom_get_irq_senses(unsigned char *, int, int); extern int prom_n_addr_cells(struct device_node* np); extern int prom_n_size_cells(struct device_node* np); diff --git a/include/asm-ppc/rio.h b/include/asm-ppc/rio.h new file mode 100644 index 0000000000000000000000000000000000000000..0018bf80cb25d523562a6754cbec75a7eee63688 --- /dev/null +++ b/include/asm-ppc/rio.h @@ -0,0 +1,18 @@ +/* + * RapidIO architecture support + * + * Copyright 2005 MontaVista Software, Inc. + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef ASM_PPC_RIO_H +#define ASM_PPC_RIO_H + +extern void platform_rio_init(void); + +#endif /* ASM_PPC_RIO_H */ diff --git a/include/asm-ppc64/ide.h b/include/asm-ppc64/ide.h deleted file mode 100644 index 0aae1c590c0e9d134afc2d34b1c7414eb8bd2a1b..0000000000000000000000000000000000000000 --- a/include/asm-ppc64/ide.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * linux/include/asm-ppc/ide.h - * - * Copyright (C) 1994-1996 Linus Torvalds & authors - * - * 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 file contains the ppc64 architecture specific IDE code. - */ - -#ifndef __ASMPPC64_IDE_H -#define __ASMPPC64_IDE_H - -#ifdef __KERNEL__ - -#ifndef MAX_HWIFS -# define MAX_HWIFS 10 -#endif - -#define IDE_ARCH_OBSOLETE_INIT -#define ide_default_io_ctl(base) ((base) + 0x206) /* obsolete */ - -#endif /* __KERNEL__ */ - -#endif /* __ASMPPC64_IDE_H */ diff --git a/include/asm-ppc64/pci.h b/include/asm-ppc64/pci.h index 342e2d755550a1de3cf7907352e86b54ce53fcad..fafdf885a3cca595091c3520a4bde7b390b5dceb 100644 --- a/include/asm-ppc64/pci.h +++ b/include/asm-ppc64/pci.h @@ -162,6 +162,14 @@ pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus); extern struct pci_controller *init_phb_dynamic(struct device_node *dn); +extern struct pci_dev *of_create_pci_dev(struct device_node *node, + struct pci_bus *bus, int devfn); + +extern void of_scan_pci_bridge(struct device_node *node, + struct pci_dev *dev); + +extern void of_scan_bus(struct device_node *node, struct pci_bus *bus); + extern int pci_read_irq_line(struct pci_dev *dev); extern void pcibios_add_platform_entries(struct pci_dev *dev); diff --git a/include/asm-ppc64/pgtable-4k.h b/include/asm-ppc64/pgtable-4k.h index c883a274855878c20602cf246d45993f218ebffe..e9590c06ad9276541a191ec1f3a3057452c7bde9 100644 --- a/include/asm-ppc64/pgtable-4k.h +++ b/include/asm-ppc64/pgtable-4k.h @@ -23,6 +23,9 @@ #define PMD_SIZE (1UL << PMD_SHIFT) #define PMD_MASK (~(PMD_SIZE-1)) +/* With 4k base page size, hugepage PTEs go at the PMD level */ +#define MIN_HUGEPTE_SHIFT PMD_SHIFT + /* PUD_SHIFT determines what a third-level page table entry can map */ #define PUD_SHIFT (PMD_SHIFT + PMD_INDEX_SIZE) #define PUD_SIZE (1UL << PUD_SHIFT) diff --git a/include/asm-ppc64/pgtable-64k.h b/include/asm-ppc64/pgtable-64k.h index c5f437c86b3c7a67b264edea5b9de83dedf9001c..154f1840ece4d0c49e403177b8262640e91048a6 100644 --- a/include/asm-ppc64/pgtable-64k.h +++ b/include/asm-ppc64/pgtable-64k.h @@ -14,6 +14,9 @@ #define PTRS_PER_PMD (1 << PMD_INDEX_SIZE) #define PTRS_PER_PGD (1 << PGD_INDEX_SIZE) +/* With 4k base page size, hugepage PTEs go at the PMD level */ +#define MIN_HUGEPTE_SHIFT PAGE_SHIFT + /* PMD_SHIFT determines what a second-level page table entry can map */ #define PMD_SHIFT (PAGE_SHIFT + PTE_INDEX_SIZE) #define PMD_SIZE (1UL << PMD_SHIFT) diff --git a/include/asm-ppc64/pgtable.h b/include/asm-ppc64/pgtable.h index fde93ec36abc5550e91724357ef1137debd4cbe6..a9783ba7fe9898f87291bc59168a7452b656b24d 100644 --- a/include/asm-ppc64/pgtable.h +++ b/include/asm-ppc64/pgtable.h @@ -13,6 +13,7 @@ #include #include #include +struct mm_struct; #endif /* __ASSEMBLY__ */ #ifdef CONFIG_PPC_64K_PAGES diff --git a/include/asm-ppc64/ppcdebug.h b/include/asm-ppc64/ppcdebug.h deleted file mode 100644 index fd7f696065c4a280e9d4e0f468b24c5c431277ff..0000000000000000000000000000000000000000 --- a/include/asm-ppc64/ppcdebug.h +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef __PPCDEBUG_H -#define __PPCDEBUG_H -/******************************************************************** - * Author: Adam Litke, IBM Corp - * (c) 2001 - * - * This file contains definitions and macros for a runtime debugging - * system for ppc64 (This should also work on 32 bit with a few - * adjustments. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - ********************************************************************/ - -#include -#include -#include -#include - -#define PPCDBG_BITVAL(X) ((1UL)<<((unsigned long)(X))) - -/* Defined below are the bit positions of various debug flags in the - * ppc64_debug_switch variable. - * -- When adding new values, please enter them into trace names below -- - * - * Values 62 & 63 can be used to stress the hardware page table management - * code. They must be set statically, any attempt to change them dynamically - * would be a very bad idea. - */ -#define PPCDBG_MMINIT PPCDBG_BITVAL(0) -#define PPCDBG_MM PPCDBG_BITVAL(1) -#define PPCDBG_SYS32 PPCDBG_BITVAL(2) -#define PPCDBG_SYS32NI PPCDBG_BITVAL(3) -#define PPCDBG_SYS32X PPCDBG_BITVAL(4) -#define PPCDBG_SYS32M PPCDBG_BITVAL(5) -#define PPCDBG_SYS64 PPCDBG_BITVAL(6) -#define PPCDBG_SYS64NI PPCDBG_BITVAL(7) -#define PPCDBG_SYS64X PPCDBG_BITVAL(8) -#define PPCDBG_SIGNAL PPCDBG_BITVAL(9) -#define PPCDBG_SIGNALXMON PPCDBG_BITVAL(10) -#define PPCDBG_BINFMT32 PPCDBG_BITVAL(11) -#define PPCDBG_BINFMT64 PPCDBG_BITVAL(12) -#define PPCDBG_BINFMTXMON PPCDBG_BITVAL(13) -#define PPCDBG_BINFMT_32ADDR PPCDBG_BITVAL(14) -#define PPCDBG_ALIGNFIXUP PPCDBG_BITVAL(15) -#define PPCDBG_TCEINIT PPCDBG_BITVAL(16) -#define PPCDBG_TCE PPCDBG_BITVAL(17) -#define PPCDBG_PHBINIT PPCDBG_BITVAL(18) -#define PPCDBG_SMP PPCDBG_BITVAL(19) -#define PPCDBG_BOOT PPCDBG_BITVAL(20) -#define PPCDBG_BUSWALK PPCDBG_BITVAL(21) -#define PPCDBG_PROM PPCDBG_BITVAL(22) -#define PPCDBG_RTAS PPCDBG_BITVAL(23) -#define PPCDBG_HTABSTRESS PPCDBG_BITVAL(62) -#define PPCDBG_HTABSIZE PPCDBG_BITVAL(63) -#define PPCDBG_NONE (0UL) -#define PPCDBG_ALL (0xffffffffUL) - -/* The default initial value for the debug switch */ -#define PPC_DEBUG_DEFAULT 0 -/* #define PPC_DEBUG_DEFAULT PPCDBG_ALL */ - -#define PPCDBG_NUM_FLAGS 64 - -extern u64 ppc64_debug_switch; - -#ifdef WANT_PPCDBG_TAB -/* A table of debug switch names to allow name lookup in xmon - * (and whoever else wants it. - */ -char *trace_names[PPCDBG_NUM_FLAGS] = { - /* Known debug names */ - "mminit", "mm", - "syscall32", "syscall32_ni", "syscall32x", "syscall32m", - "syscall64", "syscall64_ni", "syscall64x", - "signal", "signal_xmon", - "binfmt32", "binfmt64", "binfmt_xmon", "binfmt_32addr", - "alignfixup", "tceinit", "tce", "phb_init", - "smp", "boot", "buswalk", "prom", - "rtas" -}; -#else -extern char *trace_names[64]; -#endif /* WANT_PPCDBG_TAB */ - -#ifdef CONFIG_PPCDBG -/* Macro to conditionally print debug based on debug_switch */ -#define PPCDBG(...) udbg_ppcdbg(__VA_ARGS__) - -/* Macro to conditionally call a debug routine based on debug_switch */ -#define PPCDBGCALL(FLAGS,FUNCTION) ifppcdebug(FLAGS) FUNCTION - -/* Macros to test for debug states */ -#define ifppcdebug(FLAGS) if (udbg_ifdebug(FLAGS)) -#define ppcdebugset(FLAGS) (udbg_ifdebug(FLAGS)) -#define PPCDBG_BINFMT (test_thread_flag(TIF_32BIT) ? PPCDBG_BINFMT32 : PPCDBG_BINFMT64) - -#else -#define PPCDBG(...) do {;} while (0) -#define PPCDBGCALL(FLAGS,FUNCTION) do {;} while (0) -#define ifppcdebug(...) if (0) -#define ppcdebugset(FLAGS) (0) -#endif /* CONFIG_PPCDBG */ - -#endif /*__PPCDEBUG_H */ diff --git a/include/asm-ppc64/prom.h b/include/asm-ppc64/prom.h index bdb47174ff0eacde3a69089905bafa02196d3d5b..76bb0266d67c1d2a6c241fe41d7129f003f00e24 100644 --- a/include/asm-ppc64/prom.h +++ b/include/asm-ppc64/prom.h @@ -213,6 +213,6 @@ extern int prom_n_addr_cells(struct device_node* np); extern int prom_n_size_cells(struct device_node* np); extern int prom_n_intr_cells(struct device_node* np); extern void prom_get_irq_senses(unsigned char *senses, int off, int max); -extern void prom_add_property(struct device_node* np, struct property* prop); +extern int prom_add_property(struct device_node* np, struct property* prop); #endif /* _PPC64_PROM_H */ diff --git a/include/asm-ppc64/udbg.h b/include/asm-ppc64/udbg.h index 8192fb8541cc424d45d6f7bbfeada93b28ce2574..e3b927991851d357e6efe9d1ce30bda3f6d298ee 100644 --- a/include/asm-ppc64/udbg.h +++ b/include/asm-ppc64/udbg.h @@ -23,9 +23,6 @@ extern int udbg_read(char *buf, int buflen); extern void register_early_udbg_console(void); extern void udbg_printf(const char *fmt, ...); -extern void udbg_ppcdbg(unsigned long flags, const char *fmt, ...); -extern unsigned long udbg_ifdebug(unsigned long flags); -extern void __init ppcdbg_initialize(void); extern void udbg_init_uart(void __iomem *comport, unsigned int speed); diff --git a/include/asm-s390/bitops.h b/include/asm-s390/bitops.h index 8651524217fde5108f6e5ded6ba1f4c4e5100f2c..b07c578b22ea677d55f9bf147d8791a18c75a20e 100644 --- a/include/asm-s390/bitops.h +++ b/include/asm-s390/bitops.h @@ -518,8 +518,8 @@ static inline int __test_bit(unsigned long nr, const volatile unsigned long *ptr static inline int __constant_test_bit(unsigned long nr, const volatile unsigned long *addr) { - return (((volatile char *) addr) - [(nr^(__BITOPS_WORDSIZE-8))>>3] & (1<<(nr&7))); + return ((((volatile char *) addr) + [(nr^(__BITOPS_WORDSIZE-8))>>3] & (1<<(nr&7)))) != 0; } #define test_bit(nr,addr) \ diff --git a/include/asm-s390/elf.h b/include/asm-s390/elf.h index 3b8bd46832a14c9a746dab57d2e7f370ad250e60..372d51cccd5306a46494744898132a4929551c19 100644 --- a/include/asm-s390/elf.h +++ b/include/asm-s390/elf.h @@ -96,6 +96,7 @@ * ELF register definitions.. */ +#include /* for task_struct */ #include #include #include /* for save_access_regs */ diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h index df94f89038cc3ab5f93d3f6db8df742b1f24c720..9be741bb1496fd831601559936d51708127990da 100644 --- a/include/asm-s390/pgtable.h +++ b/include/asm-s390/pgtable.h @@ -36,6 +36,7 @@ #include struct vm_area_struct; /* forward declaration (include/linux/mm.h) */ +struct mm_struct; extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096))); extern void paging_init(void); diff --git a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h index fc7c96edc697c5922f0377811b3531cc0d161cdb..a949cc077cc72fcfc5b371e4acd54c7bde23621b 100644 --- a/include/asm-s390/ptrace.h +++ b/include/asm-s390/ptrace.h @@ -468,6 +468,8 @@ struct user_regs_struct }; #ifdef __KERNEL__ +#define __ARCH_SYS_PTRACE 1 + #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0) #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN) #define profile_pc(regs) instruction_pointer(regs) diff --git a/include/asm-s390/uaccess.h b/include/asm-s390/uaccess.h index 38a5cf8ab9e3e5cc69f162f1b8af363f886b7046..10a619da4761cddd316266891b26c5f69b86cb43 100644 --- a/include/asm-s390/uaccess.h +++ b/include/asm-s390/uaccess.h @@ -200,21 +200,37 @@ extern int __put_user_bad(void) __attribute__((noreturn)); #define __get_user(x, ptr) \ ({ \ - __typeof__(*(ptr)) __x; \ int __gu_err; \ __chk_user_ptr(ptr); \ switch (sizeof(*(ptr))) { \ - case 1: \ - case 2: \ - case 4: \ - case 8: \ + case 1: { \ + unsigned char __x; \ + __get_user_asm(__x, ptr, __gu_err); \ + (x) = (__typeof__(*(ptr))) __x; \ + break; \ + }; \ + case 2: { \ + unsigned short __x; \ + __get_user_asm(__x, ptr, __gu_err); \ + (x) = (__typeof__(*(ptr))) __x; \ + break; \ + }; \ + case 4: { \ + unsigned int __x; \ + __get_user_asm(__x, ptr, __gu_err); \ + (x) = (__typeof__(*(ptr))) __x; \ + break; \ + }; \ + case 8: { \ + unsigned long long __x; \ __get_user_asm(__x, ptr, __gu_err); \ + (x) = (__typeof__(*(ptr))) __x; \ break; \ + }; \ default: \ __get_user_bad(); \ break; \ } \ - (x) = __x; \ __gu_err; \ }) diff --git a/include/asm-s390/vtoc.h b/include/asm-s390/vtoc.h index a14e34e80b8811904318552778981d2f0d25a070..41d369f38b0e163fdded72953014c785dd458fad 100644 --- a/include/asm-s390/vtoc.h +++ b/include/asm-s390/vtoc.h @@ -1,372 +1,179 @@ -#ifndef __KERNEL__ -#include -#include -#include -#include -#include -#include -#include -#include +/* + * include/asm-s390/vtoc.h + * + * This file contains volume label definitions for DASD devices. + * + * (C) Copyright IBM Corp. 2005 + * + * Author(s): Volker Sameske + * + */ + +#ifndef _ASM_S390_VTOC_H +#define _ASM_S390_VTOC_H -#include -#include - -#include #include -#include -#include -#endif - - -#define LINE_LENGTH 80 -#define VTOC_START_CC 0x0 -#define VTOC_START_HH 0x1 -#define FIRST_USABLE_CYL 1 -#define FIRST_USABLE_TRK 2 - -#define DASD_3380_TYPE 13148 -#define DASD_3390_TYPE 13200 -#define DASD_9345_TYPE 37701 - -#define DASD_3380_VALUE 0xbb60 -#define DASD_3390_VALUE 0xe5a2 -#define DASD_9345_VALUE 0xbc98 - -#define VOLSER_LENGTH 6 -#define BIG_DISK_SIZE 0x10000 - -#define VTOC_ERROR "VTOC error:" - -typedef struct ttr +struct vtoc_ttr { - __u16 tt; - __u8 r; -} __attribute__ ((packed)) ttr_t; + __u16 tt; + __u8 r; +} __attribute__ ((packed)); -typedef struct cchhb +struct vtoc_cchhb { - __u16 cc; - __u16 hh; - __u8 b; -} __attribute__ ((packed)) cchhb_t; + __u16 cc; + __u16 hh; + __u8 b; +} __attribute__ ((packed)); -typedef struct cchh +struct vtoc_cchh { - __u16 cc; - __u16 hh; -} __attribute__ ((packed)) cchh_t; + __u16 cc; + __u16 hh; +} __attribute__ ((packed)); -typedef struct labeldate +struct vtoc_labeldate { - __u8 year; - __u16 day; -} __attribute__ ((packed)) labeldate_t; + __u8 year; + __u16 day; +} __attribute__ ((packed)); - -typedef struct volume_label +struct vtoc_volume_label { - char volkey[4]; /* volume key = volume label */ - char vollbl[4]; /* volume label */ - char volid[6]; /* volume identifier */ - __u8 security; /* security byte */ - cchhb_t vtoc; /* VTOC address */ - char res1[5]; /* reserved */ - char cisize[4]; /* CI-size for FBA,... */ - /* ...blanks for CKD */ - char blkperci[4]; /* no of blocks per CI (FBA), blanks for CKD */ - char labperci[4]; /* no of labels per CI (FBA), blanks for CKD */ - char res2[4]; /* reserved */ - char lvtoc[14]; /* owner code for LVTOC */ - char res3[29]; /* reserved */ -} __attribute__ ((packed)) volume_label_t; - - -typedef struct extent + char volkey[4]; /* volume key = volume label */ + char vollbl[4]; /* volume label */ + char volid[6]; /* volume identifier */ + __u8 security; /* security byte */ + struct vtoc_cchhb vtoc; /* VTOC address */ + char res1[5]; /* reserved */ + char cisize[4]; /* CI-size for FBA,... */ + /* ...blanks for CKD */ + char blkperci[4]; /* no of blocks per CI (FBA), blanks for CKD */ + char labperci[4]; /* no of labels per CI (FBA), blanks for CKD */ + char res2[4]; /* reserved */ + char lvtoc[14]; /* owner code for LVTOC */ + char res3[29]; /* reserved */ +} __attribute__ ((packed)); + +struct vtoc_extent { - __u8 typeind; /* extent type indicator */ - __u8 seqno; /* extent sequence number */ - cchh_t llimit; /* starting point of this extent */ - cchh_t ulimit; /* ending point of this extent */ -} __attribute__ ((packed)) extent_t; - + __u8 typeind; /* extent type indicator */ + __u8 seqno; /* extent sequence number */ + struct vtoc_cchh llimit; /* starting point of this extent */ + struct vtoc_cchh ulimit; /* ending point of this extent */ +} __attribute__ ((packed)); -typedef struct dev_const +struct vtoc_dev_const { - __u16 DS4DSCYL; /* number of logical cyls */ - __u16 DS4DSTRK; /* number of tracks in a logical cylinder */ - __u16 DS4DEVTK; /* device track length */ - __u8 DS4DEVI; /* non-last keyed record overhead */ - __u8 DS4DEVL; /* last keyed record overhead */ - __u8 DS4DEVK; /* non-keyed record overhead differential */ - __u8 DS4DEVFG; /* flag byte */ - __u16 DS4DEVTL; /* device tolerance */ - __u8 DS4DEVDT; /* number of DSCB's per track */ - __u8 DS4DEVDB; /* number of directory blocks per track */ -} __attribute__ ((packed)) dev_const_t; - - -typedef struct format1_label + __u16 DS4DSCYL; /* number of logical cyls */ + __u16 DS4DSTRK; /* number of tracks in a logical cylinder */ + __u16 DS4DEVTK; /* device track length */ + __u8 DS4DEVI; /* non-last keyed record overhead */ + __u8 DS4DEVL; /* last keyed record overhead */ + __u8 DS4DEVK; /* non-keyed record overhead differential */ + __u8 DS4DEVFG; /* flag byte */ + __u16 DS4DEVTL; /* device tolerance */ + __u8 DS4DEVDT; /* number of DSCB's per track */ + __u8 DS4DEVDB; /* number of directory blocks per track */ +} __attribute__ ((packed)); + +struct vtoc_format1_label { - char DS1DSNAM[44]; /* data set name */ - __u8 DS1FMTID; /* format identifier */ - char DS1DSSN[6]; /* data set serial number */ - __u16 DS1VOLSQ; /* volume sequence number */ - labeldate_t DS1CREDT; /* creation date: ydd */ - labeldate_t DS1EXPDT; /* expiration date */ - __u8 DS1NOEPV; /* number of extents on volume */ - __u8 DS1NOBDB; /* no. of bytes used in last direction blk */ - __u8 DS1FLAG1; /* flag 1 */ - char DS1SYSCD[13]; /* system code */ - labeldate_t DS1REFD; /* date last referenced */ - __u8 DS1SMSFG; /* system managed storage indicators */ - __u8 DS1SCXTF; /* sec. space extension flag byte */ - __u16 DS1SCXTV; /* secondary space extension value */ - __u8 DS1DSRG1; /* data set organisation byte 1 */ - __u8 DS1DSRG2; /* data set organisation byte 2 */ - __u8 DS1RECFM; /* record format */ - __u8 DS1OPTCD; /* option code */ - __u16 DS1BLKL; /* block length */ - __u16 DS1LRECL; /* record length */ - __u8 DS1KEYL; /* key length */ - __u16 DS1RKP; /* relative key position */ - __u8 DS1DSIND; /* data set indicators */ - __u8 DS1SCAL1; /* secondary allocation flag byte */ - char DS1SCAL3[3]; /* secondary allocation quantity */ - ttr_t DS1LSTAR; /* last used track and block on track */ - __u16 DS1TRBAL; /* space remaining on last used track */ - __u16 res1; /* reserved */ - extent_t DS1EXT1; /* first extent description */ - extent_t DS1EXT2; /* second extent description */ - extent_t DS1EXT3; /* third extent description */ - cchhb_t DS1PTRDS; /* possible pointer to f2 or f3 DSCB */ -} __attribute__ ((packed)) format1_label_t; - - -typedef struct format4_label + char DS1DSNAM[44]; /* data set name */ + __u8 DS1FMTID; /* format identifier */ + char DS1DSSN[6]; /* data set serial number */ + __u16 DS1VOLSQ; /* volume sequence number */ + struct vtoc_labeldate DS1CREDT; /* creation date: ydd */ + struct vtoc_labeldate DS1EXPDT; /* expiration date */ + __u8 DS1NOEPV; /* number of extents on volume */ + __u8 DS1NOBDB; /* no. of bytes used in last direction blk */ + __u8 DS1FLAG1; /* flag 1 */ + char DS1SYSCD[13]; /* system code */ + struct vtoc_labeldate DS1REFD; /* date last referenced */ + __u8 DS1SMSFG; /* system managed storage indicators */ + __u8 DS1SCXTF; /* sec. space extension flag byte */ + __u16 DS1SCXTV; /* secondary space extension value */ + __u8 DS1DSRG1; /* data set organisation byte 1 */ + __u8 DS1DSRG2; /* data set organisation byte 2 */ + __u8 DS1RECFM; /* record format */ + __u8 DS1OPTCD; /* option code */ + __u16 DS1BLKL; /* block length */ + __u16 DS1LRECL; /* record length */ + __u8 DS1KEYL; /* key length */ + __u16 DS1RKP; /* relative key position */ + __u8 DS1DSIND; /* data set indicators */ + __u8 DS1SCAL1; /* secondary allocation flag byte */ + char DS1SCAL3[3]; /* secondary allocation quantity */ + struct vtoc_ttr DS1LSTAR; /* last used track and block on track */ + __u16 DS1TRBAL; /* space remaining on last used track */ + __u16 res1; /* reserved */ + struct vtoc_extent DS1EXT1; /* first extent description */ + struct vtoc_extent DS1EXT2; /* second extent description */ + struct vtoc_extent DS1EXT3; /* third extent description */ + struct vtoc_cchhb DS1PTRDS; /* possible pointer to f2 or f3 DSCB */ +} __attribute__ ((packed)); + +struct vtoc_format4_label { - char DS4KEYCD[44]; /* key code for VTOC labels: 44 times 0x04 */ - __u8 DS4IDFMT; /* format identifier */ - cchhb_t DS4HPCHR; /* highest address of a format 1 DSCB */ - __u16 DS4DSREC; /* number of available DSCB's */ - cchh_t DS4HCCHH; /* CCHH of next available alternate track */ - __u16 DS4NOATK; /* number of remaining alternate tracks */ - __u8 DS4VTOCI; /* VTOC indicators */ - __u8 DS4NOEXT; /* number of extents in VTOC */ - __u8 DS4SMSFG; /* system managed storage indicators */ - __u8 DS4DEVAC; /* number of alternate cylinders. - Subtract from first two bytes of - DS4DEVSZ to get number of usable - cylinders. can be zero. valid - only if DS4DEVAV on. */ - dev_const_t DS4DEVCT; /* device constants */ - char DS4AMTIM[8]; /* VSAM time stamp */ - char DS4AMCAT[3]; /* VSAM catalog indicator */ - char DS4R2TIM[8]; /* VSAM volume/catalog match time stamp */ - char res1[5]; /* reserved */ - char DS4F6PTR[5]; /* pointer to first format 6 DSCB */ - extent_t DS4VTOCE; /* VTOC extent description */ - char res2[10]; /* reserved */ - __u8 DS4EFLVL; /* extended free-space management level */ - cchhb_t DS4EFPTR; /* pointer to extended free-space info */ - char res3[9]; /* reserved */ -} __attribute__ ((packed)) format4_label_t; - - -typedef struct ds5ext + char DS4KEYCD[44]; /* key code for VTOC labels: 44 times 0x04 */ + __u8 DS4IDFMT; /* format identifier */ + struct vtoc_cchhb DS4HPCHR; /* highest address of a format 1 DSCB */ + __u16 DS4DSREC; /* number of available DSCB's */ + struct vtoc_cchh DS4HCCHH; /* CCHH of next available alternate track */ + __u16 DS4NOATK; /* number of remaining alternate tracks */ + __u8 DS4VTOCI; /* VTOC indicators */ + __u8 DS4NOEXT; /* number of extents in VTOC */ + __u8 DS4SMSFG; /* system managed storage indicators */ + __u8 DS4DEVAC; /* number of alternate cylinders. + * Subtract from first two bytes of + * DS4DEVSZ to get number of usable + * cylinders. can be zero. valid + * only if DS4DEVAV on. */ + struct vtoc_dev_const DS4DEVCT; /* device constants */ + char DS4AMTIM[8]; /* VSAM time stamp */ + char DS4AMCAT[3]; /* VSAM catalog indicator */ + char DS4R2TIM[8]; /* VSAM volume/catalog match time stamp */ + char res1[5]; /* reserved */ + char DS4F6PTR[5]; /* pointer to first format 6 DSCB */ + struct vtoc_extent DS4VTOCE; /* VTOC extent description */ + char res2[10]; /* reserved */ + __u8 DS4EFLVL; /* extended free-space management level */ + struct vtoc_cchhb DS4EFPTR; /* pointer to extended free-space info */ + char res3[9]; /* reserved */ +} __attribute__ ((packed)); + +struct vtoc_ds5ext { - __u16 t; /* RTA of the first track of free extent */ - __u16 fc; /* number of whole cylinders in free ext. */ - __u8 ft; /* number of remaining free tracks */ -} __attribute__ ((packed)) ds5ext_t; - + __u16 t; /* RTA of the first track of free extent */ + __u16 fc; /* number of whole cylinders in free ext. */ + __u8 ft; /* number of remaining free tracks */ +} __attribute__ ((packed)); -typedef struct format5_label +struct vtoc_format5_label { - char DS5KEYID[4]; /* key identifier */ - ds5ext_t DS5AVEXT; /* first available (free-space) extent. */ - ds5ext_t DS5EXTAV[7]; /* seven available extents */ - __u8 DS5FMTID; /* format identifier */ - ds5ext_t DS5MAVET[18]; /* eighteen available extents */ - cchhb_t DS5PTRDS; /* pointer to next format5 DSCB */ -} __attribute__ ((packed)) format5_label_t; - - -typedef struct ds7ext + char DS5KEYID[4]; /* key identifier */ + struct vtoc_ds5ext DS5AVEXT; /* first available (free-space) extent. */ + struct vtoc_ds5ext DS5EXTAV[7]; /* seven available extents */ + __u8 DS5FMTID; /* format identifier */ + struct vtoc_ds5ext DS5MAVET[18]; /* eighteen available extents */ + struct vtoc_cchhb DS5PTRDS; /* pointer to next format5 DSCB */ +} __attribute__ ((packed)); + +struct vtoc_ds7ext { - __u32 a; /* starting RTA value */ - __u32 b; /* ending RTA value + 1 */ -} __attribute__ ((packed)) ds7ext_t; + __u32 a; /* starting RTA value */ + __u32 b; /* ending RTA value + 1 */ +} __attribute__ ((packed)); - -typedef struct format7_label +struct vtoc_format7_label { - char DS7KEYID[4]; /* key identifier */ - ds7ext_t DS7EXTNT[5]; /* space for 5 extent descriptions */ - __u8 DS7FMTID; /* format identifier */ - ds7ext_t DS7ADEXT[11]; /* space for 11 extent descriptions */ - char res1[2]; /* reserved */ - cchhb_t DS7PTRDS; /* pointer to next FMT7 DSCB */ -} __attribute__ ((packed)) format7_label_t; - - -char * vtoc_ebcdic_enc ( - unsigned char source[LINE_LENGTH], - unsigned char target[LINE_LENGTH], - int l); -char * vtoc_ebcdic_dec ( - unsigned char source[LINE_LENGTH], - unsigned char target[LINE_LENGTH], - int l); -void vtoc_set_extent ( - extent_t * ext, - __u8 typeind, - __u8 seqno, - cchh_t * lower, - cchh_t * upper); -void vtoc_set_cchh ( - cchh_t * addr, - __u16 cc, - __u16 hh); -void vtoc_set_cchhb ( - cchhb_t * addr, - __u16 cc, - __u16 hh, - __u8 b); -void vtoc_set_date ( - labeldate_t * d, - __u8 year, - __u16 day); - -void vtoc_volume_label_init ( - volume_label_t *vlabel); - -int vtoc_read_volume_label ( - char * device, - unsigned long vlabel_start, - volume_label_t * vlabel); - -int vtoc_write_volume_label ( - char *device, - unsigned long vlabel_start, - volume_label_t *vlabel); - -void vtoc_volume_label_set_volser ( - volume_label_t *vlabel, - char *volser); - -char *vtoc_volume_label_get_volser ( - volume_label_t *vlabel, - char *volser); - -void vtoc_volume_label_set_key ( - volume_label_t *vlabel, - char *key); - -void vtoc_volume_label_set_label ( - volume_label_t *vlabel, - char *lbl); - -char *vtoc_volume_label_get_label ( - volume_label_t *vlabel, - char *lbl); - -void vtoc_read_label ( - char *device, - unsigned long position, - format1_label_t *f1, - format4_label_t *f4, - format5_label_t *f5, - format7_label_t *f7); - -void vtoc_write_label ( - char *device, - unsigned long position, - format1_label_t *f1, - format4_label_t *f4, - format5_label_t *f5, - format7_label_t *f7); - - -void vtoc_init_format1_label ( - char *volid, - unsigned int blksize, - extent_t *part_extent, - format1_label_t *f1); - - -void vtoc_init_format4_label ( - format4_label_t *f4lbl, - unsigned int usable_partitions, - unsigned int cylinders, - unsigned int tracks, - unsigned int blocks, - unsigned int blksize, - __u16 dev_type); - -void vtoc_update_format4_label ( - format4_label_t *f4, - cchhb_t *highest_f1, - __u16 unused_update); - - -void vtoc_init_format5_label ( - format5_label_t *f5); - -void vtoc_update_format5_label_add ( - format5_label_t *f5, - int verbose, - int cyl, - int trk, - __u16 a, - __u16 b, - __u8 c); - -void vtoc_update_format5_label_del ( - format5_label_t *f5, - int verbose, - int cyl, - int trk, - __u16 a, - __u16 b, - __u8 c); - - -void vtoc_init_format7_label ( - format7_label_t *f7); - -void vtoc_update_format7_label_add ( - format7_label_t *f7, - int verbose, - __u32 a, - __u32 b); - -void vtoc_update_format7_label_del ( - format7_label_t *f7, - int verbose, - __u32 a, - __u32 b); - - -void vtoc_set_freespace( - format4_label_t *f4, - format5_label_t *f5, - format7_label_t *f7, - char ch, - int verbose, - __u32 start, - __u32 stop, - int cyl, - int trk); - - - - - - - - - - - - + char DS7KEYID[4]; /* key identifier */ + struct vtoc_ds7ext DS7EXTNT[5]; /* space for 5 extent descriptions */ + __u8 DS7FMTID; /* format identifier */ + struct vtoc_ds7ext DS7ADEXT[11]; /* space for 11 extent descriptions */ + char res1[2]; /* reserved */ + struct vtoc_cchhb DS7PTRDS; /* pointer to next FMT7 DSCB */ +} __attribute__ ((packed)); + +#endif /* _ASM_S390_VTOC_H */ diff --git a/include/asm-sh/elf.h b/include/asm-sh/elf.h index 8fe00a1981ce757fcf1ed899cb570331bd59b3d8..1b63dfeea4f2b3e165a4689e80c130a46b6eb1c0 100644 --- a/include/asm-sh/elf.h +++ b/include/asm-sh/elf.h @@ -111,6 +111,7 @@ typedef struct user_fpu_struct elf_fpregset_t; #ifdef __KERNEL__ #define SET_PERSONALITY(ex, ibcs2) set_personality(PER_LINUX_32BIT) +struct task_struct; extern int dump_task_regs (struct task_struct *, elf_gregset_t *); extern int dump_task_fpu (struct task_struct *, elf_fpregset_t *); diff --git a/include/asm-sh/mmzone.h b/include/asm-sh/mmzone.h deleted file mode 100644 index 0e7406601fdf811e023de29c4969dba295a84c02..0000000000000000000000000000000000000000 --- a/include/asm-sh/mmzone.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * linux/include/asm-sh/mmzone.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#ifndef __ASM_SH_MMZONE_H -#define __ASM_SH_MMZONE_H - -#include - -#ifdef CONFIG_DISCONTIGMEM - -/* Currently, just for HP690 */ -#define PHYSADDR_TO_NID(phys) ((((phys) - __MEMORY_START) >= 0x01000000)?1:0) - -extern pg_data_t discontig_page_data[MAX_NUMNODES]; -extern bootmem_data_t discontig_node_bdata[MAX_NUMNODES]; - -/* - * Following are macros that each numa implmentation must define. - */ - -/* - * Given a kernel address, find the home node of the underlying memory. - */ -#define KVADDR_TO_NID(kaddr) PHYSADDR_TO_NID(__pa(kaddr)) - -/* - * Return a pointer to the node data for node n. - */ -#define NODE_DATA(nid) (&discontig_page_data[nid]) - -/* - * NODE_MEM_MAP gives the kaddr for the mem_map of the node. - */ -#define NODE_MEM_MAP(nid) (NODE_DATA(nid)->node_mem_map) - -#define phys_to_page(phys) \ -({ unsigned int node = PHYSADDR_TO_NID(phys); \ - NODE_MEM_MAP(node) \ - + (((phys) - NODE_DATA(node)->node_start_paddr) >> PAGE_SHIFT); }) - -static inline int is_valid_page(struct page *page) -{ - unsigned int i; - - for (i = 0; i < MAX_NUMNODES; i++) { - if (page >= NODE_MEM_MAP(i) && - page < NODE_MEM_MAP(i) + NODE_DATA(i)->node_size) - return 1; - } - return 0; -} - -#define VALID_PAGE(page) is_valid_page(page) -#define page_to_phys(page) PHYSADDR(page_address(page)) - -#endif /* CONFIG_DISCONTIGMEM */ -#endif diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h index 324e6cc5ecf71c90d66fa90fe459e944791f6c86..972c3f655b2a01030f78fc720056264361f1af88 100644 --- a/include/asm-sh/page.h +++ b/include/asm-sh/page.h @@ -93,11 +93,6 @@ typedef struct { unsigned long pgprot; } pgprot_t; #define __MEMORY_START CONFIG_MEMORY_START #define __MEMORY_SIZE CONFIG_MEMORY_SIZE -#ifdef CONFIG_DISCONTIGMEM -/* Just for HP690, for now.. */ -#define __MEMORY_START_2ND (__MEMORY_START+0x02000000) -#define __MEMORY_SIZE_2ND 0x001000000 /* 16MB */ -#endif #define PAGE_OFFSET (0x80000000UL) #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) @@ -105,10 +100,8 @@ typedef struct { unsigned long pgprot; } pgprot_t; #define MAP_NR(addr) (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT) -#ifndef CONFIG_DISCONTIGMEM #define phys_to_page(phys) (mem_map + (((phys)-__MEMORY_START) >> PAGE_SHIFT)) #define page_to_phys(page) (((page - mem_map) << PAGE_SHIFT) + __MEMORY_START) -#endif /* PFN start number, because of __MEMORY_START */ #define PFN_START (__MEMORY_START >> PAGE_SHIFT) diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h index aef8ae43de1367de335ee4b698ae76f5a040f33a..bb0efb31a8cbeb230a60ab4386b3c4d122b8f099 100644 --- a/include/asm-sh/pgtable.h +++ b/include/asm-sh/pgtable.h @@ -196,7 +196,9 @@ static inline pte_t pte_mkexec(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _ static inline pte_t pte_mkdirty(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; } static inline pte_t pte_mkyoung(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; } static inline pte_t pte_mkwrite(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_RW)); return pte; } +#ifdef CONFIG_HUGETLB_PAGE static inline pte_t pte_mkhuge(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_SZHUGE)); return pte; } +#endif /* * Macro and implementation to make a page protection as uncachable. @@ -282,6 +284,8 @@ typedef pte_t *pte_addr_t; #define GET_IOSPACE(pfn) 0 #define GET_PFN(pfn) (pfn) +struct mm_struct; + /* * No page table caches to initialise */ diff --git a/include/asm-sh64/pgtable.h b/include/asm-sh64/pgtable.h index 51b05818e4ebc9cfc848f2992782e43cc0990f6d..a1906a772df9b66594bb39da22866e0097317d11 100644 --- a/include/asm-sh64/pgtable.h +++ b/include/asm-sh64/pgtable.h @@ -24,6 +24,8 @@ #include #include +struct vm_area_struct; + extern void paging_init(void); /* We provide our own get_unmapped_area to avoid cache synonym issue */ diff --git a/include/asm-sparc/audioio.h b/include/asm-sparc/audioio.h deleted file mode 100644 index cf16173f521b00a026c3a4eceb8f243fb1ab52fa..0000000000000000000000000000000000000000 --- a/include/asm-sparc/audioio.h +++ /dev/null @@ -1,234 +0,0 @@ -/* - * include/asm-sparc/audioio.h - * - * Sparc Audio Midlayer - * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) - */ - -#ifndef _AUDIOIO_H_ -#define _AUDIOIO_H_ - -/* - * SunOS/Solaris /dev/audio interface - */ - -#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) -#include -#include -#include -#endif - -/* - * This structure contains state information for audio device IO streams. - */ -typedef struct audio_prinfo { - /* - * The following values describe the audio data encoding. - */ - unsigned int sample_rate; /* samples per second */ - unsigned int channels; /* number of interleaved channels */ - unsigned int precision; /* bit-width of each sample */ - unsigned int encoding; /* data encoding method */ - - /* - * The following values control audio device configuration - */ - unsigned int gain; /* gain level: 0 - 255 */ - unsigned int port; /* selected I/O port (see below) */ - unsigned int avail_ports; /* available I/O ports (see below) */ - unsigned int _xxx[2]; /* Reserved for future use */ - - unsigned int buffer_size; /* I/O buffer size */ - - /* - * The following values describe driver state - */ - unsigned int samples; /* number of samples converted */ - unsigned int eof; /* End Of File counter (play only) */ - - unsigned char pause; /* non-zero for pause, zero to resume */ - unsigned char error; /* non-zero if overflow/underflow */ - unsigned char waiting; /* non-zero if a process wants access */ - unsigned char balance; /* stereo channel balance */ - - unsigned short minordev; - - /* - * The following values are read-only state flags - */ - unsigned char open; /* non-zero if open access permitted */ - unsigned char active; /* non-zero if I/O is active */ -} audio_prinfo_t; - - -/* - * This structure describes the current state of the audio device. - */ -typedef struct audio_info { - /* - * Per-stream information - */ - audio_prinfo_t play; /* output status information */ - audio_prinfo_t record; /* input status information */ - - /* - * Per-unit/channel information - */ - unsigned int monitor_gain; /* input to output mix: 0 - 255 */ - unsigned char output_muted; /* non-zero if output is muted */ - unsigned char _xxx[3]; /* Reserved for future use */ - unsigned int _yyy[3]; /* Reserved for future use */ -} audio_info_t; - - -/* - * Audio encoding types - */ -#define AUDIO_ENCODING_NONE (0) /* no encoding assigned */ -#define AUDIO_ENCODING_ULAW (1) /* u-law encoding */ -#define AUDIO_ENCODING_ALAW (2) /* A-law encoding */ -#define AUDIO_ENCODING_LINEAR (3) /* Linear PCM encoding */ -#define AUDIO_ENCODING_FLOAT (4) /* IEEE float (-1. <-> +1.) */ -#define AUDIO_ENCODING_DVI (104) /* DVI ADPCM */ -#define AUDIO_ENCODING_LINEAR8 (105) /* 8 bit UNSIGNED */ -#define AUDIO_ENCODING_LINEARLE (106) /* Linear PCM LE encoding */ - -/* - * These ranges apply to record, play, and monitor gain values - */ -#define AUDIO_MIN_GAIN (0) /* minimum gain value */ -#define AUDIO_MAX_GAIN (255) /* maximum gain value */ - -/* - * These values apply to the balance field to adjust channel gain values - */ -#define AUDIO_LEFT_BALANCE (0) /* left channel only */ -#define AUDIO_MID_BALANCE (32) /* equal left/right channel */ -#define AUDIO_RIGHT_BALANCE (64) /* right channel only */ -#define AUDIO_BALANCE_SHIFT (3) - -/* - * Generic minimum/maximum limits for number of channels, both modes - */ -#define AUDIO_MIN_PLAY_CHANNELS (1) -#define AUDIO_MAX_PLAY_CHANNELS (4) -#define AUDIO_MIN_REC_CHANNELS (1) -#define AUDIO_MAX_REC_CHANNELS (4) - -/* - * Generic minimum/maximum limits for sample precision - */ -#define AUDIO_MIN_PLAY_PRECISION (8) -#define AUDIO_MAX_PLAY_PRECISION (32) -#define AUDIO_MIN_REC_PRECISION (8) -#define AUDIO_MAX_REC_PRECISION (32) - -/* - * Define some convenient names for typical audio ports - */ -/* - * output ports (several may be enabled simultaneously) - */ -#define AUDIO_SPEAKER 0x01 /* output to built-in speaker */ -#define AUDIO_HEADPHONE 0x02 /* output to headphone jack */ -#define AUDIO_LINE_OUT 0x04 /* output to line out */ - -/* - * input ports (usually only one at a time) - */ -#define AUDIO_MICROPHONE 0x01 /* input from microphone */ -#define AUDIO_LINE_IN 0x02 /* input from line in */ -#define AUDIO_CD 0x04 /* input from on-board CD inputs */ -#define AUDIO_INTERNAL_CD_IN AUDIO_CD /* input from internal CDROM */ -#define AUDIO_ANALOG_LOOPBACK 0x40 /* input from output */ - - -/* - * This macro initializes an audio_info structure to 'harmless' values. - * Note that (~0) might not be a harmless value for a flag that was - * a signed int. - */ -#define AUDIO_INITINFO(i) { \ - unsigned int *__x__; \ - for (__x__ = (unsigned int *)(i); \ - (char *) __x__ < (((char *)(i)) + sizeof (audio_info_t)); \ - *__x__++ = ~0); \ -} - -/* - * These allow testing for what the user wants to set - */ -#define AUD_INITVALUE (~0) -#define Modify(X) ((unsigned int)(X) != AUD_INITVALUE) -#define Modifys(X) ((X) != (unsigned short)AUD_INITVALUE) -#define Modifyc(X) ((X) != (unsigned char)AUD_INITVALUE) - -/* - * Parameter for the AUDIO_GETDEV ioctl to determine current - * audio devices. - */ -#define MAX_AUDIO_DEV_LEN (16) -typedef struct audio_device { - char name[MAX_AUDIO_DEV_LEN]; - char version[MAX_AUDIO_DEV_LEN]; - char config[MAX_AUDIO_DEV_LEN]; -} audio_device_t; - - -/* - * Ioctl calls for the audio device. - */ - -/* - * AUDIO_GETINFO retrieves the current state of the audio device. - * - * AUDIO_SETINFO copies all fields of the audio_info structure whose - * values are not set to the initialized value (-1) to the device state. - * It performs an implicit AUDIO_GETINFO to return the new state of the - * device. Note that the record.samples and play.samples fields are set - * to the last value before the AUDIO_SETINFO took effect. This allows - * an application to reset the counters while atomically retrieving the - * last value. - * - * AUDIO_DRAIN suspends the calling process until the write buffers are - * empty. - * - * AUDIO_GETDEV returns a structure of type audio_device_t which contains - * three strings. The string "name" is a short identifying string (for - * example, the SBus Fcode name string), the string "version" identifies - * the current version of the device, and the "config" string identifies - * the specific configuration of the audio stream. All fields are - * device-dependent -- see the device specific manual pages for details. - * - * AUDIO_GETDEV_SUNOS returns a number which is an audio device defined - * herein (making it not too portable) - * - * AUDIO_FLUSH stops all playback and recording, clears all queued buffers, - * resets error counters, and restarts recording and playback as appropriate - * for the current sampling mode. - */ -#define AUDIO_GETINFO _IOR('A', 1, audio_info_t) -#define AUDIO_SETINFO _IOWR('A', 2, audio_info_t) -#define AUDIO_DRAIN _IO('A', 3) -#define AUDIO_GETDEV _IOR('A', 4, audio_device_t) -#define AUDIO_GETDEV_SUNOS _IOR('A', 4, int) -#define AUDIO_FLUSH _IO('A', 5) - -/* Define possible audio hardware configurations for - * old SunOS-style AUDIO_GETDEV ioctl */ -#define AUDIO_DEV_UNKNOWN (0) /* not defined */ -#define AUDIO_DEV_AMD (1) /* audioamd device */ -#define AUDIO_DEV_SPEAKERBOX (2) /* dbri device with speakerbox */ -#define AUDIO_DEV_CODEC (3) /* dbri device (internal speaker) */ -#define AUDIO_DEV_CS4231 (5) /* cs4231 device */ - -/* - * The following ioctl sets the audio device into an internal loopback mode, - * if the hardware supports this. The argument is TRUE to set loopback, - * FALSE to reset to normal operation. If the hardware does not support - * internal loopback, the ioctl should fail with EINVAL. - * Causes ADC data to be digitally mixed in and sent to the DAC. - */ -#define AUDIO_DIAG_LOOPBACK _IOW('A', 101, int) - -#endif /* _AUDIOIO_H_ */ diff --git a/include/asm-sparc/kbio.h b/include/asm-sparc/kbio.h deleted file mode 100644 index 3cf496bdf399a44b7fcfde6b9d86a4cb73587f2a..0000000000000000000000000000000000000000 --- a/include/asm-sparc/kbio.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef __LINUX_KBIO_H -#define __LINUX_KBIO_H - -/* Return keyboard type */ -#define KIOCTYPE _IOR('k', 9, int) -/* Return Keyboard layout */ -#define KIOCLAYOUT _IOR('k', 20, int) - -enum { - TR_NONE, - TR_ASCII, /* keyboard is in regular state */ - TR_EVENT, /* keystrokes sent as firm events */ - TR_UNTRANS_EVENT /* EVENT+up and down+no translation */ -}; - -/* Return the current keyboard translation */ -#define KIOCGTRANS _IOR('k', 5, int) -/* Set the keyboard translation */ -#define KIOCTRANS _IOW('k', 0, int) - -/* Send a keyboard command */ -#define KIOCCMD _IOW('k', 8, int) - -/* Return if keystrokes are being sent to /dev/kbd */ - -/* Set routing of keystrokes to /dev/kbd */ -#define KIOCSDIRECT _IOW('k', 10, int) - -/* Set keyboard leds */ -#define KIOCSLED _IOW('k', 14, unsigned char) - -/* Get keyboard leds */ -#define KIOCGLED _IOR('k', 15, unsigned char) - -/* Used by KIOC[GS]RATE */ -struct kbd_rate { - unsigned char delay; /* Delay in Hz before first repeat. */ - unsigned char rate; /* In characters per second (0..50). */ -}; - -/* Set keyboard rate */ -#define KIOCSRATE _IOW('k', 40, struct kbd_rate) - -/* Get keyboard rate */ -#define KIOCGRATE _IOW('k', 41, struct kbd_rate) - -/* Top bit records if the key is up or down */ -#define KBD_UP 0x80 - -/* Usable information */ -#define KBD_KEYMASK 0x7f - -/* All keys up */ -#define KBD_IDLE 0x75 - -#endif /* __LINUX_KBIO_H */ diff --git a/include/asm-sparc/ptrace.h b/include/asm-sparc/ptrace.h index a8ecb2d6977aadcb20bd40a652403a2f3f7fde07..714497099a423ae54d35a2d0e6d0985a219d043c 100644 --- a/include/asm-sparc/ptrace.h +++ b/include/asm-sparc/ptrace.h @@ -60,6 +60,9 @@ struct sparc_stackf { #define STACKFRAME_SZ sizeof(struct sparc_stackf) #ifdef __KERNEL__ + +#define __ARCH_SYS_PTRACE 1 + #define user_mode(regs) (!((regs)->psr & PSR_PS)) #define instruction_pointer(regs) ((regs)->pc) unsigned long profile_pc(struct pt_regs *); diff --git a/include/asm-sparc/termios.h b/include/asm-sparc/termios.h index 0a8ad4cac125c68825139282e79e7ca8a449bafe..d05f83c809893c404a9fc897fdf5164fbac6fbc9 100644 --- a/include/asm-sparc/termios.h +++ b/include/asm-sparc/termios.h @@ -38,15 +38,6 @@ struct sunos_ttysize { int st_columns; /* Columns on the terminal */ }; -/* Used for packet mode */ -#define TIOCPKT_DATA 0 -#define TIOCPKT_FLUSHREAD 1 -#define TIOCPKT_FLUSHWRITE 2 -#define TIOCPKT_STOP 4 -#define TIOCPKT_START 8 -#define TIOCPKT_NOSTOP 16 -#define TIOCPKT_DOSTOP 32 - struct winsize { unsigned short ws_row; unsigned short ws_col; diff --git a/include/asm-sparc/vuid_event.h b/include/asm-sparc/vuid_event.h deleted file mode 100644 index 7781e9f2fdd31ed568753206cf308e62011c8e0d..0000000000000000000000000000000000000000 --- a/include/asm-sparc/vuid_event.h +++ /dev/null @@ -1,41 +0,0 @@ -/* SunOS Virtual User Input Device (VUID) compatibility */ - - -typedef struct firm_event { - unsigned short id; /* tag for this event */ - unsigned char pair_type; /* unused by X11 */ - unsigned char pair; /* unused by X11 */ - int value; /* VKEY_UP, VKEY_DOWN or delta */ - struct timeval time; -} Firm_event; - -enum { - FE_PAIR_NONE, - FE_PAIR_SET, - FE_PAIR_DELTA, - FE_PAIR_ABSOLUTE -}; - -/* VUID stream formats */ -#define VUID_NATIVE 0 /* Native byte stream format */ -#define VUID_FIRM_EVENT 1 /* send firm_event structures */ - -/* ioctls */ - /* Set input device byte stream format (any of VUID_{NATIVE,FIRM_EVENT}) */ -#define VUIDSFORMAT _IOW('v', 1, int) - /* Retrieve input device byte stream format */ -#define VUIDGFORMAT _IOR('v', 2, int) - -/* Possible tag values */ -/* mouse buttons: */ -#define MS_LEFT 0x7f20 -#define MS_MIDDLE 0x7f21 -#define MS_RIGHT 0x7f22 -/* motion: */ -#define LOC_X_DELTA 0x7f80 -#define LOC_Y_DELTA 0x7f81 -#define LOC_X_ABSOLUTE 0x7f82 /* X compat, unsupported */ -#define LOC_Y_ABSOLUTE 0x7f83 /* X compat, unsupported */ - -#define VKEY_UP 0 -#define VKEY_DOWN 1 diff --git a/include/asm-sparc64/audioio.h b/include/asm-sparc64/audioio.h deleted file mode 100644 index cf16173f521b00a026c3a4eceb8f243fb1ab52fa..0000000000000000000000000000000000000000 --- a/include/asm-sparc64/audioio.h +++ /dev/null @@ -1,234 +0,0 @@ -/* - * include/asm-sparc/audioio.h - * - * Sparc Audio Midlayer - * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) - */ - -#ifndef _AUDIOIO_H_ -#define _AUDIOIO_H_ - -/* - * SunOS/Solaris /dev/audio interface - */ - -#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) -#include -#include -#include -#endif - -/* - * This structure contains state information for audio device IO streams. - */ -typedef struct audio_prinfo { - /* - * The following values describe the audio data encoding. - */ - unsigned int sample_rate; /* samples per second */ - unsigned int channels; /* number of interleaved channels */ - unsigned int precision; /* bit-width of each sample */ - unsigned int encoding; /* data encoding method */ - - /* - * The following values control audio device configuration - */ - unsigned int gain; /* gain level: 0 - 255 */ - unsigned int port; /* selected I/O port (see below) */ - unsigned int avail_ports; /* available I/O ports (see below) */ - unsigned int _xxx[2]; /* Reserved for future use */ - - unsigned int buffer_size; /* I/O buffer size */ - - /* - * The following values describe driver state - */ - unsigned int samples; /* number of samples converted */ - unsigned int eof; /* End Of File counter (play only) */ - - unsigned char pause; /* non-zero for pause, zero to resume */ - unsigned char error; /* non-zero if overflow/underflow */ - unsigned char waiting; /* non-zero if a process wants access */ - unsigned char balance; /* stereo channel balance */ - - unsigned short minordev; - - /* - * The following values are read-only state flags - */ - unsigned char open; /* non-zero if open access permitted */ - unsigned char active; /* non-zero if I/O is active */ -} audio_prinfo_t; - - -/* - * This structure describes the current state of the audio device. - */ -typedef struct audio_info { - /* - * Per-stream information - */ - audio_prinfo_t play; /* output status information */ - audio_prinfo_t record; /* input status information */ - - /* - * Per-unit/channel information - */ - unsigned int monitor_gain; /* input to output mix: 0 - 255 */ - unsigned char output_muted; /* non-zero if output is muted */ - unsigned char _xxx[3]; /* Reserved for future use */ - unsigned int _yyy[3]; /* Reserved for future use */ -} audio_info_t; - - -/* - * Audio encoding types - */ -#define AUDIO_ENCODING_NONE (0) /* no encoding assigned */ -#define AUDIO_ENCODING_ULAW (1) /* u-law encoding */ -#define AUDIO_ENCODING_ALAW (2) /* A-law encoding */ -#define AUDIO_ENCODING_LINEAR (3) /* Linear PCM encoding */ -#define AUDIO_ENCODING_FLOAT (4) /* IEEE float (-1. <-> +1.) */ -#define AUDIO_ENCODING_DVI (104) /* DVI ADPCM */ -#define AUDIO_ENCODING_LINEAR8 (105) /* 8 bit UNSIGNED */ -#define AUDIO_ENCODING_LINEARLE (106) /* Linear PCM LE encoding */ - -/* - * These ranges apply to record, play, and monitor gain values - */ -#define AUDIO_MIN_GAIN (0) /* minimum gain value */ -#define AUDIO_MAX_GAIN (255) /* maximum gain value */ - -/* - * These values apply to the balance field to adjust channel gain values - */ -#define AUDIO_LEFT_BALANCE (0) /* left channel only */ -#define AUDIO_MID_BALANCE (32) /* equal left/right channel */ -#define AUDIO_RIGHT_BALANCE (64) /* right channel only */ -#define AUDIO_BALANCE_SHIFT (3) - -/* - * Generic minimum/maximum limits for number of channels, both modes - */ -#define AUDIO_MIN_PLAY_CHANNELS (1) -#define AUDIO_MAX_PLAY_CHANNELS (4) -#define AUDIO_MIN_REC_CHANNELS (1) -#define AUDIO_MAX_REC_CHANNELS (4) - -/* - * Generic minimum/maximum limits for sample precision - */ -#define AUDIO_MIN_PLAY_PRECISION (8) -#define AUDIO_MAX_PLAY_PRECISION (32) -#define AUDIO_MIN_REC_PRECISION (8) -#define AUDIO_MAX_REC_PRECISION (32) - -/* - * Define some convenient names for typical audio ports - */ -/* - * output ports (several may be enabled simultaneously) - */ -#define AUDIO_SPEAKER 0x01 /* output to built-in speaker */ -#define AUDIO_HEADPHONE 0x02 /* output to headphone jack */ -#define AUDIO_LINE_OUT 0x04 /* output to line out */ - -/* - * input ports (usually only one at a time) - */ -#define AUDIO_MICROPHONE 0x01 /* input from microphone */ -#define AUDIO_LINE_IN 0x02 /* input from line in */ -#define AUDIO_CD 0x04 /* input from on-board CD inputs */ -#define AUDIO_INTERNAL_CD_IN AUDIO_CD /* input from internal CDROM */ -#define AUDIO_ANALOG_LOOPBACK 0x40 /* input from output */ - - -/* - * This macro initializes an audio_info structure to 'harmless' values. - * Note that (~0) might not be a harmless value for a flag that was - * a signed int. - */ -#define AUDIO_INITINFO(i) { \ - unsigned int *__x__; \ - for (__x__ = (unsigned int *)(i); \ - (char *) __x__ < (((char *)(i)) + sizeof (audio_info_t)); \ - *__x__++ = ~0); \ -} - -/* - * These allow testing for what the user wants to set - */ -#define AUD_INITVALUE (~0) -#define Modify(X) ((unsigned int)(X) != AUD_INITVALUE) -#define Modifys(X) ((X) != (unsigned short)AUD_INITVALUE) -#define Modifyc(X) ((X) != (unsigned char)AUD_INITVALUE) - -/* - * Parameter for the AUDIO_GETDEV ioctl to determine current - * audio devices. - */ -#define MAX_AUDIO_DEV_LEN (16) -typedef struct audio_device { - char name[MAX_AUDIO_DEV_LEN]; - char version[MAX_AUDIO_DEV_LEN]; - char config[MAX_AUDIO_DEV_LEN]; -} audio_device_t; - - -/* - * Ioctl calls for the audio device. - */ - -/* - * AUDIO_GETINFO retrieves the current state of the audio device. - * - * AUDIO_SETINFO copies all fields of the audio_info structure whose - * values are not set to the initialized value (-1) to the device state. - * It performs an implicit AUDIO_GETINFO to return the new state of the - * device. Note that the record.samples and play.samples fields are set - * to the last value before the AUDIO_SETINFO took effect. This allows - * an application to reset the counters while atomically retrieving the - * last value. - * - * AUDIO_DRAIN suspends the calling process until the write buffers are - * empty. - * - * AUDIO_GETDEV returns a structure of type audio_device_t which contains - * three strings. The string "name" is a short identifying string (for - * example, the SBus Fcode name string), the string "version" identifies - * the current version of the device, and the "config" string identifies - * the specific configuration of the audio stream. All fields are - * device-dependent -- see the device specific manual pages for details. - * - * AUDIO_GETDEV_SUNOS returns a number which is an audio device defined - * herein (making it not too portable) - * - * AUDIO_FLUSH stops all playback and recording, clears all queued buffers, - * resets error counters, and restarts recording and playback as appropriate - * for the current sampling mode. - */ -#define AUDIO_GETINFO _IOR('A', 1, audio_info_t) -#define AUDIO_SETINFO _IOWR('A', 2, audio_info_t) -#define AUDIO_DRAIN _IO('A', 3) -#define AUDIO_GETDEV _IOR('A', 4, audio_device_t) -#define AUDIO_GETDEV_SUNOS _IOR('A', 4, int) -#define AUDIO_FLUSH _IO('A', 5) - -/* Define possible audio hardware configurations for - * old SunOS-style AUDIO_GETDEV ioctl */ -#define AUDIO_DEV_UNKNOWN (0) /* not defined */ -#define AUDIO_DEV_AMD (1) /* audioamd device */ -#define AUDIO_DEV_SPEAKERBOX (2) /* dbri device with speakerbox */ -#define AUDIO_DEV_CODEC (3) /* dbri device (internal speaker) */ -#define AUDIO_DEV_CS4231 (5) /* cs4231 device */ - -/* - * The following ioctl sets the audio device into an internal loopback mode, - * if the hardware supports this. The argument is TRUE to set loopback, - * FALSE to reset to normal operation. If the hardware does not support - * internal loopback, the ioctl should fail with EINVAL. - * Causes ADC data to be digitally mixed in and sent to the DAC. - */ -#define AUDIO_DIAG_LOOPBACK _IOW('A', 101, int) - -#endif /* _AUDIOIO_H_ */ diff --git a/include/asm-sparc64/ebus.h b/include/asm-sparc64/ebus.h index 543e4e500a72f46d882fd1f9cf7a5d2ddd3f9114..7a408a030f52fabb24919687684613c759928883 100644 --- a/include/asm-sparc64/ebus.h +++ b/include/asm-sparc64/ebus.h @@ -79,6 +79,7 @@ extern int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr, size_t len); extern void ebus_dma_prepare(struct ebus_dma_info *p, int write); extern unsigned int ebus_dma_residue(struct ebus_dma_info *p); +extern unsigned int ebus_dma_addr(struct ebus_dma_info *p); extern void ebus_dma_enable(struct ebus_dma_info *p, int on); extern struct linux_ebus *ebus_chain; diff --git a/include/asm-sparc64/kbio.h b/include/asm-sparc64/kbio.h deleted file mode 100644 index 3cf496bdf399a44b7fcfde6b9d86a4cb73587f2a..0000000000000000000000000000000000000000 --- a/include/asm-sparc64/kbio.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef __LINUX_KBIO_H -#define __LINUX_KBIO_H - -/* Return keyboard type */ -#define KIOCTYPE _IOR('k', 9, int) -/* Return Keyboard layout */ -#define KIOCLAYOUT _IOR('k', 20, int) - -enum { - TR_NONE, - TR_ASCII, /* keyboard is in regular state */ - TR_EVENT, /* keystrokes sent as firm events */ - TR_UNTRANS_EVENT /* EVENT+up and down+no translation */ -}; - -/* Return the current keyboard translation */ -#define KIOCGTRANS _IOR('k', 5, int) -/* Set the keyboard translation */ -#define KIOCTRANS _IOW('k', 0, int) - -/* Send a keyboard command */ -#define KIOCCMD _IOW('k', 8, int) - -/* Return if keystrokes are being sent to /dev/kbd */ - -/* Set routing of keystrokes to /dev/kbd */ -#define KIOCSDIRECT _IOW('k', 10, int) - -/* Set keyboard leds */ -#define KIOCSLED _IOW('k', 14, unsigned char) - -/* Get keyboard leds */ -#define KIOCGLED _IOR('k', 15, unsigned char) - -/* Used by KIOC[GS]RATE */ -struct kbd_rate { - unsigned char delay; /* Delay in Hz before first repeat. */ - unsigned char rate; /* In characters per second (0..50). */ -}; - -/* Set keyboard rate */ -#define KIOCSRATE _IOW('k', 40, struct kbd_rate) - -/* Get keyboard rate */ -#define KIOCGRATE _IOW('k', 41, struct kbd_rate) - -/* Top bit records if the key is up or down */ -#define KBD_UP 0x80 - -/* Usable information */ -#define KBD_KEYMASK 0x7f - -/* All keys up */ -#define KBD_IDLE 0x75 - -#endif /* __LINUX_KBIO_H */ diff --git a/include/asm-sparc64/kprobes.h b/include/asm-sparc64/kprobes.h index a8d326a598f0215994f1d0b2bf7cfb56cb355b17..7ba845320f5c05d0d9450d89cbf2dacf72b72819 100644 --- a/include/asm-sparc64/kprobes.h +++ b/include/asm-sparc64/kprobes.h @@ -3,6 +3,7 @@ #include #include +#include typedef u32 kprobe_opcode_t; @@ -18,6 +19,25 @@ struct arch_specific_insn { kprobe_opcode_t insn[MAX_INSN_SIZE]; }; +struct prev_kprobe { + struct kprobe *kp; + unsigned int status; + unsigned long orig_tnpc; + unsigned long orig_tstate_pil; +}; + +/* per-cpu kprobe control block */ +struct kprobe_ctlblk { + unsigned long kprobe_status; + unsigned long kprobe_orig_tnpc; + unsigned long kprobe_orig_tstate_pil; + long *jprobe_saved_esp; + struct pt_regs jprobe_saved_regs; + struct pt_regs *jprobe_saved_regs_location; + struct sparc_stackf jprobe_saved_stack; + struct prev_kprobe prev_kprobe; +}; + #ifdef CONFIG_KPROBES extern int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *data); diff --git a/include/asm-sparc64/mmu_context.h b/include/asm-sparc64/mmu_context.h index 87c43c67866e9bb6afbc5cdd8186d3edecdf5816..08ba72d7722c9c4be4fe7d96eb534ceb75d968c4 100644 --- a/include/asm-sparc64/mmu_context.h +++ b/include/asm-sparc64/mmu_context.h @@ -87,37 +87,35 @@ extern void __flush_tlb_mm(unsigned long, unsigned long); static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk) { unsigned long ctx_valid; + int cpu; + /* Note: page_table_lock is used here to serialize switch_mm + * and activate_mm, and their calls to get_new_mmu_context. + * This use of page_table_lock is unrelated to its other uses. + */ spin_lock(&mm->page_table_lock); - if (CTX_VALID(mm->context)) - ctx_valid = 1; - else - ctx_valid = 0; + ctx_valid = CTX_VALID(mm->context); + if (!ctx_valid) + get_new_mmu_context(mm); + spin_unlock(&mm->page_table_lock); if (!ctx_valid || (old_mm != mm)) { - if (!ctx_valid) - get_new_mmu_context(mm); - load_secondary_context(mm); reload_tlbmiss_state(tsk, mm); } - { - int cpu = smp_processor_id(); - - /* Even if (mm == old_mm) we _must_ check - * the cpu_vm_mask. If we do not we could - * corrupt the TLB state because of how - * smp_flush_tlb_{page,range,mm} on sparc64 - * and lazy tlb switches work. -DaveM - */ - if (!ctx_valid || !cpu_isset(cpu, mm->cpu_vm_mask)) { - cpu_set(cpu, mm->cpu_vm_mask); - __flush_tlb_mm(CTX_HWBITS(mm->context), - SECONDARY_CONTEXT); - } + /* Even if (mm == old_mm) we _must_ check + * the cpu_vm_mask. If we do not we could + * corrupt the TLB state because of how + * smp_flush_tlb_{page,range,mm} on sparc64 + * and lazy tlb switches work. -DaveM + */ + cpu = smp_processor_id(); + if (!ctx_valid || !cpu_isset(cpu, mm->cpu_vm_mask)) { + cpu_set(cpu, mm->cpu_vm_mask); + __flush_tlb_mm(CTX_HWBITS(mm->context), + SECONDARY_CONTEXT); } - spin_unlock(&mm->page_table_lock); } #define deactivate_mm(tsk,mm) do { } while (0) @@ -127,6 +125,10 @@ static inline void activate_mm(struct mm_struct *active_mm, struct mm_struct *mm { int cpu; + /* Note: page_table_lock is used here to serialize switch_mm + * and activate_mm, and their calls to get_new_mmu_context. + * This use of page_table_lock is unrelated to its other uses. + */ spin_lock(&mm->page_table_lock); if (!CTX_VALID(mm->context)) get_new_mmu_context(mm); diff --git a/include/asm-sparc64/ptrace.h b/include/asm-sparc64/ptrace.h index 6194f771e9fc738536b0165a2ee7f6b99e625b34..7eba90c6c7535394859269ea5610f31650a3b247 100644 --- a/include/asm-sparc64/ptrace.h +++ b/include/asm-sparc64/ptrace.h @@ -94,6 +94,9 @@ struct sparc_trapf { #define STACKFRAME32_SZ sizeof(struct sparc_stackf32) #ifdef __KERNEL__ + +#define __ARCH_SYS_PTRACE 1 + #define force_successful_syscall_return() \ do { current_thread_info()->syscall_noerror = 1; \ } while (0) diff --git a/include/asm-sparc64/termios.h b/include/asm-sparc64/termios.h index 9777a9cca88aa900a68545fccb1e7939bcf51a81..ee26a071c67776074f9386249c8b3af040370077 100644 --- a/include/asm-sparc64/termios.h +++ b/include/asm-sparc64/termios.h @@ -38,15 +38,6 @@ struct sunos_ttysize { int st_columns; /* Columns on the terminal */ }; -/* Used for packet mode */ -#define TIOCPKT_DATA 0 -#define TIOCPKT_FLUSHREAD 1 -#define TIOCPKT_FLUSHWRITE 2 -#define TIOCPKT_STOP 4 -#define TIOCPKT_START 8 -#define TIOCPKT_NOSTOP 16 -#define TIOCPKT_DOSTOP 32 - struct winsize { unsigned short ws_row; unsigned short ws_col; diff --git a/include/asm-sparc64/tlb.h b/include/asm-sparc64/tlb.h index 66138d959df5e25be7ceaed865f3873f8ae51a18..61c01882b5629db7f665943255fc7574e3ee7c46 100644 --- a/include/asm-sparc64/tlb.h +++ b/include/asm-sparc64/tlb.h @@ -58,11 +58,9 @@ static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm, unsigned i static inline void tlb_flush_mmu(struct mmu_gather *mp) { if (mp->need_flush) { + free_pages_and_swap_cache(mp->pages, mp->pages_nr); + mp->pages_nr = 0; mp->need_flush = 0; - if (!tlb_fast_mode(mp)) { - free_pages_and_swap_cache(mp->pages, mp->pages_nr); - mp->pages_nr = 0; - } } } @@ -78,11 +76,9 @@ static inline void tlb_finish_mmu(struct mmu_gather *mp, unsigned long start, un { tlb_flush_mmu(mp); - if (mp->fullmm) { - if (CTX_VALID(mp->mm->context)) - do_flush_tlb_mm(mp->mm); + if (mp->fullmm) mp->fullmm = 0; - } else + else flush_tlb_pending(); /* keep the page table cache within bounds */ @@ -93,11 +89,11 @@ static inline void tlb_finish_mmu(struct mmu_gather *mp, unsigned long start, un static inline void tlb_remove_page(struct mmu_gather *mp, struct page *page) { - mp->need_flush = 1; if (tlb_fast_mode(mp)) { free_page_and_swap_cache(page); return; } + mp->need_flush = 1; mp->pages[mp->pages_nr++] = page; if (mp->pages_nr >= FREE_PTE_NR) tlb_flush_mmu(mp); diff --git a/include/asm-sparc64/vuid_event.h b/include/asm-sparc64/vuid_event.h deleted file mode 100644 index 9ef4d17ad08f0ee9c05f2a2dfa212ba49e9f898e..0000000000000000000000000000000000000000 --- a/include/asm-sparc64/vuid_event.h +++ /dev/null @@ -1,40 +0,0 @@ -/* SunOS Virtual User Input Device (VUID) compatibility */ - -typedef struct firm_event { - unsigned short id; /* tag for this event */ - unsigned char pair_type; /* unused by X11 */ - unsigned char pair; /* unused by X11 */ - int value; /* VKEY_UP, VKEY_DOWN or delta */ - struct timeval time; -} Firm_event; - -enum { - FE_PAIR_NONE, - FE_PAIR_SET, - FE_PAIR_DELTA, - FE_PAIR_ABSOLUTE -}; - -/* VUID stream formats */ -#define VUID_NATIVE 0 /* Native byte stream format */ -#define VUID_FIRM_EVENT 1 /* send firm_event structures */ - -/* ioctls */ - /* Set input device byte stream format (any of VUID_{NATIVE,FIRM_EVENT}) */ -#define VUIDSFORMAT _IOW('v', 1, int) - /* Retrieve input device byte stream format */ -#define VUIDGFORMAT _IOR('v', 2, int) - -/* Possible tag values */ -/* mouse buttons: */ -#define MS_LEFT 0x7f20 -#define MS_MIDDLE 0x7f21 -#define MS_RIGHT 0x7f22 -/* motion: */ -#define LOC_X_DELTA 0x7f80 -#define LOC_Y_DELTA 0x7f81 -#define LOC_X_ABSOLUTE 0x7f82 /* X compat, unsupported */ -#define LOC_Y_ABSOLUTE 0x7f83 /* X compat, unsupported */ - -#define VKEY_UP 0 -#define VKEY_DOWN 1 diff --git a/include/asm-um/ldt-i386.h b/include/asm-um/ldt-i386.h new file mode 100644 index 0000000000000000000000000000000000000000..b42662929b6c04b9980d1607b5856d609976ca7b --- /dev/null +++ b/include/asm-um/ldt-i386.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2004 Fujitsu Siemens Computers GmbH + * Licensed under the GPL + * + * Author: Bodo Stroesser + */ + +#ifndef __ASM_LDT_I386_H +#define __ASM_LDT_I386_H + +#include "asm/semaphore.h" +#include "asm/arch/ldt.h" + +struct mmu_context_skas; +extern void ldt_host_info(void); +extern long init_new_ldt(struct mmu_context_skas * to_mm, + struct mmu_context_skas * from_mm); +extern void free_ldt(struct mmu_context_skas * mm); + +#define LDT_PAGES_MAX \ + ((LDT_ENTRIES * LDT_ENTRY_SIZE)/PAGE_SIZE) +#define LDT_ENTRIES_PER_PAGE \ + (PAGE_SIZE/LDT_ENTRY_SIZE) +#define LDT_DIRECT_ENTRIES \ + ((LDT_PAGES_MAX*sizeof(void *))/LDT_ENTRY_SIZE) + +struct ldt_entry { + __u32 a; + __u32 b; +}; + +typedef struct uml_ldt { + int entry_count; + struct semaphore semaphore; + union { + struct ldt_entry * pages[LDT_PAGES_MAX]; + struct ldt_entry entries[LDT_DIRECT_ENTRIES]; + }; +} uml_ldt_t; + +/* + * macros stolen from include/asm-i386/desc.h + */ +#define LDT_entry_a(info) \ + ((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff)) + +#define LDT_entry_b(info) \ + (((info)->base_addr & 0xff000000) | \ + (((info)->base_addr & 0x00ff0000) >> 16) | \ + ((info)->limit & 0xf0000) | \ + (((info)->read_exec_only ^ 1) << 9) | \ + ((info)->contents << 10) | \ + (((info)->seg_not_present ^ 1) << 15) | \ + ((info)->seg_32bit << 22) | \ + ((info)->limit_in_pages << 23) | \ + ((info)->useable << 20) | \ + 0x7000) + +#define LDT_empty(info) (\ + (info)->base_addr == 0 && \ + (info)->limit == 0 && \ + (info)->contents == 0 && \ + (info)->read_exec_only == 1 && \ + (info)->seg_32bit == 0 && \ + (info)->limit_in_pages == 0 && \ + (info)->seg_not_present == 1 && \ + (info)->useable == 0 ) + +#endif diff --git a/include/asm-um/ldt.h b/include/asm-um/ldt.h index e908439d338aef6c881ea0f4d2e9e5476136295d..4466ff6de0fde32afdd449c7f10959563ecaef4d 100644 --- a/include/asm-um/ldt.h +++ b/include/asm-um/ldt.h @@ -1,3 +1,72 @@ +/* + * Copyright (C) 2004 Fujitsu Siemens Computers GmbH + * Licensed under the GPL + * + * Author: Bodo Stroesser + */ + +#ifndef __ASM_LDT_I386_H +#define __ASM_LDT_I386_H + +#include "asm/semaphore.h" +#include "asm/arch/ldt.h" + +struct mmu_context_skas; +extern void ldt_host_info(void); +extern long init_new_ldt(struct mmu_context_skas * to_mm, + struct mmu_context_skas * from_mm); +extern void free_ldt(struct mmu_context_skas * mm); + +#define LDT_PAGES_MAX \ + ((LDT_ENTRIES * LDT_ENTRY_SIZE)/PAGE_SIZE) +#define LDT_ENTRIES_PER_PAGE \ + (PAGE_SIZE/LDT_ENTRY_SIZE) +#define LDT_DIRECT_ENTRIES \ + ((LDT_PAGES_MAX*sizeof(void *))/LDT_ENTRY_SIZE) + +struct ldt_entry { + __u32 a; + __u32 b; +}; + +typedef struct uml_ldt { + int entry_count; + struct semaphore semaphore; + union { + struct ldt_entry * pages[LDT_PAGES_MAX]; + struct ldt_entry entries[LDT_DIRECT_ENTRIES]; + }; +} uml_ldt_t; + +/* + * macros stolen from include/asm-i386/desc.h + */ +#define LDT_entry_a(info) \ + ((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff)) + +#define LDT_entry_b(info) \ + (((info)->base_addr & 0xff000000) | \ + (((info)->base_addr & 0x00ff0000) >> 16) | \ + ((info)->limit & 0xf0000) | \ + (((info)->read_exec_only ^ 1) << 9) | \ + ((info)->contents << 10) | \ + (((info)->seg_not_present ^ 1) << 15) | \ + ((info)->seg_32bit << 22) | \ + ((info)->limit_in_pages << 23) | \ + ((info)->useable << 20) | \ + 0x7000) + +#define LDT_empty(info) (\ + (info)->base_addr == 0 && \ + (info)->limit == 0 && \ + (info)->contents == 0 && \ + (info)->read_exec_only == 1 && \ + (info)->seg_32bit == 0 && \ + (info)->limit_in_pages == 0 && \ + (info)->seg_not_present == 1 && \ + (info)->useable == 0 ) + +#endif #ifndef __UM_LDT_H #define __UM_LDT_H diff --git a/include/asm-um/mmu_context.h b/include/asm-um/mmu_context.h index 2edb4f1f789cdb96e0208da409622db6f1eaa70b..9a0e48eb542e019d5e259f3972550649bb1e46a8 100644 --- a/include/asm-um/mmu_context.h +++ b/include/asm-um/mmu_context.h @@ -29,7 +29,8 @@ static inline void activate_mm(struct mm_struct *old, struct mm_struct *new) * possible. */ if (old != new && (current->flags & PF_BORROWED_MM)) - force_flush_all(); + CHOOSE_MODE(force_flush_all(), + switch_mm_skas(&new->context.skas.id)); } static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, diff --git a/include/asm-v850/atomic.h b/include/asm-v850/atomic.h index 8284aa7363f21ff7c75fb4377a297b34ba2fb2b6..395268a8c0dec1787fca9f39d29eab8df1d51797 100644 --- a/include/asm-v850/atomic.h +++ b/include/asm-v850/atomic.h @@ -31,7 +31,7 @@ typedef struct { int counter; } atomic_t; #define atomic_read(v) ((v)->counter) #define atomic_set(v,i) (((v)->counter) = (i)) -extern __inline__ int atomic_add_return (int i, volatile atomic_t *v) +static inline int atomic_add_return (int i, volatile atomic_t *v) { unsigned long flags; int res; diff --git a/include/asm-v850/bitops.h b/include/asm-v850/bitops.h index 0e5c2f210872b75165f4d622d63b2656352ec40f..b91e799763fdf4f3896b20abb17563323f717b76 100644 --- a/include/asm-v850/bitops.h +++ b/include/asm-v850/bitops.h @@ -30,7 +30,7 @@ * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. */ -extern __inline__ unsigned long ffz (unsigned long word) +static inline unsigned long ffz (unsigned long word) { unsigned long result = 0; @@ -135,7 +135,7 @@ extern __inline__ unsigned long ffz (unsigned long word) "m" (*((const char *)(addr) + ((nr) >> 3)))); \ __test_bit_res; \ }) -extern __inline__ int __test_bit (int nr, const void *addr) +static inline int __test_bit (int nr, const void *addr) { int res; __asm__ __volatile__ ("tst1 %1, [%2]; setf nz, %0" @@ -157,7 +157,7 @@ extern __inline__ int __test_bit (int nr, const void *addr) #define find_first_zero_bit(addr, size) \ find_next_zero_bit ((addr), (size), 0) -extern __inline__ int find_next_zero_bit(const void *addr, int size, int offset) +static inline int find_next_zero_bit(const void *addr, int size, int offset) { unsigned long *p = ((unsigned long *) addr) + (offset >> 5); unsigned long result = offset & ~31UL; diff --git a/include/asm-v850/delay.h b/include/asm-v850/delay.h index 1ce65d48a7c5acb22df5c52690d6eafee2571154..6d028e6b2354cf7cf3f0fcc11be735c09039d07c 100644 --- a/include/asm-v850/delay.h +++ b/include/asm-v850/delay.h @@ -16,7 +16,7 @@ #include -extern __inline__ void __delay(unsigned long loops) +static inline void __delay(unsigned long loops) { if (loops) __asm__ __volatile__ ("1: add -1, %0; bnz 1b" @@ -33,7 +33,7 @@ extern __inline__ void __delay(unsigned long loops) extern unsigned long loops_per_jiffy; -extern __inline__ void udelay(unsigned long usecs) +static inline void udelay(unsigned long usecs) { register unsigned long full_loops, part_loops; diff --git a/include/asm-v850/hw_irq.h b/include/asm-v850/hw_irq.h index 4bdc98edb9f854b01018bd8fe259ed0f1f6caf6e..a8aab4342712a77a7e1f2ac49ae8b536fb270d40 100644 --- a/include/asm-v850/hw_irq.h +++ b/include/asm-v850/hw_irq.h @@ -1,7 +1,7 @@ #ifndef __V850_HW_IRQ_H__ #define __V850_HW_IRQ_H__ -extern inline void hw_resend_irq (struct hw_interrupt_type *h, unsigned int i) +static inline void hw_resend_irq (struct hw_interrupt_type *h, unsigned int i) { } diff --git a/include/asm-v850/processor.h b/include/asm-v850/processor.h index d41f925f5182508117482d4d1ce0ccfbaa41c289..98f929427d3dcfde6e8a825ba0f7620f3743511d 100644 --- a/include/asm-v850/processor.h +++ b/include/asm-v850/processor.h @@ -59,7 +59,7 @@ struct thread_struct { /* Do necessary setup to start up a newly executed thread. */ -extern inline void start_thread (struct pt_regs *regs, +static inline void start_thread (struct pt_regs *regs, unsigned long pc, unsigned long usp) { regs->pc = pc; @@ -68,7 +68,7 @@ extern inline void start_thread (struct pt_regs *regs, } /* Free all resources held by a thread. */ -extern inline void release_thread (struct task_struct *dead_task) +static inline void release_thread (struct task_struct *dead_task) { } diff --git a/include/asm-v850/semaphore.h b/include/asm-v850/semaphore.h index df6cdecf6c1f12522bb3f49ff30ba20ae9811309..735baaf3a16e8fe7478f8307a10be49f1c6a7a09 100644 --- a/include/asm-v850/semaphore.h +++ b/include/asm-v850/semaphore.h @@ -24,7 +24,7 @@ struct semaphore { #define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC (name,1) #define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC (name,0) -extern inline void sema_init (struct semaphore *sem, int val) +static inline void sema_init (struct semaphore *sem, int val) { *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val); } @@ -52,14 +52,14 @@ extern int __down_interruptible (struct semaphore * sem); extern int __down_trylock (struct semaphore * sem); extern void __up (struct semaphore * sem); -extern inline void down (struct semaphore * sem) +static inline void down (struct semaphore * sem) { might_sleep(); if (atomic_dec_return (&sem->count) < 0) __down (sem); } -extern inline int down_interruptible (struct semaphore * sem) +static inline int down_interruptible (struct semaphore * sem) { int ret = 0; might_sleep(); @@ -68,7 +68,7 @@ extern inline int down_interruptible (struct semaphore * sem) return ret; } -extern inline int down_trylock (struct semaphore *sem) +static inline int down_trylock (struct semaphore *sem) { int ret = 0; if (atomic_dec_return (&sem->count) < 0) @@ -76,7 +76,7 @@ extern inline int down_trylock (struct semaphore *sem) return ret; } -extern inline void up (struct semaphore * sem) +static inline void up (struct semaphore * sem) { if (atomic_inc_return (&sem->count) <= 0) __up (sem); diff --git a/include/asm-v850/system.h b/include/asm-v850/system.h index 20f4c738c04efea475020764849ce8d1009488fa..107decbd6e6cfc038a1729a77154f97ed5f65204 100644 --- a/include/asm-v850/system.h +++ b/include/asm-v850/system.h @@ -81,7 +81,7 @@ static inline int irqs_disabled (void) ((__typeof__ (*(ptr)))__xchg ((unsigned long)(with), (ptr), sizeof (*(ptr)))) #define tas(ptr) (xchg ((ptr), 1)) -extern inline unsigned long __xchg (unsigned long with, +static inline unsigned long __xchg (unsigned long with, __volatile__ void *ptr, int size) { unsigned long tmp, flags; diff --git a/include/asm-v850/tlbflush.h b/include/asm-v850/tlbflush.h index 501e4498172c02e274ece2eb57a10126f1a5a47a..5f2f85f636ea74bc0fe019ef51c53e978ac9a348 100644 --- a/include/asm-v850/tlbflush.h +++ b/include/asm-v850/tlbflush.h @@ -56,12 +56,12 @@ static inline void flush_tlb_range(struct vm_area_struct *vma, BUG (); } -extern inline void flush_tlb_kernel_page(unsigned long addr) +static inline void flush_tlb_kernel_page(unsigned long addr) { BUG (); } -extern inline void flush_tlb_pgtables(struct mm_struct *mm, +static inline void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start, unsigned long end) { BUG (); diff --git a/include/asm-v850/uaccess.h b/include/asm-v850/uaccess.h index 188b28597cf1f680a96f271fa7e3244ffdc74831..64563c409bb2219f2fcb24fa06e5f540a1aa0c59 100644 --- a/include/asm-v850/uaccess.h +++ b/include/asm-v850/uaccess.h @@ -14,7 +14,7 @@ #define VERIFY_READ 0 #define VERIFY_WRITE 1 -extern inline int access_ok (int type, const void *addr, unsigned long size) +static inline int access_ok (int type, const void *addr, unsigned long size) { /* XXX I guess we should check against real ram bounds at least, and possibly make sure ADDR is not within the kernel. diff --git a/include/asm-v850/unaligned.h b/include/asm-v850/unaligned.h index 65e38362142b8bcdd9ae7d5a14b13abfd3e2287a..e30b18653a94bf8cde19b2573888692d1d46d55a 100644 --- a/include/asm-v850/unaligned.h +++ b/include/asm-v850/unaligned.h @@ -82,19 +82,19 @@ extern int __bug_unaligned_x(void *ptr); }) -extern inline void __put_unaligned_2(__u32 __v, register __u8 *__p) +static inline void __put_unaligned_2(__u32 __v, register __u8 *__p) { *__p++ = __v; *__p++ = __v >> 8; } -extern inline void __put_unaligned_4(__u32 __v, register __u8 *__p) +static inline void __put_unaligned_4(__u32 __v, register __u8 *__p) { __put_unaligned_2(__v >> 16, __p + 2); __put_unaligned_2(__v, __p); } -extern inline void __put_unaligned_8(const unsigned long long __v, register __u8 *__p) +static inline void __put_unaligned_8(const unsigned long long __v, register __u8 *__p) { /* * tradeoff: 8 bytes of stack for all unaligned puts (2 diff --git a/include/asm-x86_64/elf.h b/include/asm-x86_64/elf.h index a60a35e792226248cbbcc4e4e44ff266b7e5a04a..43862cd6a569d7a20886325f1a19a53a51782925 100644 --- a/include/asm-x86_64/elf.h +++ b/include/asm-x86_64/elf.h @@ -149,6 +149,8 @@ extern void set_personality_64bit(void); */ #define elf_read_implies_exec(ex, executable_stack) (executable_stack != EXSTACK_DISABLE_X) +struct task_struct; + extern int dump_task_regs (struct task_struct *, elf_gregset_t *); extern int dump_task_fpu (struct task_struct *, elf_fpregset_t *); diff --git a/include/asm-x86_64/kprobes.h b/include/asm-x86_64/kprobes.h index 6d6d883fdf6d0f2862d3a41771f15ba09ed04c5a..4dd7a7e148d450d6ba93c347c655cc8975ac8230 100644 --- a/include/asm-x86_64/kprobes.h +++ b/include/asm-x86_64/kprobes.h @@ -25,6 +25,7 @@ */ #include #include +#include struct pt_regs; @@ -48,6 +49,24 @@ struct arch_specific_insn { kprobe_opcode_t *insn; }; +struct prev_kprobe { + struct kprobe *kp; + unsigned long status; + unsigned long old_rflags; + unsigned long saved_rflags; +}; + +/* per-cpu kprobe control block */ +struct kprobe_ctlblk { + unsigned long kprobe_status; + unsigned long kprobe_old_rflags; + unsigned long kprobe_saved_rflags; + long *jprobe_saved_rsp; + struct pt_regs jprobe_saved_regs; + kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE]; + struct prev_kprobe prev_kprobe; +}; + /* trap3/1 are intr gates for kprobes. So, restore the status of IF, * if necessary, before executing the original int3/1 (trap) handler. */ diff --git a/include/asm-x86_64/pgtable.h b/include/asm-x86_64/pgtable.h index 7a07196a72022f56ebef52ace38ec35d88be7c9e..7309fffeec9a04fe0b45abd0b7a39060a9abe19d 100644 --- a/include/asm-x86_64/pgtable.h +++ b/include/asm-x86_64/pgtable.h @@ -105,6 +105,8 @@ static inline void pgd_clear (pgd_t * pgd) #define ptep_get_and_clear(mm,addr,xp) __pte(xchg(&(xp)->pte, 0)) +struct mm_struct; + static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long addr, pte_t *ptep, int full) { pte_t pte; diff --git a/include/asm-xtensa/elf.h b/include/asm-xtensa/elf.h index 64f1f53874fe4b65c875182220f1395bc4b01f82..de0667453b2ecb28ef6f6cac3b70a31af29b4282 100644 --- a/include/asm-xtensa/elf.h +++ b/include/asm-xtensa/elf.h @@ -209,6 +209,8 @@ extern void xtensa_elf_core_copy_regs (xtensa_gregset_t *, struct pt_regs *); #define SET_PERSONALITY(ex, ibcs2) set_personality(PER_LINUX_32BIT) +struct task_struct; + extern void do_copy_regs (xtensa_gregset_t*, struct pt_regs*, struct task_struct*); extern void do_restore_regs (xtensa_gregset_t*, struct pt_regs*, diff --git a/include/asm-xtensa/pgtable.h b/include/asm-xtensa/pgtable.h index 987e3b802313561d837b7f43f1e53133db0d0656..7b15afb70c5678b624c55a2a85c715b0e67d241e 100644 --- a/include/asm-xtensa/pgtable.h +++ b/include/asm-xtensa/pgtable.h @@ -278,6 +278,8 @@ static inline void update_pte(pte_t *ptep, pte_t pteval) #endif } +struct mm_struct; + static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pteval) { @@ -294,6 +296,7 @@ set_pmd(pmd_t *pmdp, pmd_t pmdval) #endif } +struct vm_area_struct; static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, diff --git a/include/asm-xtensa/semaphore.h b/include/asm-xtensa/semaphore.h index 2a10e193b92972504e12c68199cc5691cd084a04..f10c3487cd4c5cb26b18d2e92df574395c349594 100644 --- a/include/asm-xtensa/semaphore.h +++ b/include/asm-xtensa/semaphore.h @@ -38,6 +38,7 @@ struct semaphore { static inline void sema_init (struct semaphore *sem, int val) { atomic_set(&sem->count, val); + sem->sleepers = 0; init_waitqueue_head(&sem->wait); } diff --git a/include/linux/acct.h b/include/linux/acct.h index 19f70462b3be6f9cdd3abdbb07f4b646370b7aeb..93c5b3cdf9519a34d73f6e4eec697b3b0836b395 100644 --- a/include/linux/acct.h +++ b/include/linux/acct.h @@ -117,12 +117,15 @@ struct acct_v3 #include #ifdef CONFIG_BSD_PROCESS_ACCT +struct vfsmount; struct super_block; +extern void acct_auto_close_mnt(struct vfsmount *m); extern void acct_auto_close(struct super_block *sb); extern void acct_process(long exitcode); extern void acct_update_integrals(struct task_struct *tsk); extern void acct_clear_integrals(struct task_struct *tsk); #else +#define acct_auto_close_mnt(x) do { } while (0) #define acct_auto_close(x) do { } while (0) #define acct_process(x) do { } while (0) #define acct_update_integrals(x) do { } while (0) diff --git a/include/linux/aio.h b/include/linux/aio.h index 0decf66117c16c995a35ab8017440dc73368972c..403d71dcb7c818beb2b43101af33d6133f6d5622 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h @@ -183,6 +183,7 @@ struct kioctx { struct list_head active_reqs; /* used for cancellation */ struct list_head run_list; /* used for kicked reqs */ + /* sys_io_setup currently limits this to an unsigned int */ unsigned max_reqs; struct aio_ring_info ring_info; @@ -234,7 +235,7 @@ static inline struct kiocb *list_kiocb(struct list_head *h) } /* for sysctl: */ -extern atomic_t aio_nr; -extern unsigned aio_max_nr; +extern unsigned long aio_nr; +extern unsigned long aio_max_nr; #endif /* __LINUX__AIO_H */ diff --git a/include/linux/cn_proc.h b/include/linux/cn_proc.h new file mode 100644 index 0000000000000000000000000000000000000000..70ab5631738084935a1ef5cad40a2131f4d776c0 --- /dev/null +++ b/include/linux/cn_proc.h @@ -0,0 +1,127 @@ +/* + * cn_proc.h - process events connector + * + * Copyright (C) Matt Helsley, IBM Corp. 2005 + * Based on cn_fork.h by Nguyen Anh Quynh and Guillaume Thouvenin + * Original copyright notice follows: + * Copyright (C) 2005 Nguyen Anh Quynh + * Copyright (C) 2005 Guillaume Thouvenin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CN_PROC_H +#define CN_PROC_H + +#include +#include + +/* + * Userspace sends this enum to register with the kernel that it is listening + * for events on the connector. + */ +enum proc_cn_mcast_op { + PROC_CN_MCAST_LISTEN = 1, + PROC_CN_MCAST_IGNORE = 2 +}; + +/* + * From the user's point of view, the process + * ID is the thread group ID and thread ID is the internal + * kernel "pid". So, fields are assigned as follow: + * + * In user space - In kernel space + * + * parent process ID = parent->tgid + * parent thread ID = parent->pid + * child process ID = child->tgid + * child thread ID = child->pid + */ + +struct proc_event { + enum what { + /* Use successive bits so the enums can be used to record + * sets of events as well + */ + PROC_EVENT_NONE = 0x00000000, + PROC_EVENT_FORK = 0x00000001, + PROC_EVENT_EXEC = 0x00000002, + PROC_EVENT_UID = 0x00000004, + PROC_EVENT_GID = 0x00000040, + /* "next" should be 0x00000400 */ + /* "last" is the last process event: exit */ + PROC_EVENT_EXIT = 0x80000000 + } what; + __u32 cpu; + union { /* must be last field of proc_event struct */ + struct { + __u32 err; + } ack; + + struct fork_proc_event { + pid_t parent_pid; + pid_t parent_tgid; + pid_t child_pid; + pid_t child_tgid; + } fork; + + struct exec_proc_event { + pid_t process_pid; + pid_t process_tgid; + } exec; + + struct id_proc_event { + pid_t process_pid; + pid_t process_tgid; + union { + uid_t ruid; /* current->uid */ + gid_t rgid; /* current->gid */ + } r; + union { + uid_t euid; + gid_t egid; + } e; + } id; + + struct exit_proc_event { + pid_t process_pid; + pid_t process_tgid; + __u32 exit_code, exit_signal; + } exit; + } event_data; +}; + +#ifdef __KERNEL__ +#ifdef CONFIG_PROC_EVENTS +void proc_fork_connector(struct task_struct *task); +void proc_exec_connector(struct task_struct *task); +void proc_id_connector(struct task_struct *task, int which_id); +void proc_exit_connector(struct task_struct *task); +#else +static inline void proc_fork_connector(struct task_struct *task) +{} + +static inline void proc_exec_connector(struct task_struct *task) +{} + +static inline void proc_id_connector(struct task_struct *task, + int which_id) +{} + +static inline void proc_exit_connector(struct task_struct *task) +{} +#endif /* CONFIG_PROC_EVENTS */ +#endif /* __KERNEL__ */ +#endif /* CN_PROC_H */ diff --git a/include/linux/connector.h b/include/linux/connector.h index 95952cc1f525b509b365191738911c2d992d19ac..c5769c6585f4cf9c623b8e086ba830310cff3256 100644 --- a/include/linux/connector.h +++ b/include/linux/connector.h @@ -27,6 +27,12 @@ #define CN_IDX_CONNECTOR 0xffffffff #define CN_VAL_CONNECTOR 0xffffffff +/* + * Process Events connector unique ids -- used for message routing + */ +#define CN_IDX_PROC 0x1 +#define CN_VAL_PROC 0x1 + #define CN_NETLINK_USERS 1 /* diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h index 725be90ef55ecb1c239707c8d98297f8ad0087dd..f8e5587a0f92178cf3bd1604f4b4c7cc27cd3f68 100644 --- a/include/linux/console_struct.h +++ b/include/linux/console_struct.h @@ -9,6 +9,8 @@ * to achieve effects such as fast scrolling by changing the origin. */ +#include + struct vt_struct; #define NPAR 16 diff --git a/include/linux/dcache.h b/include/linux/dcache.h index ab04b4f9b0db0e822dc08bc5a2abccdab32cadd3..46a2ba6175954880fcdfa89bc9a9a063f4e76443 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -329,6 +329,7 @@ static inline int d_mountpoint(struct dentry *dentry) } extern struct vfsmount *lookup_mnt(struct vfsmount *, struct dentry *); +extern struct vfsmount *__lookup_mnt(struct vfsmount *, struct dentry *, int); extern struct dentry *lookup_create(struct nameidata *nd, int is_dir); extern int sysctl_vfs_cache_pressure; diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index d2c390eff1b2267d77557a7b8cd3372f578c6d11..93535f0932167818e5e7e9c168188cbed0626df9 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -453,10 +453,11 @@ struct ethtool_ops { * it was foced up into this mode or autonegotiated. */ -/* The forced speed, 10Mb, 100Mb, gigabit, 10GbE. */ +/* The forced speed, 10Mb, 100Mb, gigabit, 2.5Gb, 10GbE. */ #define SPEED_10 10 #define SPEED_100 100 #define SPEED_1000 1000 +#define SPEED_2500 2500 #define SPEED_10000 10000 /* Duplex, half or full. */ diff --git a/include/linux/fb.h b/include/linux/fb.h index c698055266d062b09fa7e19b447144c67fd82c22..e7ff98e395f620c5b17625683176bf9d85ab8fdb 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -810,7 +810,6 @@ struct fb_info { extern int fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var); extern int fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var); extern int fb_blank(struct fb_info *info, int blank); -extern int soft_cursor(struct fb_info *info, struct fb_cursor *cursor); extern void cfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect); extern void cfb_copyarea(struct fb_info *info, const struct fb_copyarea *area); extern void cfb_imageblit(struct fb_info *info, const struct fb_image *image); @@ -898,11 +897,13 @@ extern struct fb_videomode *fb_match_mode(struct fb_var_screeninfo *var, struct list_head *head); extern struct fb_videomode *fb_find_best_mode(struct fb_var_screeninfo *var, struct list_head *head); -extern struct fb_videomode *fb_find_nearest_mode(struct fb_var_screeninfo *var, +extern struct fb_videomode *fb_find_nearest_mode(struct fb_videomode *mode, struct list_head *head); extern void fb_destroy_modelist(struct list_head *head); extern void fb_videomode_to_modelist(struct fb_videomode *modedb, int num, struct list_head *head); +extern struct fb_videomode *fb_find_best_display(struct fb_monspecs *specs, + struct list_head *head); /* drivers/video/fbcmap.c */ extern int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp); diff --git a/include/linux/file.h b/include/linux/file.h index f5bbd4c508b3da00b3af27dc20f2178996cc9496..d3b1a15d5f21b378731bd2fca44edd2be5d3dc5d 100644 --- a/include/linux/file.h +++ b/include/linux/file.h @@ -59,9 +59,9 @@ extern void FASTCALL(set_close_on_exec(unsigned int fd, int flag)); extern void put_filp(struct file *); extern int get_unused_fd(void); extern void FASTCALL(put_unused_fd(unsigned int fd)); -struct kmem_cache_s; -extern void filp_ctor(void * objp, struct kmem_cache_s *cachep, unsigned long cflags); -extern void filp_dtor(void * objp, struct kmem_cache_s *cachep, unsigned long dflags); +struct kmem_cache; +extern void filp_ctor(void * objp, struct kmem_cache *cachep, unsigned long cflags); +extern void filp_dtor(void * objp, struct kmem_cache *cachep, unsigned long dflags); extern struct file ** alloc_fd_array(int); extern void free_fd_array(struct file **, int); diff --git a/include/linux/font.h b/include/linux/font.h index 53b129f07f6f294a896ce4bcc62133641f79d9ef..8aac48c37f3db1c7ef6fa00383e1a41a987d44d2 100644 --- a/include/linux/font.h +++ b/include/linux/font.h @@ -31,6 +31,7 @@ struct font_desc { #define SUN12x22_IDX 7 #define ACORN8x8_IDX 8 #define MINI4x6_IDX 9 +#define RL_IDX 10 extern const struct font_desc font_vga_8x8, font_vga_8x16, @@ -41,6 +42,7 @@ extern const struct font_desc font_vga_8x8, font_sun_8x16, font_sun_12x22, font_acorn_8x8, + font_rl, font_mini_4x6; /* Find a font with a specific name */ diff --git a/include/linux/fs.h b/include/linux/fs.h index 6d6226732c93ba96e5edf946e2c934f3e23b390b..1b5f502a4b8fdb303f932079ac1f4498113d1374 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -104,6 +104,10 @@ extern int dir_notify_enable; #define MS_MOVE 8192 #define MS_REC 16384 #define MS_VERBOSE 32768 +#define MS_UNBINDABLE (1<<17) /* change to unbindable */ +#define MS_PRIVATE (1<<18) /* change to private */ +#define MS_SLAVE (1<<19) /* change to slave */ +#define MS_SHARED (1<<20) /* change to shared */ #define MS_POSIXACL (1<<16) /* VFS does not apply the umask */ #define MS_ACTIVE (1<<30) #define MS_NOUSER (1<<31) @@ -264,6 +268,7 @@ typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset, #define ATTR_ATTR_FLAG 1024 #define ATTR_KILL_SUID 2048 #define ATTR_KILL_SGID 4096 +#define ATTR_FILE 8192 /* * This is the Inode Attributes structure, used for notify_change(). It @@ -283,6 +288,13 @@ struct iattr { struct timespec ia_atime; struct timespec ia_mtime; struct timespec ia_ctime; + + /* + * Not an attribute, but an auxilary info for filesystems wanting to + * implement an ftruncate() like method. NOTE: filesystem should + * check for (ia_valid & ATTR_FILE), and not for (ia_file != NULL). + */ + struct file *ia_file; }; /* @@ -1088,6 +1100,8 @@ int sync_inode(struct inode *inode, struct writeback_control *wbc); * @get_name: find the name for a given inode in a given directory * @get_parent: find the parent of a given directory * @get_dentry: find a dentry for the inode given a file handle sub-fragment + * @find_exported_dentry: + * set by the exporting module to a standard helper function. * * Description: * The export_operations structure provides a means for nfsd to communicate @@ -1239,7 +1253,12 @@ extern int unregister_filesystem(struct file_system_type *); extern struct vfsmount *kern_mount(struct file_system_type *); extern int may_umount_tree(struct vfsmount *); extern int may_umount(struct vfsmount *); +extern void umount_tree(struct vfsmount *, int, struct list_head *); +extern void release_mounts(struct list_head *); extern long do_mount(char *, char *, char *, unsigned long, void *); +extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int); +extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *, + struct vfsmount *); extern int vfs_statfs(struct super_block *, struct kstatfs *); @@ -1288,7 +1307,7 @@ static inline int break_lease(struct inode *inode, unsigned int mode) /* fs/open.c */ -extern int do_truncate(struct dentry *, loff_t start); +extern int do_truncate(struct dentry *, loff_t start, struct file *filp); extern long do_sys_open(const char __user *filename, int flags, int mode); extern struct file *filp_open(const char *, int, int); extern struct file * dentry_open(struct dentry *, struct vfsmount *, int); diff --git a/include/linux/fuse.h b/include/linux/fuse.h index f98854c2abd7a9dffa35a5e091d954e81c34cfb0..b76b558b03d481376c6a41d75d42786a2dae168e 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -14,7 +14,7 @@ #define FUSE_KERNEL_VERSION 7 /** Minor version number of this interface */ -#define FUSE_KERNEL_MINOR_VERSION 2 +#define FUSE_KERNEL_MINOR_VERSION 3 /** The node ID of the root inode */ #define FUSE_ROOT_ID 1 @@ -61,6 +61,7 @@ struct fuse_kstatfs { #define FATTR_SIZE (1 << 3) #define FATTR_ATIME (1 << 4) #define FATTR_MTIME (1 << 5) +#define FATTR_FH (1 << 6) /** * Flags returned by the OPEN request @@ -99,7 +100,9 @@ enum fuse_opcode { FUSE_OPENDIR = 27, FUSE_READDIR = 28, FUSE_RELEASEDIR = 29, - FUSE_FSYNCDIR = 30 + FUSE_FSYNCDIR = 30, + FUSE_ACCESS = 34, + FUSE_CREATE = 35 }; /* Conservative buffer size for the client */ @@ -152,12 +155,25 @@ struct fuse_link_in { struct fuse_setattr_in { __u32 valid; __u32 padding; - struct fuse_attr attr; + __u64 fh; + __u64 size; + __u64 unused1; + __u64 atime; + __u64 mtime; + __u64 unused2; + __u32 atimensec; + __u32 mtimensec; + __u32 unused3; + __u32 mode; + __u32 unused4; + __u32 uid; + __u32 gid; + __u32 unused5; }; struct fuse_open_in { __u32 flags; - __u32 padding; + __u32 mode; }; struct fuse_open_out { @@ -222,6 +238,11 @@ struct fuse_getxattr_out { __u32 padding; }; +struct fuse_access_in { + __u32 mask; + __u32 padding; +}; + struct fuse_init_in_out { __u32 major; __u32 minor; diff --git a/include/linux/if_ppp.h b/include/linux/if_ppp.h index 572aff7daa216fd9956407f6bae82bad480ca5da..768372f07caab7928a284acf592174608eb87213 100644 --- a/include/linux/if_ppp.h +++ b/include/linux/if_ppp.h @@ -21,7 +21,7 @@ */ /* - * ==FILEVERSION 20000724== + * ==FILEVERSION 20050812== * * NOTE TO MAINTAINERS: * If you modify this file at all, please set the above date. @@ -35,6 +35,8 @@ #ifndef _IF_PPP_H_ #define _IF_PPP_H_ +#include + /* * Packet sizes */ @@ -70,7 +72,8 @@ #define SC_LOG_RAWIN 0x00080000 /* log all chars received */ #define SC_LOG_FLUSH 0x00100000 /* log all chars flushed */ #define SC_SYNC 0x00200000 /* synchronous serial mode */ -#define SC_MASK 0x0f200fff /* bits that user can change */ +#define SC_MUST_COMP 0x00400000 /* no uncompressed packets may be sent or received */ +#define SC_MASK 0x0f600fff /* bits that user can change */ /* state bits */ #define SC_XMIT_BUSY 0x10000000 /* (used by isdn_ppp?) */ diff --git a/include/linux/input.h b/include/linux/input.h index f623c745c21cee3691862f54bc56cedd1e78504e..3c5823368ddb4e680f0bf702e75efd4eed4e8d97 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1007,7 +1007,7 @@ static inline void input_put_device(struct input_dev *dev) class_device_put(&dev->cdev); } -void input_register_device(struct input_dev *); +int input_register_device(struct input_dev *); void input_unregister_device(struct input_dev *); void input_register_handler(struct input_handler *); diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 18d010bee635dafc4156b54234c1c89db14737e1..cd6bd001ba4edbc68dfc5b52f08ef3bb832c785e 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -94,7 +94,7 @@ extern struct resource iomem_resource; extern int request_resource(struct resource *root, struct resource *new); extern struct resource * ____request_resource(struct resource *root, struct resource *new); extern int release_resource(struct resource *new); -extern int insert_resource(struct resource *parent, struct resource *new); +extern __deprecated_for_modules int insert_resource(struct resource *parent, struct resource *new); extern int allocate_resource(struct resource *root, struct resource *new, unsigned long size, unsigned long min, unsigned long max, diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h index 938d55b813a5f600050fcc557331195b036fa12c..d6276e60b3bf3672343046f49c63d0af3e2b9987 100644 --- a/include/linux/ipmi.h +++ b/include/linux/ipmi.h @@ -256,10 +256,7 @@ struct ipmi_recv_msg }; /* Allocate and free the receive message. */ -static inline void ipmi_free_recv_msg(struct ipmi_recv_msg *msg) -{ - msg->done(msg); -} +void ipmi_free_recv_msg(struct ipmi_recv_msg *msg); struct ipmi_user_hndl { diff --git a/include/linux/irq.h b/include/linux/irq.h index 69681c3b1f05f8fac09efb8ad5334c60b65686c0..c516382fbec2fa5fb5871937ba0bab6de48d4dfd 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -10,6 +10,7 @@ */ #include +#include /* cpu_online_map */ #if !defined(CONFIG_ARCH_S390) diff --git a/include/linux/jbd.h b/include/linux/jbd.h index be197eb900777167fedecdce824be0c2275a78d5..aa56172c6fed9533136aab5f98a43a2912bf19eb 100644 --- a/include/linux/jbd.h +++ b/include/linux/jbd.h @@ -611,6 +611,9 @@ struct transaction_s * @j_revoke: The revoke table - maintains the list of revoked blocks in the * current transaction. * @j_revoke_table: alternate revoke tables for j_revoke + * @j_wbuf: array of buffer_heads for journal_commit_transaction + * @j_wbufsize: maximum number of buffer_heads allowed in j_wbuf, the + * number that will fit in j_blocksize * @j_private: An opaque pointer to fs-private information. */ diff --git a/include/linux/jffs2.h b/include/linux/jffs2.h index 419fc953ac16ee0d52e67ebaa258efd578bfb7b9..cf792bb3c72655beafc28d29c72f25f14bf96a4b 100644 --- a/include/linux/jffs2.h +++ b/include/linux/jffs2.h @@ -5,10 +5,10 @@ * * Created by David Woodhouse * - * For licensing information, see the file 'LICENCE' in the + * For licensing information, see the file 'LICENCE' in the * jffs2 directory. * - * $Id: jffs2.h,v 1.34 2004/11/16 20:36:14 dwmw2 Exp $ + * $Id: jffs2.h,v 1.38 2005/09/26 11:37:23 havasi Exp $ * */ @@ -28,6 +28,9 @@ #define JFFS2_EMPTY_BITMASK 0xffff #define JFFS2_DIRTY_BITMASK 0x0000 +/* Summary node MAGIC marker */ +#define JFFS2_SUM_MAGIC 0x02851885 + /* We only allow a single char for length, and 0xFF is empty flash so we don't want it confused with a real length. Hence max 254. */ @@ -43,8 +46,6 @@ #define JFFS2_COMPR_COPY 0x04 #define JFFS2_COMPR_DYNRUBIN 0x05 #define JFFS2_COMPR_ZLIB 0x06 -#define JFFS2_COMPR_LZO 0x07 -#define JFFS2_COMPR_LZARI 0x08 /* Compatibility flags. */ #define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */ #define JFFS2_NODE_ACCURATE 0x2000 @@ -62,15 +63,17 @@ #define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) #define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4) +#define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6) + // Maybe later... //#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) //#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4) -#define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at - mount time, don't wait for it to +#define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at + mount time, don't wait for it to happen later */ -#define JFFS2_INO_FLAG_USERCOMPR 2 /* User has requested a specific +#define JFFS2_INO_FLAG_USERCOMPR 2 /* User has requested a specific compression type */ @@ -101,7 +104,7 @@ struct jffs2_unknown_node struct jffs2_raw_dirent { jint16_t magic; - jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */ + jint16_t nodetype; /* == JFFS2_NODETYPE_DIRENT */ jint32_t totlen; jint32_t hdr_crc; jint32_t pino; @@ -117,7 +120,7 @@ struct jffs2_raw_dirent } __attribute__((packed)); /* The JFFS2 raw inode structure: Used for storage on physical media. */ -/* The uid, gid, atime, mtime and ctime members could be longer, but +/* The uid, gid, atime, mtime and ctime members could be longer, but are left like this for space efficiency. If and when people decide they really need them extended, it's simple enough to add support for a new type of raw node. @@ -125,7 +128,7 @@ struct jffs2_raw_dirent struct jffs2_raw_inode { jint16_t magic; /* A constant magic number. */ - jint16_t nodetype; /* == JFFS_NODETYPE_INODE */ + jint16_t nodetype; /* == JFFS2_NODETYPE_INODE */ jint32_t totlen; /* Total length of this node (inc data, etc.) */ jint32_t hdr_crc; jint32_t ino; /* Inode number. */ @@ -148,9 +151,25 @@ struct jffs2_raw_inode uint8_t data[0]; } __attribute__((packed)); -union jffs2_node_union { +struct jffs2_raw_summary +{ + jint16_t magic; + jint16_t nodetype; /* = JFFS2_NODETYPE_SUMMARY */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t sum_num; /* number of sum entries*/ + jint32_t cln_mkr; /* clean marker size, 0 = no cleanmarker */ + jint32_t padded; /* sum of the size of padding nodes */ + jint32_t sum_crc; /* summary information crc */ + jint32_t node_crc; /* node crc */ + jint32_t sum[0]; /* inode summary info */ +} __attribute__((packed)); + +union jffs2_node_union +{ struct jffs2_raw_inode i; struct jffs2_raw_dirent d; + struct jffs2_raw_summary s; struct jffs2_unknown_node u; }; diff --git a/include/linux/jffs2_fs_i.h b/include/linux/jffs2_fs_i.h index 6dbb1cce66460504deeb0bd15245eadfe3ed64ec..ef85ab56302b990f1b884f42deca2aeee3a4ec12 100644 --- a/include/linux/jffs2_fs_i.h +++ b/include/linux/jffs2_fs_i.h @@ -1,4 +1,4 @@ -/* $Id: jffs2_fs_i.h,v 1.17 2004/11/11 23:51:27 dwmw2 Exp $ */ +/* $Id: jffs2_fs_i.h,v 1.19 2005/11/07 11:14:52 gleixner Exp $ */ #ifndef _JFFS2_FS_I #define _JFFS2_FS_I @@ -25,13 +25,16 @@ struct jffs2_inode_info { /* There may be one datanode which isn't referenced by any of the above fragments, if it contains a metadata update but no actual data - or if this is a directory inode */ - /* This also holds the _only_ dnode for symlinks/device nodes, + /* This also holds the _only_ dnode for symlinks/device nodes, etc. */ struct jffs2_full_dnode *metadata; /* Directory entries */ struct jffs2_full_dirent *dents; + /* The target path if this is the inode of a symlink */ + unsigned char *target; + /* Some stuff we just have to keep in-core at all times, for each inode. */ struct jffs2_inode_cache *inocache; diff --git a/include/linux/jffs2_fs_sb.h b/include/linux/jffs2_fs_sb.h index 1e21546622de3b0bb2269550141774b5c5919402..4bcfb5570221a6fe7e1fa4347c9f5e78f6fc3b68 100644 --- a/include/linux/jffs2_fs_sb.h +++ b/include/linux/jffs2_fs_sb.h @@ -1,4 +1,4 @@ -/* $Id: jffs2_fs_sb.h,v 1.52 2005/05/19 16:12:17 gleixner Exp $ */ +/* $Id: jffs2_fs_sb.h,v 1.54 2005/09/21 13:37:34 dedekind Exp $ */ #ifndef _JFFS2_FS_SB #define _JFFS2_FS_SB @@ -20,7 +20,7 @@ struct jffs2_inodirty; /* A struct for the overall file system control. Pointers to - jffs2_sb_info structs are named `c' in the source code. + jffs2_sb_info structs are named `c' in the source code. Nee jffs_control */ struct jffs2_sb_info { @@ -35,7 +35,7 @@ struct jffs2_sb_info { struct completion gc_thread_start; /* GC thread start completion */ struct completion gc_thread_exit; /* GC thread exit completion port */ - struct semaphore alloc_sem; /* Used to protect all the following + struct semaphore alloc_sem; /* Used to protect all the following fields, and also to protect against out-of-order writing of nodes. And GC. */ uint32_t cleanmarker_size; /* Size of an _inline_ CLEANMARKER @@ -64,7 +64,7 @@ struct jffs2_sb_info { uint32_t nospc_dirty_size; uint32_t nr_blocks; - struct jffs2_eraseblock *blocks; /* The whole array of blocks. Used for getting blocks + struct jffs2_eraseblock *blocks; /* The whole array of blocks. Used for getting blocks * from the offset (blocks[ofs / sector_size]) */ struct jffs2_eraseblock *nextblock; /* The block we're currently filling */ @@ -82,25 +82,26 @@ struct jffs2_sb_info { struct list_head bad_list; /* Bad blocks. */ struct list_head bad_used_list; /* Bad blocks with valid data in. */ - spinlock_t erase_completion_lock; /* Protect free_list and erasing_list + spinlock_t erase_completion_lock; /* Protect free_list and erasing_list against erase completion handler */ wait_queue_head_t erase_wait; /* For waiting for erases to complete */ wait_queue_head_t inocache_wq; struct jffs2_inode_cache **inocache_list; spinlock_t inocache_lock; - + /* Sem to allow jffs2_garbage_collect_deletion_dirent to - drop the erase_completion_lock while it's holding a pointer + drop the erase_completion_lock while it's holding a pointer to an obsoleted node. I don't like this. Alternatives welcomed. */ struct semaphore erase_free_sem; + uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */ + #ifdef CONFIG_JFFS2_FS_WRITEBUFFER /* Write-behind buffer for NAND flash */ unsigned char *wbuf; uint32_t wbuf_ofs; uint32_t wbuf_len; - uint32_t wbuf_pagesize; struct jffs2_inodirty *wbuf_inodes; struct rw_semaphore wbuf_sem; /* Protects the write buffer */ @@ -112,6 +113,8 @@ struct jffs2_sb_info { uint32_t fsdata_len; #endif + struct jffs2_summary *summary; /* Summary information */ + /* OS-private pointer for getting back to master superblock info */ void *os_priv; }; diff --git a/include/linux/kernel.h b/include/linux/kernel.h index f1925ccc9fe1696496cdad0f9f2bcf583bf2eb5c..b1e407a4fbda1ec9b101c5e0bd2c3c4378b7bb5b 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -168,7 +168,7 @@ static inline void console_verbose(void) extern void bust_spinlocks(int yes); extern int oops_in_progress; /* If set, an oops, panic(), BUG() or die() is in progress */ -extern int panic_timeout; +extern __deprecated_for_modules int panic_timeout; extern int panic_on_oops; extern int tainted; extern const char *print_tainted(void); @@ -266,7 +266,6 @@ extern void dump_stack(void); /** * container_of - cast a member of a structure out to the containing structure - * * @ptr: the pointer to the member. * @type: the type of the container struct this is embedded in. * @member: the name of the member within the struct. diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h index dba27749b428368f159a91666797c218bfd60521..a484572c302e10fd43a81aa3cdffd9c2be6eb07b 100644 --- a/include/linux/kernel_stat.h +++ b/include/linux/kernel_stat.h @@ -6,6 +6,7 @@ #include #include #include +#include #include /* @@ -43,11 +44,10 @@ extern unsigned long long nr_context_switches(void); */ static inline int kstat_irqs(int irq) { - int i, sum=0; + int cpu, sum = 0; - for (i = 0; i < NR_CPUS; i++) - if (cpu_possible(i)) - sum += kstat_cpu(i).irqs[irq]; + for_each_cpu(cpu) + sum += kstat_cpu(cpu).irqs[irq]; return sum; } diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index e30afdca79174f9a01b0b538dca138f62bf697f2..e373c4a9de53601a3f6e85bf1623a2b1d896f36c 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h @@ -33,6 +33,9 @@ #include #include #include +#include +#include +#include #include @@ -106,6 +109,9 @@ struct jprobe { kprobe_opcode_t *entry; /* probe handling code to jump to */ }; +DECLARE_PER_CPU(struct kprobe *, current_kprobe); +DECLARE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); + #ifdef ARCH_SUPPORTS_KRETPROBES extern void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs); #else /* ARCH_SUPPORTS_KRETPROBES */ @@ -142,17 +148,7 @@ struct kretprobe_instance { }; #ifdef CONFIG_KPROBES -/* Locks kprobe: irq must be disabled */ -void lock_kprobes(void); -void unlock_kprobes(void); - -/* kprobe running now on this CPU? */ -static inline int kprobe_running(void) -{ - extern unsigned int kprobe_cpu; - return kprobe_cpu == smp_processor_id(); -} - +extern spinlock_t kretprobe_lock; extern int arch_prepare_kprobe(struct kprobe *p); extern void arch_copy_kprobe(struct kprobe *p); extern void arch_arm_kprobe(struct kprobe *p); @@ -163,10 +159,26 @@ extern void show_registers(struct pt_regs *regs); extern kprobe_opcode_t *get_insn_slot(void); extern void free_insn_slot(kprobe_opcode_t *slot); -/* Get the kprobe at this addr (if any). Must have called lock_kprobes */ +/* Get the kprobe at this addr (if any) - called with preemption disabled */ struct kprobe *get_kprobe(void *addr); struct hlist_head * kretprobe_inst_table_head(struct task_struct *tsk); +/* kprobe_running() will just return the current_kprobe on this CPU */ +static inline struct kprobe *kprobe_running(void) +{ + return (__get_cpu_var(current_kprobe)); +} + +static inline void reset_current_kprobe(void) +{ + __get_cpu_var(current_kprobe) = NULL; +} + +static inline struct kprobe_ctlblk *get_kprobe_ctlblk(void) +{ + return (&__get_cpu_var(kprobe_ctlblk)); +} + int register_kprobe(struct kprobe *p); void unregister_kprobe(struct kprobe *p); int setjmp_pre_handler(struct kprobe *, struct pt_regs *); @@ -183,9 +195,9 @@ void add_rp_inst(struct kretprobe_instance *ri); void kprobe_flush_task(struct task_struct *tk); void recycle_rp_inst(struct kretprobe_instance *ri); #else /* CONFIG_KPROBES */ -static inline int kprobe_running(void) +static inline struct kprobe *kprobe_running(void) { - return 0; + return NULL; } static inline int register_kprobe(struct kprobe *p) { diff --git a/include/linux/list.h b/include/linux/list.h index 084971f333fe30e7ffc312258d5cfb47afe6d1b8..fbfca73355a3a6791a3f2afb20fa41823c5f6fc6 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -601,7 +601,7 @@ static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) * or hlist_del_rcu(), running on this same list. * However, it is perfectly legal to run concurrently with * the _rcu list-traversal primitives, such as - * hlist_for_each_rcu(), used to prevent memory-consistency + * hlist_for_each_entry_rcu(), used to prevent memory-consistency * problems on Alpha CPUs. Regardless of the type of CPU, the * list-traversal primitive must be guarded by rcu_read_lock(). */ @@ -650,7 +650,7 @@ static inline void hlist_add_after(struct hlist_node *n, * or hlist_del_rcu(), running on this same list. * However, it is perfectly legal to run concurrently with * the _rcu list-traversal primitives, such as - * hlist_for_each_rcu(), used to prevent memory-consistency + * hlist_for_each_entry_rcu(), used to prevent memory-consistency * problems on Alpha CPUs. */ static inline void hlist_add_before_rcu(struct hlist_node *n, @@ -675,7 +675,7 @@ static inline void hlist_add_before_rcu(struct hlist_node *n, * or hlist_del_rcu(), running on this same list. * However, it is perfectly legal to run concurrently with * the _rcu list-traversal primitives, such as - * hlist_for_each_rcu(), used to prevent memory-consistency + * hlist_for_each_entry_rcu(), used to prevent memory-consistency * problems on Alpha CPUs. */ static inline void hlist_add_after_rcu(struct hlist_node *prev, @@ -699,11 +699,6 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev, for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ pos = n) -#define hlist_for_each_rcu(pos, head) \ - for ((pos) = (head)->first; \ - rcu_dereference((pos)) && ({ prefetch((pos)->next); 1; }); \ - (pos) = (pos)->next) - /** * hlist_for_each_entry - iterate over list of given type * @tpos: the type * to use as a loop counter. @@ -756,7 +751,7 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev, /** * hlist_for_each_entry_rcu - iterate over rcu list of given type - * @pos: the type * to use as a loop counter. + * @tpos: the type * to use as a loop counter. * @pos: the &struct hlist_node to use as a loop counter. * @head: the head for your list. * @member: the name of the hlist_node within the struct. diff --git a/include/linux/memory.h b/include/linux/memory.h index 0def328ab5cfbae5fc44a769f8bc30f5257a5b85..9a424383e6c60064fdb76ae8b0c7895351da69a0 100644 --- a/include/linux/memory.h +++ b/include/linux/memory.h @@ -54,6 +54,9 @@ struct memory_block { */ #define MEM_MAPPING_INVALID (1<<3) +struct notifier_block; +struct mem_section; + #ifndef CONFIG_MEMORY_HOTPLUG static inline int memory_dev_init(void) { diff --git a/include/linux/mm.h b/include/linux/mm.h index 5c1fb0a2e806bb4d13bd7b716c022bad64f59523..7b115feca4df23064dfd3ee80a66a9e638b0dcbd 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -932,13 +932,13 @@ int write_one_page(struct page *page, int wait); * turning readahead off */ int do_page_cache_readahead(struct address_space *mapping, struct file *filp, - unsigned long offset, unsigned long nr_to_read); + pgoff_t offset, unsigned long nr_to_read); int force_page_cache_readahead(struct address_space *mapping, struct file *filp, - unsigned long offset, unsigned long nr_to_read); -unsigned long page_cache_readahead(struct address_space *mapping, + pgoff_t offset, unsigned long nr_to_read); +unsigned long page_cache_readahead(struct address_space *mapping, struct file_ra_state *ra, struct file *filp, - unsigned long offset, + pgoff_t offset, unsigned long size); void handle_ra_miss(struct address_space *mapping, struct file_ra_state *ra, pgoff_t offset); diff --git a/include/linux/mount.h b/include/linux/mount.h index f8f39937e301be584f3258881f5740457234cb31..dd4e83eba933a3f345e55077b745afb7975c853a 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h @@ -17,12 +17,14 @@ #include #include -#define MNT_NOSUID 1 -#define MNT_NODEV 2 -#define MNT_NOEXEC 4 +#define MNT_NOSUID 0x01 +#define MNT_NODEV 0x02 +#define MNT_NOEXEC 0x04 +#define MNT_SHARED 0x10 /* if the vfsmount is a shared mount */ +#define MNT_UNBINDABLE 0x20 /* if the vfsmount is a unbindable mount */ +#define MNT_PNODE_MASK 0x30 /* propogation flag mask */ -struct vfsmount -{ +struct vfsmount { struct list_head mnt_hash; struct vfsmount *mnt_parent; /* fs we are mounted on */ struct dentry *mnt_mountpoint; /* dentry of mountpoint */ @@ -36,7 +38,12 @@ struct vfsmount char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */ struct list_head mnt_list; struct list_head mnt_expire; /* link in fs-specific expiry list */ + struct list_head mnt_share; /* circular list of shared mounts */ + struct list_head mnt_slave_list;/* list of slave mounts */ + struct list_head mnt_slave; /* slave list entry */ + struct vfsmount *mnt_master; /* slave is on master->mnt_slave_list */ struct namespace *mnt_namespace; /* containing namespace */ + int mnt_pinned; }; static inline struct vfsmount *mntget(struct vfsmount *mnt) @@ -46,15 +53,9 @@ static inline struct vfsmount *mntget(struct vfsmount *mnt) return mnt; } -extern void __mntput(struct vfsmount *mnt); - -static inline void mntput_no_expire(struct vfsmount *mnt) -{ - if (mnt) { - if (atomic_dec_and_test(&mnt->mnt_count)) - __mntput(mnt); - } -} +extern void mntput_no_expire(struct vfsmount *mnt); +extern void mnt_pin(struct vfsmount *mnt); +extern void mnt_unpin(struct vfsmount *mnt); static inline void mntput(struct vfsmount *mnt) { diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h new file mode 100644 index 0000000000000000000000000000000000000000..7a7fbe87fef0908906eea4cfd16682f849e943fd --- /dev/null +++ b/include/linux/mtd/bbm.h @@ -0,0 +1,122 @@ +/* + * linux/include/linux/mtd/bbm.h + * + * NAND family Bad Block Management (BBM) header file + * - Bad Block Table (BBT) implementation + * + * Copyright (c) 2005 Samsung Electronics + * Kyungmin Park + * + * Copyright (c) 2000-2005 + * Thomas Gleixner + * + */ +#ifndef __LINUX_MTD_BBM_H +#define __LINUX_MTD_BBM_H + +/* The maximum number of NAND chips in an array */ +#define NAND_MAX_CHIPS 8 + +/** + * struct nand_bbt_descr - bad block table descriptor + * @param options options for this descriptor + * @param pages the page(s) where we find the bbt, used with + * option BBT_ABSPAGE when bbt is searched, + * then we store the found bbts pages here. + * Its an array and supports up to 8 chips now + * @param offs offset of the pattern in the oob area of the page + * @param veroffs offset of the bbt version counter in the oob are of the page + * @param version version read from the bbt page during scan + * @param len length of the pattern, if 0 no pattern check is performed + * @param maxblocks maximum number of blocks to search for a bbt. This number of + * blocks is reserved at the end of the device + * where the tables are written. + * @param reserved_block_code if non-0, this pattern denotes a reserved + * (rather than bad) block in the stored bbt + * @param pattern pattern to identify bad block table or factory marked + * good / bad blocks, can be NULL, if len = 0 + * + * Descriptor for the bad block table marker and the descriptor for the + * pattern which identifies good and bad blocks. The assumption is made + * that the pattern and the version count are always located in the oob area + * of the first block. + */ +struct nand_bbt_descr { + int options; + int pages[NAND_MAX_CHIPS]; + int offs; + int veroffs; + uint8_t version[NAND_MAX_CHIPS]; + int len; + int maxblocks; + int reserved_block_code; + uint8_t *pattern; +}; + +/* Options for the bad block table descriptors */ + +/* The number of bits used per block in the bbt on the device */ +#define NAND_BBT_NRBITS_MSK 0x0000000F +#define NAND_BBT_1BIT 0x00000001 +#define NAND_BBT_2BIT 0x00000002 +#define NAND_BBT_4BIT 0x00000004 +#define NAND_BBT_8BIT 0x00000008 +/* The bad block table is in the last good block of the device */ +#define NAND_BBT_LASTBLOCK 0x00000010 +/* The bbt is at the given page, else we must scan for the bbt */ +#define NAND_BBT_ABSPAGE 0x00000020 +/* The bbt is at the given page, else we must scan for the bbt */ +#define NAND_BBT_SEARCH 0x00000040 +/* bbt is stored per chip on multichip devices */ +#define NAND_BBT_PERCHIP 0x00000080 +/* bbt has a version counter at offset veroffs */ +#define NAND_BBT_VERSION 0x00000100 +/* Create a bbt if none axists */ +#define NAND_BBT_CREATE 0x00000200 +/* Search good / bad pattern through all pages of a block */ +#define NAND_BBT_SCANALLPAGES 0x00000400 +/* Scan block empty during good / bad block scan */ +#define NAND_BBT_SCANEMPTY 0x00000800 +/* Write bbt if neccecary */ +#define NAND_BBT_WRITE 0x00001000 +/* Read and write back block contents when writing bbt */ +#define NAND_BBT_SAVECONTENT 0x00002000 +/* Search good / bad pattern on the first and the second page */ +#define NAND_BBT_SCAN2NDPAGE 0x00004000 + +/* The maximum number of blocks to scan for a bbt */ +#define NAND_BBT_SCAN_MAXBLOCKS 4 + +/* + * Constants for oob configuration + */ +#define ONENAND_BADBLOCK_POS 0 + +/** + * struct bbt_info - [GENERIC] Bad Block Table data structure + * @param bbt_erase_shift [INTERN] number of address bits in a bbt entry + * @param badblockpos [INTERN] position of the bad block marker in the oob area + * @param bbt [INTERN] bad block table pointer + * @param badblock_pattern [REPLACEABLE] bad block scan pattern used for initial bad block scan + * @param priv [OPTIONAL] pointer to private bbm date + */ +struct bbm_info { + int bbt_erase_shift; + int badblockpos; + int options; + + uint8_t *bbt; + + int (*isbad_bbt)(struct mtd_info *mtd, loff_t ofs, int allowbbt); + + /* TODO Add more NAND specific fileds */ + struct nand_bbt_descr *badblock_pattern; + + void *priv; +}; + +/* OneNAND BBT interface */ +extern int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd); +extern int onenand_default_bbt(struct mtd_info *mtd); + +#endif /* __LINUX_MTD_BBM_H */ diff --git a/include/linux/mtd/blktrans.h b/include/linux/mtd/blktrans.h index 4ebc2e5a16e28463a5894345affa226b659c5b96..f46afec6fbf8977d58097a2222cb681f0050d7ee 100644 --- a/include/linux/mtd/blktrans.h +++ b/include/linux/mtd/blktrans.h @@ -1,5 +1,5 @@ /* - * $Id: blktrans.h,v 1.5 2003/06/23 12:00:08 dwmw2 Exp $ + * $Id: blktrans.h,v 1.6 2005/11/07 11:14:54 gleixner Exp $ * * (C) 2003 David Woodhouse * @@ -67,6 +67,6 @@ extern int register_mtd_blktrans(struct mtd_blktrans_ops *tr); extern int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr); extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); - + #endif /* __MTD_TRANS_H__ */ diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h index e6b6a1c66bd5ded3bbca6dff3838585beef868e5..39f1430bd6d5fc2bee1702d96c6d0c11f78e8875 100644 --- a/include/linux/mtd/cfi.h +++ b/include/linux/mtd/cfi.h @@ -1,7 +1,7 @@ -/* Common Flash Interface structures +/* Common Flash Interface structures * See http://support.intel.com/design/flash/technote/index.htm - * $Id: cfi.h,v 1.54 2005/06/06 23:04:36 tpoynor Exp $ + * $Id: cfi.h,v 1.56 2005/11/07 11:14:54 gleixner Exp $ */ #ifndef __MTD_CFI_H__ @@ -82,8 +82,8 @@ static inline int cfi_interleave_supported(int i) } -/* NB: these values must represents the number of bytes needed to meet the - * device type (x8, x16, x32). Eg. a 32 bit device is 4 x 8 bytes. +/* NB: these values must represents the number of bytes needed to meet the + * device type (x8, x16, x32). Eg. a 32 bit device is 4 x 8 bytes. * These numbers are used in calculations. */ #define CFI_DEVICETYPE_X8 (8 / 8) @@ -173,6 +173,15 @@ struct cfi_intelext_regioninfo { struct cfi_intelext_blockinfo BlockTypes[1]; } __attribute__((packed)); +struct cfi_intelext_programming_regioninfo { + uint8_t ProgRegShift; + uint8_t Reserved1; + uint8_t ControlValid; + uint8_t Reserved2; + uint8_t ControlInvalid; + uint8_t Reserved3; +} __attribute__((packed)); + /* Vendor-Specific PRI for AMD/Fujitsu Extended Command Set (0x0002) */ struct cfi_pri_amdstd { @@ -250,7 +259,7 @@ static inline uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs, int interleave, int /* * Transforms the CFI command for the given geometry (bus width & interleave). * It looks too long to be inline, but in the common case it should almost all - * get optimised away. + * get optimised away. */ static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi) { @@ -259,7 +268,7 @@ static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cf unsigned long onecmd; int i; - /* We do it this way to give the compiler a fighting chance + /* We do it this way to give the compiler a fighting chance of optimising away all the crap for 'bankwidth' larger than an unsigned long, in the common case where that support is disabled */ @@ -270,7 +279,7 @@ static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cf wordwidth = map_bankwidth(map); words_per_bus = 1; } - + chip_mode = map_bankwidth(map) / cfi_interleave(cfi); chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map); @@ -289,7 +298,7 @@ static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cf break; } - /* Now replicate it across the size of an unsigned long, or + /* Now replicate it across the size of an unsigned long, or just to the bus width as appropriate */ switch (chips_per_word) { default: BUG(); @@ -305,7 +314,7 @@ static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cf ; } - /* And finally, for the multi-word case, replicate it + /* And finally, for the multi-word case, replicate it in all words in the structure */ for (i=0; i < words_per_bus; i++) { val.x[i] = onecmd; @@ -316,14 +325,14 @@ static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cf #define CMD(x) cfi_build_cmd((x), map, cfi) -static inline unsigned char cfi_merge_status(map_word val, struct map_info *map, +static inline unsigned long cfi_merge_status(map_word val, struct map_info *map, struct cfi_private *cfi) { int wordwidth, words_per_bus, chip_mode, chips_per_word; unsigned long onestat, res = 0; int i; - /* We do it this way to give the compiler a fighting chance + /* We do it this way to give the compiler a fighting chance of optimising away all the crap for 'bankwidth' larger than an unsigned long, in the common case where that support is disabled */ @@ -334,7 +343,7 @@ static inline unsigned char cfi_merge_status(map_word val, struct map_info *map, wordwidth = map_bankwidth(map); words_per_bus = 1; } - + chip_mode = map_bankwidth(map) / cfi_interleave(cfi); chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map); diff --git a/include/linux/mtd/doc2000.h b/include/linux/mtd/doc2000.h index 953e64fb8ac5d7193cb680a289428c1d67ab12bf..386a52cf8b1b4e0faccb7ee1ba8eee8b08c5ab90 100644 --- a/include/linux/mtd/doc2000.h +++ b/include/linux/mtd/doc2000.h @@ -1,12 +1,12 @@ -/* +/* * Linux driver for Disk-On-Chip devices * - * Copyright (C) 1999 Machine Vision Holdings, Inc. + * Copyright (C) 1999 Machine Vision Holdings, Inc. * Copyright (C) 2001-2003 David Woodhouse * Copyright (C) 2002-2003 Greg Ungerer * Copyright (C) 2002-2003 SnapGear Inc * - * $Id: doc2000.h,v 1.24 2005/01/05 12:40:38 dwmw2 Exp $ + * $Id: doc2000.h,v 1.25 2005/11/07 11:14:54 gleixner Exp $ * * Released under GPL */ @@ -75,10 +75,10 @@ #define DoC_Mplus_CtrlConfirm 0x1076 #define DoC_Mplus_Power 0x1fff -/* How to access the device? - * On ARM, it'll be mmap'd directly with 32-bit wide accesses. +/* How to access the device? + * On ARM, it'll be mmap'd directly with 32-bit wide accesses. * On PPC, it's mmap'd and 16-bit wide. - * Others use readb/writeb + * Others use readb/writeb */ #if defined(__arm__) #define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)))) @@ -172,7 +172,7 @@ struct DiskOnChip { unsigned long totlen; unsigned char ChipID; /* Type of DiskOnChip */ int ioreg; - + unsigned long mfr; /* Flash IDs - only one type of flash per device */ unsigned long id; int chipshift; @@ -180,10 +180,10 @@ struct DiskOnChip { char pageadrlen; char interleave; /* Internal interleaving - Millennium Plus style */ unsigned long erasesize; - + int curfloor; int curchip; - + int numchips; struct Nand *chips; struct mtd_info *nextdoc; diff --git a/include/linux/mtd/flashchip.h b/include/linux/mtd/flashchip.h index 675776fa3e27159a85b4a4792ca00986b4417eb1..a293a3b78e05741ff372229959aee31fb5b5e834 100644 --- a/include/linux/mtd/flashchip.h +++ b/include/linux/mtd/flashchip.h @@ -1,12 +1,12 @@ -/* +/* * struct flchip definition - * - * Contains information about the location and state of a given flash device + * + * Contains information about the location and state of a given flash device * * (C) 2000 Red Hat. GPLd. * - * $Id: flashchip.h,v 1.17 2005/03/14 18:27:15 bjd Exp $ + * $Id: flashchip.h,v 1.18 2005/11/07 11:14:54 gleixner Exp $ * */ @@ -15,11 +15,11 @@ /* For spinlocks. sched.h includes spinlock.h from whichever directory it * happens to be in - so we don't have to care whether we're on 2.2, which - * has asm/spinlock.h, or 2.4, which has linux/spinlock.h + * has asm/spinlock.h, or 2.4, which has linux/spinlock.h */ #include -typedef enum { +typedef enum { FL_READY, FL_STATUS, FL_CFI_QUERY, @@ -45,7 +45,7 @@ typedef enum { -/* NOTE: confusingly, this can be used to refer to more than one chip at a time, +/* NOTE: confusingly, this can be used to refer to more than one chip at a time, if they're interleaved. This can even refer to individual partitions on the same physical chip when present. */ diff --git a/include/linux/mtd/ftl.h b/include/linux/mtd/ftl.h index 3678459b4535ec66c32c6f4981475eb004bd5f2d..d996091133076141ab35abef365017fd956ae556 100644 --- a/include/linux/mtd/ftl.h +++ b/include/linux/mtd/ftl.h @@ -1,6 +1,6 @@ /* - * $Id: ftl.h,v 1.6 2003/01/24 13:20:04 dwmw2 Exp $ - * + * $Id: ftl.h,v 1.7 2005/11/07 11:14:54 gleixner Exp $ + * * Derived from (and probably identical to): * ftl.h 1.7 1999/10/25 20:23:17 * @@ -12,7 +12,7 @@ * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and - * limitations under the License. + * limitations under the License. * * The initial developer of the original code is David A. Hinds * . Portions created by David A. Hinds diff --git a/include/linux/mtd/gen_probe.h b/include/linux/mtd/gen_probe.h index 3d7bdec14f976e5bc455bc1b47a4347d40519609..256e7342ed1eead34a474f13d762f7b91885127b 100644 --- a/include/linux/mtd/gen_probe.h +++ b/include/linux/mtd/gen_probe.h @@ -1,14 +1,14 @@ /* * (C) 2001, 2001 Red Hat, Inc. * GPL'd - * $Id: gen_probe.h,v 1.3 2004/10/20 22:10:33 dwmw2 Exp $ + * $Id: gen_probe.h,v 1.4 2005/11/07 11:14:54 gleixner Exp $ */ #ifndef __LINUX_MTD_GEN_PROBE_H__ #define __LINUX_MTD_GEN_PROBE_H__ #include -#include +#include #include #include diff --git a/include/linux/mtd/jedec.h b/include/linux/mtd/jedec.h index 2ba0f700ddbcfe03c09d1dcf20e49554ae717ed5..9006feb218b93f36ac994917d3ae696d12c80318 100644 --- a/include/linux/mtd/jedec.h +++ b/include/linux/mtd/jedec.h @@ -1,13 +1,13 @@ /* JEDEC Flash Interface. - * This is an older type of interface for self programming flash. It is + * This is an older type of interface for self programming flash. It is * commonly use in older AMD chips and is obsolete compared with CFI. * It is called JEDEC because the JEDEC association distributes the ID codes * for the chips. * * See the AMD flash databook for information on how to operate the interface. * - * $Id: jedec.h,v 1.3 2003/05/21 11:51:01 dwmw2 Exp $ + * $Id: jedec.h,v 1.4 2005/11/07 11:14:54 gleixner Exp $ */ #ifndef __LINUX_MTD_JEDEC_H__ @@ -33,16 +33,16 @@ struct jedec_flash_chip __u16 jedec; unsigned long size; unsigned long sectorsize; - + // *(__u8*)(base + (adder << addrshift)) = data << datashift // Address size = size << addrshift unsigned long base; // Byte 0 of the flash, will be unaligned unsigned int datashift; // Useful for 32bit/16bit accesses unsigned int addrshift; unsigned long offset; // linerized start. base==offset for unbanked, uninterleaved flash - + __u32 capabilities; - + // These markers are filled in by the flash_chip_scan function unsigned long start; unsigned long length; @@ -51,16 +51,16 @@ struct jedec_flash_chip struct jedec_private { unsigned long size; // Total size of all the devices - + /* Bank handling. If sum(bank_fill) == size then this is linear flash. Otherwise the mapping has holes in it. bank_fill may be used to - find the holes, but in the common symetric case - bank_fill[0] == bank_fill[*], thus addresses may be computed + find the holes, but in the common symetric case + bank_fill[0] == bank_fill[*], thus addresses may be computed mathmatically. bank_fill must be powers of two */ unsigned is_banked; unsigned long bank_fill[MAX_JEDEC_CHIPS]; - - struct jedec_flash_chip chips[MAX_JEDEC_CHIPS]; + + struct jedec_flash_chip chips[MAX_JEDEC_CHIPS]; }; #endif diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h index fc28841f340975181d6813c5f5d701921aad9219..fedfbc8a287ff64228dee5a0f9fe551026988ea0 100644 --- a/include/linux/mtd/map.h +++ b/include/linux/mtd/map.h @@ -1,6 +1,6 @@ /* Overhauled routines for dealing with different mmap regions of flash */ -/* $Id: map.h,v 1.52 2005/05/25 10:29:41 gleixner Exp $ */ +/* $Id: map.h,v 1.54 2005/11/07 11:14:54 gleixner Exp $ */ #ifndef __LINUX_MTD_MAP_H__ #define __LINUX_MTD_MAP_H__ @@ -170,14 +170,14 @@ typedef union { to a chip probe routine -- either JEDEC or CFI probe or both -- via do_map_probe(). If a chip is recognised, the probe code will invoke the appropriate chip driver (if present) and return a struct mtd_info. - At which point, you fill in the mtd->module with your own module + At which point, you fill in the mtd->module with your own module address, and register it with the MTD core code. Or you could partition it and register the partitions instead, or keep it for your own private use; whatever. - + The mtd->priv field will point to the struct map_info, and any further - private data required by the chip driver is linked from the - mtd->priv->fldrv_priv field. This allows the map driver to get at + private data required by the chip driver is linked from the + mtd->priv->fldrv_priv field. This allows the map driver to get at the destructor function map->fldrv_destroy() when it's tired of living. */ @@ -214,7 +214,7 @@ struct map_info { If there is no cache to care about this can be set to NULL. */ void (*inval_cache)(struct map_info *, unsigned long, ssize_t); - /* set_vpp() must handle being reentered -- enable, enable, disable + /* set_vpp() must handle being reentered -- enable, enable, disable must leave it enabled. */ void (*set_vpp)(struct map_info *, int); @@ -353,7 +353,7 @@ static inline map_word map_word_ff(struct map_info *map) { map_word r; int i; - + if (map_bankwidth(map) < MAP_FF_LIMIT) { int bw = 8 * map_bankwidth(map); r.x[0] = (1 << bw) - 1; diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index c50c3f3927d959ceda9e1ad2539e9df785219139..e95d0463a3e5a5237007455c02f8bba71367eee4 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -1,5 +1,5 @@ -/* - * $Id: mtd.h,v 1.59 2005/04/11 10:19:02 gleixner Exp $ +/* + * $Id: mtd.h,v 1.61 2005/11/07 11:14:54 gleixner Exp $ * * Copyright (C) 1999-2003 David Woodhouse et al. * @@ -72,7 +72,17 @@ struct mtd_info { u_int32_t oobsize; // Amount of OOB data per block (e.g. 16) u_int32_t ecctype; u_int32_t eccsize; - + + /* + * Reuse some of the above unused fields in the case of NOR flash + * with configurable programming regions to avoid modifying the + * user visible structure layout/size. Only valid when the + * MTD_PROGRAM_REGIONS flag is set. + * (Maybe we should have an union for those?) + */ +#define MTD_PROGREGION_SIZE(mtd) (mtd)->oobblock +#define MTD_PROGREGION_CTRLMODE_VALID(mtd) (mtd)->oobsize +#define MTD_PROGREGION_CTRLMODE_INVALID(mtd) (mtd)->ecctype // Kernel-only stuff starts here. char *name; @@ -80,13 +90,13 @@ struct mtd_info { // oobinfo is a nand_oobinfo structure, which can be set by iotcl (MEMSETOOBINFO) struct nand_oobinfo oobinfo; - u_int32_t oobavail; // Number of bytes in OOB area available for fs + u_int32_t oobavail; // Number of bytes in OOB area available for fs /* Data for variable erase regions. If numeraseregions is zero, - * it means that the whole device has erasesize as given above. + * it means that the whole device has erasesize as given above. */ int numeraseregions; - struct mtd_erase_region_info *eraseregions; + struct mtd_erase_region_info *eraseregions; /* This really shouldn't be here. It can go away in 2.5 */ u_int32_t bank_size; @@ -109,10 +119,10 @@ struct mtd_info { int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); - /* - * Methods to access the protection register area, present in some + /* + * Methods to access the protection register area, present in some * flash devices. The user data is one time programmable but the - * factory data is read only. + * factory data is read only. */ int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len); int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); @@ -123,14 +133,14 @@ struct mtd_info { /* kvec-based read/write methods. We need these especially for NAND flash, with its limited number of write cycles per erase. - NB: The 'count' parameter is the number of _vectors_, each of + NB: The 'count' parameter is the number of _vectors_, each of which contains an (ofs, len) tuple. */ int (*readv) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, size_t *retlen); - int (*readv_ecc) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, + int (*readv_ecc) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen); - int (*writev_ecc) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, + int (*writev_ecc) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); /* Sync */ @@ -194,7 +204,7 @@ int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs, #define MTD_WRITEECC(mtd, args...) (*(mtd->write_ecc))(mtd, args) #define MTD_READOOB(mtd, args...) (*(mtd->read_oob))(mtd, args) #define MTD_WRITEOOB(mtd, args...) (*(mtd->write_oob))(mtd, args) -#define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd); } while (0) +#define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd); } while (0) #ifdef CONFIG_MTD_PARTITIONS diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 9b5b762175849e13274d84f54788aad309fcefd4..da5e67b3fc70ec8851f5aee64ce9a9b4f7ea6686 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -5,7 +5,7 @@ * Steven J. Hill * Thomas Gleixner * - * $Id: nand.h,v 1.73 2005/05/31 19:39:17 gleixner Exp $ + * $Id: nand.h,v 1.74 2005/09/15 13:58:50 vwool Exp $ * * 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 @@ -24,7 +24,7 @@ * bat later if I did something naughty. * 10-11-2000 SJH Added private NAND flash structure for driver * 10-24-2000 SJH Added prototype for 'nand_scan' function - * 10-29-2001 TG changed nand_chip structure to support + * 10-29-2001 TG changed nand_chip structure to support * hardwarespecific function for accessing control lines * 02-21-2002 TG added support for different read/write adress and * ready/busy line access function @@ -36,21 +36,21 @@ * CONFIG_MTD_NAND_ECC_JFFS2 is not set * 08-10-2002 TG extensions to nand_chip structure to support HW-ECC * - * 08-29-2002 tglx nand_chip structure: data_poi for selecting + * 08-29-2002 tglx nand_chip structure: data_poi for selecting * internal / fs-driver buffer * support for 6byte/512byte hardware ECC * read_ecc, write_ecc extended for different oob-layout * oob layout selections: NAND_NONE_OOB, NAND_JFFS2_OOB, * NAND_YAFFS_OOB * 11-25-2002 tglx Added Manufacturer code FUJITSU, NATIONAL - * Split manufacturer and device ID structures + * Split manufacturer and device ID structures * * 02-08-2004 tglx added option field to nand structure for chip anomalities * 05-25-2004 tglx added bad block table support, ST-MICRO manufacturer id * update of nand_chip structure description - * 01-17-2005 dmarlin added extended commands for AG-AND device and added option + * 01-17-2005 dmarlin added extended commands for AG-AND device and added option * for BBT_AUTO_REFRESH. - * 01-20-2005 dmarlin added optional pointer to hardware specific callback for + * 01-20-2005 dmarlin added optional pointer to hardware specific callback for * extra error status checks. */ #ifndef __LINUX_MTD_NAND_H @@ -120,8 +120,8 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ #define NAND_CMD_CACHEDPROG 0x15 /* Extended commands for AG-AND device */ -/* - * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but +/* + * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but * there is no way to distinguish that from NAND_CMD_READ0 * until the remaining sequence of commands has been completed * so add a high order bit and mask it off in the command. @@ -145,7 +145,7 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ #define NAND_STATUS_READY 0x40 #define NAND_STATUS_WP 0x80 -/* +/* * Constants for ECC_MODES */ @@ -191,12 +191,12 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ #define NAND_CACHEPRG 0x00000008 /* Chip has copy back function */ #define NAND_COPYBACK 0x00000010 -/* AND Chip which has 4 banks and a confusing page / block +/* AND Chip which has 4 banks and a confusing page / block * assignment. See Renesas datasheet for further information */ #define NAND_IS_AND 0x00000020 /* Chip has a array of 4 pages which can be read without * additional ready /busy waits */ -#define NAND_4PAGE_ARRAY 0x00000040 +#define NAND_4PAGE_ARRAY 0x00000040 /* Chip requires that BBT is periodically rewritten to prevent * bits from adjacent blocks from 'leaking' in altering data. * This happens with the Renesas AG-AND chips, possibly others. */ @@ -219,8 +219,8 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ /* Use a flash based bad block table. This option is passed to the * default bad block table function. */ #define NAND_USE_FLASH_BBT 0x00010000 -/* The hw ecc generator provides a syndrome instead a ecc value on read - * This can only work if we have the ecc bytes directly behind the +/* The hw ecc generator provides a syndrome instead a ecc value on read + * This can only work if we have the ecc bytes directly behind the * data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */ #define NAND_HWECC_SYNDROME 0x00020000 /* This option skips the bbt scan during initialization. */ @@ -244,6 +244,7 @@ typedef enum { FL_ERASING, FL_SYNCING, FL_CACHEDPRG, + FL_PM_SUSPENDED, } nand_state_t; /* Keep gcc happy */ @@ -251,7 +252,7 @@ struct nand_chip; /** * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independend devices - * @lock: protection lock + * @lock: protection lock * @active: the mtd device which holds the controller currently * @wq: wait queue to sleep on if a NAND operation is in progress * used instead of the per chip wait queue when a hw controller is available @@ -264,8 +265,8 @@ struct nand_hw_control { /** * struct nand_chip - NAND Private Flash Chip Data - * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device - * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the flash device + * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device + * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the flash device * @read_byte: [REPLACEABLE] read one byte from the chip * @write_byte: [REPLACEABLE] write one byte to the chip * @read_word: [REPLACEABLE] read one word from the chip @@ -288,7 +289,7 @@ struct nand_hw_control { * be provided if a hardware ECC is available * @erase_cmd: [INTERN] erase command write function, selectable due to AND support * @scan_bbt: [REPLACEABLE] function to scan bad block table - * @eccmode: [BOARDSPECIFIC] mode of ecc, see defines + * @eccmode: [BOARDSPECIFIC] mode of ecc, see defines * @eccsize: [INTERN] databytes used per ecc-calculation * @eccbytes: [INTERN] number of ecc bytes per ecc-calculation step * @eccsteps: [INTERN] number of ecc calculation steps per page @@ -300,7 +301,7 @@ struct nand_hw_control { * @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock * @bbt_erase_shift: [INTERN] number of address bits in a bbt entry * @chip_shift: [INTERN] number of address bits in one chip - * @data_buf: [INTERN] internal buffer for one page + oob + * @data_buf: [INTERN] internal buffer for one page + oob * @oob_buf: [INTERN] oob buffer for one eraseblock * @oobdirty: [INTERN] indicates that oob_buf must be reinitialized * @data_poi: [INTERN] pointer to a data buffer @@ -315,22 +316,22 @@ struct nand_hw_control { * @bbt: [INTERN] bad block table pointer * @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup * @bbt_md: [REPLACEABLE] bad block table mirror descriptor - * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan + * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan * @controller: [OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices * @priv: [OPTIONAL] pointer to private chip date - * @errstat: [OPTIONAL] hardware specific function to perform additional error status checks + * @errstat: [OPTIONAL] hardware specific function to perform additional error status checks * (determine if errors are correctable) */ - + struct nand_chip { void __iomem *IO_ADDR_R; void __iomem *IO_ADDR_W; - + u_char (*read_byte)(struct mtd_info *mtd); void (*write_byte)(struct mtd_info *mtd, u_char byte); u16 (*read_word)(struct mtd_info *mtd); void (*write_word)(struct mtd_info *mtd, u16 word); - + void (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len); void (*read_buf)(struct mtd_info *mtd, u_char *buf, int len); int (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len); @@ -395,7 +396,7 @@ struct nand_chip { * @name: Identify the device type * @id: device ID code * @pagesize: Pagesize in bytes. Either 256 or 512 or 0 - * If the pagesize is 0, then the real pagesize + * If the pagesize is 0, then the real pagesize * and the eraseize are determined from the * extended id bytes in the chip * @erasesize: Size of an erase block in the flash device. @@ -424,7 +425,7 @@ struct nand_manufacturers { extern struct nand_flash_dev nand_flash_ids[]; extern struct nand_manufacturers nand_manuf_ids[]; -/** +/** * struct nand_bbt_descr - bad block table descriptor * @options: options for this descriptor * @pages: the page(s) where we find the bbt, used with option BBT_ABSPAGE @@ -435,14 +436,14 @@ extern struct nand_manufacturers nand_manuf_ids[]; * @version: version read from the bbt page during scan * @len: length of the pattern, if 0 no pattern check is performed * @maxblocks: maximum number of blocks to search for a bbt. This number of - * blocks is reserved at the end of the device where the tables are + * blocks is reserved at the end of the device where the tables are * written. * @reserved_block_code: if non-0, this pattern denotes a reserved (rather than * bad) block in the stored bbt - * @pattern: pattern to identify bad block table or factory marked good / + * @pattern: pattern to identify bad block table or factory marked good / * bad blocks, can be NULL, if len = 0 * - * Descriptor for the bad block table marker and the descriptor for the + * Descriptor for the bad block table marker and the descriptor for the * pattern which identifies good and bad blocks. The assumption is made * that the pattern and the version count are always located in the oob area * of the first block. diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h new file mode 100644 index 0000000000000000000000000000000000000000..f1fd4215686acc2b7655c6a5e63f974115c3ff78 --- /dev/null +++ b/include/linux/mtd/onenand.h @@ -0,0 +1,155 @@ +/* + * linux/include/linux/mtd/onenand.h + * + * Copyright (C) 2005 Samsung Electronics + * Kyungmin Park + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_MTD_ONENAND_H +#define __LINUX_MTD_ONENAND_H + +#include +#include +#include + +#define MAX_BUFFERRAM 2 +#define MAX_ONENAND_PAGESIZE (2048 + 64) + +/* Scan and identify a OneNAND device */ +extern int onenand_scan(struct mtd_info *mtd, int max_chips); +/* Free resources held by the OneNAND device */ +extern void onenand_release(struct mtd_info *mtd); + +/** + * onenand_state_t - chip states + * Enumeration for OneNAND flash chip state + */ +typedef enum { + FL_READY, + FL_READING, + FL_WRITING, + FL_ERASING, + FL_SYNCING, + FL_UNLOCKING, + FL_LOCKING, + FL_PM_SUSPENDED, +} onenand_state_t; + +/** + * struct onenand_bufferram - OneNAND BufferRAM Data + * @param block block address in BufferRAM + * @param page page address in BufferRAM + * @param valid valid flag + */ +struct onenand_bufferram { + int block; + int page; + int valid; +}; + +/** + * struct onenand_chip - OneNAND Private Flash Chip Data + * @param base [BOARDSPECIFIC] address to access OneNAND + * @param chipsize [INTERN] the size of one chip for multichip arrays + * @param device_id [INTERN] device ID + * @param verstion_id [INTERN] version ID + * @param options [BOARDSPECIFIC] various chip options. They can partly be set to inform onenand_scan about + * @param erase_shift [INTERN] number of address bits in a block + * @param page_shift [INTERN] number of address bits in a page + * @param ppb_shift [INTERN] number of address bits in a pages per block + * @param page_mask [INTERN] a page per block mask + * @param bufferam_index [INTERN] BufferRAM index + * @param bufferam [INTERN] BufferRAM info + * @param readw [REPLACEABLE] hardware specific function for read short + * @param writew [REPLACEABLE] hardware specific function for write short + * @param command [REPLACEABLE] hardware specific function for writing commands to the chip + * @param wait [REPLACEABLE] hardware specific function for wait on ready + * @param read_bufferram [REPLACEABLE] hardware specific function for BufferRAM Area + * @param write_bufferram [REPLACEABLE] hardware specific function for BufferRAM Area + * @param read_word [REPLACEABLE] hardware specific function for read register of OneNAND + * @param write_word [REPLACEABLE] hardware specific function for write register of OneNAND + * @param scan_bbt [REPLACEALBE] hardware specific function for scaning Bad block Table + * @param chip_lock [INTERN] spinlock used to protect access to this structure and the chip + * @param wq [INTERN] wait queue to sleep on if a OneNAND operation is in progress + * @param state [INTERN] the current state of the OneNAND device + * @param autooob [REPLACEABLE] the default (auto)placement scheme + * @param bbm [REPLACEABLE] pointer to Bad Block Management + * @param priv [OPTIONAL] pointer to private chip date + */ +struct onenand_chip { + void __iomem *base; + unsigned int chipsize; + unsigned int device_id; + unsigned int density_mask; + unsigned int options; + + unsigned int erase_shift; + unsigned int page_shift; + unsigned int ppb_shift; /* Pages per block shift */ + unsigned int page_mask; + + unsigned int bufferram_index; + struct onenand_bufferram bufferram[MAX_BUFFERRAM]; + + int (*command)(struct mtd_info *mtd, int cmd, loff_t address, size_t len); + int (*wait)(struct mtd_info *mtd, int state); + int (*read_bufferram)(struct mtd_info *mtd, int area, + unsigned char *buffer, int offset, size_t count); + int (*write_bufferram)(struct mtd_info *mtd, int area, + const unsigned char *buffer, int offset, size_t count); + unsigned short (*read_word)(void __iomem *addr); + void (*write_word)(unsigned short value, void __iomem *addr); + void (*mmcontrol)(struct mtd_info *mtd, int sync_read); + int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); + int (*scan_bbt)(struct mtd_info *mtd); + + spinlock_t chip_lock; + wait_queue_head_t wq; + onenand_state_t state; + + struct nand_oobinfo *autooob; + + void *bbm; + + void *priv; +}; + +/* + * Helper macros + */ +#define ONENAND_CURRENT_BUFFERRAM(this) (this->bufferram_index) +#define ONENAND_NEXT_BUFFERRAM(this) (this->bufferram_index ^ 1) +#define ONENAND_SET_NEXT_BUFFERRAM(this) (this->bufferram_index ^= 1) + +#define ONENAND_GET_SYS_CFG1(this) \ + (this->read_word(this->base + ONENAND_REG_SYS_CFG1)) +#define ONENAND_SET_SYS_CFG1(v, this) \ + (this->write_word(v, this->base + ONENAND_REG_SYS_CFG1)) + +/* + * Options bits + */ +#define ONENAND_CONT_LOCK (0x0001) + + +/* + * OneNAND Flash Manufacturer ID Codes + */ +#define ONENAND_MFR_SAMSUNG 0xec +#define ONENAND_MFR_UNKNOWN 0x00 + +/** + * struct nand_manufacturers - NAND Flash Manufacturer ID Structure + * @param name: Manufacturer name + * @param id: manufacturer ID code of device. +*/ +struct onenand_manufacturers { + int id; + char *name; +}; + +#endif /* __LINUX_MTD_ONENAND_H */ diff --git a/include/linux/mtd/onenand_regs.h b/include/linux/mtd/onenand_regs.h new file mode 100644 index 0000000000000000000000000000000000000000..d7832ef8ed635e9bb37a182b3ffe766afaf6be3d --- /dev/null +++ b/include/linux/mtd/onenand_regs.h @@ -0,0 +1,180 @@ +/* + * linux/include/linux/mtd/onenand_regs.h + * + * OneNAND Register header file + * + * Copyright (C) 2005 Samsung Electronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ONENAND_REG_H +#define __ONENAND_REG_H + +/* Memory Address Map Translation (Word order) */ +#define ONENAND_MEMORY_MAP(x) ((x) << 1) + +/* + * External BufferRAM area + */ +#define ONENAND_BOOTRAM ONENAND_MEMORY_MAP(0x0000) +#define ONENAND_DATARAM ONENAND_MEMORY_MAP(0x0200) +#define ONENAND_SPARERAM ONENAND_MEMORY_MAP(0x8010) + +/* + * OneNAND Registers + */ +#define ONENAND_REG_MANUFACTURER_ID ONENAND_MEMORY_MAP(0xF000) +#define ONENAND_REG_DEVICE_ID ONENAND_MEMORY_MAP(0xF001) +#define ONENAND_REG_VERSION_ID ONENAND_MEMORY_MAP(0xF002) +#define ONENAND_REG_DATA_BUFFER_SIZE ONENAND_MEMORY_MAP(0xF003) +#define ONENAND_REG_BOOT_BUFFER_SIZE ONENAND_MEMORY_MAP(0xF004) +#define ONENAND_REG_NUM_BUFFERS ONENAND_MEMORY_MAP(0xF005) +#define ONENAND_REG_TECHNOLOGY ONENAND_MEMORY_MAP(0xF006) + +#define ONENAND_REG_START_ADDRESS1 ONENAND_MEMORY_MAP(0xF100) +#define ONENAND_REG_START_ADDRESS2 ONENAND_MEMORY_MAP(0xF101) +#define ONENAND_REG_START_ADDRESS3 ONENAND_MEMORY_MAP(0xF102) +#define ONENAND_REG_START_ADDRESS4 ONENAND_MEMORY_MAP(0xF103) +#define ONENAND_REG_START_ADDRESS5 ONENAND_MEMORY_MAP(0xF104) +#define ONENAND_REG_START_ADDRESS6 ONENAND_MEMORY_MAP(0xF105) +#define ONENAND_REG_START_ADDRESS7 ONENAND_MEMORY_MAP(0xF106) +#define ONENAND_REG_START_ADDRESS8 ONENAND_MEMORY_MAP(0xF107) + +#define ONENAND_REG_START_BUFFER ONENAND_MEMORY_MAP(0xF200) +#define ONENAND_REG_COMMAND ONENAND_MEMORY_MAP(0xF220) +#define ONENAND_REG_SYS_CFG1 ONENAND_MEMORY_MAP(0xF221) +#define ONENAND_REG_SYS_CFG2 ONENAND_MEMORY_MAP(0xF222) +#define ONENAND_REG_CTRL_STATUS ONENAND_MEMORY_MAP(0xF240) +#define ONENAND_REG_INTERRUPT ONENAND_MEMORY_MAP(0xF241) +#define ONENAND_REG_START_BLOCK_ADDRESS ONENAND_MEMORY_MAP(0xF24C) +#define ONENAND_REG_END_BLOCK_ADDRESS ONENAND_MEMORY_MAP(0xF24D) +#define ONENAND_REG_WP_STATUS ONENAND_MEMORY_MAP(0xF24E) + +#define ONENAND_REG_ECC_STATUS ONENAND_MEMORY_MAP(0xFF00) +#define ONENAND_REG_ECC_M0 ONENAND_MEMORY_MAP(0xFF01) +#define ONENAND_REG_ECC_S0 ONENAND_MEMORY_MAP(0xFF02) +#define ONENAND_REG_ECC_M1 ONENAND_MEMORY_MAP(0xFF03) +#define ONENAND_REG_ECC_S1 ONENAND_MEMORY_MAP(0xFF04) +#define ONENAND_REG_ECC_M2 ONENAND_MEMORY_MAP(0xFF05) +#define ONENAND_REG_ECC_S2 ONENAND_MEMORY_MAP(0xFF06) +#define ONENAND_REG_ECC_M3 ONENAND_MEMORY_MAP(0xFF07) +#define ONENAND_REG_ECC_S3 ONENAND_MEMORY_MAP(0xFF08) + +/* + * Device ID Register F001h (R) + */ +#define ONENAND_DEVICE_DENSITY_SHIFT (4) +#define ONENAND_DEVICE_IS_DDP (1 << 3) +#define ONENAND_DEVICE_IS_DEMUX (1 << 2) +#define ONENAND_DEVICE_VCC_MASK (0x3) + +#define ONENAND_DEVICE_DENSITY_512Mb (0x002) + +/* + * Version ID Register F002h (R) + */ +#define ONENAND_VERSION_PROCESS_SHIFT (8) + +/* + * Start Address 1 F100h (R/W) + */ +#define ONENAND_DDP_SHIFT (15) + +/* + * Start Address 8 F107h (R/W) + */ +#define ONENAND_FPA_MASK (0x3f) +#define ONENAND_FPA_SHIFT (2) +#define ONENAND_FSA_MASK (0x03) + +/* + * Start Buffer Register F200h (R/W) + */ +#define ONENAND_BSA_MASK (0x03) +#define ONENAND_BSA_SHIFT (8) +#define ONENAND_BSA_BOOTRAM (0 << 2) +#define ONENAND_BSA_DATARAM0 (2 << 2) +#define ONENAND_BSA_DATARAM1 (3 << 2) +#define ONENAND_BSC_MASK (0x03) + +/* + * Command Register F220h (R/W) + */ +#define ONENAND_CMD_READ (0x00) +#define ONENAND_CMD_READOOB (0x13) +#define ONENAND_CMD_PROG (0x80) +#define ONENAND_CMD_PROGOOB (0x1A) +#define ONENAND_CMD_UNLOCK (0x23) +#define ONENAND_CMD_LOCK (0x2A) +#define ONENAND_CMD_LOCK_TIGHT (0x2C) +#define ONENAND_CMD_ERASE (0x94) +#define ONENAND_CMD_RESET (0xF0) +#define ONENAND_CMD_READID (0x90) + +/* NOTE: Those are not *REAL* commands */ +#define ONENAND_CMD_BUFFERRAM (0x1978) + +/* + * System Configuration 1 Register F221h (R, R/W) + */ +#define ONENAND_SYS_CFG1_SYNC_READ (1 << 15) +#define ONENAND_SYS_CFG1_BRL_7 (7 << 12) +#define ONENAND_SYS_CFG1_BRL_6 (6 << 12) +#define ONENAND_SYS_CFG1_BRL_5 (5 << 12) +#define ONENAND_SYS_CFG1_BRL_4 (4 << 12) +#define ONENAND_SYS_CFG1_BRL_3 (3 << 12) +#define ONENAND_SYS_CFG1_BRL_10 (2 << 12) +#define ONENAND_SYS_CFG1_BRL_9 (1 << 12) +#define ONENAND_SYS_CFG1_BRL_8 (0 << 12) +#define ONENAND_SYS_CFG1_BRL_SHIFT (12) +#define ONENAND_SYS_CFG1_BL_32 (4 << 9) +#define ONENAND_SYS_CFG1_BL_16 (3 << 9) +#define ONENAND_SYS_CFG1_BL_8 (2 << 9) +#define ONENAND_SYS_CFG1_BL_4 (1 << 9) +#define ONENAND_SYS_CFG1_BL_CONT (0 << 9) +#define ONENAND_SYS_CFG1_BL_SHIFT (9) +#define ONENAND_SYS_CFG1_NO_ECC (1 << 8) +#define ONENAND_SYS_CFG1_RDY (1 << 7) +#define ONENAND_SYS_CFG1_INT (1 << 6) +#define ONENAND_SYS_CFG1_IOBE (1 << 5) +#define ONENAND_SYS_CFG1_RDY_CONF (1 << 4) + +/* + * Controller Status Register F240h (R) + */ +#define ONENAND_CTRL_ONGO (1 << 15) +#define ONENAND_CTRL_LOCK (1 << 14) +#define ONENAND_CTRL_LOAD (1 << 13) +#define ONENAND_CTRL_PROGRAM (1 << 12) +#define ONENAND_CTRL_ERASE (1 << 11) +#define ONENAND_CTRL_ERROR (1 << 10) +#define ONENAND_CTRL_RSTB (1 << 7) + +/* + * Interrupt Status Register F241h (R) + */ +#define ONENAND_INT_MASTER (1 << 15) +#define ONENAND_INT_READ (1 << 7) +#define ONENAND_INT_WRITE (1 << 6) +#define ONENAND_INT_ERASE (1 << 5) +#define ONENAND_INT_RESET (1 << 4) +#define ONENAND_INT_CLEAR (0 << 0) + +/* + * NAND Flash Write Protection Status Register F24Eh (R) + */ +#define ONENAND_WP_US (1 << 2) +#define ONENAND_WP_LS (1 << 1) +#define ONENAND_WP_LTS (1 << 0) + +/* + * ECC Status Reigser FF00h (R) + */ +#define ONENAND_ECC_1BIT (1 << 0) +#define ONENAND_ECC_2BIT (1 << 1) +#define ONENAND_ECC_2BIT_ALL (0xAAAA) + +#endif /* __ONENAND_REG_H */ diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index 50b2edfc8f11d8d44ac3dc8e62aae217c0a3a6d2..b03f512d51b9c96d865cebd5cf4cb85596b4d436 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -5,7 +5,7 @@ * * This code is GPL * - * $Id: partitions.h,v 1.16 2004/11/16 18:34:40 dwmw2 Exp $ + * $Id: partitions.h,v 1.17 2005/11/07 11:14:55 gleixner Exp $ */ #ifndef MTD_PARTITIONS_H @@ -16,25 +16,25 @@ /* * Partition definition structure: - * + * * An array of struct partition is passed along with a MTD object to * add_mtd_partitions() to create them. * * For each partition, these fields are available: * name: string that will be used to label the partition's MTD device. - * size: the partition size; if defined as MTDPART_SIZ_FULL, the partition + * size: the partition size; if defined as MTDPART_SIZ_FULL, the partition * will extend to the end of the master MTD device. - * offset: absolute starting position within the master MTD device; if - * defined as MTDPART_OFS_APPEND, the partition will start where the + * offset: absolute starting position within the master MTD device; if + * defined as MTDPART_OFS_APPEND, the partition will start where the * previous one ended; if MTDPART_OFS_NXTBLK, at the next erase block. - * mask_flags: contains flags that have to be masked (removed) from the + * mask_flags: contains flags that have to be masked (removed) from the * master MTD flag set for the corresponding MTD partition. - * For example, to force a read-only partition, simply adding + * For example, to force a read-only partition, simply adding * MTD_WRITEABLE to the mask_flags will do the trick. * - * Note: writeable partitions require their size and offset be + * Note: writeable partitions require their size and offset be * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK). - */ + */ struct mtd_partition { char *name; /* identifier string */ @@ -66,7 +66,7 @@ struct mtd_part_parser { extern int register_mtd_parser(struct mtd_part_parser *parser); extern int deregister_mtd_parser(struct mtd_part_parser *parser); -extern int parse_mtd_partitions(struct mtd_info *master, const char **types, +extern int parse_mtd_partitions(struct mtd_info *master, const char **types, struct mtd_partition **pparts, unsigned long origin); #define put_partition_parser(p) do { module_put((p)->owner); } while(0) diff --git a/include/linux/mtd/physmap.h b/include/linux/mtd/physmap.h index 05aa4970677f6aaeab52b68191f09ebef98abe2d..c7b8bcdef013bfd6629a62cf8899ac5153305a82 100644 --- a/include/linux/mtd/physmap.h +++ b/include/linux/mtd/physmap.h @@ -1,8 +1,8 @@ /* - * For boards with physically mapped flash and using + * For boards with physically mapped flash and using * drivers/mtd/maps/physmap.c mapping driver. * - * $Id: physmap.h,v 1.3 2004/07/21 00:16:15 jwboyer Exp $ + * $Id: physmap.h,v 1.4 2005/11/07 11:14:55 gleixner Exp $ * * Copyright (C) 2003 MontaVista Software Inc. * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net @@ -18,7 +18,7 @@ #include -#if defined(CONFIG_MTD_PHYSMAP) +#if defined(CONFIG_MTD_PHYSMAP) #include #include @@ -44,12 +44,12 @@ static inline void physmap_configure(unsigned long addr, unsigned long size, int #if defined(CONFIG_MTD_PARTITIONS) /* - * Machines that wish to do flash partition may want to call this function in - * their setup routine. + * Machines that wish to do flash partition may want to call this function in + * their setup routine. * * physmap_set_partitions(mypartitions, num_parts); * - * Note that one can always override this hard-coded partition with + * Note that one can always override this hard-coded partition with * command line partition (you need to enable CONFIG_MTD_CMDLINE_PARTS). */ void physmap_set_partitions(struct mtd_partition *parts, int num_parts); diff --git a/include/linux/mtd/pmc551.h b/include/linux/mtd/pmc551.h index 113e3087f68a74a8d5a12856d0832b3828295bf1..a7f6d20ad407bf7dcbb5859ed6dc78a6a2cfc7d7 100644 --- a/include/linux/mtd/pmc551.h +++ b/include/linux/mtd/pmc551.h @@ -1,5 +1,5 @@ /* - * $Id: pmc551.h,v 1.5 2003/01/24 16:49:53 dwmw2 Exp $ + * $Id: pmc551.h,v 1.6 2005/11/07 11:14:55 gleixner Exp $ * * PMC551 PCI Mezzanine Ram Device * @@ -7,7 +7,7 @@ * Mark Ferrell * Copyright 1999,2000 Nortel Networks * - * License: + * License: * As part of this driver was derrived from the slram.c driver it falls * under the same license, which is GNU General Public License v2 */ @@ -17,7 +17,7 @@ #include -#define PMC551_VERSION "$Id: pmc551.h,v 1.5 2003/01/24 16:49:53 dwmw2 Exp $\n"\ +#define PMC551_VERSION "$Id: pmc551.h,v 1.6 2005/11/07 11:14:55 gleixner Exp $\n"\ "Ramix PMC551 PCI Mezzanine Ram Driver. (C) 1999,2000 Nortel Networks.\n" /* @@ -30,7 +30,7 @@ struct mypriv { u32 curr_map0; u32 asize; struct mtd_info *nextpmc551; -}; +}; /* * Function Prototypes @@ -39,7 +39,7 @@ static int pmc551_erase(struct mtd_info *, struct erase_info *); static void pmc551_unpoint(struct mtd_info *, u_char *, loff_t, size_t); static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf); static int pmc551_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *); -static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); +static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); /* @@ -50,7 +50,7 @@ static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_cha #endif #ifndef PCI_DEVICE_ID_V3_SEMI_V370PDC -#define PCI_DEVICE_ID_V3_SEMI_V370PDC 0x0200 +#define PCI_DEVICE_ID_V3_SEMI_V370PDC 0x0200 #endif diff --git a/include/linux/mtd/xip.h b/include/linux/mtd/xip.h index 7b7deef6b180a920fd491f1d1d1660cf2b848745..220d50bb71cd06bd86625e55b98fc77a03543598 100644 --- a/include/linux/mtd/xip.h +++ b/include/linux/mtd/xip.h @@ -12,7 +12,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * $Id: xip.h,v 1.2 2004/12/01 15:49:10 nico Exp $ + * $Id: xip.h,v 1.5 2005/11/07 11:14:55 gleixner Exp $ */ #ifndef __LINUX_MTD_XIP_H__ @@ -22,19 +22,19 @@ #ifdef CONFIG_MTD_XIP -/* - * Function that are modifying the flash state away from array mode must - * obviously not be running from flash. The __xipram is therefore marking - * those functions so they get relocated to ram. - */ -#define __xipram __attribute__ ((__section__ (".data"))) - /* * We really don't want gcc to guess anything. * We absolutely _need_ proper inlining. */ #include +/* + * Function that are modifying the flash state away from array mode must + * obviously not be running from flash. The __xipram is therefore marking + * those functions so they get relocated to ram. + */ +#define __xipram noinline __attribute__ ((__section__ (".data"))) + /* * Each architecture has to provide the following macros. They must access * the hardware directly and not rely on any other (XIP) functions since they @@ -60,9 +60,9 @@ * overflowing. * * xip_iprefetch() - * + * * Macro to fill instruction prefetch - * e.g. a series of nops: asm volatile (".rep 8; nop; .endr"); + * e.g. a series of nops: asm volatile (".rep 8; nop; .endr"); */ #include diff --git a/include/linux/namespace.h b/include/linux/namespace.h index 0e5a86f13b2f8b4bbac4b50f32836827fef9fae8..6731977c4c13a00e39a251a12d7be31311960062 100644 --- a/include/linux/namespace.h +++ b/include/linux/namespace.h @@ -9,7 +9,8 @@ struct namespace { atomic_t count; struct vfsmount * root; struct list_head list; - struct rw_semaphore sem; + wait_queue_head_t poll; + int event; }; extern int copy_namespace(int, struct task_struct *); diff --git a/include/linux/net.h b/include/linux/net.h index 4e981585a89a349f9444ffdbfe9588cbf66d1671..d6a41e6577f61a3b2729247af897532ab3b44ea3 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -71,6 +71,7 @@ typedef enum { * @SOCK_RAW: raw socket * @SOCK_RDM: reliably-delivered message * @SOCK_SEQPACKET: sequential packet socket + * @SOCK_DCCP: Datagram Congestion Control Protocol socket * @SOCK_PACKET: linux specific way of getting packets at the dev level. * For writing rarp and other similar things on the user level. * diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h index 6d5a24f3fc6d902aad24b9c532d15dec3a863da1..51c231a1e5a669457ef5a4aef34207ad74a78b37 100644 --- a/include/linux/nfsd/nfsd.h +++ b/include/linux/nfsd/nfsd.h @@ -60,7 +60,7 @@ typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int); extern struct svc_program nfsd_program; extern struct svc_version nfsd_version2, nfsd_version3, nfsd_version4; - +extern struct svc_serv *nfsd_serv; /* * Function prototypes. */ diff --git a/include/linux/nfsd/syscall.h b/include/linux/nfsd/syscall.h index e65c9db6d13f975952850a04e73dab753f0e8097..781efbf94ed359c47b4a9db04aa6d0632a3da787 100644 --- a/include/linux/nfsd/syscall.h +++ b/include/linux/nfsd/syscall.h @@ -39,6 +39,21 @@ #define NFSCTL_GETFD 7 /* get an fh by path (used by mountd) */ #define NFSCTL_GETFS 8 /* get an fh by path with max FH len */ +/* + * Macros used to set version + */ +#define NFSCTL_VERSET(_cltbits, _v) ((_cltbits) |= (1 << (_v))) +#define NFSCTL_VERUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << (_v))) +#define NFSCTL_VERISSET(_cltbits, _v) ((_cltbits) & (1 << (_v))) + +#if defined(CONFIG_NFSD_V4) +#define NFSCTL_VERALL (0x1c /* 0b011100 */) +#elif defined(CONFIG_NFSD_V3) +#define NFSCTL_VERALL (0x0c /* 0b001100 */) +#else +#define NFSCTL_VERALL (0x04 /* 0b000100 */) +#endif + /* SVC */ struct nfsctl_svc { unsigned short svc_port; @@ -120,6 +135,8 @@ extern int exp_delclient(struct nfsctl_client *ncp); extern int exp_export(struct nfsctl_export *nxp); extern int exp_unexport(struct nfsctl_export *nxp); +extern unsigned int nfsd_versbits; + #endif /* __KERNEL__ */ #endif /* NFSD_SYSCALL_H */ diff --git a/include/linux/nfsd/xdr3.h b/include/linux/nfsd/xdr3.h index 21e18ce7ca63bc047b9a31be8da1700621326c15..3c2a71b43bacc38a33ad9b8ab3efa4aaf61d8190 100644 --- a/include/linux/nfsd/xdr3.h +++ b/include/linux/nfsd/xdr3.h @@ -42,7 +42,7 @@ struct nfsd3_writeargs { __u64 offset; __u32 count; int stable; - int len; + __u32 len; struct kvec vec[RPCSVC_MAXPAGES]; int vlen; }; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 88de3f8ce1a2cedcc7ec4325ae4a9da6e4e26fc1..9a96f05883935a32955b216fcc3184bf162b0a85 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -519,6 +519,7 @@ #define PCI_DEVICE_ID_MATROX_MIL 0x0519 #define PCI_DEVICE_ID_MATROX_MYS 0x051A #define PCI_DEVICE_ID_MATROX_MIL_2 0x051b +#define PCI_DEVICE_ID_MATROX_MYS_AGP 0x051e #define PCI_DEVICE_ID_MATROX_MIL_2_AGP 0x051f #define PCI_DEVICE_ID_MATROX_MGA_IMP 0x0d10 #define PCI_DEVICE_ID_MATROX_G100_MM 0x1000 @@ -1785,6 +1786,7 @@ #define PCI_DEVICE_ID_TIGON3_5704 0x1648 #define PCI_DEVICE_ID_TIGON3_5704S_2 0x1649 #define PCI_DEVICE_ID_NX2_5706 0x164a +#define PCI_DEVICE_ID_NX2_5708 0x164c #define PCI_DEVICE_ID_TIGON3_5702FE 0x164d #define PCI_DEVICE_ID_TIGON3_5705 0x1653 #define PCI_DEVICE_ID_TIGON3_5705_2 0x1654 @@ -1809,6 +1811,7 @@ #define PCI_DEVICE_ID_TIGON3_5703X 0x16a7 #define PCI_DEVICE_ID_TIGON3_5704S 0x16a8 #define PCI_DEVICE_ID_NX2_5706S 0x16aa +#define PCI_DEVICE_ID_NX2_5708S 0x16ac #define PCI_DEVICE_ID_TIGON3_5702A3 0x16c6 #define PCI_DEVICE_ID_TIGON3_5703A3 0x16c7 #define PCI_DEVICE_ID_TIGON3_5781 0x16dd diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h index 60ffcb9c5791aef695ce0a48f02f66057ec06c88..e87b233615b349a4d982174779eaceaa7c1f127f 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h @@ -93,6 +93,7 @@ struct tc_fifo_qopt /* PRIO section */ #define TCQ_PRIO_BANDS 16 +#define TCQ_MIN_PRIO_BANDS 2 struct tc_prio_qopt { @@ -169,6 +170,7 @@ struct tc_red_qopt unsigned char Scell_log; /* cell size for idle damping */ unsigned char flags; #define TC_RED_ECN 1 +#define TC_RED_HARDDROP 2 }; struct tc_red_xstats @@ -194,38 +196,34 @@ enum #define TCA_GRED_MAX (__TCA_GRED_MAX - 1) -#define TCA_SET_OFF TCA_GRED_PARMS struct tc_gred_qopt { - __u32 limit; /* HARD maximal queue length (bytes) -*/ - __u32 qth_min; /* Min average length threshold (bytes) -*/ - __u32 qth_max; /* Max average length threshold (bytes) -*/ - __u32 DP; /* upto 2^32 DPs */ - __u32 backlog; - __u32 qave; - __u32 forced; - __u32 early; - __u32 other; - __u32 pdrop; - - unsigned char Wlog; /* log(W) */ - unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */ - unsigned char Scell_log; /* cell size for idle damping */ - __u8 prio; /* prio of this VQ */ - __u32 packets; - __u32 bytesin; + __u32 limit; /* HARD maximal queue length (bytes) */ + __u32 qth_min; /* Min average length threshold (bytes) */ + __u32 qth_max; /* Max average length threshold (bytes) */ + __u32 DP; /* upto 2^32 DPs */ + __u32 backlog; + __u32 qave; + __u32 forced; + __u32 early; + __u32 other; + __u32 pdrop; + __u8 Wlog; /* log(W) */ + __u8 Plog; /* log(P_max/(qth_max-qth_min)) */ + __u8 Scell_log; /* cell size for idle damping */ + __u8 prio; /* prio of this VQ */ + __u32 packets; + __u32 bytesin; }; + /* gred setup */ struct tc_gred_sopt { - __u32 DPs; - __u32 def_DP; - __u8 grio; - __u8 pad1; - __u16 pad2; + __u32 DPs; + __u32 def_DP; + __u8 grio; + __u8 flags; + __u16 pad1; }; /* HTB section */ diff --git a/include/linux/pnp.h b/include/linux/pnp.h index aadbac29103cfc7601291e8fc0415f46d6cafc85..584d57cb393a1e1cc7339e11b7d747882016b85c 100644 --- a/include/linux/pnp.h +++ b/include/linux/pnp.h @@ -353,7 +353,6 @@ struct pnp_protocol { int pnp_register_protocol(struct pnp_protocol *protocol); void pnp_unregister_protocol(struct pnp_protocol *protocol); int pnp_add_device(struct pnp_dev *dev); -void pnp_remove_device(struct pnp_dev *dev); int pnp_device_attach(struct pnp_dev *pnp_dev); void pnp_device_detach(struct pnp_dev *pnp_dev); extern struct list_head pnp_global; @@ -399,7 +398,6 @@ static inline int pnp_register_protocol(struct pnp_protocol *protocol) { return static inline void pnp_unregister_protocol(struct pnp_protocol *protocol) { } static inline int pnp_init_device(struct pnp_dev *dev) { return -ENODEV; } static inline int pnp_add_device(struct pnp_dev *dev) { return -ENODEV; } -static inline void pnp_remove_device(struct pnp_dev *dev) { } static inline int pnp_device_attach(struct pnp_dev *pnp_dev) { return -ENODEV; } static inline void pnp_device_detach(struct pnp_dev *pnp_dev) { ; } diff --git a/include/linux/ppp-comp.h b/include/linux/ppp-comp.h index 7227e653b3beacdb7e496196e86b08f821671772..e86a7a5cf355ce3135e3351f9bec314fbbb24b24 100644 --- a/include/linux/ppp-comp.h +++ b/include/linux/ppp-comp.h @@ -111,6 +111,8 @@ struct compressor { /* Used in locking compressor modules */ struct module *owner; + /* Extra skb space needed by the compressor algorithm */ + unsigned int comp_extra; }; /* @@ -190,6 +192,13 @@ struct compressor { #define DEFLATE_MAKE_OPT(w) ((((w) - 8) << 4) + DEFLATE_METHOD_VAL) #define DEFLATE_CHK_SEQUENCE 0 +/* + * Definitions for MPPE. + */ + +#define CI_MPPE 18 /* config option for MPPE */ +#define CILEN_MPPE 6 /* length of config option */ + /* * Definitions for other, as yet unsupported, compression methods. */ diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 0563581e3a0289b7c4ff9ce2868609cf2d39dda4..74488e49166d88c40018c91f247e5873ad842510 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -66,6 +66,7 @@ struct proc_dir_entry { write_proc_t *write_proc; atomic_t count; /* use count */ int deleted; /* delete flag */ + void *set; }; struct kcore_list { @@ -139,15 +140,12 @@ extern void proc_tty_unregister_driver(struct tty_driver *driver); /* * proc_devtree.c */ +#ifdef CONFIG_PROC_DEVICETREE struct device_node; +struct property; extern void proc_device_tree_init(void); -#ifdef CONFIG_PROC_DEVICETREE extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *); -#else /* !CONFIG_PROC_DEVICETREE */ -static inline void proc_device_tree_add_node(struct device_node *np, struct proc_dir_entry *pde) -{ - return; -} +extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop); #endif /* CONFIG_PROC_DEVICETREE */ extern struct proc_dir_entry *proc_symlink(const char *, diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index dc6f3647bfbc01cfcfca8192d631b12d4c9bdd80..b2b3dba1298d1fef7f1b4e4ecfba22fe142c88d2 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -78,6 +78,8 @@ #include /* For unlikely. */ #include /* For struct task_struct. */ + +extern long arch_ptrace(struct task_struct *child, long request, long addr, long data); extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len); extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len); extern int ptrace_attach(struct task_struct *tsk); diff --git a/include/linux/quota.h b/include/linux/quota.h index 700ead45084fd4694ec5925bf318aa4ad0634621..f33aeb22c26a321c211b1de244427c50be1db6fb 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h @@ -289,7 +289,6 @@ struct quota_info { struct semaphore dqonoff_sem; /* Serialize quotaon & quotaoff */ struct rw_semaphore dqptr_sem; /* serialize ops using quota_info struct, pointers from inode to dquots */ struct inode *files[MAXQUOTAS]; /* inodes of quotafiles */ - struct vfsmount *mnt[MAXQUOTAS]; /* mountpoint entries of filesystems with quota files */ struct mem_dqinfo info[MAXQUOTAS]; /* Information for each quota type */ struct quota_format_ops *ops[MAXQUOTAS]; /* Operations for each type */ }; diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h index d211507ab24611b32a6edc8b6ff716505fc9d864..4f34d3d60f2ed6485d450bd4ca06cbea450e6997 100644 --- a/include/linux/quotaops.h +++ b/include/linux/quotaops.h @@ -198,38 +198,38 @@ static __inline__ int DQUOT_OFF(struct super_block *sb) #define DQUOT_SYNC(sb) do { } while(0) #define DQUOT_OFF(sb) do { } while(0) #define DQUOT_TRANSFER(inode, iattr) (0) -extern __inline__ int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr) +static inline int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { inode_add_bytes(inode, nr); return 0; } -extern __inline__ int DQUOT_PREALLOC_SPACE(struct inode *inode, qsize_t nr) +static inline int DQUOT_PREALLOC_SPACE(struct inode *inode, qsize_t nr) { DQUOT_PREALLOC_SPACE_NODIRTY(inode, nr); mark_inode_dirty(inode); return 0; } -extern __inline__ int DQUOT_ALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr) +static inline int DQUOT_ALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { inode_add_bytes(inode, nr); return 0; } -extern __inline__ int DQUOT_ALLOC_SPACE(struct inode *inode, qsize_t nr) +static inline int DQUOT_ALLOC_SPACE(struct inode *inode, qsize_t nr) { DQUOT_ALLOC_SPACE_NODIRTY(inode, nr); mark_inode_dirty(inode); return 0; } -extern __inline__ void DQUOT_FREE_SPACE_NODIRTY(struct inode *inode, qsize_t nr) +static inline void DQUOT_FREE_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { inode_sub_bytes(inode, nr); } -extern __inline__ void DQUOT_FREE_SPACE(struct inode *inode, qsize_t nr) +static inline void DQUOT_FREE_SPACE(struct inode *inode, qsize_t nr) { DQUOT_FREE_SPACE_NODIRTY(inode, nr); mark_inode_dirty(inode); diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h index 9f0f9281f42a01628adbdb80f317172486eca583..36e5d269612fec7ce193f2edee5fd816af353650 100644 --- a/include/linux/radix-tree.h +++ b/include/linux/radix-tree.h @@ -46,6 +46,7 @@ do { \ int radix_tree_insert(struct radix_tree_root *, unsigned long, void *); void *radix_tree_lookup(struct radix_tree_root *, unsigned long); +void **radix_tree_lookup_slot(struct radix_tree_root *, unsigned long); void *radix_tree_delete(struct radix_tree_root *, unsigned long); unsigned int radix_tree_gang_lookup(struct radix_tree_root *root, void **results, diff --git a/include/linux/rio.h b/include/linux/rio.h new file mode 100644 index 0000000000000000000000000000000000000000..c7e907faae9cccace8425249a54066f7c4b3a2b3 --- /dev/null +++ b/include/linux/rio.h @@ -0,0 +1,325 @@ +/* + * RapidIO interconnect services + * (RapidIO Interconnect Specification, http://www.rapidio.org) + * + * Copyright 2005 MontaVista Software, Inc. + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef LINUX_RIO_H +#define LINUX_RIO_H + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include +#include +#include + +#define RIO_ANY_DESTID 0xff +#define RIO_NO_HOPCOUNT -1 + +#define RIO_MAX_MPORT_RESOURCES 16 +#define RIO_MAX_DEV_RESOURCES 16 + +#define RIO_GLOBAL_TABLE 0xff /* Indicates access of a switch's + global routing table if it + has multiple (or per port) + tables */ + +#define RIO_INVALID_ROUTE 0xff /* Indicates that a route table + entry is invalid (no route + exists for the device ID) */ + +#ifdef CONFIG_RAPIDIO_8_BIT_TRANSPORT +#define RIO_MAX_ROUTE_ENTRIES (1 << 8) +#else +#define RIO_MAX_ROUTE_ENTRIES (1 << 16) +#endif + +#define RIO_MAX_MBOX 4 +#define RIO_MAX_MSG_SIZE 0x1000 + +/* + * Error values that may be returned by RIO functions. + */ +#define RIO_SUCCESSFUL 0x00 +#define RIO_BAD_SIZE 0x81 + +/* + * For RIO devices, the region numbers are assigned this way: + * + * 0 RapidIO outbound doorbells + * 1-15 RapidIO memory regions + * + * For RIO master ports, the region number are assigned this way: + * + * 0 RapidIO inbound doorbells + * 1 RapidIO inbound mailboxes + * 1 RapidIO outbound mailboxes + */ +#define RIO_DOORBELL_RESOURCE 0 +#define RIO_INB_MBOX_RESOURCE 1 +#define RIO_OUTB_MBOX_RESOURCE 2 + +extern struct bus_type rio_bus_type; +extern struct list_head rio_devices; /* list of all devices */ + +struct rio_mport; + +/** + * struct rio_dev - RIO device info + * @global_list: Node in list of all RIO devices + * @net_list: Node in list of RIO devices in a network + * @net: Network this device is a part of + * @did: Device ID + * @vid: Vendor ID + * @device_rev: Device revision + * @asm_did: Assembly device ID + * @asm_vid: Assembly vendor ID + * @asm_rev: Assembly revision + * @efptr: Extended feature pointer + * @pef: Processing element features + * @swpinfo: Switch port info + * @src_ops: Source operation capabilities + * @dst_ops: Destination operation capabilities + * @dma_mask: Mask of bits of RIO address this device implements + * @rswitch: Pointer to &struct rio_switch if valid for this device + * @driver: Driver claiming this device + * @dev: Device model device + * @riores: RIO resources this device owns + * @destid: Network destination ID + */ +struct rio_dev { + struct list_head global_list; /* node in list of all RIO devices */ + struct list_head net_list; /* node in per net list */ + struct rio_net *net; /* RIO net this device resides in */ + u16 did; + u16 vid; + u32 device_rev; + u16 asm_did; + u16 asm_vid; + u16 asm_rev; + u16 efptr; + u32 pef; + u32 swpinfo; /* Only used for switches */ + u32 src_ops; + u32 dst_ops; + u64 dma_mask; + struct rio_switch *rswitch; /* RIO switch info */ + struct rio_driver *driver; /* RIO driver claiming this device */ + struct device dev; /* LDM device structure */ + struct resource riores[RIO_MAX_DEV_RESOURCES]; + u16 destid; +}; + +#define rio_dev_g(n) list_entry(n, struct rio_dev, global_list) +#define rio_dev_f(n) list_entry(n, struct rio_dev, net_list) +#define to_rio_dev(n) container_of(n, struct rio_dev, dev) + +/** + * struct rio_msg - RIO message event + * @res: Mailbox resource + * @mcback: Message event callback + */ +struct rio_msg { + struct resource *res; + void (*mcback) (struct rio_mport * mport, void *dev_id, int mbox, int slot); +}; + +/** + * struct rio_dbell - RIO doorbell event + * @node: Node in list of doorbell events + * @res: Doorbell resource + * @dinb: Doorbell event callback + * @dev_id: Device specific pointer to pass on event + */ +struct rio_dbell { + struct list_head node; + struct resource *res; + void (*dinb) (struct rio_mport *mport, void *dev_id, u16 src, u16 dst, u16 info); + void *dev_id; +}; + +/** + * struct rio_mport - RIO master port info + * @dbells: List of doorbell events + * @node: Node in global list of master ports + * @nnode: Node in network list of master ports + * @iores: I/O mem resource that this master port interface owns + * @riores: RIO resources that this master port interfaces owns + * @inb_msg: RIO inbound message event descriptors + * @outb_msg: RIO outbound message event descriptors + * @host_deviceid: Host device ID associated with this master port + * @ops: configuration space functions + * @id: Port ID, unique among all ports + * @index: Port index, unique among all port interfaces of the same type + * @name: Port name string + */ +struct rio_mport { + struct list_head dbells; /* list of doorbell events */ + struct list_head node; /* node in global list of ports */ + struct list_head nnode; /* node in net list of ports */ + struct resource iores; + struct resource riores[RIO_MAX_MPORT_RESOURCES]; + struct rio_msg inb_msg[RIO_MAX_MBOX]; + struct rio_msg outb_msg[RIO_MAX_MBOX]; + int host_deviceid; /* Host device ID */ + struct rio_ops *ops; /* maintenance transaction functions */ + unsigned char id; /* port ID, unique among all ports */ + unsigned char index; /* port index, unique among all port + interfaces of the same type */ + unsigned char name[40]; +}; + +/** + * struct rio_net - RIO network info + * @node: Node in global list of RIO networks + * @devices: List of devices in this network + * @mports: List of master ports accessing this network + * @hport: Default port for accessing this network + * @id: RIO network ID + */ +struct rio_net { + struct list_head node; /* node in list of networks */ + struct list_head devices; /* list of devices in this net */ + struct list_head mports; /* list of ports accessing net */ + struct rio_mport *hport; /* primary port for accessing net */ + unsigned char id; /* RIO network ID */ +}; + +/** + * struct rio_switch - RIO switch info + * @node: Node in global list of switches + * @switchid: Switch ID that is unique across a network + * @hopcount: Hopcount to this switch + * @destid: Associated destid in the path + * @route_table: Copy of switch routing table + * @add_entry: Callback for switch-specific route add function + * @get_entry: Callback for switch-specific route get function + */ +struct rio_switch { + struct list_head node; + u16 switchid; + u16 hopcount; + u16 destid; + u8 route_table[RIO_MAX_ROUTE_ENTRIES]; + int (*add_entry) (struct rio_mport * mport, u16 destid, u8 hopcount, + u16 table, u16 route_destid, u8 route_port); + int (*get_entry) (struct rio_mport * mport, u16 destid, u8 hopcount, + u16 table, u16 route_destid, u8 * route_port); +}; + +/* Low-level architecture-dependent routines */ + +/** + * struct rio_ops - Low-level RIO configuration space operations + * @lcread: Callback to perform local (master port) read of config space. + * @lcwrite: Callback to perform local (master port) write of config space. + * @cread: Callback to perform network read of config space. + * @cwrite: Callback to perform network write of config space. + * @dsend: Callback to send a doorbell message. + */ +struct rio_ops { + int (*lcread) (int index, u32 offset, int len, u32 * data); + int (*lcwrite) (int index, u32 offset, int len, u32 data); + int (*cread) (int index, u16 destid, u8 hopcount, u32 offset, int len, + u32 * data); + int (*cwrite) (int index, u16 destid, u8 hopcount, u32 offset, int len, + u32 data); + int (*dsend) (int index, u16 destid, u16 data); +}; + +#define RIO_RESOURCE_MEM 0x00000100 +#define RIO_RESOURCE_DOORBELL 0x00000200 +#define RIO_RESOURCE_MAILBOX 0x00000400 + +#define RIO_RESOURCE_CACHEABLE 0x00010000 +#define RIO_RESOURCE_PCI 0x00020000 + +#define RIO_RESOURCE_BUSY 0x80000000 + +/** + * struct rio_driver - RIO driver info + * @node: Node in list of drivers + * @name: RIO driver name + * @id_table: RIO device ids to be associated with this driver + * @probe: RIO device inserted + * @remove: RIO device removed + * @suspend: RIO device suspended + * @resume: RIO device awakened + * @enable_wake: RIO device enable wake event + * @driver: LDM driver struct + * + * Provides info on a RIO device driver for insertion/removal and + * power management purposes. + */ +struct rio_driver { + struct list_head node; + char *name; + const struct rio_device_id *id_table; + int (*probe) (struct rio_dev * dev, const struct rio_device_id * id); + void (*remove) (struct rio_dev * dev); + int (*suspend) (struct rio_dev * dev, u32 state); + int (*resume) (struct rio_dev * dev); + int (*enable_wake) (struct rio_dev * dev, u32 state, int enable); + struct device_driver driver; +}; + +#define to_rio_driver(drv) container_of(drv,struct rio_driver, driver) + +/** + * struct rio_device_id - RIO device identifier + * @did: RIO device ID + * @vid: RIO vendor ID + * @asm_did: RIO assembly device ID + * @asm_vid: RIO assembly vendor ID + * + * Identifies a RIO device based on both the device/vendor IDs and + * the assembly device/vendor IDs. + */ +struct rio_device_id { + u16 did, vid; + u16 asm_did, asm_vid; +}; + +/** + * struct rio_route_ops - Per-switch route operations + * @vid: RIO vendor ID + * @did: RIO device ID + * @add_hook: Callback that adds a route entry + * @get_hook: Callback that gets a route entry + * + * Defines the operations that are necessary to manipulate the route + * tables for a particular RIO switch device. + */ +struct rio_route_ops { + u16 vid, did; + int (*add_hook) (struct rio_mport * mport, u16 destid, u8 hopcount, + u16 table, u16 route_destid, u8 route_port); + int (*get_hook) (struct rio_mport * mport, u16 destid, u8 hopcount, + u16 table, u16 route_destid, u8 * route_port); +}; + +/* Architecture and hardware-specific functions */ +extern int rio_init_mports(void); +extern void rio_register_mport(struct rio_mport *); +extern int rio_hw_add_outb_message(struct rio_mport *, struct rio_dev *, int, + void *, size_t); +extern int rio_hw_add_inb_buffer(struct rio_mport *, int, void *); +extern void *rio_hw_get_inb_message(struct rio_mport *, int); +extern int rio_open_inb_mbox(struct rio_mport *, void *, int, int); +extern void rio_close_inb_mbox(struct rio_mport *, int); +extern int rio_open_outb_mbox(struct rio_mport *, void *, int, int); +extern void rio_close_outb_mbox(struct rio_mport *, int); + +#endif /* __KERNEL__ */ +#endif /* LINUX_RIO_H */ diff --git a/include/linux/rio_drv.h b/include/linux/rio_drv.h new file mode 100644 index 0000000000000000000000000000000000000000..3bd7cce19e2645cd32e240471230d84910c945a7 --- /dev/null +++ b/include/linux/rio_drv.h @@ -0,0 +1,469 @@ +/* + * RapidIO driver services + * + * Copyright 2005 MontaVista Software, Inc. + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef LINUX_RIO_DRV_H +#define LINUX_RIO_DRV_H + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include +#include +#include + +extern int __rio_local_read_config_32(struct rio_mport *port, u32 offset, + u32 * data); +extern int __rio_local_write_config_32(struct rio_mport *port, u32 offset, + u32 data); +extern int __rio_local_read_config_16(struct rio_mport *port, u32 offset, + u16 * data); +extern int __rio_local_write_config_16(struct rio_mport *port, u32 offset, + u16 data); +extern int __rio_local_read_config_8(struct rio_mport *port, u32 offset, + u8 * data); +extern int __rio_local_write_config_8(struct rio_mport *port, u32 offset, + u8 data); + +extern int rio_mport_read_config_32(struct rio_mport *port, u16 destid, + u8 hopcount, u32 offset, u32 * data); +extern int rio_mport_write_config_32(struct rio_mport *port, u16 destid, + u8 hopcount, u32 offset, u32 data); +extern int rio_mport_read_config_16(struct rio_mport *port, u16 destid, + u8 hopcount, u32 offset, u16 * data); +extern int rio_mport_write_config_16(struct rio_mport *port, u16 destid, + u8 hopcount, u32 offset, u16 data); +extern int rio_mport_read_config_8(struct rio_mport *port, u16 destid, + u8 hopcount, u32 offset, u8 * data); +extern int rio_mport_write_config_8(struct rio_mport *port, u16 destid, + u8 hopcount, u32 offset, u8 data); + +/** + * rio_local_read_config_32 - Read 32 bits from local configuration space + * @port: Master port + * @offset: Offset into local configuration space + * @data: Pointer to read data into + * + * Reads 32 bits of data from the specified offset within the local + * device's configuration space. + */ +static inline int rio_local_read_config_32(struct rio_mport *port, u32 offset, + u32 * data) +{ + return __rio_local_read_config_32(port, offset, data); +} + +/** + * rio_local_write_config_32 - Write 32 bits to local configuration space + * @port: Master port + * @offset: Offset into local configuration space + * @data: Data to be written + * + * Writes 32 bits of data to the specified offset within the local + * device's configuration space. + */ +static inline int rio_local_write_config_32(struct rio_mport *port, u32 offset, + u32 data) +{ + return __rio_local_write_config_32(port, offset, data); +} + +/** + * rio_local_read_config_16 - Read 16 bits from local configuration space + * @port: Master port + * @offset: Offset into local configuration space + * @data: Pointer to read data into + * + * Reads 16 bits of data from the specified offset within the local + * device's configuration space. + */ +static inline int rio_local_read_config_16(struct rio_mport *port, u32 offset, + u16 * data) +{ + return __rio_local_read_config_16(port, offset, data); +} + +/** + * rio_local_write_config_16 - Write 16 bits to local configuration space + * @port: Master port + * @offset: Offset into local configuration space + * @data: Data to be written + * + * Writes 16 bits of data to the specified offset within the local + * device's configuration space. + */ + +static inline int rio_local_write_config_16(struct rio_mport *port, u32 offset, + u16 data) +{ + return __rio_local_write_config_16(port, offset, data); +} + +/** + * rio_local_read_config_8 - Read 8 bits from local configuration space + * @port: Master port + * @offset: Offset into local configuration space + * @data: Pointer to read data into + * + * Reads 8 bits of data from the specified offset within the local + * device's configuration space. + */ +static inline int rio_local_read_config_8(struct rio_mport *port, u32 offset, + u8 * data) +{ + return __rio_local_read_config_8(port, offset, data); +} + +/** + * rio_local_write_config_8 - Write 8 bits to local configuration space + * @port: Master port + * @offset: Offset into local configuration space + * @data: Data to be written + * + * Writes 8 bits of data to the specified offset within the local + * device's configuration space. + */ +static inline int rio_local_write_config_8(struct rio_mport *port, u32 offset, + u8 data) +{ + return __rio_local_write_config_8(port, offset, data); +} + +/** + * rio_read_config_32 - Read 32 bits from configuration space + * @rdev: RIO device + * @offset: Offset into device configuration space + * @data: Pointer to read data into + * + * Reads 32 bits of data from the specified offset within the + * RIO device's configuration space. + */ +static inline int rio_read_config_32(struct rio_dev *rdev, u32 offset, + u32 * data) +{ + u8 hopcount = 0xff; + u16 destid = rdev->destid; + + if (rdev->rswitch) { + destid = rdev->rswitch->destid; + hopcount = rdev->rswitch->hopcount; + } + + return rio_mport_read_config_32(rdev->net->hport, destid, hopcount, + offset, data); +}; + +/** + * rio_write_config_32 - Write 32 bits to configuration space + * @rdev: RIO device + * @offset: Offset into device configuration space + * @data: Data to be written + * + * Writes 32 bits of data to the specified offset within the + * RIO device's configuration space. + */ +static inline int rio_write_config_32(struct rio_dev *rdev, u32 offset, + u32 data) +{ + u8 hopcount = 0xff; + u16 destid = rdev->destid; + + if (rdev->rswitch) { + destid = rdev->rswitch->destid; + hopcount = rdev->rswitch->hopcount; + } + + return rio_mport_write_config_32(rdev->net->hport, destid, hopcount, + offset, data); +}; + +/** + * rio_read_config_16 - Read 16 bits from configuration space + * @rdev: RIO device + * @offset: Offset into device configuration space + * @data: Pointer to read data into + * + * Reads 16 bits of data from the specified offset within the + * RIO device's configuration space. + */ +static inline int rio_read_config_16(struct rio_dev *rdev, u32 offset, + u16 * data) +{ + u8 hopcount = 0xff; + u16 destid = rdev->destid; + + if (rdev->rswitch) { + destid = rdev->rswitch->destid; + hopcount = rdev->rswitch->hopcount; + } + + return rio_mport_read_config_16(rdev->net->hport, destid, hopcount, + offset, data); +}; + +/** + * rio_write_config_16 - Write 16 bits to configuration space + * @rdev: RIO device + * @offset: Offset into device configuration space + * @data: Data to be written + * + * Writes 16 bits of data to the specified offset within the + * RIO device's configuration space. + */ +static inline int rio_write_config_16(struct rio_dev *rdev, u32 offset, + u16 data) +{ + u8 hopcount = 0xff; + u16 destid = rdev->destid; + + if (rdev->rswitch) { + destid = rdev->rswitch->destid; + hopcount = rdev->rswitch->hopcount; + } + + return rio_mport_write_config_16(rdev->net->hport, destid, hopcount, + offset, data); +}; + +/** + * rio_read_config_8 - Read 8 bits from configuration space + * @rdev: RIO device + * @offset: Offset into device configuration space + * @data: Pointer to read data into + * + * Reads 8 bits of data from the specified offset within the + * RIO device's configuration space. + */ +static inline int rio_read_config_8(struct rio_dev *rdev, u32 offset, u8 * data) +{ + u8 hopcount = 0xff; + u16 destid = rdev->destid; + + if (rdev->rswitch) { + destid = rdev->rswitch->destid; + hopcount = rdev->rswitch->hopcount; + } + + return rio_mport_read_config_8(rdev->net->hport, destid, hopcount, + offset, data); +}; + +/** + * rio_write_config_8 - Write 8 bits to configuration space + * @rdev: RIO device + * @offset: Offset into device configuration space + * @data: Data to be written + * + * Writes 8 bits of data to the specified offset within the + * RIO device's configuration space. + */ +static inline int rio_write_config_8(struct rio_dev *rdev, u32 offset, u8 data) +{ + u8 hopcount = 0xff; + u16 destid = rdev->destid; + + if (rdev->rswitch) { + destid = rdev->rswitch->destid; + hopcount = rdev->rswitch->hopcount; + } + + return rio_mport_write_config_8(rdev->net->hport, destid, hopcount, + offset, data); +}; + +extern int rio_mport_send_doorbell(struct rio_mport *mport, u16 destid, + u16 data); + +/** + * rio_send_doorbell - Send a doorbell message to a device + * @rdev: RIO device + * @data: Doorbell message data + * + * Send a doorbell message to a RIO device. The doorbell message + * has a 16-bit info field provided by the @data argument. + */ +static inline int rio_send_doorbell(struct rio_dev *rdev, u16 data) +{ + return rio_mport_send_doorbell(rdev->net->hport, rdev->destid, data); +}; + +/** + * rio_init_mbox_res - Initialize a RIO mailbox resource + * @res: resource struct + * @start: start of mailbox range + * @end: end of mailbox range + * + * This function is used to initialize the fields of a resource + * for use as a mailbox resource. It initializes a range of + * mailboxes using the start and end arguments. + */ +static inline void rio_init_mbox_res(struct resource *res, int start, int end) +{ + memset(res, 0, sizeof(struct resource)); + res->start = start; + res->end = end; + res->flags = RIO_RESOURCE_MAILBOX; +} + +/** + * rio_init_dbell_res - Initialize a RIO doorbell resource + * @res: resource struct + * @start: start of doorbell range + * @end: end of doorbell range + * + * This function is used to initialize the fields of a resource + * for use as a doorbell resource. It initializes a range of + * doorbell messages using the start and end arguments. + */ +static inline void rio_init_dbell_res(struct resource *res, u16 start, u16 end) +{ + memset(res, 0, sizeof(struct resource)); + res->start = start; + res->end = end; + res->flags = RIO_RESOURCE_DOORBELL; +} + +/** + * RIO_DEVICE - macro used to describe a specific RIO device + * @vid: the 16 bit RIO vendor ID + * @did: the 16 bit RIO device ID + * + * This macro is used to create a struct rio_device_id that matches a + * specific device. The assembly vendor and assembly device fields + * will be set to %RIO_ANY_ID. + */ +#define RIO_DEVICE(dev,ven) \ + .did = (dev), .vid = (ven), \ + .asm_did = RIO_ANY_ID, .asm_vid = RIO_ANY_ID + +/* Mailbox management */ +extern int rio_request_outb_mbox(struct rio_mport *, void *, int, int, + void (*)(struct rio_mport *, void *,int, int)); +extern int rio_release_outb_mbox(struct rio_mport *, int); + +/** + * rio_add_outb_message - Add RIO message to an outbound mailbox queue + * @mport: RIO master port containing the outbound queue + * @rdev: RIO device the message is be sent to + * @mbox: The outbound mailbox queue + * @buffer: Pointer to the message buffer + * @len: Length of the message buffer + * + * Adds a RIO message buffer to an outbound mailbox queue for + * transmission. Returns 0 on success. + */ +static inline int rio_add_outb_message(struct rio_mport *mport, + struct rio_dev *rdev, int mbox, + void *buffer, size_t len) +{ + return rio_hw_add_outb_message(mport, rdev, mbox, buffer, len); +} + +extern int rio_request_inb_mbox(struct rio_mport *, void *, int, int, + void (*)(struct rio_mport *, void *, int, int)); +extern int rio_release_inb_mbox(struct rio_mport *, int); + +/** + * rio_add_inb_buffer - Add buffer to an inbound mailbox queue + * @mport: Master port containing the inbound mailbox + * @mbox: The inbound mailbox number + * @buffer: Pointer to the message buffer + * + * Adds a buffer to an inbound mailbox queue for reception. Returns + * 0 on success. + */ +static inline int rio_add_inb_buffer(struct rio_mport *mport, int mbox, + void *buffer) +{ + return rio_hw_add_inb_buffer(mport, mbox, buffer); +} + +/** + * rio_get_inb_message - Get A RIO message from an inbound mailbox queue + * @mport: Master port containing the inbound mailbox + * @mbox: The inbound mailbox number + * @buffer: Pointer to the message buffer + * + * Get a RIO message from an inbound mailbox queue. Returns 0 on success. + */ +static inline void *rio_get_inb_message(struct rio_mport *mport, int mbox) +{ + return rio_hw_get_inb_message(mport, mbox); +} + +/* Doorbell management */ +extern int rio_request_inb_dbell(struct rio_mport *, void *, u16, u16, + void (*)(struct rio_mport *, void *, u16, u16, u16)); +extern int rio_release_inb_dbell(struct rio_mport *, u16, u16); +extern struct resource *rio_request_outb_dbell(struct rio_dev *, u16, u16); +extern int rio_release_outb_dbell(struct rio_dev *, struct resource *); + +/* Memory region management */ +int rio_claim_resource(struct rio_dev *, int); +int rio_request_regions(struct rio_dev *, char *); +void rio_release_regions(struct rio_dev *); +int rio_request_region(struct rio_dev *, int, char *); +void rio_release_region(struct rio_dev *, int); + +/* LDM support */ +int rio_register_driver(struct rio_driver *); +void rio_unregister_driver(struct rio_driver *); +struct rio_dev *rio_dev_get(struct rio_dev *); +void rio_dev_put(struct rio_dev *); + +/** + * rio_name - Get the unique RIO device identifier + * @rdev: RIO device + * + * Get the unique RIO device identifier. Returns the device + * identifier string. + */ +static inline char *rio_name(struct rio_dev *rdev) +{ + return rdev->dev.bus_id; +} + +/** + * rio_get_drvdata - Get RIO driver specific data + * @rdev: RIO device + * + * Get RIO driver specific data. Returns a pointer to the + * driver specific data. + */ +static inline void *rio_get_drvdata(struct rio_dev *rdev) +{ + return dev_get_drvdata(&rdev->dev); +} + +/** + * rio_set_drvdata - Set RIO driver specific data + * @rdev: RIO device + * @data: Pointer to driver specific data + * + * Set RIO driver specific data. device struct driver data pointer + * is set to the @data argument. + */ +static inline void rio_set_drvdata(struct rio_dev *rdev, void *data) +{ + dev_set_drvdata(&rdev->dev, data); +} + +/* Misc driver helpers */ +extern u16 rio_local_get_device_id(struct rio_mport *port); +extern struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *from); +extern struct rio_dev *rio_get_asm(u16 vid, u16 did, u16 asm_vid, u16 asm_did, + struct rio_dev *from); + +#endif /* __KERNEL__ */ +#endif /* LINUX_RIO_DRV_H */ diff --git a/include/linux/rio_ids.h b/include/linux/rio_ids.h new file mode 100644 index 0000000000000000000000000000000000000000..919d4e07d54e5c528369bb399d8c57e064f9dbbc --- /dev/null +++ b/include/linux/rio_ids.h @@ -0,0 +1,24 @@ +/* + * RapidIO devices + * + * Copyright 2005 MontaVista Software, Inc. + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef LINUX_RIO_IDS_H +#define LINUX_RIO_IDS_H + +#define RIO_ANY_ID 0xffff + +#define RIO_VID_FREESCALE 0x0002 +#define RIO_DID_MPC8560 0x0003 + +#define RIO_VID_TUNDRA 0x000d +#define RIO_DID_TSI500 0x0500 + +#endif /* LINUX_RIO_IDS_H */ diff --git a/include/linux/rio_regs.h b/include/linux/rio_regs.h new file mode 100644 index 0000000000000000000000000000000000000000..326540f9b54e4c4ad253acbbd932eb663c0e6012 --- /dev/null +++ b/include/linux/rio_regs.h @@ -0,0 +1,215 @@ +/* + * RapidIO register definitions + * + * Copyright 2005 MontaVista Software, Inc. + * 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 + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef LINUX_RIO_REGS_H +#define LINUX_RIO_REGS_H + +/* + * In RapidIO, each device has a 2MB configuration space that is + * accessed via maintenance transactions. Portions of configuration + * space are standardized and/or reserved. + */ +#define RIO_DEV_ID_CAR 0x00 /* [I] Device Identity CAR */ +#define RIO_DEV_INFO_CAR 0x04 /* [I] Device Information CAR */ +#define RIO_ASM_ID_CAR 0x08 /* [I] Assembly Identity CAR */ +#define RIO_ASM_ID_MASK 0xffff0000 /* [I] Asm ID Mask */ +#define RIO_ASM_VEN_ID_MASK 0x0000ffff /* [I] Asm Vend Mask */ + +#define RIO_ASM_INFO_CAR 0x0c /* [I] Assembly Information CAR */ +#define RIO_ASM_REV_MASK 0xffff0000 /* [I] Asm Rev Mask */ +#define RIO_EXT_FTR_PTR_MASK 0x0000ffff /* [I] EF_PTR Mask */ + +#define RIO_PEF_CAR 0x10 /* [I] Processing Element Features CAR */ +#define RIO_PEF_BRIDGE 0x80000000 /* [I] Bridge */ +#define RIO_PEF_MEMORY 0x40000000 /* [I] MMIO */ +#define RIO_PEF_PROCESSOR 0x20000000 /* [I] Processor */ +#define RIO_PEF_SWITCH 0x10000000 /* [I] Switch */ +#define RIO_PEF_INB_MBOX 0x00f00000 /* [II] Mailboxes */ +#define RIO_PEF_INB_MBOX0 0x00800000 /* [II] Mailbox 0 */ +#define RIO_PEF_INB_MBOX1 0x00400000 /* [II] Mailbox 1 */ +#define RIO_PEF_INB_MBOX2 0x00200000 /* [II] Mailbox 2 */ +#define RIO_PEF_INB_MBOX3 0x00100000 /* [II] Mailbox 3 */ +#define RIO_PEF_INB_DOORBELL 0x00080000 /* [II] Doorbells */ +#define RIO_PEF_CTLS 0x00000010 /* [III] CTLS */ +#define RIO_PEF_EXT_FEATURES 0x00000008 /* [I] EFT_PTR valid */ +#define RIO_PEF_ADDR_66 0x00000004 /* [I] 66 bits */ +#define RIO_PEF_ADDR_50 0x00000002 /* [I] 50 bits */ +#define RIO_PEF_ADDR_34 0x00000001 /* [I] 34 bits */ + +#define RIO_SWP_INFO_CAR 0x14 /* [I] Switch Port Information CAR */ +#define RIO_SWP_INFO_PORT_TOTAL_MASK 0x0000ff00 /* [I] Total number of ports */ +#define RIO_SWP_INFO_PORT_NUM_MASK 0x000000ff /* [I] Maintenance transaction port number */ +#define RIO_GET_TOTAL_PORTS(x) ((x & RIO_SWP_INFO_PORT_TOTAL_MASK) >> 8) + +#define RIO_SRC_OPS_CAR 0x18 /* [I] Source Operations CAR */ +#define RIO_SRC_OPS_READ 0x00008000 /* [I] Read op */ +#define RIO_SRC_OPS_WRITE 0x00004000 /* [I] Write op */ +#define RIO_SRC_OPS_STREAM_WRITE 0x00002000 /* [I] Str-write op */ +#define RIO_SRC_OPS_WRITE_RESPONSE 0x00001000 /* [I] Write/resp op */ +#define RIO_SRC_OPS_DATA_MSG 0x00000800 /* [II] Data msg op */ +#define RIO_SRC_OPS_DOORBELL 0x00000400 /* [II] Doorbell op */ +#define RIO_SRC_OPS_ATOMIC_TST_SWP 0x00000100 /* [I] Atomic TAS op */ +#define RIO_SRC_OPS_ATOMIC_INC 0x00000080 /* [I] Atomic inc op */ +#define RIO_SRC_OPS_ATOMIC_DEC 0x00000040 /* [I] Atomic dec op */ +#define RIO_SRC_OPS_ATOMIC_SET 0x00000020 /* [I] Atomic set op */ +#define RIO_SRC_OPS_ATOMIC_CLR 0x00000010 /* [I] Atomic clr op */ +#define RIO_SRC_OPS_PORT_WRITE 0x00000004 /* [I] Port-write op */ + +#define RIO_DST_OPS_CAR 0x1c /* Destination Operations CAR */ +#define RIO_DST_OPS_READ 0x00008000 /* [I] Read op */ +#define RIO_DST_OPS_WRITE 0x00004000 /* [I] Write op */ +#define RIO_DST_OPS_STREAM_WRITE 0x00002000 /* [I] Str-write op */ +#define RIO_DST_OPS_WRITE_RESPONSE 0x00001000 /* [I] Write/resp op */ +#define RIO_DST_OPS_DATA_MSG 0x00000800 /* [II] Data msg op */ +#define RIO_DST_OPS_DOORBELL 0x00000400 /* [II] Doorbell op */ +#define RIO_DST_OPS_ATOMIC_TST_SWP 0x00000100 /* [I] Atomic TAS op */ +#define RIO_DST_OPS_ATOMIC_INC 0x00000080 /* [I] Atomic inc op */ +#define RIO_DST_OPS_ATOMIC_DEC 0x00000040 /* [I] Atomic dec op */ +#define RIO_DST_OPS_ATOMIC_SET 0x00000020 /* [I] Atomic set op */ +#define RIO_DST_OPS_ATOMIC_CLR 0x00000010 /* [I] Atomic clr op */ +#define RIO_DST_OPS_PORT_WRITE 0x00000004 /* [I] Port-write op */ + +#define RIO_OPS_READ 0x00008000 /* [I] Read op */ +#define RIO_OPS_WRITE 0x00004000 /* [I] Write op */ +#define RIO_OPS_STREAM_WRITE 0x00002000 /* [I] Str-write op */ +#define RIO_OPS_WRITE_RESPONSE 0x00001000 /* [I] Write/resp op */ +#define RIO_OPS_DATA_MSG 0x00000800 /* [II] Data msg op */ +#define RIO_OPS_DOORBELL 0x00000400 /* [II] Doorbell op */ +#define RIO_OPS_ATOMIC_TST_SWP 0x00000100 /* [I] Atomic TAS op */ +#define RIO_OPS_ATOMIC_INC 0x00000080 /* [I] Atomic inc op */ +#define RIO_OPS_ATOMIC_DEC 0x00000040 /* [I] Atomic dec op */ +#define RIO_OPS_ATOMIC_SET 0x00000020 /* [I] Atomic set op */ +#define RIO_OPS_ATOMIC_CLR 0x00000010 /* [I] Atomic clr op */ +#define RIO_OPS_PORT_WRITE 0x00000004 /* [I] Port-write op */ + + /* 0x20-0x3c *//* Reserved */ + +#define RIO_MBOX_CSR 0x40 /* [II] Mailbox CSR */ +#define RIO_MBOX0_AVAIL 0x80000000 /* [II] Mbox 0 avail */ +#define RIO_MBOX0_FULL 0x40000000 /* [II] Mbox 0 full */ +#define RIO_MBOX0_EMPTY 0x20000000 /* [II] Mbox 0 empty */ +#define RIO_MBOX0_BUSY 0x10000000 /* [II] Mbox 0 busy */ +#define RIO_MBOX0_FAIL 0x08000000 /* [II] Mbox 0 fail */ +#define RIO_MBOX0_ERROR 0x04000000 /* [II] Mbox 0 error */ +#define RIO_MBOX1_AVAIL 0x00800000 /* [II] Mbox 1 avail */ +#define RIO_MBOX1_FULL 0x00200000 /* [II] Mbox 1 full */ +#define RIO_MBOX1_EMPTY 0x00200000 /* [II] Mbox 1 empty */ +#define RIO_MBOX1_BUSY 0x00100000 /* [II] Mbox 1 busy */ +#define RIO_MBOX1_FAIL 0x00080000 /* [II] Mbox 1 fail */ +#define RIO_MBOX1_ERROR 0x00040000 /* [II] Mbox 1 error */ +#define RIO_MBOX2_AVAIL 0x00008000 /* [II] Mbox 2 avail */ +#define RIO_MBOX2_FULL 0x00004000 /* [II] Mbox 2 full */ +#define RIO_MBOX2_EMPTY 0x00002000 /* [II] Mbox 2 empty */ +#define RIO_MBOX2_BUSY 0x00001000 /* [II] Mbox 2 busy */ +#define RIO_MBOX2_FAIL 0x00000800 /* [II] Mbox 2 fail */ +#define RIO_MBOX2_ERROR 0x00000400 /* [II] Mbox 2 error */ +#define RIO_MBOX3_AVAIL 0x00000080 /* [II] Mbox 3 avail */ +#define RIO_MBOX3_FULL 0x00000040 /* [II] Mbox 3 full */ +#define RIO_MBOX3_EMPTY 0x00000020 /* [II] Mbox 3 empty */ +#define RIO_MBOX3_BUSY 0x00000010 /* [II] Mbox 3 busy */ +#define RIO_MBOX3_FAIL 0x00000008 /* [II] Mbox 3 fail */ +#define RIO_MBOX3_ERROR 0x00000004 /* [II] Mbox 3 error */ + +#define RIO_WRITE_PORT_CSR 0x44 /* [I] Write Port CSR */ +#define RIO_DOORBELL_CSR 0x44 /* [II] Doorbell CSR */ +#define RIO_DOORBELL_AVAIL 0x80000000 /* [II] Doorbell avail */ +#define RIO_DOORBELL_FULL 0x40000000 /* [II] Doorbell full */ +#define RIO_DOORBELL_EMPTY 0x20000000 /* [II] Doorbell empty */ +#define RIO_DOORBELL_BUSY 0x10000000 /* [II] Doorbell busy */ +#define RIO_DOORBELL_FAILED 0x08000000 /* [II] Doorbell failed */ +#define RIO_DOORBELL_ERROR 0x04000000 /* [II] Doorbell error */ +#define RIO_WRITE_PORT_AVAILABLE 0x00000080 /* [I] Write Port Available */ +#define RIO_WRITE_PORT_FULL 0x00000040 /* [I] Write Port Full */ +#define RIO_WRITE_PORT_EMPTY 0x00000020 /* [I] Write Port Empty */ +#define RIO_WRITE_PORT_BUSY 0x00000010 /* [I] Write Port Busy */ +#define RIO_WRITE_PORT_FAILED 0x00000008 /* [I] Write Port Failed */ +#define RIO_WRITE_PORT_ERROR 0x00000004 /* [I] Write Port Error */ + + /* 0x48 *//* Reserved */ + +#define RIO_PELL_CTRL_CSR 0x4c /* [I] PE Logical Layer Control CSR */ +#define RIO_PELL_ADDR_66 0x00000004 /* [I] 66-bit addr */ +#define RIO_PELL_ADDR_50 0x00000002 /* [I] 50-bit addr */ +#define RIO_PELL_ADDR_34 0x00000001 /* [I] 34-bit addr */ + + /* 0x50-0x54 *//* Reserved */ + +#define RIO_LCSH_BA 0x58 /* [I] LCS High Base Address */ +#define RIO_LCSL_BA 0x5c /* [I] LCS Base Address */ + +#define RIO_DID_CSR 0x60 /* [III] Base Device ID CSR */ + + /* 0x64 *//* Reserved */ + +#define RIO_HOST_DID_LOCK_CSR 0x68 /* [III] Host Base Device ID Lock CSR */ +#define RIO_COMPONENT_TAG_CSR 0x6c /* [III] Component Tag CSR */ + + /* 0x70-0xf8 *//* Reserved */ + /* 0x100-0xfff8 *//* [I] Extended Features Space */ + /* 0x10000-0xfffff8 *//* [I] Implementation-defined Space */ + +/* + * Extended Features Space is a configuration space area where + * functionality is mapped into extended feature blocks via a + * singly linked list of extended feature pointers (EFT_PTR). + * + * Each extended feature block can be identified/located in + * Extended Features Space by walking the extended feature + * list starting with the Extended Feature Pointer located + * in the Assembly Information CAR. + * + * Extended Feature Blocks (EFBs) are identified with an assigned + * EFB ID. Extended feature block offsets in the definitions are + * relative to the offset of the EFB within the Extended Features + * Space. + */ + +/* Helper macros to parse the Extended Feature Block header */ +#define RIO_EFB_PTR_MASK 0xffff0000 +#define RIO_EFB_ID_MASK 0x0000ffff +#define RIO_GET_BLOCK_PTR(x) ((x & RIO_EFB_PTR_MASK) >> 16) +#define RIO_GET_BLOCK_ID(x) (x & RIO_EFB_ID_MASK) + +/* Extended Feature Block IDs */ +#define RIO_EFB_PAR_EP_ID 0x0001 /* [IV] LP/LVDS EP Devices */ +#define RIO_EFB_PAR_EP_REC_ID 0x0002 /* [IV] LP/LVDS EP Recovery Devices */ +#define RIO_EFB_PAR_EP_FREE_ID 0x0003 /* [IV] LP/LVDS EP Free Devices */ +#define RIO_EFB_SER_EP_ID 0x0004 /* [VI] LP/Serial EP Devices */ +#define RIO_EFB_SER_EP_REC_ID 0x0005 /* [VI] LP/Serial EP Recovery Devices */ +#define RIO_EFB_SER_EP_FREE_ID 0x0006 /* [VI] LP/Serial EP Free Devices */ + +/* + * Physical 8/16 LP-LVDS + * ID=0x0001, Generic End Point Devices + * ID=0x0002, Generic End Point Devices, software assisted recovery option + * ID=0x0003, Generic End Point Free Devices + * + * Physical LP-Serial + * ID=0x0004, Generic End Point Devices + * ID=0x0005, Generic End Point Devices, software assisted recovery option + * ID=0x0006, Generic End Point Free Devices + */ +#define RIO_PORT_MNT_HEADER 0x0000 +#define RIO_PORT_REQ_CTL_CSR 0x0020 +#define RIO_PORT_RSP_CTL_CSR 0x0024 /* 0x0001/0x0002 */ +#define RIO_PORT_GEN_CTL_CSR 0x003c +#define RIO_PORT_GEN_HOST 0x80000000 +#define RIO_PORT_GEN_MASTER 0x40000000 +#define RIO_PORT_GEN_DISCOVERED 0x20000000 +#define RIO_PORT_N_MNT_REQ_CSR(x) (0x0040 + x*0x20) /* 0x0002 */ +#define RIO_PORT_N_MNT_RSP_CSR(x) (0x0044 + x*0x20) /* 0x0002 */ +#define RIO_PORT_N_ACK_STS_CSR(x) (0x0048 + x*0x20) /* 0x0002 */ +#define RIO_PORT_N_ERR_STS_CSR(x) (0x58 + x*0x20) +#define PORT_N_ERR_STS_PORT_OK 0x00000002 +#define RIO_PORT_N_CTL_CSR(x) (0x5c + x*0x20) + +#endif /* LINUX_RIO_REGS_H */ diff --git a/include/linux/rslib.h b/include/linux/rslib.h index 980c8f74d8dc3d4dcce517720fd686c725241c10..ace25acfdc97375d0d403afb4bf12c08443e6309 100644 --- a/include/linux/rslib.h +++ b/include/linux/rslib.h @@ -1,15 +1,15 @@ -/* +/* * include/linux/rslib.h * * Overview: * Generic Reed Solomon encoder / decoder library - * + * * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) * * RS code lifted from reed solomon library written by Phil Karn * Copyright 2002 Phil Karn, KA9Q * - * $Id: rslib.h,v 1.3 2004/10/05 22:08:22 gleixner Exp $ + * $Id: rslib.h,v 1.4 2005/11/07 11:14:52 gleixner Exp $ * * 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 @@ -21,20 +21,20 @@ #include -/** +/** * struct rs_control - rs control structure - * + * * @mm: Bits per symbol * @nn: Symbols per block (= (1<mm = number of bits per symbol + * rs->mm = number of bits per symbol * rs->nn = (2^rs->mm) - 1 - * + * * Simple arithmetic modulo would return a wrong result for values * >= 3 * rs->nn */ diff --git a/include/linux/sem.h b/include/linux/sem.h index 106f9757339a54aeffc52a440129b5827040c8c1..3c1f1120fe8846de2ef1f9a3ec2d4cf47171f8b0 100644 --- a/include/linux/sem.h +++ b/include/linux/sem.h @@ -79,6 +79,8 @@ struct seminfo { #ifdef __KERNEL__ +struct task_struct; + /* One semaphore structure for each semaphore in the system. */ struct sem { int semval; /* current value */ diff --git a/include/linux/shm.h b/include/linux/shm.h index 80113a1f60bc83447184c6cc55b89eafa7eebd10..a2c896ad0befa6819dbae3e1ffd47b1679597346 100644 --- a/include/linux/shm.h +++ b/include/linux/shm.h @@ -92,6 +92,7 @@ struct shmid_kernel /* private to the kernel */ #define SHM_DEST 01000 /* segment will be destroyed on last detach */ #define SHM_LOCKED 02000 /* segment will not be swapped */ #define SHM_HUGETLB 04000 /* segment will use huge TLB pages */ +#define SHM_NORESERVE 010000 /* don't check for reservations */ #ifdef CONFIG_SYSVIPC long do_shmat(int shmid, char __user *shmaddr, int shmflg, unsigned long *addr); diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 4286d832166f1bf1d6a697d5063a48d60d502cca..fdfb8fe8c38ce0a6f38f342558b1858a5f6b5f60 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -603,29 +603,46 @@ static inline void skb_queue_head_init(struct sk_buff_head *list) */ /** - * __skb_queue_head - queue a buffer at the list head + * __skb_queue_after - queue a buffer at the list head * @list: list to use + * @prev: place after this buffer * @newsk: buffer to queue * - * Queue a buffer at the start of a list. This function takes no locks + * Queue a buffer int the middle of a list. This function takes no locks * and you must therefore hold required locks before calling it. * * A buffer cannot be placed on two lists at the same time. */ -extern void skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk); -static inline void __skb_queue_head(struct sk_buff_head *list, - struct sk_buff *newsk) +static inline void __skb_queue_after(struct sk_buff_head *list, + struct sk_buff *prev, + struct sk_buff *newsk) { - struct sk_buff *prev, *next; - + struct sk_buff *next; list->qlen++; - prev = (struct sk_buff *)list; + next = prev->next; newsk->next = next; newsk->prev = prev; next->prev = prev->next = newsk; } +/** + * __skb_queue_head - queue a buffer at the list head + * @list: list to use + * @newsk: buffer to queue + * + * Queue a buffer at the start of a list. This function takes no locks + * and you must therefore hold required locks before calling it. + * + * A buffer cannot be placed on two lists at the same time. + */ +extern void skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk); +static inline void __skb_queue_head(struct sk_buff_head *list, + struct sk_buff *newsk) +{ + __skb_queue_after(list, (struct sk_buff *)list, newsk); +} + /** * __skb_queue_tail - queue a buffer at the list tail * @list: list to use @@ -1203,6 +1220,11 @@ static inline void kunmap_skb_frag(void *vaddr) prefetch(skb->next), (skb != (struct sk_buff *)(queue)); \ skb = skb->next) +#define skb_queue_reverse_walk(queue, skb) \ + for (skb = (queue)->prev; \ + prefetch(skb->prev), (skb != (struct sk_buff *)(queue)); \ + skb = skb->prev) + extern struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err); diff --git a/include/linux/slab.h b/include/linux/slab.h index 09b9aa60063dda9d56d062f9e44e2042df72f744..d1ea4051b99618b1f12a6a31291353cd9cf3ce69 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -9,7 +9,7 @@ #if defined(__KERNEL__) -typedef struct kmem_cache_s kmem_cache_t; +typedef struct kmem_cache kmem_cache_t; #include /* kmalloc_sizes.h needs CONFIG_ options */ #include diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 5af8800e0ce328a05aa7cbaeaa0b604ba28b00ab..e4086ec8b952a3a87b5f16bd654df3c70a05066a 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -171,7 +171,8 @@ xdr_argsize_check(struct svc_rqst *rqstp, u32 *p) { char *cp = (char *)p; struct kvec *vec = &rqstp->rq_arg.head[0]; - return cp - (char*)vec->iov_base <= vec->iov_len; + return cp >= (char*)vec->iov_base + && cp <= (char*)vec->iov_base + vec->iov_len; } static inline int diff --git a/include/linux/superhyway.h b/include/linux/superhyway.h index c906c5a0aaefadb6f93f53f45ce25f9b3ff62d2f..17ea468fa3621a9246a2e5717a99c94ca0b01ddc 100644 --- a/include/linux/superhyway.h +++ b/include/linux/superhyway.h @@ -19,7 +19,7 @@ */ #define SUPERHYWAY_DEVICE_ID_SH5_DMAC 0x0183 -struct vcr_info { +struct superhyway_vcr_info { u8 perr_flags; /* P-port Error flags */ u8 merr_flags; /* Module Error flags */ u16 mod_vers; /* Module Version */ @@ -28,6 +28,17 @@ struct vcr_info { u8 top_mb; /* Top Memory block */ }; +struct superhyway_ops { + int (*read_vcr)(unsigned long base, struct superhyway_vcr_info *vcr); + int (*write_vcr)(unsigned long base, struct superhyway_vcr_info vcr); +}; + +struct superhyway_bus { + struct superhyway_ops *ops; +}; + +extern struct superhyway_bus superhyway_channels[]; + struct superhyway_device_id { unsigned int id; unsigned long driver_data; @@ -55,9 +66,11 @@ struct superhyway_device { struct superhyway_device_id id; struct superhyway_driver *drv; + struct superhyway_bus *bus; - struct resource resource; - struct vcr_info vcr; + int num_resources; + struct resource *resource; + struct superhyway_vcr_info vcr; }; #define to_superhyway_device(d) container_of((d), struct superhyway_device, dev) @@ -65,12 +78,27 @@ struct superhyway_device { #define superhyway_get_drvdata(d) dev_get_drvdata(&(d)->dev) #define superhyway_set_drvdata(d,p) dev_set_drvdata(&(d)->dev, (p)) -extern int superhyway_scan_bus(void); +static inline int +superhyway_read_vcr(struct superhyway_device *dev, unsigned long base, + struct superhyway_vcr_info *vcr) +{ + return dev->bus->ops->read_vcr(base, vcr); +} + +static inline int +superhyway_write_vcr(struct superhyway_device *dev, unsigned long base, + struct superhyway_vcr_info vcr) +{ + return dev->bus->ops->write_vcr(base, vcr); +} + +extern int superhyway_scan_bus(struct superhyway_bus *); /* drivers/sh/superhyway/superhyway.c */ int superhyway_register_driver(struct superhyway_driver *); void superhyway_unregister_driver(struct superhyway_driver *); -int superhyway_add_device(unsigned int, unsigned long, unsigned long long); +int superhyway_add_device(unsigned long base, struct superhyway_device *, struct superhyway_bus *); +int superhyway_add_devices(struct superhyway_bus *bus, struct superhyway_device **devices, int nr_devices); /* drivers/sh/superhyway/superhyway-sysfs.c */ extern struct device_attribute superhyway_dev_attrs[]; diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index fc8e367f671e11bccc88faccb6247ce0017e5009..fc131d6602b989a289f0bd9ff3f4c4f1aa987c71 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -24,6 +24,7 @@ #include struct file; +struct completion; #define CTL_MAXNAME 10 /* how many path components do we allow in a call to sysctl? In other words, what is @@ -925,6 +926,8 @@ struct ctl_table_header { ctl_table *ctl_table; struct list_head ctl_entry; + int used; + struct completion *unregistering; }; struct ctl_table_header * register_sysctl_table(ctl_table * table, diff --git a/include/linux/wait.h b/include/linux/wait.h index d38c9fecdc368450d00a4e5602944b0288a2c64b..d28518236b62fea581606ee74c76607743153aad 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -54,6 +54,7 @@ struct __wait_queue_head { }; typedef struct __wait_queue_head wait_queue_head_t; +struct task_struct; /* * Macros for declaration and initialisaton of the datatypes diff --git a/include/mtd/inftl-user.h b/include/mtd/inftl-user.h index bda4f2c8f7284d67848aab6dbd3c60be4f6ef6fe..9b1e2526b45ec2be45e58768f8ad3e801dc8dcd5 100644 --- a/include/mtd/inftl-user.h +++ b/include/mtd/inftl-user.h @@ -1,7 +1,7 @@ /* - * $Id: inftl-user.h,v 1.1 2004/05/05 15:17:00 dwmw2 Exp $ + * $Id: inftl-user.h,v 1.2 2005/11/07 11:14:56 gleixner Exp $ * - * Parts of INFTL headers shared with userspace + * Parts of INFTL headers shared with userspace * */ diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h index 428d9122940b131dd4450edbd45e614ba70de33d..b5994ea56a5a19ba6aae6f297e370ea9bd1b4d60 100644 --- a/include/mtd/mtd-abi.h +++ b/include/mtd/mtd-abi.h @@ -1,7 +1,7 @@ /* - * $Id: mtd-abi.h,v 1.11 2005/05/19 16:08:58 gleixner Exp $ + * $Id: mtd-abi.h,v 1.13 2005/11/07 11:14:56 gleixner Exp $ * - * Portions of MTD ABI definition which are shared by kernel and user space + * Portions of MTD ABI definition which are shared by kernel and user space */ #ifndef __MTD_ABI_H__ @@ -42,6 +42,7 @@ struct mtd_oob_buf { #define MTD_OOB 64 // Out-of-band data (NAND flash) #define MTD_ECC 128 // Device capable of automatic ECC #define MTD_NO_VIRTBLOCKS 256 // Virtual blocks not allowed +#define MTD_PROGRAM_REGIONS 512 // Configurable Programming Regions // Some common devices / combinations of capabilities #define MTD_CAP_ROM 0 @@ -80,7 +81,7 @@ struct mtd_info_user { }; struct region_info_user { - uint32_t offset; /* At which this region starts, + uint32_t offset; /* At which this region starts, * from the beginning of the MTD */ uint32_t erasesize; /* For this region */ uint32_t numblocks; /* Number of blocks in this region */ diff --git a/include/mtd/nftl-user.h b/include/mtd/nftl-user.h index 924ec0459e9c09600ce2820954cdf9b4c8b14eb4..b2bca18e7311bf1670271b3cf5988b0c933278fe 100644 --- a/include/mtd/nftl-user.h +++ b/include/mtd/nftl-user.h @@ -1,7 +1,7 @@ /* - * $Id: nftl-user.h,v 1.1 2004/05/05 14:44:57 dwmw2 Exp $ + * $Id: nftl-user.h,v 1.2 2005/11/07 11:14:56 gleixner Exp $ * - * Parts of NFTL headers shared with userspace + * Parts of NFTL headers shared with userspace * */ diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index e42d728b16208d70d1398ec5f1bada1cca4401ea..911ceb5cd263b51c90eee3e5803cee3206a88bd8 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -57,8 +57,6 @@ #define BT_DBG(fmt, arg...) printk(KERN_INFO "%s: " fmt "\n" , __FUNCTION__ , ## arg) #define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __FUNCTION__ , ## arg) -extern struct proc_dir_entry *proc_bt; - /* Connection and socket states */ enum { BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */ @@ -177,4 +175,6 @@ extern int hci_sock_cleanup(void); extern int bt_sysfs_init(void); extern void bt_sysfs_cleanup(void); +extern struct class bt_class; + #endif /* __BLUETOOTH_H */ diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index fa2d12b0579b49fc9c5e480c65a931ad36c784a5..b06a2d2f63d2dd3d8aaef4b7f7ad22431609a64d 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -184,10 +184,10 @@ enum { struct hci_rp_read_loc_version { __u8 status; __u8 hci_ver; - __u16 hci_rev; + __le16 hci_rev; __u8 lmp_ver; - __u16 manufacturer; - __u16 lmp_subver; + __le16 manufacturer; + __le16 lmp_subver; } __attribute__ ((packed)); #define OCF_READ_LOCAL_FEATURES 0x0003 @@ -199,10 +199,10 @@ struct hci_rp_read_loc_features { #define OCF_READ_BUFFER_SIZE 0x0005 struct hci_rp_read_buffer_size { __u8 status; - __u16 acl_mtu; + __le16 acl_mtu; __u8 sco_mtu; - __u16 acl_max_pkt; - __u16 sco_max_pkt; + __le16 acl_max_pkt; + __le16 sco_max_pkt; } __attribute__ ((packed)); #define OCF_READ_BD_ADDR 0x0009 @@ -267,21 +267,21 @@ struct hci_cp_write_dev_class { #define OCF_READ_VOICE_SETTING 0x0025 struct hci_rp_read_voice_setting { - __u8 status; - __u16 voice_setting; + __u8 status; + __le16 voice_setting; } __attribute__ ((packed)); #define OCF_WRITE_VOICE_SETTING 0x0026 struct hci_cp_write_voice_setting { - __u16 voice_setting; + __le16 voice_setting; } __attribute__ ((packed)); #define OCF_HOST_BUFFER_SIZE 0x0033 struct hci_cp_host_buffer_size { - __u16 acl_mtu; + __le16 acl_mtu; __u8 sco_mtu; - __u16 acl_max_pkt; - __u16 sco_max_pkt; + __le16 acl_max_pkt; + __le16 sco_max_pkt; } __attribute__ ((packed)); /* Link Control */ @@ -289,10 +289,10 @@ struct hci_cp_host_buffer_size { #define OCF_CREATE_CONN 0x0005 struct hci_cp_create_conn { bdaddr_t bdaddr; - __u16 pkt_type; + __le16 pkt_type; __u8 pscan_rep_mode; __u8 pscan_mode; - __u16 clock_offset; + __le16 clock_offset; __u8 role_switch; } __attribute__ ((packed)); @@ -310,14 +310,14 @@ struct hci_cp_reject_conn_req { #define OCF_DISCONNECT 0x0006 struct hci_cp_disconnect { - __u16 handle; + __le16 handle; __u8 reason; } __attribute__ ((packed)); #define OCF_ADD_SCO 0x0007 struct hci_cp_add_sco { - __u16 handle; - __u16 pkt_type; + __le16 handle; + __le16 pkt_type; } __attribute__ ((packed)); #define OCF_INQUIRY 0x0001 @@ -354,56 +354,56 @@ struct hci_cp_pin_code_neg_reply { #define OCF_CHANGE_CONN_PTYPE 0x000F struct hci_cp_change_conn_ptype { - __u16 handle; - __u16 pkt_type; + __le16 handle; + __le16 pkt_type; } __attribute__ ((packed)); #define OCF_AUTH_REQUESTED 0x0011 struct hci_cp_auth_requested { - __u16 handle; + __le16 handle; } __attribute__ ((packed)); #define OCF_SET_CONN_ENCRYPT 0x0013 struct hci_cp_set_conn_encrypt { - __u16 handle; + __le16 handle; __u8 encrypt; } __attribute__ ((packed)); #define OCF_CHANGE_CONN_LINK_KEY 0x0015 struct hci_cp_change_conn_link_key { - __u16 handle; + __le16 handle; } __attribute__ ((packed)); #define OCF_READ_REMOTE_FEATURES 0x001B struct hci_cp_read_rmt_features { - __u16 handle; + __le16 handle; } __attribute__ ((packed)); #define OCF_READ_REMOTE_VERSION 0x001D struct hci_cp_read_rmt_version { - __u16 handle; + __le16 handle; } __attribute__ ((packed)); /* Link Policy */ #define OGF_LINK_POLICY 0x02 #define OCF_ROLE_DISCOVERY 0x0009 struct hci_cp_role_discovery { - __u16 handle; + __le16 handle; } __attribute__ ((packed)); struct hci_rp_role_discovery { __u8 status; - __u16 handle; + __le16 handle; __u8 role; } __attribute__ ((packed)); #define OCF_READ_LINK_POLICY 0x000C struct hci_cp_read_link_policy { - __u16 handle; + __le16 handle; } __attribute__ ((packed)); struct hci_rp_read_link_policy { __u8 status; - __u16 handle; - __u16 policy; + __le16 handle; + __le16 policy; } __attribute__ ((packed)); #define OCF_SWITCH_ROLE 0x000B @@ -414,12 +414,12 @@ struct hci_cp_switch_role { #define OCF_WRITE_LINK_POLICY 0x000D struct hci_cp_write_link_policy { - __u16 handle; - __u16 policy; + __le16 handle; + __le16 policy; } __attribute__ ((packed)); struct hci_rp_write_link_policy { __u8 status; - __u16 handle; + __le16 handle; } __attribute__ ((packed)); /* Status params */ @@ -441,7 +441,7 @@ struct inquiry_info { __u8 pscan_period_mode; __u8 pscan_mode; __u8 dev_class[3]; - __u16 clock_offset; + __le16 clock_offset; } __attribute__ ((packed)); #define HCI_EV_INQUIRY_RESULT_WITH_RSSI 0x22 @@ -450,7 +450,7 @@ struct inquiry_info_with_rssi { __u8 pscan_rep_mode; __u8 pscan_period_mode; __u8 dev_class[3]; - __u16 clock_offset; + __le16 clock_offset; __s8 rssi; } __attribute__ ((packed)); struct inquiry_info_with_rssi_and_pscan_mode { @@ -459,7 +459,7 @@ struct inquiry_info_with_rssi_and_pscan_mode { __u8 pscan_period_mode; __u8 pscan_mode; __u8 dev_class[3]; - __u16 clock_offset; + __le16 clock_offset; __s8 rssi; } __attribute__ ((packed)); @@ -469,7 +469,7 @@ struct extended_inquiry_info { __u8 pscan_rep_mode; __u8 pscan_period_mode; __u8 dev_class[3]; - __u16 clock_offset; + __le16 clock_offset; __s8 rssi; __u8 data[240]; } __attribute__ ((packed)); @@ -477,7 +477,7 @@ struct extended_inquiry_info { #define HCI_EV_CONN_COMPLETE 0x03 struct hci_ev_conn_complete { __u8 status; - __u16 handle; + __le16 handle; bdaddr_t bdaddr; __u8 link_type; __u8 encr_mode; @@ -493,27 +493,27 @@ struct hci_ev_conn_request { #define HCI_EV_DISCONN_COMPLETE 0x05 struct hci_ev_disconn_complete { __u8 status; - __u16 handle; + __le16 handle; __u8 reason; } __attribute__ ((packed)); #define HCI_EV_AUTH_COMPLETE 0x06 struct hci_ev_auth_complete { __u8 status; - __u16 handle; + __le16 handle; } __attribute__ ((packed)); #define HCI_EV_ENCRYPT_CHANGE 0x08 struct hci_ev_encrypt_change { __u8 status; - __u16 handle; + __le16 handle; __u8 encrypt; } __attribute__ ((packed)); #define HCI_EV_CHANGE_CONN_LINK_KEY_COMPLETE 0x09 struct hci_ev_change_conn_link_key_complete { __u8 status; - __u16 handle; + __le16 handle; } __attribute__ ((packed)); #define HCI_EV_QOS_SETUP_COMPLETE 0x0D @@ -526,21 +526,21 @@ struct hci_qos { } __attribute__ ((packed)); struct hci_ev_qos_setup_complete { __u8 status; - __u16 handle; + __le16 handle; struct hci_qos qos; } __attribute__ ((packed)); #define HCI_EV_CMD_COMPLETE 0x0E struct hci_ev_cmd_complete { __u8 ncmd; - __u16 opcode; + __le16 opcode; } __attribute__ ((packed)); #define HCI_EV_CMD_STATUS 0x0F struct hci_ev_cmd_status { __u8 status; __u8 ncmd; - __u16 opcode; + __le16 opcode; } __attribute__ ((packed)); #define HCI_EV_NUM_COMP_PKTS 0x13 @@ -559,9 +559,9 @@ struct hci_ev_role_change { #define HCI_EV_MODE_CHANGE 0x14 struct hci_ev_mode_change { __u8 status; - __u16 handle; + __le16 handle; __u8 mode; - __u16 interval; + __le16 interval; } __attribute__ ((packed)); #define HCI_EV_PIN_CODE_REQ 0x16 @@ -584,24 +584,24 @@ struct hci_ev_link_key_notify { #define HCI_EV_RMT_FEATURES 0x0B struct hci_ev_rmt_features { __u8 status; - __u16 handle; + __le16 handle; __u8 features[8]; } __attribute__ ((packed)); #define HCI_EV_RMT_VERSION 0x0C struct hci_ev_rmt_version { __u8 status; - __u16 handle; + __le16 handle; __u8 lmp_ver; - __u16 manufacturer; - __u16 lmp_subver; + __le16 manufacturer; + __le16 lmp_subver; } __attribute__ ((packed)); #define HCI_EV_CLOCK_OFFSET 0x01C struct hci_ev_clock_offset { __u8 status; - __u16 handle; - __u16 clock_offset; + __le16 handle; + __le16 clock_offset; } __attribute__ ((packed)); #define HCI_EV_PSCAN_REP_MODE 0x20 @@ -638,7 +638,7 @@ struct hci_ev_si_security { #define HCI_SCO_HDR_SIZE 3 struct hci_command_hdr { - __u16 opcode; /* OCF & OGF */ + __le16 opcode; /* OCF & OGF */ __u8 plen; } __attribute__ ((packed)); @@ -648,22 +648,22 @@ struct hci_event_hdr { } __attribute__ ((packed)); struct hci_acl_hdr { - __u16 handle; /* Handle & Flags(PB, BC) */ - __u16 dlen; + __le16 handle; /* Handle & Flags(PB, BC) */ + __le16 dlen; } __attribute__ ((packed)); struct hci_sco_hdr { - __u16 handle; + __le16 handle; __u8 dlen; } __attribute__ ((packed)); /* Command opcode pack/unpack */ -#define hci_opcode_pack(ogf, ocf) (__u16)((ocf & 0x03ff)|(ogf << 10)) +#define hci_opcode_pack(ogf, ocf) (__u16) ((ocf & 0x03ff)|(ogf << 10)) #define hci_opcode_ogf(op) (op >> 10) #define hci_opcode_ocf(op) (op & 0x03ff) /* ACL handle and flags pack/unpack */ -#define hci_handle_pack(h, f) (__u16)((h & 0x0fff)|(f << 12)) +#define hci_handle_pack(h, f) (__u16) ((h & 0x0fff)|(f << 12)) #define hci_handle(h) (h & 0x0fff) #define hci_flags(h) (h >> 12) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 7f933f30207830333996a9d872acbbef536e636d..bb9f81dc8723c5522daffd6d6184f3df675d0321 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -25,7 +25,6 @@ #ifndef __HCI_CORE_H #define __HCI_CORE_H -#include #include /* HCI upper protocols */ @@ -34,8 +33,6 @@ #define HCI_INIT_TIMEOUT (HZ * 10) -extern struct proc_dir_entry *proc_bt_hci; - /* HCI Core structures */ struct inquiry_data { @@ -44,7 +41,7 @@ struct inquiry_data { __u8 pscan_period_mode; __u8 pscan_mode; __u8 dev_class[3]; - __u16 clock_offset; + __le16 clock_offset; __s8 rssi; }; @@ -126,10 +123,6 @@ struct hci_dev { atomic_t promisc; -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *proc; -#endif - struct class_device class_dev; struct module *owner; diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h index e656be7c001a342935119c44a8ffd741a5aa0a13..bbfac86734ec44f50b34efaf5067498c8080a3dc 100644 --- a/include/net/bluetooth/rfcomm.h +++ b/include/net/bluetooth/rfcomm.h @@ -351,6 +351,4 @@ int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, void __user *arg); int rfcomm_init_ttys(void); void rfcomm_cleanup_ttys(void); -extern struct proc_dir_entry *proc_bt_rfcomm; - #endif /* __RFCOMM_H */ diff --git a/include/net/inet_ecn.h b/include/net/inet_ecn.h index f87845e2e96589a30791dac5af7603779f2c355a..b0c47e2eccf10849d7ca097eeeaf3b08c307837e 100644 --- a/include/net/inet_ecn.h +++ b/include/net/inet_ecn.h @@ -2,6 +2,7 @@ #define _INET_ECN_H_ #include +#include #include enum { @@ -48,7 +49,7 @@ static inline __u8 INET_ECN_encapsulate(__u8 outer, __u8 inner) (label) |= __constant_htons(INET_ECN_ECT_0 << 4); \ } while (0) -static inline void IP_ECN_set_ce(struct iphdr *iph) +static inline int IP_ECN_set_ce(struct iphdr *iph) { u32 check = iph->check; u32 ecn = (iph->tos + 1) & INET_ECN_MASK; @@ -61,7 +62,7 @@ static inline void IP_ECN_set_ce(struct iphdr *iph) * INET_ECN_CE => 00 */ if (!(ecn & 2)) - return; + return !ecn; /* * The following gives us: @@ -72,6 +73,7 @@ static inline void IP_ECN_set_ce(struct iphdr *iph) iph->check = check + (check>=0xFFFF); iph->tos |= INET_ECN_CE; + return 1; } static inline void IP_ECN_clear(struct iphdr *iph) @@ -87,11 +89,12 @@ static inline void ipv4_copy_dscp(struct iphdr *outer, struct iphdr *inner) struct ipv6hdr; -static inline void IP6_ECN_set_ce(struct ipv6hdr *iph) +static inline int IP6_ECN_set_ce(struct ipv6hdr *iph) { if (INET_ECN_is_not_ect(ipv6_get_dsfield(iph))) - return; + return 0; *(u32*)iph |= htonl(INET_ECN_CE << 20); + return 1; } static inline void IP6_ECN_clear(struct ipv6hdr *iph) @@ -105,4 +108,21 @@ static inline void ipv6_copy_dscp(struct ipv6hdr *outer, struct ipv6hdr *inner) ipv6_change_dsfield(inner, INET_ECN_MASK, dscp); } +static inline int INET_ECN_set_ce(struct sk_buff *skb) +{ + switch (skb->protocol) { + case __constant_htons(ETH_P_IP): + if (skb->nh.raw + sizeof(struct iphdr) <= skb->tail) + return IP_ECN_set_ce(skb->nh.iph); + break; + + case __constant_htons(ETH_P_IPV6): + if (skb->nh.raw + sizeof(struct ipv6hdr) <= skb->tail) + return IP6_ECN_set_ce(skb->nh.ipv6h); + break; + } + + return 0; +} + #endif diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index f50f959683400b78df241e061f64138c0f7a9ff9..07840baa934125280a97a3261fcb25da1840588e 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -125,9 +125,7 @@ struct inet_hashinfo { rwlock_t lhash_lock ____cacheline_aligned; atomic_t lhash_users; wait_queue_head_t lhash_wait; - spinlock_t portalloc_lock; kmem_cache_t *bind_bucket_cachep; - int port_rover; }; static inline unsigned int inet_ehashfn(const __u32 laddr, const __u16 lport, diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 65ec86678a08e34280fdd23e7e10f2c2cbb1494f..6addb4d464d6c87b0b7d9ae2884c46e57c2e8737 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -252,12 +252,25 @@ typedef int (*inet_getfrag_t) (const void *data, char *, unsigned int, unsigned int); - -extern int ipv6_addr_type(const struct in6_addr *addr); +extern int __ipv6_addr_type(const struct in6_addr *addr); +static inline int ipv6_addr_type(const struct in6_addr *addr) +{ + return __ipv6_addr_type(addr) & 0xffff; +} static inline int ipv6_addr_scope(const struct in6_addr *addr) { - return ipv6_addr_type(addr) & IPV6_ADDR_SCOPE_MASK; + return __ipv6_addr_type(addr) & IPV6_ADDR_SCOPE_MASK; +} + +static inline int __ipv6_addr_src_scope(int type) +{ + return (type == IPV6_ADDR_ANY ? __IPV6_ADDR_SCOPE_INVALID : (type >> 16)); +} + +static inline int ipv6_addr_src_scope(const struct in6_addr *addr) +{ + return __ipv6_addr_src_scope(__ipv6_addr_type(addr)); } static inline int ipv6_addr_cmp(const struct in6_addr *a1, const struct in6_addr *a2) @@ -340,6 +353,54 @@ static inline int ipv6_addr_any(const struct in6_addr *a) a->s6_addr32[2] | a->s6_addr32[3] ) == 0); } +/* + * find the first different bit between two addresses + * length of address must be a multiple of 32bits + */ +static inline int __ipv6_addr_diff(const void *token1, const void *token2, int addrlen) +{ + const __u32 *a1 = token1, *a2 = token2; + int i; + + addrlen >>= 2; + + for (i = 0; i < addrlen; i++) { + __u32 xb = a1[i] ^ a2[i]; + if (xb) { + int j = 31; + + xb = ntohl(xb); + while ((xb & (1 << j)) == 0) + j--; + + return (i * 32 + 31 - j); + } + } + + /* + * we should *never* get to this point since that + * would mean the addrs are equal + * + * However, we do get to it 8) And exacly, when + * addresses are equal 8) + * + * ip route add 1111::/128 via ... + * ip route add 1111::/64 via ... + * and we are here. + * + * Ideally, this function should stop comparison + * at prefix length. It does not, but it is still OK, + * if returned value is greater than prefix length. + * --ANK (980803) + */ + return (addrlen << 5); +} + +static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_addr *a2) +{ + return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr)); +} + /* * Prototypes exported by ipv6 */ diff --git a/include/net/red.h b/include/net/red.h new file mode 100644 index 0000000000000000000000000000000000000000..2ed4358e3295c2f03595efd9bc9a91c86fa2b496 --- /dev/null +++ b/include/net/red.h @@ -0,0 +1,325 @@ +#ifndef __NET_SCHED_RED_H +#define __NET_SCHED_RED_H + +#include +#include +#include +#include +#include + +/* Random Early Detection (RED) algorithm. + ======================================= + + Source: Sally Floyd and Van Jacobson, "Random Early Detection Gateways + for Congestion Avoidance", 1993, IEEE/ACM Transactions on Networking. + + This file codes a "divisionless" version of RED algorithm + as written down in Fig.17 of the paper. + + Short description. + ------------------ + + When a new packet arrives we calculate the average queue length: + + avg = (1-W)*avg + W*current_queue_len, + + W is the filter time constant (chosen as 2^(-Wlog)), it controls + the inertia of the algorithm. To allow larger bursts, W should be + decreased. + + if (avg > th_max) -> packet marked (dropped). + if (avg < th_min) -> packet passes. + if (th_min < avg < th_max) we calculate probability: + + Pb = max_P * (avg - th_min)/(th_max-th_min) + + and mark (drop) packet with this probability. + Pb changes from 0 (at avg==th_min) to max_P (avg==th_max). + max_P should be small (not 1), usually 0.01..0.02 is good value. + + max_P is chosen as a number, so that max_P/(th_max-th_min) + is a negative power of two in order arithmetics to contain + only shifts. + + + Parameters, settable by user: + ----------------------------- + + qth_min - bytes (should be < qth_max/2) + qth_max - bytes (should be at least 2*qth_min and less limit) + Wlog - bits (<32) log(1/W). + Plog - bits (<32) + + Plog is related to max_P by formula: + + max_P = (qth_max-qth_min)/2^Plog; + + F.e. if qth_max=128K and qth_min=32K, then Plog=22 + corresponds to max_P=0.02 + + Scell_log + Stab + + Lookup table for log((1-W)^(t/t_ave). + + + NOTES: + + Upper bound on W. + ----------------- + + If you want to allow bursts of L packets of size S, + you should choose W: + + L + 1 - th_min/S < (1-(1-W)^L)/W + + th_min/S = 32 th_min/S = 4 + + log(W) L + -1 33 + -2 35 + -3 39 + -4 46 + -5 57 + -6 75 + -7 101 + -8 135 + -9 190 + etc. + */ + +#define RED_STAB_SIZE 256 +#define RED_STAB_MASK (RED_STAB_SIZE - 1) + +struct red_stats +{ + u32 prob_drop; /* Early probability drops */ + u32 prob_mark; /* Early probability marks */ + u32 forced_drop; /* Forced drops, qavg > max_thresh */ + u32 forced_mark; /* Forced marks, qavg > max_thresh */ + u32 pdrop; /* Drops due to queue limits */ + u32 other; /* Drops due to drop() calls */ + u32 backlog; +}; + +struct red_parms +{ + /* Parameters */ + u32 qth_min; /* Min avg length threshold: A scaled */ + u32 qth_max; /* Max avg length threshold: A scaled */ + u32 Scell_max; + u32 Rmask; /* Cached random mask, see red_rmask */ + u8 Scell_log; + u8 Wlog; /* log(W) */ + u8 Plog; /* random number bits */ + u8 Stab[RED_STAB_SIZE]; + + /* Variables */ + int qcount; /* Number of packets since last random + number generation */ + u32 qR; /* Cached random number */ + + unsigned long qavg; /* Average queue length: A scaled */ + psched_time_t qidlestart; /* Start of current idle period */ +}; + +static inline u32 red_rmask(u8 Plog) +{ + return Plog < 32 ? ((1 << Plog) - 1) : ~0UL; +} + +static inline void red_set_parms(struct red_parms *p, + u32 qth_min, u32 qth_max, u8 Wlog, u8 Plog, + u8 Scell_log, u8 *stab) +{ + /* Reset average queue length, the value is strictly bound + * to the parameters below, reseting hurts a bit but leaving + * it might result in an unreasonable qavg for a while. --TGR + */ + p->qavg = 0; + + p->qcount = -1; + p->qth_min = qth_min << Wlog; + p->qth_max = qth_max << Wlog; + p->Wlog = Wlog; + p->Plog = Plog; + p->Rmask = red_rmask(Plog); + p->Scell_log = Scell_log; + p->Scell_max = (255 << Scell_log); + + memcpy(p->Stab, stab, sizeof(p->Stab)); +} + +static inline int red_is_idling(struct red_parms *p) +{ + return !PSCHED_IS_PASTPERFECT(p->qidlestart); +} + +static inline void red_start_of_idle_period(struct red_parms *p) +{ + PSCHED_GET_TIME(p->qidlestart); +} + +static inline void red_end_of_idle_period(struct red_parms *p) +{ + PSCHED_SET_PASTPERFECT(p->qidlestart); +} + +static inline void red_restart(struct red_parms *p) +{ + red_end_of_idle_period(p); + p->qavg = 0; + p->qcount = -1; +} + +static inline unsigned long red_calc_qavg_from_idle_time(struct red_parms *p) +{ + psched_time_t now; + long us_idle; + int shift; + + PSCHED_GET_TIME(now); + us_idle = PSCHED_TDIFF_SAFE(now, p->qidlestart, p->Scell_max); + + /* + * The problem: ideally, average length queue recalcultion should + * be done over constant clock intervals. This is too expensive, so + * that the calculation is driven by outgoing packets. + * When the queue is idle we have to model this clock by hand. + * + * SF+VJ proposed to "generate": + * + * m = idletime / (average_pkt_size / bandwidth) + * + * dummy packets as a burst after idle time, i.e. + * + * p->qavg *= (1-W)^m + * + * This is an apparently overcomplicated solution (f.e. we have to + * precompute a table to make this calculation in reasonable time) + * I believe that a simpler model may be used here, + * but it is field for experiments. + */ + + shift = p->Stab[(us_idle >> p->Scell_log) & RED_STAB_MASK]; + + if (shift) + return p->qavg >> shift; + else { + /* Approximate initial part of exponent with linear function: + * + * (1-W)^m ~= 1-mW + ... + * + * Seems, it is the best solution to + * problem of too coarse exponent tabulation. + */ + us_idle = (p->qavg * us_idle) >> p->Scell_log; + + if (us_idle < (p->qavg >> 1)) + return p->qavg - us_idle; + else + return p->qavg >> 1; + } +} + +static inline unsigned long red_calc_qavg_no_idle_time(struct red_parms *p, + unsigned int backlog) +{ + /* + * NOTE: p->qavg is fixed point number with point at Wlog. + * The formula below is equvalent to floating point + * version: + * + * qavg = qavg*(1-W) + backlog*W; + * + * --ANK (980924) + */ + return p->qavg + (backlog - (p->qavg >> p->Wlog)); +} + +static inline unsigned long red_calc_qavg(struct red_parms *p, + unsigned int backlog) +{ + if (!red_is_idling(p)) + return red_calc_qavg_no_idle_time(p, backlog); + else + return red_calc_qavg_from_idle_time(p); +} + +static inline u32 red_random(struct red_parms *p) +{ + return net_random() & p->Rmask; +} + +static inline int red_mark_probability(struct red_parms *p, unsigned long qavg) +{ + /* The formula used below causes questions. + + OK. qR is random number in the interval 0..Rmask + i.e. 0..(2^Plog). If we used floating point + arithmetics, it would be: (2^Plog)*rnd_num, + where rnd_num is less 1. + + Taking into account, that qavg have fixed + point at Wlog, and Plog is related to max_P by + max_P = (qth_max-qth_min)/2^Plog; two lines + below have the following floating point equivalent: + + max_P*(qavg - qth_min)/(qth_max-qth_min) < rnd/qcount + + Any questions? --ANK (980924) + */ + return !(((qavg - p->qth_min) >> p->Wlog) * p->qcount < p->qR); +} + +enum { + RED_BELOW_MIN_THRESH, + RED_BETWEEN_TRESH, + RED_ABOVE_MAX_TRESH, +}; + +static inline int red_cmp_thresh(struct red_parms *p, unsigned long qavg) +{ + if (qavg < p->qth_min) + return RED_BELOW_MIN_THRESH; + else if (qavg >= p->qth_max) + return RED_ABOVE_MAX_TRESH; + else + return RED_BETWEEN_TRESH; +} + +enum { + RED_DONT_MARK, + RED_PROB_MARK, + RED_HARD_MARK, +}; + +static inline int red_action(struct red_parms *p, unsigned long qavg) +{ + switch (red_cmp_thresh(p, qavg)) { + case RED_BELOW_MIN_THRESH: + p->qcount = -1; + return RED_DONT_MARK; + + case RED_BETWEEN_TRESH: + if (++p->qcount) { + if (red_mark_probability(p, qavg)) { + p->qcount = 0; + p->qR = red_random(p); + return RED_PROB_MARK; + } + } else + p->qR = red_random(p); + + return RED_DONT_MARK; + + case RED_ABOVE_MAX_TRESH: + p->qcount = -1; + return RED_HARD_MARK; + } + + BUG(); + return RED_DONT_MARK; +} + +#endif diff --git a/include/net/sock.h b/include/net/sock.h index e0498bd360042121d99fa0aea7ec77b8ebb2a03b..ff13c4cc287add76e658418aaae91970c1c87f66 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -461,16 +461,16 @@ static inline void sk_stream_free_skb(struct sock *sk, struct sk_buff *skb) } /* The per-socket spinlock must be held here. */ -#define sk_add_backlog(__sk, __skb) \ -do { if (!(__sk)->sk_backlog.tail) { \ - (__sk)->sk_backlog.head = \ - (__sk)->sk_backlog.tail = (__skb); \ - } else { \ - ((__sk)->sk_backlog.tail)->next = (__skb); \ - (__sk)->sk_backlog.tail = (__skb); \ - } \ - (__skb)->next = NULL; \ -} while(0) +static inline void sk_add_backlog(struct sock *sk, struct sk_buff *skb) +{ + if (!sk->sk_backlog.tail) { + sk->sk_backlog.head = sk->sk_backlog.tail = skb; + } else { + sk->sk_backlog.tail->next = skb; + sk->sk_backlog.tail = skb; + } + skb->next = NULL; +} #define sk_wait_event(__sk, __timeo, __condition) \ ({ int rc; \ diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index d11f34832a972597dfa71890dde819dc24d8ad03..7f0ca79d6c98556ef9565a861e6ced9fec1a7507 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h @@ -387,15 +387,6 @@ #define AC97_RATES_MIC_ADC 4 #define AC97_RATES_SPDIF 5 -/* shared controllers */ -enum { - AC97_SHARED_TYPE_NONE, - AC97_SHARED_TYPE_ICH, - AC97_SHARED_TYPE_ATIIXP, - AC97_SHARED_TYPE_VIA, - AC97_SHARED_TYPES -}; - /* * */ @@ -468,7 +459,6 @@ struct _snd_ac97_bus { unsigned short used_slots[2][4]; /* actually used PCM slots */ unsigned short pcms_count; /* count of PCMs */ struct ac97_pcm *pcms; - unsigned int shared_type; /* type of shared controller betwen audio and modem */ ac97_t *codec[4]; snd_info_entry_t *proc; }; diff --git a/include/sound/core.h b/include/sound/core.h index 6d971a4c4ca00aaa0001a6cfc133f0ccbfa98491..2be65ad2fd835dbfa200bacf605fe9ddde00c235 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -29,7 +29,6 @@ #include /* pm_message_t */ /* Typedef's */ -typedef struct timespec snd_timestamp_t; typedef struct sndrv_interval snd_interval_t; typedef enum sndrv_card_type snd_card_type; typedef struct sndrv_xferi snd_xferi_t; @@ -256,6 +255,7 @@ typedef struct _snd_minor snd_minor_t; /* sound.c */ +extern int snd_major; extern int snd_ecards_limit; void snd_request_card(int card); @@ -285,39 +285,6 @@ int snd_oss_init_module(void); /* memory.c */ -#ifdef CONFIG_SND_DEBUG_MEMORY -void snd_memory_init(void); -void snd_memory_done(void); -int snd_memory_info_init(void); -int snd_memory_info_done(void); -void *snd_hidden_kmalloc(size_t size, gfp_t flags); -void *snd_hidden_kzalloc(size_t size, gfp_t flags); -void *snd_hidden_kcalloc(size_t n, size_t size, gfp_t flags); -void snd_hidden_kfree(const void *obj); -void *snd_hidden_vmalloc(unsigned long size); -void snd_hidden_vfree(void *obj); -char *snd_hidden_kstrdup(const char *s, gfp_t flags); -#define kmalloc(size, flags) snd_hidden_kmalloc(size, flags) -#define kzalloc(size, flags) snd_hidden_kzalloc(size, flags) -#define kcalloc(n, size, flags) snd_hidden_kcalloc(n, size, flags) -#define kfree(obj) snd_hidden_kfree(obj) -#define vmalloc(size) snd_hidden_vmalloc(size) -#define vfree(obj) snd_hidden_vfree(obj) -#define kmalloc_nocheck(size, flags) snd_wrapper_kmalloc(size, flags) -#define vmalloc_nocheck(size) snd_wrapper_vmalloc(size) -#define kfree_nocheck(obj) snd_wrapper_kfree(obj) -#define vfree_nocheck(obj) snd_wrapper_vfree(obj) -#define kstrdup(s, flags) snd_hidden_kstrdup(s, flags) -#else -#define snd_memory_init() /*NOP*/ -#define snd_memory_done() /*NOP*/ -#define snd_memory_info_init() /*NOP*/ -#define snd_memory_info_done() /*NOP*/ -#define kmalloc_nocheck(size, flags) kmalloc(size, flags) -#define vmalloc_nocheck(size) vmalloc(size) -#define kfree_nocheck(obj) kfree(obj) -#define vfree_nocheck(obj) vfree(obj) -#endif int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size_t count); int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size_t count); @@ -373,8 +340,9 @@ unsigned int snd_dma_pointer(unsigned long dma, unsigned int size); #endif /* misc.c */ +struct resource; +void release_and_free_resource(struct resource *res); -int snd_task_name(struct task_struct *task, char *name, size_t size); #ifdef CONFIG_SND_VERBOSE_PRINTK void snd_verbose_printk(const char *file, int line, const char *format, ...) __attribute__ ((format (printf, 3, 4))); @@ -429,34 +397,24 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...) * When CONFIG_SND_DEBUG is not set, the expression is executed but * not checked. */ -#define snd_assert(expr, args...) do {\ - if (unlikely(!(expr))) { \ - snd_printk(KERN_ERR "BUG? (%s) (called from %p)\n", __ASTRING__(expr), __builtin_return_address(0));\ - args;\ - }\ +#define snd_assert(expr, args...) do { \ + if (unlikely(!(expr))) { \ + snd_printk(KERN_ERR "BUG? (%s)\n", __ASTRING__(expr)); \ + dump_stack(); \ + args; \ + } \ } while (0) -/** - * snd_runtime_check - run-time assertion macro - * @expr: expression - * @args...: the action - * - * This macro checks the expression in run-time and invokes the commands - * given in the rest arguments if the assertion is failed. - * Unlike snd_assert(), the action commands are executed even if - * CONFIG_SND_DEBUG is not set but without any error messages. - */ -#define snd_runtime_check(expr, args...) do {\ - if (unlikely(!(expr))) { \ - snd_printk(KERN_ERR "ERROR (%s) (called from %p)\n", __ASTRING__(expr), __builtin_return_address(0));\ - args;\ - }\ + +#define snd_BUG() do { \ + snd_printk(KERN_ERR "BUG?\n"); \ + dump_stack(); \ } while (0) #else /* !CONFIG_SND_DEBUG */ #define snd_printd(fmt, args...) /* nothing */ #define snd_assert(expr, args...) (void)(expr) -#define snd_runtime_check(expr, args...) do { if (!(expr)) { args; } } while (0) +#define snd_BUG() /* nothing */ #endif /* CONFIG_SND_DEBUG */ @@ -473,30 +431,6 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...) #define snd_printdd(format, args...) /* nothing */ #endif -#define snd_BUG() snd_assert(0, ) - - -static inline void snd_timestamp_now(struct timespec *tstamp, int timespec) -{ - struct timeval val; - /* FIXME: use a linear time source */ - do_gettimeofday(&val); - tstamp->tv_sec = val.tv_sec; - tstamp->tv_nsec = val.tv_usec; - if (timespec) - tstamp->tv_nsec *= 1000L; -} - -static inline void snd_timestamp_zero(struct timespec *tstamp) -{ - tstamp->tv_sec = 0; - tstamp->tv_nsec = 0; -} - -static inline int snd_timestamp_null(struct timespec *tstamp) -{ - return tstamp->tv_sec == 0 && tstamp->tv_nsec == 0; -} #define SNDRV_OSS_VERSION ((3<<16)|(8<<8)|(1<<4)|(0)) /* 3.8.1a */ diff --git a/include/sound/driver.h b/include/sound/driver.h index 1ec2fae050a638914d98c72d0c1eaaec8073ccf8..3f0416ac24d95fe9d711165451028e7e85a38747 100644 --- a/include/sound/driver.h +++ b/include/sound/driver.h @@ -44,21 +44,4 @@ #include -/* - * ========================================================================== - */ - -#ifdef CONFIG_SND_DEBUG_MEMORY -#include -#include -void *snd_wrapper_kmalloc(size_t, gfp_t); -#undef kmalloc -void snd_wrapper_kfree(const void *); -#undef kfree -void *snd_wrapper_vmalloc(size_t); -#undef vmalloc -void snd_wrapper_vfree(void *); -#undef vfree -#endif - #endif /* __SOUND_DRIVER_H */ diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 46e3c0bf3c946bc0cead53cfdd8cb12ae9d791c4..8411c7ef6f1148249f599c22e1b106a623d2edb6 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -48,7 +48,8 @@ /* FIXME? - according to the OSS driver the EMU10K1 needs a 29 bit DMA mask */ #define EMU10K1_DMA_MASK 0x7fffffffUL /* 31bit */ -#define AUDIGY_DMA_MASK 0xffffffffUL /* 32bit */ +#define AUDIGY_DMA_MASK 0x7fffffffUL /* 31bit FIXME - 32 should work? */ + /* See ALSA bug #1276 - rlrevell */ #define TMEMSIZE 256*1024 #define TMEMSIZEREG 4 diff --git a/include/sound/minors.h b/include/sound/minors.h index b7b0d83094497b9d37c43c682bfe3ac457f542d0..a17b5c9961bb2246e62f59658922738108e962ca 100644 --- a/include/sound/minors.h +++ b/include/sound/minors.h @@ -27,8 +27,9 @@ #define SNDRV_MINOR(card, dev) (((card) << 5) | (dev)) #define SNDRV_MINOR_CONTROL 0 /* 0 - 0 */ -#define SNDRV_MINOR_SEQUENCER 1 -#define SNDRV_MINOR_TIMER (1+32) +#define SNDRV_MINOR_GLOBAL 1 /* 1 */ +#define SNDRV_MINOR_SEQUENCER (SNDRV_MINOR_GLOBAL + 0 * 32) +#define SNDRV_MINOR_TIMER (SNDRV_MINOR_GLOBAL + 1 * 32) #define SNDRV_MINOR_HWDEP 4 /* 4 - 7 */ #define SNDRV_MINOR_HWDEPS 4 #define SNDRV_MINOR_RAWMIDI 8 /* 8 - 15 */ @@ -39,12 +40,9 @@ #define SNDRV_DEVICE_TYPE_CONTROL SNDRV_MINOR_CONTROL #define SNDRV_DEVICE_TYPE_HWDEP SNDRV_MINOR_HWDEP -#define SNDRV_DEVICE_TYPE_MIXER SNDRV_MINOR_MIXER #define SNDRV_DEVICE_TYPE_RAWMIDI SNDRV_MINOR_RAWMIDI #define SNDRV_DEVICE_TYPE_PCM_PLAYBACK SNDRV_MINOR_PCM_PLAYBACK -#define SNDRV_DEVICE_TYPE_PCM_PLOOP SNDRV_MINOR_PCM_PLOOP #define SNDRV_DEVICE_TYPE_PCM_CAPTURE SNDRV_MINOR_PCM_CAPTURE -#define SNDRV_DEVICE_TYPE_PCM_CLOOP SNDRV_MINOR_PCM_CLOOP #define SNDRV_DEVICE_TYPE_SEQUENCER SNDRV_MINOR_SEQUENCER #define SNDRV_DEVICE_TYPE_TIMER SNDRV_MINOR_TIMER diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 2b23a596707114faf2315b9fef045890cab95550..acc4fa9d5abeae27188b5800fd90c6712e72222f 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -281,7 +281,7 @@ typedef struct { struct _snd_pcm_runtime { /* -- Status -- */ snd_pcm_substream_t *trigger_master; - snd_timestamp_t trigger_tstamp; /* trigger timestamp */ + struct timespec trigger_tstamp; /* trigger timestamp */ int overrange; snd_pcm_uframes_t avail_max; snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */ @@ -306,7 +306,6 @@ struct _snd_pcm_runtime { unsigned int rate_den; /* -- SW params -- */ - int tstamp_timespec; /* use timeval (0) or timespec (1) */ snd_pcm_tstamp_t tstamp_mode; /* mmap timestamp is updated */ unsigned int period_step; unsigned int sleep_min; /* min ticks to sleep */ diff --git a/include/sound/timer.h b/include/sound/timer.h index 1898511a0f389d53a61023d68d7ad2c2f0b8df9c..b55f38ae56e13ed3428f189a09a39a8ff4566cf0 100644 --- a/include/sound/timer.h +++ b/include/sound/timer.h @@ -88,6 +88,7 @@ struct _snd_timer_hardware { struct _snd_timer { snd_timer_class_t tmr_class; snd_card_t *card; + struct module *module; int tmr_device; int tmr_subdevice; char id[64]; diff --git a/include/sound/version.h b/include/sound/version.h index ee32af20dba9de068ac7ee2f680776664ac9dbc0..d1bd3b7239670952d0fca8cc23b9367280e24273 100644 --- a/include/sound/version.h +++ b/include/sound/version.h @@ -1,3 +1,3 @@ /* include/version.h. Generated by configure. */ -#define CONFIG_SND_VERSION "1.0.10rc1" -#define CONFIG_SND_DATE " (Mon Sep 12 08:13:09 2005 UTC)" +#define CONFIG_SND_VERSION "1.0.10rc3" +#define CONFIG_SND_DATE " (Mon Nov 07 13:30:21 2005 UTC)" diff --git a/init/Kconfig b/init/Kconfig index 3dcbd5bfd49843168d6b45f62d3ae5a7b8cfecdc..ea097e0a9c02964abbe421d5aaf3efc1459e4010 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -501,3 +501,7 @@ config STOP_MACHINE help Need stop_machine() primitive. endmenu + +menu "Block layer" +source "block/Kconfig" +endmenu diff --git a/ipc/mqueue.c b/ipc/mqueue.c index a0f18c9cc89df5983b16afc41c610e66391f5a0b..c8943b53d8e6c3620f5dd3237c34af6462e6740d 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -2,7 +2,7 @@ * POSIX message queues filesystem for Linux. * * Copyright (C) 2003,2004 Krzysztof Benedyczak (golbi@mat.uni.torun.pl) - * Michal Wronski (wrona@mat.uni.torun.pl) + * Michal Wronski (Michal.Wronski@motorola.com) * * Spinlocks: Mohamed Abbas (abbas.mohamed@intel.com) * Lockless receive & send, fd based notify: diff --git a/ipc/shm.c b/ipc/shm.c index b58c651d31ae23a36c58a1de3005e6b5d46a2662..587d836d80d9d07f075259d3efe73917413f8010 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -212,8 +212,16 @@ static int newseg (key_t key, int shmflg, size_t size) file = hugetlb_zero_setup(size); shp->mlock_user = current->user; } else { + int acctflag = VM_ACCOUNT; + /* + * Do not allow no accounting for OVERCOMMIT_NEVER, even + * if it's asked for. + */ + if ((shmflg & SHM_NORESERVE) && + sysctl_overcommit_memory != OVERCOMMIT_NEVER) + acctflag = 0; sprintf (name, "SYSV%08x", key); - file = shmem_file_setup(name, size, VM_ACCOUNT); + file = shmem_file_setup(name, size, acctflag); } error = PTR_ERR(file); if (IS_ERR(file)) diff --git a/ipc/util.c b/ipc/util.c index 10e836d0d89e86fb36de703364a0afdeb0f21c7e..23f1cec150c106dd7e0aa17e34699679c70e02dc 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -410,7 +410,8 @@ void ipc_rcu_getref(void *ptr) } /** - * ipc_schedule_free - free ipc + rcu space + * ipc_schedule_free - free ipc + rcu space + * @head: RCU callback structure for queued work * * Since RCU callback function is called in bh, * we need to defer the vfree to schedule_work @@ -427,10 +428,10 @@ static void ipc_schedule_free(struct rcu_head *head) } /** - * ipc_immediate_free - free ipc + rcu space - * - * Free from the RCU callback context + * ipc_immediate_free - free ipc + rcu space + * @head: RCU callback structure that contains pointer to be freed * + * Free from the RCU callback context */ static void ipc_immediate_free(struct rcu_head *head) { diff --git a/kernel/acct.c b/kernel/acct.c index 2e3f4a47e7d0578c6a7dc05f2296d1c6be8cc18d..6312d6bd43e3101648c7b5f3cbf9dc91e5a433bf 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include /* sector_div */ @@ -192,6 +193,7 @@ static void acct_file_reopen(struct file *file) add_timer(&acct_globals.timer); } if (old_acct) { + mnt_unpin(old_acct->f_vfsmnt); spin_unlock(&acct_globals.lock); do_acct_process(0, old_acct); filp_close(old_acct, NULL); @@ -199,6 +201,42 @@ static void acct_file_reopen(struct file *file) } } +static int acct_on(char *name) +{ + struct file *file; + int error; + + /* Difference from BSD - they don't do O_APPEND */ + file = filp_open(name, O_WRONLY|O_APPEND|O_LARGEFILE, 0); + if (IS_ERR(file)) + return PTR_ERR(file); + + if (!S_ISREG(file->f_dentry->d_inode->i_mode)) { + filp_close(file, NULL); + return -EACCES; + } + + if (!file->f_op->write) { + filp_close(file, NULL); + return -EIO; + } + + error = security_acct(file); + if (error) { + filp_close(file, NULL); + return error; + } + + spin_lock(&acct_globals.lock); + mnt_pin(file->f_vfsmnt); + acct_file_reopen(file); + spin_unlock(&acct_globals.lock); + + mntput(file->f_vfsmnt); /* it's pinned, now give up active reference */ + + return 0; +} + /** * sys_acct - enable/disable process accounting * @name: file name for accounting records or NULL to shutdown accounting @@ -212,47 +250,41 @@ static void acct_file_reopen(struct file *file) */ asmlinkage long sys_acct(const char __user *name) { - struct file *file = NULL; - char *tmp; int error; if (!capable(CAP_SYS_PACCT)) return -EPERM; if (name) { - tmp = getname(name); - if (IS_ERR(tmp)) { + char *tmp = getname(name); + if (IS_ERR(tmp)) return (PTR_ERR(tmp)); - } - /* Difference from BSD - they don't do O_APPEND */ - file = filp_open(tmp, O_WRONLY|O_APPEND|O_LARGEFILE, 0); + error = acct_on(tmp); putname(tmp); - if (IS_ERR(file)) { - return (PTR_ERR(file)); - } - if (!S_ISREG(file->f_dentry->d_inode->i_mode)) { - filp_close(file, NULL); - return (-EACCES); - } - - if (!file->f_op->write) { - filp_close(file, NULL); - return (-EIO); + } else { + error = security_acct(NULL); + if (!error) { + spin_lock(&acct_globals.lock); + acct_file_reopen(NULL); + spin_unlock(&acct_globals.lock); } } + return error; +} - error = security_acct(file); - if (error) { - if (file) - filp_close(file, NULL); - return error; - } - +/** + * acct_auto_close - turn off a filesystem's accounting if it is on + * @m: vfsmount being shut down + * + * If the accounting is turned on for a file in the subtree pointed to + * to by m, turn accounting off. Done when m is about to die. + */ +void acct_auto_close_mnt(struct vfsmount *m) +{ spin_lock(&acct_globals.lock); - acct_file_reopen(file); + if (acct_globals.file && acct_globals.file->f_vfsmnt == m) + acct_file_reopen(NULL); spin_unlock(&acct_globals.lock); - - return (0); } /** @@ -266,8 +298,8 @@ void acct_auto_close(struct super_block *sb) { spin_lock(&acct_globals.lock); if (acct_globals.file && - acct_globals.file->f_dentry->d_inode->i_sb == sb) { - acct_file_reopen((struct file *)NULL); + acct_globals.file->f_vfsmnt->mnt_sb == sb) { + acct_file_reopen(NULL); } spin_unlock(&acct_globals.lock); } diff --git a/kernel/exit.c b/kernel/exit.c index 537394b25e8d9a6d1e108ae0f78cbb3fab317769..452a1d1161782130204c934542aa2cb7f5f44b25 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -863,6 +864,7 @@ fastcall NORET_TYPE void do_exit(long code) module_put(tsk->binfmt->module); tsk->exit_code = code; + proc_exit_connector(tsk); exit_notify(tsk); #ifdef CONFIG_NUMA mpol_free(tsk->mempolicy); diff --git a/kernel/fork.c b/kernel/fork.c index 8a069612eac39e285afc9bc9314311e5980ef536..158710d22566006a36e6fbfb2583641eea24369e 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -469,13 +470,6 @@ static int copy_mm(unsigned long clone_flags, struct task_struct * tsk) if (clone_flags & CLONE_VM) { atomic_inc(&oldmm->mm_users); mm = oldmm; - /* - * There are cases where the PTL is held to ensure no - * new threads start up in user mode using an mm, which - * allows optimizing out ipis; the tlb_gather_mmu code - * is an example. - */ - spin_unlock_wait(&oldmm->page_table_lock); goto good_mm; } @@ -1143,6 +1137,7 @@ static task_t *copy_process(unsigned long clone_flags, __get_cpu_var(process_counts)++; } + proc_fork_connector(p); if (!current->signal->tty && p->signal->tty) p->signal->tty = NULL; diff --git a/kernel/futex.c b/kernel/futex.c index 3b4d5ad44cc6eb182a6bece56d2574436762fe56..aca8d10704f675cbdf35267d49bb984669c49f44 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -365,6 +365,11 @@ static int futex_wake_op(unsigned long uaddr1, unsigned long uaddr2, int nr_wake if (bh1 != bh2) spin_unlock(&bh2->lock); + if (unlikely(op_ret != -EFAULT)) { + ret = op_ret; + goto out; + } + /* futex_atomic_op_inuser needs to both read and write * *(int __user *)uaddr2, but we can't modify it * non-atomically. Therefore, if get_user below is not diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 1cfdb08ddf2054f6f219d28c78b97828e2f8b447..3bd7226d15fa10b5c4d6183506cff3368d4b7dfd 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -24,6 +24,7 @@ cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS]; /** * synchronize_irq - wait for pending IRQ handlers (on other CPUs) + * @irq: interrupt number to wait for * * This function waits for any pending IRQ handlers for this interrupt * to complete before returning. If you use this function while diff --git a/kernel/kprobes.c b/kernel/kprobes.c index ce4915dd683a3f35b120a31e1b1a356beb2fb94c..5beda378cc7518b353dc5f0551c636d8dd81b02a 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -32,7 +32,6 @@ * added function-return probes. */ #include -#include #include #include #include @@ -49,9 +48,9 @@ static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE]; static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE]; -unsigned int kprobe_cpu = NR_CPUS; -static DEFINE_SPINLOCK(kprobe_lock); -static struct kprobe *curr_kprobe; +static DEFINE_SPINLOCK(kprobe_lock); /* Protects kprobe_table */ +DEFINE_SPINLOCK(kretprobe_lock); /* Protects kretprobe_inst_table */ +static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL; /* * kprobe->ainsn.insn points to the copy of the instruction to be @@ -153,50 +152,31 @@ void __kprobes free_insn_slot(kprobe_opcode_t *slot) } } -/* Locks kprobe: irqs must be disabled */ -void __kprobes lock_kprobes(void) +/* We have preemption disabled.. so it is safe to use __ versions */ +static inline void set_kprobe_instance(struct kprobe *kp) { - unsigned long flags = 0; - - /* Avoiding local interrupts to happen right after we take the kprobe_lock - * and before we get a chance to update kprobe_cpu, this to prevent - * deadlock when we have a kprobe on ISR routine and a kprobe on task - * routine - */ - local_irq_save(flags); - - spin_lock(&kprobe_lock); - kprobe_cpu = smp_processor_id(); - - local_irq_restore(flags); + __get_cpu_var(kprobe_instance) = kp; } -void __kprobes unlock_kprobes(void) +static inline void reset_kprobe_instance(void) { - unsigned long flags = 0; - - /* Avoiding local interrupts to happen right after we update - * kprobe_cpu and before we get a a chance to release kprobe_lock, - * this to prevent deadlock when we have a kprobe on ISR routine and - * a kprobe on task routine - */ - local_irq_save(flags); - - kprobe_cpu = NR_CPUS; - spin_unlock(&kprobe_lock); - - local_irq_restore(flags); + __get_cpu_var(kprobe_instance) = NULL; } -/* You have to be holding the kprobe_lock */ +/* + * This routine is called either: + * - under the kprobe_lock spinlock - during kprobe_[un]register() + * OR + * - with preemption disabled - from arch/xxx/kernel/kprobes.c + */ struct kprobe __kprobes *get_kprobe(void *addr) { struct hlist_head *head; struct hlist_node *node; + struct kprobe *p; head = &kprobe_table[hash_ptr(addr, KPROBE_HASH_BITS)]; - hlist_for_each(node, head) { - struct kprobe *p = hlist_entry(node, struct kprobe, hlist); + hlist_for_each_entry_rcu(p, node, head, hlist) { if (p->addr == addr) return p; } @@ -211,13 +191,13 @@ static int __kprobes aggr_pre_handler(struct kprobe *p, struct pt_regs *regs) { struct kprobe *kp; - list_for_each_entry(kp, &p->list, list) { + list_for_each_entry_rcu(kp, &p->list, list) { if (kp->pre_handler) { - curr_kprobe = kp; + set_kprobe_instance(kp); if (kp->pre_handler(kp, regs)) return 1; } - curr_kprobe = NULL; + reset_kprobe_instance(); } return 0; } @@ -227,11 +207,11 @@ static void __kprobes aggr_post_handler(struct kprobe *p, struct pt_regs *regs, { struct kprobe *kp; - list_for_each_entry(kp, &p->list, list) { + list_for_each_entry_rcu(kp, &p->list, list) { if (kp->post_handler) { - curr_kprobe = kp; + set_kprobe_instance(kp); kp->post_handler(kp, regs, flags); - curr_kprobe = NULL; + reset_kprobe_instance(); } } return; @@ -240,12 +220,14 @@ static void __kprobes aggr_post_handler(struct kprobe *p, struct pt_regs *regs, static int __kprobes aggr_fault_handler(struct kprobe *p, struct pt_regs *regs, int trapnr) { + struct kprobe *cur = __get_cpu_var(kprobe_instance); + /* * if we faulted "during" the execution of a user specified * probe handler, invoke just that probe's fault handler */ - if (curr_kprobe && curr_kprobe->fault_handler) { - if (curr_kprobe->fault_handler(curr_kprobe, regs, trapnr)) + if (cur && cur->fault_handler) { + if (cur->fault_handler(cur, regs, trapnr)) return 1; } return 0; @@ -253,17 +235,18 @@ static int __kprobes aggr_fault_handler(struct kprobe *p, struct pt_regs *regs, static int __kprobes aggr_break_handler(struct kprobe *p, struct pt_regs *regs) { - struct kprobe *kp = curr_kprobe; - if (curr_kprobe && kp->break_handler) { - if (kp->break_handler(kp, regs)) { - curr_kprobe = NULL; - return 1; - } + struct kprobe *cur = __get_cpu_var(kprobe_instance); + int ret = 0; + + if (cur && cur->break_handler) { + if (cur->break_handler(cur, regs)) + ret = 1; } - curr_kprobe = NULL; - return 0; + reset_kprobe_instance(); + return ret; } +/* Called with kretprobe_lock held */ struct kretprobe_instance __kprobes *get_free_rp_inst(struct kretprobe *rp) { struct hlist_node *node; @@ -273,6 +256,7 @@ struct kretprobe_instance __kprobes *get_free_rp_inst(struct kretprobe *rp) return NULL; } +/* Called with kretprobe_lock held */ static struct kretprobe_instance __kprobes *get_used_rp_inst(struct kretprobe *rp) { @@ -283,6 +267,7 @@ static struct kretprobe_instance __kprobes *get_used_rp_inst(struct kretprobe return NULL; } +/* Called with kretprobe_lock held */ void __kprobes add_rp_inst(struct kretprobe_instance *ri) { /* @@ -301,6 +286,7 @@ void __kprobes add_rp_inst(struct kretprobe_instance *ri) hlist_add_head(&ri->uflist, &ri->rp->used_instances); } +/* Called with kretprobe_lock held */ void __kprobes recycle_rp_inst(struct kretprobe_instance *ri) { /* remove rp inst off the rprobe_inst_table */ @@ -334,13 +320,13 @@ void __kprobes kprobe_flush_task(struct task_struct *tk) struct hlist_node *node, *tmp; unsigned long flags = 0; - spin_lock_irqsave(&kprobe_lock, flags); + spin_lock_irqsave(&kretprobe_lock, flags); head = kretprobe_inst_table_head(current); hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { if (ri->task == tk) recycle_rp_inst(ri); } - spin_unlock_irqrestore(&kprobe_lock, flags); + spin_unlock_irqrestore(&kretprobe_lock, flags); } /* @@ -351,9 +337,12 @@ static int __kprobes pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs) { struct kretprobe *rp = container_of(p, struct kretprobe, kp); + unsigned long flags = 0; /*TODO: consider to only swap the RA after the last pre_handler fired */ + spin_lock_irqsave(&kretprobe_lock, flags); arch_prepare_kretprobe(rp, regs); + spin_unlock_irqrestore(&kretprobe_lock, flags); return 0; } @@ -384,13 +373,13 @@ static int __kprobes add_new_kprobe(struct kprobe *old_p, struct kprobe *p) struct kprobe *kp; if (p->break_handler) { - list_for_each_entry(kp, &old_p->list, list) { + list_for_each_entry_rcu(kp, &old_p->list, list) { if (kp->break_handler) return -EEXIST; } - list_add_tail(&p->list, &old_p->list); + list_add_tail_rcu(&p->list, &old_p->list); } else - list_add(&p->list, &old_p->list); + list_add_rcu(&p->list, &old_p->list); return 0; } @@ -408,18 +397,18 @@ static inline void add_aggr_kprobe(struct kprobe *ap, struct kprobe *p) ap->break_handler = aggr_break_handler; INIT_LIST_HEAD(&ap->list); - list_add(&p->list, &ap->list); + list_add_rcu(&p->list, &ap->list); INIT_HLIST_NODE(&ap->hlist); - hlist_del(&p->hlist); - hlist_add_head(&ap->hlist, + hlist_del_rcu(&p->hlist); + hlist_add_head_rcu(&ap->hlist, &kprobe_table[hash_ptr(ap->addr, KPROBE_HASH_BITS)]); } /* * This is the second or subsequent kprobe at the address - handle * the intricacies - * TODO: Move kcalloc outside the spinlock + * TODO: Move kcalloc outside the spin_lock */ static int __kprobes register_aggr_kprobe(struct kprobe *old_p, struct kprobe *p) @@ -445,7 +434,7 @@ static int __kprobes register_aggr_kprobe(struct kprobe *old_p, static inline void cleanup_kprobe(struct kprobe *p, unsigned long flags) { arch_disarm_kprobe(p); - hlist_del(&p->hlist); + hlist_del_rcu(&p->hlist); spin_unlock_irqrestore(&kprobe_lock, flags); arch_remove_kprobe(p); } @@ -453,11 +442,10 @@ static inline void cleanup_kprobe(struct kprobe *p, unsigned long flags) static inline void cleanup_aggr_kprobe(struct kprobe *old_p, struct kprobe *p, unsigned long flags) { - list_del(&p->list); - if (list_empty(&old_p->list)) { + list_del_rcu(&p->list); + if (list_empty(&old_p->list)) cleanup_kprobe(old_p, flags); - kfree(old_p); - } else + else spin_unlock_irqrestore(&kprobe_lock, flags); } @@ -480,9 +468,9 @@ int __kprobes register_kprobe(struct kprobe *p) if ((ret = arch_prepare_kprobe(p)) != 0) goto rm_kprobe; + p->nmissed = 0; spin_lock_irqsave(&kprobe_lock, flags); old_p = get_kprobe(p->addr); - p->nmissed = 0; if (old_p) { ret = register_aggr_kprobe(old_p, p); goto out; @@ -490,7 +478,7 @@ int __kprobes register_kprobe(struct kprobe *p) arch_copy_kprobe(p); INIT_HLIST_NODE(&p->hlist); - hlist_add_head(&p->hlist, + hlist_add_head_rcu(&p->hlist, &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]); arch_arm_kprobe(p); @@ -511,10 +499,16 @@ void __kprobes unregister_kprobe(struct kprobe *p) spin_lock_irqsave(&kprobe_lock, flags); old_p = get_kprobe(p->addr); if (old_p) { + /* cleanup_*_kprobe() does the spin_unlock_irqrestore */ if (old_p->pre_handler == aggr_pre_handler) cleanup_aggr_kprobe(old_p, p, flags); else cleanup_kprobe(p, flags); + + synchronize_sched(); + if (old_p->pre_handler == aggr_pre_handler && + list_empty(&old_p->list)) + kfree(old_p); } else spin_unlock_irqrestore(&kprobe_lock, flags); } @@ -591,13 +585,13 @@ void __kprobes unregister_kretprobe(struct kretprobe *rp) unregister_kprobe(&rp->kp); /* No race here */ - spin_lock_irqsave(&kprobe_lock, flags); + spin_lock_irqsave(&kretprobe_lock, flags); free_rp_inst(rp); while ((ri = get_used_rp_inst(rp)) != NULL) { ri->rp = NULL; hlist_del(&ri->uflist); } - spin_unlock_irqrestore(&kprobe_lock, flags); + spin_unlock_irqrestore(&kretprobe_lock, flags); } static int __init init_kprobes(void) diff --git a/kernel/module.c b/kernel/module.c index ff5c500ab625202ef8401998bc0a71cac53424aa..2ea929d51ad08dc49e515d02bce7414c6cfdddbe 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c index 91a8942649413f48916196f4aed68deed9a1ae2b..84af54c39e1b0c31ff32854b45cbb15a512a4ba5 100644 --- a/kernel/posix-cpu-timers.c +++ b/kernel/posix-cpu-timers.c @@ -497,7 +497,7 @@ static void process_timer_rebalance(struct task_struct *p, left = cputime_div(cputime_sub(expires.cpu, val.cpu), nthreads); do { - if (!unlikely(t->flags & PF_EXITING)) { + if (likely(!(t->flags & PF_EXITING))) { ticks = cputime_add(prof_ticks(t), left); if (cputime_eq(t->it_prof_expires, cputime_zero) || @@ -512,7 +512,7 @@ static void process_timer_rebalance(struct task_struct *p, left = cputime_div(cputime_sub(expires.cpu, val.cpu), nthreads); do { - if (!unlikely(t->flags & PF_EXITING)) { + if (likely(!(t->flags & PF_EXITING))) { ticks = cputime_add(virt_ticks(t), left); if (cputime_eq(t->it_virt_expires, cputime_zero) || @@ -527,7 +527,7 @@ static void process_timer_rebalance(struct task_struct *p, nsleft = expires.sched - val.sched; do_div(nsleft, nthreads); do { - if (!unlikely(t->flags & PF_EXITING)) { + if (likely(!(t->flags & PF_EXITING))) { ns = t->sched_time + nsleft; if (t->it_sched_expires == 0 || t->it_sched_expires > ns) { diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 42a6287043983e93a67d54d5168c56df62a2e51c..723f5179883e57d054d13bbb53bf2854b70e1b00 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -168,9 +168,8 @@ static unsigned count_data_pages(void) { struct zone *zone; unsigned long zone_pfn; - unsigned n; + unsigned int n = 0; - n = 0; for_each_zone (zone) { if (is_highmem(zone)) continue; @@ -250,10 +249,10 @@ static inline void fill_pb_page(struct pbe *pbpage) * of memory pages allocated with alloc_pagedir() */ -void create_pbe_list(struct pbe *pblist, unsigned nr_pages) +void create_pbe_list(struct pbe *pblist, unsigned int nr_pages) { struct pbe *pbpage, *p; - unsigned num = PBES_PER_PAGE; + unsigned int num = PBES_PER_PAGE; for_each_pb_page (pbpage, pblist) { if (num >= nr_pages) @@ -293,9 +292,9 @@ static void *alloc_image_page(void) * On each page we set up a list of struct_pbe elements. */ -struct pbe *alloc_pagedir(unsigned nr_pages) +struct pbe *alloc_pagedir(unsigned int nr_pages) { - unsigned num; + unsigned int num; struct pbe *pblist, *pbe; if (!nr_pages) @@ -329,7 +328,7 @@ void swsusp_free(void) for_each_zone(zone) { for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) if (pfn_valid(zone_pfn + zone->zone_start_pfn)) { - struct page * page; + struct page *page; page = pfn_to_page(zone_pfn + zone->zone_start_pfn); if (PageNosave(page) && PageNosaveFree(page)) { ClearPageNosave(page); @@ -348,7 +347,7 @@ void swsusp_free(void) * free pages. */ -static int enough_free_mem(unsigned nr_pages) +static int enough_free_mem(unsigned int nr_pages) { pr_debug("swsusp: available memory: %u pages\n", nr_free_pages()); return nr_free_pages() > (nr_pages + PAGES_FOR_IO + @@ -356,7 +355,7 @@ static int enough_free_mem(unsigned nr_pages) } -static struct pbe *swsusp_alloc(unsigned nr_pages) +static struct pbe *swsusp_alloc(unsigned int nr_pages) { struct pbe *pblist, *p; @@ -380,7 +379,7 @@ static struct pbe *swsusp_alloc(unsigned nr_pages) asmlinkage int swsusp_save(void) { - unsigned nr_pages; + unsigned int nr_pages; pr_debug("swsusp: critical section: \n"); if (save_highmem()) { diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index 12db1d2ad61f89e5667f21f339b2bd9c3fd3969f..e1ab28b9b2176fe14c364fb00485e9d0c2067900 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c @@ -85,18 +85,11 @@ unsigned int nr_copy_pages __nosavedata = 0; /* Suspend pagedir is allocated before final copy, therefore it must be freed after resume - Warning: this is evil. There are actually two pagedirs at time of - resume. One is "pagedir_save", which is empty frame allocated at - time of suspend, that must be freed. Second is "pagedir_nosave", - allocated at time of resume, that travels through memory not to - collide with anything. - Warning: this is even more evil than it seems. Pagedirs this file talks about are completely different from page directories used by MMU hardware. */ suspend_pagedir_t *pagedir_nosave __nosavedata = NULL; -suspend_pagedir_t *pagedir_save; #define SWSUSP_SIG "S1SUSPEND" @@ -122,8 +115,8 @@ static struct swsusp_info swsusp_info; static unsigned short swapfile_used[MAX_SWAPFILES]; static unsigned short root_swap; -static int write_page(unsigned long addr, swp_entry_t * loc); -static int bio_read_page(pgoff_t page_off, void * page); +static int write_page(unsigned long addr, swp_entry_t *loc); +static int bio_read_page(pgoff_t page_off, void *page); static u8 key_iv[MAXKEY+MAXIV]; @@ -355,7 +348,7 @@ static void lock_swapdevices(void) * This is a partial improvement, since we will at least return other * errors, though we need to eventually fix the damn code. */ -static int write_page(unsigned long addr, swp_entry_t * loc) +static int write_page(unsigned long addr, swp_entry_t *loc) { swp_entry_t entry; int error = 0; @@ -383,9 +376,9 @@ static int write_page(unsigned long addr, swp_entry_t * loc) static void data_free(void) { swp_entry_t entry; - struct pbe * p; + struct pbe *p; - for_each_pbe(p, pagedir_nosave) { + for_each_pbe (p, pagedir_nosave) { entry = p->swap_address; if (entry.val) swap_free(entry); @@ -492,8 +485,8 @@ static void free_pagedir_entries(void) static int write_pagedir(void) { int error = 0; - unsigned n = 0; - struct pbe * pbe; + unsigned int n = 0; + struct pbe *pbe; printk( "Writing pagedir..."); for_each_pb_page (pbe, pagedir_nosave) { @@ -543,7 +536,7 @@ static int write_suspend_image(void) * We should only consider resume_device. */ -int enough_swap(unsigned nr_pages) +int enough_swap(unsigned int nr_pages) { struct sysinfo i; @@ -694,7 +687,7 @@ static int check_pagedir(struct pbe *pblist) * restore from the loaded pages later. We relocate them here. */ -static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist) +static struct pbe *swsusp_pagedir_relocate(struct pbe *pblist) { struct zone *zone; unsigned long zone_pfn; @@ -770,7 +763,7 @@ static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist) static atomic_t io_done = ATOMIC_INIT(0); -static int end_io(struct bio * bio, unsigned int num, int err) +static int end_io(struct bio *bio, unsigned int num, int err) { if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) panic("I/O error reading memory image"); @@ -778,7 +771,7 @@ static int end_io(struct bio * bio, unsigned int num, int err) return 0; } -static struct block_device * resume_bdev; +static struct block_device *resume_bdev; /** * submit - submit BIO request. @@ -791,10 +784,10 @@ static struct block_device * resume_bdev; * Then submit it and wait. */ -static int submit(int rw, pgoff_t page_off, void * page) +static int submit(int rw, pgoff_t page_off, void *page) { int error = 0; - struct bio * bio; + struct bio *bio; bio = bio_alloc(GFP_ATOMIC, 1); if (!bio) @@ -823,12 +816,12 @@ static int submit(int rw, pgoff_t page_off, void * page) return error; } -static int bio_read_page(pgoff_t page_off, void * page) +static int bio_read_page(pgoff_t page_off, void *page) { return submit(READ, page_off, page); } -static int bio_write_page(pgoff_t page_off, void * page) +static int bio_write_page(pgoff_t page_off, void *page) { return submit(WRITE, page_off, page); } @@ -838,7 +831,7 @@ static int bio_write_page(pgoff_t page_off, void * page) * I really don't think that it's foolproof but more than nothing.. */ -static const char * sanity_check(void) +static const char *sanity_check(void) { dump_info(); if (swsusp_info.version_code != LINUX_VERSION_CODE) @@ -864,7 +857,7 @@ static const char * sanity_check(void) static int check_header(void) { - const char * reason = NULL; + const char *reason = NULL; int error; if ((error = bio_read_page(swp_offset(swsusp_header.swsusp_info), &swsusp_info))) @@ -912,7 +905,7 @@ static int check_sig(void) static int data_read(struct pbe *pblist) { - struct pbe * p; + struct pbe *p; int error = 0; int i = 0; int mod = swsusp_info.image_pages / 100; @@ -950,7 +943,7 @@ static int data_read(struct pbe *pblist) static int read_pagedir(struct pbe *pblist) { struct pbe *pbpage, *p; - unsigned i = 0; + unsigned int i = 0; int error; if (!pblist) diff --git a/kernel/printk.c b/kernel/printk.c index 3cb9708209bcb94a9d30a4c807f760ae485bf0c4..e9be027bc9300d03322a7ecf5681bdb2dec69f4b 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -806,7 +806,6 @@ void console_unblank(void) c->unblank(); release_console_sem(); } -EXPORT_SYMBOL(console_unblank); /* * Return the console tty driver structure and its associated index diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 863eee8bff4763d949489d17bdfd9cef33cbca6c..5b8dd98a230e442c1ec46adc968acb60dfdb74ae 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -406,3 +406,85 @@ int ptrace_request(struct task_struct *child, long request, return ret; } + +#ifndef __ARCH_SYS_PTRACE +static int ptrace_get_task_struct(long request, long pid, + struct task_struct **childp) +{ + struct task_struct *child; + int ret; + + /* + * Callers use child == NULL as an indication to exit early even + * when the return value is 0, so make sure it is non-NULL here. + */ + *childp = NULL; + + if (request == PTRACE_TRACEME) { + /* + * Are we already being traced? + */ + if (current->ptrace & PT_PTRACED) + return -EPERM; + ret = security_ptrace(current->parent, current); + if (ret) + return -EPERM; + /* + * Set the ptrace bit in the process ptrace flags. + */ + current->ptrace |= PT_PTRACED; + return 0; + } + + /* + * You may not mess with init + */ + if (pid == 1) + return -EPERM; + + ret = -ESRCH; + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + if (child) + get_task_struct(child); + read_unlock(&tasklist_lock); + if (!child) + return -ESRCH; + + *childp = child; + return 0; +} + +asmlinkage long sys_ptrace(long request, long pid, long addr, long data) +{ + struct task_struct *child; + long ret; + + /* + * This lock_kernel fixes a subtle race with suid exec + */ + lock_kernel(); + ret = ptrace_get_task_struct(request, pid, &child); + if (!child) + goto out; + + if (request == PTRACE_ATTACH) { + ret = ptrace_attach(child); + goto out; + } + + ret = ptrace_check_attach(child, request == PTRACE_KILL); + if (ret < 0) + goto out_put_task_struct; + + ret = arch_ptrace(child, request, addr, data); + if (ret < 0) + goto out_put_task_struct; + + out_put_task_struct: + put_task_struct(child); + out: + unlock_kernel(); + return ret; +} +#endif /* __ARCH_SYS_PTRACE */ diff --git a/kernel/sched.c b/kernel/sched.c index b4f4eb6135372d258d51ded475ff68c5517c2614..3ce26954be1284e4f74abf0c5ca602f6d46dbef0 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -3563,8 +3563,6 @@ int idle_cpu(int cpu) return cpu_curr(cpu) == cpu_rq(cpu)->idle; } -EXPORT_SYMBOL_GPL(idle_cpu); - /** * idle_task - return the idle task for a given cpu. * @cpu: the processor in question. @@ -4680,7 +4678,8 @@ static int migration_call(struct notifier_block *nfb, unsigned long action, #ifdef CONFIG_HOTPLUG_CPU case CPU_UP_CANCELED: /* Unbind it from offline cpu so it can run. Fall thru. */ - kthread_bind(cpu_rq(cpu)->migration_thread,smp_processor_id()); + kthread_bind(cpu_rq(cpu)->migration_thread, + any_online_cpu(cpu_online_map)); kthread_stop(cpu_rq(cpu)->migration_thread); cpu_rq(cpu)->migration_thread = NULL; break; diff --git a/kernel/softirq.c b/kernel/softirq.c index f766b2fc48be8cd54cc254c91660ec414603a2c5..ad3295cdded55032f248bf53dc6b908c56702581 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -470,7 +470,8 @@ static int __devinit cpu_callback(struct notifier_block *nfb, #ifdef CONFIG_HOTPLUG_CPU case CPU_UP_CANCELED: /* Unbind so it can run. Fall thru. */ - kthread_bind(per_cpu(ksoftirqd, hotcpu), smp_processor_id()); + kthread_bind(per_cpu(ksoftirqd, hotcpu), + any_online_cpu(cpu_online_map)); case CPU_DEAD: p = per_cpu(ksoftirqd, hotcpu); per_cpu(ksoftirqd, hotcpu) = NULL; diff --git a/kernel/softlockup.c b/kernel/softlockup.c index 75976209cea7dbf44549b2bfca079142accb45a4..a2dcceb9437d61561caf1f85b0099cd4cd9e262d 100644 --- a/kernel/softlockup.c +++ b/kernel/softlockup.c @@ -123,7 +123,8 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) #ifdef CONFIG_HOTPLUG_CPU case CPU_UP_CANCELED: /* Unbind so it can run. Fall thru. */ - kthread_bind(per_cpu(watchdog_task, hotcpu), smp_processor_id()); + kthread_bind(per_cpu(watchdog_task, hotcpu), + any_online_cpu(cpu_online_map)); case CPU_DEAD: p = per_cpu(watchdog_task, hotcpu); per_cpu(watchdog_task, hotcpu) = NULL; diff --git a/kernel/sys.c b/kernel/sys.c index 2fa1ed18123cb8c84f241d4a19e1ed9b2727574e..c43b3e22bbda5b215515ca54c1f359e5a776c896 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -375,18 +376,21 @@ void emergency_restart(void) } EXPORT_SYMBOL_GPL(emergency_restart); -/** - * kernel_restart - reboot the system - * - * Shutdown everything and perform a clean reboot. - * This is not safe to call in interrupt context. - */ void kernel_restart_prepare(char *cmd) { notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); system_state = SYSTEM_RESTART; device_shutdown(); } + +/** + * kernel_restart - reboot the system + * @cmd: pointer to buffer containing command to execute for restart + * or %NULL + * + * Shutdown everything and perform a clean reboot. + * This is not safe to call in interrupt context. + */ void kernel_restart(char *cmd) { kernel_restart_prepare(cmd); @@ -623,6 +627,7 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid) current->egid = new_egid; current->gid = new_rgid; key_fsgid_changed(current); + proc_id_connector(current, PROC_EVENT_GID); return 0; } @@ -662,6 +667,7 @@ asmlinkage long sys_setgid(gid_t gid) return -EPERM; key_fsgid_changed(current); + proc_id_connector(current, PROC_EVENT_GID); return 0; } @@ -751,6 +757,7 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) current->fsuid = current->euid; key_fsuid_changed(current); + proc_id_connector(current, PROC_EVENT_UID); return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE); } @@ -798,6 +805,7 @@ asmlinkage long sys_setuid(uid_t uid) current->suid = new_suid; key_fsuid_changed(current); + proc_id_connector(current, PROC_EVENT_UID); return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID); } @@ -846,6 +854,7 @@ asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) current->suid = suid; key_fsuid_changed(current); + proc_id_connector(current, PROC_EVENT_UID); return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES); } @@ -898,6 +907,7 @@ asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) current->sgid = sgid; key_fsgid_changed(current); + proc_id_connector(current, PROC_EVENT_GID); return 0; } @@ -940,6 +950,7 @@ asmlinkage long sys_setfsuid(uid_t uid) } key_fsuid_changed(current); + proc_id_connector(current, PROC_EVENT_UID); security_task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS); @@ -968,6 +979,7 @@ asmlinkage long sys_setfsgid(gid_t gid) } current->fsgid = gid; key_fsgid_changed(current); + proc_id_connector(current, PROC_EVENT_GID); } return old_fsgid; } @@ -1485,8 +1497,6 @@ EXPORT_SYMBOL(in_egroup_p); DECLARE_RWSEM(uts_sem); -EXPORT_SYMBOL(uts_sem); - asmlinkage long sys_newuname(struct new_utsname __user * name) { int errno = 0; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 8e56e2495542be41fa688aa7a15604cb2e3e6897..9990e10192e8e645c62d1e640b67b48edefe762d 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -169,7 +169,7 @@ struct file_operations proc_sys_file_operations = { extern struct proc_dir_entry *proc_sys_root; -static void register_proc_table(ctl_table *, struct proc_dir_entry *); +static void register_proc_table(ctl_table *, struct proc_dir_entry *, void *); static void unregister_proc_table(ctl_table *, struct proc_dir_entry *); #endif @@ -952,7 +952,7 @@ static ctl_table fs_table[] = { .data = &aio_nr, .maxlen = sizeof(aio_nr), .mode = 0444, - .proc_handler = &proc_dointvec, + .proc_handler = &proc_doulongvec_minmax, }, { .ctl_name = FS_AIO_MAX_NR, @@ -960,7 +960,7 @@ static ctl_table fs_table[] = { .data = &aio_max_nr, .maxlen = sizeof(aio_max_nr), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = &proc_doulongvec_minmax, }, #ifdef CONFIG_INOTIFY { @@ -992,10 +992,51 @@ static ctl_table dev_table[] = { extern void init_irq_proc (void); +static DEFINE_SPINLOCK(sysctl_lock); + +/* called under sysctl_lock */ +static int use_table(struct ctl_table_header *p) +{ + if (unlikely(p->unregistering)) + return 0; + p->used++; + return 1; +} + +/* called under sysctl_lock */ +static void unuse_table(struct ctl_table_header *p) +{ + if (!--p->used) + if (unlikely(p->unregistering)) + complete(p->unregistering); +} + +/* called under sysctl_lock, will reacquire if has to wait */ +static void start_unregistering(struct ctl_table_header *p) +{ + /* + * if p->used is 0, nobody will ever touch that entry again; + * we'll eliminate all paths to it before dropping sysctl_lock + */ + if (unlikely(p->used)) { + struct completion wait; + init_completion(&wait); + p->unregistering = &wait; + spin_unlock(&sysctl_lock); + wait_for_completion(&wait); + spin_lock(&sysctl_lock); + } + /* + * do not remove from the list until nobody holds it; walking the + * list in do_sysctl() relies on that. + */ + list_del_init(&p->ctl_entry); +} + void __init sysctl_init(void) { #ifdef CONFIG_PROC_FS - register_proc_table(root_table, proc_sys_root); + register_proc_table(root_table, proc_sys_root, &root_table_header); init_irq_proc(); #endif } @@ -1004,6 +1045,7 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol void __user *newval, size_t newlen) { struct list_head *tmp; + int error = -ENOTDIR; if (nlen <= 0 || nlen >= CTL_MAXNAME) return -ENOTDIR; @@ -1012,20 +1054,30 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol if (!oldlenp || get_user(old_len, oldlenp)) return -EFAULT; } + spin_lock(&sysctl_lock); tmp = &root_table_header.ctl_entry; do { struct ctl_table_header *head = list_entry(tmp, struct ctl_table_header, ctl_entry); void *context = NULL; - int error = parse_table(name, nlen, oldval, oldlenp, + + if (!use_table(head)) + continue; + + spin_unlock(&sysctl_lock); + + error = parse_table(name, nlen, oldval, oldlenp, newval, newlen, head->ctl_table, &context); kfree(context); + + spin_lock(&sysctl_lock); + unuse_table(head); if (error != -ENOTDIR) - return error; - tmp = tmp->next; - } while (tmp != &root_table_header.ctl_entry); - return -ENOTDIR; + break; + } while ((tmp = tmp->next) != &root_table_header.ctl_entry); + spin_unlock(&sysctl_lock); + return error; } asmlinkage long sys_sysctl(struct __sysctl_args __user *args) @@ -1236,12 +1288,16 @@ struct ctl_table_header *register_sysctl_table(ctl_table * table, return NULL; tmp->ctl_table = table; INIT_LIST_HEAD(&tmp->ctl_entry); + tmp->used = 0; + tmp->unregistering = NULL; + spin_lock(&sysctl_lock); if (insert_at_head) list_add(&tmp->ctl_entry, &root_table_header.ctl_entry); else list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry); + spin_unlock(&sysctl_lock); #ifdef CONFIG_PROC_FS - register_proc_table(table, proc_sys_root); + register_proc_table(table, proc_sys_root, tmp); #endif return tmp; } @@ -1255,10 +1311,13 @@ struct ctl_table_header *register_sysctl_table(ctl_table * table, */ void unregister_sysctl_table(struct ctl_table_header * header) { - list_del(&header->ctl_entry); + might_sleep(); + spin_lock(&sysctl_lock); + start_unregistering(header); #ifdef CONFIG_PROC_FS unregister_proc_table(header->ctl_table, proc_sys_root); #endif + spin_unlock(&sysctl_lock); kfree(header); } @@ -1269,7 +1328,7 @@ void unregister_sysctl_table(struct ctl_table_header * header) #ifdef CONFIG_PROC_FS /* Scan the sysctl entries in table and add them all into /proc */ -static void register_proc_table(ctl_table * table, struct proc_dir_entry *root) +static void register_proc_table(ctl_table * table, struct proc_dir_entry *root, void *set) { struct proc_dir_entry *de; int len; @@ -1305,13 +1364,14 @@ static void register_proc_table(ctl_table * table, struct proc_dir_entry *root) de = create_proc_entry(table->procname, mode, root); if (!de) continue; + de->set = set; de->data = (void *) table; if (table->proc_handler) de->proc_fops = &proc_sys_file_operations; } table->de = de; if (de->mode & S_IFDIR) - register_proc_table(table->child, de); + register_proc_table(table->child, de, set); } } @@ -1336,6 +1396,13 @@ static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root continue; } + /* + * In any case, mark the entry as goner; we'll keep it + * around if it's busy, but we'll know to do nothing with + * its fields. We are under sysctl_lock here. + */ + de->data = NULL; + /* Don't unregister proc entries that are still being used.. */ if (atomic_read(&de->count)) continue; @@ -1349,27 +1416,38 @@ static ssize_t do_rw_proc(int write, struct file * file, char __user * buf, size_t count, loff_t *ppos) { int op; - struct proc_dir_entry *de; + struct proc_dir_entry *de = PDE(file->f_dentry->d_inode); struct ctl_table *table; size_t res; - ssize_t error; - - de = PDE(file->f_dentry->d_inode); - if (!de || !de->data) - return -ENOTDIR; - table = (struct ctl_table *) de->data; - if (!table || !table->proc_handler) - return -ENOTDIR; - op = (write ? 002 : 004); - if (ctl_perm(table, op)) - return -EPERM; + ssize_t error = -ENOTDIR; - res = count; - - error = (*table->proc_handler) (table, write, file, buf, &res, ppos); - if (error) - return error; - return res; + spin_lock(&sysctl_lock); + if (de && de->data && use_table(de->set)) { + /* + * at that point we know that sysctl was not unregistered + * and won't be until we finish + */ + spin_unlock(&sysctl_lock); + table = (struct ctl_table *) de->data; + if (!table || !table->proc_handler) + goto out; + error = -EPERM; + op = (write ? 002 : 004); + if (ctl_perm(table, op)) + goto out; + + /* careful: calling conventions are nasty here */ + res = count; + error = (*table->proc_handler)(table, write, file, + buf, &res, ppos); + if (!error) + error = res; + out: + spin_lock(&sysctl_lock); + unuse_table(de->set); + } + spin_unlock(&sysctl_lock); + return error; } static int proc_opensys(struct inode *inode, struct file *file) @@ -1997,6 +2075,7 @@ int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp, * @filp: the file structure * @buffer: the user buffer * @lenp: the size of the user buffer + * @ppos: pointer to the file position * * Reads/writes up to table->maxlen/sizeof(unsigned int) integer * values from/to the user buffer, treated as an ASCII string. diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 7cee222231bc46843d7d5b68acbb82f375c1af71..42df83d7fad21d7176efdfef13282ef693f3c6ba 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -524,7 +524,7 @@ static int __devinit workqueue_cpu_callback(struct notifier_block *nfb, list_for_each_entry(wq, &workqueues, list) { /* Unbind so it can run. */ kthread_bind(per_cpu_ptr(wq->cpu_wq, hotcpu)->thread, - smp_processor_id()); + any_online_cpu(cpu_online_map)); cleanup_workqueue_thread(wq, hotcpu); } break; diff --git a/lib/radix-tree.c b/lib/radix-tree.c index d1c057e71b683db7328f1c8ef619e93866e486cf..88511c3805ad77fc9515b7a75bdc52e09a6393df 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -281,35 +281,60 @@ int radix_tree_insert(struct radix_tree_root *root, } EXPORT_SYMBOL(radix_tree_insert); -/** - * radix_tree_lookup - perform lookup operation on a radix tree - * @root: radix tree root - * @index: index key - * - * Lookup the item at the position @index in the radix tree @root. - */ -void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index) +static inline void **__lookup_slot(struct radix_tree_root *root, + unsigned long index) { unsigned int height, shift; - struct radix_tree_node *slot; + struct radix_tree_node **slot; height = root->height; if (index > radix_tree_maxindex(height)) return NULL; shift = (height-1) * RADIX_TREE_MAP_SHIFT; - slot = root->rnode; + slot = &root->rnode; while (height > 0) { - if (slot == NULL) + if (*slot == NULL) return NULL; - slot = slot->slots[(index >> shift) & RADIX_TREE_MAP_MASK]; + slot = (struct radix_tree_node **) + ((*slot)->slots + + ((index >> shift) & RADIX_TREE_MAP_MASK)); shift -= RADIX_TREE_MAP_SHIFT; height--; } - return slot; + return (void **)slot; +} + +/** + * radix_tree_lookup_slot - lookup a slot in a radix tree + * @root: radix tree root + * @index: index key + * + * Lookup the slot corresponding to the position @index in the radix tree + * @root. This is useful for update-if-exists operations. + */ +void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index) +{ + return __lookup_slot(root, index); +} +EXPORT_SYMBOL(radix_tree_lookup_slot); + +/** + * radix_tree_lookup - perform lookup operation on a radix tree + * @root: radix tree root + * @index: index key + * + * Lookup the item at the position @index in the radix tree @root. + */ +void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index) +{ + void **slot; + + slot = __lookup_slot(root, index); + return slot != NULL ? *slot : NULL; } EXPORT_SYMBOL(radix_tree_lookup); diff --git a/lib/reed_solomon/Makefile b/lib/reed_solomon/Makefile index 747a2de293465943d1e68cd233d0b07051360c90..c3d7136827edd9ec7d44b44a59ad3910b1a7d0e7 100644 --- a/lib/reed_solomon/Makefile +++ b/lib/reed_solomon/Makefile @@ -1,5 +1,5 @@ # -# This is a modified version of reed solomon lib, +# This is a modified version of reed solomon lib, # obj-$(CONFIG_REED_SOLOMON) += reed_solomon.o diff --git a/lib/reed_solomon/decode_rs.c b/lib/reed_solomon/decode_rs.c index d401decd62890ba52e135659e279b139fbe385ab..a58df56f09b6093f06a038f9a38675936ec3fa88 100644 --- a/lib/reed_solomon/decode_rs.c +++ b/lib/reed_solomon/decode_rs.c @@ -1,22 +1,22 @@ -/* +/* * lib/reed_solomon/decode_rs.c * * Overview: * Generic Reed Solomon encoder / decoder library - * + * * Copyright 2002, Phil Karn, KA9Q * May be used under the terms of the GNU General Public License (GPL) * * Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de) * - * $Id: decode_rs.c,v 1.6 2004/10/22 15:41:47 gleixner Exp $ + * $Id: decode_rs.c,v 1.7 2005/11/07 11:14:59 gleixner Exp $ * */ -/* Generic data width independent code which is included by the +/* Generic data width independent code which is included by the * wrappers. */ -{ +{ int deg_lambda, el, deg_omega; int i, j, r, k, pad; int nn = rs->nn; @@ -41,9 +41,9 @@ pad = nn - nroots - len; if (pad < 0 || pad >= nn) return -ERANGE; - + /* Does the caller provide the syndrome ? */ - if (s != NULL) + if (s != NULL) goto decode; /* form the syndromes; i.e., evaluate data(x) at roots of @@ -54,11 +54,11 @@ for (j = 1; j < len; j++) { for (i = 0; i < nroots; i++) { if (syn[i] == 0) { - syn[i] = (((uint16_t) data[j]) ^ + syn[i] = (((uint16_t) data[j]) ^ invmsk) & msk; } else { syn[i] = ((((uint16_t) data[j]) ^ - invmsk) & msk) ^ + invmsk) & msk) ^ alpha_to[rs_modnn(rs, index_of[syn[i]] + (fcr + i) * prim)]; } @@ -70,7 +70,7 @@ if (syn[i] == 0) { syn[i] = ((uint16_t) par[j]) & msk; } else { - syn[i] = (((uint16_t) par[j]) & msk) ^ + syn[i] = (((uint16_t) par[j]) & msk) ^ alpha_to[rs_modnn(rs, index_of[syn[i]] + (fcr+i)*prim)]; } @@ -99,14 +99,14 @@ if (no_eras > 0) { /* Init lambda to be the erasure locator polynomial */ - lambda[1] = alpha_to[rs_modnn(rs, + lambda[1] = alpha_to[rs_modnn(rs, prim * (nn - 1 - eras_pos[0]))]; for (i = 1; i < no_eras; i++) { u = rs_modnn(rs, prim * (nn - 1 - eras_pos[i])); for (j = i + 1; j > 0; j--) { tmp = index_of[lambda[j - 1]]; if (tmp != nn) { - lambda[j] ^= + lambda[j] ^= alpha_to[rs_modnn(rs, u + tmp)]; } } @@ -127,8 +127,8 @@ discr_r = 0; for (i = 0; i < r; i++) { if ((lambda[i] != 0) && (s[r - i - 1] != nn)) { - discr_r ^= - alpha_to[rs_modnn(rs, + discr_r ^= + alpha_to[rs_modnn(rs, index_of[lambda[i]] + s[r - i - 1])]; } @@ -143,7 +143,7 @@ t[0] = lambda[0]; for (i = 0; i < nroots; i++) { if (b[i] != nn) { - t[i + 1] = lambda[i + 1] ^ + t[i + 1] = lambda[i + 1] ^ alpha_to[rs_modnn(rs, discr_r + b[i])]; } else @@ -229,7 +229,7 @@ num1 = 0; for (i = deg_omega; i >= 0; i--) { if (omega[i] != nn) - num1 ^= alpha_to[rs_modnn(rs, omega[i] + + num1 ^= alpha_to[rs_modnn(rs, omega[i] + i * root[j])]; } num2 = alpha_to[rs_modnn(rs, root[j] * (fcr - 1) + nn)]; @@ -239,13 +239,13 @@ * lambda_pr of lambda[i] */ for (i = min(deg_lambda, nroots - 1) & ~1; i >= 0; i -= 2) { if (lambda[i + 1] != nn) { - den ^= alpha_to[rs_modnn(rs, lambda[i + 1] + + den ^= alpha_to[rs_modnn(rs, lambda[i + 1] + i * root[j])]; } } /* Apply error to data */ if (num1 != 0 && loc[j] >= pad) { - uint16_t cor = alpha_to[rs_modnn(rs,index_of[num1] + + uint16_t cor = alpha_to[rs_modnn(rs,index_of[num1] + index_of[num2] + nn - index_of[den])]; /* Store the error correction pattern, if a diff --git a/lib/reed_solomon/encode_rs.c b/lib/reed_solomon/encode_rs.c index 237bf65ae88688935bfc7a2d1da209d645ec4ef3..0b5b1a6728ec03892078689ab6f651ab873550d5 100644 --- a/lib/reed_solomon/encode_rs.c +++ b/lib/reed_solomon/encode_rs.c @@ -1,19 +1,19 @@ -/* +/* * lib/reed_solomon/encode_rs.c * * Overview: * Generic Reed Solomon encoder / decoder library - * + * * Copyright 2002, Phil Karn, KA9Q * May be used under the terms of the GNU General Public License (GPL) * * Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de) * - * $Id: encode_rs.c,v 1.4 2004/10/22 15:41:47 gleixner Exp $ + * $Id: encode_rs.c,v 1.5 2005/11/07 11:14:59 gleixner Exp $ * */ -/* Generic data width independent code which is included by the +/* Generic data width independent code which is included by the * wrappers. * int encode_rsX (struct rs_control *rs, uintX_t *data, int len, uintY_t *par) */ @@ -35,16 +35,16 @@ for (i = 0; i < len; i++) { fb = index_of[((((uint16_t) data[i])^invmsk) & msk) ^ par[0]]; /* feedback term is non-zero */ - if (fb != nn) { + if (fb != nn) { for (j = 1; j < nroots; j++) { - par[j] ^= alpha_to[rs_modnn(rs, fb + + par[j] ^= alpha_to[rs_modnn(rs, fb + genpoly[nroots - j])]; } } /* Shift */ memmove(&par[0], &par[1], sizeof(uint16_t) * (nroots - 1)); if (fb != nn) { - par[nroots - 1] = alpha_to[rs_modnn(rs, + par[nroots - 1] = alpha_to[rs_modnn(rs, fb + genpoly[0])]; } else { par[nroots - 1] = 0; diff --git a/lib/reed_solomon/reed_solomon.c b/lib/reed_solomon/reed_solomon.c index 6604e3b1940c191cde247723e5bb436450f549ce..f5fef948a415e0cb3118b0a22eaab4f374e044b3 100644 --- a/lib/reed_solomon/reed_solomon.c +++ b/lib/reed_solomon/reed_solomon.c @@ -1,22 +1,22 @@ -/* +/* * lib/reed_solomon/rslib.c * * Overview: * Generic Reed Solomon encoder / decoder library - * + * * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) * * Reed Solomon code lifted from reed solomon library written by Phil Karn * Copyright 2002 Phil Karn, KA9Q * - * $Id: rslib.c,v 1.5 2004/10/22 15:41:47 gleixner Exp $ + * $Id: rslib.c,v 1.7 2005/11/07 11:14:59 gleixner Exp $ * * 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. * * Description: - * + * * The generic Reed Solomon library provides runtime configurable * encoding / decoding of RS codes. * Each user must call init_rs to get a pointer to a rs_control @@ -25,11 +25,11 @@ * If a structure is generated then the polynomial arrays for * fast encoding / decoding are built. This can take some time so * make sure not to call this function from a time critical path. - * Usually a module / driver should initialize the necessary + * Usually a module / driver should initialize the necessary * rs_control structure on module / driver init and release it * on exit. - * The encoding puts the calculated syndrome into a given syndrome - * buffer. + * The encoding puts the calculated syndrome into a given syndrome + * buffer. * The decoding is a two step process. The first step calculates * the syndrome over the received (data + syndrome) and calls the * second stage, which does the decoding / error correction itself. @@ -51,7 +51,7 @@ static LIST_HEAD (rslist); /* Protection for the list */ static DECLARE_MUTEX(rslistlock); -/** +/** * rs_init - Initialize a Reed-Solomon codec * * @symsize: symbol size, bits (1-8) @@ -63,7 +63,7 @@ static DECLARE_MUTEX(rslistlock); * Allocate a control structure and the polynom arrays for faster * en/decoding. Fill the arrays according to the given parameters */ -static struct rs_control *rs_init(int symsize, int gfpoly, int fcr, +static struct rs_control *rs_init(int symsize, int gfpoly, int fcr, int prim, int nroots) { struct rs_control *rs; @@ -124,15 +124,15 @@ static struct rs_control *rs_init(int symsize, int gfpoly, int fcr, /* Multiply rs->genpoly[] by @**(root + x) */ for (j = i; j > 0; j--) { if (rs->genpoly[j] != 0) { - rs->genpoly[j] = rs->genpoly[j -1] ^ - rs->alpha_to[rs_modnn(rs, + rs->genpoly[j] = rs->genpoly[j -1] ^ + rs->alpha_to[rs_modnn(rs, rs->index_of[rs->genpoly[j]] + root)]; } else rs->genpoly[j] = rs->genpoly[j - 1]; } /* rs->genpoly[0] can never be zero */ - rs->genpoly[0] = - rs->alpha_to[rs_modnn(rs, + rs->genpoly[0] = + rs->alpha_to[rs_modnn(rs, rs->index_of[rs->genpoly[0]] + root)]; } /* convert rs->genpoly[] to index form for quicker encoding */ @@ -153,7 +153,7 @@ static struct rs_control *rs_init(int symsize, int gfpoly, int fcr, } -/** +/** * free_rs - Free the rs control structure, if its not longer used * * @rs: the control structure which is not longer used by the @@ -173,19 +173,19 @@ void free_rs(struct rs_control *rs) up(&rslistlock); } -/** +/** * init_rs - Find a matching or allocate a new rs control structure * * @symsize: the symbol size (number of bits) * @gfpoly: the extended Galois field generator polynomial coefficients, * with the 0th coefficient in the low order bit. The polynomial * must be primitive; - * @fcr: the first consecutive root of the rs code generator polynomial + * @fcr: the first consecutive root of the rs code generator polynomial * in index form * @prim: primitive element to generate polynomial roots * @nroots: RS code generator polynomial degree (number of roots) */ -struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim, +struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim, int nroots) { struct list_head *tmp; @@ -198,9 +198,9 @@ struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim, return NULL; if (prim <= 0 || prim >= (1<= (1< 8) + if (nroots < 0 || nroots >= (1<gfpoly) continue; if (fcr != rs->fcr) - continue; + continue; if (prim != rs->prim) - continue; + continue; if (nroots != rs->nroots) continue; /* We have a matching one already */ @@ -227,18 +227,18 @@ struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim, rs->users = 1; list_add(&rs->list, &rslist); } -out: +out: up(&rslistlock); return rs; } #ifdef CONFIG_REED_SOLOMON_ENC8 -/** +/** * encode_rs8 - Calculate the parity for data values (8bit data width) * * @rs: the rs control structure * @data: data field of a given type - * @len: data length + * @len: data length * @par: parity data, must be initialized by caller (usually all 0) * @invmsk: invert data mask (will be xored on data) * @@ -246,7 +246,7 @@ struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim, * symbol size > 8. The calling code must take care of encoding of the * syndrome result for storage itself. */ -int encode_rs8(struct rs_control *rs, uint8_t *data, int len, uint16_t *par, +int encode_rs8(struct rs_control *rs, uint8_t *data, int len, uint16_t *par, uint16_t invmsk) { #include "encode_rs.c" @@ -255,7 +255,7 @@ EXPORT_SYMBOL_GPL(encode_rs8); #endif #ifdef CONFIG_REED_SOLOMON_DEC8 -/** +/** * decode_rs8 - Decode codeword (8bit data width) * * @rs: the rs control structure @@ -273,7 +273,7 @@ EXPORT_SYMBOL_GPL(encode_rs8); * syndrome result and the received parity before calling this code. */ int decode_rs8(struct rs_control *rs, uint8_t *data, uint16_t *par, int len, - uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk, + uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk, uint16_t *corr) { #include "decode_rs.c" @@ -287,13 +287,13 @@ EXPORT_SYMBOL_GPL(decode_rs8); * * @rs: the rs control structure * @data: data field of a given type - * @len: data length + * @len: data length * @par: parity data, must be initialized by caller (usually all 0) * @invmsk: invert data mask (will be xored on data, not on parity!) * * Each field in the data array contains up to symbol size bits of valid data. */ -int encode_rs16(struct rs_control *rs, uint16_t *data, int len, uint16_t *par, +int encode_rs16(struct rs_control *rs, uint16_t *data, int len, uint16_t *par, uint16_t invmsk) { #include "encode_rs.c" @@ -302,7 +302,7 @@ EXPORT_SYMBOL_GPL(encode_rs16); #endif #ifdef CONFIG_REED_SOLOMON_DEC16 -/** +/** * decode_rs16 - Decode codeword (16bit data width) * * @rs: the rs control structure @@ -312,13 +312,13 @@ EXPORT_SYMBOL_GPL(encode_rs16); * @s: syndrome data field (if NULL, syndrome is calculated) * @no_eras: number of erasures * @eras_pos: position of erasures, can be NULL - * @invmsk: invert data mask (will be xored on data, not on parity!) + * @invmsk: invert data mask (will be xored on data, not on parity!) * @corr: buffer to store correction bitmask on eras_pos * * Each field in the data array contains up to symbol size bits of valid data. */ int decode_rs16(struct rs_control *rs, uint16_t *data, uint16_t *par, int len, - uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk, + uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk, uint16_t *corr) { #include "decode_rs.c" diff --git a/mm/Kconfig b/mm/Kconfig index 1a4473fcb2ca0d2ea163301ba49d740d78310e8b..ae9ce6b73e8a8351d1a5533349f141bbb5492e3a 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -126,9 +126,11 @@ comment "Memory hotplug is currently incompatible with Software Suspend" # Default to 4 for wider testing, though 8 might be more appropriate. # ARM's adjust_pte (unused if VIPT) depends on mm-wide page_table_lock. # PA-RISC's debug spinlock_t is too large for the 32-bit struct page. +# ARM26 and SPARC32 and PPC64 may use one page for multiple page tables. # config SPLIT_PTLOCK_CPUS int default "4096" if ARM && !CPU_CACHE_VIPT default "4096" if PARISC && DEBUG_SPINLOCK && !64BIT + default "4096" if ARM26 || SPARC32 || PPC64 default "4" diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 9a565808da3fac6cad64e7412aa2d12f1a75eb70..728e9bda12ea9971c1cf0212184b1ca2c2d94020 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -237,7 +237,6 @@ unsigned long hugetlb_total_pages(void) { return nr_huge_pages * (HPAGE_SIZE / PAGE_SIZE); } -EXPORT_SYMBOL(hugetlb_total_pages); /* * We cannot handle pagefaults against hugetlb pages at all. They cause diff --git a/mm/mmap.c b/mm/mmap.c index 320dda1778c3b3489aea3a44e12251f939e75e3c..6c997b159600b89b6d6cb4b5a4059e8adf3b0e92 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -155,10 +155,6 @@ int __vm_enough_memory(long pages, int cap_sys_admin) return -ENOMEM; } -EXPORT_SYMBOL(sysctl_overcommit_memory); -EXPORT_SYMBOL(sysctl_overcommit_ratio); -EXPORT_SYMBOL(sysctl_max_map_count); -EXPORT_SYMBOL(vm_committed_space); EXPORT_SYMBOL(__vm_enough_memory); /* diff --git a/mm/nommu.c b/mm/nommu.c index d1e076a487cbe3eff161ca2f2472186977f30e41..6deb6ab3d6ada1a27cfcbc65303fa1403d498ac0 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -44,10 +44,6 @@ int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT; int heap_stack_gap = 0; EXPORT_SYMBOL(mem_map); -EXPORT_SYMBOL(sysctl_max_map_count); -EXPORT_SYMBOL(sysctl_overcommit_memory); -EXPORT_SYMBOL(sysctl_overcommit_ratio); -EXPORT_SYMBOL(vm_committed_space); EXPORT_SYMBOL(__vm_enough_memory); /* list of shareable VMAs */ diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 0166ea15c9ee8d61f08ddc6e100de841e59205c7..74138c9a22b982a9a74fb4076e41826a0d56c3b5 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -750,7 +750,6 @@ int clear_page_dirty_for_io(struct page *page) } return TestClearPageDirty(page); } -EXPORT_SYMBOL(clear_page_dirty_for_io); int test_clear_page_writeback(struct page *page) { diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 2dbdd98426fd46f9270d45acb081b7554df1740d..ff81b5c65511df6a1604f486ba6fae44553cb8e4 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -64,7 +64,6 @@ long nr_swap_pages; int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES-1] = { 256, 32 }; EXPORT_SYMBOL(totalram_pages); -EXPORT_SYMBOL(nr_swap_pages); /* * Used by page_zone() to look up the address of the struct zone whose diff --git a/mm/readahead.c b/mm/readahead.c index d0b50034e245a0095c7d359388b59676af0bdb59..72e7adbb87c7dd1e08cc1eb2851bdb96300d7e02 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -254,7 +254,7 @@ static int read_pages(struct address_space *mapping, struct file *filp, */ static int __do_page_cache_readahead(struct address_space *mapping, struct file *filp, - unsigned long offset, unsigned long nr_to_read) + pgoff_t offset, unsigned long nr_to_read) { struct inode *inode = mapping->host; struct page *page; @@ -274,7 +274,7 @@ __do_page_cache_readahead(struct address_space *mapping, struct file *filp, */ read_lock_irq(&mapping->tree_lock); for (page_idx = 0; page_idx < nr_to_read; page_idx++) { - unsigned long page_offset = offset + page_idx; + pgoff_t page_offset = offset + page_idx; if (page_offset > end_index) break; @@ -311,7 +311,7 @@ __do_page_cache_readahead(struct address_space *mapping, struct file *filp, * memory at once. */ int force_page_cache_readahead(struct address_space *mapping, struct file *filp, - unsigned long offset, unsigned long nr_to_read) + pgoff_t offset, unsigned long nr_to_read) { int ret = 0; @@ -368,7 +368,7 @@ static inline int check_ra_success(struct file_ra_state *ra, * request queues. */ int do_page_cache_readahead(struct address_space *mapping, struct file *filp, - unsigned long offset, unsigned long nr_to_read) + pgoff_t offset, unsigned long nr_to_read) { if (bdi_read_congested(mapping->backing_dev_info)) return -1; @@ -385,7 +385,7 @@ int do_page_cache_readahead(struct address_space *mapping, struct file *filp, */ static int blockable_page_cache_readahead(struct address_space *mapping, struct file *filp, - unsigned long offset, unsigned long nr_to_read, + pgoff_t offset, unsigned long nr_to_read, struct file_ra_state *ra, int block) { int actual; @@ -430,14 +430,27 @@ static int make_ahead_window(struct address_space *mapping, struct file *filp, return ret; } -/* - * page_cache_readahead is the main function. If performs the adaptive +/** + * page_cache_readahead - generic adaptive readahead + * @mapping: address_space which holds the pagecache and I/O vectors + * @ra: file_ra_state which holds the readahead state + * @filp: passed on to ->readpage() and ->readpages() + * @offset: start offset into @mapping, in PAGE_CACHE_SIZE units + * @req_size: hint: total size of the read which the caller is performing in + * PAGE_CACHE_SIZE units + * + * page_cache_readahead() is the main function. If performs the adaptive * readahead window size management and submits the readahead I/O. + * + * Note that @filp is purely used for passing on to the ->readpage[s]() + * handler: it may refer to a different file from @mapping (so we may not use + * @filp->f_mapping or @filp->f_dentry->d_inode here). + * Also, @ra may not be equal to &@filp->f_ra. + * */ unsigned long page_cache_readahead(struct address_space *mapping, struct file_ra_state *ra, - struct file *filp, unsigned long offset, - unsigned long req_size) + struct file *filp, pgoff_t offset, unsigned long req_size) { unsigned long max, newsize; int sequential; diff --git a/mm/slab.c b/mm/slab.c index 22bfb0b2ac8b441d479bbfe16028fa7e0db132e8..e291f5e1afbb3acd9d53ad3646527e2f06c3169f 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -368,7 +368,7 @@ static inline void kmem_list3_init(struct kmem_list3 *parent) * manages a cache. */ -struct kmem_cache_s { +struct kmem_cache { /* 1) per-cpu data, touched during every alloc/free */ struct array_cache *array[NR_CPUS]; unsigned int batchcount; @@ -1502,6 +1502,7 @@ kmem_cache_create (const char *name, size_t size, size_t align, { size_t left_over, slab_size, ralign; kmem_cache_t *cachep = NULL; + struct list_head *p; /* * Sanity checks... these are all serious usage bugs. @@ -1516,6 +1517,35 @@ kmem_cache_create (const char *name, size_t size, size_t align, BUG(); } + down(&cache_chain_sem); + + list_for_each(p, &cache_chain) { + kmem_cache_t *pc = list_entry(p, kmem_cache_t, next); + mm_segment_t old_fs = get_fs(); + char tmp; + int res; + + /* + * This happens when the module gets unloaded and doesn't + * destroy its slab cache and no-one else reuses the vmalloc + * area of the module. Print a warning. + */ + set_fs(KERNEL_DS); + res = __get_user(tmp, pc->name); + set_fs(old_fs); + if (res) { + printk("SLAB: cache with size %d has lost its name\n", + pc->objsize); + continue; + } + + if (!strcmp(pc->name,name)) { + printk("kmem_cache_create: duplicate cache %s\n", name); + dump_stack(); + goto oops; + } + } + #if DEBUG WARN_ON(strchr(name, ' ')); /* It confuses parsers */ if ((flags & SLAB_DEBUG_INITIAL) && !ctor) { @@ -1592,7 +1622,7 @@ kmem_cache_create (const char *name, size_t size, size_t align, /* Get cache's description obj. */ cachep = (kmem_cache_t *) kmem_cache_alloc(&cache_cache, SLAB_KERNEL); if (!cachep) - goto opps; + goto oops; memset(cachep, 0, sizeof(kmem_cache_t)); #if DEBUG @@ -1686,7 +1716,7 @@ kmem_cache_create (const char *name, size_t size, size_t align, printk("kmem_cache_create: couldn't create cache %s.\n", name); kmem_cache_free(&cache_cache, cachep); cachep = NULL; - goto opps; + goto oops; } slab_size = ALIGN(cachep->num*sizeof(kmem_bufctl_t) + sizeof(struct slab), align); @@ -1781,43 +1811,14 @@ kmem_cache_create (const char *name, size_t size, size_t align, cachep->limit = BOOT_CPUCACHE_ENTRIES; } - /* Need the semaphore to access the chain. */ - down(&cache_chain_sem); - { - struct list_head *p; - mm_segment_t old_fs; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - list_for_each(p, &cache_chain) { - kmem_cache_t *pc = list_entry(p, kmem_cache_t, next); - char tmp; - /* This happens when the module gets unloaded and doesn't - destroy its slab cache and noone else reuses the vmalloc - area of the module. Print a warning. */ - if (__get_user(tmp,pc->name)) { - printk("SLAB: cache with size %d has lost its name\n", - pc->objsize); - continue; - } - if (!strcmp(pc->name,name)) { - printk("kmem_cache_create: duplicate cache %s\n",name); - up(&cache_chain_sem); - unlock_cpu_hotplug(); - BUG(); - } - } - set_fs(old_fs); - } - /* cache setup completed, link it into the list */ list_add(&cachep->next, &cache_chain); - up(&cache_chain_sem); unlock_cpu_hotplug(); -opps: +oops: if (!cachep && (flags & SLAB_PANIC)) panic("kmem_cache_create(): failed to create slab `%s'\n", name); + up(&cache_chain_sem); return cachep; } EXPORT_SYMBOL(kmem_cache_create); @@ -3262,6 +3263,7 @@ static void drain_array_locked(kmem_cache_t *cachep, /** * cache_reap - Reclaim memory from caches. + * @unused: unused parameter * * Called from workqueue/eventd every few seconds. * Purpose: @@ -3278,7 +3280,7 @@ static void cache_reap(void *unused) if (down_trylock(&cache_chain_sem)) { /* Give up. Setup the next iteration. */ - schedule_delayed_work(&__get_cpu_var(reap_work), REAPTIMEOUT_CPUC + smp_processor_id()); + schedule_delayed_work(&__get_cpu_var(reap_work), REAPTIMEOUT_CPUC); return; } @@ -3347,7 +3349,7 @@ static void cache_reap(void *unused) up(&cache_chain_sem); drain_remote_pages(); /* Setup the next iteration */ - schedule_delayed_work(&__get_cpu_var(reap_work), REAPTIMEOUT_CPUC + smp_processor_id()); + schedule_delayed_work(&__get_cpu_var(reap_work), REAPTIMEOUT_CPUC); } #ifdef CONFIG_PROC_FS diff --git a/mm/swap.c b/mm/swap.c index 154ae13d8b7e33bd9f5d929b2c7e4c16ab38590c..d09cf7f03e767e57e500ac5f6dd4c35c72c5f9a4 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -413,7 +413,6 @@ void vm_acct_memory(long pages) } preempt_enable(); } -EXPORT_SYMBOL(vm_acct_memory); #ifdef CONFIG_HOTPLUG_CPU static void lru_drain_cache(unsigned int cpu) diff --git a/mm/swap_state.c b/mm/swap_state.c index dfd9a46755b84f7ffdcc97e6526d9a0665062b6c..0df9a57b1de84bca534a9f6cc0c32d1ddefb939a 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -40,7 +40,6 @@ struct address_space swapper_space = { .i_mmap_nonlinear = LIST_HEAD_INIT(swapper_space.i_mmap_nonlinear), .backing_dev_info = &swap_backing_dev_info, }; -EXPORT_SYMBOL(swapper_space); #define INC_CACHE_INFO(x) do { swap_cache_info.x++; } while (0) diff --git a/mm/swapfile.c b/mm/swapfile.c index 8970c0b74194f45f2bce26592399e9db40f2947b..edafeace301f01879e04d31c9bf9e5c01a4484e9 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -36,8 +36,6 @@ unsigned int nr_swapfiles; long total_swap_pages; static int swap_overflow; -EXPORT_SYMBOL(total_swap_pages); - static const char Bad_file[] = "Bad swap file entry "; static const char Unused_file[] = "Unused swap file entry "; static const char Bad_offset[] = "Bad swap offset entry "; diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 54a90e83cb318aa32e2f8ee6adc28960ee1da32c..729eb3eec75fd7043b8b8a74e6b748b9390b0f6d 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -457,7 +457,7 @@ void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot) * @size: allocation size * @gfp_mask: flags for the page level allocator * @prot: protection mask for the allocated pages - * @node node to use for allocation or -1 + * @node: node to use for allocation or -1 * * Allocate enough pages to cover @size from the page level * allocator with @gfp_mask flags. Map them into contiguous @@ -507,7 +507,7 @@ EXPORT_SYMBOL(vmalloc); * vmalloc_node - allocate memory on a specific node * * @size: allocation size - * @node; numa node + * @node: numa node * * Allocate enough pages to cover @size from the page level * allocator and map them into contiguous kernel virtual space. diff --git a/net/802/p8023.c b/net/802/p8023.c index 6368d3dce444489ea41e654067aa92c012c0b924..d23e906456eb373ccbbd5ead89270ff198ceaf2e 100644 --- a/net/802/p8023.c +++ b/net/802/p8023.c @@ -54,8 +54,7 @@ struct datalink_proto *make_8023_client(void) */ void destroy_8023_client(struct datalink_proto *dl) { - if (dl) - kfree(dl); + kfree(dl); } EXPORT_SYMBOL(destroy_8023_client); diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 8e37e71e34ff1929aef5a8b8efb2ef362dec6b54..1b683f302657d376f438b8f9ea68805bdd14118c 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -1138,10 +1138,8 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, sk->sk_state = TCP_CLOSE; sock->state = SS_UNCONNECTED; - if (ax25->digipeat != NULL) { - kfree(ax25->digipeat); - ax25->digipeat = NULL; - } + kfree(ax25->digipeat); + ax25->digipeat = NULL; /* * Handle digi-peaters to be used. diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c index 73cfc3411c461d50d7dbb7d718dd3e2315d26428..4cf87540fb3abd79df222319a9c79e3dc09f2e3d 100644 --- a/net/ax25/ax25_in.c +++ b/net/ax25/ax25_in.c @@ -401,10 +401,8 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, } if (dp.ndigi == 0) { - if (ax25->digipeat != NULL) { - kfree(ax25->digipeat); - ax25->digipeat = NULL; - } + kfree(ax25->digipeat); + ax25->digipeat = NULL; } else { /* Reverse the source SABM's path */ memcpy(ax25->digipeat, &reverse_dp, sizeof(ax25_digi)); diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c index 26b77d9722201232d7adfcb2bb27dcc3fb90e246..b1e945bd6ed3d0f22e1a306303ad32ca4a471cc6 100644 --- a/net/ax25/ax25_route.c +++ b/net/ax25/ax25_route.c @@ -54,15 +54,13 @@ void ax25_rt_device_down(struct net_device *dev) if (s->dev == dev) { if (ax25_route_list == s) { ax25_route_list = s->next; - if (s->digipeat != NULL) - kfree(s->digipeat); + kfree(s->digipeat); kfree(s); } else { for (t = ax25_route_list; t != NULL; t = t->next) { if (t->next == s) { t->next = s->next; - if (s->digipeat != NULL) - kfree(s->digipeat); + kfree(s->digipeat); kfree(s); break; } @@ -90,10 +88,8 @@ static int ax25_rt_add(struct ax25_routes_struct *route) while (ax25_rt != NULL) { if (ax25cmp(&ax25_rt->callsign, &route->dest_addr) == 0 && ax25_rt->dev == ax25_dev->dev) { - if (ax25_rt->digipeat != NULL) { - kfree(ax25_rt->digipeat); - ax25_rt->digipeat = NULL; - } + kfree(ax25_rt->digipeat); + ax25_rt->digipeat = NULL; if (route->digi_count != 0) { if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { write_unlock(&ax25_route_lock); @@ -145,8 +141,7 @@ static int ax25_rt_add(struct ax25_routes_struct *route) static void ax25_rt_destroy(ax25_route *ax25_rt) { if (atomic_read(&ax25_rt->ref) == 0) { - if (ax25_rt->digipeat != NULL) - kfree(ax25_rt->digipeat); + kfree(ax25_rt->digipeat); kfree(ax25_rt); return; } @@ -530,9 +525,7 @@ void __exit ax25_rt_free(void) s = ax25_rt; ax25_rt = ax25_rt->next; - if (s->digipeat != NULL) - kfree(s->digipeat); - + kfree(s->digipeat); kfree(s); } write_unlock(&ax25_route_lock); diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 03532062a46a9168b662abad180a2e2347017e9d..ea616e3fc98e73f3806a5dc04e9770b6fba38425 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #if defined(CONFIG_KMOD) @@ -50,10 +49,7 @@ #define BT_DBG(D...) #endif -#define VERSION "2.7" - -struct proc_dir_entry *proc_bt; -EXPORT_SYMBOL(proc_bt); +#define VERSION "2.8" /* Bluetooth sockets */ #define BT_MAX_PROTO 8 @@ -312,10 +308,6 @@ static int __init bt_init(void) { BT_INFO("Core ver %s", VERSION); - proc_bt = proc_mkdir("bluetooth", NULL); - if (proc_bt) - proc_bt->owner = THIS_MODULE; - sock_register(&bt_sock_family_ops); BT_INFO("HCI device and connection manager initialized"); @@ -334,8 +326,6 @@ static void __exit bt_exit(void) bt_sysfs_cleanup(); sock_unregister(PF_BLUETOOTH); - - remove_proc_entry("bluetooth", NULL); } subsys_initcall(bt_init); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index cf0df1c8c933c0f346b50f77578ba92f636d99a4..9106354c781e68c868d1830bec83c4312d1ccd04 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -183,7 +183,7 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt) static void hci_init_req(struct hci_dev *hdev, unsigned long opt) { struct sk_buff *skb; - __u16 param; + __le16 param; BT_DBG("%s %ld", hdev->name, opt); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index b61b4e8e36fdab2bd7c555acdfb7a93f23de5e14..eb64555d1fb346d90ff34dad9ed16ef4700d0fdc 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -242,7 +242,7 @@ static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb break; status = *((__u8 *) skb->data); - setting = __le16_to_cpu(get_unaligned((__u16 *) sent)); + setting = __le16_to_cpu(get_unaligned((__le16 *) sent)); if (!status && hdev->voice_setting != setting) { hdev->voice_setting = setting; @@ -728,7 +728,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_num_comp_pkts *ev = (struct hci_ev_num_comp_pkts *) skb->data; - __u16 *ptr; + __le16 *ptr; int i; skb_pull(skb, sizeof(*ev)); @@ -742,7 +742,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s tasklet_disable(&hdev->tx_task); - for (i = 0, ptr = (__u16 *) skb->data; i < ev->num_hndl; i++) { + for (i = 0, ptr = (__le16 *) skb->data; i < ev->num_hndl; i++) { struct hci_conn *conn; __u16 handle, count; diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 799e448750ad906114c85c3a908e10ab44ec7cb4..1d6d0a15c099a8c4e8f38a63ed78925c0c6f827e 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -416,7 +416,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, skb->dev = (void *) hdev; if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) { - u16 opcode = __le16_to_cpu(get_unaligned((u16 *)skb->data)); + u16 opcode = __le16_to_cpu(get_unaligned((__le16 *) skb->data)); u16 ogf = hci_opcode_ogf(opcode); u16 ocf = hci_opcode_ocf(opcode); diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 7856bc26accb2acf6bdc28f9aaa91b6acee89667..bd7568ac87fc5ad7883e19cdd63b2dfb98193760 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -103,7 +103,7 @@ static void bt_release(struct class_device *cdev) kfree(hdev); } -static struct class bt_class = { +struct class bt_class = { .name = "bluetooth", .release = bt_release, #ifdef CONFIG_HOTPLUG @@ -111,6 +111,8 @@ static struct class bt_class = { #endif }; +EXPORT_SYMBOL_GPL(bt_class); + int hci_register_sysfs(struct hci_dev *hdev) { struct class_device *cdev = &hdev->class_dev; diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 860444a7fc0f8e1e014f063721ecdc221a365304..cdb9cfafd960b5c45730b933f0515e1b79f1bfd4 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -660,9 +660,7 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, failed: up_write(&hidp_session_sem); - if (session->input) - kfree(session->input); - + kfree(session->input); kfree(session); return err; } diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 59b2dd36baa77e1414177e1363cb697f2feebbc6..e3bb11ca4235562af24b7748873ef8de5ba1d362 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -38,9 +38,8 @@ #include #include #include -#include -#include #include +#include #include #include @@ -56,7 +55,7 @@ #define BT_DBG(D...) #endif -#define VERSION "2.7" +#define VERSION "2.8" static struct proto_ops l2cap_sock_ops; @@ -2137,94 +2136,29 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl return 0; } -/* ---- Proc fs support ---- */ -#ifdef CONFIG_PROC_FS -static void *l2cap_seq_start(struct seq_file *seq, loff_t *pos) +static ssize_t l2cap_sysfs_show(struct class *dev, char *buf) { struct sock *sk; struct hlist_node *node; - loff_t l = *pos; + char *str = buf; read_lock_bh(&l2cap_sk_list.lock); - sk_for_each(sk, node, &l2cap_sk_list.head) - if (!l--) - goto found; - sk = NULL; -found: - return sk; -} + sk_for_each(sk, node, &l2cap_sk_list.head) { + struct l2cap_pinfo *pi = l2cap_pi(sk); -static void *l2cap_seq_next(struct seq_file *seq, void *e, loff_t *pos) -{ - (*pos)++; - return sk_next(e); -} + str += sprintf(str, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n", + batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), + sk->sk_state, pi->psm, pi->scid, pi->dcid, pi->imtu, + pi->omtu, pi->link_mode); + } -static void l2cap_seq_stop(struct seq_file *seq, void *e) -{ read_unlock_bh(&l2cap_sk_list.lock); -} -static int l2cap_seq_show(struct seq_file *seq, void *e) -{ - struct sock *sk = e; - struct l2cap_pinfo *pi = l2cap_pi(sk); - - seq_printf(seq, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n", - batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), - sk->sk_state, pi->psm, pi->scid, pi->dcid, pi->imtu, - pi->omtu, pi->link_mode); - return 0; + return (str - buf); } -static struct seq_operations l2cap_seq_ops = { - .start = l2cap_seq_start, - .next = l2cap_seq_next, - .stop = l2cap_seq_stop, - .show = l2cap_seq_show -}; - -static int l2cap_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &l2cap_seq_ops); -} - -static struct file_operations l2cap_seq_fops = { - .owner = THIS_MODULE, - .open = l2cap_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static int __init l2cap_proc_init(void) -{ - struct proc_dir_entry *p = create_proc_entry("l2cap", S_IRUGO, proc_bt); - if (!p) - return -ENOMEM; - p->owner = THIS_MODULE; - p->proc_fops = &l2cap_seq_fops; - return 0; -} - -static void __exit l2cap_proc_cleanup(void) -{ - remove_proc_entry("l2cap", proc_bt); -} - -#else /* CONFIG_PROC_FS */ - -static int __init l2cap_proc_init(void) -{ - return 0; -} - -static void __exit l2cap_proc_cleanup(void) -{ - return; -} -#endif /* CONFIG_PROC_FS */ +static CLASS_ATTR(l2cap, S_IRUGO, l2cap_sysfs_show, NULL); static struct proto_ops l2cap_sock_ops = { .family = PF_BLUETOOTH, @@ -2266,7 +2200,7 @@ static struct hci_proto l2cap_hci_proto = { static int __init l2cap_init(void) { int err; - + err = proto_register(&l2cap_proto, 0); if (err < 0) return err; @@ -2284,7 +2218,7 @@ static int __init l2cap_init(void) goto error; } - l2cap_proc_init(); + class_create_file(&bt_class, &class_attr_l2cap); BT_INFO("L2CAP ver %s", VERSION); BT_INFO("L2CAP socket layer initialized"); @@ -2298,7 +2232,7 @@ static int __init l2cap_init(void) static void __exit l2cap_exit(void) { - l2cap_proc_cleanup(); + class_remove_file(&bt_class, &class_attr_l2cap); if (bt_sock_unregister(BTPROTO_L2CAP) < 0) BT_ERR("L2CAP socket unregistration failed"); diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index c3d56ead840cbb42cbfc6814e32fed1ff83de066..0d89d64341364fcf9e6eb4214568c24795ea6a51 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -35,9 +35,8 @@ #include #include #include +#include #include -#include -#include #include #include #include @@ -47,17 +46,13 @@ #include #include -#define VERSION "1.5" +#define VERSION "1.6" #ifndef CONFIG_BT_RFCOMM_DEBUG #undef BT_DBG #define BT_DBG(D...) #endif -#ifdef CONFIG_PROC_FS -struct proc_dir_entry *proc_bt_rfcomm; -#endif - static struct task_struct *rfcomm_thread; static DECLARE_MUTEX(rfcomm_sem); @@ -2001,117 +1996,32 @@ static struct hci_cb rfcomm_cb = { .encrypt_cfm = rfcomm_encrypt_cfm }; -/* ---- Proc fs support ---- */ -#ifdef CONFIG_PROC_FS -static void *rfcomm_seq_start(struct seq_file *seq, loff_t *pos) +static ssize_t rfcomm_dlc_sysfs_show(struct class *dev, char *buf) { struct rfcomm_session *s; struct list_head *pp, *p; - loff_t l = *pos; + char *str = buf; rfcomm_lock(); list_for_each(p, &session_list) { s = list_entry(p, struct rfcomm_session, list); - list_for_each(pp, &s->dlcs) - if (!l--) { - seq->private = s; - return pp; - } - } - return NULL; -} + list_for_each(pp, &s->dlcs) { + struct sock *sk = s->sock->sk; + struct rfcomm_dlc *d = list_entry(pp, struct rfcomm_dlc, list); -static void *rfcomm_seq_next(struct seq_file *seq, void *e, loff_t *pos) -{ - struct rfcomm_session *s = seq->private; - struct list_head *pp, *p = e; - (*pos)++; - - if (p->next != &s->dlcs) - return p->next; - - list_for_each(p, &session_list) { - s = list_entry(p, struct rfcomm_session, list); - __list_for_each(pp, &s->dlcs) { - seq->private = s; - return pp; + str += sprintf(str, "%s %s %ld %d %d %d %d\n", + batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), + d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits); } } - return NULL; -} -static void rfcomm_seq_stop(struct seq_file *seq, void *e) -{ rfcomm_unlock(); -} - -static int rfcomm_seq_show(struct seq_file *seq, void *e) -{ - struct rfcomm_session *s = seq->private; - struct sock *sk = s->sock->sk; - struct rfcomm_dlc *d = list_entry(e, struct rfcomm_dlc, list); - - seq_printf(seq, "%s %s %ld %d %d %d %d\n", - batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), - d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits); - return 0; -} - -static struct seq_operations rfcomm_seq_ops = { - .start = rfcomm_seq_start, - .next = rfcomm_seq_next, - .stop = rfcomm_seq_stop, - .show = rfcomm_seq_show -}; - -static int rfcomm_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &rfcomm_seq_ops); -} - -static struct file_operations rfcomm_seq_fops = { - .owner = THIS_MODULE, - .open = rfcomm_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static int __init rfcomm_proc_init(void) -{ - struct proc_dir_entry *p; - - proc_bt_rfcomm = proc_mkdir("rfcomm", proc_bt); - if (proc_bt_rfcomm) { - proc_bt_rfcomm->owner = THIS_MODULE; - - p = create_proc_entry("dlc", S_IRUGO, proc_bt_rfcomm); - if (p) - p->proc_fops = &rfcomm_seq_fops; - } - return 0; -} - -static void __exit rfcomm_proc_cleanup(void) -{ - remove_proc_entry("dlc", proc_bt_rfcomm); - remove_proc_entry("rfcomm", proc_bt); + return (str - buf); } -#else /* CONFIG_PROC_FS */ - -static int __init rfcomm_proc_init(void) -{ - return 0; -} - -static void __exit rfcomm_proc_cleanup(void) -{ - return; -} -#endif /* CONFIG_PROC_FS */ +static CLASS_ATTR(rfcomm_dlc, S_IRUGO, rfcomm_dlc_sysfs_show, NULL); /* ---- Initialization ---- */ static int __init rfcomm_init(void) @@ -2122,9 +2032,7 @@ static int __init rfcomm_init(void) kernel_thread(rfcomm_run, NULL, CLONE_KERNEL); - BT_INFO("RFCOMM ver %s", VERSION); - - rfcomm_proc_init(); + class_create_file(&bt_class, &class_attr_rfcomm_dlc); rfcomm_init_sockets(); @@ -2132,11 +2040,15 @@ static int __init rfcomm_init(void) rfcomm_init_ttys(); #endif + BT_INFO("RFCOMM ver %s", VERSION); + return 0; } static void __exit rfcomm_exit(void) { + class_remove_file(&bt_class, &class_attr_rfcomm_dlc); + hci_unregister_cb(&rfcomm_cb); /* Terminate working thread. @@ -2153,8 +2065,6 @@ static void __exit rfcomm_exit(void) #endif rfcomm_cleanup_sockets(); - - rfcomm_proc_cleanup(); } module_init(rfcomm_init); diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index a2b30f0aedb7b4bc586cdabc141c392fc6eca775..6c34261b232e4cd2d9d0b254e7ae8701a3dfd021 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -42,8 +42,7 @@ #include #include #include -#include -#include +#include #include #include @@ -887,89 +886,26 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * return result; } -/* ---- Proc fs support ---- */ -#ifdef CONFIG_PROC_FS -static void *rfcomm_seq_start(struct seq_file *seq, loff_t *pos) +static ssize_t rfcomm_sock_sysfs_show(struct class *dev, char *buf) { struct sock *sk; struct hlist_node *node; - loff_t l = *pos; + char *str = buf; read_lock_bh(&rfcomm_sk_list.lock); - sk_for_each(sk, node, &rfcomm_sk_list.head) - if (!l--) - return sk; - return NULL; -} - -static void *rfcomm_seq_next(struct seq_file *seq, void *e, loff_t *pos) -{ - struct sock *sk = e; - (*pos)++; - return sk_next(sk); -} + sk_for_each(sk, node, &rfcomm_sk_list.head) { + str += sprintf(str, "%s %s %d %d\n", + batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), + sk->sk_state, rfcomm_pi(sk)->channel); + } -static void rfcomm_seq_stop(struct seq_file *seq, void *e) -{ read_unlock_bh(&rfcomm_sk_list.lock); -} -static int rfcomm_seq_show(struct seq_file *seq, void *e) -{ - struct sock *sk = e; - seq_printf(seq, "%s %s %d %d\n", - batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), - sk->sk_state, rfcomm_pi(sk)->channel); - return 0; -} - -static struct seq_operations rfcomm_seq_ops = { - .start = rfcomm_seq_start, - .next = rfcomm_seq_next, - .stop = rfcomm_seq_stop, - .show = rfcomm_seq_show -}; - -static int rfcomm_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &rfcomm_seq_ops); + return (str - buf); } -static struct file_operations rfcomm_seq_fops = { - .owner = THIS_MODULE, - .open = rfcomm_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static int __init rfcomm_sock_proc_init(void) -{ - struct proc_dir_entry *p = create_proc_entry("sock", S_IRUGO, proc_bt_rfcomm); - if (!p) - return -ENOMEM; - p->proc_fops = &rfcomm_seq_fops; - return 0; -} - -static void __exit rfcomm_sock_proc_cleanup(void) -{ - remove_proc_entry("sock", proc_bt_rfcomm); -} - -#else /* CONFIG_PROC_FS */ - -static int __init rfcomm_sock_proc_init(void) -{ - return 0; -} - -static void __exit rfcomm_sock_proc_cleanup(void) -{ - return; -} -#endif /* CONFIG_PROC_FS */ +static CLASS_ATTR(rfcomm, S_IRUGO, rfcomm_sock_sysfs_show, NULL); static struct proto_ops rfcomm_sock_ops = { .family = PF_BLUETOOTH, @@ -997,7 +933,7 @@ static struct net_proto_family rfcomm_sock_family_ops = { .create = rfcomm_sock_create }; -int __init rfcomm_init_sockets(void) +int __init rfcomm_init_sockets(void) { int err; @@ -1009,7 +945,7 @@ int __init rfcomm_init_sockets(void) if (err < 0) goto error; - rfcomm_sock_proc_init(); + class_create_file(&bt_class, &class_attr_rfcomm); BT_INFO("RFCOMM socket layer initialized"); @@ -1023,7 +959,7 @@ int __init rfcomm_init_sockets(void) void __exit rfcomm_cleanup_sockets(void) { - rfcomm_sock_proc_cleanup(); + class_remove_file(&bt_class, &class_attr_rfcomm); if (bt_sock_unregister(BTPROTO_RFCOMM) < 0) BT_ERR("RFCOMM socket layer unregistration failed"); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 997e42df115c5f6eba7be27fa4ec02883eb42a56..9cb00dc6c08c6d18b4cf1031a4405e144d1f69c0 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -38,8 +38,7 @@ #include #include #include -#include -#include +#include #include #include @@ -55,7 +54,7 @@ #define BT_DBG(D...) #endif -#define VERSION "0.4" +#define VERSION "0.5" static struct proto_ops sco_sock_ops; @@ -893,91 +892,26 @@ static int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb) return 0; } -/* ---- Proc fs support ---- */ -#ifdef CONFIG_PROC_FS -static void *sco_seq_start(struct seq_file *seq, loff_t *pos) +static ssize_t sco_sysfs_show(struct class *dev, char *buf) { struct sock *sk; struct hlist_node *node; - loff_t l = *pos; + char *str = buf; read_lock_bh(&sco_sk_list.lock); - sk_for_each(sk, node, &sco_sk_list.head) - if (!l--) - goto found; - sk = NULL; -found: - return sk; -} - -static void *sco_seq_next(struct seq_file *seq, void *e, loff_t *pos) -{ - struct sock *sk = e; - (*pos)++; - return sk_next(sk); -} + sk_for_each(sk, node, &sco_sk_list.head) { + str += sprintf(str, "%s %s %d\n", + batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), + sk->sk_state); + } -static void sco_seq_stop(struct seq_file *seq, void *e) -{ read_unlock_bh(&sco_sk_list.lock); -} - -static int sco_seq_show(struct seq_file *seq, void *e) -{ - struct sock *sk = e; - seq_printf(seq, "%s %s %d\n", - batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), sk->sk_state); - return 0; -} -static struct seq_operations sco_seq_ops = { - .start = sco_seq_start, - .next = sco_seq_next, - .stop = sco_seq_stop, - .show = sco_seq_show -}; - -static int sco_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &sco_seq_ops); + return (str - buf); } -static struct file_operations sco_seq_fops = { - .owner = THIS_MODULE, - .open = sco_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static int __init sco_proc_init(void) -{ - struct proc_dir_entry *p = create_proc_entry("sco", S_IRUGO, proc_bt); - if (!p) - return -ENOMEM; - p->owner = THIS_MODULE; - p->proc_fops = &sco_seq_fops; - return 0; -} - -static void __exit sco_proc_cleanup(void) -{ - remove_proc_entry("sco", proc_bt); -} - -#else /* CONFIG_PROC_FS */ - -static int __init sco_proc_init(void) -{ - return 0; -} - -static void __exit sco_proc_cleanup(void) -{ - return; -} -#endif /* CONFIG_PROC_FS */ +static CLASS_ATTR(sco, S_IRUGO, sco_sysfs_show, NULL); static struct proto_ops sco_sock_ops = { .family = PF_BLUETOOTH, @@ -1035,7 +969,7 @@ static int __init sco_init(void) goto error; } - sco_proc_init(); + class_create_file(&bt_class, &class_attr_sco); BT_INFO("SCO (Voice Link) ver %s", VERSION); BT_INFO("SCO socket layer initialized"); @@ -1049,7 +983,7 @@ static int __init sco_init(void) static void __exit sco_exit(void) { - sco_proc_cleanup(); + class_remove_file(&bt_class, &class_attr_sco); if (bt_sock_unregister(BTPROTO_SCO) < 0) BT_ERR("SCO socket unregistration failed"); diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c index db098ff3cd6a7509b58cec0b45da50e6cf76673e..cb530eef0e3990f2f3fce1076b2660b5109555b7 100644 --- a/net/core/dev_mcast.c +++ b/net/core/dev_mcast.c @@ -194,8 +194,7 @@ int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl) done: spin_unlock_bh(&dev->xmit_lock); - if (dmi1) - kfree(dmi1); + kfree(dmi1); return err; } diff --git a/net/core/sock.c b/net/core/sock.c index 9602ceb3bac9a2d33eec5ce1bc0cb8a55340203b..13cc3be4f056fb92f86cd660b6dcd29ba88ed30d 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1242,8 +1242,7 @@ static void sock_def_write_space(struct sock *sk) static void sock_def_destruct(struct sock *sk) { - if (sk->sk_protinfo) - kfree(sk->sk_protinfo); + kfree(sk->sk_protinfo); } void sk_send_sigurg(struct sock *sk) diff --git a/net/core/stream.c b/net/core/stream.c index ac9edfdf874214432ba7c81978035c5960debba1..15bfd03e8024e95c9804c20f29d09cd8e5abc985 100644 --- a/net/core/stream.c +++ b/net/core/stream.c @@ -52,8 +52,9 @@ int sk_stream_wait_connect(struct sock *sk, long *timeo_p) { struct task_struct *tsk = current; DEFINE_WAIT(wait); + int done; - while (1) { + do { if (sk->sk_err) return sock_error(sk); if ((1 << sk->sk_state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) @@ -65,13 +66,12 @@ int sk_stream_wait_connect(struct sock *sk, long *timeo_p) prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); sk->sk_write_pending++; - if (sk_wait_event(sk, timeo_p, - !((1 << sk->sk_state) & - ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)))) - break; + done = sk_wait_event(sk, timeo_p, + !((1 << sk->sk_state) & + ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))); finish_wait(sk->sk_sleep, &wait); sk->sk_write_pending--; - } + } while (!done); return 0; } diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 6298cf58ff9e88b329ddba654f3c4ad79b500bcc..ca03521112c52bfa4e279b351aee54c980105e71 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -31,8 +31,6 @@ struct inet_hashinfo __cacheline_aligned dccp_hashinfo = { .lhash_lock = RW_LOCK_UNLOCKED, .lhash_users = ATOMIC_INIT(0), .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(dccp_hashinfo.lhash_wait), - .portalloc_lock = SPIN_LOCK_UNLOCKED, - .port_rover = 1024 - 1, }; EXPORT_SYMBOL_GPL(dccp_hashinfo); @@ -125,36 +123,15 @@ static int dccp_v4_hash_connect(struct sock *sk) int ret; if (snum == 0) { - int rover; int low = sysctl_local_port_range[0]; int high = sysctl_local_port_range[1]; int remaining = (high - low) + 1; + int rover = net_random() % (high - low) + low; struct hlist_node *node; struct inet_timewait_sock *tw = NULL; local_bh_disable(); - - /* TODO. Actually it is not so bad idea to remove - * dccp_hashinfo.portalloc_lock before next submission to - * Linus. - * As soon as we touch this place at all it is time to think. - * - * Now it protects single _advisory_ variable - * dccp_hashinfo.port_rover, hence it is mostly useless. - * Code will work nicely if we just delete it, but - * I am afraid in contented case it will work not better or - * even worse: another cpu just will hit the same bucket - * and spin there. - * So some cpu salt could remove both contention and - * memory pingpong. Any ideas how to do this in a nice way? - */ - spin_lock(&dccp_hashinfo.portalloc_lock); - rover = dccp_hashinfo.port_rover; - do { - rover++; - if ((rover < low) || (rover > high)) - rover = low; head = &dccp_hashinfo.bhash[inet_bhashfn(rover, dccp_hashinfo.bhash_size)]; spin_lock(&head->lock); @@ -187,9 +164,9 @@ static int dccp_v4_hash_connect(struct sock *sk) next_port: spin_unlock(&head->lock); + if (++rover > high) + rover = low; } while (--remaining > 0); - dccp_hashinfo.port_rover = rover; - spin_unlock(&dccp_hashinfo.portalloc_lock); local_bh_enable(); @@ -197,9 +174,6 @@ static int dccp_v4_hash_connect(struct sock *sk) ok: /* All locks still held and bhs disabled */ - dccp_hashinfo.port_rover = rover; - spin_unlock(&dccp_hashinfo.portalloc_lock); - inet_bind_hash(sk, tb, rover); if (sk_unhashed(sk)) { inet_sk(sk)->sport = htons(rover); @@ -1289,10 +1263,8 @@ static int dccp_v4_destroy_sock(struct sock *sk) if (inet_csk(sk)->icsk_bind_hash != NULL) inet_put_port(&dccp_hashinfo, sk); - if (dp->dccps_service_list != NULL) { - kfree(dp->dccps_service_list); - dp->dccps_service_list = NULL; - } + kfree(dp->dccps_service_list); + dp->dccps_service_list = NULL; ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk); ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk); diff --git a/net/dccp/proto.c b/net/dccp/proto.c index a021c3422f6773d3d5643e9b7e9ccdc475511951..e0ace7cbb9960cc5d145304b7ce8bf8a8a5de2a2 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -238,8 +238,7 @@ static int dccp_setsockopt_service(struct sock *sk, const u32 service, lock_sock(sk); dp->dccps_service = service; - if (dp->dccps_service_list != NULL) - kfree(dp->dccps_service_list); + kfree(dp->dccps_service_list); dp->dccps_service_list = sl; release_sock(sk); diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c index eeba56f99323b0cf82131b0fa3f6c9614dc2927e..6f8b5658cb4e9caf0c9d84438f02dcdd37348b66 100644 --- a/net/decnet/dn_table.c +++ b/net/decnet/dn_table.c @@ -784,16 +784,14 @@ struct dn_fib_table *dn_fib_get_table(int n, int create) static void dn_fib_del_tree(int n) { - struct dn_fib_table *t; + struct dn_fib_table *t; - write_lock(&dn_fib_tables_lock); - t = dn_fib_tables[n]; - dn_fib_tables[n] = NULL; - write_unlock(&dn_fib_tables_lock); + write_lock(&dn_fib_tables_lock); + t = dn_fib_tables[n]; + dn_fib_tables[n] = NULL; + write_unlock(&dn_fib_tables_lock); - if (t) { - kfree(t); - } + kfree(t); } struct dn_fib_table *dn_fib_empty_table(void) diff --git a/net/ethernet/pe2.c b/net/ethernet/pe2.c index 98a494be6039452700e39a227fcf7a23d69ab3f6..9d57b4fb6440c74532856b9fc4160821aa19d2b8 100644 --- a/net/ethernet/pe2.c +++ b/net/ethernet/pe2.c @@ -32,8 +32,7 @@ struct datalink_proto *make_EII_client(void) void destroy_EII_client(struct datalink_proto *dl) { - if (dl) - kfree(dl); + kfree(dl); } EXPORT_SYMBOL(destroy_EII_client); diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c index f3b6aa3be63878a08708cf5542f654117882527e..20cc580a07e0dcec958aeaf22387e6fe008f7800 100644 --- a/net/ieee80211/ieee80211_crypt.c +++ b/net/ieee80211/ieee80211_crypt.c @@ -12,7 +12,6 @@ */ #include -#include #include #include #include diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c index 05a853c13012836fe518cf965049e84ce1f59b0a..4702217285032c57dda4ea1b6f1494bd12e64af2 100644 --- a/net/ieee80211/ieee80211_crypt_ccmp.c +++ b/net/ieee80211/ieee80211_crypt_ccmp.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index 2e34f29b7956f46c4f81fef31953af4953fd2752..e0988320efbfef0ad976437c83c7dac6357e9f7a 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c index 7c08ed2f2628f4dd439465f0abdd90358a8e39a9..073aebdf0f67cff356d56c50efd0a878a123dd0f 100644 --- a/net/ieee80211/ieee80211_crypt_wep.c +++ b/net/ieee80211/ieee80211_crypt_wep.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/net/ieee80211/ieee80211_geo.c b/net/ieee80211/ieee80211_geo.c index c4b54ef8f6d5d4e6e8e2a6c912028f9a44794669..610cc5cbc2524e7fe3c38082ae44f93d7a7e7e1e 100644 --- a/net/ieee80211/ieee80211_geo.c +++ b/net/ieee80211/ieee80211_geo.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c index f66d792cd204b068976f7655e625cb4a21d99978..321287bc887f2808438af09f9e955d78828063bd 100644 --- a/net/ieee80211/ieee80211_module.c +++ b/net/ieee80211/ieee80211_module.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index ce694cf5c1604a945c491446241debf8d3ee9666..6ad88218f57300ca3879c92e82f03e5a3bb1385b 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index 95ccbadbf55b49cd2809ccd6b4d11ed510c7f8e9..445f206e65e0ea4b73327b1734d89d8639590958 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index a9d84f93442c9560a8e7050a60292876b09bd508..eaa150c33b0403204fa22224d6434e5c45f7695c 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -147,8 +147,7 @@ void inet_sock_destruct(struct sock *sk) BUG_TRAP(!sk->sk_wmem_queued); BUG_TRAP(!sk->sk_forward_alloc); - if (inet->opt) - kfree(inet->opt); + kfree(inet->opt); dst_release(sk->sk_dst_cache); sk_refcnt_debug_dec(sk); } diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 990633c09dfe4ccdf345d06281880117b57c7906..2267c1fad879f6d047d86a52d572b270d3af5af0 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -266,8 +266,7 @@ int ip_rt_ioctl(unsigned int cmd, void __user *arg) if (tb) err = tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL); } - if (rta.rta_mx) - kfree(rta.rta_mx); + kfree(rta.rta_mx); } rtnl_unlock(); return err; diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 94468a76c5b4e0f70bca33afcf0c5b95cf654a7c..3fe021f1a566ad40353fa8a92e1c6d049409a7ad 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -78,17 +78,9 @@ int inet_csk_get_port(struct inet_hashinfo *hashinfo, int low = sysctl_local_port_range[0]; int high = sysctl_local_port_range[1]; int remaining = (high - low) + 1; - int rover; + int rover = net_random() % (high - low) + low; - spin_lock(&hashinfo->portalloc_lock); - if (hashinfo->port_rover < low) - rover = low; - else - rover = hashinfo->port_rover; do { - rover++; - if (rover > high) - rover = low; head = &hashinfo->bhash[inet_bhashfn(rover, hashinfo->bhash_size)]; spin_lock(&head->lock); inet_bind_bucket_for_each(tb, node, &head->chain) @@ -97,9 +89,9 @@ int inet_csk_get_port(struct inet_hashinfo *hashinfo, break; next: spin_unlock(&head->lock); + if (++rover > high) + rover = low; } while (--remaining > 0); - hashinfo->port_rover = rover; - spin_unlock(&hashinfo->portalloc_lock); /* Exhausted local port range during search? It is not * possible for us to be holding one of the bind hash diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index bce4e875193be1d596c4c607ab42e9e1f966513f..dbe12da8d8b3960fe7dc796de97eae2546e1528d 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -510,8 +510,7 @@ static int ip_options_get_finish(struct ip_options **optp, kfree(opt); return -EINVAL; } - if (*optp) - kfree(*optp); + kfree(*optp); *optp = opt; return 0; } diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 17758234a3e351e4787824bf1e1cda3dc72dfded..11c2f68254f0a8a04602222216a03578c0327d20 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -353,7 +353,8 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok) ip_options_build(skb, opt, inet->daddr, rt, 0); } - ip_select_ident_more(iph, &rt->u.dst, sk, skb_shinfo(skb)->tso_segs); + ip_select_ident_more(iph, &rt->u.dst, sk, + (skb_shinfo(skb)->tso_segs ?: 1) - 1); /* Add an IP checksum. */ ip_send_check(iph); @@ -1262,10 +1263,8 @@ int ip_push_pending_frames(struct sock *sk) out: inet->cork.flags &= ~IPCORK_OPT; - if (inet->cork.opt) { - kfree(inet->cork.opt); - inet->cork.opt = NULL; - } + kfree(inet->cork.opt); + inet->cork.opt = NULL; if (inet->cork.rt) { ip_rt_put(inet->cork.rt); inet->cork.rt = NULL; @@ -1289,10 +1288,8 @@ void ip_flush_pending_frames(struct sock *sk) kfree_skb(skb); inet->cork.flags &= ~IPCORK_OPT; - if (inet->cork.opt) { - kfree(inet->cork.opt); - inet->cork.opt = NULL; - } + kfree(inet->cork.opt); + inet->cork.opt = NULL; if (inet->cork.rt) { ip_rt_put(inet->cork.rt); inet->cork.rt = NULL; diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 2f0b47da5b37e3b3c0c44235355e704958cba8a3..4f2d8725730958f498b3d319c9e3dca68cd50722 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -202,8 +202,7 @@ int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct s if (ra->sk == sk) { if (on) { write_unlock_bh(&ip_ra_lock); - if (new_ra) - kfree(new_ra); + kfree(new_ra); return -EADDRINUSE; } *rap = ra->next; @@ -446,8 +445,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, #endif } opt = xchg(&inet->opt, opt); - if (opt) - kfree(opt); + kfree(opt); break; } case IP_PKTINFO: @@ -828,10 +826,8 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, err = ip_mc_msfilter(sk, msf, ifindex); mc_msf_out: - if (msf) - kfree(msf); - if (gsf) - kfree(gsf); + kfree(msf); + kfree(gsf); break; } case IP_ROUTER_ALERT: diff --git a/net/ipv4/ipvs/ip_vs_app.c b/net/ipv4/ipvs/ip_vs_app.c index fc6f95aaa96976e27c14d733e09f03888ea31592..d7eb680101c25311233b9195faedca1aa17d812b 100644 --- a/net/ipv4/ipvs/ip_vs_app.c +++ b/net/ipv4/ipvs/ip_vs_app.c @@ -110,8 +110,7 @@ ip_vs_app_inc_new(struct ip_vs_app *app, __u16 proto, __u16 port) return 0; out: - if (inc->timeout_table) - kfree(inc->timeout_table); + kfree(inc->timeout_table); kfree(inc); return ret; } @@ -136,8 +135,7 @@ ip_vs_app_inc_release(struct ip_vs_app *inc) list_del(&inc->a_list); - if (inc->timeout_table != NULL) - kfree(inc->timeout_table); + kfree(inc->timeout_table); kfree(inc); } diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c index 981cc3244ef2724827e9c303a27d2a79a511cb4c..1a0843cd58a9e40d84e03b003ed0984e16763edf 100644 --- a/net/ipv4/ipvs/ip_vs_core.c +++ b/net/ipv4/ipvs/ip_vs_core.c @@ -1009,11 +1009,10 @@ ip_vs_in(unsigned int hooknum, struct sk_buff **pskb, if (sysctl_ip_vs_expire_nodest_conn) { /* try to expire the connection immediately */ ip_vs_conn_expire_now(cp); - } else { - /* don't restart its timer, and silently - drop the packet. */ - __ip_vs_conn_put(cp); } + /* don't restart its timer, and silently + drop the packet. */ + __ip_vs_conn_put(cp); return NF_DROP; } diff --git a/net/ipv4/multipath_wrandom.c b/net/ipv4/multipath_wrandom.c index bd7d75b6abe0a6a7e1ed63d78b5d18becf3eb961..d34a9fa608e0b88dec20adaa567100a5b63c4ee0 100644 --- a/net/ipv4/multipath_wrandom.c +++ b/net/ipv4/multipath_wrandom.c @@ -207,16 +207,12 @@ static void wrandom_select_route(const struct flowi *flp, decision = mpc->rt; last_power = mpc->power; - if (last_mpc) - kfree(last_mpc); - + kfree(last_mpc); last_mpc = mpc; } - if (last_mpc) { - /* concurrent __multipath_flush may lead to !last_mpc */ - kfree(last_mpc); - } + /* concurrent __multipath_flush may lead to !last_mpc */ + kfree(last_mpc); decision->u.dst.__use++; *rp = decision; diff --git a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c index 926a6684643dd0caf3d5378651fbfaf28097bb0c..4108a5e12b3c3d702bcd8211533ac4bee00ea3f7 100644 --- a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c +++ b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c @@ -270,14 +270,10 @@ exp_gre(struct ip_conntrack *master, exp_orig->expectfn = pptp_expectfn; exp_orig->flags = 0; - exp_orig->dir = IP_CT_DIR_ORIGINAL; - /* both expectations are identical apart from tuple */ memcpy(exp_reply, exp_orig, sizeof(*exp_reply)); memcpy(&exp_reply->tuple, &exp_tuples[1], sizeof(exp_reply->tuple)); - exp_reply->dir = !exp_orig->dir; - if (ip_nat_pptp_hook_exp_gre) ret = ip_nat_pptp_hook_exp_gre(exp_orig, exp_reply); else { diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index 166e6069f1212302c16c150fb267161af33ccc0d..82a65043a8ef6a0c1b900a2ef5f282a12e7428ee 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c @@ -815,7 +815,7 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, IPCTNL_MSG_CT_NEW, 1, ct); ip_conntrack_put(ct); if (err <= 0) - goto out; + goto free; err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); if (err < 0) @@ -824,9 +824,9 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, DEBUGP("leaving\n"); return 0; +free: + kfree_skb(skb2); out: - if (skb2) - kfree_skb(skb2); return -1; } @@ -1322,21 +1322,16 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, 1, exp); if (err <= 0) - goto out; + goto free; ip_conntrack_expect_put(exp); - err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); - if (err < 0) - goto free; - - return err; + return netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); +free: + kfree_skb(skb2); out: ip_conntrack_expect_put(exp); -free: - if (skb2) - kfree_skb(skb2); return err; } diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c index c5e3abd24672beb3bf04ccef61a2d8b3582b79fd..762f4d93936b93497a31c77415a77bc6b6b78568 100644 --- a/net/ipv4/netfilter/ip_nat_core.c +++ b/net/ipv4/netfilter/ip_nat_core.c @@ -66,10 +66,8 @@ ip_nat_proto_find_get(u_int8_t protonum) * removed until we've grabbed the reference */ preempt_disable(); p = __ip_nat_proto_find(protonum); - if (p) { - if (!try_module_get(p->me)) - p = &ip_nat_unknown_protocol; - } + if (!try_module_get(p->me)) + p = &ip_nat_unknown_protocol; preempt_enable(); return p; diff --git a/net/ipv4/netfilter/ip_nat_helper_pptp.c b/net/ipv4/netfilter/ip_nat_helper_pptp.c index 3cdd0684d30d32242963309f35941c123f041504..ee6ab74ad3a91e7c03451c37873a3597e5fa4764 100644 --- a/net/ipv4/netfilter/ip_nat_helper_pptp.c +++ b/net/ipv4/netfilter/ip_nat_helper_pptp.c @@ -216,6 +216,7 @@ pptp_exp_gre(struct ip_conntrack_expect *expect_orig, expect_orig->saved_proto.gre.key = htons(nat_pptp_info->pac_call_id); expect_orig->tuple.src.u.gre.key = htons(nat_pptp_info->pns_call_id); expect_orig->tuple.dst.u.gre.key = htons(ct_pptp_info->pac_call_id); + expect_orig->dir = IP_CT_DIR_ORIGINAL; inv_t.src.ip = reply_t->src.ip; inv_t.dst.ip = reply_t->dst.ip; inv_t.src.u.gre.key = htons(nat_pptp_info->pac_call_id); @@ -233,6 +234,7 @@ pptp_exp_gre(struct ip_conntrack_expect *expect_orig, expect_reply->saved_proto.gre.key = htons(nat_pptp_info->pns_call_id); expect_reply->tuple.src.u.gre.key = htons(nat_pptp_info->pac_call_id); expect_reply->tuple.dst.u.gre.key = htons(ct_pptp_info->pns_call_id); + expect_reply->dir = IP_CT_DIR_REPLY; inv_t.src.ip = orig_t->src.ip; inv_t.dst.ip = orig_t->dst.ip; inv_t.src.u.gre.key = htons(nat_pptp_info->pns_call_id); diff --git a/net/ipv4/netfilter/ip_nat_proto_gre.c b/net/ipv4/netfilter/ip_nat_proto_gre.c index 7c12854016723891b9077711abcf863c9a42d404..f7cad7cf1aec2f48e0633c66dbf541ad25a0a775 100644 --- a/net/ipv4/netfilter/ip_nat_proto_gre.c +++ b/net/ipv4/netfilter/ip_nat_proto_gre.c @@ -139,8 +139,8 @@ gre_manip_pkt(struct sk_buff **pskb, break; case GRE_VERSION_PPTP: DEBUGP("call_id -> 0x%04x\n", - ntohl(tuple->dst.u.gre.key)); - pgreh->call_id = htons(ntohl(tuple->dst.u.gre.key)); + ntohs(tuple->dst.u.gre.key)); + pgreh->call_id = tuple->dst.u.gre.key; break; default: DEBUGP("can't nat unknown GRE version\n"); diff --git a/net/ipv4/netfilter/ip_nat_proto_unknown.c b/net/ipv4/netfilter/ip_nat_proto_unknown.c index 99bbef56f84e9ff346b856760e4db18319d3d78f..f0099a646a0b430488f9ba625486585ae04fa8b6 100644 --- a/net/ipv4/netfilter/ip_nat_proto_unknown.c +++ b/net/ipv4/netfilter/ip_nat_proto_unknown.c @@ -62,7 +62,7 @@ unknown_print_range(char *buffer, const struct ip_nat_range *range) struct ip_nat_protocol ip_nat_unknown_protocol = { .name = "unknown", - .me = THIS_MODULE, + /* .me isn't set: getting a ref to this cannot fail. */ .manip_pkt = unknown_manip_pkt, .in_range = unknown_in_range, .unique_tuple = unknown_unique_tuple, diff --git a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c index 93b2c5111bb2338b15f765ed604866d4a860310b..8acb7ed40b47f7c5e25adae81f774601ffaa15ba 100644 --- a/net/ipv4/netfilter/ip_nat_snmp_basic.c +++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c @@ -1161,8 +1161,7 @@ static int snmp_parse_mangle(unsigned char *msg, if (!snmp_object_decode(&ctx, obj)) { if (*obj) { - if ((*obj)->id) - kfree((*obj)->id); + kfree((*obj)->id); kfree(*obj); } kfree(obj); diff --git a/net/ipv4/netfilter/ipt_CONNMARK.c b/net/ipv4/netfilter/ipt_CONNMARK.c index 134638021339d8126885231fa7abc896ecfb2266..05d66ab59424fc0bf0ae2f6729d6bb10ac6b52ab 100644 --- a/net/ipv4/netfilter/ipt_CONNMARK.c +++ b/net/ipv4/netfilter/ipt_CONNMARK.c @@ -109,6 +109,7 @@ static struct ipt_target ipt_connmark_reg = { static int __init init(void) { + need_ip_conntrack(); return ipt_register_target(&ipt_connmark_reg); } diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index f3f0013a95804808d1522e89192b0beaefa91a30..72b7c22e1ea5aa23306e69b26857d78224e841b0 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2112,7 +2112,6 @@ void __init tcp_init(void) sysctl_tcp_max_orphans >>= (3 - order); sysctl_max_syn_backlog = 128; } - tcp_hashinfo.port_rover = sysctl_local_port_range[0] - 1; sysctl_tcp_mem[0] = 768 << order; sysctl_tcp_mem[1] = 1024 << order; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index c85819d8474bba64dc433ca4fd93684bee7421c5..634dabb558fd6f5942e709c99846f83985db8b41 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -93,8 +93,6 @@ struct inet_hashinfo __cacheline_aligned tcp_hashinfo = { .lhash_lock = RW_LOCK_UNLOCKED, .lhash_users = ATOMIC_INIT(0), .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(tcp_hashinfo.lhash_wait), - .portalloc_lock = SPIN_LOCK_UNLOCKED, - .port_rover = 1024 - 1, }; static int tcp_v4_get_port(struct sock *sk, unsigned short snum) @@ -825,8 +823,7 @@ static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req, */ static void tcp_v4_reqsk_destructor(struct request_sock *req) { - if (inet_rsk(req)->opt) - kfree(inet_rsk(req)->opt); + kfree(inet_rsk(req)->opt); } static inline void syn_flood_warning(struct sk_buff *skb) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 2c5f57299d63b1f2badbd056286513f7ef51e646..b7a5f51238b3958f88bc18adfac17704d3aa0bf7 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -35,6 +35,9 @@ * YOSHIFUJI Hideaki @USAGI : ARCnet support * YOSHIFUJI Hideaki @USAGI : convert /proc/net/if_inet6 to * seq_file. + * YOSHIFUJI Hideaki @USAGI : improved source address + * selection; consider scope, + * status etc. */ #include @@ -193,46 +196,51 @@ const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; #endif const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; -int ipv6_addr_type(const struct in6_addr *addr) +#define IPV6_ADDR_SCOPE_TYPE(scope) ((scope) << 16) + +static inline unsigned ipv6_addr_scope2type(unsigned scope) +{ + switch(scope) { + case IPV6_ADDR_SCOPE_NODELOCAL: + return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_NODELOCAL) | + IPV6_ADDR_LOOPBACK); + case IPV6_ADDR_SCOPE_LINKLOCAL: + return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL) | + IPV6_ADDR_LINKLOCAL); + case IPV6_ADDR_SCOPE_SITELOCAL: + return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL) | + IPV6_ADDR_SITELOCAL); + } + return IPV6_ADDR_SCOPE_TYPE(scope); +} + +int __ipv6_addr_type(const struct in6_addr *addr) { - int type; u32 st; st = addr->s6_addr32[0]; - if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) { - type = IPV6_ADDR_MULTICAST; - - switch((st & htonl(0x00FF0000))) { - case __constant_htonl(0x00010000): - type |= IPV6_ADDR_LOOPBACK; - break; - - case __constant_htonl(0x00020000): - type |= IPV6_ADDR_LINKLOCAL; - break; - - case __constant_htonl(0x00050000): - type |= IPV6_ADDR_SITELOCAL; - break; - }; - return type; - } - - type = IPV6_ADDR_UNICAST; - /* Consider all addresses with the first three bits different of - 000 and 111 as finished. + 000 and 111 as unicasts. */ if ((st & htonl(0xE0000000)) != htonl(0x00000000) && (st & htonl(0xE0000000)) != htonl(0xE0000000)) - return type; - - if ((st & htonl(0xFFC00000)) == htonl(0xFE800000)) - return (IPV6_ADDR_LINKLOCAL | type); + return (IPV6_ADDR_UNICAST | + IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); + + if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) { + /* multicast */ + /* addr-select 3.1 */ + return (IPV6_ADDR_MULTICAST | + ipv6_addr_scope2type(IPV6_ADDR_MC_SCOPE(addr))); + } + if ((st & htonl(0xFFC00000)) == htonl(0xFE800000)) + return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST | + IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL)); /* addr-select 3.1 */ if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000)) - return (IPV6_ADDR_SITELOCAL | type); + return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST | + IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL)); /* addr-select 3.1 */ if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) { if (addr->s6_addr32[2] == 0) { @@ -240,24 +248,20 @@ int ipv6_addr_type(const struct in6_addr *addr) return IPV6_ADDR_ANY; if (addr->s6_addr32[3] == htonl(0x00000001)) - return (IPV6_ADDR_LOOPBACK | type); + return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST | + IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL)); /* addr-select 3.4 */ - return (IPV6_ADDR_COMPATv4 | type); + return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST | + IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.3 */ } if (addr->s6_addr32[2] == htonl(0x0000ffff)) - return IPV6_ADDR_MAPPED; + return (IPV6_ADDR_MAPPED | + IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.3 */ } - st &= htonl(0xFF000000); - if (st == 0) - return IPV6_ADDR_RESERVED; - st &= htonl(0xFE000000); - if (st == htonl(0x02000000)) - return IPV6_ADDR_RESERVED; /* for NSAP */ - if (st == htonl(0x04000000)) - return IPV6_ADDR_RESERVED; /* for IPX */ - return type; + return (IPV6_ADDR_RESERVED | + IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.4 */ } static void addrconf_del_timer(struct inet6_ifaddr *ifp) @@ -805,138 +809,274 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i #endif /* - * Choose an appropriate source address - * should do: - * i) get an address with an appropriate scope - * ii) see if there is a specific route for the destination and use - * an address of the attached interface - * iii) don't use deprecated addresses + * Choose an appropriate source address (RFC3484) */ -static int inline ipv6_saddr_pref(const struct inet6_ifaddr *ifp, u8 invpref) +struct ipv6_saddr_score { + int addr_type; + unsigned int attrs; + int matchlen; + unsigned int scope; + unsigned int rule; +}; + +#define IPV6_SADDR_SCORE_LOCAL 0x0001 +#define IPV6_SADDR_SCORE_PREFERRED 0x0004 +#define IPV6_SADDR_SCORE_HOA 0x0008 +#define IPV6_SADDR_SCORE_OIF 0x0010 +#define IPV6_SADDR_SCORE_LABEL 0x0020 +#define IPV6_SADDR_SCORE_PRIVACY 0x0040 + +static int inline ipv6_saddr_preferred(int type) { - int pref; - pref = ifp->flags&IFA_F_DEPRECATED ? 0 : 2; -#ifdef CONFIG_IPV6_PRIVACY - pref |= (ifp->flags^invpref)&IFA_F_TEMPORARY ? 0 : 1; -#endif - return pref; + if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4| + IPV6_ADDR_LOOPBACK|IPV6_ADDR_RESERVED)) + return 1; + return 0; } -#ifdef CONFIG_IPV6_PRIVACY -#define IPV6_GET_SADDR_MAXSCORE(score) ((score) == 3) -#else -#define IPV6_GET_SADDR_MAXSCORE(score) (score) -#endif +/* static matching label */ +static int inline ipv6_saddr_label(const struct in6_addr *addr, int type) +{ + /* + * prefix (longest match) label + * ----------------------------- + * ::1/128 0 + * ::/0 1 + * 2002::/16 2 + * ::/96 3 + * ::ffff:0:0/96 4 + */ + if (type & IPV6_ADDR_LOOPBACK) + return 0; + else if (type & IPV6_ADDR_COMPATv4) + return 3; + else if (type & IPV6_ADDR_MAPPED) + return 4; + else if (addr->s6_addr16[0] == htons(0x2002)) + return 2; + return 1; +} -int ipv6_dev_get_saddr(struct net_device *dev, +int ipv6_dev_get_saddr(struct net_device *daddr_dev, struct in6_addr *daddr, struct in6_addr *saddr) { - struct inet6_ifaddr *ifp = NULL; - struct inet6_ifaddr *match = NULL; - struct inet6_dev *idev; - int scope; - int err; - int hiscore = -1, score; + struct ipv6_saddr_score hiscore; + struct inet6_ifaddr *ifa_result = NULL; + int daddr_type = __ipv6_addr_type(daddr); + int daddr_scope = __ipv6_addr_src_scope(daddr_type); + u32 daddr_label = ipv6_saddr_label(daddr, daddr_type); + struct net_device *dev; - scope = ipv6_addr_scope(daddr); + memset(&hiscore, 0, sizeof(hiscore)); - /* - * known dev - * search dev and walk through dev addresses - */ + read_lock(&dev_base_lock); + read_lock(&addrconf_lock); - if (dev) { - if (dev->flags & IFF_LOOPBACK) - scope = IFA_HOST; + for (dev = dev_base; dev; dev=dev->next) { + struct inet6_dev *idev; + struct inet6_ifaddr *ifa; + + /* Rule 0: Candidate Source Address (section 4) + * - multicast and link-local destination address, + * the set of candidate source address MUST only + * include addresses assigned to interfaces + * belonging to the same link as the outgoing + * interface. + * (- For site-local destination addresses, the + * set of candidate source addresses MUST only + * include addresses assigned to interfaces + * belonging to the same site as the outgoing + * interface.) + */ + if ((daddr_type & IPV6_ADDR_MULTICAST || + daddr_scope <= IPV6_ADDR_SCOPE_LINKLOCAL) && + daddr_dev && dev != daddr_dev) + continue; - read_lock(&addrconf_lock); idev = __in6_dev_get(dev); - if (idev) { - read_lock_bh(&idev->lock); - for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { - if (ifp->scope == scope) { - if (ifp->flags&IFA_F_TENTATIVE) - continue; -#ifdef CONFIG_IPV6_PRIVACY - score = ipv6_saddr_pref(ifp, idev->cnf.use_tempaddr > 1 ? IFA_F_TEMPORARY : 0); -#else - score = ipv6_saddr_pref(ifp, 0); -#endif - if (score <= hiscore) - continue; + if (!idev) + continue; - if (match) - in6_ifa_put(match); - match = ifp; - hiscore = score; - in6_ifa_hold(ifp); + read_lock_bh(&idev->lock); + for (ifa = idev->addr_list; ifa; ifa = ifa->if_next) { + struct ipv6_saddr_score score; - if (IPV6_GET_SADDR_MAXSCORE(score)) { - read_unlock_bh(&idev->lock); - read_unlock(&addrconf_lock); - goto out; - } + score.addr_type = __ipv6_addr_type(&ifa->addr); + + /* Rule 0: Candidate Source Address (section 4) + * - In any case, anycast addresses, multicast + * addresses, and the unspecified address MUST + * NOT be included in a candidate set. + */ + if (unlikely(score.addr_type == IPV6_ADDR_ANY || + score.addr_type & IPV6_ADDR_MULTICAST)) { + LIMIT_NETDEBUG(KERN_DEBUG + "ADDRCONF: unspecified / multicast address" + "assigned as unicast address on %s", + dev->name); + continue; + } + + score.attrs = 0; + score.matchlen = 0; + score.scope = 0; + score.rule = 0; + + if (ifa_result == NULL) { + /* record it if the first available entry */ + goto record_it; + } + + /* Rule 1: Prefer same address */ + if (hiscore.rule < 1) { + if (ipv6_addr_equal(&ifa_result->addr, daddr)) + hiscore.attrs |= IPV6_SADDR_SCORE_LOCAL; + hiscore.rule++; + } + if (ipv6_addr_equal(&ifa->addr, daddr)) { + score.attrs |= IPV6_SADDR_SCORE_LOCAL; + if (!(hiscore.attrs & IPV6_SADDR_SCORE_LOCAL)) { + score.rule = 1; + goto record_it; } + } else { + if (hiscore.attrs & IPV6_SADDR_SCORE_LOCAL) + continue; } - read_unlock_bh(&idev->lock); - } - read_unlock(&addrconf_lock); - } - if (scope == IFA_LINK) - goto out; + /* Rule 2: Prefer appropriate scope */ + if (hiscore.rule < 2) { + hiscore.scope = __ipv6_addr_src_scope(hiscore.addr_type); + hiscore.rule++; + } + score.scope = __ipv6_addr_src_scope(score.addr_type); + if (hiscore.scope < score.scope) { + if (hiscore.scope < daddr_scope) { + score.rule = 2; + goto record_it; + } else + continue; + } else if (score.scope < hiscore.scope) { + if (score.scope < daddr_scope) + continue; + else { + score.rule = 2; + goto record_it; + } + } - /* - * dev == NULL or search failed for specified dev - */ + /* Rule 3: Avoid deprecated address */ + if (hiscore.rule < 3) { + if (ipv6_saddr_preferred(hiscore.addr_type) || + !(ifa_result->flags & IFA_F_DEPRECATED)) + hiscore.attrs |= IPV6_SADDR_SCORE_PREFERRED; + hiscore.rule++; + } + if (ipv6_saddr_preferred(score.addr_type) || + !(ifa->flags & IFA_F_DEPRECATED)) { + score.attrs |= IPV6_SADDR_SCORE_PREFERRED; + if (!(hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)) { + score.rule = 3; + goto record_it; + } + } else { + if (hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED) + continue; + } - read_lock(&dev_base_lock); - read_lock(&addrconf_lock); - for (dev = dev_base; dev; dev=dev->next) { - idev = __in6_dev_get(dev); - if (idev) { - read_lock_bh(&idev->lock); - for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { - if (ifp->scope == scope) { - if (ifp->flags&IFA_F_TENTATIVE) - continue; -#ifdef CONFIG_IPV6_PRIVACY - score = ipv6_saddr_pref(ifp, idev->cnf.use_tempaddr > 1 ? IFA_F_TEMPORARY : 0); -#else - score = ipv6_saddr_pref(ifp, 0); -#endif - if (score <= hiscore) - continue; + /* Rule 4: Prefer home address -- not implemented yet */ - if (match) - in6_ifa_put(match); - match = ifp; - hiscore = score; - in6_ifa_hold(ifp); + /* Rule 5: Prefer outgoing interface */ + if (hiscore.rule < 5) { + if (daddr_dev == NULL || + daddr_dev == ifa_result->idev->dev) + hiscore.attrs |= IPV6_SADDR_SCORE_OIF; + hiscore.rule++; + } + if (daddr_dev == NULL || + daddr_dev == ifa->idev->dev) { + score.attrs |= IPV6_SADDR_SCORE_OIF; + if (!(hiscore.attrs & IPV6_SADDR_SCORE_OIF)) { + score.rule = 5; + goto record_it; + } + } else { + if (hiscore.attrs & IPV6_SADDR_SCORE_OIF) + continue; + } - if (IPV6_GET_SADDR_MAXSCORE(score)) { - read_unlock_bh(&idev->lock); - goto out_unlock_base; - } + /* Rule 6: Prefer matching label */ + if (hiscore.rule < 6) { + if (ipv6_saddr_label(&ifa_result->addr, hiscore.addr_type) == daddr_label) + hiscore.attrs |= IPV6_SADDR_SCORE_LABEL; + hiscore.rule++; + } + if (ipv6_saddr_label(&ifa->addr, score.addr_type) == daddr_label) { + score.attrs |= IPV6_SADDR_SCORE_LABEL; + if (!(hiscore.attrs & IPV6_SADDR_SCORE_LABEL)) { + score.rule = 6; + goto record_it; + } + } else { + if (hiscore.attrs & IPV6_SADDR_SCORE_LABEL) + continue; + } + + /* Rule 7: Prefer public address + * Note: prefer temprary address if use_tempaddr >= 2 + */ + if (hiscore.rule < 7) { + if ((!(ifa_result->flags & IFA_F_TEMPORARY)) ^ + (ifa_result->idev->cnf.use_tempaddr >= 2)) + hiscore.attrs |= IPV6_SADDR_SCORE_PRIVACY; + hiscore.rule++; + } + if ((!(ifa->flags & IFA_F_TEMPORARY)) ^ + (ifa->idev->cnf.use_tempaddr >= 2)) { + score.attrs |= IPV6_SADDR_SCORE_PRIVACY; + if (!(hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY)) { + score.rule = 7; + goto record_it; } + } else { + if (hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY) + continue; } - read_unlock_bh(&idev->lock); + + /* Rule 8: Use longest matching prefix */ + if (hiscore.rule < 8) + hiscore.matchlen = ipv6_addr_diff(&ifa_result->addr, daddr); + score.rule++; + score.matchlen = ipv6_addr_diff(&ifa->addr, daddr); + if (score.matchlen > hiscore.matchlen) { + score.rule = 8; + goto record_it; + } +#if 0 + else if (score.matchlen < hiscore.matchlen) + continue; +#endif + + /* Final Rule: choose first available one */ + continue; +record_it: + if (ifa_result) + in6_ifa_put(ifa_result); + in6_ifa_hold(ifa); + ifa_result = ifa; + hiscore = score; } + read_unlock_bh(&idev->lock); } - -out_unlock_base: read_unlock(&addrconf_lock); read_unlock(&dev_base_lock); -out: - err = -EADDRNOTAVAIL; - if (match) { - ipv6_addr_copy(saddr, &match->addr); - err = 0; - in6_ifa_put(match); - } - - return err; + if (!ifa_result) + return -EADDRNOTAVAIL; + + ipv6_addr_copy(saddr, &ifa_result->addr); + in6_ifa_put(ifa_result); + return 0; } @@ -2950,8 +3090,7 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, nlmsg_failure: rtattr_failure: - if (array) - kfree(array); + kfree(array); skb_trim(skb, b - skb->data); return -1; } diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 4fcc5a7acf6e446ce2715df397d37d78b3b34354..1bf6d9a769e61fa2a54a1838c9f26a0aaf502127 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -127,56 +127,6 @@ static __inline__ int addr_bit_set(void *token, int fn_bit) return htonl(1 << ((~fn_bit)&0x1F)) & addr[fn_bit>>5]; } -/* - * find the first different bit between two addresses - * length of address must be a multiple of 32bits - */ - -static __inline__ int addr_diff(void *token1, void *token2, int addrlen) -{ - __u32 *a1 = token1; - __u32 *a2 = token2; - int i; - - addrlen >>= 2; - - for (i = 0; i < addrlen; i++) { - __u32 xb; - - xb = a1[i] ^ a2[i]; - - if (xb) { - int j = 31; - - xb = ntohl(xb); - - while ((xb & (1 << j)) == 0) - j--; - - return (i * 32 + 31 - j); - } - } - - /* - * we should *never* get to this point since that - * would mean the addrs are equal - * - * However, we do get to it 8) And exacly, when - * addresses are equal 8) - * - * ip route add 1111::/128 via ... - * ip route add 1111::/64 via ... - * and we are here. - * - * Ideally, this function should stop comparison - * at prefix length. It does not, but it is still OK, - * if returned value is greater than prefix length. - * --ANK (980803) - */ - - return addrlen<<5; -} - static __inline__ struct fib6_node * node_alloc(void) { struct fib6_node *fn; @@ -296,11 +246,11 @@ static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr, /* find 1st bit in difference between the 2 addrs. - See comment in addr_diff: bit may be an invalid value, + See comment in __ipv6_addr_diff: bit may be an invalid value, but if it is >= plen, the value is ignored in any case. */ - bit = addr_diff(addr, &key->addr, addrlen); + bit = __ipv6_addr_diff(addr, &key->addr, addrlen); /* * (intermediate)[in] diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 614296a920c6ab189b58607726eea55bee4d0426..dbd9767b32e45ee3373e94ae20afee2b5449a83c 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -587,8 +587,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) skb->next = NULL; } - if (tmp_hdr) - kfree(tmp_hdr); + kfree(tmp_hdr); if (err == 0) { IP6_INC_STATS(IPSTATS_MIB_FRAGOKS); @@ -1186,10 +1185,8 @@ int ip6_push_pending_frames(struct sock *sk) out: inet->cork.flags &= ~IPCORK_OPT; - if (np->cork.opt) { - kfree(np->cork.opt); - np->cork.opt = NULL; - } + kfree(np->cork.opt); + np->cork.opt = NULL; if (np->cork.rt) { dst_release(&np->cork.rt->u.dst); np->cork.rt = NULL; @@ -1214,10 +1211,8 @@ void ip6_flush_pending_frames(struct sock *sk) inet->cork.flags &= ~IPCORK_OPT; - if (np->cork.opt) { - kfree(np->cork.opt); - np->cork.opt = NULL; - } + kfree(np->cork.opt); + np->cork.opt = NULL; if (np->cork.rt) { dst_release(&np->cork.rt->u.dst); np->cork.rt = NULL; diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index cf94372d1af39980b108f3161fd8d94837e0f94c..e6b0e3954c02be114b6bba4f2e14007ff069d1db 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -756,8 +756,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) } ip6_tnl_dst_store(t, dst); - if (opt) - kfree(opt); + kfree(opt); t->recursion--; return 0; @@ -766,8 +765,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) dst_link_failure(skb); tx_err_dst_release: dst_release(dst); - if (opt) - kfree(opt); + kfree(opt); tx_err: stats->tx_errors++; stats->tx_dropped++; diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 85bfbc69b2c3dc716618f6e528dfcb63658e96b5..55917fb170949cfdcd5dd427dc8baf7201c14a17 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -130,8 +130,7 @@ static int ipcomp6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, s out_put_cpu: put_cpu(); out: - if (tmp_hdr) - kfree(tmp_hdr); + kfree(tmp_hdr); if (err) goto error_out; return nexthdr; diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 8567873d0dd85fabd972537eccce7d79d8107611..003fd99ff597d6f4332008c90f6bdcb2b9e80493 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -80,8 +80,7 @@ int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *)) if (ra->sk == sk) { if (sel>=0) { write_unlock_bh(&ip6_ra_lock); - if (new_ra) - kfree(new_ra); + kfree(new_ra); return -EADDRINUSE; } diff --git a/net/ipv6/ipv6_syms.c b/net/ipv6/ipv6_syms.c index 37a4a99c9fe9e1837e5cd82f686ff3736fd94daa..16482785bdfddf322fad974dfe3e407285549ee2 100644 --- a/net/ipv6/ipv6_syms.c +++ b/net/ipv6/ipv6_syms.c @@ -7,7 +7,7 @@ #include #include -EXPORT_SYMBOL(ipv6_addr_type); +EXPORT_SYMBOL(__ipv6_addr_type); EXPORT_SYMBOL(icmpv6_send); EXPORT_SYMBOL(icmpv6_statistics); EXPORT_SYMBOL(icmpv6_err_convert); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index d693cb988b78f99407f529e0a956e099e468c6ef..d746d3b27efb7c84407ff432756e32132f7f49fa 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -114,16 +114,9 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum) int low = sysctl_local_port_range[0]; int high = sysctl_local_port_range[1]; int remaining = (high - low) + 1; - int rover; + int rover = net_random() % (high - low) + low; - spin_lock(&tcp_hashinfo.portalloc_lock); - if (tcp_hashinfo.port_rover < low) - rover = low; - else - rover = tcp_hashinfo.port_rover; - do { rover++; - if (rover > high) - rover = low; + do { head = &tcp_hashinfo.bhash[inet_bhashfn(rover, tcp_hashinfo.bhash_size)]; spin_lock(&head->lock); inet_bind_bucket_for_each(tb, node, &head->chain) @@ -132,9 +125,9 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum) break; next: spin_unlock(&head->lock); + if (++rover > high) + rover = low; } while (--remaining > 0); - tcp_hashinfo.port_rover = rover; - spin_unlock(&tcp_hashinfo.portalloc_lock); /* Exhausted local port range during search? It is not * possible for us to be holding one of the bind hash diff --git a/net/irda/discovery.c b/net/irda/discovery.c index c4ba5fa1446a47da6ba85981cc8c4a7e693e73ad..3fefc822c1c087c2cebd4baadb646ef771442784 100644 --- a/net/irda/discovery.c +++ b/net/irda/discovery.c @@ -194,8 +194,7 @@ void irlmp_expire_discoveries(hashbin_t *log, __u32 saddr, int force) /* Remove it from the log */ curr = hashbin_remove_this(log, (irda_queue_t *) curr); - if (curr) - kfree(curr); + kfree(curr); } } diff --git a/net/irda/irias_object.c b/net/irda/irias_object.c index 6fec428b45123df937bff9b6bc177a24fa793d41..75f2666e863056d7255875285c5188fee69042cd 100644 --- a/net/irda/irias_object.c +++ b/net/irda/irias_object.c @@ -122,8 +122,7 @@ static void __irias_delete_attrib(struct ias_attrib *attrib) IRDA_ASSERT(attrib != NULL, return;); IRDA_ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, return;); - if (attrib->name) - kfree(attrib->name); + kfree(attrib->name); irias_delete_value(attrib->value); attrib->magic = ~IAS_ATTRIB_MAGIC; @@ -136,8 +135,7 @@ void __irias_delete_object(struct ias_object *obj) IRDA_ASSERT(obj != NULL, return;); IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;); - if (obj->name) - kfree(obj->name); + kfree(obj->name); hashbin_delete(obj->attribs, (FREE_FUNC) __irias_delete_attrib); @@ -562,14 +560,12 @@ void irias_delete_value(struct ias_value *value) /* No need to deallocate */ break; case IAS_STRING: - /* If string, deallocate string */ - if (value->t.string != NULL) - kfree(value->t.string); + /* Deallocate string */ + kfree(value->t.string); break; case IAS_OCT_SEQ: - /* If byte stream, deallocate byte stream */ - if (value->t.oct_seq != NULL) - kfree(value->t.oct_seq); + /* Deallocate byte stream */ + kfree(value->t.oct_seq); break; default: IRDA_DEBUG(0, "%s(), Unknown value type!\n", __FUNCTION__); diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index d10d552d9c40e2911aaf8cf796125c4212bdabff..d3a4f30a7f2247f0bac16cdc9466c31b12409e39 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -117,7 +117,7 @@ int nf_queue(struct sk_buff **skb, /* QUEUE == DROP if noone is waiting, to be safe. */ read_lock(&queue_handler_lock); - if (!queue_handler[pf]->outfn) { + if (!queue_handler[pf] || !queue_handler[pf]->outfn) { read_unlock(&queue_handler_lock); kfree_skb(*skb); return 1; diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index efcd10f996ba516294f5e607c72a0268bd0ce808..d194676f36558848ac00012c2e394c04873e8a9b 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -146,11 +146,10 @@ instance_create(u_int16_t group_num, int pid) goto out_unlock; } - inst = kmalloc(sizeof(*inst), GFP_ATOMIC); + inst = kzalloc(sizeof(*inst), GFP_ATOMIC); if (!inst) goto out_unlock; - memset(inst, 0, sizeof(*inst)); INIT_HLIST_NODE(&inst->hlist); inst->lock = SPIN_LOCK_UNLOCKED; /* needs to be two, since we _put() after creation */ @@ -962,10 +961,9 @@ static int nful_open(struct inode *inode, struct file *file) struct iter_state *is; int ret; - is = kmalloc(sizeof(*is), GFP_KERNEL); + is = kzalloc(sizeof(*is), GFP_KERNEL); if (!is) return -ENOMEM; - memset(is, 0, sizeof(*is)); ret = seq_open(file, &nful_seq_ops); if (ret < 0) goto out_free; diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index eaa44c49567be362e95ceaf359b4f7fa9d2ea532..f065a6c949532cc187b4ec584c5f32c2f928770a 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -136,11 +136,10 @@ instance_create(u_int16_t queue_num, int pid) goto out_unlock; } - inst = kmalloc(sizeof(*inst), GFP_ATOMIC); + inst = kzalloc(sizeof(*inst), GFP_ATOMIC); if (!inst) goto out_unlock; - memset(inst, 0, sizeof(*inst)); inst->queue_num = queue_num; inst->peer_pid = pid; inst->queue_maxlen = NFQNL_QMAX_DEFAULT; @@ -1036,10 +1035,9 @@ static int nfqnl_open(struct inode *inode, struct file *file) struct iter_state *is; int ret; - is = kmalloc(sizeof(*is), GFP_KERNEL); + is = kzalloc(sizeof(*is), GFP_KERNEL); if (!is) return -ENOMEM; - memset(is, 0, sizeof(*is)); ret = seq_open(file, &nfqnl_seq_ops); if (ret < 0) goto out_free; diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index b18fe504301944d8514816df8d6eb90f715b048d..8631b65a7312c830d35e4d843163024432bac54e 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c @@ -240,8 +240,7 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh) if ((s = rose_neigh_list) == rose_neigh) { rose_neigh_list = rose_neigh->next; spin_unlock_bh(&rose_neigh_list_lock); - if (rose_neigh->digipeat != NULL) - kfree(rose_neigh->digipeat); + kfree(rose_neigh->digipeat); kfree(rose_neigh); return; } @@ -250,8 +249,7 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh) if (s->next == rose_neigh) { s->next = rose_neigh->next; spin_unlock_bh(&rose_neigh_list_lock); - if (rose_neigh->digipeat != NULL) - kfree(rose_neigh->digipeat); + kfree(rose_neigh->digipeat); kfree(rose_neigh); return; } diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c index 29d8b9a4d162f2aa72b38f3df3f68e9f1ffe625e..75470486e4050edb23e4db439a3228adfbfc170e 100644 --- a/net/sched/cls_fw.c +++ b/net/sched/cls_fw.c @@ -298,8 +298,7 @@ static int fw_change(struct tcf_proto *tp, unsigned long base, return 0; errout: - if (f) - kfree(f); + kfree(f); return err; } diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c index 02996ac05c75d11b738649fd3069abeb17b82bdd..520ff716dab2f0d744845747366f320dd83f9434 100644 --- a/net/sched/cls_route.c +++ b/net/sched/cls_route.c @@ -525,8 +525,7 @@ static int route4_change(struct tcf_proto *tp, unsigned long base, return 0; errout: - if (f) - kfree(f); + kfree(f); return err; } diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h index 006168d6937654d7ece5493fad1b96cad9e0806b..572f06be3b02a181447c1e125056a833687ef017 100644 --- a/net/sched/cls_rsvp.h +++ b/net/sched/cls_rsvp.h @@ -555,8 +555,7 @@ static int rsvp_change(struct tcf_proto *tp, unsigned long base, goto insert; errout: - if (f) - kfree(f); + kfree(f); errout2: tcf_exts_destroy(tp, &e); return err; diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c index 404d9d83a7fab040efab32341db2732b31626cf9..9f921174c8ab39d33e9544c9b78051b3b8a12cdf 100644 --- a/net/sched/cls_tcindex.c +++ b/net/sched/cls_tcindex.c @@ -194,8 +194,7 @@ __tcindex_delete(struct tcf_proto *tp, unsigned long arg, int lock) } tcf_unbind_filter(tp, &r->res); tcf_exts_destroy(tp, &r->exts); - if (f) - kfree(f); + kfree(f); return 0; } @@ -442,10 +441,8 @@ static void tcindex_destroy(struct tcf_proto *tp) walker.skip = 0; walker.fn = &tcindex_destroy_element; tcindex_walk(tp,&walker); - if (p->perfect) - kfree(p->perfect); - if (p->h) - kfree(p->h); + kfree(p->perfect); + kfree(p->h); kfree(p); tp->root = NULL; } diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 364b87d86455dc8671d17d8fbeceb4ae9d1d51e8..2b670479dde1d68ea192e641dbe69ffb754bf9f4 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -347,7 +347,7 @@ static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n) if (n->ht_down) n->ht_down->refcnt--; #ifdef CONFIG_CLS_U32_PERF - if (n && (NULL != n->pf)) + if (n) kfree(n->pf); #endif kfree(n); @@ -680,7 +680,7 @@ static int u32_change(struct tcf_proto *tp, unsigned long base, u32 handle, return 0; } #ifdef CONFIG_CLS_U32_PERF - if (n && (NULL != n->pf)) + if (n) kfree(n->pf); #endif kfree(n); diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c index cf68a59fdc5a4d4d6ac2bfbd5b63f99cd4574cee..700844d49d795d36acffd22815b5fb4f15ec3ce9 100644 --- a/net/sched/em_meta.c +++ b/net/sched/em_meta.c @@ -561,8 +561,7 @@ static int meta_var_change(struct meta_value *dst, struct rtattr *rta) static void meta_var_destroy(struct meta_value *v) { - if (v->val) - kfree((void *) v->val); + kfree((void *) v->val); } static void meta_var_apply_extras(struct meta_value *v, diff --git a/net/sched/ematch.c b/net/sched/ematch.c index ebfe2e7d21bdff98494baf479c2cca37c4175b99..64b047c65568cafe0912b92f7bb18b7e56031c25 100644 --- a/net/sched/ematch.c +++ b/net/sched/ematch.c @@ -298,6 +298,11 @@ int tcf_em_tree_validate(struct tcf_proto *tp, struct rtattr *rta, struct tcf_ematch_tree_hdr *tree_hdr; struct tcf_ematch *em; + if (!rta) { + memset(tree, 0, sizeof(*tree)); + return 0; + } + if (rtattr_parse_nested(tb, TCA_EMATCH_TREE_MAX, rta) < 0) goto errout; diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c index 25c171c32715422123ca367663b81bb29da45c45..29a2dd9f30296f613123118976c963f557e899d6 100644 --- a/net/sched/sch_gred.c +++ b/net/sched/sch_gred.c @@ -15,247 +15,281 @@ * from Ren Liu * - More error checks * - * - * - * For all the glorious comments look at Alexey's sch_red.c + * For all the glorious comments look at include/net/red.h */ #include #include -#include -#include -#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include #include -#include #include +#include -#if 1 /* control */ -#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -#else -#define DPRINTK(format,args...) -#endif - -#if 0 /* data */ -#define D2PRINTK(format,args...) printk(KERN_DEBUG format,##args) -#else -#define D2PRINTK(format,args...) -#endif +#define GRED_DEF_PRIO (MAX_DPs / 2) +#define GRED_VQ_MASK (MAX_DPs - 1) struct gred_sched_data; struct gred_sched; struct gred_sched_data { -/* Parameters */ u32 limit; /* HARD maximal queue length */ - u32 qth_min; /* Min average length threshold: A scaled */ - u32 qth_max; /* Max average length threshold: A scaled */ u32 DP; /* the drop pramaters */ - char Wlog; /* log(W) */ - char Plog; /* random number bits */ - u32 Scell_max; - u32 Rmask; u32 bytesin; /* bytes seen on virtualQ so far*/ u32 packetsin; /* packets seen on virtualQ so far*/ u32 backlog; /* bytes on the virtualQ */ - u32 forced; /* packets dropped for exceeding limits */ - u32 early; /* packets dropped as a warning */ - u32 other; /* packets dropped by invoking drop() */ - u32 pdrop; /* packets dropped because we exceeded physical queue limits */ - char Scell_log; - u8 Stab[256]; - u8 prio; /* the prio of this vq */ - -/* Variables */ - unsigned long qave; /* Average queue length: A scaled */ - int qcount; /* Packets since last random number generation */ - u32 qR; /* Cached random number */ - - psched_time_t qidlestart; /* Start of idle period */ + u8 prio; /* the prio of this vq */ + + struct red_parms parms; + struct red_stats stats; +}; + +enum { + GRED_WRED_MODE = 1, + GRED_RIO_MODE, }; struct gred_sched { struct gred_sched_data *tab[MAX_DPs]; - u32 DPs; - u32 def; - u8 initd; - u8 grio; - u8 eqp; + unsigned long flags; + u32 red_flags; + u32 DPs; + u32 def; + struct red_parms wred_set; }; -static int -gred_enqueue(struct sk_buff *skb, struct Qdisc* sch) +static inline int gred_wred_mode(struct gred_sched *table) { - psched_time_t now; - struct gred_sched_data *q=NULL; - struct gred_sched *t= qdisc_priv(sch); - unsigned long qave=0; - int i=0; + return test_bit(GRED_WRED_MODE, &table->flags); +} + +static inline void gred_enable_wred_mode(struct gred_sched *table) +{ + __set_bit(GRED_WRED_MODE, &table->flags); +} + +static inline void gred_disable_wred_mode(struct gred_sched *table) +{ + __clear_bit(GRED_WRED_MODE, &table->flags); +} + +static inline int gred_rio_mode(struct gred_sched *table) +{ + return test_bit(GRED_RIO_MODE, &table->flags); +} + +static inline void gred_enable_rio_mode(struct gred_sched *table) +{ + __set_bit(GRED_RIO_MODE, &table->flags); +} + +static inline void gred_disable_rio_mode(struct gred_sched *table) +{ + __clear_bit(GRED_RIO_MODE, &table->flags); +} + +static inline int gred_wred_mode_check(struct Qdisc *sch) +{ + struct gred_sched *table = qdisc_priv(sch); + int i; - if (!t->initd && skb_queue_len(&sch->q) < (sch->dev->tx_queue_len ? : 1)) { - D2PRINTK("NO GRED Queues setup yet! Enqueued anyway\n"); - goto do_enqueue; + /* Really ugly O(n^2) but shouldn't be necessary too frequent. */ + for (i = 0; i < table->DPs; i++) { + struct gred_sched_data *q = table->tab[i]; + int n; + + if (q == NULL) + continue; + + for (n = 0; n < table->DPs; n++) + if (table->tab[n] && table->tab[n] != q && + table->tab[n]->prio == q->prio) + return 1; } + return 0; +} + +static inline unsigned int gred_backlog(struct gred_sched *table, + struct gred_sched_data *q, + struct Qdisc *sch) +{ + if (gred_wred_mode(table)) + return sch->qstats.backlog; + else + return q->backlog; +} + +static inline u16 tc_index_to_dp(struct sk_buff *skb) +{ + return skb->tc_index & GRED_VQ_MASK; +} + +static inline void gred_load_wred_set(struct gred_sched *table, + struct gred_sched_data *q) +{ + q->parms.qavg = table->wred_set.qavg; + q->parms.qidlestart = table->wred_set.qidlestart; +} + +static inline void gred_store_wred_set(struct gred_sched *table, + struct gred_sched_data *q) +{ + table->wred_set.qavg = q->parms.qavg; +} + +static inline int gred_use_ecn(struct gred_sched *t) +{ + return t->red_flags & TC_RED_ECN; +} - if ( ((skb->tc_index&0xf) > (t->DPs -1)) || !(q=t->tab[skb->tc_index&0xf])) { - printk("GRED: setting to default (%d)\n ",t->def); - if (!(q=t->tab[t->def])) { - DPRINTK("GRED: setting to default FAILED! dropping!! " - "(%d)\n ", t->def); - goto drop; +static inline int gred_use_harddrop(struct gred_sched *t) +{ + return t->red_flags & TC_RED_HARDDROP; +} + +static int gred_enqueue(struct sk_buff *skb, struct Qdisc* sch) +{ + struct gred_sched_data *q=NULL; + struct gred_sched *t= qdisc_priv(sch); + unsigned long qavg = 0; + u16 dp = tc_index_to_dp(skb); + + if (dp >= t->DPs || (q = t->tab[dp]) == NULL) { + dp = t->def; + + if ((q = t->tab[dp]) == NULL) { + /* Pass through packets not assigned to a DP + * if no default DP has been configured. This + * allows for DP flows to be left untouched. + */ + if (skb_queue_len(&sch->q) < sch->dev->tx_queue_len) + return qdisc_enqueue_tail(skb, sch); + else + goto drop; } + /* fix tc_index? --could be controvesial but needed for requeueing */ - skb->tc_index=(skb->tc_index&0xfffffff0) | t->def; + skb->tc_index = (skb->tc_index & ~GRED_VQ_MASK) | dp; } - D2PRINTK("gred_enqueue virtualQ 0x%x classid %x backlog %d " - "general backlog %d\n",skb->tc_index&0xf,sch->handle,q->backlog, - sch->qstats.backlog); - /* sum up all the qaves of prios <= to ours to get the new qave*/ - if (!t->eqp && t->grio) { - for (i=0;iDPs;i++) { - if ((!t->tab[i]) || (i==q->DP)) - continue; - - if ((t->tab[i]->prio < q->prio) && (PSCHED_IS_PASTPERFECT(t->tab[i]->qidlestart))) - qave +=t->tab[i]->qave; + /* sum up all the qaves of prios <= to ours to get the new qave */ + if (!gred_wred_mode(t) && gred_rio_mode(t)) { + int i; + + for (i = 0; i < t->DPs; i++) { + if (t->tab[i] && t->tab[i]->prio < q->prio && + !red_is_idling(&t->tab[i]->parms)) + qavg +=t->tab[i]->parms.qavg; } - + } q->packetsin++; - q->bytesin+=skb->len; + q->bytesin += skb->len; - if (t->eqp && t->grio) { - qave=0; - q->qave=t->tab[t->def]->qave; - q->qidlestart=t->tab[t->def]->qidlestart; - } + if (gred_wred_mode(t)) + gred_load_wred_set(t, q); - if (!PSCHED_IS_PASTPERFECT(q->qidlestart)) { - long us_idle; - PSCHED_GET_TIME(now); - us_idle = PSCHED_TDIFF_SAFE(now, q->qidlestart, q->Scell_max); - PSCHED_SET_PASTPERFECT(q->qidlestart); + q->parms.qavg = red_calc_qavg(&q->parms, gred_backlog(t, q, sch)); - q->qave >>= q->Stab[(us_idle>>q->Scell_log)&0xFF]; - } else { - if (t->eqp) { - q->qave += sch->qstats.backlog - (q->qave >> q->Wlog); - } else { - q->qave += q->backlog - (q->qave >> q->Wlog); - } + if (red_is_idling(&q->parms)) + red_end_of_idle_period(&q->parms); - } - - - if (t->eqp && t->grio) - t->tab[t->def]->qave=q->qave; - - if ((q->qave+qave) < q->qth_min) { - q->qcount = -1; -enqueue: - if (q->backlog + skb->len <= q->limit) { - q->backlog += skb->len; -do_enqueue: - __skb_queue_tail(&sch->q, skb); - sch->qstats.backlog += skb->len; - sch->bstats.bytes += skb->len; - sch->bstats.packets++; - return 0; - } else { - q->pdrop++; - } + if (gred_wred_mode(t)) + gred_store_wred_set(t, q); -drop: - kfree_skb(skb); - sch->qstats.drops++; - return NET_XMIT_DROP; - } - if ((q->qave+qave) >= q->qth_max) { - q->qcount = -1; - sch->qstats.overlimits++; - q->forced++; - goto drop; + switch (red_action(&q->parms, q->parms.qavg + qavg)) { + case RED_DONT_MARK: + break; + + case RED_PROB_MARK: + sch->qstats.overlimits++; + if (!gred_use_ecn(t) || !INET_ECN_set_ce(skb)) { + q->stats.prob_drop++; + goto congestion_drop; + } + + q->stats.prob_mark++; + break; + + case RED_HARD_MARK: + sch->qstats.overlimits++; + if (gred_use_harddrop(t) || !gred_use_ecn(t) || + !INET_ECN_set_ce(skb)) { + q->stats.forced_drop++; + goto congestion_drop; + } + q->stats.forced_mark++; + break; } - if (++q->qcount) { - if ((((qave+q->qave) - q->qth_min)>>q->Wlog)*q->qcount < q->qR) - goto enqueue; - q->qcount = 0; - q->qR = net_random()&q->Rmask; - sch->qstats.overlimits++; - q->early++; - goto drop; + + if (q->backlog + skb->len <= q->limit) { + q->backlog += skb->len; + return qdisc_enqueue_tail(skb, sch); } - q->qR = net_random()&q->Rmask; - goto enqueue; + + q->stats.pdrop++; +drop: + return qdisc_drop(skb, sch); + +congestion_drop: + qdisc_drop(skb, sch); + return NET_XMIT_CN; } -static int -gred_requeue(struct sk_buff *skb, struct Qdisc* sch) +static int gred_requeue(struct sk_buff *skb, struct Qdisc* sch) { + struct gred_sched *t = qdisc_priv(sch); struct gred_sched_data *q; - struct gred_sched *t= qdisc_priv(sch); - q= t->tab[(skb->tc_index&0xf)]; -/* error checking here -- probably unnecessary */ - PSCHED_SET_PASTPERFECT(q->qidlestart); - - __skb_queue_head(&sch->q, skb); - sch->qstats.backlog += skb->len; - sch->qstats.requeues++; - q->backlog += skb->len; - return 0; + u16 dp = tc_index_to_dp(skb); + + if (dp >= t->DPs || (q = t->tab[dp]) == NULL) { + if (net_ratelimit()) + printk(KERN_WARNING "GRED: Unable to relocate VQ 0x%x " + "for requeue, screwing up backlog.\n", + tc_index_to_dp(skb)); + } else { + if (red_is_idling(&q->parms)) + red_end_of_idle_period(&q->parms); + q->backlog += skb->len; + } + + return qdisc_requeue(skb, sch); } -static struct sk_buff * -gred_dequeue(struct Qdisc* sch) +static struct sk_buff *gred_dequeue(struct Qdisc* sch) { struct sk_buff *skb; - struct gred_sched_data *q; - struct gred_sched *t= qdisc_priv(sch); + struct gred_sched *t = qdisc_priv(sch); + + skb = qdisc_dequeue_head(sch); - skb = __skb_dequeue(&sch->q); if (skb) { - sch->qstats.backlog -= skb->len; - q= t->tab[(skb->tc_index&0xf)]; - if (q) { - q->backlog -= skb->len; - if (!q->backlog && !t->eqp) - PSCHED_GET_TIME(q->qidlestart); + struct gred_sched_data *q; + u16 dp = tc_index_to_dp(skb); + + if (dp >= t->DPs || (q = t->tab[dp]) == NULL) { + if (net_ratelimit()) + printk(KERN_WARNING "GRED: Unable to relocate " + "VQ 0x%x after dequeue, screwing up " + "backlog.\n", tc_index_to_dp(skb)); } else { - D2PRINTK("gred_dequeue: skb has bad tcindex %x\n",skb->tc_index&0xf); + q->backlog -= skb->len; + + if (!q->backlog && !gred_wred_mode(t)) + red_start_of_idle_period(&q->parms); } + return skb; } - if (t->eqp) { - q= t->tab[t->def]; - if (!q) - D2PRINTK("no default VQ set: Results will be " - "screwed up\n"); - else - PSCHED_GET_TIME(q->qidlestart); - } + if (gred_wred_mode(t) && !red_is_idling(&t->wred_set)) + red_start_of_idle_period(&t->wred_set); return NULL; } @@ -263,36 +297,34 @@ gred_dequeue(struct Qdisc* sch) static unsigned int gred_drop(struct Qdisc* sch) { struct sk_buff *skb; + struct gred_sched *t = qdisc_priv(sch); - struct gred_sched_data *q; - struct gred_sched *t= qdisc_priv(sch); - - skb = __skb_dequeue_tail(&sch->q); + skb = qdisc_dequeue_tail(sch); if (skb) { unsigned int len = skb->len; - sch->qstats.backlog -= len; - sch->qstats.drops++; - q= t->tab[(skb->tc_index&0xf)]; - if (q) { - q->backlog -= len; - q->other++; - if (!q->backlog && !t->eqp) - PSCHED_GET_TIME(q->qidlestart); + struct gred_sched_data *q; + u16 dp = tc_index_to_dp(skb); + + if (dp >= t->DPs || (q = t->tab[dp]) == NULL) { + if (net_ratelimit()) + printk(KERN_WARNING "GRED: Unable to relocate " + "VQ 0x%x while dropping, screwing up " + "backlog.\n", tc_index_to_dp(skb)); } else { - D2PRINTK("gred_dequeue: skb has bad tcindex %x\n",skb->tc_index&0xf); + q->backlog -= len; + q->stats.other++; + + if (!q->backlog && !gred_wred_mode(t)) + red_start_of_idle_period(&q->parms); } - kfree_skb(skb); + qdisc_drop(skb, sch); return len; } - q=t->tab[t->def]; - if (!q) { - D2PRINTK("no default VQ set: Results might be screwed up\n"); - return 0; - } + if (gred_wred_mode(t) && !red_is_idling(&t->wred_set)) + red_start_of_idle_period(&t->wred_set); - PSCHED_GET_TIME(q->qidlestart); return 0; } @@ -300,293 +332,241 @@ static unsigned int gred_drop(struct Qdisc* sch) static void gred_reset(struct Qdisc* sch) { int i; - struct gred_sched_data *q; - struct gred_sched *t= qdisc_priv(sch); + struct gred_sched *t = qdisc_priv(sch); + + qdisc_reset_queue(sch); - __skb_queue_purge(&sch->q); + for (i = 0; i < t->DPs; i++) { + struct gred_sched_data *q = t->tab[i]; - sch->qstats.backlog = 0; + if (!q) + continue; - for (i=0;iDPs;i++) { - q= t->tab[i]; - if (!q) - continue; - PSCHED_SET_PASTPERFECT(q->qidlestart); - q->qave = 0; - q->qcount = -1; + red_restart(&q->parms); q->backlog = 0; - q->other=0; - q->forced=0; - q->pdrop=0; - q->early=0; } } -static int gred_change(struct Qdisc *sch, struct rtattr *opt) +static inline void gred_destroy_vq(struct gred_sched_data *q) +{ + kfree(q); +} + +static inline int gred_change_table_def(struct Qdisc *sch, struct rtattr *dps) { struct gred_sched *table = qdisc_priv(sch); - struct gred_sched_data *q; - struct tc_gred_qopt *ctl; struct tc_gred_sopt *sopt; - struct rtattr *tb[TCA_GRED_STAB]; - struct rtattr *tb2[TCA_GRED_DPS]; int i; - if (opt == NULL || rtattr_parse_nested(tb, TCA_GRED_STAB, opt)) + if (dps == NULL || RTA_PAYLOAD(dps) < sizeof(*sopt)) return -EINVAL; - if (tb[TCA_GRED_PARMS-1] == 0 && tb[TCA_GRED_STAB-1] == 0) { - rtattr_parse_nested(tb2, TCA_GRED_DPS, opt); + sopt = RTA_DATA(dps); + + if (sopt->DPs > MAX_DPs || sopt->DPs == 0 || sopt->def_DP >= sopt->DPs) + return -EINVAL; - if (tb2[TCA_GRED_DPS-1] == 0) - return -EINVAL; + sch_tree_lock(sch); + table->DPs = sopt->DPs; + table->def = sopt->def_DP; + table->red_flags = sopt->flags; + + /* + * Every entry point to GRED is synchronized with the above code + * and the DP is checked against DPs, i.e. shadowed VQs can no + * longer be found so we can unlock right here. + */ + sch_tree_unlock(sch); + + if (sopt->grio) { + gred_enable_rio_mode(table); + gred_disable_wred_mode(table); + if (gred_wred_mode_check(sch)) + gred_enable_wred_mode(table); + } else { + gred_disable_rio_mode(table); + gred_disable_wred_mode(table); + } - sopt = RTA_DATA(tb2[TCA_GRED_DPS-1]); - table->DPs=sopt->DPs; - table->def=sopt->def_DP; - table->grio=sopt->grio; - table->initd=0; - /* probably need to clear all the table DP entries as well */ - return 0; - } + for (i = table->DPs; i < MAX_DPs; i++) { + if (table->tab[i]) { + printk(KERN_WARNING "GRED: Warning: Destroying " + "shadowed VQ 0x%x\n", i); + gred_destroy_vq(table->tab[i]); + table->tab[i] = NULL; + } + } + return 0; +} - if (!table->DPs || tb[TCA_GRED_PARMS-1] == 0 || tb[TCA_GRED_STAB-1] == 0 || - RTA_PAYLOAD(tb[TCA_GRED_PARMS-1]) < sizeof(*ctl) || - RTA_PAYLOAD(tb[TCA_GRED_STAB-1]) < 256) - return -EINVAL; +static inline int gred_change_vq(struct Qdisc *sch, int dp, + struct tc_gred_qopt *ctl, int prio, u8 *stab) +{ + struct gred_sched *table = qdisc_priv(sch); + struct gred_sched_data *q; - ctl = RTA_DATA(tb[TCA_GRED_PARMS-1]); - if (ctl->DP > MAX_DPs-1 ) { - /* misbehaving is punished! Put in the default drop probability */ - DPRINTK("\nGRED: DP %u not in the proper range fixed. New DP " - "set to default at %d\n",ctl->DP,table->def); - ctl->DP=table->def; - } - - if (table->tab[ctl->DP] == NULL) { - table->tab[ctl->DP]=kmalloc(sizeof(struct gred_sched_data), - GFP_KERNEL); - if (NULL == table->tab[ctl->DP]) + if (table->tab[dp] == NULL) { + table->tab[dp] = kmalloc(sizeof(*q), GFP_KERNEL); + if (table->tab[dp] == NULL) return -ENOMEM; - memset(table->tab[ctl->DP], 0, (sizeof(struct gred_sched_data))); - } - q= table->tab[ctl->DP]; - - if (table->grio) { - if (ctl->prio <=0) { - if (table->def && table->tab[table->def]) { - DPRINTK("\nGRED: DP %u does not have a prio" - "setting default to %d\n",ctl->DP, - table->tab[table->def]->prio); - q->prio=table->tab[table->def]->prio; - } else { - DPRINTK("\nGRED: DP %u does not have a prio" - " setting default to 8\n",ctl->DP); - q->prio=8; - } - } else { - q->prio=ctl->prio; - } - } else { - q->prio=8; + memset(table->tab[dp], 0, sizeof(*q)); } - - q->DP=ctl->DP; - q->Wlog = ctl->Wlog; - q->Plog = ctl->Plog; + q = table->tab[dp]; + q->DP = dp; + q->prio = prio; q->limit = ctl->limit; - q->Scell_log = ctl->Scell_log; - q->Rmask = ctl->Plog < 32 ? ((1<Plog) - 1) : ~0UL; - q->Scell_max = (255<Scell_log); - q->qth_min = ctl->qth_min<Wlog; - q->qth_max = ctl->qth_max<Wlog; - q->qave=0; - q->backlog=0; - q->qcount = -1; - q->other=0; - q->forced=0; - q->pdrop=0; - q->early=0; - - PSCHED_SET_PASTPERFECT(q->qidlestart); - memcpy(q->Stab, RTA_DATA(tb[TCA_GRED_STAB-1]), 256); - - if ( table->initd && table->grio) { - /* this looks ugly but it's not in the fast path */ - for (i=0;iDPs;i++) { - if ((!table->tab[i]) || (i==q->DP) ) - continue; - if (table->tab[i]->prio == q->prio ){ - /* WRED mode detected */ - table->eqp=1; - break; - } - } - } - if (!table->initd) { - table->initd=1; - /* - the first entry also goes into the default until - over-written - */ - - if (table->tab[table->def] == NULL) { - table->tab[table->def]= - kmalloc(sizeof(struct gred_sched_data), GFP_KERNEL); - if (NULL == table->tab[table->def]) - return -ENOMEM; - - memset(table->tab[table->def], 0, - (sizeof(struct gred_sched_data))); - } - q= table->tab[table->def]; - q->DP=table->def; - q->Wlog = ctl->Wlog; - q->Plog = ctl->Plog; - q->limit = ctl->limit; - q->Scell_log = ctl->Scell_log; - q->Rmask = ctl->Plog < 32 ? ((1<Plog) - 1) : ~0UL; - q->Scell_max = (255<Scell_log); - q->qth_min = ctl->qth_min<Wlog; - q->qth_max = ctl->qth_max<Wlog; - - if (table->grio) - q->prio=table->tab[ctl->DP]->prio; - else - q->prio=8; - - q->qcount = -1; - PSCHED_SET_PASTPERFECT(q->qidlestart); - memcpy(q->Stab, RTA_DATA(tb[TCA_GRED_STAB-1]), 256); - } - return 0; + if (q->backlog == 0) + red_end_of_idle_period(&q->parms); + red_set_parms(&q->parms, + ctl->qth_min, ctl->qth_max, ctl->Wlog, ctl->Plog, + ctl->Scell_log, stab); + + return 0; } -static int gred_init(struct Qdisc *sch, struct rtattr *opt) +static int gred_change(struct Qdisc *sch, struct rtattr *opt) { struct gred_sched *table = qdisc_priv(sch); - struct tc_gred_sopt *sopt; - struct rtattr *tb[TCA_GRED_STAB]; - struct rtattr *tb2[TCA_GRED_DPS]; + struct tc_gred_qopt *ctl; + struct rtattr *tb[TCA_GRED_MAX]; + int err = -EINVAL, prio = GRED_DEF_PRIO; + u8 *stab; - if (opt == NULL || rtattr_parse_nested(tb, TCA_GRED_STAB, opt)) + if (opt == NULL || rtattr_parse_nested(tb, TCA_GRED_MAX, opt)) return -EINVAL; - if (tb[TCA_GRED_PARMS-1] == 0 && tb[TCA_GRED_STAB-1] == 0) { - rtattr_parse_nested(tb2, TCA_GRED_DPS, opt); + if (tb[TCA_GRED_PARMS-1] == NULL && tb[TCA_GRED_STAB-1] == NULL) + return gred_change_table_def(sch, opt); + + if (tb[TCA_GRED_PARMS-1] == NULL || + RTA_PAYLOAD(tb[TCA_GRED_PARMS-1]) < sizeof(*ctl) || + tb[TCA_GRED_STAB-1] == NULL || + RTA_PAYLOAD(tb[TCA_GRED_STAB-1]) < 256) + return -EINVAL; + + ctl = RTA_DATA(tb[TCA_GRED_PARMS-1]); + stab = RTA_DATA(tb[TCA_GRED_STAB-1]); + + if (ctl->DP >= table->DPs) + goto errout; - if (tb2[TCA_GRED_DPS-1] == 0) - return -EINVAL; + if (gred_rio_mode(table)) { + if (ctl->prio == 0) { + int def_prio = GRED_DEF_PRIO; - sopt = RTA_DATA(tb2[TCA_GRED_DPS-1]); - table->DPs=sopt->DPs; - table->def=sopt->def_DP; - table->grio=sopt->grio; - table->initd=0; - return 0; + if (table->tab[table->def]) + def_prio = table->tab[table->def]->prio; + + printk(KERN_DEBUG "GRED: DP %u does not have a prio " + "setting default to %d\n", ctl->DP, def_prio); + + prio = def_prio; + } else + prio = ctl->prio; + } + + sch_tree_lock(sch); + + err = gred_change_vq(sch, ctl->DP, ctl, prio, stab); + if (err < 0) + goto errout_locked; + + if (gred_rio_mode(table)) { + gred_disable_wred_mode(table); + if (gred_wred_mode_check(sch)) + gred_enable_wred_mode(table); } - DPRINTK("\n GRED_INIT error!\n"); - return -EINVAL; + err = 0; + +errout_locked: + sch_tree_unlock(sch); +errout: + return err; } -static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) +static int gred_init(struct Qdisc *sch, struct rtattr *opt) { - unsigned long qave; - struct rtattr *rta; - struct tc_gred_qopt *opt = NULL ; - struct tc_gred_qopt *dst; - struct gred_sched *table = qdisc_priv(sch); - struct gred_sched_data *q; - int i; - unsigned char *b = skb->tail; + struct rtattr *tb[TCA_GRED_MAX]; - rta = (struct rtattr*)b; - RTA_PUT(skb, TCA_OPTIONS, 0, NULL); + if (opt == NULL || rtattr_parse_nested(tb, TCA_GRED_MAX, opt)) + return -EINVAL; - opt=kmalloc(sizeof(struct tc_gred_qopt)*MAX_DPs, GFP_KERNEL); + if (tb[TCA_GRED_PARMS-1] || tb[TCA_GRED_STAB-1]) + return -EINVAL; - if (opt == NULL) { - DPRINTK("gred_dump:failed to malloc for %Zd\n", - sizeof(struct tc_gred_qopt)*MAX_DPs); - goto rtattr_failure; - } + return gred_change_table_def(sch, tb[TCA_GRED_DPS-1]); +} - memset(opt, 0, (sizeof(struct tc_gred_qopt))*table->DPs); +static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) +{ + struct gred_sched *table = qdisc_priv(sch); + struct rtattr *parms, *opts = NULL; + int i; + struct tc_gred_sopt sopt = { + .DPs = table->DPs, + .def_DP = table->def, + .grio = gred_rio_mode(table), + .flags = table->red_flags, + }; - if (!table->initd) { - DPRINTK("NO GRED Queues setup!\n"); - } + opts = RTA_NEST(skb, TCA_OPTIONS); + RTA_PUT(skb, TCA_GRED_DPS, sizeof(sopt), &sopt); + parms = RTA_NEST(skb, TCA_GRED_PARMS); + + for (i = 0; i < MAX_DPs; i++) { + struct gred_sched_data *q = table->tab[i]; + struct tc_gred_qopt opt; - for (i=0;itab[i]; + memset(&opt, 0, sizeof(opt)); if (!q) { /* hack -- fix at some point with proper message This is how we indicate to tc that there is no VQ at this DP */ - dst->DP=MAX_DPs+i; - continue; + opt.DP = MAX_DPs + i; + goto append_opt; } - dst->limit=q->limit; - dst->qth_min=q->qth_min>>q->Wlog; - dst->qth_max=q->qth_max>>q->Wlog; - dst->DP=q->DP; - dst->backlog=q->backlog; - if (q->qave) { - if (table->eqp && table->grio) { - q->qidlestart=table->tab[table->def]->qidlestart; - q->qave=table->tab[table->def]->qave; - } - if (!PSCHED_IS_PASTPERFECT(q->qidlestart)) { - long idle; - psched_time_t now; - PSCHED_GET_TIME(now); - idle = PSCHED_TDIFF_SAFE(now, q->qidlestart, q->Scell_max); - qave = q->qave >> q->Stab[(idle>>q->Scell_log)&0xFF]; - dst->qave = qave >> q->Wlog; - - } else { - dst->qave = q->qave >> q->Wlog; - } - } else { - dst->qave = 0; + opt.limit = q->limit; + opt.DP = q->DP; + opt.backlog = q->backlog; + opt.prio = q->prio; + opt.qth_min = q->parms.qth_min >> q->parms.Wlog; + opt.qth_max = q->parms.qth_max >> q->parms.Wlog; + opt.Wlog = q->parms.Wlog; + opt.Plog = q->parms.Plog; + opt.Scell_log = q->parms.Scell_log; + opt.other = q->stats.other; + opt.early = q->stats.prob_drop; + opt.forced = q->stats.forced_drop; + opt.pdrop = q->stats.pdrop; + opt.packets = q->packetsin; + opt.bytesin = q->bytesin; + + if (gred_wred_mode(table)) { + q->parms.qidlestart = + table->tab[table->def]->parms.qidlestart; + q->parms.qavg = table->tab[table->def]->parms.qavg; } - - - dst->Wlog = q->Wlog; - dst->Plog = q->Plog; - dst->Scell_log = q->Scell_log; - dst->other = q->other; - dst->forced = q->forced; - dst->early = q->early; - dst->pdrop = q->pdrop; - dst->prio = q->prio; - dst->packets=q->packetsin; - dst->bytesin=q->bytesin; + + opt.qave = red_calc_qavg(&q->parms, q->parms.qavg); + +append_opt: + RTA_APPEND(skb, sizeof(opt), &opt); } - RTA_PUT(skb, TCA_GRED_PARMS, sizeof(struct tc_gred_qopt)*MAX_DPs, opt); - rta->rta_len = skb->tail - b; + RTA_NEST_END(skb, parms); - kfree(opt); - return skb->len; + return RTA_NEST_END(skb, opts); rtattr_failure: - if (opt) - kfree(opt); - DPRINTK("gred_dump: FAILURE!!!!\n"); - -/* also free the opt struct here */ - skb_trim(skb, b - skb->data); - return -1; + return RTA_NEST_CANCEL(skb, opts); } static void gred_destroy(struct Qdisc *sch) @@ -594,15 +574,13 @@ static void gred_destroy(struct Qdisc *sch) struct gred_sched *table = qdisc_priv(sch); int i; - for (i = 0;i < table->DPs; i++) { + for (i = 0; i < table->DPs; i++) { if (table->tab[i]) - kfree(table->tab[i]); + gred_destroy_vq(table->tab[i]); } } static struct Qdisc_ops gred_qdisc_ops = { - .next = NULL, - .cl_ops = NULL, .id = "gred", .priv_size = sizeof(struct gred_sched), .enqueue = gred_enqueue, @@ -621,10 +599,13 @@ static int __init gred_module_init(void) { return register_qdisc(&gred_qdisc_ops); } -static void __exit gred_module_exit(void) + +static void __exit gred_module_exit(void) { unregister_qdisc(&gred_qdisc_ops); } + module_init(gred_module_init) module_exit(gred_module_exit) + MODULE_LICENSE("GPL"); diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index bb9bf8d5003c62d79a4928df12acb59fc05adf67..cdc8d283791c7d89388d911cf76c344e0ad04ba9 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -25,6 +25,8 @@ #include +#define VERSION "1.1" + /* Network Emulation Queuing algorithm. ==================================== @@ -185,10 +187,13 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) || q->counter < q->gap /* inside last reordering gap */ || q->reorder < get_crandom(&q->reorder_cor)) { psched_time_t now; + psched_tdiff_t delay; + + delay = tabledist(q->latency, q->jitter, + &q->delay_cor, q->delay_dist); + PSCHED_GET_TIME(now); - PSCHED_TADD2(now, tabledist(q->latency, q->jitter, - &q->delay_cor, q->delay_dist), - cb->time_to_send); + PSCHED_TADD2(now, delay, cb->time_to_send); ++q->counter; ret = q->qdisc->enqueue(skb, q->qdisc); } else { @@ -248,24 +253,31 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch) const struct netem_skb_cb *cb = (const struct netem_skb_cb *)skb->cb; psched_time_t now; - long delay; /* if more time remaining? */ PSCHED_GET_TIME(now); - delay = PSCHED_US2JIFFIE(PSCHED_TDIFF(cb->time_to_send, now)); - pr_debug("netem_run: skb=%p delay=%ld\n", skb, delay); - if (delay <= 0) { + + if (PSCHED_TLESS(cb->time_to_send, now)) { pr_debug("netem_dequeue: return skb=%p\n", skb); sch->q.qlen--; sch->flags &= ~TCQ_F_THROTTLED; return skb; - } + } else { + psched_tdiff_t delay = PSCHED_TDIFF(cb->time_to_send, now); + + if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) { + sch->qstats.drops++; - mod_timer(&q->timer, jiffies + delay); - sch->flags |= TCQ_F_THROTTLED; + /* After this qlen is confused */ + printk(KERN_ERR "netem: queue discpline %s could not requeue\n", + q->qdisc->ops->id); - if (q->qdisc->ops->requeue(skb, q->qdisc) != 0) - sch->qstats.drops++; + sch->q.qlen--; + } + + mod_timer(&q->timer, jiffies + PSCHED_US2JIFFIE(delay)); + sch->flags |= TCQ_F_THROTTLED; + } } return NULL; @@ -290,11 +302,16 @@ static void netem_reset(struct Qdisc *sch) del_timer_sync(&q->timer); } +/* Pass size change message down to embedded FIFO */ static int set_fifo_limit(struct Qdisc *q, int limit) { struct rtattr *rta; int ret = -ENOMEM; + /* Hack to avoid sending change message to non-FIFO */ + if (strncmp(q->ops->id + 1, "fifo", 4) != 0) + return 0; + rta = kmalloc(RTA_LENGTH(sizeof(struct tc_fifo_qopt)), GFP_KERNEL); if (rta) { rta->rta_type = RTM_NEWQDISC; @@ -426,6 +443,84 @@ static int netem_change(struct Qdisc *sch, struct rtattr *opt) return 0; } +/* + * Special case version of FIFO queue for use by netem. + * It queues in order based on timestamps in skb's + */ +struct fifo_sched_data { + u32 limit; +}; + +static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch) +{ + struct fifo_sched_data *q = qdisc_priv(sch); + struct sk_buff_head *list = &sch->q; + const struct netem_skb_cb *ncb + = (const struct netem_skb_cb *)nskb->cb; + struct sk_buff *skb; + + if (likely(skb_queue_len(list) < q->limit)) { + skb_queue_reverse_walk(list, skb) { + const struct netem_skb_cb *cb + = (const struct netem_skb_cb *)skb->cb; + + if (PSCHED_TLESS(cb->time_to_send, ncb->time_to_send)) + break; + } + + __skb_queue_after(list, skb, nskb); + + sch->qstats.backlog += nskb->len; + sch->bstats.bytes += nskb->len; + sch->bstats.packets++; + + return NET_XMIT_SUCCESS; + } + + return qdisc_drop(nskb, sch); +} + +static int tfifo_init(struct Qdisc *sch, struct rtattr *opt) +{ + struct fifo_sched_data *q = qdisc_priv(sch); + + if (opt) { + struct tc_fifo_qopt *ctl = RTA_DATA(opt); + if (RTA_PAYLOAD(opt) < sizeof(*ctl)) + return -EINVAL; + + q->limit = ctl->limit; + } else + q->limit = max_t(u32, sch->dev->tx_queue_len, 1); + + return 0; +} + +static int tfifo_dump(struct Qdisc *sch, struct sk_buff *skb) +{ + struct fifo_sched_data *q = qdisc_priv(sch); + struct tc_fifo_qopt opt = { .limit = q->limit }; + + RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); + return skb->len; + +rtattr_failure: + return -1; +} + +static struct Qdisc_ops tfifo_qdisc_ops = { + .id = "tfifo", + .priv_size = sizeof(struct fifo_sched_data), + .enqueue = tfifo_enqueue, + .dequeue = qdisc_dequeue_head, + .requeue = qdisc_requeue, + .drop = qdisc_queue_drop, + .init = tfifo_init, + .reset = qdisc_reset_queue, + .change = tfifo_init, + .dump = tfifo_dump, +}; + static int netem_init(struct Qdisc *sch, struct rtattr *opt) { struct netem_sched_data *q = qdisc_priv(sch); @@ -438,7 +533,7 @@ static int netem_init(struct Qdisc *sch, struct rtattr *opt) q->timer.function = netem_watchdog; q->timer.data = (unsigned long) sch; - q->qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops); + q->qdisc = qdisc_create_dflt(sch->dev, &tfifo_qdisc_ops); if (!q->qdisc) { pr_debug("netem: qdisc create failed\n"); return -ENOMEM; @@ -601,6 +696,7 @@ static struct Qdisc_ops netem_qdisc_ops = { static int __init netem_module_init(void) { + pr_info("netem: version " VERSION "\n"); return register_qdisc(&netem_qdisc_ops); } static void __exit netem_module_exit(void) diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index 7845d045eec4d1434037eaf0a964f33f70fcb0e9..dccfa44c2d71d3be7d7d766987a7b1d0bdc9977d 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -9,76 +9,23 @@ * Authors: Alexey Kuznetsov, * * Changes: - * J Hadi Salim 980914: computation fixes + * J Hadi Salim 980914: computation fixes * Alexey Makarenko 990814: qave on idle link was calculated incorrectly. - * J Hadi Salim 980816: ECN support + * J Hadi Salim 980816: ECN support */ #include #include -#include -#include -#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include #include -#include #include #include -#include +#include -/* Random Early Detection (RED) algorithm. - ======================================= - - Source: Sally Floyd and Van Jacobson, "Random Early Detection Gateways - for Congestion Avoidance", 1993, IEEE/ACM Transactions on Networking. - - This file codes a "divisionless" version of RED algorithm - as written down in Fig.17 of the paper. - -Short description. ------------------- - - When a new packet arrives we calculate the average queue length: - - avg = (1-W)*avg + W*current_queue_len, - - W is the filter time constant (chosen as 2^(-Wlog)), it controls - the inertia of the algorithm. To allow larger bursts, W should be - decreased. - - if (avg > th_max) -> packet marked (dropped). - if (avg < th_min) -> packet passes. - if (th_min < avg < th_max) we calculate probability: - - Pb = max_P * (avg - th_min)/(th_max-th_min) - - and mark (drop) packet with this probability. - Pb changes from 0 (at avg==th_min) to max_P (avg==th_max). - max_P should be small (not 1), usually 0.01..0.02 is good value. - - max_P is chosen as a number, so that max_P/(th_max-th_min) - is a negative power of two in order arithmetics to contain - only shifts. - - - Parameters, settable by user: +/* Parameters, settable by user: ----------------------------- limit - bytes (must be > qth_max + burst) @@ -89,243 +36,93 @@ Short description. arbitrarily high (well, less than ram size) Really, this limit will never be reached if RED works correctly. - - qth_min - bytes (should be < qth_max/2) - qth_max - bytes (should be at least 2*qth_min and less limit) - Wlog - bits (<32) log(1/W). - Plog - bits (<32) - - Plog is related to max_P by formula: - - max_P = (qth_max-qth_min)/2^Plog; - - F.e. if qth_max=128K and qth_min=32K, then Plog=22 - corresponds to max_P=0.02 - - Scell_log - Stab - - Lookup table for log((1-W)^(t/t_ave). - - -NOTES: - -Upper bound on W. ------------------ - - If you want to allow bursts of L packets of size S, - you should choose W: - - L + 1 - th_min/S < (1-(1-W)^L)/W - - th_min/S = 32 th_min/S = 4 - - log(W) L - -1 33 - -2 35 - -3 39 - -4 46 - -5 57 - -6 75 - -7 101 - -8 135 - -9 190 - etc. */ struct red_sched_data { -/* Parameters */ - u32 limit; /* HARD maximal queue length */ - u32 qth_min; /* Min average length threshold: A scaled */ - u32 qth_max; /* Max average length threshold: A scaled */ - u32 Rmask; - u32 Scell_max; - unsigned char flags; - char Wlog; /* log(W) */ - char Plog; /* random number bits */ - char Scell_log; - u8 Stab[256]; - -/* Variables */ - unsigned long qave; /* Average queue length: A scaled */ - int qcount; /* Packets since last random number generation */ - u32 qR; /* Cached random number */ - - psched_time_t qidlestart; /* Start of idle period */ - struct tc_red_xstats st; + u32 limit; /* HARD maximal queue length */ + unsigned char flags; + struct red_parms parms; + struct red_stats stats; }; -static int red_ecn_mark(struct sk_buff *skb) +static inline int red_use_ecn(struct red_sched_data *q) { - if (skb->nh.raw + 20 > skb->tail) - return 0; - - switch (skb->protocol) { - case __constant_htons(ETH_P_IP): - if (INET_ECN_is_not_ect(skb->nh.iph->tos)) - return 0; - IP_ECN_set_ce(skb->nh.iph); - return 1; - case __constant_htons(ETH_P_IPV6): - if (INET_ECN_is_not_ect(ipv6_get_dsfield(skb->nh.ipv6h))) - return 0; - IP6_ECN_set_ce(skb->nh.ipv6h); - return 1; - default: - return 0; - } + return q->flags & TC_RED_ECN; } -static int -red_enqueue(struct sk_buff *skb, struct Qdisc* sch) +static inline int red_use_harddrop(struct red_sched_data *q) +{ + return q->flags & TC_RED_HARDDROP; +} + +static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch) { struct red_sched_data *q = qdisc_priv(sch); - psched_time_t now; + q->parms.qavg = red_calc_qavg(&q->parms, sch->qstats.backlog); - if (!PSCHED_IS_PASTPERFECT(q->qidlestart)) { - long us_idle; - int shift; + if (red_is_idling(&q->parms)) + red_end_of_idle_period(&q->parms); - PSCHED_GET_TIME(now); - us_idle = PSCHED_TDIFF_SAFE(now, q->qidlestart, q->Scell_max); - PSCHED_SET_PASTPERFECT(q->qidlestart); + switch (red_action(&q->parms, q->parms.qavg)) { + case RED_DONT_MARK: + break; -/* - The problem: ideally, average length queue recalcultion should - be done over constant clock intervals. This is too expensive, so that - the calculation is driven by outgoing packets. - When the queue is idle we have to model this clock by hand. - - SF+VJ proposed to "generate" m = idletime/(average_pkt_size/bandwidth) - dummy packets as a burst after idle time, i.e. - - q->qave *= (1-W)^m - - This is an apparently overcomplicated solution (f.e. we have to precompute - a table to make this calculation in reasonable time) - I believe that a simpler model may be used here, - but it is field for experiments. -*/ - shift = q->Stab[us_idle>>q->Scell_log]; - - if (shift) { - q->qave >>= shift; - } else { - /* Approximate initial part of exponent - with linear function: - (1-W)^m ~= 1-mW + ... - - Seems, it is the best solution to - problem of too coarce exponent tabulation. - */ - - us_idle = (q->qave * us_idle)>>q->Scell_log; - if (us_idle < q->qave/2) - q->qave -= us_idle; - else - q->qave >>= 1; - } - } else { - q->qave += sch->qstats.backlog - (q->qave >> q->Wlog); - /* NOTE: - q->qave is fixed point number with point at Wlog. - The formulae above is equvalent to floating point - version: - - qave = qave*(1-W) + sch->qstats.backlog*W; - --ANK (980924) - */ - } + case RED_PROB_MARK: + sch->qstats.overlimits++; + if (!red_use_ecn(q) || !INET_ECN_set_ce(skb)) { + q->stats.prob_drop++; + goto congestion_drop; + } - if (q->qave < q->qth_min) { - q->qcount = -1; -enqueue: - if (sch->qstats.backlog + skb->len <= q->limit) { - __skb_queue_tail(&sch->q, skb); - sch->qstats.backlog += skb->len; - sch->bstats.bytes += skb->len; - sch->bstats.packets++; - return NET_XMIT_SUCCESS; - } else { - q->st.pdrop++; - } - kfree_skb(skb); - sch->qstats.drops++; - return NET_XMIT_DROP; - } - if (q->qave >= q->qth_max) { - q->qcount = -1; - sch->qstats.overlimits++; -mark: - if (!(q->flags&TC_RED_ECN) || !red_ecn_mark(skb)) { - q->st.early++; - goto drop; - } - q->st.marked++; - goto enqueue; - } + q->stats.prob_mark++; + break; + + case RED_HARD_MARK: + sch->qstats.overlimits++; + if (red_use_harddrop(q) || !red_use_ecn(q) || + !INET_ECN_set_ce(skb)) { + q->stats.forced_drop++; + goto congestion_drop; + } - if (++q->qcount) { - /* The formula used below causes questions. - - OK. qR is random number in the interval 0..Rmask - i.e. 0..(2^Plog). If we used floating point - arithmetics, it would be: (2^Plog)*rnd_num, - where rnd_num is less 1. - - Taking into account, that qave have fixed - point at Wlog, and Plog is related to max_P by - max_P = (qth_max-qth_min)/2^Plog; two lines - below have the following floating point equivalent: - - max_P*(qave - qth_min)/(qth_max-qth_min) < rnd/qcount - - Any questions? --ANK (980924) - */ - if (((q->qave - q->qth_min)>>q->Wlog)*q->qcount < q->qR) - goto enqueue; - q->qcount = 0; - q->qR = net_random()&q->Rmask; - sch->qstats.overlimits++; - goto mark; + q->stats.forced_mark++; + break; } - q->qR = net_random()&q->Rmask; - goto enqueue; -drop: - kfree_skb(skb); - sch->qstats.drops++; + if (sch->qstats.backlog + skb->len <= q->limit) + return qdisc_enqueue_tail(skb, sch); + + q->stats.pdrop++; + return qdisc_drop(skb, sch); + +congestion_drop: + qdisc_drop(skb, sch); return NET_XMIT_CN; } -static int -red_requeue(struct sk_buff *skb, struct Qdisc* sch) +static int red_requeue(struct sk_buff *skb, struct Qdisc* sch) { struct red_sched_data *q = qdisc_priv(sch); - PSCHED_SET_PASTPERFECT(q->qidlestart); + if (red_is_idling(&q->parms)) + red_end_of_idle_period(&q->parms); - __skb_queue_head(&sch->q, skb); - sch->qstats.backlog += skb->len; - sch->qstats.requeues++; - return 0; + return qdisc_requeue(skb, sch); } -static struct sk_buff * -red_dequeue(struct Qdisc* sch) +static struct sk_buff * red_dequeue(struct Qdisc* sch) { struct sk_buff *skb; struct red_sched_data *q = qdisc_priv(sch); - skb = __skb_dequeue(&sch->q); - if (skb) { - sch->qstats.backlog -= skb->len; - return skb; - } - PSCHED_GET_TIME(q->qidlestart); - return NULL; + skb = qdisc_dequeue_head(sch); + + if (skb == NULL && !red_is_idling(&q->parms)) + red_start_of_idle_period(&q->parms); + + return skb; } static unsigned int red_drop(struct Qdisc* sch) @@ -333,16 +130,17 @@ static unsigned int red_drop(struct Qdisc* sch) struct sk_buff *skb; struct red_sched_data *q = qdisc_priv(sch); - skb = __skb_dequeue_tail(&sch->q); + skb = qdisc_dequeue_tail(sch); if (skb) { unsigned int len = skb->len; - sch->qstats.backlog -= len; - sch->qstats.drops++; - q->st.other++; - kfree_skb(skb); + q->stats.other++; + qdisc_drop(skb, sch); return len; } - PSCHED_GET_TIME(q->qidlestart); + + if (!red_is_idling(&q->parms)) + red_start_of_idle_period(&q->parms); + return 0; } @@ -350,43 +148,38 @@ static void red_reset(struct Qdisc* sch) { struct red_sched_data *q = qdisc_priv(sch); - __skb_queue_purge(&sch->q); - sch->qstats.backlog = 0; - PSCHED_SET_PASTPERFECT(q->qidlestart); - q->qave = 0; - q->qcount = -1; + qdisc_reset_queue(sch); + red_restart(&q->parms); } static int red_change(struct Qdisc *sch, struct rtattr *opt) { struct red_sched_data *q = qdisc_priv(sch); - struct rtattr *tb[TCA_RED_STAB]; + struct rtattr *tb[TCA_RED_MAX]; struct tc_red_qopt *ctl; - if (opt == NULL || - rtattr_parse_nested(tb, TCA_RED_STAB, opt) || - tb[TCA_RED_PARMS-1] == 0 || tb[TCA_RED_STAB-1] == 0 || + if (opt == NULL || rtattr_parse_nested(tb, TCA_RED_MAX, opt)) + return -EINVAL; + + if (tb[TCA_RED_PARMS-1] == NULL || RTA_PAYLOAD(tb[TCA_RED_PARMS-1]) < sizeof(*ctl) || - RTA_PAYLOAD(tb[TCA_RED_STAB-1]) < 256) + tb[TCA_RED_STAB-1] == NULL || + RTA_PAYLOAD(tb[TCA_RED_STAB-1]) < RED_STAB_SIZE) return -EINVAL; ctl = RTA_DATA(tb[TCA_RED_PARMS-1]); sch_tree_lock(sch); q->flags = ctl->flags; - q->Wlog = ctl->Wlog; - q->Plog = ctl->Plog; - q->Rmask = ctl->Plog < 32 ? ((1<Plog) - 1) : ~0UL; - q->Scell_log = ctl->Scell_log; - q->Scell_max = (255<Scell_log); - q->qth_min = ctl->qth_min<Wlog; - q->qth_max = ctl->qth_max<Wlog; q->limit = ctl->limit; - memcpy(q->Stab, RTA_DATA(tb[TCA_RED_STAB-1]), 256); - q->qcount = -1; + red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog, + ctl->Plog, ctl->Scell_log, + RTA_DATA(tb[TCA_RED_STAB-1])); + if (skb_queue_empty(&sch->q)) - PSCHED_SET_PASTPERFECT(q->qidlestart); + red_end_of_idle_period(&q->parms); + sch_tree_unlock(sch); return 0; } @@ -399,39 +192,39 @@ static int red_init(struct Qdisc* sch, struct rtattr *opt) static int red_dump(struct Qdisc *sch, struct sk_buff *skb) { struct red_sched_data *q = qdisc_priv(sch); - unsigned char *b = skb->tail; - struct rtattr *rta; - struct tc_red_qopt opt; - - rta = (struct rtattr*)b; - RTA_PUT(skb, TCA_OPTIONS, 0, NULL); - opt.limit = q->limit; - opt.qth_min = q->qth_min>>q->Wlog; - opt.qth_max = q->qth_max>>q->Wlog; - opt.Wlog = q->Wlog; - opt.Plog = q->Plog; - opt.Scell_log = q->Scell_log; - opt.flags = q->flags; + struct rtattr *opts = NULL; + struct tc_red_qopt opt = { + .limit = q->limit, + .flags = q->flags, + .qth_min = q->parms.qth_min >> q->parms.Wlog, + .qth_max = q->parms.qth_max >> q->parms.Wlog, + .Wlog = q->parms.Wlog, + .Plog = q->parms.Plog, + .Scell_log = q->parms.Scell_log, + }; + + opts = RTA_NEST(skb, TCA_OPTIONS); RTA_PUT(skb, TCA_RED_PARMS, sizeof(opt), &opt); - rta->rta_len = skb->tail - b; - - return skb->len; + return RTA_NEST_END(skb, opts); rtattr_failure: - skb_trim(skb, b - skb->data); - return -1; + return RTA_NEST_CANCEL(skb, opts); } static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d) { struct red_sched_data *q = qdisc_priv(sch); - - return gnet_stats_copy_app(d, &q->st, sizeof(q->st)); + struct tc_red_xstats st = { + .early = q->stats.prob_drop + q->stats.forced_drop, + .pdrop = q->stats.pdrop, + .other = q->stats.other, + .marked = q->stats.prob_mark + q->stats.forced_mark, + }; + + return gnet_stats_copy_app(d, &st, sizeof(st)); } static struct Qdisc_ops red_qdisc_ops = { - .next = NULL, - .cl_ops = NULL, .id = "red", .priv_size = sizeof(struct red_sched_data), .enqueue = red_enqueue, @@ -450,10 +243,13 @@ static int __init red_module_init(void) { return register_qdisc(&red_qdisc_ops); } -static void __exit red_module_exit(void) + +static void __exit red_module_exit(void) { unregister_qdisc(&red_qdisc_ops); } + module_init(red_module_init) module_exit(red_module_exit) + MODULE_LICENSE("GPL"); diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 12b0f582a66b29707941da349b3f63582e5c0407..8c8ddf7f9b61c7c9ca7a804f8cbf8101fc151aa9 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -344,9 +344,7 @@ void sctp_association_free(struct sctp_association *asoc) } /* Free peer's cached cookie. */ - if (asoc->peer.cookie) { - kfree(asoc->peer.cookie); - } + kfree(asoc->peer.cookie); /* Release the transport structures. */ list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 660c61bdf16423c883dff5291fd60e2067b552d9..f9573eba5c7aa2f5507c12c0ff55a75e0e700490 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -254,8 +254,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc, aiparam.adaption_ind = htonl(sp->adaption_ind); sctp_addto_chunk(retval, sizeof(aiparam), &aiparam); nodata: - if (addrs.v) - kfree(addrs.v); + kfree(addrs.v); return retval; } @@ -347,8 +346,7 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc, nomem_chunk: kfree(cookie); nomem_cookie: - if (addrs.v) - kfree(addrs.v); + kfree(addrs.v); return retval; } diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index 13f8ae9794542d436f82274bff2e38c0a7724f18..d0dfdfd5e79efa926140d23e10ecba89e16cc381 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c @@ -143,6 +143,6 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, return ((ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE); out_err: - if (md5cksum.data) kfree(md5cksum.data); + kfree(md5cksum.data); return GSS_S_FAILURE; } diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c index 2030475d98ed26b22632a6dc6f01068ef6f92947..db055fd7d7789c22ef62e4e8faab7ebac7cafebd 100644 --- a/net/sunrpc/auth_gss/gss_krb5_unseal.c +++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c @@ -176,6 +176,6 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx, ret = GSS_S_COMPLETE; out: - if (md5cksum.data) kfree(md5cksum.data); + kfree(md5cksum.data); return ret; } diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c index b048bf672da2bbffbe35953b3e47a57b7e2383d3..f8bac6ccd524008a669c4e603d8526b9dabb006b 100644 --- a/net/sunrpc/auth_gss/gss_mech_switch.c +++ b/net/sunrpc/auth_gss/gss_mech_switch.c @@ -60,8 +60,7 @@ gss_mech_free(struct gss_api_mech *gm) for (i = 0; i < gm->gm_pf_num; i++) { pf = &gm->gm_pfs[i]; - if (pf->auth_domain_name) - kfree(pf->auth_domain_name); + kfree(pf->auth_domain_name); pf->auth_domain_name = NULL; } } diff --git a/net/sunrpc/auth_gss/gss_spkm3_seal.c b/net/sunrpc/auth_gss/gss_spkm3_seal.c index 148201e929d08de77ca44f6b6dfbe8da20ab7e04..d1e12b25d6e21f2b4e205c49b3ddd0d0fb7580b6 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_seal.c +++ b/net/sunrpc/auth_gss/gss_spkm3_seal.c @@ -122,8 +122,7 @@ spkm3_make_token(struct spkm3_ctx *ctx, return GSS_S_COMPLETE; out_err: - if (md5cksum.data) - kfree(md5cksum.data); + kfree(md5cksum.data); token->data = NULL; token->len = 0; return GSS_S_FAILURE; diff --git a/net/sunrpc/auth_gss/gss_spkm3_token.c b/net/sunrpc/auth_gss/gss_spkm3_token.c index 46c08a0710f62e147f0a4c6b4e6502be5a89ebbd..1f824578d773691c17c67daa6f76e9096730a789 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_token.c +++ b/net/sunrpc/auth_gss/gss_spkm3_token.c @@ -259,8 +259,7 @@ spkm3_verify_mic_token(unsigned char **tokp, int *mic_hdrlen, unsigned char **ck ret = GSS_S_COMPLETE; out: - if (spkm3_ctx_id.data) - kfree(spkm3_ctx_id.data); + kfree(spkm3_ctx_id.data); return ret; } diff --git a/net/sunrpc/auth_gss/gss_spkm3_unseal.c b/net/sunrpc/auth_gss/gss_spkm3_unseal.c index c3c0d95861039958305e89f437174b8c3bc13272..241d5b30dfcbcfb851093856f88b79698da35a81 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_unseal.c +++ b/net/sunrpc/auth_gss/gss_spkm3_unseal.c @@ -120,9 +120,7 @@ spkm3_read_token(struct spkm3_ctx *ctx, /* XXX: need to add expiration and sequencing */ ret = GSS_S_COMPLETE; out: - if (md5cksum.data) - kfree(md5cksum.data); - if (wire_cksum.data) - kfree(wire_cksum.data); + kfree(md5cksum.data); + kfree(wire_cksum.data); return ret; } diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index e9bd91265f70854654e0624fd0a3120b299d82fe..e4296c8b861eba85fead5bf1d839aa212e59ac7c 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -196,12 +196,9 @@ svc_exit_thread(struct svc_rqst *rqstp) struct svc_serv *serv = rqstp->rq_server; svc_release_buffer(rqstp); - if (rqstp->rq_resp) - kfree(rqstp->rq_resp); - if (rqstp->rq_argp) - kfree(rqstp->rq_argp); - if (rqstp->rq_auth_data) - kfree(rqstp->rq_auth_data); + kfree(rqstp->rq_resp); + kfree(rqstp->rq_argp); + kfree(rqstp->rq_auth_data); kfree(rqstp); /* Release the server */ @@ -313,6 +310,11 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp) rqstp->rq_proc = proc = ntohl(svc_getu32(argv)); /* procedure number */ progp = serv->sv_program; + + for (progp = serv->sv_program; progp; progp = progp->pg_next) + if (prog == progp->pg_prog) + break; + /* * Decode auth data, and add verifier to reply buffer. * We do this before anything else in order to get a decent @@ -320,7 +322,7 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp) */ auth_res = svc_authenticate(rqstp, &auth_stat); /* Also give the program a chance to reject this call: */ - if (auth_res == SVC_OK) { + if (auth_res == SVC_OK && progp) { auth_stat = rpc_autherr_badcred; auth_res = progp->pg_authenticate(rqstp); } @@ -340,10 +342,7 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp) case SVC_COMPLETE: goto sendit; } - - for (progp = serv->sv_program; progp; progp = progp->pg_next) - if (prog == progp->pg_prog) - break; + if (progp == NULL) goto err_bad_prog; diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 32df43372ee97cc277ed54d058f77667c8985160..aaf08cdd19f09fad9b9a36e7cdd8041606dbfd6e 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -992,8 +992,7 @@ xdr_xcode_array2(struct xdr_buf *buf, unsigned int base, err = 0; out: - if (elem) - kfree(elem); + kfree(elem); if (ppages) kunmap(*ppages); return err; diff --git a/net/wanrouter/af_wanpipe.c b/net/wanrouter/af_wanpipe.c index 596cb96e5f471227c348ce214d46dce63f5cf4a7..59fec59b2132df1ab43e782d2a469a84bf373dd0 100644 --- a/net/wanrouter/af_wanpipe.c +++ b/net/wanrouter/af_wanpipe.c @@ -1099,7 +1099,7 @@ static void release_driver(struct sock *sk) sock_reset_flag(sk, SOCK_ZAPPED); wp = wp_sk(sk); - if (wp && wp->mbox) { + if (wp) { kfree(wp->mbox); wp->mbox = NULL; } @@ -1186,10 +1186,8 @@ static void wanpipe_kill_sock_timer (unsigned long data) return; } - if (wp_sk(sk)) { - kfree(wp_sk(sk)); - wp_sk(sk) = NULL; - } + kfree(wp_sk(sk)); + wp_sk(sk) = NULL; if (atomic_read(&sk->sk_refcnt) != 1) { atomic_set(&sk->sk_refcnt, 1); @@ -1219,10 +1217,8 @@ static void wanpipe_kill_sock_accept (struct sock *sk) sk->sk_socket = NULL; - if (wp_sk(sk)) { - kfree(wp_sk(sk)); - wp_sk(sk) = NULL; - } + kfree(wp_sk(sk)); + wp_sk(sk) = NULL; if (atomic_read(&sk->sk_refcnt) != 1) { atomic_set(&sk->sk_refcnt, 1); @@ -1243,10 +1239,8 @@ static void wanpipe_kill_sock_irq (struct sock *sk) sk->sk_socket = NULL; - if (wp_sk(sk)) { - kfree(wp_sk(sk)); - wp_sk(sk) = NULL; - } + kfree(wp_sk(sk)); + wp_sk(sk) = NULL; if (atomic_read(&sk->sk_refcnt) != 1) { atomic_set(&sk->sk_refcnt, 1); diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c index 13b650ad22e21a6a6bec891d5bfe8ce4efb52236..bcf7b3faa76a4020d6308f5998fead39cce7b961 100644 --- a/net/wanrouter/wanmain.c +++ b/net/wanrouter/wanmain.c @@ -714,10 +714,8 @@ static int wanrouter_device_new_if(struct wan_device *wandev, } /* This code has moved from del_if() function */ - if (dev->priv) { - kfree(dev->priv); - dev->priv = NULL; - } + kfree(dev->priv); + dev->priv = NULL; #ifdef CONFIG_WANPIPE_MULTPPP if (cnf->config_id == WANCONFIG_MPPP) @@ -851,10 +849,8 @@ static int wanrouter_delete_interface(struct wan_device *wandev, char *name) /* Due to new interface linking method using dev->priv, * this code has moved from del_if() function.*/ - if (dev->priv){ - kfree(dev->priv); - dev->priv=NULL; - } + kfree(dev->priv); + dev->priv=NULL; unregister_netdev(dev); diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 8b9a4747417d00bbf4c6b9050f59f7ca4eb24951..7cf48aa6c95bdb48a9438c6c4a3159fefe403869 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -62,14 +62,10 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x) { if (del_timer(&x->timer)) BUG(); - if (x->aalg) - kfree(x->aalg); - if (x->ealg) - kfree(x->ealg); - if (x->calg) - kfree(x->calg); - if (x->encap) - kfree(x->encap); + kfree(x->aalg); + kfree(x->ealg); + kfree(x->calg); + kfree(x->encap); if (x->type) { x->type->destructor(x); xfrm_put_type(x->type); diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 455aeabd95dd59a441566e2de9e2f80f1961fa26..c65c435c4923b52de56e8d024d773a53a01848d2 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -118,7 +118,7 @@ clean-files := lkc_defs.h qconf.moc .tmp_qtcheck \ # Needed for systems without gettext KBUILD_HAVE_NLS := $(shell \ - if echo "\#include " | $(HOSTCC) $(HOSTCFLAGS) -E - > /dev/null 2>&1 ; \ + if echo "\#include " | $(HOSTCC) $(HOSTCFLAGS) -E - > /dev/null 2>&1 ; \ then echo yes ; \ else echo no ; fi) ifeq ($(KBUILD_HAVE_NLS),no) diff --git a/security/keys/key.c b/security/keys/key.c index ccde17aff6167848388ce263c4fddec30c8131e5..01bcfecb7eae755d28189419736361d42a41bc26 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -115,8 +115,7 @@ struct key_user *key_user_lookup(uid_t uid) found: atomic_inc(&user->usage); spin_unlock(&key_user_lock); - if (candidate) - kfree(candidate); + kfree(candidate); out: return user; diff --git a/security/keys/keyring.c b/security/keys/keyring.c index e1cc4dd7901221352185e71daeffe1f3f779e325..c7a0ab1cfda35aacd868504c3033417c58c9e9e7 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -434,8 +434,8 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, if (sp >= KEYRING_SEARCH_MAX_DEPTH) continue; - if (!key_task_permission(make_key_ref(key, possessed), - context, KEY_SEARCH) < 0) + if (key_task_permission(make_key_ref(key, possessed), + context, KEY_SEARCH) < 0) continue; /* stack the current position */ @@ -621,8 +621,8 @@ struct key *find_keyring_by_name(const char *name, key_serial_t bound) if (strcmp(keyring->description, name) != 0) continue; - if (!key_permission(make_key_ref(keyring, 0), - KEY_SEARCH) < 0) + if (key_permission(make_key_ref(keyring, 0), + KEY_SEARCH) < 0) continue; /* found a potential candidate, but we still need to diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 2f5f539875f2d0e60b780b407deef7fb64aeecdb..0ac311dc8371ecd540168f200c535ae4a6f7ac12 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -632,22 +632,22 @@ void policydb_destroy(struct policydb *p) cond_policydb_destroy(p); for (tr = p->role_tr; tr; tr = tr->next) { - if (ltr) kfree(ltr); + kfree(ltr); ltr = tr; } - if (ltr) kfree(ltr); + kfree(ltr); for (ra = p->role_allow; ra; ra = ra -> next) { - if (lra) kfree(lra); + kfree(lra); lra = ra; } - if (lra) kfree(lra); + kfree(lra); for (rt = p->range_tr; rt; rt = rt -> next) { - if (lrt) kfree(lrt); + kfree(lrt); lrt = rt; } - if (lrt) kfree(lrt); + kfree(lrt); if (p->type_attr_map) { for (i = 0; i < p->p_types.nprim; i++) diff --git a/sound/Kconfig b/sound/Kconfig index b65ee4701f98fab7d6564d9cee6d771455aa3603..d8f11408ce274a2b2c67256d0ec07d3c3a828bdd 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -48,6 +48,14 @@ config SND For more information, see +config SND_AC97_CODEC + tristate + select SND_PCM + select SND_AC97_BUS + +config SND_AC97_BUS + tristate + source "sound/core/Kconfig" source "sound/drivers/Kconfig" diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 48cf45cfd0b7943f23f1890fa3c898dc1b5a98eb..82718836f93726a0d2ec464117b759dc4aa28442 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -127,12 +127,6 @@ config SND_DEBUG help Say Y here to enable ALSA debug code. -config SND_DEBUG_MEMORY - bool "Debug memory" - depends on SND_DEBUG - help - Say Y here to enable debugging of memory allocations. - config SND_DEBUG_DETECT bool "Debug detection" depends on SND_DEBUG diff --git a/sound/core/Makefile b/sound/core/Makefile index 969d75528bdeb9189f5ff9fdc8aaddac165bf1f5..5a01c76d02e8f0c90b7196c2588e2695a43e6bc8 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -3,8 +3,7 @@ # Copyright (c) 1999,2001 by Jaroslav Kysela # -snd-objs := sound.o init.o memory.o info.o control.o misc.o \ - device.o wrappers.o +snd-objs := sound.o init.o memory.o info.o control.o misc.o device.o ifeq ($(CONFIG_ISA_DMA_API),y) snd-objs += isadma.o endif diff --git a/sound/core/control.c b/sound/core/control.c index 736edf358e050cee4f93e698811e974fe2f380c0..212c46a94376c29cf303f225c4d7036d7e32842c 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -144,7 +144,7 @@ void snd_ctl_notify(snd_card_t *card, unsigned int mask, snd_ctl_elem_id_t *id) snd_ctl_file_t *ctl; snd_kctl_event_t *ev; - snd_runtime_check(card != NULL && id != NULL, return); + snd_assert(card != NULL && id != NULL, return); read_lock(&card->ctl_files_rwlock); #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) card->mixer_oss_change_count++; @@ -193,8 +193,8 @@ snd_kcontrol_t *snd_ctl_new(snd_kcontrol_t * control, unsigned int access) snd_kcontrol_t *kctl; unsigned int idx; - snd_runtime_check(control != NULL, return NULL); - snd_runtime_check(control->count > 0, return NULL); + snd_assert(control != NULL, return NULL); + snd_assert(control->count > 0, return NULL); kctl = kzalloc(sizeof(*kctl) + sizeof(snd_kcontrol_volatile_t) * control->count, GFP_KERNEL); if (kctl == NULL) return NULL; @@ -220,7 +220,7 @@ snd_kcontrol_t *snd_ctl_new1(const snd_kcontrol_new_t * ncontrol, void *private_ snd_kcontrol_t kctl; unsigned int access; - snd_runtime_check(ncontrol != NULL, return NULL); + snd_assert(ncontrol != NULL, return NULL); snd_assert(ncontrol->info != NULL, return NULL); memset(&kctl, 0, sizeof(kctl)); kctl.id.iface = ncontrol->iface; @@ -309,7 +309,7 @@ int snd_ctl_add(snd_card_t * card, snd_kcontrol_t * kcontrol) snd_ctl_elem_id_t id; unsigned int idx; - snd_runtime_check(card != NULL && kcontrol != NULL, return -EINVAL); + snd_assert(card != NULL && kcontrol != NULL, return -EINVAL); snd_assert(kcontrol->info != NULL, return -EINVAL); id = kcontrol->id; down_write(&card->controls_rwsem); @@ -355,7 +355,7 @@ int snd_ctl_remove(snd_card_t * card, snd_kcontrol_t * kcontrol) snd_ctl_elem_id_t id; unsigned int idx; - snd_runtime_check(card != NULL && kcontrol != NULL, return -EINVAL); + snd_assert(card != NULL && kcontrol != NULL, return -EINVAL); list_del(&kcontrol->list); card->controls_count -= kcontrol->count; id = kcontrol->id; @@ -468,7 +468,7 @@ snd_kcontrol_t *snd_ctl_find_numid(snd_card_t * card, unsigned int numid) struct list_head *list; snd_kcontrol_t *kctl; - snd_runtime_check(card != NULL && numid != 0, return NULL); + snd_assert(card != NULL && numid != 0, return NULL); list_for_each(list, &card->controls) { kctl = snd_kcontrol(list); if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid) @@ -494,7 +494,7 @@ snd_kcontrol_t *snd_ctl_find_id(snd_card_t * card, snd_ctl_elem_id_t *id) struct list_head *list; snd_kcontrol_t *kctl; - snd_runtime_check(card != NULL && id != NULL, return NULL); + snd_assert(card != NULL && id != NULL, return NULL); if (id->numid != 0) return snd_ctl_find_numid(card, id->numid); list_for_each(list, &card->controls) { @@ -1215,7 +1215,7 @@ static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head struct list_head *list; snd_kctl_ioctl_t *p; - snd_runtime_check(fcn != NULL, return -EINVAL); + snd_assert(fcn != NULL, return -EINVAL); down_write(&snd_ioctl_rwsem); list_for_each(list, lists) { p = list_entry(list, snd_kctl_ioctl_t, list); diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 9383f1294fb5ec528bd2160df78fd1b579ec5279..e91cee35a4b9e3d640ad159b489644a941bf0da9 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -81,20 +81,16 @@ static int snd_hwdep_open(struct inode *inode, struct file * file) int err; wait_queue_t wait; - switch (major) { - case CONFIG_SND_MAJOR: + if (major == snd_major) { cardnum = SNDRV_MINOR_CARD(iminor(inode)); device = SNDRV_MINOR_DEVICE(iminor(inode)) - SNDRV_MINOR_HWDEP; - break; #ifdef CONFIG_SND_OSSEMUL - case SOUND_MAJOR: + } else if (major == SOUND_MAJOR) { cardnum = SNDRV_MINOR_OSS_CARD(iminor(inode)); device = 0; - break; #endif - default: + } else return -ENXIO; - } cardnum %= SNDRV_CARDS; device %= SNDRV_MINOR_HWDEPS; hw = snd_hwdep_devices[(cardnum * SNDRV_MINOR_HWDEPS) + device]; diff --git a/sound/core/info.c b/sound/core/info.c index 37024d68a26ea25a5358aff96c5c34857fc549d2..39f9b97d92198582fbb34a6281d864b6443d90e8 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -566,7 +566,6 @@ int __init snd_info_init(void) } #endif snd_info_version_init(); - snd_memory_info_init(); snd_minor_info_init(); snd_minor_info_oss_init(); snd_card_info_init(); @@ -578,7 +577,6 @@ int __exit snd_info_done(void) snd_card_info_done(); snd_minor_info_oss_done(); snd_minor_info_done(); - snd_memory_info_done(); snd_info_version_done(); if (snd_proc_root) { #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) diff --git a/sound/core/init.c b/sound/core/init.c index 41e224986f35e7306e5a8fda52bdf91a0860c81c..d9ee27ae9a510a2a1e5ff23e767fda896a9e5e37 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -420,7 +420,7 @@ int snd_card_register(snd_card_t * card) int err; snd_info_entry_t *entry; - snd_runtime_check(card != NULL, return -EINVAL); + snd_assert(card != NULL, return -EINVAL); if ((err = snd_device_register_all(card)) < 0) return err; write_lock(&snd_card_rwlock); @@ -524,7 +524,8 @@ int __init snd_card_info_init(void) snd_info_entry_t *entry; entry = snd_info_create_module_entry(THIS_MODULE, "cards", NULL); - snd_runtime_check(entry != NULL, return -ENOMEM); + if (! entry) + return -ENOMEM; entry->c.text.read_size = PAGE_SIZE; entry->c.text.read = snd_card_info_read; if (snd_info_register(entry) < 0) { @@ -840,7 +841,7 @@ static int snd_generic_resume(struct device *dev) card = get_snd_generic_card(dev); if (card->power_state == SNDRV_CTL_POWER_D0) return 0; - if (card->pm_suspend) + if (card->pm_resume) card->pm_resume(card); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; diff --git a/sound/core/memory.c b/sound/core/memory.c index 7d8e2eebba5185326d0d3161a429b7758e263a3b..862d62d2e144f107a76d9c2b0af93e4c95e1096d 100644 --- a/sound/core/memory.c +++ b/sound/core/memory.c @@ -1,7 +1,7 @@ /* * Copyright (c) by Jaroslav Kysela * - * Memory allocation helpers. + * Misc memory accessors * * * This program is free software; you can redistribute it and/or modify @@ -20,221 +20,9 @@ * */ -#include +#include #include #include -#include -#include -#include -#include -#include -#include - -/* - * memory allocation helpers and debug routines - */ - -#ifdef CONFIG_SND_DEBUG_MEMORY - -struct snd_alloc_track { - unsigned long magic; - void *caller; - size_t size; - struct list_head list; - long data[0]; -}; - -#define snd_alloc_track_entry(obj) (struct snd_alloc_track *)((char*)obj - (unsigned long)((struct snd_alloc_track *)0)->data) - -static long snd_alloc_kmalloc; -static long snd_alloc_vmalloc; -static LIST_HEAD(snd_alloc_kmalloc_list); -static LIST_HEAD(snd_alloc_vmalloc_list); -static DEFINE_SPINLOCK(snd_alloc_kmalloc_lock); -static DEFINE_SPINLOCK(snd_alloc_vmalloc_lock); -#define KMALLOC_MAGIC 0x87654321 -#define VMALLOC_MAGIC 0x87654320 -static snd_info_entry_t *snd_memory_info_entry; - -void __init snd_memory_init(void) -{ - snd_alloc_kmalloc = 0; - snd_alloc_vmalloc = 0; -} - -void snd_memory_done(void) -{ - struct list_head *head; - struct snd_alloc_track *t; - - if (snd_alloc_kmalloc > 0) - snd_printk(KERN_ERR "Not freed snd_alloc_kmalloc = %li\n", snd_alloc_kmalloc); - if (snd_alloc_vmalloc > 0) - snd_printk(KERN_ERR "Not freed snd_alloc_vmalloc = %li\n", snd_alloc_vmalloc); - list_for_each_prev(head, &snd_alloc_kmalloc_list) { - t = list_entry(head, struct snd_alloc_track, list); - if (t->magic != KMALLOC_MAGIC) { - snd_printk(KERN_ERR "Corrupted kmalloc\n"); - break; - } - snd_printk(KERN_ERR "kmalloc(%ld) from %p not freed\n", (long) t->size, t->caller); - } - list_for_each_prev(head, &snd_alloc_vmalloc_list) { - t = list_entry(head, struct snd_alloc_track, list); - if (t->magic != VMALLOC_MAGIC) { - snd_printk(KERN_ERR "Corrupted vmalloc\n"); - break; - } - snd_printk(KERN_ERR "vmalloc(%ld) from %p not freed\n", (long) t->size, t->caller); - } -} - -static void *__snd_kmalloc(size_t size, gfp_t flags, void *caller) -{ - unsigned long cpu_flags; - struct snd_alloc_track *t; - void *ptr; - - ptr = snd_wrapper_kmalloc(size + sizeof(struct snd_alloc_track), flags); - if (ptr != NULL) { - t = (struct snd_alloc_track *)ptr; - t->magic = KMALLOC_MAGIC; - t->caller = caller; - spin_lock_irqsave(&snd_alloc_kmalloc_lock, cpu_flags); - list_add_tail(&t->list, &snd_alloc_kmalloc_list); - spin_unlock_irqrestore(&snd_alloc_kmalloc_lock, cpu_flags); - t->size = size; - snd_alloc_kmalloc += size; - ptr = t->data; - } - return ptr; -} - -#define _snd_kmalloc(size, flags) __snd_kmalloc((size), (flags), __builtin_return_address(0)); -void *snd_hidden_kmalloc(size_t size, gfp_t flags) -{ - return _snd_kmalloc(size, flags); -} - -void *snd_hidden_kzalloc(size_t size, gfp_t flags) -{ - void *ret = _snd_kmalloc(size, flags); - if (ret) - memset(ret, 0, size); - return ret; -} -EXPORT_SYMBOL(snd_hidden_kzalloc); - -void *snd_hidden_kcalloc(size_t n, size_t size, gfp_t flags) -{ - void *ret = NULL; - if (n != 0 && size > INT_MAX / n) - return ret; - return snd_hidden_kzalloc(n * size, flags); -} - -void snd_hidden_kfree(const void *obj) -{ - unsigned long flags; - struct snd_alloc_track *t; - if (obj == NULL) - return; - t = snd_alloc_track_entry(obj); - if (t->magic != KMALLOC_MAGIC) { - snd_printk(KERN_WARNING "bad kfree (called from %p)\n", __builtin_return_address(0)); - return; - } - spin_lock_irqsave(&snd_alloc_kmalloc_lock, flags); - list_del(&t->list); - spin_unlock_irqrestore(&snd_alloc_kmalloc_lock, flags); - t->magic = 0; - snd_alloc_kmalloc -= t->size; - obj = t; - snd_wrapper_kfree(obj); -} - -void *snd_hidden_vmalloc(unsigned long size) -{ - void *ptr; - ptr = snd_wrapper_vmalloc(size + sizeof(struct snd_alloc_track)); - if (ptr) { - struct snd_alloc_track *t = (struct snd_alloc_track *)ptr; - t->magic = VMALLOC_MAGIC; - t->caller = __builtin_return_address(0); - spin_lock(&snd_alloc_vmalloc_lock); - list_add_tail(&t->list, &snd_alloc_vmalloc_list); - spin_unlock(&snd_alloc_vmalloc_lock); - t->size = size; - snd_alloc_vmalloc += size; - ptr = t->data; - } - return ptr; -} - -void snd_hidden_vfree(void *obj) -{ - struct snd_alloc_track *t; - if (obj == NULL) - return; - t = snd_alloc_track_entry(obj); - if (t->magic != VMALLOC_MAGIC) { - snd_printk(KERN_ERR "bad vfree (called from %p)\n", __builtin_return_address(0)); - return; - } - spin_lock(&snd_alloc_vmalloc_lock); - list_del(&t->list); - spin_unlock(&snd_alloc_vmalloc_lock); - t->magic = 0; - snd_alloc_vmalloc -= t->size; - obj = t; - snd_wrapper_vfree(obj); -} - -char *snd_hidden_kstrdup(const char *s, gfp_t flags) -{ - int len; - char *buf; - - if (!s) return NULL; - - len = strlen(s) + 1; - buf = _snd_kmalloc(len, flags); - if (buf) - memcpy(buf, s, len); - return buf; -} - -static void snd_memory_info_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer) -{ - snd_iprintf(buffer, "kmalloc: %li bytes\n", snd_alloc_kmalloc); - snd_iprintf(buffer, "vmalloc: %li bytes\n", snd_alloc_vmalloc); -} - -int __init snd_memory_info_init(void) -{ - snd_info_entry_t *entry; - - entry = snd_info_create_module_entry(THIS_MODULE, "meminfo", NULL); - if (entry) { - entry->c.text.read_size = 256; - entry->c.text.read = snd_memory_info_read; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } - } - snd_memory_info_entry = entry; - return 0; -} - -int __exit snd_memory_info_done(void) -{ - if (snd_memory_info_entry) - snd_info_unregister(snd_memory_info_entry); - return 0; -} - -#endif /* CONFIG_SND_DEBUG_MEMORY */ /** * copy_to_user_fromio - copy data from mmio-space to user-space diff --git a/sound/core/misc.c b/sound/core/misc.c index 1a81fe4df218b2a47c7428d7b5225bc6b1ad8446..b53e563c09e60d0e16f843bb034d0842df0cc432 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c @@ -23,17 +23,15 @@ #include #include #include +#include #include -int snd_task_name(struct task_struct *task, char *name, size_t size) +void release_and_free_resource(struct resource *res) { - unsigned int idx; - - snd_assert(task != NULL && name != NULL && size >= 2, return -EINVAL); - for (idx = 0; idx < sizeof(task->comm) && idx + 1 < size; idx++) - name[idx] = task->comm[idx]; - name[idx] = '\0'; - return 0; + if (res) { + release_resource(res); + kfree(res); + } } #ifdef CONFIG_SND_VERBOSE_PRINTK diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 69e1059112d1ace7eadd3fd85a40b48020488394..214933cf5d49a62084fc655a9ec05a5a438a7919 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -521,9 +521,13 @@ static void snd_mixer_oss_get_volume1_vol(snd_mixer_oss_file_t *fmixer, uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) goto __unalloc; - snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc); - snd_runtime_check(!kctl->get(kctl, uctl), goto __unalloc); - snd_runtime_check(uinfo->type != SNDRV_CTL_ELEM_TYPE_BOOLEAN || uinfo->value.integer.min != 0 || uinfo->value.integer.max != 1, goto __unalloc); + if (kctl->info(kctl, uinfo)) + goto __unalloc; + if (kctl->get(kctl, uctl)) + goto __unalloc; + if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN && + uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1) + goto __unalloc; *left = snd_mixer_oss_conv1(uctl->value.integer.value[0], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[0]); if (uinfo->count > 1) *right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]); @@ -555,8 +559,10 @@ static void snd_mixer_oss_get_volume1_sw(snd_mixer_oss_file_t *fmixer, uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) goto __unalloc; - snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc); - snd_runtime_check(!kctl->get(kctl, uctl), goto __unalloc); + if (kctl->info(kctl, uinfo)) + goto __unalloc; + if (kctl->get(kctl, uctl)) + goto __unalloc; if (!uctl->value.integer.value[0]) { *left = 0; if (uinfo->count == 1) @@ -616,12 +622,16 @@ static void snd_mixer_oss_put_volume1_vol(snd_mixer_oss_file_t *fmixer, uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) goto __unalloc; - snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc); - snd_runtime_check(uinfo->type != SNDRV_CTL_ELEM_TYPE_BOOLEAN || uinfo->value.integer.min != 0 || uinfo->value.integer.max != 1, goto __unalloc); + if (kctl->info(kctl, uinfo)) + goto __unalloc; + if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN && + uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1) + goto __unalloc; uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max); if (uinfo->count > 1) uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max); - snd_runtime_check((res = kctl->put(kctl, uctl)) >= 0, goto __unalloc); + if ((res = kctl->put(kctl, uctl)) < 0) + goto __unalloc; if (res > 0) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); __unalloc: @@ -653,7 +663,8 @@ static void snd_mixer_oss_put_volume1_sw(snd_mixer_oss_file_t *fmixer, uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) goto __unalloc; - snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc); + if (kctl->info(kctl, uinfo)) + goto __unalloc; if (uinfo->count > 1) { uctl->value.integer.value[0] = left > 0 ? 1 : 0; uctl->value.integer.value[route ? 3 : 1] = right > 0 ? 1 : 0; @@ -664,7 +675,8 @@ static void snd_mixer_oss_put_volume1_sw(snd_mixer_oss_file_t *fmixer, } else { uctl->value.integer.value[0] = (left > 0 || right > 0) ? 1 : 0; } - snd_runtime_check((res = kctl->put(kctl, uctl)) >= 0, goto __unalloc); + if ((res = kctl->put(kctl, uctl)) < 0) + goto __unalloc; if (res > 0) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); __unalloc: @@ -776,9 +788,14 @@ static int snd_mixer_oss_get_recsrc2(snd_mixer_oss_file_t *fmixer, unsigned int } down_read(&card->controls_rwsem); kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); - snd_runtime_check(kctl != NULL, err = -ENOENT; goto __unlock); - snd_runtime_check(!(err = kctl->info(kctl, uinfo)), goto __unlock); - snd_runtime_check(!(err = kctl->get(kctl, uctl)), goto __unlock); + if (! kctl) { + err = -ENOENT; + goto __unlock; + } + if ((err = kctl->info(kctl, uinfo)) < 0) + goto __unlock; + if ((err = kctl->get(kctl, uctl)) < 0) + goto __unlock; for (idx = 0; idx < 32; idx++) { if (!(mixer->mask_recsrc & (1 << idx))) continue; @@ -821,8 +838,12 @@ static int snd_mixer_oss_put_recsrc2(snd_mixer_oss_file_t *fmixer, unsigned int } down_read(&card->controls_rwsem); kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); - snd_runtime_check(kctl != NULL, err = -ENOENT; goto __unlock); - snd_runtime_check(!(err = kctl->info(kctl, uinfo)), goto __unlock); + if (! kctl) { + err = -ENOENT; + goto __unlock; + } + if ((err = kctl->info(kctl, uinfo)) < 0) + goto __unlock; for (idx = 0; idx < 32; idx++) { if (!(mixer->mask_recsrc & (1 << idx))) continue; @@ -836,10 +857,11 @@ static int snd_mixer_oss_put_recsrc2(snd_mixer_oss_file_t *fmixer, unsigned int break; slot = NULL; } - snd_runtime_check(slot != NULL, goto __unlock); + if (! slot) + goto __unlock; for (idx = 0; idx < uinfo->count; idx++) uctl->value.enumerated.item[idx] = slot->capture_item; - snd_runtime_check((err = kctl->put(kctl, uctl)) >= 0, ); + err = kctl->put(kctl, uctl); if (err > 0) snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); err = 0; @@ -1008,7 +1030,8 @@ static int snd_mixer_oss_build_input(snd_mixer_oss_t *mixer, struct snd_mixer_os up_read(&mixer->card->controls_rwsem); if (slot.present != 0) { pslot = (struct slot *)kmalloc(sizeof(slot), GFP_KERNEL); - snd_runtime_check(pslot != NULL, return -ENOMEM); + if (! pslot) + return -ENOMEM; *pslot = slot; pslot->signature = SNDRV_MIXER_OSS_SIGNATURE; pslot->assigned = ptr; @@ -1271,7 +1294,8 @@ static int snd_mixer_oss_notify_handler(snd_card_t * card, int cmd) card, 0, &snd_mixer_oss_reg, name)) < 0) { - snd_printk("unable to register OSS mixer device %i:%i\n", card->number, 0); + snd_printk(KERN_ERR "unable to register OSS mixer device %i:%i\n", + card->number, 0); kfree(mixer); return err; } diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 842c28b2ed55cfad9266cd3e0245fe2f4648892d..bcc970759134ec86e3c271e4c1738451227ca5de 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1821,6 +1821,17 @@ static int snd_pcm_oss_open_file(struct file *file, } +static int snd_task_name(struct task_struct *task, char *name, size_t size) +{ + unsigned int idx; + + snd_assert(task != NULL && name != NULL && size >= 2, return -EINVAL); + for (idx = 0; idx < sizeof(task->comm) && idx + 1 < size; idx++) + name[idx] = task->comm[idx]; + name[idx] = '\0'; + return 0; +} + static int snd_pcm_oss_open(struct inode *inode, struct file *file) { int minor = iminor(inode); @@ -2446,7 +2457,8 @@ static void register_oss_dsp(snd_pcm_t *pcm, int index) if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM, pcm->card, index, &snd_pcm_oss_reg, name) < 0) { - snd_printk("unable to register OSS PCM device %i:%i\n", pcm->card->number, pcm->device); + snd_printk(KERN_ERR "unable to register OSS PCM device %i:%i\n", + pcm->card->number, pcm->device); } } @@ -2528,11 +2540,13 @@ static int __init alsa_pcm_oss_init(void) /* check device map table */ for (i = 0; i < SNDRV_CARDS; i++) { if (dsp_map[i] < 0 || dsp_map[i] >= SNDRV_PCM_DEVICES) { - snd_printk("invalid dsp_map[%d] = %d\n", i, dsp_map[i]); + snd_printk(KERN_ERR "invalid dsp_map[%d] = %d\n", + i, dsp_map[i]); dsp_map[i] = 0; } if (adsp_map[i] < 0 || adsp_map[i] >= SNDRV_PCM_DEVICES) { - snd_printk("invalid adsp_map[%d] = %d\n", i, adsp_map[i]); + snd_printk(KERN_ERR "invalid adsp_map[%d] = %d\n", + i, adsp_map[i]); adsp_map[i] = 1; } } diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 1be470e942efa6e0c6159d99a0bac430caa553f2..184e74b75ba96f78c523d3464960c42cf09396b9 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -273,7 +273,8 @@ static void snd_pcm_proc_info_read(snd_pcm_substream_t *substream, snd_info_buff snd_pcm_info_t *info; int err; - snd_runtime_check(substream, return); + if (! substream) + return; info = kmalloc(sizeof(*info), GFP_KERNEL); if (! info) { diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 0503980c23d91ca67ac04c93fc9ae86740cc42df..3dbf9bf2ac162ef49cb40f79805b99927384c7e9 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -152,13 +152,12 @@ static inline snd_pcm_uframes_t snd_pcm_update_hw_ptr_pos(snd_pcm_substream_t *s if (pos == SNDRV_PCM_POS_XRUN) return pos; /* XRUN */ if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP) - snd_timestamp_now((snd_timestamp_t*)&runtime->status->tstamp, runtime->tstamp_timespec); + getnstimeofday((struct timespec *)&runtime->status->tstamp); #ifdef CONFIG_SND_DEBUG if (pos >= runtime->buffer_size) { snd_printk(KERN_ERR "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size); - } else + } #endif - snd_runtime_check(pos < runtime->buffer_size, return 0); pos -= pos % runtime->min_align; return pos; } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index e97b2d162cc72f3140792ec9725bf71078011183..16e252f5495424fc051eb0c3d4f2584990fe22bb 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -565,9 +565,9 @@ int snd_pcm_status(snd_pcm_substream_t *substream, if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP) status->tstamp = runtime->status->tstamp; else - snd_timestamp_now(&status->tstamp, runtime->tstamp_timespec); + getnstimeofday(&status->tstamp); } else - snd_timestamp_now(&status->tstamp, runtime->tstamp_timespec); + getnstimeofday(&status->tstamp); status->appl_ptr = runtime->control->appl_ptr; status->hw_ptr = runtime->status->hw_ptr; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { @@ -652,7 +652,7 @@ static void snd_pcm_trigger_tstamp(snd_pcm_substream_t *substream) if (runtime->trigger_master == NULL) return; if (runtime->trigger_master == substream) { - snd_timestamp_now(&runtime->trigger_tstamp, runtime->tstamp_timespec); + getnstimeofday(&runtime->trigger_tstamp); } else { snd_pcm_trigger_tstamp(runtime->trigger_master); runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp; @@ -1522,7 +1522,6 @@ static int snd_pcm_drop(snd_pcm_substream_t *substream) /* WARNING: Don't forget to fput back the file */ -extern int snd_major; static struct file *snd_pcm_file_fd(int fd) { struct file *file; @@ -2053,7 +2052,8 @@ static int snd_pcm_open(struct inode *inode, struct file *file) snd_pcm_file_t *pcm_file; wait_queue_t wait; - snd_runtime_check(device >= SNDRV_MINOR_PCM_PLAYBACK && device < SNDRV_MINOR_DEVICES, return -ENXIO); + if (device < SNDRV_MINOR_PCM_PLAYBACK || device >= SNDRV_MINOR_DEVICES) + return -ENXIO; pcm = snd_pcm_devices[(cardnum * SNDRV_PCM_DEVICES) + (device % SNDRV_MINOR_PCMS)]; if (pcm == NULL) { err = -ENODEV; @@ -2445,14 +2445,8 @@ static int snd_pcm_common_ioctl1(snd_pcm_substream_t *substream, return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0; case SNDRV_PCM_IOCTL_INFO: return snd_pcm_info_user(substream, arg); - case SNDRV_PCM_IOCTL_TSTAMP: - { - int xarg; - if (get_user(xarg, (int __user *)arg)) - return -EFAULT; - substream->runtime->tstamp_timespec = xarg ? 1 : 0; + case SNDRV_PCM_IOCTL_TSTAMP: /* just for compatibility */ return 0; - } case SNDRV_PCM_IOCTL_HW_REFINE: return snd_pcm_hw_refine_user(substream, arg); case SNDRV_PCM_IOCTL_HW_PARAMS: diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 7c20eafecb8ac6932cf9e547d6d16e0edeb129da..d033e61c05c7b24ac9687fb6f059e66160a8757d 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -378,24 +378,20 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) struct list_head *list; snd_ctl_file_t *kctl; - switch (maj) { - case CONFIG_SND_MAJOR: + if (maj == snd_major) { cardnum = SNDRV_MINOR_CARD(iminor(inode)); cardnum %= SNDRV_CARDS; device = SNDRV_MINOR_DEVICE(iminor(inode)) - SNDRV_MINOR_RAWMIDI; device %= SNDRV_MINOR_RAWMIDIS; - break; #ifdef CONFIG_SND_OSSEMUL - case SOUND_MAJOR: + } else if (maj == SOUND_MAJOR) { cardnum = SNDRV_MINOR_OSS_CARD(iminor(inode)); cardnum %= SNDRV_CARDS; device = SNDRV_MINOR_OSS_DEVICE(iminor(inode)) == SNDRV_MINOR_OSS_MIDI ? midi_map[cardnum] : amidi_map[cardnum]; - break; #endif - default: + } else return -ENXIO; - } rmidi = snd_rawmidi_devices[(cardnum * SNDRV_RAWMIDI_DEVICES) + device]; if (rmidi == NULL) @@ -411,7 +407,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) if (err < 0) return -ENODEV; fflags = snd_rawmidi_file_flags(file); - if ((file->f_flags & O_APPEND) || maj != CONFIG_SND_MAJOR) /* OSS emul? */ + if ((file->f_flags & O_APPEND) || maj == SOUND_MAJOR) /* OSS emul? */ fflags |= SNDRV_RAWMIDI_LFLG_APPEND; fflags |= SNDRV_RAWMIDI_LFLG_NOOPENLOCK; rawmidi_file = kmalloc(sizeof(*rawmidi_file), GFP_KERNEL); diff --git a/sound/core/rtctimer.c b/sound/core/rtctimer.c index bd5d584d284d58f13035aa2a71f728095ec2f03f..c3c18568207e4f1a70bfd7bba7318dd69bb98660 100644 --- a/sound/core/rtctimer.c +++ b/sound/core/rtctimer.c @@ -60,7 +60,6 @@ static struct _snd_timer_hardware rtc_hw = { static int rtctimer_freq = RTC_FREQ; /* frequency */ static snd_timer_t *rtctimer; -static atomic_t rtc_inc = ATOMIC_INIT(0); static rtc_task_t rtc_task; @@ -94,7 +93,6 @@ rtctimer_start(snd_timer_t *timer) snd_assert(rtc != NULL, return -EINVAL); rtc_control(rtc, RTC_IRQP_SET, rtctimer_freq); rtc_control(rtc, RTC_PIE_ON, 0); - atomic_set(&rtc_inc, 0); return 0; } @@ -112,12 +110,7 @@ rtctimer_stop(snd_timer_t *timer) */ static void rtctimer_interrupt(void *private_data) { - int ticks; - - atomic_inc(&rtc_inc); - ticks = atomic_read(&rtc_inc); - snd_timer_interrupt((snd_timer_t*)private_data, ticks); - atomic_sub(ticks, &rtc_inc); + snd_timer_interrupt(private_data, 1); } @@ -126,17 +119,13 @@ static void rtctimer_interrupt(void *private_data) */ static int __init rtctimer_init(void) { - int order, err; + int err; snd_timer_t *timer; - if (rtctimer_freq < 2 || rtctimer_freq > 8192) { - snd_printk(KERN_ERR "rtctimer: invalid frequency %d\n", rtctimer_freq); - return -EINVAL; - } - for (order = 1; rtctimer_freq > order; order <<= 1) - ; - if (rtctimer_freq != order) { - snd_printk(KERN_ERR "rtctimer: invalid frequency %d\n", rtctimer_freq); + if (rtctimer_freq < 2 || rtctimer_freq > 8192 || + (rtctimer_freq & (rtctimer_freq - 1)) != 0) { + snd_printk(KERN_ERR "rtctimer: invalid frequency %d\n", + rtctimer_freq); return -EINVAL; } @@ -145,6 +134,7 @@ static int __init rtctimer_init(void) if (err < 0) return err; + timer->module = THIS_MODULE; strcpy(timer->name, "RTC timer"); timer->hw = rtc_hw; timer->hw.resolution = NANO_SEC / rtctimer_freq; diff --git a/sound/core/seq/seq_instr.c b/sound/core/seq/seq_instr.c index 019d43a462d7ade1e8094189094a9b4c1bb0c8c2..1d525b13ebb673a2a1bbf127dce7e586054a48c8 100644 --- a/sound/core/seq/seq_instr.c +++ b/sound/core/seq/seq_instr.c @@ -109,8 +109,7 @@ void snd_seq_instr_list_free(snd_seq_kinstr_list_t **list_ptr) spin_lock_irqsave(&list->lock, flags); while (instr->use) { spin_unlock_irqrestore(&list->lock, flags); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_interruptible(1); spin_lock_irqsave(&list->lock, flags); } spin_unlock_irqrestore(&list->lock, flags); @@ -199,10 +198,8 @@ int snd_seq_instr_list_free_cond(snd_seq_kinstr_list_t *list, while (flist) { instr = flist; flist = instr->next; - while (instr->use) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - } + while (instr->use) + schedule_timeout_interruptible(1); if (snd_seq_instr_free(instr, atomic)<0) snd_printk(KERN_WARNING "instrument free problem\n"); instr = next; @@ -554,8 +551,7 @@ static int instr_free(snd_seq_kinstr_ops_t *ops, instr->ops->notify(instr->ops->private_data, instr, SNDRV_SEQ_INSTR_NOTIFY_REMOVE); while (instr->use) { spin_unlock_irqrestore(&list->lock, flags); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_interruptible(1); spin_lock_irqsave(&list->lock, flags); } spin_unlock_irqrestore(&list->lock, flags); diff --git a/sound/core/seq/seq_lock.c b/sound/core/seq/seq_lock.c index b09cee058fa7bac3e2ff705a36ef53872d237338..a837a94b2d2a816e7fce833e74115b1f59fcf4da 100644 --- a/sound/core/seq/seq_lock.c +++ b/sound/core/seq/seq_lock.c @@ -39,8 +39,7 @@ void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line) snd_printk(KERN_WARNING "seq_lock: timeout [%d left] in %s:%d\n", atomic_read(lockp), file, line); break; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); max_count--; } } diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index d4d7d326c4b150af1fc4589d1a4794cf9fdf2d20..8416bcffa0914f4b12fc8541d42ee6bcd6838064 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c @@ -423,8 +423,7 @@ int snd_seq_pool_done(pool_t *pool) snd_printk(KERN_WARNING "snd_seq_pool_done timeout: %d cells remain\n", atomic_read(&pool->counter)); break; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); max_count--; } diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index b4674ae3bc30d39d808dbfe006036924a44f4f7b..f89f40f44876169c5f80fd30ba3e6123cd53cb44 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -449,11 +449,9 @@ snd_seq_midisynth_unregister_port(snd_seq_device_t *dev) client->ports_per_device[device] = 0; msynth = client->ports[device]; client->ports[device] = NULL; - snd_runtime_check(msynth != NULL || ports <= 0, goto __skip); for (p = 0; p < ports; p++) snd_seq_midisynth_delete(&msynth[p]); kfree(msynth); - __skip: client->num_ports--; if (client->num_ports <= 0) { snd_seq_delete_kernel_client(client->seq_client); diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index b57a3c07ff6f6c0eb1c161f8d7ed2efed1e363a6..65b64a7c456dbd02636e091ca7f8e2498116fa02 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -34,10 +34,15 @@ extern int seq_default_timer_device; extern int seq_default_timer_subdevice; extern int seq_default_timer_resolution; +/* allowed sequencer timer frequencies, in Hz */ +#define MIN_FREQUENCY 10 +#define MAX_FREQUENCY 6250 +#define DEFAULT_FREQUENCY 1000 + #define SKEW_BASE 0x10000 /* 16bit shift */ static void snd_seq_timer_set_tick_resolution(seq_timer_tick_t *tick, - int tempo, int ppq, int nticks) + int tempo, int ppq) { if (tempo < 1000000) tick->resolution = (tempo * 1000) / ppq; @@ -51,7 +56,6 @@ static void snd_seq_timer_set_tick_resolution(seq_timer_tick_t *tick, } if (tick->resolution <= 0) tick->resolution = 1; - tick->resolution *= nticks; snd_seq_timer_update_tick(tick, 0); } @@ -100,7 +104,7 @@ void snd_seq_timer_defaults(seq_timer_t * tmr) /* setup defaults */ tmr->ppq = 96; /* 96 PPQ */ tmr->tempo = 500000; /* 120 BPM */ - snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq, 1); + snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq); tmr->running = 0; tmr->type = SNDRV_SEQ_TIMER_ALSA; @@ -183,7 +187,7 @@ int snd_seq_timer_set_tempo(seq_timer_t * tmr, int tempo) spin_lock_irqsave(&tmr->lock, flags); if ((unsigned int)tempo != tmr->tempo) { tmr->tempo = tempo; - snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq, 1); + snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq); } spin_unlock_irqrestore(&tmr->lock, flags); return 0; @@ -207,7 +211,7 @@ int snd_seq_timer_set_ppq(seq_timer_t * tmr, int ppq) } tmr->ppq = ppq; - snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq, 1); + snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq); spin_unlock_irqrestore(&tmr->lock, flags); return 0; } @@ -326,17 +330,26 @@ int snd_seq_timer_stop(seq_timer_t * tmr) static int initialize_timer(seq_timer_t *tmr) { snd_timer_t *t; + unsigned long freq; + t = tmr->timeri->timer; snd_assert(t, return -EINVAL); + freq = tmr->preferred_resolution; + if (!freq) + freq = DEFAULT_FREQUENCY; + else if (freq < MIN_FREQUENCY) + freq = MIN_FREQUENCY; + else if (freq > MAX_FREQUENCY) + freq = MAX_FREQUENCY; + tmr->ticks = 1; - if (tmr->preferred_resolution && - ! (t->hw.flags & SNDRV_TIMER_HW_SLAVE)) { + if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE)) { unsigned long r = t->hw.resolution; if (! r && t->hw.c_resolution) r = t->hw.c_resolution(t); if (r) { - tmr->ticks = (unsigned int)(1000000000uL / (r * tmr->preferred_resolution)); + tmr->ticks = (unsigned int)(1000000000uL / (r * freq)); if (! tmr->ticks) tmr->ticks = 1; } diff --git a/sound/core/sound.c b/sound/core/sound.c index b57519a3e3d90058135dc2781cbf72e14a36acd9..1139dd8ca8eb0d38aa3dcd1f22857ad6b888669f 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -130,7 +130,7 @@ static int snd_open(struct inode *inode, struct file *file) struct file_operations *old_fops; int err = 0; - if (dev != SNDRV_MINOR_SEQUENCER && dev != SNDRV_MINOR_TIMER) { + if (dev != SNDRV_MINOR_GLOBAL) { if (snd_cards[card] == NULL) { #ifdef CONFIG_KMOD snd_request_card(card); @@ -287,7 +287,7 @@ static void snd_minor_info_read(snd_info_entry_t *entry, snd_info_buffer_t * buf for (card = 0; card < SNDRV_CARDS; card++) { list_for_each(list, &snd_minors_hash[card]) { mptr = list_entry(list, snd_minor_t, list); - if (SNDRV_MINOR_DEVICE(mptr->number) != SNDRV_MINOR_SEQUENCER) { + if (SNDRV_MINOR_DEVICE(mptr->number) != SNDRV_MINOR_GLOBAL) { if ((device = mptr->device) >= 0) snd_iprintf(buffer, "%3i: [%i-%2i]: %s\n", mptr->number, card, device, mptr->comment); else @@ -350,9 +350,7 @@ static int __init alsa_sound_init(void) devfs_remove("snd"); return -EIO; } - snd_memory_init(); if (snd_info_init() < 0) { - snd_memory_done(); unregister_chrdev(major, "alsa"); devfs_remove("snd"); return -ENOMEM; @@ -381,7 +379,6 @@ static void __exit alsa_sound_exit(void) #endif snd_info_minor_unregister(); snd_info_done(); - snd_memory_done(); if (unregister_chrdev(major, "alsa") != 0) snd_printk(KERN_ERR "unable to unregister major device number %d\n", major); devfs_remove("snd"); @@ -403,14 +400,6 @@ EXPORT_SYMBOL(snd_register_oss_device); EXPORT_SYMBOL(snd_unregister_oss_device); #endif /* memory.c */ -#ifdef CONFIG_SND_DEBUG_MEMORY -EXPORT_SYMBOL(snd_hidden_kmalloc); -EXPORT_SYMBOL(snd_hidden_kcalloc); -EXPORT_SYMBOL(snd_hidden_kfree); -EXPORT_SYMBOL(snd_hidden_vmalloc); -EXPORT_SYMBOL(snd_hidden_vfree); -EXPORT_SYMBOL(snd_hidden_kstrdup); -#endif EXPORT_SYMBOL(copy_to_user_fromio); EXPORT_SYMBOL(copy_from_user_toio); /* init.c */ @@ -487,17 +476,10 @@ EXPORT_SYMBOL(snd_ctl_unregister_ioctl_compat); EXPORT_SYMBOL(snd_ctl_elem_read); EXPORT_SYMBOL(snd_ctl_elem_write); /* misc.c */ -EXPORT_SYMBOL(snd_task_name); +EXPORT_SYMBOL(release_and_free_resource); #ifdef CONFIG_SND_VERBOSE_PRINTK EXPORT_SYMBOL(snd_verbose_printk); #endif #if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK) EXPORT_SYMBOL(snd_verbose_printd); -#endif - /* wrappers */ -#ifdef CONFIG_SND_DEBUG_MEMORY -EXPORT_SYMBOL(snd_wrapper_kmalloc); -EXPORT_SYMBOL(snd_wrapper_kfree); -EXPORT_SYMBOL(snd_wrapper_vmalloc); -EXPORT_SYMBOL(snd_wrapper_vfree); #endif diff --git a/sound/core/timer.c b/sound/core/timer.c index 22b104624084656b25c8062693e8c7c75a352341..1b90a38d10ff4a261bfc06c575e2a3f169f70224 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -55,7 +55,7 @@ MODULE_PARM_DESC(timer_limit, "Maximum global timers in system."); typedef struct { snd_timer_instance_t *timeri; - int tread; /* enhanced read with timestamps and events */ + int tread; /* enhanced read with timestamps and events */ unsigned long ticks; unsigned long overrun; int qhead; @@ -95,7 +95,8 @@ static void snd_timer_reschedule(snd_timer_t * timer, unsigned long ticks_left); * create a timer instance with the given owner string. * when timer is not NULL, increments the module counter */ -static snd_timer_instance_t *snd_timer_instance_new(char *owner, snd_timer_t *timer) +static snd_timer_instance_t *snd_timer_instance_new(char *owner, + snd_timer_t *timer) { snd_timer_instance_t *timeri; timeri = kzalloc(sizeof(*timeri), GFP_KERNEL); @@ -113,7 +114,7 @@ static snd_timer_instance_t *snd_timer_instance_new(char *owner, snd_timer_t *ti INIT_LIST_HEAD(&timeri->slave_active_head); timeri->timer = timer; - if (timer && timer->card && !try_module_get(timer->card->module)) { + if (timer && !try_module_get(timer->module)) { kfree(timeri->owner); kfree(timeri); return NULL; @@ -131,7 +132,7 @@ static snd_timer_t *snd_timer_find(snd_timer_id_t *tid) struct list_head *p; list_for_each(p, &snd_timer_list) { - timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list); + timer = list_entry(p, snd_timer_t, device_list); if (timer->tmr_class != tid->dev_class) continue; @@ -186,13 +187,14 @@ static void snd_timer_check_slave(snd_timer_instance_t *slave) /* FIXME: it's really dumb to look up all entries.. */ list_for_each(p, &snd_timer_list) { - timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list); + timer = list_entry(p, snd_timer_t, device_list); list_for_each(q, &timer->open_list_head) { - master = (snd_timer_instance_t *)list_entry(q, snd_timer_instance_t, open_list); + master = list_entry(q, snd_timer_instance_t, open_list); if (slave->slave_class == master->slave_class && slave->slave_id == master->slave_id) { list_del(&slave->open_list); - list_add_tail(&slave->open_list, &master->slave_list_head); + list_add_tail(&slave->open_list, + &master->slave_list_head); spin_lock_irq(&slave_active_lock); slave->master = master; slave->timer = master->timer; @@ -216,7 +218,7 @@ static void snd_timer_check_master(snd_timer_instance_t *master) /* check all pending slaves */ list_for_each_safe(p, n, &snd_timer_slave_list) { - slave = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, open_list); + slave = list_entry(p, snd_timer_instance_t, open_list); if (slave->slave_class == master->slave_class && slave->slave_id == master->slave_id) { list_del(p); @@ -225,7 +227,8 @@ static void snd_timer_check_master(snd_timer_instance_t *master) slave->master = master; slave->timer = master->timer; if (slave->flags & SNDRV_TIMER_IFLG_RUNNING) - list_add_tail(&slave->active_list, &master->slave_active_head); + list_add_tail(&slave->active_list, + &master->slave_active_head); spin_unlock_irq(&slave_active_lock); } } @@ -241,7 +244,7 @@ int snd_timer_open(snd_timer_instance_t **ti, { snd_timer_t *timer; snd_timer_instance_t *timeri = NULL; - + if (tid->dev_class == SNDRV_TIMER_CLASS_SLAVE) { /* open a slave instance */ if (tid->dev_sclass <= SNDRV_TIMER_SCLASS_NONE || @@ -251,6 +254,10 @@ int snd_timer_open(snd_timer_instance_t **ti, } down(®ister_mutex); timeri = snd_timer_instance_new(owner, NULL); + if (!timeri) { + up(®ister_mutex); + return -ENOMEM; + } timeri->slave_class = tid->dev_sclass; timeri->slave_id = tid->device; timeri->flags |= SNDRV_TIMER_IFLG_SLAVE; @@ -272,33 +279,36 @@ int snd_timer_open(snd_timer_instance_t **ti, timer = snd_timer_find(tid); } #endif - if (timer) { - if (!list_empty(&timer->open_list_head)) { - timeri = (snd_timer_instance_t *)list_entry(timer->open_list_head.next, snd_timer_instance_t, open_list); - if (timeri->flags & SNDRV_TIMER_IFLG_EXCLUSIVE) { - up(®ister_mutex); - return -EBUSY; - } - } - timeri = snd_timer_instance_new(owner, timer); - if (timeri) { - timeri->slave_class = tid->dev_sclass; - timeri->slave_id = slave_id; - if (list_empty(&timer->open_list_head) && timer->hw.open) - timer->hw.open(timer); - list_add_tail(&timeri->open_list, &timer->open_list_head); - snd_timer_check_master(timeri); - } - } else { + if (!timer) { up(®ister_mutex); return -ENODEV; } + if (!list_empty(&timer->open_list_head)) { + timeri = list_entry(timer->open_list_head.next, + snd_timer_instance_t, open_list); + if (timeri->flags & SNDRV_TIMER_IFLG_EXCLUSIVE) { + up(®ister_mutex); + return -EBUSY; + } + } + timeri = snd_timer_instance_new(owner, timer); + if (!timeri) { + up(®ister_mutex); + return -ENOMEM; + } + timeri->slave_class = tid->dev_sclass; + timeri->slave_id = slave_id; + if (list_empty(&timer->open_list_head) && timer->hw.open) + timer->hw.open(timer); + list_add_tail(&timeri->open_list, &timer->open_list_head); + snd_timer_check_master(timeri); up(®ister_mutex); *ti = timeri; return 0; } -static int _snd_timer_stop(snd_timer_instance_t * timeri, int keep_flag, enum sndrv_timer_event event); +static int _snd_timer_stop(snd_timer_instance_t * timeri, + int keep_flag, enum sndrv_timer_event event); /* * close a timer instance @@ -338,11 +348,12 @@ int snd_timer_close(snd_timer_instance_t * timeri) spin_unlock_irq(&timer->lock); down(®ister_mutex); list_del(&timeri->open_list); - if (timer && list_empty(&timer->open_list_head) && timer->hw.close) + if (timer && list_empty(&timer->open_list_head) && + timer->hw.close) timer->hw.close(timer); /* remove slave links */ list_for_each_safe(p, n, &timeri->slave_list_head) { - slave = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, open_list); + slave = list_entry(p, snd_timer_instance_t, open_list); spin_lock_irq(&slave_active_lock); _snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION); list_del(p); @@ -357,8 +368,8 @@ int snd_timer_close(snd_timer_instance_t * timeri) timeri->private_free(timeri); kfree(timeri->owner); kfree(timeri); - if (timer && timer->card) - module_put(timer->card->module); + if (timer) + module_put(timer->module); return 0; } @@ -376,7 +387,8 @@ unsigned long snd_timer_resolution(snd_timer_instance_t * timeri) return 0; } -static void snd_timer_notify1(snd_timer_instance_t *ti, enum sndrv_timer_event event) +static void snd_timer_notify1(snd_timer_instance_t *ti, + enum sndrv_timer_event event) { snd_timer_t *timer; unsigned long flags; @@ -385,9 +397,11 @@ static void snd_timer_notify1(snd_timer_instance_t *ti, enum sndrv_timer_event e struct list_head *n; struct timespec tstamp; - snd_timestamp_now(&tstamp, 1); - snd_assert(event >= SNDRV_TIMER_EVENT_START && event <= SNDRV_TIMER_EVENT_PAUSE, return); - if (event == SNDRV_TIMER_EVENT_START || event == SNDRV_TIMER_EVENT_CONTINUE) + getnstimeofday(&tstamp); + snd_assert(event >= SNDRV_TIMER_EVENT_START && + event <= SNDRV_TIMER_EVENT_PAUSE, return); + if (event == SNDRV_TIMER_EVENT_START || + event == SNDRV_TIMER_EVENT_CONTINUE) resolution = snd_timer_resolution(ti); if (ti->ccallback) ti->ccallback(ti, SNDRV_TIMER_EVENT_START, &tstamp, resolution); @@ -400,14 +414,15 @@ static void snd_timer_notify1(snd_timer_instance_t *ti, enum sndrv_timer_event e return; spin_lock_irqsave(&timer->lock, flags); list_for_each(n, &ti->slave_active_head) { - ts = (snd_timer_instance_t *)list_entry(n, snd_timer_instance_t, active_list); + ts = list_entry(n, snd_timer_instance_t, active_list); if (ts->ccallback) ts->ccallback(ti, event + 100, &tstamp, resolution); } spin_unlock_irqrestore(&timer->lock, flags); } -static int snd_timer_start1(snd_timer_t *timer, snd_timer_instance_t *timeri, unsigned long sticks) +static int snd_timer_start1(snd_timer_t *timer, snd_timer_instance_t *timeri, + unsigned long sticks) { list_del(&timeri->active_list); list_add_tail(&timeri->active_list, &timer->active_list_head); @@ -434,14 +449,15 @@ static int snd_timer_start_slave(snd_timer_instance_t *timeri) spin_lock_irqsave(&slave_active_lock, flags); timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; if (timeri->master) - list_add_tail(&timeri->active_list, &timeri->master->slave_active_head); + list_add_tail(&timeri->active_list, + &timeri->master->slave_active_head); spin_unlock_irqrestore(&slave_active_lock, flags); return 1; /* delayed start */ } /* * start the timer instance - */ + */ int snd_timer_start(snd_timer_instance_t * timeri, unsigned int ticks) { snd_timer_t *timer; @@ -467,7 +483,8 @@ int snd_timer_start(snd_timer_instance_t * timeri, unsigned int ticks) return result; } -static int _snd_timer_stop(snd_timer_instance_t * timeri, int keep_flag, enum sndrv_timer_event event) +static int _snd_timer_stop(snd_timer_instance_t * timeri, + int keep_flag, enum sndrv_timer_event event) { snd_timer_t *timer; unsigned long flags; @@ -501,7 +518,8 @@ static int _snd_timer_stop(snd_timer_instance_t * timeri, int keep_flag, enum sn } } if (!keep_flag) - timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING|SNDRV_TIMER_IFLG_START); + timeri->flags &= + ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START); spin_unlock_irqrestore(&timer->lock, flags); __end: if (event != SNDRV_TIMER_EVENT_RESOLUTION) @@ -578,7 +596,7 @@ static void snd_timer_reschedule(snd_timer_t * timer, unsigned long ticks_left) struct list_head *p; list_for_each(p, &timer->active_list_head) { - ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, active_list); + ti = list_entry(p, snd_timer_instance_t, active_list); if (ti->flags & SNDRV_TIMER_IFLG_START) { ti->flags &= ~SNDRV_TIMER_IFLG_START; ti->flags |= SNDRV_TIMER_IFLG_RUNNING; @@ -615,11 +633,11 @@ static void snd_timer_tasklet(unsigned long arg) /* now process all callbacks */ while (!list_empty(&timer->sack_list_head)) { p = timer->sack_list_head.next; /* get first item */ - ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, ack_list); + ti = list_entry(p, snd_timer_instance_t, ack_list); /* remove from ack_list and make empty */ list_del_init(p); - + ticks = ti->pticks; ti->pticks = 0; resolution = ti->resolution; @@ -644,7 +662,7 @@ void snd_timer_interrupt(snd_timer_t * timer, unsigned long ticks_left) { snd_timer_instance_t *ti, *ts; unsigned long resolution, ticks; - struct list_head *p, *q, *n; + struct list_head *p, *q, *n, *ack_list_head; int use_tasklet = 0; if (timer == NULL) @@ -659,11 +677,12 @@ void snd_timer_interrupt(snd_timer_t * timer, unsigned long ticks_left) resolution = timer->hw.resolution; /* loop for all active instances - * here we cannot use list_for_each because the active_list of a processed - * instance is relinked to done_list_head before callback is called. + * Here we cannot use list_for_each because the active_list of a + * processed instance is relinked to done_list_head before the callback + * is called. */ list_for_each_safe(p, n, &timer->active_list_head) { - ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, active_list); + ti = list_entry(p, snd_timer_instance_t, active_list); if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING)) continue; ti->pticks += ticks_left; @@ -681,26 +700,19 @@ void snd_timer_interrupt(snd_timer_t * timer, unsigned long ticks_left) if (--timer->running) list_del(p); } - if (list_empty(&ti->ack_list)) { - if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || - (ti->flags & SNDRV_TIMER_IFLG_FAST)) { - list_add_tail(&ti->ack_list, &timer->ack_list_head); - } else { - list_add_tail(&ti->ack_list, &timer->sack_list_head); - } - } + if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || + (ti->flags & SNDRV_TIMER_IFLG_FAST)) + ack_list_head = &timer->ack_list_head; + else + ack_list_head = &timer->sack_list_head; + if (list_empty(&ti->ack_list)) + list_add_tail(&ti->ack_list, ack_list_head); list_for_each(q, &ti->slave_active_head) { - ts = (snd_timer_instance_t *)list_entry(q, snd_timer_instance_t, active_list); + ts = list_entry(q, snd_timer_instance_t, active_list); ts->pticks = ti->pticks; ts->resolution = resolution; - if (list_empty(&ts->ack_list)) { - if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || - (ti->flags & SNDRV_TIMER_IFLG_FAST)) { - list_add_tail(&ts->ack_list, &timer->ack_list_head); - } else { - list_add_tail(&ts->ack_list, &timer->sack_list_head); - } - } + if (list_empty(&ts->ack_list)) + list_add_tail(&ts->ack_list, ack_list_head); } } if (timer->flags & SNDRV_TIMER_FLG_RESCHED) @@ -723,11 +735,11 @@ void snd_timer_interrupt(snd_timer_t * timer, unsigned long ticks_left) /* now process all fast callbacks */ while (!list_empty(&timer->ack_list_head)) { p = timer->ack_list_head.next; /* get first item */ - ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, ack_list); - + ti = list_entry(p, snd_timer_instance_t, ack_list); + /* remove from ack_list and make empty */ list_del_init(p); - + ticks = ti->pticks; ti->pticks = 0; @@ -751,7 +763,8 @@ void snd_timer_interrupt(snd_timer_t * timer, unsigned long ticks_left) */ -int snd_timer_new(snd_card_t *card, char *id, snd_timer_id_t *tid, snd_timer_t ** rtimer) +int snd_timer_new(snd_card_t *card, char *id, snd_timer_id_t *tid, + snd_timer_t **rtimer) { snd_timer_t *timer; int err; @@ -779,9 +792,12 @@ int snd_timer_new(snd_card_t *card, char *id, snd_timer_id_t *tid, snd_timer_t * INIT_LIST_HEAD(&timer->ack_list_head); INIT_LIST_HEAD(&timer->sack_list_head); spin_lock_init(&timer->lock); - tasklet_init(&timer->task_queue, snd_timer_tasklet, (unsigned long)timer); + tasklet_init(&timer->task_queue, snd_timer_tasklet, + (unsigned long)timer); if (card != NULL) { - if ((err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops)) < 0) { + timer->module = card->module; + err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops); + if (err < 0) { snd_timer_free(timer); return err; } @@ -811,14 +827,15 @@ static int snd_timer_dev_register(snd_device_t *dev) snd_timer_t *timer1; struct list_head *p; - snd_assert(timer != NULL && timer->hw.start != NULL && timer->hw.stop != NULL, return -ENXIO); + snd_assert(timer != NULL && timer->hw.start != NULL && + timer->hw.stop != NULL, return -ENXIO); if (!(timer->hw.flags & SNDRV_TIMER_HW_SLAVE) && !timer->hw.resolution && timer->hw.c_resolution == NULL) return -EINVAL; down(®ister_mutex); list_for_each(p, &snd_timer_list) { - timer1 = (snd_timer_t *)list_entry(p, snd_timer_t, device_list); + timer1 = list_entry(p, snd_timer_t, device_list); if (timer1->tmr_class > timer->tmr_class) break; if (timer1->tmr_class < timer->tmr_class) @@ -857,7 +874,7 @@ static int snd_timer_unregister(snd_timer_t *timer) snd_printk(KERN_WARNING "timer 0x%lx is busy?\n", (long)timer); list_for_each_safe(p, n, &timer->open_list_head) { list_del_init(p); - ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, open_list); + ti = list_entry(p, snd_timer_instance_t, open_list); ti->timer = NULL; } } @@ -872,15 +889,18 @@ static int snd_timer_dev_unregister(snd_device_t *device) return snd_timer_unregister(timer); } -void snd_timer_notify(snd_timer_t *timer, enum sndrv_timer_event event, struct timespec *tstamp) +void snd_timer_notify(snd_timer_t *timer, enum sndrv_timer_event event, + struct timespec *tstamp) { unsigned long flags; unsigned long resolution = 0; snd_timer_instance_t *ti, *ts; struct list_head *p, *n; - snd_runtime_check(timer->hw.flags & SNDRV_TIMER_HW_SLAVE, return); - snd_assert(event >= SNDRV_TIMER_EVENT_MSTART && event <= SNDRV_TIMER_EVENT_MRESUME, return); + if (! (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)) + return; + snd_assert(event >= SNDRV_TIMER_EVENT_MSTART && + event <= SNDRV_TIMER_EVENT_MRESUME, return); spin_lock_irqsave(&timer->lock, flags); if (event == SNDRV_TIMER_EVENT_MSTART || event == SNDRV_TIMER_EVENT_MCONTINUE || @@ -891,11 +911,11 @@ void snd_timer_notify(snd_timer_t *timer, enum sndrv_timer_event event, struct t resolution = timer->hw.resolution; } list_for_each(p, &timer->active_list_head) { - ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, active_list); + ti = list_entry(p, snd_timer_instance_t, active_list); if (ti->ccallback) ti->ccallback(ti, event, tstamp, resolution); list_for_each(n, &ti->slave_active_head) { - ts = (snd_timer_instance_t *)list_entry(n, snd_timer_instance_t, active_list); + ts = list_entry(n, snd_timer_instance_t, active_list); if (ts->ccallback) ts->ccallback(ts, event, tstamp, resolution); } @@ -909,7 +929,7 @@ void snd_timer_notify(snd_timer_t *timer, enum sndrv_timer_event event, struct t int snd_timer_global_new(char *id, int device, snd_timer_t **rtimer) { snd_timer_id_t tid; - + tid.dev_class = SNDRV_TIMER_CLASS_GLOBAL; tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; tid.card = -1; @@ -937,7 +957,7 @@ int snd_timer_global_unregister(snd_timer_t *timer) return snd_timer_unregister(timer); } -/* +/* * System timer */ @@ -1013,7 +1033,8 @@ static int snd_timer_register_system(void) struct snd_timer_system_private *priv; int err; - if ((err = snd_timer_global_new("system", SNDRV_TIMER_GLOBAL_SYSTEM, &timer)) < 0) + err = snd_timer_global_new("system", SNDRV_TIMER_GLOBAL_SYSTEM, &timer); + if (err < 0) return err; strcpy(timer->name, "system timer"); timer->hw = snd_timer_system; @@ -1044,33 +1065,41 @@ static void snd_timer_proc_read(snd_info_entry_t *entry, down(®ister_mutex); list_for_each(p, &snd_timer_list) { - timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list); + timer = list_entry(p, snd_timer_t, device_list); switch (timer->tmr_class) { case SNDRV_TIMER_CLASS_GLOBAL: snd_iprintf(buffer, "G%i: ", timer->tmr_device); break; case SNDRV_TIMER_CLASS_CARD: - snd_iprintf(buffer, "C%i-%i: ", timer->card->number, timer->tmr_device); + snd_iprintf(buffer, "C%i-%i: ", + timer->card->number, timer->tmr_device); break; case SNDRV_TIMER_CLASS_PCM: - snd_iprintf(buffer, "P%i-%i-%i: ", timer->card->number, timer->tmr_device, timer->tmr_subdevice); + snd_iprintf(buffer, "P%i-%i-%i: ", timer->card->number, + timer->tmr_device, timer->tmr_subdevice); break; default: - snd_iprintf(buffer, "?%i-%i-%i-%i: ", timer->tmr_class, timer->card ? timer->card->number : -1, timer->tmr_device, timer->tmr_subdevice); + snd_iprintf(buffer, "?%i-%i-%i-%i: ", timer->tmr_class, + timer->card ? timer->card->number : -1, + timer->tmr_device, timer->tmr_subdevice); } snd_iprintf(buffer, "%s :", timer->name); if (timer->hw.resolution) - snd_iprintf(buffer, " %lu.%03luus (%lu ticks)", timer->hw.resolution / 1000, timer->hw.resolution % 1000, timer->hw.ticks); + snd_iprintf(buffer, " %lu.%03luus (%lu ticks)", + timer->hw.resolution / 1000, + timer->hw.resolution % 1000, + timer->hw.ticks); if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) snd_iprintf(buffer, " SLAVE"); snd_iprintf(buffer, "\n"); spin_lock_irqsave(&timer->lock, flags); list_for_each(q, &timer->open_list_head) { - ti = (snd_timer_instance_t *)list_entry(q, snd_timer_instance_t, open_list); - snd_iprintf(buffer, " Client %s : %s : lost interrupts %li\n", - ti->owner ? ti->owner : "unknown", - ti->flags & (SNDRV_TIMER_IFLG_START|SNDRV_TIMER_IFLG_RUNNING) ? "running" : "stopped", - ti->lost); + ti = list_entry(q, snd_timer_instance_t, open_list); + snd_iprintf(buffer, " Client %s : %s\n", + ti->owner ? ti->owner : "unknown", + ti->flags & (SNDRV_TIMER_IFLG_START | + SNDRV_TIMER_IFLG_RUNNING) + ? "running" : "stopped"); } spin_unlock_irqrestore(&timer->lock, flags); } @@ -1088,7 +1117,7 @@ static void snd_timer_user_interrupt(snd_timer_instance_t *timeri, snd_timer_user_t *tu = timeri->callback_data; snd_timer_read_t *r; int prev; - + spin_lock(&tu->qlock); if (tu->qused > 0) { prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1; @@ -1113,7 +1142,8 @@ static void snd_timer_user_interrupt(snd_timer_instance_t *timeri, wake_up(&tu->qchange_sleep); } -static void snd_timer_user_append_to_tqueue(snd_timer_user_t *tu, snd_timer_tread_t *tread) +static void snd_timer_user_append_to_tqueue(snd_timer_user_t *tu, + snd_timer_tread_t *tread) { if (tu->qused >= tu->queue_size) { tu->overrun++; @@ -1132,7 +1162,8 @@ static void snd_timer_user_ccallback(snd_timer_instance_t *timeri, snd_timer_user_t *tu = timeri->callback_data; snd_timer_tread_t r1; - if (event >= SNDRV_TIMER_EVENT_START && event <= SNDRV_TIMER_EVENT_PAUSE) + if (event >= SNDRV_TIMER_EVENT_START && + event <= SNDRV_TIMER_EVENT_PAUSE) tu->tstamp = *tstamp; if ((tu->filter & (1 << event)) == 0 || !tu->tread) return; @@ -1155,15 +1186,17 @@ static void snd_timer_user_tinterrupt(snd_timer_instance_t *timeri, struct timespec tstamp; int prev, append = 0; - snd_timestamp_zero(&tstamp); + memset(&tstamp, 0, sizeof(tstamp)); spin_lock(&tu->qlock); - if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION)|(1 << SNDRV_TIMER_EVENT_TICK))) == 0) { + if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION) | + (1 << SNDRV_TIMER_EVENT_TICK))) == 0) { spin_unlock(&tu->qlock); return; } if (tu->last_resolution != resolution || ticks > 0) - snd_timestamp_now(&tstamp, 1); - if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && tu->last_resolution != resolution) { + getnstimeofday(&tstamp); + if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && + tu->last_resolution != resolution) { r1.event = SNDRV_TIMER_EVENT_RESOLUTION; r1.tstamp = tstamp; r1.val = resolution; @@ -1201,7 +1234,7 @@ static void snd_timer_user_tinterrupt(snd_timer_instance_t *timeri, static int snd_timer_user_open(struct inode *inode, struct file *file) { snd_timer_user_t *tu; - + tu = kzalloc(sizeof(*tu), GFP_KERNEL); if (tu == NULL) return -ENOMEM; @@ -1210,7 +1243,8 @@ static int snd_timer_user_open(struct inode *inode, struct file *file) init_MUTEX(&tu->tread_sem); tu->ticks = 1; tu->queue_size = 128; - tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL); + tu->queue = kmalloc(tu->queue_size * sizeof(snd_timer_read_t), + GFP_KERNEL); if (tu->queue == NULL) { kfree(tu); return -ENOMEM; @@ -1259,7 +1293,7 @@ static int snd_timer_user_next_device(snd_timer_id_t __user *_tid) snd_timer_id_t id; snd_timer_t *timer; struct list_head *p; - + if (copy_from_user(&id, _tid, sizeof(id))) return -EFAULT; down(®ister_mutex); @@ -1267,7 +1301,8 @@ static int snd_timer_user_next_device(snd_timer_id_t __user *_tid) if (list_empty(&snd_timer_list)) snd_timer_user_zero_id(&id); else { - timer = (snd_timer_t *)list_entry(snd_timer_list.next, snd_timer_t, device_list); + timer = list_entry(snd_timer_list.next, + snd_timer_t, device_list); snd_timer_user_copy_id(&id, timer); } } else { @@ -1275,7 +1310,7 @@ static int snd_timer_user_next_device(snd_timer_id_t __user *_tid) case SNDRV_TIMER_CLASS_GLOBAL: id.device = id.device < 0 ? 0 : id.device + 1; list_for_each(p, &snd_timer_list) { - timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list); + timer = list_entry(p, snd_timer_t, device_list); if (timer->tmr_class > SNDRV_TIMER_CLASS_GLOBAL) { snd_timer_user_copy_id(&id, timer); break; @@ -1299,12 +1334,16 @@ static int snd_timer_user_next_device(snd_timer_id_t __user *_tid) if (id.device < 0) { id.device = 0; } else { - id.subdevice = id.subdevice < 0 ? 0 : id.subdevice + 1; + if (id.subdevice < 0) { + id.subdevice = 0; + } else { + id.subdevice++; + } } } } list_for_each(p, &snd_timer_list) { - timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list); + timer = list_entry(p, snd_timer_t, device_list); if (timer->tmr_class > id.dev_class) { snd_timer_user_copy_id(&id, timer); break; @@ -1343,9 +1382,10 @@ static int snd_timer_user_next_device(snd_timer_id_t __user *_tid) if (copy_to_user(_tid, &id, sizeof(*_tid))) return -EFAULT; return 0; -} +} -static int snd_timer_user_ginfo(struct file *file, snd_timer_ginfo_t __user *_ginfo) +static int snd_timer_user_ginfo(struct file *file, + snd_timer_ginfo_t __user *_ginfo) { snd_timer_ginfo_t *ginfo; snd_timer_id_t tid; @@ -1389,7 +1429,8 @@ static int snd_timer_user_ginfo(struct file *file, snd_timer_ginfo_t __user *_gi return err; } -static int snd_timer_user_gparams(struct file *file, snd_timer_gparams_t __user *_gparams) +static int snd_timer_user_gparams(struct file *file, + snd_timer_gparams_t __user *_gparams) { snd_timer_gparams_t gparams; snd_timer_t *t; @@ -1399,23 +1440,26 @@ static int snd_timer_user_gparams(struct file *file, snd_timer_gparams_t __user return -EFAULT; down(®ister_mutex); t = snd_timer_find(&gparams.tid); - if (t != NULL) { - if (list_empty(&t->open_list_head)) { - if (t->hw.set_period) - err = t->hw.set_period(t, gparams.period_num, gparams.period_den); - else - err = -ENOSYS; - } else { - err = -EBUSY; - } - } else { + if (!t) { err = -ENODEV; + goto _error; + } + if (!list_empty(&t->open_list_head)) { + err = -EBUSY; + goto _error; } + if (!t->hw.set_period) { + err = -ENOSYS; + goto _error; + } + err = t->hw.set_period(t, gparams.period_num, gparams.period_den); +_error: up(®ister_mutex); return err; } -static int snd_timer_user_gstatus(struct file *file, snd_timer_gstatus_t __user *_gstatus) +static int snd_timer_user_gstatus(struct file *file, + snd_timer_gstatus_t __user *_gstatus) { snd_timer_gstatus_t gstatus; snd_timer_id_t tid; @@ -1435,7 +1479,8 @@ static int snd_timer_user_gstatus(struct file *file, snd_timer_gstatus_t __user else gstatus.resolution = t->hw.resolution; if (t->hw.precise_resolution) { - t->hw.precise_resolution(t, &gstatus.resolution_num, &gstatus.resolution_den); + t->hw.precise_resolution(t, &gstatus.resolution_num, + &gstatus.resolution_den); } else { gstatus.resolution_num = gstatus.resolution; gstatus.resolution_den = 1000000000uL; @@ -1449,13 +1494,14 @@ static int snd_timer_user_gstatus(struct file *file, snd_timer_gstatus_t __user return err; } -static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user *_tselect) +static int snd_timer_user_tselect(struct file *file, + snd_timer_select_t __user *_tselect) { snd_timer_user_t *tu; snd_timer_select_t tselect; char str[32]; int err = 0; - + tu = file->private_data; down(&tu->tread_sem); if (tu->timeri) { @@ -1469,7 +1515,8 @@ static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user * sprintf(str, "application %i", current->pid); if (tselect.id.dev_class != SNDRV_TIMER_CLASS_SLAVE) tselect.id.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION; - if ((err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid)) < 0) + err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid); + if (err < 0) goto __err; kfree(tu->queue); @@ -1477,21 +1524,24 @@ static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user * kfree(tu->tqueue); tu->tqueue = NULL; if (tu->tread) { - tu->tqueue = (snd_timer_tread_t *)kmalloc(tu->queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL); + tu->tqueue = kmalloc(tu->queue_size * sizeof(snd_timer_tread_t), + GFP_KERNEL); if (tu->tqueue == NULL) err = -ENOMEM; } else { - tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL); + tu->queue = kmalloc(tu->queue_size * sizeof(snd_timer_read_t), + GFP_KERNEL); if (tu->queue == NULL) err = -ENOMEM; } - + if (err < 0) { snd_timer_close(tu->timeri); tu->timeri = NULL; } else { tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; - tu->timeri->callback = tu->tread ? snd_timer_user_tinterrupt : snd_timer_user_interrupt; + tu->timeri->callback = tu->tread + ? snd_timer_user_tinterrupt : snd_timer_user_interrupt; tu->timeri->ccallback = snd_timer_user_ccallback; tu->timeri->callback_data = (void *)tu; } @@ -1501,7 +1551,8 @@ static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user * return err; } -static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info) +static int snd_timer_user_info(struct file *file, + snd_timer_info_t __user *_info) { snd_timer_user_t *tu; snd_timer_info_t *info; @@ -1528,7 +1579,8 @@ static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info return err; } -static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_params) +static int snd_timer_user_params(struct file *file, + snd_timer_params_t __user *_params) { snd_timer_user_t *tu; snd_timer_params_t params; @@ -1536,7 +1588,7 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_ snd_timer_read_t *tr; snd_timer_tread_t *ttr; int err; - + tu = file->private_data; snd_assert(tu->timeri != NULL, return -ENXIO); t = tu->timeri->timer; @@ -1547,7 +1599,8 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_ err = -EINVAL; goto _end; } - if (params.queue_size > 0 && (params.queue_size < 32 || params.queue_size > 1024)) { + if (params.queue_size > 0 && + (params.queue_size < 32 || params.queue_size > 1024)) { err = -EINVAL; goto _end; } @@ -1580,16 +1633,19 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_ if (params.flags & SNDRV_TIMER_PSFLG_EARLY_EVENT) tu->timeri->flags |= SNDRV_TIMER_IFLG_EARLY_EVENT; spin_unlock_irq(&t->lock); - if (params.queue_size > 0 && (unsigned int)tu->queue_size != params.queue_size) { + if (params.queue_size > 0 && + (unsigned int)tu->queue_size != params.queue_size) { if (tu->tread) { - ttr = (snd_timer_tread_t *)kmalloc(params.queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL); + ttr = kmalloc(params.queue_size * sizeof(*ttr), + GFP_KERNEL); if (ttr) { kfree(tu->tqueue); tu->queue_size = params.queue_size; tu->tqueue = ttr; } } else { - tr = (snd_timer_read_t *)kmalloc(params.queue_size * sizeof(snd_timer_read_t), GFP_KERNEL); + tr = kmalloc(params.queue_size * sizeof(*tr), + GFP_KERNEL); if (tr) { kfree(tu->queue); tu->queue_size = params.queue_size; @@ -1613,7 +1669,6 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_ tu->qused++; tu->qtail++; } - } tu->filter = params.filter; tu->ticks = params.ticks; @@ -1624,11 +1679,12 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_ return err; } -static int snd_timer_user_status(struct file *file, snd_timer_status_t __user *_status) +static int snd_timer_user_status(struct file *file, + snd_timer_status_t __user *_status) { snd_timer_user_t *tu; snd_timer_status_t status; - + tu = file->private_data; snd_assert(tu->timeri != NULL, return -ENXIO); memset(&status, 0, sizeof(status)); @@ -1648,7 +1704,7 @@ static int snd_timer_user_start(struct file *file) { int err; snd_timer_user_t *tu; - + tu = file->private_data; snd_assert(tu->timeri != NULL, return -ENXIO); snd_timer_stop(tu->timeri); @@ -1661,7 +1717,7 @@ static int snd_timer_user_stop(struct file *file) { int err; snd_timer_user_t *tu; - + tu = file->private_data; snd_assert(tu->timeri != NULL, return -ENXIO); return (err = snd_timer_stop(tu->timeri)) < 0 ? err : 0; @@ -1671,7 +1727,7 @@ static int snd_timer_user_continue(struct file *file) { int err; snd_timer_user_t *tu; - + tu = file->private_data; snd_assert(tu->timeri != NULL, return -ENXIO); tu->timeri->lost = 0; @@ -1682,7 +1738,7 @@ static int snd_timer_user_pause(struct file *file) { int err; snd_timer_user_t *tu; - + tu = file->private_data; snd_assert(tu->timeri != NULL, return -ENXIO); return (err = snd_timer_pause(tu->timeri)) < 0 ? err : 0; @@ -1695,12 +1751,13 @@ enum { SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23), }; -static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { snd_timer_user_t *tu; void __user *argp = (void __user *)arg; int __user *p = argp; - + tu = file->private_data; switch (cmd) { case SNDRV_TIMER_IOCTL_PVERSION: @@ -1710,7 +1767,7 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned l case SNDRV_TIMER_IOCTL_TREAD: { int xarg; - + down(&tu->tread_sem); if (tu->timeri) { /* too late */ up(&tu->tread_sem); @@ -1758,7 +1815,7 @@ static int snd_timer_user_fasync(int fd, struct file * file, int on) { snd_timer_user_t *tu; int err; - + tu = file->private_data; err = fasync_helper(fd, file, on, &tu->fasync); if (err < 0) @@ -1766,12 +1823,13 @@ static int snd_timer_user_fasync(int fd, struct file * file, int on) return 0; } -static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, size_t count, loff_t *offset) +static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, + size_t count, loff_t *offset) { snd_timer_user_t *tu; long result = 0, unit; int err = 0; - + tu = file->private_data; unit = tu->tread ? sizeof(snd_timer_tread_t) : sizeof(snd_timer_read_t); spin_lock_irq(&tu->qlock); @@ -1805,12 +1863,14 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, size_ goto _error; if (tu->tread) { - if (copy_to_user(buffer, &tu->tqueue[tu->qhead++], sizeof(snd_timer_tread_t))) { + if (copy_to_user(buffer, &tu->tqueue[tu->qhead++], + sizeof(snd_timer_tread_t))) { err = -EFAULT; goto _error; } } else { - if (copy_to_user(buffer, &tu->queue[tu->qhead++], sizeof(snd_timer_read_t))) { + if (copy_to_user(buffer, &tu->queue[tu->qhead++], + sizeof(snd_timer_read_t))) { err = -EFAULT; goto _error; } @@ -1837,7 +1897,7 @@ static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait) tu = file->private_data; poll_wait(file, &tu->qchange_sleep, wait); - + mask = 0; if (tu->qused) mask |= POLLIN | POLLRDNORM; @@ -1881,9 +1941,11 @@ static int __init alsa_timer_init(void) snd_info_entry_t *entry; #ifdef SNDRV_OSS_INFO_DEV_TIMERS - snd_oss_info_register(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1, "system timer"); + snd_oss_info_register(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1, + "system timer"); #endif - if ((entry = snd_info_create_module_entry(THIS_MODULE, "timers", NULL)) != NULL) { + entry = snd_info_create_module_entry(THIS_MODULE, "timers", NULL); + if (entry != NULL) { entry->c.text.read_size = SNDRV_TIMER_DEVICES * 128; entry->c.text.read = snd_timer_proc_read; if (snd_info_register(entry) < 0) { @@ -1893,10 +1955,12 @@ static int __init alsa_timer_init(void) } snd_timer_proc_entry = entry; if ((err = snd_timer_register_system()) < 0) - snd_printk(KERN_ERR "unable to register system timer (%i)\n", err); + snd_printk(KERN_ERR "unable to register system timer (%i)\n", + err); if ((err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0, &snd_timer_reg, "timer"))<0) - snd_printk(KERN_ERR "unable to register timer device (%i)\n", err); + snd_printk(KERN_ERR "unable to register timer device (%i)\n", + err); return 0; } @@ -1907,7 +1971,7 @@ static void __exit alsa_timer_exit(void) snd_unregister_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0); /* unregister the system timer */ list_for_each_safe(p, n, &snd_timer_list) { - snd_timer_t *timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list); + snd_timer_t *timer = list_entry(p, snd_timer_t, device_list); snd_timer_unregister(timer); } if (snd_timer_proc_entry) { diff --git a/sound/core/wrappers.c b/sound/core/wrappers.c deleted file mode 100644 index 296b716f1376a8f7e6ae796c2ef880d9fe3a162d..0000000000000000000000000000000000000000 --- a/sound/core/wrappers.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Various wrappers - * Copyright (c) by Jaroslav Kysela - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_SND_DEBUG_MEMORY -void *snd_wrapper_kmalloc(size_t size, gfp_t flags) -{ - return kmalloc(size, flags); -} - -void snd_wrapper_kfree(const void *obj) -{ - kfree(obj); -} - -void *snd_wrapper_vmalloc(unsigned long size) -{ - return vmalloc(size); -} - -void snd_wrapper_vfree(void *obj) -{ - vfree(obj); -} -#endif - diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c index fe3f921ffbe3707137defded6690020771e641af..bdeb2c00dac5e26df9f91202cba98a0b0826e906 100644 --- a/sound/drivers/mpu401/mpu401_uart.c +++ b/sound/drivers/mpu401/mpu401_uart.c @@ -423,10 +423,7 @@ static void snd_mpu401_uart_free(snd_rawmidi_t *rmidi) mpu401_t *mpu = rmidi->private_data; if (mpu->irq_flags && mpu->irq >= 0) free_irq(mpu->irq, (void *) mpu); - if (mpu->res) { - release_resource(mpu->res); - kfree_nocheck(mpu->res); - } + release_and_free_resource(mpu->res); kfree(mpu); } diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c index 3a25c89d2983936552b081911866a1106f72dfb7..e9d52c668edcbac31f8a6206370fbdd2377dc9d9 100644 --- a/sound/drivers/mtpav.c +++ b/sound/drivers/mtpav.c @@ -717,10 +717,7 @@ static void free_mtpav(mtpav_t * crd) spin_unlock_irqrestore(&crd->spinlock, flags); if (crd->irq >= 0) free_irq(crd->irq, (void *)crd); - if (crd->res_port) { - release_resource(crd->res_port); - kfree_nocheck(crd->res_port); - } + release_and_free_resource(crd->res_port); kfree(crd); } diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c index 1f84d78260dea71d15e27d5859d7b673e1d4e621..06246503083c01b201831ac3d2f3bb53215725ab 100644 --- a/sound/drivers/opl3/opl3_lib.c +++ b/sound/drivers/opl3/opl3_lib.c @@ -325,14 +325,8 @@ static int snd_opl3_free(opl3_t *opl3) snd_assert(opl3 != NULL, return -ENXIO); if (opl3->private_free) opl3->private_free(opl3); - if (opl3->res_l_port) { - release_resource(opl3->res_l_port); - kfree_nocheck(opl3->res_l_port); - } - if (opl3->res_r_port) { - release_resource(opl3->res_r_port); - kfree_nocheck(opl3->res_r_port); - } + release_and_free_resource(opl3->res_l_port); + release_and_free_resource(opl3->res_r_port); kfree(opl3); return 0; } diff --git a/sound/drivers/opl4/opl4_lib.c b/sound/drivers/opl4/opl4_lib.c index 380c2c704c54342ea175115b8b6e219f4633c527..4ae5dd8f011e1acbec9bd410ddc37c11979bfa38 100644 --- a/sound/drivers/opl4/opl4_lib.c +++ b/sound/drivers/opl4/opl4_lib.c @@ -169,14 +169,8 @@ static void snd_opl4_free(opl4_t *opl4) #ifdef CONFIG_PROC_FS snd_opl4_free_proc(opl4); #endif - if (opl4->res_fm_port) { - release_resource(opl4->res_fm_port); - kfree_nocheck(opl4->res_fm_port); - } - if (opl4->res_pcm_port) { - release_resource(opl4->res_pcm_port); - kfree_nocheck(opl4->res_pcm_port); - } + release_and_free_resource(opl4->res_fm_port); + release_and_free_resource(opl4->res_pcm_port); kfree(opl4); } diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c index 416172ea1f4753c6acc72b56b4bf3cdd67a36499..1ed58df42671c61d61a45281eb753ba3c3fdacea 100644 --- a/sound/drivers/serial-u16550.c +++ b/sound/drivers/serial-u16550.c @@ -749,10 +749,7 @@ static int snd_uart16550_free(snd_uart16550_t *uart) { if (uart->irq >= 0) free_irq(uart->irq, (void *)uart); - if (uart->res_base) { - release_resource(uart->res_base); - kfree_nocheck(uart->res_base); - } + release_and_free_resource(uart->res_base); kfree(uart); return 0; }; diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index c2312d912fc7d8f1177dac0ad14a572a98385f61..2b46758fe86f4e0fef6d8e19884ded75967bf28d 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -79,7 +79,7 @@ static int snd_pcm_alloc_vmalloc_buffer(snd_pcm_substream_t *subs, size_t size) /* already allocated */ if (runtime->dma_bytes >= size) return 0; /* already enough large */ - vfree_nocheck(runtime->dma_area); /* bypass the memory wrapper */ + vfree(runtime->dma_area); } runtime->dma_area = vmalloc_32(size); if (! runtime->dma_area) @@ -98,7 +98,7 @@ static int snd_pcm_free_vmalloc_buffer(snd_pcm_substream_t *subs) { snd_pcm_runtime_t *runtime = subs->runtime; if (runtime->dma_area) { - vfree_nocheck(runtime->dma_area); /* bypass the memory wrapper */ + vfree(runtime->dma_area); runtime->dma_area = NULL; } return 0; diff --git a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c index a21f7d541f866ff31caea45b529a0a9262961727..1a05cfbdc7c6ec96fb876f8e5e92d5032828f141 100644 --- a/sound/i2c/cs8427.c +++ b/sound/i2c/cs8427.c @@ -75,7 +75,7 @@ int snd_cs8427_reg_write(snd_i2c_device_t *device, unsigned char reg, unsigned c buf[0] = reg & 0x7f; buf[1] = val; if ((err = snd_i2c_sendbytes(device, buf, 2)) != 2) { - snd_printk("unable to send bytes 0x%02x:0x%02x to CS8427 (%i)\n", buf[0], buf[1], err); + snd_printk(KERN_ERR "unable to send bytes 0x%02x:0x%02x to CS8427 (%i)\n", buf[0], buf[1], err); return err < 0 ? err : -EIO; } return 0; @@ -87,11 +87,11 @@ static int snd_cs8427_reg_read(snd_i2c_device_t *device, unsigned char reg) unsigned char buf; if ((err = snd_i2c_sendbytes(device, ®, 1)) != 1) { - snd_printk("unable to send register 0x%x byte to CS8427\n", reg); + snd_printk(KERN_ERR "unable to send register 0x%x byte to CS8427\n", reg); return err < 0 ? err : -EIO; } if ((err = snd_i2c_readbytes(device, &buf, 1)) != 1) { - snd_printk("unable to read register 0x%x byte from CS8427\n", reg); + snd_printk(KERN_ERR "unable to read register 0x%x byte from CS8427\n", reg); return err < 0 ? err : -EIO; } return buf; @@ -210,7 +210,7 @@ int snd_cs8427_create(snd_i2c_bus_t *bus, snd_i2c_lock(bus); if ((err = snd_cs8427_reg_read(device, CS8427_REG_ID_AND_VER)) != CS8427_VER8427A) { snd_i2c_unlock(bus); - snd_printk("unable to find CS8427 signature (expected 0x%x, read 0x%x), initialization is not completed\n", CS8427_VER8427A, err); + snd_printk(KERN_ERR "unable to find CS8427 signature (expected 0x%x, read 0x%x), initialization is not completed\n", CS8427_VER8427A, err); return -EFAULT; } /* turn off run bit while making changes to configuration */ @@ -260,7 +260,7 @@ int snd_cs8427_create(snd_i2c_bus_t *bus, snd_i2c_sendbytes(device, buf, 1); snd_i2c_readbytes(device, buf, 127); for (xx = 0; xx < 127; xx++) - printk("reg[0x%x] = 0x%x\n", xx+1, buf[xx]); + printk(KERN_DEBUG "reg[0x%x] = 0x%x\n", xx+1, buf[xx]); } #endif @@ -302,8 +302,7 @@ static void snd_cs8427_reset(snd_i2c_device_t *cs8427) snd_i2c_unlock(cs8427->bus); if (!(data & CS8427_UNLOCK)) break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } snd_i2c_lock(cs8427->bus); chip->regmap[CS8427_REG_CLOCKSOURCE] &= ~CS8427_RXDMASK; @@ -354,12 +353,12 @@ static int snd_cs8427_qsubcode_get(snd_kcontrol_t *kcontrol, snd_i2c_lock(device->bus); if ((err = snd_i2c_sendbytes(device, ®, 1)) != 1) { - snd_printk("unable to send register 0x%x byte to CS8427\n", reg); + snd_printk(KERN_ERR "unable to send register 0x%x byte to CS8427\n", reg); snd_i2c_unlock(device->bus); return err < 0 ? err : -EIO; } if ((err = snd_i2c_readbytes(device, ucontrol->value.bytes.data, 10)) != 10) { - snd_printk("unable to read Q-subcode bytes from CS8427\n"); + snd_printk(KERN_ERR "unable to read Q-subcode bytes from CS8427\n"); snd_i2c_unlock(device->bus); return err < 0 ? err : -EIO; } diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index af5eadcddd92da2e64051921fbeb00c10f9ea951..d351b3aa1916f3747b617df5270afeb108d1b60c 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c @@ -56,9 +56,9 @@ static void reg_dump(ak4114_t *ak4114) { int i; - printk("AK4114 REG DUMP:\n"); + printk(KERN_DEBUG "AK4114 REG DUMP:\n"); for (i = 0; i < 0x20; i++) - printk("reg[%02x] = %02x (%02x)\n", i, reg_read(ak4114, i), i < sizeof(ak4114->regmap) ? ak4114->regmap[i] : 0); + printk(KERN_DEBUG "reg[%02x] = %02x (%02x)\n", i, reg_read(ak4114, i), i < sizeof(ak4114->regmap) ? ak4114->regmap[i] : 0); } #endif @@ -552,7 +552,7 @@ int snd_ak4114_check_rate_and_errors(ak4114_t *ak4114, unsigned int flags) if (!(flags & AK4114_CHECK_NO_RATE) && runtime && runtime->rate != res) { snd_pcm_stream_lock_irqsave(ak4114->capture_substream, _flags); if (snd_pcm_running(ak4114->capture_substream)) { - // printk("rate changed (%i <- %i)\n", runtime->rate, res); + // printk(KERN_DEBUG "rate changed (%i <- %i)\n", runtime->rate, res); snd_pcm_stop(ak4114->capture_substream, SNDRV_PCM_STATE_DRAINING); res = 1; } diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c index d51b51dd86d6dda11178e571aadb892e327b753b..35b4584483a3f29cb0c7d65f6f5466131f9d25c6 100644 --- a/sound/i2c/other/ak4117.c +++ b/sound/i2c/other/ak4117.c @@ -54,9 +54,9 @@ static void reg_dump(ak4117_t *ak4117) { int i; - printk("AK4117 REG DUMP:\n"); + printk(KERN_DEBUG "AK4117 REG DUMP:\n"); for (i = 0; i < 0x1b; i++) - printk("reg[%02x] = %02x (%02x)\n", i, reg_read(ak4117, i), i < sizeof(ak4117->regmap) ? ak4117->regmap[i] : 0); + printk(KERN_DEBUG "reg[%02x] = %02x (%02x)\n", i, reg_read(ak4117, i), i < sizeof(ak4117->regmap) ? ak4117->regmap[i] : 0); } #endif @@ -477,7 +477,7 @@ int snd_ak4117_check_rate_and_errors(ak4117_t *ak4117, unsigned int flags) goto __rate; rcs0 = reg_read(ak4117, AK4117_REG_RCS0); rcs2 = reg_read(ak4117, AK4117_REG_RCS2); - // printk("AK IRQ: rcs0 = 0x%x, rcs1 = 0x%x, rcs2 = 0x%x\n", rcs0, rcs1, rcs2); + // printk(KERN_DEBUG "AK IRQ: rcs0 = 0x%x, rcs1 = 0x%x, rcs2 = 0x%x\n", rcs0, rcs1, rcs2); spin_lock_irqsave(&ak4117->lock, _flags); if (rcs0 & AK4117_PAR) ak4117->parity_errors++; @@ -530,7 +530,7 @@ int snd_ak4117_check_rate_and_errors(ak4117_t *ak4117, unsigned int flags) if (!(flags & AK4117_CHECK_NO_RATE) && runtime && runtime->rate != res) { snd_pcm_stream_lock_irqsave(ak4117->substream, _flags); if (snd_pcm_running(ak4117->substream)) { - // printk("rate changed (%i <- %i)\n", runtime->rate, res); + // printk(KERN_DEBUG "rate changed (%i <- %i)\n", runtime->rate, res); snd_pcm_stop(ak4117->substream, SNDRV_PCM_STATE_DRAINING); wake_up(&runtime->sleep); res = 1; diff --git a/sound/i2c/tea6330t.c b/sound/i2c/tea6330t.c index fd65da654267bda2e31ea60e6cd86dcd15b5a366..4fdd1fb57dfe1934f92eb2ac685aa7617dc246d9 100644 --- a/sound/i2c/tea6330t.c +++ b/sound/i2c/tea6330t.c @@ -58,7 +58,7 @@ static void snd_tea6330t_set(tea6330t_t *tea, unsigned char addr, unsigned char value) { #if 0 - printk("set - 0x%x/0x%x\n", addr, value); + printk(KERN_DEBUG "set - 0x%x/0x%x\n", addr, value); #endif snd_i2c_write(tea->bus, TEA6330T_ADDR, addr, value, 1); } diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index 27a9dcfbba008cbff69860fe279b80682b12edbe..7ae02396cae2bbec83a0558479f91b7cfb2a83cf 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c @@ -542,10 +542,7 @@ static int snd_ad1816a_probe(ad1816a_t *chip) static int snd_ad1816a_free(ad1816a_t *chip) { - if (chip->res_port) { - release_resource(chip->res_port); - kfree_nocheck(chip->res_port); - } + release_and_free_resource(chip->res_port); if (chip->irq >= 0) free_irq(chip->irq, (void *) chip); if (chip->dma1 >= 0) { diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c index 303861cd03cdfcc4a1396714cf7e1be60d07e672..891bacc94f68cc0e6da6fe943c9cf779a7f6aed3 100644 --- a/sound/isa/ad1848/ad1848_lib.c +++ b/sound/isa/ad1848/ad1848_lib.c @@ -109,7 +109,7 @@ void snd_ad1848_out(ad1848_t *chip, udelay(100); #ifdef CONFIG_SND_DEBUG if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) - snd_printk("auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); + snd_printk(KERN_WARNING "auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); #endif outb(chip->mce_bit | reg, AD1848P(chip, REGSEL)); outb(chip->image[reg] = value, AD1848P(chip, REG)); @@ -139,7 +139,7 @@ static unsigned char snd_ad1848_in(ad1848_t *chip, unsigned char reg) udelay(100); #ifdef CONFIG_SND_DEBUG if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) - snd_printk("auto calibration time out - reg = 0x%x\n", reg); + snd_printk(KERN_WARNING "auto calibration time out - reg = 0x%x\n", reg); #endif outb(chip->mce_bit | reg, AD1848P(chip, REGSEL)); mb(); @@ -185,13 +185,13 @@ static void snd_ad1848_mce_up(ad1848_t *chip) udelay(100); #ifdef CONFIG_SND_DEBUG if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) - snd_printk("mce_up - auto calibration time out (0)\n"); + snd_printk(KERN_WARNING "mce_up - auto calibration time out (0)\n"); #endif spin_lock_irqsave(&chip->reg_lock, flags); chip->mce_bit |= AD1848_MCE; timeout = inb(AD1848P(chip, REGSEL)); if (timeout == 0x80) - snd_printk("mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port); + snd_printk(KERN_WARNING "mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port); if (!(timeout & AD1848_MCE)) outb(chip->mce_bit | (timeout & 0x1f), AD1848P(chip, REGSEL)); spin_unlock_irqrestore(&chip->reg_lock, flags); @@ -214,13 +214,13 @@ static void snd_ad1848_mce_down(ad1848_t *chip) #endif #ifdef CONFIG_SND_DEBUG if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) - snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", AD1848P(chip, REGSEL)); + snd_printk(KERN_WARNING "mce_down [0x%lx] - auto calibration time out (0)\n", AD1848P(chip, REGSEL)); #endif chip->mce_bit &= ~AD1848_MCE; timeout = inb(AD1848P(chip, REGSEL)); outb(chip->mce_bit | (timeout & 0x1f), AD1848P(chip, REGSEL)); if (timeout == 0x80) - snd_printk("mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port); + snd_printk(KERN_WARNING "mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port); if ((timeout & AD1848_MCE) == 0) { spin_unlock_irqrestore(&chip->reg_lock, flags); return; @@ -240,11 +240,10 @@ static void snd_ad1848_mce_down(ad1848_t *chip) while (snd_ad1848_in(chip, AD1848_TEST_INIT) & AD1848_CALIB_IN_PROGRESS) { spin_unlock_irqrestore(&chip->reg_lock, flags); if (time <= 0) { - snd_printk("mce_down - auto calibration time out (2)\n"); + snd_printk(KERN_ERR "mce_down - auto calibration time out (2)\n"); return; } - set_current_state(TASK_INTERRUPTIBLE); - time = schedule_timeout(time); + time = schedule_timeout_interruptible(time); spin_lock_irqsave(&chip->reg_lock, flags); } #if 0 @@ -254,11 +253,10 @@ static void snd_ad1848_mce_down(ad1848_t *chip) while (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) { spin_unlock_irqrestore(&chip->reg_lock, flags); if (time <= 0) { - snd_printk("mce_down - auto calibration time out (3)\n"); + snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n"); return; } - set_current_state(TASK_INTERRUPTIBLE); - time = schedule_timeout(time); + time = schedule_timeout_interruptible(time); spin_lock_irqsave(&chip->reg_lock, flags); } spin_unlock_irqrestore(&chip->reg_lock, flags); @@ -846,10 +844,7 @@ static int snd_ad1848_capture_close(snd_pcm_substream_t * substream) static int snd_ad1848_free(ad1848_t *chip) { - if (chip->res_port) { - release_resource(chip->res_port); - kfree_nocheck(chip->res_port); - } + release_and_free_resource(chip->res_port); if (chip->irq >= 0) free_irq(chip->irq, (void *) chip); if (chip->dma >= 0) { diff --git a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c index 32318258cd8ed2384b0248cbf06da7a2521faaa6..4af769030beb5751f891ea86110f1f6e29bab1ec 100644 --- a/sound/isa/cs423x/cs4231_lib.c +++ b/sound/isa/cs423x/cs4231_lib.c @@ -1417,14 +1417,8 @@ static int snd_cs4231_pm_resume(snd_card_t *card) static int snd_cs4231_free(cs4231_t *chip) { - if (chip->res_port) { - release_resource(chip->res_port); - kfree_nocheck(chip->res_port); - } - if (chip->res_cport) { - release_resource(chip->res_cport); - kfree_nocheck(chip->res_cport); - } + release_and_free_resource(chip->res_port); + release_and_free_resource(chip->res_cport); if (chip->irq >= 0) { disable_irq(chip->irq); if (!(chip->hwshare & CS4231_HWSHARE_IRQ)) diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index d28315dc72f7d543a01c24622a666bd6ba6cf381..d60a55e6a0b18afdf9b89f42ea98b9bc154e578c 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -379,12 +379,8 @@ static void snd_card_cs4236_free(snd_card_t *card) { struct snd_card_cs4236 *acard = (struct snd_card_cs4236 *)card->private_data; - if (acard) { - if (acard->res_sb_port) { - release_resource(acard->res_sb_port); - kfree_nocheck(acard->res_sb_port); - } - } + if (acard) + release_and_free_resource(acard->res_sb_port); } #ifdef CONFIG_PNP diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c index 2128d4bdef418fc88303f841329855749d32c3c4..1adb88d5f8f456000feb65521c441147a4e28667 100644 --- a/sound/isa/cs423x/cs4236_lib.c +++ b/sound/isa/cs423x/cs4236_lib.c @@ -173,7 +173,10 @@ static unsigned char divisor_to_rate_register(unsigned int divisor) case 2117: return 6; case 2558: return 7; default: - snd_runtime_check(divisor >= 21 && divisor <= 192, return 192); + if (divisor < 21 || divisor > 192) { + snd_BUG(); + return 192; + } return divisor; } } diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c index aac898765c02278e99c7b8ac73efb6afb6de37f6..2edc9c9f0445c65f28c97bd5ec6272a7044373c7 100644 --- a/sound/isa/es1688/es1688_lib.c +++ b/sound/isa/es1688/es1688_lib.c @@ -606,8 +606,7 @@ static int snd_es1688_free(es1688_t *chip) { if (chip->res_port) { snd_es1688_init(chip, 0); - release_resource(chip->res_port); - kfree_nocheck(chip->res_port); + release_and_free_resource(chip->res_port); } if (chip->irq >= 0) free_irq(chip->irq, (void *) chip); diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index d0ea19f427034e886fc289f2457f457e6d8f234e..970e2aaade27dba67a660795849e5eece98769b0 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -173,7 +173,7 @@ static int snd_es18xx_dsp_command(es18xx_t *chip, unsigned char val) outb(val, chip->port + 0x0C); return 0; } - snd_printk("dsp_command: timeout (0x%x)\n", val); + snd_printk(KERN_ERR "dsp_command: timeout (0x%x)\n", val); return -EINVAL; } @@ -184,7 +184,8 @@ static int snd_es18xx_dsp_get_byte(es18xx_t *chip) for(i = MILLISECOND/10; i; i--) if (inb(chip->port + 0x0C) & 0x40) return inb(chip->port + 0x0A); - snd_printk("dsp_get_byte failed: 0x%lx = 0x%x!!!\n", chip->port + 0x0A, inb(chip->port + 0x0A)); + snd_printk(KERN_ERR "dsp_get_byte failed: 0x%lx = 0x%x!!!\n", + chip->port + 0x0A, inb(chip->port + 0x0A)); return -ENODEV; } @@ -204,7 +205,7 @@ static int snd_es18xx_write(es18xx_t *chip, end: spin_unlock_irqrestore(&chip->reg_lock, flags); #ifdef REG_DEBUG - snd_printk("Reg %02x set to %02x\n", reg, data); + snd_printk(KERN_DEBUG "Reg %02x set to %02x\n", reg, data); #endif return ret; } @@ -223,7 +224,7 @@ static int snd_es18xx_read(es18xx_t *chip, unsigned char reg) data = snd_es18xx_dsp_get_byte(chip); ret = data; #ifdef REG_DEBUG - snd_printk("Reg %02x now is %02x (%d)\n", reg, data, ret); + snd_printk(KERN_DEBUG "Reg %02x now is %02x (%d)\n", reg, data, ret); #endif end: spin_unlock_irqrestore(&chip->reg_lock, flags); @@ -259,7 +260,8 @@ static int snd_es18xx_bits(es18xx_t *chip, unsigned char reg, if (ret < 0) goto end; #ifdef REG_DEBUG - snd_printk("Reg %02x was %02x, set to %02x (%d)\n", reg, old, new, ret); + snd_printk(KERN_DEBUG "Reg %02x was %02x, set to %02x (%d)\n", + reg, old, new, ret); #endif } ret = oval; @@ -277,7 +279,7 @@ static inline void snd_es18xx_mixer_write(es18xx_t *chip, outb(data, chip->port + 0x05); spin_unlock_irqrestore(&chip->mixer_lock, flags); #ifdef REG_DEBUG - snd_printk("Mixer reg %02x set to %02x\n", reg, data); + snd_printk(KERN_DEBUG "Mixer reg %02x set to %02x\n", reg, data); #endif } @@ -290,7 +292,7 @@ static inline int snd_es18xx_mixer_read(es18xx_t *chip, unsigned char reg) data = inb(chip->port + 0x05); spin_unlock_irqrestore(&chip->mixer_lock, flags); #ifdef REG_DEBUG - snd_printk("Mixer reg %02x now is %02x\n", reg, data); + snd_printk(KERN_DEBUG "Mixer reg %02x now is %02x\n", reg, data); #endif return data; } @@ -309,7 +311,8 @@ static inline int snd_es18xx_mixer_bits(es18xx_t *chip, unsigned char reg, new = (old & ~mask) | (val & mask); outb(new, chip->port + 0x05); #ifdef REG_DEBUG - snd_printk("Mixer reg %02x was %02x, set to %02x\n", reg, old, new); + snd_printk(KERN_DEBUG "Mixer reg %02x was %02x, set to %02x\n", + reg, old, new); #endif } spin_unlock_irqrestore(&chip->mixer_lock, flags); @@ -329,7 +332,8 @@ static inline int snd_es18xx_mixer_writable(es18xx_t *chip, unsigned char reg, new = inb(chip->port + 0x05); spin_unlock_irqrestore(&chip->mixer_lock, flags); #ifdef REG_DEBUG - snd_printk("Mixer reg %02x was %02x, set to %02x, now is %02x\n", reg, old, expected, new); + snd_printk(KERN_DEBUG "Mixer reg %02x was %02x, set to %02x, now is %02x\n", + reg, old, expected, new); #endif return expected == new; } @@ -1281,7 +1285,7 @@ static void __devinit snd_es18xx_config_write(es18xx_t *chip, outb(reg, chip->ctrl_port); outb(data, chip->ctrl_port + 1); #ifdef REG_DEBUG - snd_printk("Config reg %02x set to %02x\n", reg, data); + snd_printk(KERN_DEBUG "Config reg %02x set to %02x\n", reg, data); #endif } @@ -1346,7 +1350,7 @@ static int __devinit snd_es18xx_initialize(es18xx_t *chip) irqmask = 3; break; default: - snd_printk("invalid irq %d\n", chip->irq); + snd_printk(KERN_ERR "invalid irq %d\n", chip->irq); return -ENODEV; } switch (chip->dma1) { @@ -1360,7 +1364,7 @@ static int __devinit snd_es18xx_initialize(es18xx_t *chip) dma1mask = 3; break; default: - snd_printk("invalid dma1 %d\n", chip->dma1); + snd_printk(KERN_ERR "invalid dma1 %d\n", chip->dma1); return -ENODEV; } switch (chip->dma2) { @@ -1377,7 +1381,7 @@ static int __devinit snd_es18xx_initialize(es18xx_t *chip) dma2mask = 3; break; default: - snd_printk("invalid dma2 %d\n", chip->dma2); + snd_printk(KERN_ERR "invalid dma2 %d\n", chip->dma2); return -ENODEV; } @@ -1440,7 +1444,7 @@ static int __devinit snd_es18xx_identify(es18xx_t *chip) /* reset */ if (snd_es18xx_reset(chip) < 0) { - snd_printk("reset at 0x%lx failed!!!\n", chip->port); + snd_printk(KERN_ERR "reset at 0x%lx failed!!!\n", chip->port); return -ENODEV; } @@ -1527,7 +1531,7 @@ static int __devinit snd_es18xx_probe(es18xx_t *chip) chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME | ES18XX_HWV; break; default: - snd_printk("[0x%lx] unsupported chip ES%x\n", + snd_printk(KERN_ERR "[0x%lx] unsupported chip ES%x\n", chip->port, chip->version); return -ENODEV; } @@ -1640,18 +1644,9 @@ static int snd_es18xx_resume(snd_card_t *card) static int snd_es18xx_free(es18xx_t *chip) { - if (chip->res_port) { - release_resource(chip->res_port); - kfree_nocheck(chip->res_port); - } - if (chip->res_ctrl_port) { - release_resource(chip->res_ctrl_port); - kfree_nocheck(chip->res_ctrl_port); - } - if (chip->res_mpu_port) { - release_resource(chip->res_mpu_port); - kfree_nocheck(chip->res_mpu_port); - } + release_and_free_resource(chip->res_port); + release_and_free_resource(chip->res_ctrl_port); + release_and_free_resource(chip->res_mpu_port); if (chip->irq >= 0) free_irq(chip->irq, (void *) chip); if (chip->dma1 >= 0) { diff --git a/sound/isa/gus/gus_dma.c b/sound/isa/gus/gus_dma.c index de4b56d80b35664617222b04334f9a11b84d49eb..ef1b2e9832e4601e53288d7cdc4c613206ddd7ad 100644 --- a/sound/isa/gus/gus_dma.c +++ b/sound/isa/gus/gus_dma.c @@ -199,7 +199,7 @@ int snd_gf1_dma_transfer_block(snd_gus_card_t * gus, block = kmalloc(sizeof(*block), atomic ? GFP_ATOMIC : GFP_KERNEL); if (block == NULL) { - snd_printk("gf1: DMA transfer failure; not enough memory\n"); + snd_printk(KERN_ERR "gf1: DMA transfer failure; not enough memory\n"); return -ENOMEM; } *block = *__block; diff --git a/sound/isa/gus/gus_io.c b/sound/isa/gus/gus_io.c index 23e1b5f19e1ab78f24ba8ff48614ba15876f0f25..8d5752b23787ddbbf6be31ee6c3487a6f85b597e 100644 --- a/sound/isa/gus/gus_io.c +++ b/sound/isa/gus/gus_io.c @@ -343,7 +343,7 @@ void snd_gf1_pokew(snd_gus_card_t * gus, unsigned int addr, unsigned short data) #ifdef CONFIG_SND_DEBUG if (!gus->interwave) - snd_printk("snd_gf1_pokew - GF1!!!\n"); + snd_printk(KERN_DEBUG "snd_gf1_pokew - GF1!!!\n"); #endif spin_lock_irqsave(&gus->reg_lock, flags); outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel); @@ -367,7 +367,7 @@ unsigned short snd_gf1_peekw(snd_gus_card_t * gus, unsigned int addr) #ifdef CONFIG_SND_DEBUG if (!gus->interwave) - snd_printk("snd_gf1_peekw - GF1!!!\n"); + snd_printk(KERN_DEBUG "snd_gf1_peekw - GF1!!!\n"); #endif spin_lock_irqsave(&gus->reg_lock, flags); outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel); @@ -393,7 +393,7 @@ void snd_gf1_dram_setmem(snd_gus_card_t * gus, unsigned int addr, #ifdef CONFIG_SND_DEBUG if (!gus->interwave) - snd_printk("snd_gf1_dram_setmem - GF1!!!\n"); + snd_printk(KERN_DEBUG "snd_gf1_dram_setmem - GF1!!!\n"); #endif addr &= ~1; count >>= 1; @@ -449,30 +449,30 @@ void snd_gf1_print_voice_registers(snd_gus_card_t * gus) int voice, ctrl; voice = gus->gf1.active_voice; - printk(" -%i- GF1 voice ctrl, ramp ctrl = 0x%x, 0x%x\n", voice, ctrl = snd_gf1_i_read8(gus, 0), snd_gf1_i_read8(gus, 0x0d)); - printk(" -%i- GF1 frequency = 0x%x\n", voice, snd_gf1_i_read16(gus, 1)); - printk(" -%i- GF1 loop start, end = 0x%x (0x%x), 0x%x (0x%x)\n", voice, snd_gf1_i_read_addr(gus, 2, ctrl & 4), snd_gf1_i_read_addr(gus, 2, (ctrl & 4) ^ 4), snd_gf1_i_read_addr(gus, 4, ctrl & 4), snd_gf1_i_read_addr(gus, 4, (ctrl & 4) ^ 4)); - printk(" -%i- GF1 ramp start, end, rate = 0x%x, 0x%x, 0x%x\n", voice, snd_gf1_i_read8(gus, 7), snd_gf1_i_read8(gus, 8), snd_gf1_i_read8(gus, 6)); - printk(" -%i- GF1 volume = 0x%x\n", voice, snd_gf1_i_read16(gus, 9)); - printk(" -%i- GF1 position = 0x%x (0x%x)\n", voice, snd_gf1_i_read_addr(gus, 0x0a, ctrl & 4), snd_gf1_i_read_addr(gus, 0x0a, (ctrl & 4) ^ 4)); + printk(KERN_INFO " -%i- GF1 voice ctrl, ramp ctrl = 0x%x, 0x%x\n", voice, ctrl = snd_gf1_i_read8(gus, 0), snd_gf1_i_read8(gus, 0x0d)); + printk(KERN_INFO " -%i- GF1 frequency = 0x%x\n", voice, snd_gf1_i_read16(gus, 1)); + printk(KERN_INFO " -%i- GF1 loop start, end = 0x%x (0x%x), 0x%x (0x%x)\n", voice, snd_gf1_i_read_addr(gus, 2, ctrl & 4), snd_gf1_i_read_addr(gus, 2, (ctrl & 4) ^ 4), snd_gf1_i_read_addr(gus, 4, ctrl & 4), snd_gf1_i_read_addr(gus, 4, (ctrl & 4) ^ 4)); + printk(KERN_INFO " -%i- GF1 ramp start, end, rate = 0x%x, 0x%x, 0x%x\n", voice, snd_gf1_i_read8(gus, 7), snd_gf1_i_read8(gus, 8), snd_gf1_i_read8(gus, 6)); + printk(KERN_INFO" -%i- GF1 volume = 0x%x\n", voice, snd_gf1_i_read16(gus, 9)); + printk(KERN_INFO " -%i- GF1 position = 0x%x (0x%x)\n", voice, snd_gf1_i_read_addr(gus, 0x0a, ctrl & 4), snd_gf1_i_read_addr(gus, 0x0a, (ctrl & 4) ^ 4)); if (gus->interwave && snd_gf1_i_read8(gus, 0x19) & 0x01) { /* enhanced mode */ mode = snd_gf1_i_read8(gus, 0x15); - printk(" -%i- GFA1 mode = 0x%x\n", voice, mode); + printk(KERN_INFO " -%i- GFA1 mode = 0x%x\n", voice, mode); if (mode & 0x01) { /* Effect processor */ - printk(" -%i- GFA1 effect address = 0x%x\n", voice, snd_gf1_i_read_addr(gus, 0x11, ctrl & 4)); - printk(" -%i- GFA1 effect volume = 0x%x\n", voice, snd_gf1_i_read16(gus, 0x16)); - printk(" -%i- GFA1 effect volume final = 0x%x\n", voice, snd_gf1_i_read16(gus, 0x1d)); - printk(" -%i- GFA1 effect acumulator = 0x%x\n", voice, snd_gf1_i_read8(gus, 0x14)); + printk(KERN_INFO " -%i- GFA1 effect address = 0x%x\n", voice, snd_gf1_i_read_addr(gus, 0x11, ctrl & 4)); + printk(KERN_INFO " -%i- GFA1 effect volume = 0x%x\n", voice, snd_gf1_i_read16(gus, 0x16)); + printk(KERN_INFO " -%i- GFA1 effect volume final = 0x%x\n", voice, snd_gf1_i_read16(gus, 0x1d)); + printk(KERN_INFO " -%i- GFA1 effect acumulator = 0x%x\n", voice, snd_gf1_i_read8(gus, 0x14)); } if (mode & 0x20) { - printk(" -%i- GFA1 left offset = 0x%x (%i)\n", voice, snd_gf1_i_read16(gus, 0x13), snd_gf1_i_read16(gus, 0x13) >> 4); - printk(" -%i- GFA1 left offset final = 0x%x (%i)\n", voice, snd_gf1_i_read16(gus, 0x1c), snd_gf1_i_read16(gus, 0x1c) >> 4); - printk(" -%i- GFA1 right offset = 0x%x (%i)\n", voice, snd_gf1_i_read16(gus, 0x0c), snd_gf1_i_read16(gus, 0x0c) >> 4); - printk(" -%i- GFA1 right offset final = 0x%x (%i)\n", voice, snd_gf1_i_read16(gus, 0x1b), snd_gf1_i_read16(gus, 0x1b) >> 4); + printk(KERN_INFO " -%i- GFA1 left offset = 0x%x (%i)\n", voice, snd_gf1_i_read16(gus, 0x13), snd_gf1_i_read16(gus, 0x13) >> 4); + printk(KERN_INFO " -%i- GFA1 left offset final = 0x%x (%i)\n", voice, snd_gf1_i_read16(gus, 0x1c), snd_gf1_i_read16(gus, 0x1c) >> 4); + printk(KERN_INFO " -%i- GFA1 right offset = 0x%x (%i)\n", voice, snd_gf1_i_read16(gus, 0x0c), snd_gf1_i_read16(gus, 0x0c) >> 4); + printk(KERN_INFO " -%i- GFA1 right offset final = 0x%x (%i)\n", voice, snd_gf1_i_read16(gus, 0x1b), snd_gf1_i_read16(gus, 0x1b) >> 4); } else - printk(" -%i- GF1 pan = 0x%x\n", voice, snd_gf1_i_read8(gus, 0x0c)); + printk(KERN_INFO " -%i- GF1 pan = 0x%x\n", voice, snd_gf1_i_read8(gus, 0x0c)); } else - printk(" -%i- GF1 pan = 0x%x\n", voice, snd_gf1_i_read8(gus, 0x0c)); + printk(KERN_INFO " -%i- GF1 pan = 0x%x\n", voice, snd_gf1_i_read8(gus, 0x0c)); } #if 0 @@ -481,45 +481,45 @@ void snd_gf1_print_global_registers(snd_gus_card_t * gus) { unsigned char global_mode = 0x00; - printk(" -G- GF1 active voices = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_ACTIVE_VOICES)); + printk(KERN_INFO " -G- GF1 active voices = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_ACTIVE_VOICES)); if (gus->interwave) { global_mode = snd_gf1_i_read8(gus, SNDRV_GF1_GB_GLOBAL_MODE); - printk(" -G- GF1 global mode = 0x%x\n", global_mode); + printk(KERN_INFO " -G- GF1 global mode = 0x%x\n", global_mode); } if (global_mode & 0x02) /* LFO enabled? */ - printk(" -G- GF1 LFO base = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_LFO_BASE)); - printk(" -G- GF1 voices IRQ read = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_VOICES_IRQ_READ)); - printk(" -G- GF1 DRAM DMA control = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL)); - printk(" -G- GF1 DRAM DMA high/low = 0x%x/0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_DMA_HIGH), snd_gf1_i_read16(gus, SNDRV_GF1_GW_DRAM_DMA_LOW)); - printk(" -G- GF1 DRAM IO high/low = 0x%x/0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_IO_HIGH), snd_gf1_i_read16(gus, SNDRV_GF1_GW_DRAM_IO_LOW)); + printk(KERN_INFO " -G- GF1 LFO base = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_LFO_BASE)); + printk(KERN_INFO " -G- GF1 voices IRQ read = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_VOICES_IRQ_READ)); + printk(KERN_INFO " -G- GF1 DRAM DMA control = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_DMA_CONTROL)); + printk(KERN_INFO " -G- GF1 DRAM DMA high/low = 0x%x/0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_DMA_HIGH), snd_gf1_i_read16(gus, SNDRV_GF1_GW_DRAM_DMA_LOW)); + printk(KERN_INFO " -G- GF1 DRAM IO high/low = 0x%x/0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_DRAM_IO_HIGH), snd_gf1_i_read16(gus, SNDRV_GF1_GW_DRAM_IO_LOW)); if (!gus->interwave) - printk(" -G- GF1 record DMA control = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL)); - printk(" -G- GF1 DRAM IO 16 = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_DRAM_IO16)); + printk(KERN_INFO " -G- GF1 record DMA control = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_REC_DMA_CONTROL)); + printk(KERN_INFO " -G- GF1 DRAM IO 16 = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_DRAM_IO16)); if (gus->gf1.enh_mode) { - printk(" -G- GFA1 memory config = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG)); - printk(" -G- GFA1 memory control = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_MEMORY_CONTROL)); - printk(" -G- GFA1 FIFO record base = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_FIFO_RECORD_BASE_ADDR)); - printk(" -G- GFA1 FIFO playback base = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_FIFO_PLAY_BASE_ADDR)); - printk(" -G- GFA1 interleave control = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_INTERLEAVE)); + printk(KERN_INFO " -G- GFA1 memory config = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG)); + printk(KERN_INFO " -G- GFA1 memory control = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_MEMORY_CONTROL)); + printk(KERN_INFO " -G- GFA1 FIFO record base = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_FIFO_RECORD_BASE_ADDR)); + printk(KERN_INFO " -G- GFA1 FIFO playback base = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_FIFO_PLAY_BASE_ADDR)); + printk(KERN_INFO " -G- GFA1 interleave control = 0x%x\n", snd_gf1_i_look16(gus, SNDRV_GF1_GW_INTERLEAVE)); } } void snd_gf1_print_setup_registers(snd_gus_card_t * gus) { - printk(" -S- mix control = 0x%x\n", inb(GUSP(gus, MIXCNTRLREG))); - printk(" -S- IRQ status = 0x%x\n", inb(GUSP(gus, IRQSTAT))); - printk(" -S- timer control = 0x%x\n", inb(GUSP(gus, TIMERCNTRL))); - printk(" -S- timer data = 0x%x\n", inb(GUSP(gus, TIMERDATA))); - printk(" -S- status read = 0x%x\n", inb(GUSP(gus, REGCNTRLS))); - printk(" -S- Sound Blaster control = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL)); - printk(" -S- AdLib timer 1/2 = 0x%x/0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_ADLIB_TIMER_1), snd_gf1_i_look8(gus, SNDRV_GF1_GB_ADLIB_TIMER_2)); - printk(" -S- reset = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)); + printk(KERN_INFO " -S- mix control = 0x%x\n", inb(GUSP(gus, MIXCNTRLREG))); + printk(KERN_INFO " -S- IRQ status = 0x%x\n", inb(GUSP(gus, IRQSTAT))); + printk(KERN_INFO " -S- timer control = 0x%x\n", inb(GUSP(gus, TIMERCNTRL))); + printk(KERN_INFO " -S- timer data = 0x%x\n", inb(GUSP(gus, TIMERDATA))); + printk(KERN_INFO " -S- status read = 0x%x\n", inb(GUSP(gus, REGCNTRLS))); + printk(KERN_INFO " -S- Sound Blaster control = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL)); + printk(KERN_INFO " -S- AdLib timer 1/2 = 0x%x/0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_ADLIB_TIMER_1), snd_gf1_i_look8(gus, SNDRV_GF1_GB_ADLIB_TIMER_2)); + printk(KERN_INFO " -S- reset = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)); if (gus->interwave) { - printk(" -S- compatibility = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_COMPATIBILITY)); - printk(" -S- decode control = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_DECODE_CONTROL)); - printk(" -S- version number = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_VERSION_NUMBER)); - printk(" -S- MPU-401 emul. control A/B = 0x%x/0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_MPU401_CONTROL_A), snd_gf1_i_look8(gus, SNDRV_GF1_GB_MPU401_CONTROL_B)); - printk(" -S- emulation IRQ = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_EMULATION_IRQ)); + printk(KERN_INFO " -S- compatibility = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_COMPATIBILITY)); + printk(KERN_INFO " -S- decode control = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_DECODE_CONTROL)); + printk(KERN_INFO " -S- version number = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_VERSION_NUMBER)); + printk(KERN_INFO " -S- MPU-401 emul. control A/B = 0x%x/0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_MPU401_CONTROL_A), snd_gf1_i_look8(gus, SNDRV_GF1_GB_MPU401_CONTROL_B)); + printk(KERN_INFO " -S- emulation IRQ = 0x%x\n", snd_gf1_i_look8(gus, SNDRV_GF1_GB_EMULATION_IRQ)); } } diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c index 8f2872f8e8f6daae4907480b5eeb97f2c07d0a1d..4f57ff4ab35188b2b56fc892f15e51e999374811 100644 --- a/sound/isa/gus/gus_main.c +++ b/sound/isa/gus/gus_main.c @@ -113,14 +113,8 @@ static int snd_gus_free(snd_gus_card_t *gus) snd_gf1_stop(gus); snd_gus_init_dma_irq(gus, 0); __hw_end: - if (gus->gf1.res_port1) { - release_resource(gus->gf1.res_port1); - kfree_nocheck(gus->gf1.res_port1); - } - if (gus->gf1.res_port2) { - release_resource(gus->gf1.res_port2); - kfree_nocheck(gus->gf1.res_port2); - } + release_and_free_resource(gus->gf1.res_port1); + release_and_free_resource(gus->gf1.res_port2); if (gus->gf1.irq >= 0) free_irq(gus->gf1.irq, (void *) gus); if (gus->gf1.dma1 >= 0) { @@ -252,7 +246,7 @@ static int snd_gus_detect_memory(snd_gus_card_t * gus) snd_gf1_poke(gus, 0L, 0xaa); snd_gf1_poke(gus, 1L, 0x55); if (snd_gf1_peek(gus, 0L) != 0xaa || snd_gf1_peek(gus, 1L) != 0x55) { - snd_printk("plain GF1 card at 0x%lx without onboard DRAM?\n", gus->gf1.port); + snd_printk(KERN_ERR "plain GF1 card at 0x%lx without onboard DRAM?\n", gus->gf1.port); return -ENOMEM; } for (idx = 1, d = 0xab; idx < 4; idx++, d++) { @@ -305,20 +299,17 @@ static int snd_gus_init_dma_irq(snd_gus_card_t * gus, int latches) dma2 = gus->gf1.dma2; dma2 = dma2 < 0 ? -dma2 : dma2; dma2 = dmas[dma2 & 7]; -#if 0 - printk("dma1 = %i, dma2 = %i\n", gus->gf1.dma1, gus->gf1.dma2); -#endif dma1 |= gus->equal_dma ? 0x40 : (dma2 << 3); if ((dma1 & 7) == 0 || (dma2 & 7) == 0) { - snd_printk("Error! DMA isn't defined.\n"); + snd_printk(KERN_ERR "Error! DMA isn't defined.\n"); return -EINVAL; } irq = gus->gf1.irq; irq = irq < 0 ? -irq : irq; irq = irqs[irq & 0x0f]; if (irq == 0) { - snd_printk("Error! IRQ isn't defined.\n"); + snd_printk(KERN_ERR "Error! IRQ isn't defined.\n"); return -EINVAL; } irq |= 0x40; @@ -406,8 +397,8 @@ static int snd_gus_check_version(snd_gus_card_t * gus) strcpy(card->longname, "Gravis UltraSound Extreme"); gus->ess_flag = 1; } else { - snd_printk("unknown GF1 revision number at 0x%lx - 0x%x (0x%x)\n", gus->gf1.port, rev, val); - snd_printk(" please - report to \n"); + snd_printk(KERN_ERR "unknown GF1 revision number at 0x%lx - 0x%x (0x%x)\n", gus->gf1.port, rev, val); + snd_printk(KERN_ERR " please - report to \n"); } } } @@ -431,7 +422,7 @@ int snd_gus_initialize(snd_gus_card_t *gus) if (!gus->interwave) { if ((err = snd_gus_check_version(gus)) < 0) { - snd_printk("version check failed\n"); + snd_printk(KERN_ERR "version check failed\n"); return err; } if ((err = snd_gus_detect_memory(gus)) < 0) diff --git a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c index 5eb766dd564bf60918f12aa25b814dfc2ea84154..2e23f2a8c62780a98801bac23fd64b48465a6f70 100644 --- a/sound/isa/gus/gus_mem.c +++ b/sound/isa/gus/gus_mem.c @@ -198,7 +198,7 @@ snd_gf1_mem_block_t *snd_gf1_mem_alloc(snd_gf1_mem_t * alloc, int owner, if (nblock != NULL) { if (size != (int)nblock->size) { /* TODO: remove in the future */ - snd_printk("snd_gf1_mem_alloc - share: sizes differ\n"); + snd_printk(KERN_ERR "snd_gf1_mem_alloc - share: sizes differ\n"); goto __std; } nblock->share++; diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c index beb01365dc466642f15fcbaa4599976cd74290ec..1cc89fb67bf29419fb67cfd088c0b36b22cc70d9 100644 --- a/sound/isa/gus/gus_pcm.c +++ b/sound/isa/gus/gus_pcm.c @@ -333,8 +333,7 @@ static int snd_gf1_pcm_poke_block(snd_gus_card_t *gus, unsigned char *buf, } } if (count > 0 && !in_interrupt()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_interruptible(1); if (signal_pending(current)) return -EAGAIN; } @@ -698,7 +697,7 @@ static int snd_gf1_pcm_playback_close(snd_pcm_substream_t * substream) gus_pcm_private_t *pcmp = runtime->private_data; if (!wait_event_timeout(pcmp->sleep, (atomic_read(&pcmp->dma_count) <= 0), 2*HZ)) - snd_printk("gf1 pcm - serious DMA problem\n"); + snd_printk(KERN_ERR "gf1 pcm - serious DMA problem\n"); snd_gf1_dma_done(gus); return 0; diff --git a/sound/isa/gus/gus_reset.c b/sound/isa/gus/gus_reset.c index ef687abc707093154618df5d4710a6a058c7b328..90710969ef7f60f90dc18bb94733fb0140fe9836 100644 --- a/sound/isa/gus/gus_reset.c +++ b/sound/isa/gus/gus_reset.c @@ -134,7 +134,7 @@ void snd_gf1_smart_stop_voice(snd_gus_card_t * gus, unsigned short voice) spin_lock_irqsave(&gus->reg_lock, flags); snd_gf1_select_voice(gus, voice); #if 0 - printk(" -%i- smart stop voice - volume = 0x%x\n", voice, snd_gf1_i_read16(gus, SNDRV_GF1_VW_VOLUME)); + printk(KERN_DEBUG " -%i- smart stop voice - volume = 0x%x\n", voice, snd_gf1_i_read16(gus, SNDRV_GF1_VW_VOLUME)); #endif snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_ADDRESS_CONTROL); snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); @@ -148,7 +148,7 @@ void snd_gf1_stop_voice(snd_gus_card_t * gus, unsigned short voice) spin_lock_irqsave(&gus->reg_lock, flags); snd_gf1_select_voice(gus, voice); #if 0 - printk(" -%i- stop voice - volume = 0x%x\n", voice, snd_gf1_i_read16(gus, SNDRV_GF1_VW_VOLUME)); + printk(KERN_DEBUG " -%i- stop voice - volume = 0x%x\n", voice, snd_gf1_i_read16(gus, SNDRV_GF1_VW_VOLUME)); #endif snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_ADDRESS_CONTROL); snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); diff --git a/sound/isa/gus/gus_simple.c b/sound/isa/gus/gus_simple.c index c122e7be6cebb0c616b047180289cd8c51799144..dfed85b58b3a2d77abdcb6d111905633e0868f7d 100644 --- a/sound/isa/gus/gus_simple.c +++ b/sound/isa/gus/gus_simple.c @@ -136,7 +136,7 @@ static void do_volume_envelope(snd_gus_card_t *gus, snd_gus_voice_t *voice) snd_gf1_select_voice(gus, voice->number); snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, voice->gf1_volume); - printk("gf1_volume = 0x%x\n", voice->gf1_volume); + /* printk("gf1_volume = 0x%x\n", voice->gf1_volume); */ spin_unlock_irqrestore(&gus->reg_lock, flags); return; } diff --git a/sound/isa/gus/gus_uart.c b/sound/isa/gus/gus_uart.c index 1bc2da8784e001d0bb00036b915c93e3005537a2..fbc95e99105cd32d63ccbb8765a67d579b405c2d 100644 --- a/sound/isa/gus/gus_uart.c +++ b/sound/isa/gus/gus_uart.c @@ -104,7 +104,7 @@ static int snd_gf1_uart_output_open(snd_rawmidi_substream_t * substream) gus->midi_substream_output = substream; spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); #if 0 - snd_printk("write init - cmd = 0x%x, stat = 0x%x\n", gus->gf1.uart_cmd, snd_gf1_uart_stat(gus)); + snd_printk(KERN_DEBUG "write init - cmd = 0x%x, stat = 0x%x\n", gus->gf1.uart_cmd, snd_gf1_uart_stat(gus)); #endif return 0; } @@ -126,7 +126,7 @@ static int snd_gf1_uart_input_open(snd_rawmidi_substream_t * substream) for (i = 0; i < 1000 && (snd_gf1_uart_stat(gus) & 0x01); i++) snd_gf1_uart_get(gus); /* clean Rx */ if (i >= 1000) - snd_printk("gus midi uart init read - cleanup error\n"); + snd_printk(KERN_ERR "gus midi uart init read - cleanup error\n"); } spin_unlock_irqrestore(&gus->uart_cmd_lock, flags); #if 0 diff --git a/sound/isa/gus/gus_volume.c b/sound/isa/gus/gus_volume.c index 3d36f6c8ee6a5fad70579ad8fbb34db15717e01b..b3382fec52987652364a73afef54ab2d38251556 100644 --- a/sound/isa/gus/gus_volume.c +++ b/sound/isa/gus/gus_volume.c @@ -119,7 +119,7 @@ unsigned short snd_gf1_translate_freq(snd_gus_card_t * gus, unsigned int freq16) freq16 = 50; if (freq16 & 0xf8000000) { freq16 = ~0xf8000000; - snd_printk("snd_gf1_translate_freq: overflow - freq = 0x%x\n", freq16); + snd_printk(KERN_ERR "snd_gf1_translate_freq: overflow - freq = 0x%x\n", freq16); } return ((freq16 << 9) + (gus->gf1.playback_freq >> 1)) / gus->gf1.playback_freq; } @@ -203,14 +203,14 @@ unsigned short snd_gf1_compute_freq(unsigned int freq, fc = (freq << 10) / rate; if (fc > 97391L) { fc = 97391; - snd_printk("patch: (1) fc frequency overflow - %u\n", fc); + snd_printk(KERN_ERR "patch: (1) fc frequency overflow - %u\n", fc); } fc = (fc * 44100UL) / mix_rate; while (scale--) fc <<= 1; if (fc > 65535L) { fc = 65535; - snd_printk("patch: (2) fc frequency overflow - %u\n", fc); + snd_printk(KERN_ERR "patch: (2) fc frequency overflow - %u\n", fc); } return (unsigned short) fc; } diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c index 358cba9d738fa1976a1b51488f2f40ceac396b59..f703a9f4257cec43c7326f908b5786daae6e54dc 100644 --- a/sound/isa/gus/interwave.c +++ b/sound/isa/gus/interwave.c @@ -437,7 +437,7 @@ static void __devinit snd_interwave_detect_memory(snd_gus_card_t * gus) for (i = 0; i < 8; ++i) iwave[i] = snd_gf1_peek(gus, bank_pos + i); #ifdef CONFIG_SND_DEBUG_ROM - printk("ROM at 0x%06x = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", bank_pos, + printk(KERN_DEBUG "ROM at 0x%06x = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", bank_pos, iwave[0], iwave[1], iwave[2], iwave[3], iwave[4], iwave[5], iwave[6], iwave[7]); #endif @@ -447,7 +447,7 @@ static void __devinit snd_interwave_detect_memory(snd_gus_card_t * gus) for (i = 0; i < sizeof(struct rom_hdr); i++) csum += snd_gf1_peek(gus, bank_pos + i); #ifdef CONFIG_SND_DEBUG_ROM - printk("ROM checksum = 0x%x (computed)\n", csum); + printk(KERN_DEBUG "ROM checksum = 0x%x (computed)\n", csum); #endif if (csum != 0) continue; /* not valid rom */ @@ -638,10 +638,7 @@ static void snd_interwave_free(snd_card_t *card) if (iwcard == NULL) return; #ifdef SNDRV_STB - if (iwcard->i2c_res) { - release_resource(iwcard->i2c_res); - kfree_nocheck(iwcard->i2c_res); - } + release_and_free_resource(iwcard->i2c_res); #endif if (iwcard->irq >= 0) free_irq(iwcard->irq, (void *)iwcard); diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index 4ba268f251e320a456d64e776b4fcca457a330c8..47cabda792b6ef66fa2d678fec346fc777acd0bd 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c @@ -656,10 +656,7 @@ static int snd_opl3sa2_free(opl3sa2_t *chip) { if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); - if (chip->res_port) { - release_resource(chip->res_port); - kfree_nocheck(chip->res_port); - } + release_and_free_resource(chip->res_port); kfree(chip); return 0; } diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index 73573cb1db6a3555a2b86f20472ea32863eb0330..b94339f8306fd29620005bad3856a6d26c1027aa 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -299,10 +299,8 @@ static char * snd_opti9xx_names[] = { static long snd_legacy_find_free_ioport(long *port_table, long size) { while (*port_table != -1) { - struct resource *res; - if ((res = request_region(*port_table, size, "ALSA test")) != NULL) { - release_resource(res); - kfree_nocheck(res); + if (request_region(*port_table, size, "ALSA test")) { + release_region(*port_table, size); return *port_table; } port_table++; @@ -1227,10 +1225,7 @@ static int snd_opti93x_probe(opti93x_t *chip) static int snd_opti93x_free(opti93x_t *chip) { - if (chip->res_port) { - release_resource(chip->res_port); - kfree_nocheck(chip->res_port); - } + release_and_free_resource(chip->res_port); if (chip->dma1 >= 0) { disable_dma(chip->dma1); free_dma(chip->dma1); @@ -1656,8 +1651,7 @@ static int __devinit snd_card_opti9xx_detect(snd_card_t *card, opti9xx_t *chip) if (value == snd_opti9xx_read(chip, OPTi9XX_MC_REG(1))) return 1; - release_resource(chip->res_mc_base); - kfree_nocheck(chip->res_mc_base); + release_and_free_resource(chip->res_mc_base); chip->res_mc_base = NULL; } @@ -1683,8 +1677,7 @@ static int __devinit snd_card_opti9xx_detect(snd_card_t *card, opti9xx_t *chip) if (snd_opti9xx_read(chip, OPTi9XX_MC_REG(7)) == 0xff - value) return 1; - release_resource(chip->res_mc_base); - kfree_nocheck(chip->res_mc_base); + release_and_free_resource(chip->res_mc_base); chip->res_mc_base = NULL; } #endif /* OPTi93X */ @@ -1886,12 +1879,8 @@ static void snd_card_opti9xx_free(snd_card_t *card) { opti9xx_t *chip = (opti9xx_t *)card->private_data; - if (chip) { - if (chip->res_mc_base) { - release_resource(chip->res_mc_base); - kfree_nocheck(chip->res_mc_base); - } - } + if (chip) + release_and_free_resource(chip->res_mc_base); } static int snd_card_opti9xx_probe(struct pnp_card_link *pcard, diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index 5375705c054bbaceece95c7cd7a9797136a688e6..b09c6575e01ae4dbc2975506d0927e17b3779369 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c @@ -135,8 +135,7 @@ static void __init snd_emu8000_read_wait(emu8000_t *emu) { while ((EMU8000_SMALR_READ(emu) & 0x80000000) != 0) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_interruptible(1); if (signal_pending(current)) break; } @@ -148,8 +147,7 @@ static void __init snd_emu8000_write_wait(emu8000_t *emu) { while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_interruptible(1); if (signal_pending(current)) break; } @@ -437,8 +435,7 @@ size_dram(emu8000_t *emu) for (i = 0; i < 10000; i++) { if ((EMU8000_SMALW_READ(emu) & 0x80000000) == 0) break; - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_interruptible(1); if (signal_pending(current)) break; } @@ -1054,18 +1051,9 @@ snd_emu8000_create_mixer(snd_card_t *card, emu8000_t *emu) */ static int snd_emu8000_free(emu8000_t *hw) { - if (hw->res_port1) { - release_resource(hw->res_port1); - kfree_nocheck(hw->res_port1); - } - if (hw->res_port2) { - release_resource(hw->res_port2); - kfree_nocheck(hw->res_port2); - } - if (hw->res_port3) { - release_resource(hw->res_port3); - kfree_nocheck(hw->res_port3); - } + release_and_free_resource(hw->res_port1); + release_and_free_resource(hw->res_port2); + release_and_free_resource(hw->res_port3); kfree(hw); return 0; } diff --git a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c index 26e693078cb3a1231e56874f5f9bcb7960884984..2fea67e71c78294dc987a87a2e7f2f26f56469d6 100644 --- a/sound/isa/sb/emu8000_patch.c +++ b/sound/isa/sb/emu8000_patch.c @@ -109,8 +109,7 @@ static void snd_emu8000_write_wait(emu8000_t *emu) { while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_interruptible(1); if (signal_pending(current)) break; } diff --git a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c index 0209790dc4b5dafdf4b92fbabec323956652aacf..b323beeeda156b8e9448fedcc161d5348c5b56ac 100644 --- a/sound/isa/sb/emu8000_pcm.c +++ b/sound/isa/sb/emu8000_pcm.c @@ -117,8 +117,7 @@ snd_emu8000_write_wait(emu8000_t *emu, int can_schedule) { while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) { if (can_schedule) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_interruptible(1); if (signal_pending(current)) break; } diff --git a/sound/isa/sb/emu8000_synth.c b/sound/isa/sb/emu8000_synth.c index 1f63aa52d5961035b80b081ab975ba77cd49bd7c..f68e217416a6f8ad8a8228739f5a129e910e86f9 100644 --- a/sound/isa/sb/emu8000_synth.c +++ b/sound/isa/sb/emu8000_synth.c @@ -56,7 +56,7 @@ static int snd_emu8000_new_device(snd_seq_device_t *dev) emu->num_ports = hw->seq_ports; if (hw->memhdr) { - snd_printk("memhdr is already initialized!?\n"); + snd_printk(KERN_ERR "memhdr is already initialized!?\n"); snd_util_memhdr_free(hw->memhdr); } hw->memhdr = snd_util_memhdr_new(hw->mem_size); diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c index 7888783d68f598ed2c1ef179834d22cbf5c17ff3..c2fa451bc8f05c293531e93cc23fdd7598957552 100644 --- a/sound/isa/sb/sb16.c +++ b/sound/isa/sb/sb16.c @@ -345,10 +345,7 @@ static void snd_sb16_free(snd_card_t *card) if (acard == NULL) return; - if (acard->fm_res) { - release_resource(acard->fm_res); - kfree_nocheck(acard->fm_res); - } + release_and_free_resource(acard->fm_res); } #ifdef CONFIG_PNP diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c index a99e642a68b590d9be7a3e53d3dbfaf75a814907..556b95e3e22fb9d60ac0b9483a4f65ada2fa5452 100644 --- a/sound/isa/sb/sb16_main.c +++ b/sound/isa/sb/sb16_main.c @@ -747,7 +747,7 @@ int snd_sb16dsp_configure(sb_t * chip) unsigned char realirq, realdma, realmpureg; /* note: mpu register should be present only on SB16 Vibra soundcards */ - // printk("codec->irq=%i, codec->dma8=%i, codec->dma16=%i\n", chip->irq, chip->dma8, chip->dma16); + // printk(KERN_DEBUG "codec->irq=%i, codec->dma8=%i, codec->dma16=%i\n", chip->irq, chip->dma8, chip->dma16); spin_lock_irqsave(&chip->mixer_lock, flags); mpureg = snd_sbmixer_read(chip, SB_DSP4_MPUSETUP) & ~0x06; spin_unlock_irqrestore(&chip->mixer_lock, flags); @@ -821,9 +821,9 @@ int snd_sb16dsp_configure(sb_t * chip) spin_unlock_irqrestore(&chip->mixer_lock, flags); if ((~realirq) & irqreg || (~realdma) & dmareg) { - snd_printk("SB16 [0x%lx]: unable to set DMA & IRQ (PnP device?)\n", chip->port); - snd_printk("SB16 [0x%lx]: wanted: irqreg=0x%x, dmareg=0x%x, mpureg = 0x%x\n", chip->port, realirq, realdma, realmpureg); - snd_printk("SB16 [0x%lx]: got: irqreg=0x%x, dmareg=0x%x, mpureg = 0x%x\n", chip->port, irqreg, dmareg, mpureg); + snd_printk(KERN_ERR "SB16 [0x%lx]: unable to set DMA & IRQ (PnP device?)\n", chip->port); + snd_printk(KERN_ERR "SB16 [0x%lx]: wanted: irqreg=0x%x, dmareg=0x%x, mpureg = 0x%x\n", chip->port, realirq, realdma, realmpureg); + snd_printk(KERN_ERR "SB16 [0x%lx]: got: irqreg=0x%x, dmareg=0x%x, mpureg = 0x%x\n", chip->port, irqreg, dmareg, mpureg); return -ENODEV; } return 0; diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c index c41ac25e85ca6edcb924bbb8b43f1d4179ccec04..0bc0a3afdabc0cf73b267e4477a0a1dca2bc51a4 100644 --- a/sound/isa/sb/sb8.c +++ b/sound/isa/sb/sb8.c @@ -78,10 +78,7 @@ static void snd_sb8_free(snd_card_t *card) if (acard == NULL) return; - if (acard->fm_res) { - release_resource(acard->fm_res); - kfree_nocheck(acard->fm_res); - } + release_and_free_resource(acard->fm_res); } static int __init snd_sb8_probe(int dev) diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c index 87c9b1ba06cf8f7a5318cf199dba2180513191b5..5ddc6e41d9090a15314bea6f8efa420ca43c0f73 100644 --- a/sound/isa/sb/sb8_main.c +++ b/sound/isa/sb/sb8_main.c @@ -334,9 +334,6 @@ irqreturn_t snd_sb8dsp_interrupt(sb_t *chip) snd_pcm_substream_t *substream; snd_pcm_runtime_t *runtime; -#if 0 - snd_printk("sb8: interrupt\n"); -#endif snd_sb_ack_8bit(chip); switch (chip->mode) { case SB_MODE_PLAYBACK_8: /* ok.. playback is active */ diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c index f0f205ae425fec52b29d0460243983c4f8f7bf40..603e923b5d2f84288ae0cdd0d7a6a8dfe04dba6b 100644 --- a/sound/isa/sb/sb_common.c +++ b/sound/isa/sb/sb_common.c @@ -45,7 +45,7 @@ int snd_sbdsp_command(sb_t *chip, unsigned char val) { int i; #ifdef IO_DEBUG - snd_printk("command 0x%x\n", val); + snd_printk(KERN_DEBUG "command 0x%x\n", val); #endif for (i = BUSY_LOOPS; i; i--) if ((inb(SBP(chip, STATUS)) & 0x80) == 0) { @@ -64,7 +64,7 @@ int snd_sbdsp_get_byte(sb_t *chip) if (inb(SBP(chip, DATA_AVAIL)) & 0x80) { val = inb(SBP(chip, READ)); #ifdef IO_DEBUG - snd_printk("get_byte 0x%x\n", val); + snd_printk(KERN_DEBUG "get_byte 0x%x\n", val); #endif return val; } @@ -154,7 +154,7 @@ static int snd_sbdsp_probe(sb_t * chip) str = "16"; break; default: - snd_printk("SB [0x%lx]: unknown DSP chip version %i.%i\n", + snd_printk(KERN_INFO "SB [0x%lx]: unknown DSP chip version %i.%i\n", chip->port, major, minor); return -ENODEV; } @@ -178,10 +178,8 @@ static int snd_sbdsp_probe(sb_t * chip) static int snd_sbdsp_free(sb_t *chip) { - if (chip->res_port) { - release_resource(chip->res_port); - kfree_nocheck(chip->res_port); - } + if (chip->res_port) + release_and_free_resource(chip->res_port); if (chip->irq >= 0) free_irq(chip->irq, (void *) chip); #ifdef CONFIG_ISA diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c index ff4b5996802749b5bee51e688b5a064834487fb5..5a926a452d387765f4a533a3d18a0101f477cf24 100644 --- a/sound/isa/sb/sb_mixer.c +++ b/sound/isa/sb/sb_mixer.c @@ -36,7 +36,7 @@ void snd_sbmixer_write(sb_t *chip, unsigned char reg, unsigned char data) outb(data, SBP(chip, MIXER_DATA)); udelay(10); #ifdef IO_DEBUG - snd_printk("mixer_write 0x%x 0x%x\n", reg, data); + snd_printk(KERN_DEBUG "mixer_write 0x%x 0x%x\n", reg, data); #endif } @@ -49,7 +49,7 @@ unsigned char snd_sbmixer_read(sb_t *chip, unsigned char reg) result = inb(SBP(chip, MIXER_DATA)); udelay(10); #ifdef IO_DEBUG - snd_printk("mixer_read 0x%x 0x%x\n", reg, result); + snd_printk(KERN_DEBUG "mixer_read 0x%x 0x%x\n", reg, result); #endif return result; } diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index 9f6b58c79209cbc4f217a0b9dd700bf0270e37b0..11588067fa4fe6218ea990a615eb74af7b85f6d1 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -338,24 +338,10 @@ static inline void activate_ad1845_unsafe(unsigned io_base) static void soundscape_free(snd_card_t * c) { register struct soundscape *sscape = get_card_soundscape(c); - release_resource(sscape->io_res); - kfree_nocheck(sscape->io_res); + release_and_free_resource(sscape->io_res); free_dma(sscape->chip->dma1); } -/* - * Put this process into an idle wait-state for a certain number - * of "jiffies". The process can almost certainly be rescheduled - * while we're waiting, and so we must NOT be holding any spinlocks - * when we call this function. If we are then we risk DEADLOCK in - * SMP (Ha!) or pre-emptible kernels. - */ -static inline void sleep(long jiffs, int state) -{ - set_current_state(state); - schedule_timeout(jiffs); -} - /* * Tell the SoundScape to begin a DMA tranfer using the given channel. * All locking issues are left to the caller. @@ -393,7 +379,7 @@ static int obp_startup_ack(struct soundscape *s, unsigned timeout) unsigned long flags; unsigned char x; - sleep(1, TASK_INTERRUPTIBLE); + schedule_timeout_interruptible(1); spin_lock_irqsave(&s->lock, flags); x = inb(HOST_DATA_IO(s->io_base)); @@ -420,7 +406,7 @@ static int host_startup_ack(struct soundscape *s, unsigned timeout) unsigned long flags; unsigned char x; - sleep(1, TASK_INTERRUPTIBLE); + schedule_timeout_interruptible(1); spin_lock_irqsave(&s->lock, flags); x = inb(HOST_DATA_IO(s->io_base)); @@ -1288,8 +1274,7 @@ static int __devinit create_sscape(const struct params *params, snd_card_t **rca free_dma(params->dma1); _release_region: - release_resource(io_res); - kfree_nocheck(io_res); + release_and_free_resource(io_res); return err; } diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c index 0a572e0a47e62d891f5a5e30d704cfb3f952e217..1818f1013c3f7739c3635849fc83042d7c77063d 100644 --- a/sound/isa/wavefront/wavefront.c +++ b/sound/isa/wavefront/wavefront.c @@ -379,10 +379,7 @@ snd_wavefront_free(snd_card_t *card) snd_wavefront_card_t *acard = (snd_wavefront_card_t *)card->private_data; if (acard) { - if (acard->wavefront.res_base != NULL) { - release_resource(acard->wavefront.res_base); - kfree_nocheck(acard->wavefront.res_base); - } + release_and_free_resource(acard->wavefront.res_base); if (acard->wavefront.irq > 0) free_irq(acard->wavefront.irq, (void *)acard); } diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c index 0c3c951009d85682de4a82f74c75b380032c77e6..abd79b781412c9be99d7973b84110f440c134780 100644 --- a/sound/isa/wavefront/wavefront_synth.c +++ b/sound/isa/wavefront/wavefront_synth.c @@ -275,8 +275,7 @@ static int wavefront_sleep (int limit) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(limit); + schedule_timeout_interruptible(limit); return signal_pending(current); } @@ -1788,8 +1787,7 @@ wavefront_should_cause_interrupt (snd_wavefront_t *dev, outb (val,port); spin_unlock_irq(&dev->irq_lock); while (1) { - set_current_state(TASK_INTERRUPTIBLE); - if ((timeout = schedule_timeout(timeout)) == 0) + if ((timeout = schedule_timeout_interruptible(timeout)) == 0) return; if (dev->irq_ok) return; diff --git a/sound/mips/au1x00.c b/sound/mips/au1x00.c index 3f9684f1d1d2a24e1fe7cbcf24f98d3a4ca3a5a7..d08a42b24b1f847a43b54203da326aaa45d7c35e 100644 --- a/sound/mips/au1x00.c +++ b/sound/mips/au1x00.c @@ -57,8 +57,6 @@ MODULE_CLASSES("{sound}"); MODULE_DEVICES("{{AMD,Au1000 AC'97}}"); #endif -#define chip_t au1000_t - #define PLAYBACK 0 #define CAPTURE 1 #define AC97_SLOT_3 0x01 @@ -474,7 +472,7 @@ snd_au1000_ac97_read(ac97_t *ac97, unsigned short reg) u32 volatile cmd; u16 volatile data; int i; - spin_lock(au1000->ac97_lock); + spin_lock(&au1000->ac97_lock); /* would rather use the interupt than this polling but it works and I can't get the interupt driven case to work efficiently */ for (i = 0; i < 0x5000; i++) @@ -497,7 +495,7 @@ get the interupt driven case to work efficiently */ } data = au1000->ac97_ioport->cmd & 0xffff; - spin_unlock(au1000->ac97_lock); + spin_unlock(&au1000->ac97_lock); return data; @@ -509,7 +507,7 @@ snd_au1000_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) { u32 cmd; int i; - spin_lock(au1000->ac97_lock); + spin_lock(&au1000->ac97_lock); /* would rather use the interupt than this polling but it works and I can't get the interupt driven case to work efficiently */ for (i = 0; i < 0x5000; i++) @@ -522,7 +520,7 @@ get the interupt driven case to work efficiently */ cmd &= ~AC97C_READ; cmd |= ((u32) val << AC97C_WD_BIT); au1000->ac97_ioport->cmd = cmd; - spin_unlock(au1000->ac97_lock); + spin_unlock(&au1000->ac97_lock); } static void snd_au1000_ac97_free(ac97_t *ac97) @@ -606,8 +604,7 @@ snd_au1000_free(snd_card_t *card) /* put internal AC97 block into reset */ au1000->ac97_ioport->cntrl = AC97C_RS; au1000->ac97_ioport = NULL; - release_resource(au1000->ac97_res_port); - kfree_nocheck(au1000->ac97_res_port); + release_and_free_resource(au1000->ac97_res_port); } if (au1000->stream[PLAYBACK]->dma >= 0) diff --git a/sound/oss/au1000.c b/sound/oss/au1000.c index 2c2ae2ee01ac3df26a301e7fd0f86e371a3f20c4..c407de86cbb6398d1d06242190e180e52df0528c 100644 --- a/sound/oss/au1000.c +++ b/sound/oss/au1000.c @@ -563,7 +563,7 @@ static void start_adc(struct au1000_state *s) #define DMABUF_DEFAULTORDER (17-PAGE_SHIFT) #define DMABUF_MINORDER 1 -extern inline void dealloc_dmabuf(struct au1000_state *s, struct dmabuf *db) +static inline void dealloc_dmabuf(struct au1000_state *s, struct dmabuf *db) { struct page *page, *pend; @@ -667,14 +667,14 @@ static int prog_dmabuf(struct au1000_state *s, struct dmabuf *db) return 0; } -extern inline int prog_dmabuf_adc(struct au1000_state *s) +static inline int prog_dmabuf_adc(struct au1000_state *s) { stop_adc(s); return prog_dmabuf(s, &s->dma_adc); } -extern inline int prog_dmabuf_dac(struct au1000_state *s) +static inline int prog_dmabuf_dac(struct au1000_state *s) { stop_dac(s); return prog_dmabuf(s, &s->dma_dac); diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c index b2bf8bac842d1a1384d32845536b20160b2a9ce0..cebd881b91ae97ccc552726b8987549538b0c5c8 100644 --- a/sound/oss/dmasound/dmasound_awacs.c +++ b/sound/oss/dmasound/dmasound_awacs.c @@ -2805,16 +2805,7 @@ __init setup_beep(void) return 0 ; } -static struct input_dev awacs_beep_dev = { - .evbit = { BIT(EV_SND) }, - .sndbit = { BIT(SND_BELL) | BIT(SND_TONE) }, - .event = awacs_beep_event, - .name = "dmasound beeper", - .phys = "macio/input0", /* what the heck is this?? */ - .id = { - .bustype = BUS_HOST, - }, -}; +static struct input_dev *awacs_beep_dev; int __init dmasound_awacs_init(void) { @@ -2907,6 +2898,22 @@ printk("dmasound_pmac: couldn't find a Codec we can handle\n"); return -ENODEV; } + awacs_beep_dev = input_allocate_device(); + if (!awacs_beep_dev) { + release_OF_resource(io, 0); + release_OF_resource(io, 1); + release_OF_resource(io, 2); + printk(KERN_ERR "dmasound: can't allocate input device !\n"); + return -ENOMEM; + } + + awacs_beep_dev->name = "dmasound beeper"; + awacs_beep_dev->phys = "macio/input0"; + awacs_beep_dev->id.bustype = BUS_HOST; + awacs_beep_dev->event = awacs_beep_event; + awacs_beep_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); + awacs_beep_dev->evbit[0] = BIT(EV_SND); + /* all OF versions I've seen use this value */ if (i2s_node) i2s = ioremap(io->addrs[0].address, 0x1000); @@ -3140,14 +3147,14 @@ printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev); * XXX: we should handle errors here, but that would mean * rewriting the whole init code. later.. */ - input_register_device(&awacs_beep_dev); + input_register_device(awacs_beep_dev); return dmasound_init(); } static void __exit dmasound_awacs_cleanup(void) { - input_unregister_device(&awacs_beep_dev); + input_unregister_device(awacs_beep_dev); switch (awacs_revision) { case AWACS_TUMBLER: diff --git a/sound/oss/nec_vrc5477.c b/sound/oss/nec_vrc5477.c index 0481e5e54ddf27eb91ffee7d9245ed9bb035631e..9ac4bf7e1e894f62d6048a11f40a8a6a996ef453 100644 --- a/sound/oss/nec_vrc5477.c +++ b/sound/oss/nec_vrc5477.c @@ -435,7 +435,7 @@ static int ac97_codec_not_present(struct ac97_codec *codec) /* --------------------------------------------------------------------- */ -extern inline void +static inline void stop_dac(struct vrc5477_ac97_state *s) { struct dmabuf* db = &s->dma_dac; @@ -553,7 +553,7 @@ static void start_dac(struct vrc5477_ac97_state *s) spin_unlock_irqrestore(&s->lock, flags); } -extern inline void stop_adc(struct vrc5477_ac97_state *s) +static inline void stop_adc(struct vrc5477_ac97_state *s) { struct dmabuf* db = &s->dma_adc; unsigned long flags; @@ -652,7 +652,7 @@ static void start_adc(struct vrc5477_ac97_state *s) #define DMABUF_DEFAULTORDER (16-PAGE_SHIFT) #define DMABUF_MINORDER 1 -extern inline void dealloc_dmabuf(struct vrc5477_ac97_state *s, +static inline void dealloc_dmabuf(struct vrc5477_ac97_state *s, struct dmabuf *db) { if (db->lbuf) { diff --git a/sound/oss/sequencer_syms.c b/sound/oss/sequencer_syms.c index 45edfd767e4e7b1edcc4cb14ad18a36961f6c5e6..5d008798c31018bdc1a0af6976476acce59347a9 100644 --- a/sound/oss/sequencer_syms.c +++ b/sound/oss/sequencer_syms.c @@ -19,7 +19,6 @@ EXPORT_SYMBOL(sequencer_timer); EXPORT_SYMBOL(sound_timer_init); EXPORT_SYMBOL(sound_timer_interrupt); EXPORT_SYMBOL(sound_timer_syncinterval); -EXPORT_SYMBOL(reprogram_timer); /* Tuning */ diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index a5d593c66f9fca6b05ebade6a33d873dfba89397..0fb16cf335ea1a85cf3e19576de777b3cf4cc405 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -1,13 +1,5 @@ # ALSA PCI drivers -config SND_AC97_CODEC - tristate - select SND_PCM - select SND_AC97_BUS - -config SND_AC97_BUS - tristate - menu "PCI devices" depends on SND!=n && PCI @@ -192,6 +184,7 @@ config SND_CA0106 tristate "SB Audigy LS / Live 24bit" depends on SND select SND_AC97_CODEC + select SND_RAWMIDI help Say Y here to include support for the Sound Blaster Audigy LS and Live 24bit. diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 41fc290149ed19a49dcd40b84161c7191657563b..9bde76c4c6a2d332ddfeef34edf449e95e44734e 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -220,12 +220,6 @@ const char *snd_ac97_stereo_enhancements[] = /* 31 */ "Reserved 31" }; -/* - * Shared AC97 controllers (ICH, ATIIXP...) - */ -static DECLARE_MUTEX(shared_codec_mutex); -static ac97_t *shared_codec[AC97_SHARED_TYPES][4]; - /* * I/O routines @@ -996,14 +990,8 @@ static int snd_ac97_free(ac97_t *ac97) { if (ac97) { snd_ac97_proc_done(ac97); - if (ac97->bus) { + if (ac97->bus) ac97->bus->codec[ac97->num] = NULL; - if (ac97->bus->shared_type) { - down(&shared_codec_mutex); - shared_codec[ac97->bus->shared_type-1][ac97->num] = NULL; - up(&shared_codec_mutex); - } - } if (ac97->private_free) ac97->private_free(ac97); kfree(ac97); @@ -1139,7 +1127,6 @@ snd_kcontrol_t *snd_ac97_cnew(const snd_kcontrol_new_t *_template, ac97_t * ac97 { snd_kcontrol_new_t template; memcpy(&template, _template, sizeof(template)); - snd_runtime_check(!template.index, return NULL); template.index = ac97->num; return snd_ctl_new1(&template, ac97); } @@ -1758,8 +1745,7 @@ static int ac97_reset_wait(ac97_t *ac97, int timeout, int with_modem) if ((snd_ac97_read(ac97, AC97_REC_GAIN) & 0x7fff) == 0x0a05) return 0; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); return -ENODEV; } @@ -1889,21 +1875,6 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97) snd_assert(bus != NULL && template != NULL, return -EINVAL); snd_assert(template->num < 4 && bus->codec[template->num] == NULL, return -EINVAL); - snd_assert(bus->shared_type <= AC97_SHARED_TYPES, return -EINVAL); - if (bus->shared_type) { - /* already shared? */ - down(&shared_codec_mutex); - ac97 = shared_codec[bus->shared_type-1][template->num]; - if (ac97) { - if ((ac97_is_audio(ac97) && (template->scaps & AC97_SCAP_SKIP_AUDIO)) || - (ac97_is_modem(ac97) && (template->scaps & AC97_SCAP_SKIP_MODEM))) { - up(&shared_codec_mutex); - return -EACCES; /* skip this */ - } - } - up(&shared_codec_mutex); - } - card = bus->card; ac97 = kzalloc(sizeof(*ac97), GFP_KERNEL); if (ac97 == NULL) @@ -2020,8 +1991,7 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97) do { if ((snd_ac97_read(ac97, AC97_POWERDOWN) & 0x0f) == 0x0f) goto __ready_ok; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); snd_printk(KERN_WARNING "AC'97 %d analog subsections not ready\n", ac97->num); } @@ -2053,8 +2023,7 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97) do { if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp) goto __ready_ok; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); snd_printk(KERN_WARNING "MC'97 %d converters and GPIO not ready (0x%x)\n", ac97->num, snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS)); } @@ -2077,6 +2046,8 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97) snd_ac97_update_bits(ac97, AC97_GENERAL_PURPOSE, AC97_GP_DRSS_MASK, AC97_GP_DRSS_78); if ((snd_ac97_read(ac97, AC97_GENERAL_PURPOSE) & AC97_GP_DRSS_MASK) == AC97_GP_DRSS_78) ac97->flags |= AC97_DOUBLE_RATE; + /* restore to slots 10/11 to avoid the confliction with surrounds */ + snd_ac97_update_bits(ac97, AC97_GENERAL_PURPOSE, AC97_GP_DRSS_MASK, 0); } if (ac97->ext_id & AC97_EI_VRA) { /* VRA support */ snd_ac97_determine_rates(ac97, AC97_PCM_FRONT_DAC_RATE, 0, &ac97->rates[AC97_RATES_FRONT_DAC]); @@ -2153,7 +2124,7 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97) } } /* make sure the proper powerdown bits are cleared */ - if (ac97->scaps) { + if (ac97->scaps && ac97_is_audio(ac97)) { reg = snd_ac97_read(ac97, AC97_EXTENDED_STATUS); if (ac97->scaps & AC97_SCAP_SURROUND_DAC) reg &= ~AC97_EA_PRJ; @@ -2167,13 +2138,6 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97) return err; } *rac97 = ac97; - - if (bus->shared_type) { - down(&shared_codec_mutex); - shared_codec[bus->shared_type-1][ac97->num] = ac97; - up(&shared_codec_mutex); - } - return 0; } @@ -2295,8 +2259,7 @@ void snd_ac97_resume(ac97_t *ac97) do { if (snd_ac97_read(ac97, AC97_MASTER) == 0x8101) break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); /* FIXME: extra delay */ ac97->bus->ops->write(ac97, AC97_MASTER, 0x8000); @@ -2308,8 +2271,7 @@ void snd_ac97_resume(ac97_t *ac97) unsigned short val = snd_ac97_read(ac97, AC97_EXTENDED_MID); if (val != 0xffff && (val & 1) != 0) break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); } __reset_ready: diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 0238cc65d32af32735bae44ec8ebe97a3448eb09..de1c72ad2c6bb1109c5333bb3dad838e810abcf4 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -163,14 +163,24 @@ static int ac97_channel_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t .private_value = 1, \ } +static inline int is_surround_on(ac97_t *ac97) +{ + return ac97->channel_mode >= 1; +} + +static inline int is_clfe_on(ac97_t *ac97) +{ + return ac97->channel_mode >= 2; +} + static inline int is_shared_linein(ac97_t *ac97) { - return ! ac97->indep_surround && ac97->channel_mode >= 1; + return ! ac97->indep_surround && is_surround_on(ac97); } static inline int is_shared_micin(ac97_t *ac97) { - return ! ac97->indep_surround && ac97->channel_mode >= 2; + return ! ac97->indep_surround && is_clfe_on(ac97); } @@ -1450,7 +1460,8 @@ int patch_ad1881(ac97_t * ac97) codecs[1] = patch_ad1881_unchained(ac97, 1, (1<<14)); codecs[2] = patch_ad1881_unchained(ac97, 2, (1<<13)); - snd_runtime_check(codecs[0] | codecs[1] | codecs[2], goto __end); + if (! (codecs[0] || codecs[1] || codecs[2])) + goto __end; for (idx = 0; idx < 3; idx++) if (ac97->spec.ad18xx.unchained[idx]) @@ -1753,12 +1764,13 @@ static int snd_ac97_ad1888_downmix_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_va static void ad1888_update_jacks(ac97_t *ac97) { + unsigned short val = 0; + if (! is_shared_linein(ac97)) + val |= (1 << 12); + if (! is_shared_micin(ac97)) + val |= (1 << 11); /* shared Line-In */ - snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 12, - is_shared_linein(ac97) ? 0 : 1 << 12); - /* shared Mic */ - snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 11, - is_shared_micin(ac97) ? 0 : 1 << 11); + snd_ac97_update_bits(ac97, AC97_AD_MISC, (1 << 11) | (1 << 12), val); } static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = { @@ -1852,12 +1864,7 @@ static const snd_kcontrol_new_t snd_ac97_ad1985_controls[] = { static void ad1985_update_jacks(ac97_t *ac97) { - /* shared Line-In */ - snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 12, - is_shared_linein(ac97) ? 0 : 1 << 12); - /* shared Mic */ - snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 11, - is_shared_micin(ac97) ? 0 : 1 << 11); + ad1888_update_jacks(ac97); snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 1 << 9, is_shared_micin(ac97) ? 0 : 1 << 9); } @@ -2442,21 +2449,37 @@ int patch_cm9739(ac97_t * ac97) static void cm9761_update_jacks(ac97_t *ac97) { - unsigned short surr_vals[2][2] = { - { 0x0008, 0x0400 }, /* off, on */ - { 0x0000, 0x0408 }, /* off, on (9761-82 rev.B) */ + /* FIXME: check the bits for each model + * model 83 is confirmed to work + */ + static unsigned short surr_on[3][2] = { + { 0x0008, 0x0000 }, /* 9761-78 & 82 */ + { 0x0000, 0x0008 }, /* 9761-82 rev.B */ + { 0x0000, 0x0008 }, /* 9761-83 */ + }; + static unsigned short clfe_on[3][2] = { + { 0x0000, 0x1000 }, /* 9761-78 & 82 */ + { 0x1000, 0x0000 }, /* 9761-82 rev.B */ + { 0x0000, 0x1000 }, /* 9761-83 */ + }; + static unsigned short surr_shared[3][2] = { + { 0x0000, 0x0400 }, /* 9761-78 & 82 */ + { 0x0000, 0x0400 }, /* 9761-82 rev.B */ + { 0x0000, 0x0400 }, /* 9761-83 */ }; - unsigned short clfe_vals[2][2] = { - { 0x2000, 0x1880 }, /* off, on */ - { 0x1000, 0x2880 }, /* off, on (9761-82 rev.B) */ + static unsigned short clfe_shared[3][2] = { + { 0x2000, 0x0880 }, /* 9761-78 & 82 */ + { 0x0000, 0x2880 }, /* 9761-82 rev.B */ + { 0x2000, 0x0800 }, /* 9761-83 */ }; + unsigned short val = 0; - /* shared Line-In */ - snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x0408, - surr_vals[ac97->spec.dev_flags][is_shared_linein(ac97)]); - /* shared Mic */ - snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3880, - clfe_vals[ac97->spec.dev_flags][is_shared_micin(ac97)]); + val |= surr_on[ac97->spec.dev_flags][is_surround_on(ac97)]; + val |= clfe_on[ac97->spec.dev_flags][is_clfe_on(ac97)]; + val |= surr_shared[ac97->spec.dev_flags][is_shared_linein(ac97)]; + val |= clfe_shared[ac97->spec.dev_flags][is_shared_micin(ac97)]; + + snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3c88, val); } static const snd_kcontrol_new_t snd_ac97_cm9761_controls[] = { @@ -2551,7 +2574,7 @@ int patch_cm9761(ac97_t *ac97) snd_ac97_write_cache(ac97, AC97_MASTER, 0x8808); snd_ac97_write_cache(ac97, AC97_PCM, 0x8808); - ac97->spec.dev_flags = 0; /* 1 = model 82 revision B */ + ac97->spec.dev_flags = 0; /* 1 = model 82 revision B, 2 = model 83 */ if (ac97->id == AC97_ID_CM9761_82) { unsigned short tmp; /* check page 1, reg 0x60 */ @@ -2560,7 +2583,8 @@ int patch_cm9761(ac97_t *ac97) tmp = snd_ac97_read(ac97, 0x60); ac97->spec.dev_flags = tmp & 1; /* revision B? */ snd_ac97_write_cache(ac97, AC97_INT_PAGING, val); - } + } else if (ac97->id == AC97_ID_CM9761_83) + ac97->spec.dev_flags = 2; ac97->build_ops = &patch_cm9761_ops; diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c index dd289b9512e13b55c2f088464572380a4aad00dc..ded13165d635e24113e2c8f935f08399dafaadaf 100644 --- a/sound/pci/ac97/ac97_pcm.c +++ b/sound/pci/ac97/ac97_pcm.c @@ -303,6 +303,15 @@ int snd_ac97_set_rate(ac97_t *ac97, int reg, unsigned int rate) AC97_EA_DRA, dbl ? AC97_EA_DRA : 0); snd_ac97_update(ac97, reg, tmp & 0xffff); snd_ac97_read(ac97, reg); + if ((ac97->ext_id & AC97_EI_DRA) && reg == AC97_PCM_FRONT_DAC_RATE) { + /* Intel controllers require double rate data to be put in + * slots 7+8 + */ + snd_ac97_update_bits(ac97, AC97_GENERAL_PURPOSE, + AC97_GP_DRSS_MASK, + dbl ? AC97_GP_DRSS_78 : 0); + snd_ac97_read(ac97, AC97_GENERAL_PURPOSE); + } return 0; } diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index d7d99a25c5e53dffb1ac797c62d8ffac2a9db212..e72ccd1a004f9dce58479a507dfced1a8f8374cd 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c @@ -50,7 +50,7 @@ #include "ad1889.h" #include "ac97/ac97_id.h" -#define AD1889_DRVVER "$Revision: 1.3 $" +#define AD1889_DRVVER "$Revision: 1.4 $" MODULE_AUTHOR("Kyle McMartin , Thibaut Varene "); MODULE_DESCRIPTION("Analog Devices AD1889 ALSA sound driver"); @@ -982,8 +982,7 @@ snd_ad1889_create(snd_card_t *card, return 0; free_and_ret: - if (chip) - kfree(chip); + kfree(chip); pci_disable_device(pci); return err; diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index f35b558c29b2474b2e4bd8168c00c4b0bffd5841..4e76c4a636d93e9de0d6116fd3d4fde9edd72077 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -45,23 +45,25 @@ MODULE_DESCRIPTION("ALI M5451"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{ALI,M5451,pci},{ALI,M5451}}"); -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; -static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 32}; -static int spdif[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; +static int index = SNDRV_DEFAULT_IDX1; /* Index */ +static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ +static int pcm_channels = 32; +static int spdif = 0; -module_param_array(index, int, NULL, 0444); +module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for ALI M5451 PCI Audio."); -module_param_array(id, charp, NULL, 0444); +module_param(id, charp, 0444); MODULE_PARM_DESC(id, "ID string for ALI M5451 PCI Audio."); -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable ALI 5451 PCI Audio."); -module_param_array(pcm_channels, int, NULL, 0444); +module_param(pcm_channels, int, 0444); MODULE_PARM_DESC(pcm_channels, "PCM Channels"); -module_param_array(spdif, bool, NULL, 0444); +module_param(spdif, bool, 0444); MODULE_PARM_DESC(spdif, "Support SPDIF I/O"); +/* just for backward compatibility */ +static int enable; +module_param(enable, bool, 0444); + + /* * Debug part definitions */ @@ -396,10 +398,8 @@ static int snd_ali_codec_ready( ali_t *codec, res = snd_ali_5451_peek(codec,port); if (! (res & 0x8000)) return 0; - if (sched) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } + if (sched) + schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); snd_ali_5451_poke(codec, port, res & ~0x8000); snd_printdd("ali_codec_ready: codec is not ready.\n "); @@ -419,12 +419,10 @@ static int snd_ali_stimer_ready(ali_t *codec, int sched) dwChk2 = snd_ali_5451_peek(codec, ALI_STIMER); if (dwChk2 != dwChk1) return 0; - if (sched) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } + if (sched) + schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); - snd_printk("ali_stimer_read: stimer is not ready.\n"); + snd_printk(KERN_ERR "ali_stimer_read: stimer is not ready.\n"); return -EIO; } @@ -436,7 +434,7 @@ static void snd_ali_codec_poke(ali_t *codec,int secondary, unsigned int port = 0; if (reg >= 0x80) { - snd_printk("ali_codec_poke: reg(%xh) invalid.\n", reg); + snd_printk(KERN_ERR "ali_codec_poke: reg(%xh) invalid.\n", reg); return; } @@ -465,7 +463,7 @@ static unsigned short snd_ali_codec_peek( ali_t *codec, unsigned int port = 0; if (reg >= 0x80) { - snd_printk("ali_codec_peek: reg(%xh) invalid.\n", reg); + snd_printk(KERN_ERR "ali_codec_peek: reg(%xh) invalid.\n", reg); return ~0; } @@ -669,7 +667,7 @@ static int snd_ali_alloc_pcm_channel(ali_t *codec, int channel) unsigned int idx = channel & 0x1f; if (codec->synth.chcnt >= ALI_CHANNELS){ - snd_printk("ali_alloc_pcm_channel: no free channels.\n"); + snd_printk(KERN_ERR "ali_alloc_pcm_channel: no free channels.\n"); return -1; } @@ -700,7 +698,7 @@ static int snd_ali_find_free_channel(ali_t * codec, int rec) if ((result = snd_ali_alloc_pcm_channel(codec,idx)) >= 0) { return result; } else { - snd_printk("ali_find_free_channel: record channel is busy now.\n"); + snd_printk(KERN_ERR "ali_find_free_channel: record channel is busy now.\n"); return -1; } } @@ -712,7 +710,7 @@ static int snd_ali_find_free_channel(ali_t * codec, int rec) if ((result = snd_ali_alloc_pcm_channel(codec,idx)) >= 0) { return result; } else { - snd_printk("ali_find_free_channel: S/PDIF out channel is in busy now.\n"); + snd_printk(KERN_ERR "ali_find_free_channel: S/PDIF out channel is in busy now.\n"); } } @@ -720,7 +718,7 @@ static int snd_ali_find_free_channel(ali_t * codec, int rec) if ((result = snd_ali_alloc_pcm_channel(codec,idx)) >= 0) return result; } - snd_printk("ali_find_free_channel: no free channels.\n"); + snd_printk(KERN_ERR "ali_find_free_channel: no free channels.\n"); return -1; } @@ -734,7 +732,7 @@ static void snd_ali_free_channel_pcm(ali_t *codec, int channel) return; if (!(codec->synth.chmap & (1 << idx))) { - snd_printk("ali_free_channel_pcm: channel %d is not in use.\n",channel); + snd_printk(KERN_ERR "ali_free_channel_pcm: channel %d is not in use.\n",channel); return; } else { codec->synth.chmap &= ~(1 << idx); @@ -796,7 +794,7 @@ static void snd_ali_detect_spdif_rate(ali_t *codec) } if (count > 50000) { - snd_printk("ali_detect_spdif_rate: timeout!\n"); + snd_printk(KERN_ERR "ali_detect_spdif_rate: timeout!\n"); return; } @@ -809,7 +807,7 @@ static void snd_ali_detect_spdif_rate(ali_t *codec) } if (count > 50000) { - snd_printk("ali_detect_spdif_rate: timeout!\n"); + snd_printk(KERN_ERR "ali_detect_spdif_rate: timeout!\n"); return; } @@ -1077,7 +1075,7 @@ static snd_ali_voice_t *snd_ali_alloc_voice(ali_t * codec, int type, int rec, in idx = channel > 0 ? snd_ali_alloc_pcm_channel(codec, channel) : snd_ali_find_free_channel(codec,rec); if(idx < 0) { - snd_printk("ali_alloc_voice: err.\n"); + snd_printk(KERN_ERR "ali_alloc_voice: err.\n"); spin_unlock_irqrestore(&codec->voice_alloc, flags); return NULL; } @@ -1479,13 +1477,13 @@ static int snd_ali_prepare(snd_pcm_substream_t * substream) } rate = snd_ali_get_spdif_in_rate(codec); if (rate == 0) { - snd_printk("ali_capture_preapre: spdif rate detect err!\n"); + snd_printk(KERN_WARNING "ali_capture_preapre: spdif rate detect err!\n"); rate = 48000; } bValue = inb(ALI_REG(codec,ALI_SPDIF_CTRL)); if (bValue & 0x10) { outb(bValue,ALI_REG(codec,ALI_SPDIF_CTRL)); - printk("clear SPDIF parity error flag.\n"); + printk(KERN_WARNING "clear SPDIF parity error flag.\n"); } if (rate != 48000) @@ -1795,6 +1793,7 @@ struct ali_pcm_description { unsigned int capture_num; snd_pcm_ops_t *playback_ops; snd_pcm_ops_t *capture_ops; + unsigned short class; }; @@ -1813,12 +1812,11 @@ static int __devinit snd_ali_pcm(ali_t * codec, int device, struct ali_pcm_descr err = snd_pcm_new(codec->card, desc->name, device, desc->playback_num, desc->capture_num, &pcm); if (err < 0) { - snd_printk("snd_ali_pcm: err called snd_pcm_new.\n"); + snd_printk(KERN_ERR "snd_ali_pcm: err called snd_pcm_new.\n"); return err; } pcm->private_data = codec; pcm->private_free = snd_ali_pcm_free; - pcm->info_flags = 0; if (desc->playback_ops) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, desc->playback_ops); if (desc->capture_ops) @@ -1828,6 +1826,7 @@ static int __devinit snd_ali_pcm(ali_t * codec, int device, struct ali_pcm_descr snd_dma_pci_data(codec->pci), 64*1024, 128*1024); pcm->info_flags = 0; + pcm->dev_class = desc->class; pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; strcpy(pcm->name, desc->name); codec->pcm[0] = pcm; @@ -1836,7 +1835,7 @@ static int __devinit snd_ali_pcm(ali_t * codec, int device, struct ali_pcm_descr static struct ali_pcm_description ali_pcms[] = { { "ALI 5451", ALI_CHANNELS, 1, &snd_ali_playback_ops, &snd_ali_capture_ops }, - { "ALI 5451 modem", 1, 1, &snd_ali_modem_playback_ops, &snd_ali_modem_capture_ops } + { "ALI 5451 modem", 1, 1, &snd_ali_modem_playback_ops, &snd_ali_modem_capture_ops, SNDRV_PCM_CLASS_MODEM } }; static int __devinit snd_ali_build_pcms(ali_t *codec) @@ -1991,7 +1990,7 @@ static int __devinit snd_ali_mixer(ali_t * codec) for ( i = 0 ; i < codec->num_of_codecs ; i++) { ac97.num = i; if ((err = snd_ac97_mixer(codec->ac97_bus, &ac97, &codec->ac97[i])) < 0) { - snd_printk("ali mixer %d creating error.\n", i); + snd_printk(KERN_ERR "ali mixer %d creating error.\n", i); if(i == 0) return err; codec->num_of_codecs = 1; @@ -2125,7 +2124,7 @@ static int snd_ali_chip_init(ali_t *codec) snd_ali_printk("chip initializing ... \n"); if (snd_ali_reset_5451(codec)) { - snd_printk("ali_chip_init: reset 5451 error.\n"); + snd_printk(KERN_ERR "ali_chip_init: reset 5451 error.\n"); return -1; } @@ -2200,7 +2199,7 @@ static int __devinit snd_ali_resources(ali_t *codec) codec->port = pci_resource_start(codec->pci, 0); if (request_irq(codec->pci->irq, snd_ali_card_interrupt, SA_INTERRUPT|SA_SHIRQ, "ALI 5451", (void *)codec)) { - snd_printk("Unable to request irq.\n"); + snd_printk(KERN_ERR "Unable to request irq.\n"); return -EBUSY; } codec->irq = codec->pci->irq; @@ -2240,7 +2239,7 @@ static int __devinit snd_ali_create(snd_card_t * card, /* check, if we can restrict PCI DMA transfers to 31 bits */ if (pci_set_dma_mask(pci, 0x7fffffff) < 0 || pci_set_consistent_dma_mask(pci, 0x7fffffff) < 0) { - snd_printk("architecture does not support 31bit PCI busmaster DMA\n"); + snd_printk(KERN_ERR "architecture does not support 31bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -2329,7 +2328,7 @@ static int __devinit snd_ali_create(snd_card_t * card, } if ((err = snd_ali_chip_init(codec)) < 0) { - snd_printk("ali create: chip init error.\n"); + snd_printk(KERN_ERR "ali create: chip init error.\n"); return err; } @@ -2352,25 +2351,17 @@ static int __devinit snd_ali_create(snd_card_t * card, static int __devinit snd_ali_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { - static int dev; snd_card_t *card; ali_t *codec; int err; snd_ali_printk("probe ...\n"); - if (dev >= SNDRV_CARDS) - return -ENODEV; - if (!enable[dev]) { - dev++; - return -ENOENT; - } - - card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + card = snd_card_new(index, id, THIS_MODULE, 0); if (card == NULL) return -ENOMEM; - if ((err = snd_ali_create(card, pci, pcm_channels[dev], spdif[dev], &codec)) < 0) { + if ((err = snd_ali_create(card, pci, pcm_channels, spdif, &codec)) < 0) { snd_card_free(card); return err; } @@ -2401,7 +2392,6 @@ static int __devinit snd_ali_probe(struct pci_dev *pci, return err; } pci_set_drvdata(pci, card); - dev++; return 0; } diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index 196ec1c61bb4712342055924902863064e8ca200..7c61561f297fc266466120e9b52b6754b4a4dc70 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -594,8 +594,7 @@ static int __devinit snd_als4000_create_gameport(snd_card_als4000_t *acard, int acard->gameport = gp = gameport_allocate_port(); if (!gp) { printk(KERN_ERR "als4000: cannot allocate memory for gameport\n"); - release_resource(r); - kfree_nocheck(r); + release_and_free_resource(r); return -ENOMEM; } @@ -622,8 +621,7 @@ static void snd_als4000_free_gameport(snd_card_als4000_t *acard) acard->gameport = NULL; snd_als4000_set_addr(acard->gcr, 0, 0, 0, 0); /* disable joystick */ - release_resource(r); - kfree_nocheck(r); + release_and_free_resource(r); } } #else @@ -669,7 +667,7 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci, /* check, if we can restrict PCI DMA transfers to 24 bits */ if (pci_set_dma_mask(pci, 0x00ffffff) < 0 || pci_set_consistent_dma_mask(pci, 0x00ffffff) < 0) { - snd_printk("architecture does not support 24bit PCI busmaster DMA\n"); + snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 241eacf1e6522d086e1eeeceba1e15bc0844681f..f5dad9248e3999b8a69290391e9a6c3845d33975 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -39,26 +39,27 @@ MODULE_DESCRIPTION("ATI IXP AC97 controller"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{ATI,IXP150/200/250/300/400}}"); -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ -static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 48000}; -static char *ac97_quirk[SNDRV_CARDS]; -static int spdif_aclink[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; - -module_param_array(index, int, NULL, 0444); +static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ +static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ +static int ac97_clock = 48000; +static char *ac97_quirk; +static int spdif_aclink = 1; + +module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for ATI IXP controller."); -module_param_array(id, charp, NULL, 0444); +module_param(id, charp, 0444); MODULE_PARM_DESC(id, "ID string for ATI IXP controller."); -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable audio part of ATI IXP controller."); -module_param_array(ac97_clock, int, NULL, 0444); +module_param(ac97_clock, int, 0444); MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz)."); -module_param_array(ac97_quirk, charp, NULL, 0444); +module_param(ac97_quirk, charp, 0444); MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); -module_param_array(spdif_aclink, bool, NULL, 0444); +module_param(spdif_aclink, bool, 0444); MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link."); +/* just for backward compatibility */ +static int enable; +module_param(enable, bool, 0444); + /* */ @@ -329,8 +330,7 @@ static int snd_atiixp_update_bits(atiixp_t *chip, unsigned int reg, /* delay for one tick */ #define do_delay() do { \ - set_current_state(TASK_UNINTERRUPTIBLE); \ - schedule_timeout(1); \ + schedule_timeout_uninterruptible(1); \ } while (0) @@ -1372,7 +1372,6 @@ static int __devinit snd_atiixp_mixer_new(atiixp_t *chip, int clock, const char if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &pbus)) < 0) return err; pbus->clock = clock; - pbus->shared_type = AC97_SHARED_TYPE_ATIIXP; /* shared with modem driver */ chip->ac97_bus = pbus; codec_count = 0; @@ -1579,26 +1578,18 @@ static int __devinit snd_atiixp_create(snd_card_t *card, static int __devinit snd_atiixp_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { - static int dev; snd_card_t *card; atiixp_t *chip; unsigned char revision; int err; - if (dev >= SNDRV_CARDS) - return -ENODEV; - if (!enable[dev]) { - dev++; - return -ENOENT; - } - - card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + card = snd_card_new(index, id, THIS_MODULE, 0); if (card == NULL) return -ENOMEM; pci_read_config_byte(pci, PCI_REVISION_ID, &revision); - strcpy(card->driver, spdif_aclink[dev] ? "ATIIXP" : "ATIIXP-SPDMA"); + strcpy(card->driver, spdif_aclink ? "ATIIXP" : "ATIIXP-SPDMA"); strcpy(card->shortname, "ATI IXP"); if ((err = snd_atiixp_create(card, pci, &chip)) < 0) goto __error; @@ -1606,9 +1597,9 @@ static int __devinit snd_atiixp_probe(struct pci_dev *pci, if ((err = snd_atiixp_aclink_reset(chip)) < 0) goto __error; - chip->spdif_over_aclink = spdif_aclink[dev]; + chip->spdif_over_aclink = spdif_aclink; - if ((err = snd_atiixp_mixer_new(chip, ac97_clock[dev], ac97_quirk[dev])) < 0) + if ((err = snd_atiixp_mixer_new(chip, ac97_clock, ac97_quirk)) < 0) goto __error; if ((err = snd_atiixp_pcm_new(chip)) < 0) @@ -1629,7 +1620,6 @@ static int __devinit snd_atiixp_probe(struct pci_dev *pci, goto __error; pci_set_drvdata(pci, card); - dev++; return 0; __error: diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index c1a239a4dac642b785d354960f6a1c76f225c223..0cf2020795718e358ce79f5baa6d91a1ddbf1f98 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -39,20 +39,21 @@ MODULE_DESCRIPTION("ATI IXP MC97 controller"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{ATI,IXP150/200/250}}"); -static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* Exclude the first card */ -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ -static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 48000}; +static int index = -2; /* Exclude the first card */ +static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ +static int ac97_clock = 48000; -module_param_array(index, int, NULL, 0444); +module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for ATI IXP controller."); -module_param_array(id, charp, NULL, 0444); +module_param(id, charp, 0444); MODULE_PARM_DESC(id, "ID string for ATI IXP controller."); -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable audio part of ATI IXP controller."); -module_param_array(ac97_clock, int, NULL, 0444); +module_param(ac97_clock, int, 0444); MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz)."); +/* just for backward compatibility */ +static int enable; +module_param(enable, bool, 0444); + /* */ @@ -306,8 +307,7 @@ static int snd_atiixp_update_bits(atiixp_t *chip, unsigned int reg, /* delay for one tick */ #define do_delay() do { \ - set_current_state(TASK_UNINTERRUPTIBLE); \ - schedule_timeout(1); \ + schedule_timeout_uninterruptible(1); \ } while (0) @@ -989,6 +989,7 @@ static int __devinit snd_atiixp_pcm_new(atiixp_t *chip) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_atiixp_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_atiixp_capture_ops); + pcm->dev_class = SNDRV_PCM_CLASS_MODEM; pcm->private_data = chip; strcpy(pcm->name, "ATI IXP MC97"); chip->pcmdevs[ATI_PCMDEV_ANALOG] = pcm; @@ -1067,7 +1068,6 @@ static int __devinit snd_atiixp_mixer_new(atiixp_t *chip, int clock) if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &pbus)) < 0) return err; pbus->clock = clock; - pbus->shared_type = AC97_SHARED_TYPE_ATIIXP; /* shared with audio driver */ chip->ac97_bus = pbus; codec_count = 0; @@ -1256,20 +1256,12 @@ static int __devinit snd_atiixp_create(snd_card_t *card, static int __devinit snd_atiixp_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { - static int dev; snd_card_t *card; atiixp_t *chip; unsigned char revision; int err; - if (dev >= SNDRV_CARDS) - return -ENODEV; - if (!enable[dev]) { - dev++; - return -ENOENT; - } - - card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + card = snd_card_new(index, id, THIS_MODULE, 0); if (card == NULL) return -ENOMEM; @@ -1283,7 +1275,7 @@ static int __devinit snd_atiixp_probe(struct pci_dev *pci, if ((err = snd_atiixp_aclink_reset(chip)) < 0) goto __error; - if ((err = snd_atiixp_mixer_new(chip, ac97_clock[dev])) < 0) + if ((err = snd_atiixp_mixer_new(chip, ac97_clock)) < 0) goto __error; if ((err = snd_atiixp_pcm_new(chip)) < 0) @@ -1302,7 +1294,6 @@ static int __devinit snd_atiixp_probe(struct pci_dev *pci, goto __error; pci_set_drvdata(pci, card); - dev++; return 0; __error: diff --git a/sound/pci/au88x0/au8810.h b/sound/pci/au88x0/au8810.h index 3837d2ba5e673d7c991b4a7d81ac20cd56da8790..5d69c31fe3f474ace0ef2da5c6ab4a117c24036f 100644 --- a/sound/pci/au88x0/au8810.h +++ b/sound/pci/au88x0/au8810.h @@ -178,11 +178,6 @@ #define EN_SPDIF 0x000c0000 #define VORTEX_CODEC_CHN 0x29080 -#define VORTEX_CODEC_WRITE 0x00800000 -#define VORTEX_CODEC_ADDSHIFT 16 -#define VORTEX_CODEC_ADDMASK 0x7f0000 /* 0x000f0000 */ -#define VORTEX_CODEC_DATSHIFT 0 -#define VORTEX_CODEC_DATMASK 0xffff #define VORTEX_CODEC_IO 0x29188 /* SPDIF */ diff --git a/sound/pci/au88x0/au8820.h b/sound/pci/au88x0/au8820.h index be8022e78714bfdf31e5474d9277b6bc92f2b6ed..abbe85e4f7a9abb3427b502d2f3c5462ce5b88aa 100644 --- a/sound/pci/au88x0/au8820.h +++ b/sound/pci/au88x0/au8820.h @@ -162,11 +162,6 @@ #define EN_SPORT 0x00030000 #define EN_SPDIF 0x000c0000 #define VORTEX_CODEC_CHN 0x11880 -#define VORTEX_CODEC_WRITE 0x00800000 -#define VORTEX_CODEC_ADDSHIFT 16 -#define VORTEX_CODEC_ADDMASK 0x7f0000 /* 0x000f0000 */ -#define VORTEX_CODEC_DATSHIFT 0 -#define VORTEX_CODEC_DATMASK 0xffff #define VORTEX_CODEC_IO 0x11988 #define VORTEX_SPDIF_FLAGS 0x1005c /* FIXME */ diff --git a/sound/pci/au88x0/au8830.h b/sound/pci/au88x0/au8830.h index aa77826b5e59f13dea4eb36ba01ee950efd68cf9..04ece1b1c2183646bfc008855cc07e3053bc8ecc 100644 --- a/sound/pci/au88x0/au8830.h +++ b/sound/pci/au88x0/au8830.h @@ -194,11 +194,6 @@ #define VORTEX_CODEC_CTRL 0x29184 #define VORTEX_CODEC_IO 0x29188 -#define VORTEX_CODEC_WRITE 0x00800000 -#define VORTEX_CODEC_ADDSHIFT 16 -#define VORTEX_CODEC_ADDMASK 0x7f0000 /* 0x000f0000 */ -#define VORTEX_CODEC_DATSHIFT 0 -#define VORTEX_CODEC_DATMASK 0xffff #define VORTEX_CODEC_SPORTCTRL 0x2918c diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c index 04b695d6fd4839f7b77cadab3964988fdf058a2d..6af3b13f2fd1d856b59e5c9abe71bb7d3f70cdaa 100644 --- a/sound/pci/au88x0/au88x0.c +++ b/sound/pci/au88x0/au88x0.c @@ -303,7 +303,7 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_VORTEX_SYNTH, sizeof(snd_vortex_synth_arg_t), &wave) < 0 || wave == NULL) { - snd_printk("Can't initialize Aureal wavetable synth\n"); + snd_printk(KERN_ERR "Can't initialize Aureal wavetable synth\n"); } else { snd_vortex_synth_arg_t *arg; diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h index ee1ede1979f63b74b1a4e4cb8bcea773936c90e9..b1197cfab3fb4b4271bb04713627bd8b487b63a5 100644 --- a/sound/pci/au88x0/au88x0.h +++ b/sound/pci/au88x0/au88x0.h @@ -79,6 +79,14 @@ #define VORTEX_RESOURCE_A3D 0x00000004 #define VORTEX_RESOURCE_LAST 0x00000005 +/* codec io: VORTEX_CODEC_IO bits */ +#define VORTEX_CODEC_ID_SHIFT 24 +#define VORTEX_CODEC_WRITE 0x00800000 +#define VORTEX_CODEC_ADDSHIFT 16 +#define VORTEX_CODEC_ADDMASK 0x7f0000 +#define VORTEX_CODEC_DATSHIFT 0 +#define VORTEX_CODEC_DATMASK 0xffff + /* Check for SDAC bit in "Extended audio ID" AC97 register */ //#define VORTEX_IS_QUAD(x) (((x)->codec == NULL) ? 0 : ((x)->codec->ext_id&0x80)) #define VORTEX_IS_QUAD(x) ((x)->isquad) diff --git a/sound/pci/au88x0/au88x0_a3d.c b/sound/pci/au88x0/au88x0_a3d.c index 9ea2ba7bc3c84d638372a55b6892ff4e1b8019a7..d5755db5141f8027ba34919ba14022eb49816865 100644 --- a/sound/pci/au88x0/au88x0_a3d.c +++ b/sound/pci/au88x0/au88x0_a3d.c @@ -488,7 +488,7 @@ static void a3dsrc_ZeroStateA3D(a3dsrc_t * a) int i, var, var2; if ((a->vortex) == NULL) { - printk("vortex: ZeroStateA3D: ERROR: a->vortex is NULL\n"); + printk(KERN_ERR "vortex: ZeroStateA3D: ERROR: a->vortex is NULL\n"); return; } diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index f0eda4bbbb39548155b3defdb9d028d84bb3cc73..5905188d06b5e5b8d23d5ce980d9485d4b560eaf 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c @@ -2033,7 +2033,7 @@ vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype) } } } - printk("vortex: FATAL: ResManager: resource type %d exhausted.\n", restype); + printk(KERN_ERR "vortex: FATAL: ResManager: resource type %d exhausted.\n", restype); return -ENOMEM; } @@ -2165,7 +2165,7 @@ vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type) memset(stream->resources, 0, sizeof(unsigned char) * VORTEX_RESOURCE_LAST); - printk("vortex: out of A3D sources. Sorry\n"); + printk(KERN_ERR "vortex: out of A3D sources. Sorry\n"); return -EBUSY; } /* (De)Initialize A3D hardware source. */ @@ -2532,7 +2532,8 @@ vortex_codec_write(ac97_t * codec, unsigned short addr, unsigned short data) hwwrite(card->mmio, VORTEX_CODEC_IO, ((addr << VORTEX_CODEC_ADDSHIFT) & VORTEX_CODEC_ADDMASK) | ((data << VORTEX_CODEC_DATSHIFT) & VORTEX_CODEC_DATMASK) | - VORTEX_CODEC_WRITE); + VORTEX_CODEC_WRITE | + (codec->num << VORTEX_CODEC_ID_SHIFT) ); /* Flush Caches. */ hwread(card->mmio, VORTEX_CODEC_IO); @@ -2554,7 +2555,8 @@ static unsigned short vortex_codec_read(ac97_t * codec, unsigned short addr) } } /* set up read address */ - read_addr = ((addr << VORTEX_CODEC_ADDSHIFT) & VORTEX_CODEC_ADDMASK); + read_addr = ((addr << VORTEX_CODEC_ADDSHIFT) & VORTEX_CODEC_ADDMASK) | + (codec->num << VORTEX_CODEC_ID_SHIFT) ; hwwrite(card->mmio, VORTEX_CODEC_IO, read_addr); /* wait for address */ diff --git a/sound/pci/au88x0/au88x0_eq.c b/sound/pci/au88x0/au88x0_eq.c index 53b47a42c7d805ac663f88f3402de7d7f577b95e..9d933cc0ea0b06033d331366febf52f6ea6b0702 100644 --- a/sound/pci/au88x0/au88x0_eq.c +++ b/sound/pci/au88x0/au88x0_eq.c @@ -854,7 +854,7 @@ snd_vortex_peaks_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) vortex_Eqlzr_GetAllPeaks(vortex, peaks, &count); if (count != 20) { - printk("vortex: peak count error 20 != %d \n", count); + printk(KERN_ERR "vortex: peak count error 20 != %d \n", count); return -1; } for (i = 0; i < 20; i++) diff --git a/sound/pci/au88x0/au88x0_synth.c b/sound/pci/au88x0/au88x0_synth.c index 400417d34609b503d78c141cbc18aba5cdc39705..65f375bad43aca89245fd93dab6621838b37c23f 100644 --- a/sound/pci/au88x0/au88x0_synth.c +++ b/sound/pci/au88x0/au88x0_synth.c @@ -90,7 +90,7 @@ static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch) hwwrite(vortex->mmio, WT_PARM(wt, 2), 0); temp = hwread(vortex->mmio, WT_PARM(wt, 3)); - printk("vortex: WT PARM3: %x\n", temp); + printk(KERN_DEBUG "vortex: WT PARM3: %x\n", temp); //hwwrite(vortex->mmio, WT_PARM(wt, 3), temp); hwwrite(vortex->mmio, WT_DELAY(wt, 0), 0); @@ -98,7 +98,7 @@ static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch) hwwrite(vortex->mmio, WT_DELAY(wt, 2), 0); hwwrite(vortex->mmio, WT_DELAY(wt, 3), 0); - printk("vortex: WT GMODE: %x\n", hwread(vortex->mmio, WT_GMODE(wt))); + printk(KERN_DEBUG "vortex: WT GMODE: %x\n", hwread(vortex->mmio, WT_GMODE(wt))); hwwrite(vortex->mmio, WT_PARM(wt, 2), 0xffffffff); hwwrite(vortex->mmio, WT_PARM(wt, 3), 0xcff1c810); @@ -106,7 +106,7 @@ static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch) voice->parm0 = voice->parm1 = 0xcfb23e2f; hwwrite(vortex->mmio, WT_PARM(wt, 0), voice->parm0); hwwrite(vortex->mmio, WT_PARM(wt, 1), voice->parm1); - printk("vortex: WT GMODE 2 : %x\n", hwread(vortex->mmio, WT_GMODE(wt))); + printk(KERN_DEBUG "vortex: WT GMODE 2 : %x\n", hwread(vortex->mmio, WT_GMODE(wt))); return 0; } @@ -203,7 +203,7 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt, } } else { if (wt >= NR_WT) { - printk("vortex: WT SetReg: voice out of range\n"); + printk(KERN_ERR "vortex: WT SetReg: voice out of range\n"); return 0; } } diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index d5261bdec583d5fbac6bcfe438d35e8d4ac705c3..da99b1be2e8fd36e3cf639abc065ff1e85d40376 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -1,6 +1,6 @@ /* * azt3328.c - driver for Aztech AZF3328 based soundcards (e.g. PCI168). - * Copyright (C) 2002 by Andreas Mohr + * Copyright (C) 2002, 2005 by Andreas Mohr * * Framework borrowed from Bart Hartgers's als4000.c. * Driver developed on PCI168 AP(W) version (PCI rev. 10, subsystem ID 1801), @@ -46,7 +46,7 @@ * - MPU401 (+ legacy address support) FIXME: how to enable legacy addr?? * - game port (legacy address support) * - built-in General DirectX timer having a 20 bits counter - * with 1us resolution (FIXME: where is it?) + * with 1us resolution (see below!) * - I2S serial port for external DAC * - supports 33MHz PCI spec 2.1, PCI power management 1.0, compliant with ACPI * - supports hardware volume control @@ -55,13 +55,23 @@ * required for Microsoft's logo compliance (FIXME: where?) * - PCI168 AP(W) card: power amplifier with 4 Watts/channel at 4 Ohms * + * Note that this driver now is actually *better* than the Windows driver, + * since it additionally supports the card's 1MHz DirectX timer - just try + * the following snd-seq module parameters etc.: + * - options snd-seq seq_default_timer_class=2 seq_default_timer_sclass=0 + * seq_default_timer_card=0 seq_client_load=1 seq_default_timer_device=0 + * seq_default_timer_subdevice=0 seq_default_timer_resolution=1000000 + * - "timidity -iAv -B2,8 -Os -EFreverb=0" + * - "pmidi -p 128:0 jazz.mid" + * * Certain PCI versions of this card are susceptible to DMA traffic underruns * in some systems (resulting in sound crackling/clicking/popping), * probably because they don't have a DMA FIFO buffer or so. * Overview (PCI ID/PCI subID/PCI rev.): * - no DMA crackling on SiS735: 0x50DC/0x1801/16 * - unknown performance: 0x50DC/0x1801/10 - * + * (well, it's not bad on an Athlon 1800 with now very optimized IRQ handler) + * * Crackling happens with VIA chipsets or, in my case, an SiS735, which is * supposed to be very fast and supposed to get rid of crackling much * better than a VIA, yet ironically I still get crackling, like many other @@ -76,18 +86,13 @@ * - Disable ACPI/power management/"Auto Detect RAM/PCI Clk" in BIOS * * BUGS - * - when Ctrl-C'ing mpg321, the playback loops a bit - * (premature DMA playback reset?) - * - full-duplex sometimes breaks (IRQ management issues?). - * Once even a spontaneous REBOOT happened!!! + * - full-duplex might *still* be problematic, not fully tested recently * * TODO * - test MPU401 MIDI playback etc. - * - power management (CONFIG_PM). See e.g. intel8x0 or cs4281. + * - power management. See e.g. intel8x0 or cs4281. * This would be nice since the chip runs a bit hot, and it's *required* - * anyway for proper ACPI power management. In other words: rest - * assured that I *will* implement this very soon; as soon as Linux 2.5.x - * has power management that's bugfree enough to work properly on my desktop. + * anyway for proper ACPI power management. * - figure out what all unknown port bits are responsible for */ @@ -108,7 +113,7 @@ #include #include "azt3328.h" -MODULE_AUTHOR("Andreas Mohr "); +MODULE_AUTHOR("Andreas Mohr "); MODULE_DESCRIPTION("Aztech AZF3328 (PCI168)"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); @@ -122,6 +127,7 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); #define DEBUG_MIXER 0 #define DEBUG_PLAY_REC 0 #define DEBUG_IO 0 +#define DEBUG_TIMER 0 #define MIXER_TESTING 0 #if DEBUG_MISC @@ -132,8 +138,8 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); #if DEBUG_CALLS #define snd_azf3328_dbgcalls(format, args...) printk(format, ##args) -#define snd_azf3328_dbgcallenter() printk(KERN_ERR "entering %s\n", __FUNCTION__) -#define snd_azf3328_dbgcallleave() printk(KERN_ERR "leaving %s\n", __FUNCTION__) +#define snd_azf3328_dbgcallenter() printk(KERN_ERR "--> %s\n", __FUNCTION__) +#define snd_azf3328_dbgcallleave() printk(KERN_ERR "<-- %s\n", __FUNCTION__) #else #define snd_azf3328_dbgcalls(format, args...) #define snd_azf3328_dbgcallenter() @@ -152,13 +158,12 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); #define snd_azf3328_dbgplay(format, args...) #endif -#if DEBUG_IO -#define snd_azf3328_dbgio(chip, where) \ - printk(KERN_ERR "%s: IDX_IO_PLAY_FLAGS %04x, IDX_IO_PLAY_IRQMASK %04x, IDX_IO_IRQSTATUS %04x\n", where, inw(chip->codec_port+IDX_IO_PLAY_FLAGS), inw(chip->codec_port+IDX_IO_PLAY_IRQMASK), inw(chip->codec_port+IDX_IO_IRQSTATUS)) +#if DEBUG_MISC +#define snd_azf3328_dbgtimer(format, args...) printk(KERN_ERR format, ##args) #else -#define snd_azf3328_dbgio(chip, where) -#endif - +#define snd_azf3328_dbgtimer(format, args...) +#endif + static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for AZF3328 soundcard."); @@ -177,35 +182,40 @@ module_param_array(joystick, bool, NULL, 0444); MODULE_PARM_DESC(joystick, "Enable joystick for AZF3328 soundcard."); #endif -typedef struct _snd_azf3328 azf3328_t; - -struct _snd_azf3328 { - int irq; +static int seqtimer_scaling = 128; +module_param(seqtimer_scaling, int, 0444); +MODULE_PARM_DESC(seqtimer_scaling, "Set 1024000Hz sequencer timer scale factor (lockup danger!). Default 128."); +typedef struct _snd_azf3328 { + /* often-used fields towards beginning, then grouped */ unsigned long codec_port; unsigned long io2_port; unsigned long mpu_port; unsigned long synth_port; unsigned long mixer_port; -#ifdef SUPPORT_JOYSTICK - struct gameport *gameport; -#endif - - struct pci_dev *pci; - snd_card_t *card; + spinlock_t reg_lock; + snd_timer_t *timer; + snd_pcm_t *pcm; - snd_rawmidi_t *rmidi; snd_pcm_substream_t *playback_substream; snd_pcm_substream_t *capture_substream; unsigned int is_playing; unsigned int is_recording; - spinlock_t reg_lock; -}; + snd_card_t *card; + snd_rawmidi_t *rmidi; + +#ifdef SUPPORT_JOYSTICK + struct gameport *gameport; +#endif -static struct pci_device_id snd_azf3328_ids[] = { + struct pci_dev *pci; + int irq; +} azf3328_t; + +static const struct pci_device_id snd_azf3328_ids[] = { { 0x122D, 0x50DC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* PCI168/3328 */ { 0x122D, 0x80DA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* 3328 */ { 0, } @@ -213,57 +223,90 @@ static struct pci_device_id snd_azf3328_ids[] = { MODULE_DEVICE_TABLE(pci, snd_azf3328_ids); -static inline void snd_azf3328_io2_write(azf3328_t *chip, int reg, unsigned char value) +static inline void +snd_azf3328_codec_outb(const azf3328_t *chip, int reg, u8 value) +{ + outb(value, chip->codec_port + reg); +} + +static inline u8 +snd_azf3328_codec_inb(const azf3328_t *chip, int reg) +{ + return inb(chip->codec_port + reg); +} + +static inline void +snd_azf3328_codec_outw(const azf3328_t *chip, int reg, u16 value) +{ + outw(value, chip->codec_port + reg); +} + +static inline u16 +snd_azf3328_codec_inw(const azf3328_t *chip, int reg) +{ + return inw(chip->codec_port + reg); +} + +static inline void +snd_azf3328_codec_outl(const azf3328_t *chip, int reg, u32 value) +{ + outl(value, chip->codec_port + reg); +} + +static inline void +snd_azf3328_io2_outb(const azf3328_t *chip, int reg, u8 value) { outb(value, chip->io2_port + reg); } -static inline unsigned char snd_azf3328_io2_read(azf3328_t *chip, int reg) +static inline u8 +snd_azf3328_io2_inb(const azf3328_t *chip, int reg) { return inb(chip->io2_port + reg); } -static void snd_azf3328_mixer_write(azf3328_t *chip, int reg, unsigned long value, int type) +static inline void +snd_azf3328_mixer_outw(const azf3328_t *chip, int reg, u16 value) { - switch(type) { - case WORD_VALUE: - outw(value, chip->mixer_port + reg); - break; - case DWORD_VALUE: - outl(value, chip->mixer_port + reg); - break; - case BYTE_VALUE: - outb(value, chip->mixer_port + reg); - break; - } + outw(value, chip->mixer_port + reg); +} + +static inline u16 +snd_azf3328_mixer_inw(const azf3328_t *chip, int reg) +{ + return inw(chip->mixer_port + reg); } -static void snd_azf3328_mixer_set_mute(azf3328_t *chip, int reg, int do_mute) +static void +snd_azf3328_mixer_set_mute(const azf3328_t *chip, int reg, int do_mute) { + unsigned long portbase = chip->mixer_port + reg + 1; unsigned char oldval; /* the mute bit is on the *second* (i.e. right) register of a * left/right channel setting */ - oldval = inb(chip->mixer_port + reg + 1); + oldval = inb(portbase); if (do_mute) oldval |= 0x80; else oldval &= ~0x80; - outb(oldval, chip->mixer_port + reg + 1); + outb(oldval, portbase); } -static void snd_azf3328_mixer_write_volume_gradually(azf3328_t *chip, int reg, unsigned char dst_vol_left, unsigned char dst_vol_right, int chan_sel, int delay) +static void +snd_azf3328_mixer_write_volume_gradually(const azf3328_t *chip, int reg, unsigned char dst_vol_left, unsigned char dst_vol_right, int chan_sel, int delay) { + unsigned long portbase = chip->mixer_port + reg; unsigned char curr_vol_left = 0, curr_vol_right = 0; int left_done = 0, right_done = 0; snd_azf3328_dbgcallenter(); if (chan_sel & SET_CHAN_LEFT) - curr_vol_left = inb(chip->mixer_port + reg + 1); + curr_vol_left = inb(portbase + 1); else left_done = 1; if (chan_sel & SET_CHAN_RIGHT) - curr_vol_right = inb(chip->mixer_port + reg + 0); + curr_vol_right = inb(portbase + 0); else right_done = 1; @@ -284,7 +327,7 @@ static void snd_azf3328_mixer_write_volume_gradually(azf3328_t *chip, int reg, u curr_vol_left++; else left_done = 1; - outb(curr_vol_left, chip->mixer_port + reg + 1); + outb(curr_vol_left, portbase + 1); } if (!right_done) { @@ -298,7 +341,7 @@ static void snd_azf3328_mixer_write_volume_gradually(azf3328_t *chip, int reg, u /* during volume change, the right channel is crackling * somewhat more than the left channel, unfortunately. * This seems to be a hardware issue. */ - outb(curr_vol_right, chip->mixer_port + reg + 0); + outb(curr_vol_right, portbase + 0); } if (delay) mdelay(delay); @@ -320,7 +363,11 @@ typedef struct azf3328_mixer_reg { } azf3328_mixer_reg_t; #define COMPOSE_MIXER_REG(reg,lchan_shift,rchan_shift,mask,invert,stereo,enum_c) \ - ((reg) | (lchan_shift << 8) | (rchan_shift << 12) | (mask << 16) | (invert << 24) | (stereo << 25) | (enum_c << 26)) + ((reg) | (lchan_shift << 8) | (rchan_shift << 12) | \ + (mask << 16) | \ + (invert << 24) | \ + (stereo << 25) | \ + (enum_c << 26)) static void snd_azf3328_mixer_reg_decode(azf3328_mixer_reg_t *r, unsigned long val) { @@ -372,13 +419,15 @@ static void snd_azf3328_mixer_reg_decode(azf3328_mixer_reg_t *r, unsigned long v .private_value = COMPOSE_MIXER_REG(reg, shift, 0, 0, 0, 0, enum_c), \ } -static int snd_azf3328_info_mixer(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +static int +snd_azf3328_info_mixer(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { azf3328_mixer_reg_t reg; snd_azf3328_dbgcallenter(); snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); - uinfo->type = reg.mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->type = reg.mask == 1 ? + SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = reg.stereo + 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = reg.mask; @@ -386,7 +435,8 @@ static int snd_azf3328_info_mixer(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t return 0; } -static int snd_azf3328_get_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int +snd_azf3328_get_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { azf3328_t *chip = snd_kcontrol_chip(kcontrol); azf3328_mixer_reg_t reg; @@ -395,7 +445,7 @@ static int snd_azf3328_get_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t snd_azf3328_dbgcallenter(); snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); - oreg = inw(chip->mixer_port + reg.reg); + oreg = snd_azf3328_mixer_inw(chip, reg.reg); val = (oreg >> reg.lchan_shift) & reg.mask; if (reg.invert) val = reg.mask - val; @@ -406,12 +456,17 @@ static int snd_azf3328_get_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t val = reg.mask - val; ucontrol->value.integer.value[1] = val; } - snd_azf3328_dbgmixer("get: %02x is %04x -> vol %02lx|%02lx (shift %02d|%02d, mask %02x, inv. %d, stereo %d)\n", reg.reg, oreg, ucontrol->value.integer.value[0], ucontrol->value.integer.value[1], reg.lchan_shift, reg.rchan_shift, reg.mask, reg.invert, reg.stereo); + snd_azf3328_dbgmixer("get: %02x is %04x -> vol %02lx|%02lx " + "(shift %02d|%02d, mask %02x, inv. %d, stereo %d)\n", + reg.reg, oreg, + ucontrol->value.integer.value[0], ucontrol->value.integer.value[1], + reg.lchan_shift, reg.rchan_shift, reg.mask, reg.invert, reg.stereo); snd_azf3328_dbgcallleave(); return 0; } -static int snd_azf3328_put_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int +snd_azf3328_put_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { azf3328_t *chip = snd_kcontrol_chip(kcontrol); azf3328_mixer_reg_t reg; @@ -419,7 +474,7 @@ static int snd_azf3328_put_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t snd_azf3328_dbgcallenter(); snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); - oreg = inw(chip->mixer_port + reg.reg); + oreg = snd_azf3328_mixer_inw(chip, reg.reg); val = ucontrol->value.integer.value[0] & reg.mask; if (reg.invert) val = reg.mask - val; @@ -433,24 +488,37 @@ static int snd_azf3328_put_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t nreg |= (val << reg.rchan_shift); } if (reg.mask >= 0x07) /* it's a volume control, so better take care */ - snd_azf3328_mixer_write_volume_gradually(chip, reg.reg, nreg >> 8, nreg & 0xff, SET_CHAN_LEFT|SET_CHAN_RIGHT, 0); /* just set both channels, doesn't matter */ + snd_azf3328_mixer_write_volume_gradually( + chip, reg.reg, nreg >> 8, nreg & 0xff, + /* just set both channels, doesn't matter */ + SET_CHAN_LEFT|SET_CHAN_RIGHT, + 0); else - outw(nreg, chip->mixer_port + reg.reg); + snd_azf3328_mixer_outw(chip, reg.reg, nreg); - snd_azf3328_dbgmixer("put: %02x to %02lx|%02lx, oreg %04x; shift %02d|%02d -> nreg %04x; after: %04x\n", reg.reg, ucontrol->value.integer.value[0], ucontrol->value.integer.value[1], oreg, reg.lchan_shift, reg.rchan_shift, nreg, inw(chip->mixer_port + reg.reg)); + snd_azf3328_dbgmixer("put: %02x to %02lx|%02lx, " + "oreg %04x; shift %02d|%02d -> nreg %04x; after: %04x\n", + reg.reg, ucontrol->value.integer.value[0], ucontrol->value.integer.value[1], + oreg, reg.lchan_shift, reg.rchan_shift, + nreg, snd_azf3328_mixer_inw(chip, reg.reg)); snd_azf3328_dbgcallleave(); return (nreg != oreg); } -static int snd_azf3328_info_mixer_enum(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +static int +snd_azf3328_info_mixer_enum(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { - azf3328_mixer_reg_t reg; - static char *texts1[2] = { "ModemOut1", "ModemOut2" }; - static char *texts2[2] = { "MonoSelectSource1", "MonoSelectSource2" }; - static char *texts3[8] = { - "Mic", "CD", "Video", "Aux", "Line", - "Mix", "Mix Mono", "Phone" + static const char * const texts1[] = { + "ModemOut1", "ModemOut2" + }; + static const char * const texts2[] = { + "MonoSelectSource1", "MonoSelectSource2" + }; + static const char * const texts3[] = { + "Mic", "CD", "Video", "Aux", + "Line", "Mix", "Mix Mono", "Phone" }; + azf3328_mixer_reg_t reg; snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; @@ -471,14 +539,15 @@ static int snd_azf3328_info_mixer_enum(snd_kcontrol_t *kcontrol, snd_ctl_elem_in return 0; } -static int snd_azf3328_get_mixer_enum(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int +snd_azf3328_get_mixer_enum(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - azf3328_mixer_reg_t reg; azf3328_t *chip = snd_kcontrol_chip(kcontrol); + azf3328_mixer_reg_t reg; unsigned short val; snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); - val = inw(chip->mixer_port + reg.reg); + val = snd_azf3328_mixer_inw(chip, reg.reg); if (reg.reg == IDX_MIXER_REC_SELECT) { ucontrol->value.enumerated.item[0] = (val >> 8) & (reg.enum_c - 1); @@ -486,18 +555,22 @@ static int snd_azf3328_get_mixer_enum(snd_kcontrol_t * kcontrol, snd_ctl_elem_va } else ucontrol->value.enumerated.item[0] = (val >> reg.lchan_shift) & (reg.enum_c - 1); - snd_azf3328_dbgmixer("get_enum: %02x is %04x -> %d|%d (shift %02d, enum_c %d)\n", reg.reg, val, ucontrol->value.enumerated.item[0], ucontrol->value.enumerated.item[1], reg.lchan_shift, reg.enum_c); + + snd_azf3328_dbgmixer("get_enum: %02x is %04x -> %d|%d (shift %02d, enum_c %d)\n", + reg.reg, val, ucontrol->value.enumerated.item[0], ucontrol->value.enumerated.item[1], + reg.lchan_shift, reg.enum_c); return 0; } -static int snd_azf3328_put_mixer_enum(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int +snd_azf3328_put_mixer_enum(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - azf3328_mixer_reg_t reg; azf3328_t *chip = snd_kcontrol_chip(kcontrol); + azf3328_mixer_reg_t reg; unsigned int oreg, nreg, val; snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); - oreg = inw(chip->mixer_port + reg.reg); + oreg = snd_azf3328_mixer_inw(chip, reg.reg); val = oreg; if (reg.reg == IDX_MIXER_REC_SELECT) { @@ -514,19 +587,19 @@ static int snd_azf3328_put_mixer_enum(snd_kcontrol_t * kcontrol, snd_ctl_elem_va val &= ~((reg.enum_c - 1) << reg.lchan_shift); val |= (ucontrol->value.enumerated.item[0] << reg.lchan_shift); } - outw(val, chip->mixer_port + reg.reg); + snd_azf3328_mixer_outw(chip, reg.reg, val); nreg = val; snd_azf3328_dbgmixer("put_enum: %02x to %04x, oreg %04x\n", reg.reg, val, oreg); return (nreg != oreg); } -static snd_kcontrol_new_t snd_azf3328_mixer_controls[] __devinitdata = { +static const snd_kcontrol_new_t snd_azf3328_mixer_controls[] __devinitdata = { AZF3328_MIXER_SWITCH("Master Playback Switch", IDX_MIXER_PLAY_MASTER, 15, 1), AZF3328_MIXER_VOL_STEREO("Master Playback Volume", IDX_MIXER_PLAY_MASTER, 0x1f, 1), AZF3328_MIXER_SWITCH("Wave Playback Switch", IDX_MIXER_WAVEOUT, 15, 1), AZF3328_MIXER_VOL_STEREO("Wave Playback Volume", IDX_MIXER_WAVEOUT, 0x1f, 1), - AZF3328_MIXER_SWITCH("Wave Playback 3D Bypass", IDX_MIXER_ADVCTL2, 7, 1), + AZF3328_MIXER_SWITCH("Wave 3D Bypass Playback Switch", IDX_MIXER_ADVCTL2, 7, 1), AZF3328_MIXER_SWITCH("FM Playback Switch", IDX_MIXER_FMSYNTH, 15, 1), AZF3328_MIXER_VOL_STEREO("FM Playback Volume", IDX_MIXER_FMSYNTH, 0x1f, 1), AZF3328_MIXER_SWITCH("CD Playback Switch", IDX_MIXER_CDAUDIO, 15, 1), @@ -539,8 +612,8 @@ static snd_kcontrol_new_t snd_azf3328_mixer_controls[] __devinitdata = { AZF3328_MIXER_SWITCH("Mic Boost (+20dB)", IDX_MIXER_MIC, 6, 0), AZF3328_MIXER_SWITCH("Line Playback Switch", IDX_MIXER_LINEIN, 15, 1), AZF3328_MIXER_VOL_STEREO("Line Playback Volume", IDX_MIXER_LINEIN, 0x1f, 1), - AZF3328_MIXER_SWITCH("PCBeep Playback Switch", IDX_MIXER_PCBEEP, 15, 1), - AZF3328_MIXER_VOL_SPECIAL("PCBeep Playback Volume", IDX_MIXER_PCBEEP, 0x0f, 1, 1), + AZF3328_MIXER_SWITCH("PC Speaker Playback Switch", IDX_MIXER_PCBEEP, 15, 1), + AZF3328_MIXER_VOL_SPECIAL("PC Speaker Playback Volume", IDX_MIXER_PCBEEP, 0x0f, 1, 1), AZF3328_MIXER_SWITCH("Video Playback Switch", IDX_MIXER_VIDEO, 15, 1), AZF3328_MIXER_VOL_STEREO("Video Playback Volume", IDX_MIXER_VIDEO, 0x1f, 1), AZF3328_MIXER_SWITCH("Aux Playback Switch", IDX_MIXER_AUX, 15, 1), @@ -553,8 +626,8 @@ static snd_kcontrol_new_t snd_azf3328_mixer_controls[] __devinitdata = { AZF3328_MIXER_ENUM("Mono Select Source", IDX_MIXER_ADVCTL2, 2, 9), AZF3328_MIXER_VOL_SPECIAL("Tone Control - Treble", IDX_MIXER_BASSTREBLE, 0x07, 1, 0), AZF3328_MIXER_VOL_SPECIAL("Tone Control - Bass", IDX_MIXER_BASSTREBLE, 0x07, 9, 0), - AZF3328_MIXER_SWITCH("3D Control - Toggle", IDX_MIXER_ADVCTL2, 13, 0), - AZF3328_MIXER_VOL_SPECIAL("3D Control - Volume", IDX_MIXER_ADVCTL1, 0x07, 1, 0), /* "3D Width" */ + AZF3328_MIXER_SWITCH("3D Control - Switch", IDX_MIXER_ADVCTL2, 13, 0), + AZF3328_MIXER_VOL_SPECIAL("3D Control - Wide", IDX_MIXER_ADVCTL1, 0x07, 1, 0), /* "3D Width" */ AZF3328_MIXER_VOL_SPECIAL("3D Control - Space", IDX_MIXER_ADVCTL1, 0x03, 8, 0), /* "Hifi 3D" */ #if MIXER_TESTING AZF3328_MIXER_SWITCH("0", IDX_MIXER_ADVCTL2, 0, 0), @@ -576,9 +649,7 @@ static snd_kcontrol_new_t snd_azf3328_mixer_controls[] __devinitdata = { #endif }; -#define AZF3328_INIT_VALUES (sizeof(snd_azf3328_init_values)/sizeof(unsigned int)/2) - -static unsigned int snd_azf3328_init_values[][2] = { +static const u16 __devinitdata snd_azf3328_init_values[][2] = { { IDX_MIXER_PLAY_MASTER, MIXER_MUTE_MASK|0x1f1f }, { IDX_MIXER_MODEMOUT, MIXER_MUTE_MASK|0x1f1f }, { IDX_MIXER_BASSTREBLE, 0x0000 }, @@ -594,10 +665,11 @@ static unsigned int snd_azf3328_init_values[][2] = { { IDX_MIXER_REC_VOLUME, MIXER_MUTE_MASK|0x0707 }, }; -static int __devinit snd_azf3328_mixer_new(azf3328_t *chip) +static int __devinit +snd_azf3328_mixer_new(azf3328_t *chip) { snd_card_t *card; - snd_kcontrol_new_t *sw; + const snd_kcontrol_new_t *sw; unsigned int idx; int err; @@ -607,11 +679,13 @@ static int __devinit snd_azf3328_mixer_new(azf3328_t *chip) card = chip->card; /* mixer reset */ - snd_azf3328_mixer_write(chip, IDX_MIXER_RESET, 0x0, WORD_VALUE); + snd_azf3328_mixer_outw(chip, IDX_MIXER_RESET, 0x0000); /* mute and zero volume channels */ - for (idx = 0; idx < AZF3328_INIT_VALUES; idx++) { - snd_azf3328_mixer_write(chip, snd_azf3328_init_values[idx][0], snd_azf3328_init_values[idx][1], WORD_VALUE); + for (idx = 0; idx < ARRAY_SIZE(snd_azf3328_init_values); idx++) { + snd_azf3328_mixer_outw(chip, + snd_azf3328_init_values[idx][0], + snd_azf3328_init_values[idx][1]); } /* add mixer controls */ @@ -627,7 +701,8 @@ static int __devinit snd_azf3328_mixer_new(azf3328_t *chip) return 0; } -static int snd_azf3328_hw_params(snd_pcm_substream_t * substream, +static int +snd_azf3328_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params) { int res; @@ -637,7 +712,8 @@ static int snd_azf3328_hw_params(snd_pcm_substream_t * substream, return res; } -static int snd_azf3328_hw_free(snd_pcm_substream_t * substream) +static int +snd_azf3328_hw_free(snd_pcm_substream_t * substream) { snd_azf3328_dbgcallenter(); snd_pcm_lib_free_pages(substream); @@ -645,43 +721,48 @@ static int snd_azf3328_hw_free(snd_pcm_substream_t * substream) return 0; } -static void snd_azf3328_setfmt(azf3328_t *chip, +static void +snd_azf3328_setfmt(azf3328_t *chip, unsigned int reg, unsigned int bitrate, unsigned int format_width, unsigned int channels ) { - unsigned int val = 0xff00; + u16 val = 0xff00; unsigned long flags; snd_azf3328_dbgcallenter(); switch (bitrate) { - case 5512: val |= 0x0d; break; /* the AZF3328 names it "5510" for some strange reason */ - case 6620: val |= 0x0b; break; - case 8000: val |= 0x00; break; - case 9600: val |= 0x08; break; - case 11025: val |= 0x01; break; - case 16000: val |= 0x02; break; - case 22050: val |= 0x03; break; - case 32000: val |= 0x04; break; - case 44100: val |= 0x05; break; - case 48000: val |= 0x06; break; - case 64000: val |= 0x07; break; + case 4000: val |= SOUNDFORMAT_FREQ_SUSPECTED_4000; break; + case 4800: val |= SOUNDFORMAT_FREQ_SUSPECTED_4800; break; + case 5512: val |= SOUNDFORMAT_FREQ_5510; break; /* the AZF3328 names it "5510" for some strange reason */ + case 6620: val |= SOUNDFORMAT_FREQ_6620; break; + case 8000: val |= SOUNDFORMAT_FREQ_8000; break; + case 9600: val |= SOUNDFORMAT_FREQ_9600; break; + case 11025: val |= SOUNDFORMAT_FREQ_11025; break; + case 13240: val |= SOUNDFORMAT_FREQ_SUSPECTED_13240; break; + case 16000: val |= SOUNDFORMAT_FREQ_16000; break; + case 22050: val |= SOUNDFORMAT_FREQ_22050; break; + case 32000: val |= SOUNDFORMAT_FREQ_32000; break; + case 44100: val |= SOUNDFORMAT_FREQ_44100; break; + case 48000: val |= SOUNDFORMAT_FREQ_48000; break; + case 66200: val |= SOUNDFORMAT_FREQ_SUSPECTED_66200; break; default: - snd_printk("unknown bitrate %d, assuming 44.1kHz!\n", bitrate); - val |= 0x05; /* 44100 */ + snd_printk(KERN_WARNING "unknown bitrate %d, assuming 44.1kHz!\n", bitrate); + val |= SOUNDFORMAT_FREQ_44100; break; } - /* val = 0xff07; 3m27.993s (65301Hz; -> 64000Hz???) */ - /* val = 0xff09; 17m15.098s (13123,478Hz; -> 12000Hz???) */ - /* val = 0xff0a; 47m30.599s (4764,891Hz; -> 4800Hz???) */ - /* val = 0xff0c; 57m0.510s (4010,263Hz; -> 4000Hz???) */ + /* val = 0xff07; 3m27.993s (65301Hz; -> 64000Hz???) hmm, 66120, 65967, 66123 */ + /* val = 0xff09; 17m15.098s (13123,478Hz; -> 12000Hz???) hmm, 13237.2Hz? */ + /* val = 0xff0a; 47m30.599s (4764,891Hz; -> 4800Hz???) yup, 4803Hz */ + /* val = 0xff0c; 57m0.510s (4010,263Hz; -> 4000Hz???) yup, 4003Hz */ /* val = 0xff05; 5m11.556s (... -> 44100Hz) */ /* val = 0xff03; 10m21.529s (21872,463Hz; -> 22050Hz???) */ /* val = 0xff0f; 20m41.883s (10937,993Hz; -> 11025Hz???) */ /* val = 0xff0d; 41m23.135s (5523,600Hz; -> 5512Hz???) */ /* val = 0xff0e; 28m30.777s (8017Hz; -> 8000Hz???) */ + if (channels == 2) val |= SOUNDFORMAT_FLAG_2CHANNELS; @@ -691,7 +772,7 @@ static void snd_azf3328_setfmt(azf3328_t *chip, spin_lock_irqsave(&chip->reg_lock, flags); /* set bitrate/format */ - outw(val, chip->codec_port+reg); + snd_azf3328_codec_outw(chip, reg, val); /* changing the bitrate/format settings switches off the * audio output with an annoying click in case of 8/16bit format change @@ -701,47 +782,67 @@ static void snd_azf3328_setfmt(azf3328_t *chip, * FIXME: does this have some side effects for full-duplex * or other dramatic side effects? */ if (reg == IDX_IO_PLAY_SOUNDFORMAT) /* only do it for playback */ - outw(inw(chip->codec_port + IDX_IO_PLAY_FLAGS)|DMA_PLAY_SOMETHING1|DMA_PLAY_SOMETHING2|SOMETHING_ALMOST_ALWAYS_SET|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE, chip->codec_port + IDX_IO_PLAY_FLAGS); + snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, + snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) | + DMA_PLAY_SOMETHING1 | + DMA_PLAY_SOMETHING2 | + SOMETHING_ALMOST_ALWAYS_SET | + DMA_EPILOGUE_SOMETHING | + DMA_SOMETHING_ELSE + ); spin_unlock_irqrestore(&chip->reg_lock, flags); snd_azf3328_dbgcallleave(); } -static void snd_azf3328_setdmaa(azf3328_t *chip, +static void +snd_azf3328_setdmaa(azf3328_t *chip, long unsigned int addr, unsigned int count, unsigned int size, int do_recording) { - long unsigned int addr1; - long unsigned int addr2; - unsigned int count1; - unsigned int count2; - unsigned long flags; - int reg_offs = do_recording ? 0x20 : 0x00; + unsigned long flags, portbase; + unsigned int is_running; snd_azf3328_dbgcallenter(); + if (do_recording) + { + /* access capture registers, i.e. skip playback reg section */ + portbase = chip->codec_port + 0x20; + is_running = chip->is_recording; + } + else + { + /* access the playback register section */ + portbase = chip->codec_port + 0x00; + is_running = chip->is_playing; + } + /* AZF3328 uses a two buffer pointer DMA playback approach */ - if (!chip->is_playing) + if (!is_running) { - addr1 = addr; - addr2 = addr+(size/2); - count1 = (size/2)-1; - count2 = (size/2)-1; -#if DEBUG_PLAY_REC - snd_azf3328_dbgplay("setting dma: buf1 %08lx[%d], buf2 %08lx[%d]\n", addr1, count1, addr2, count2); -#endif + unsigned long addr_area2; + unsigned long count_areas, count_tmp; /* width 32bit -- overflow!! */ + count_areas = size/2; + addr_area2 = addr+count_areas; + count_areas--; /* max. index */ + snd_azf3328_dbgplay("set DMA: buf1 %08lx[%lu], buf2 %08lx[%lu]\n", addr, count_areas, addr_area2, count_areas); + + /* build combined I/O buffer length word */ + count_tmp = count_areas; + count_areas |= (count_tmp << 16); spin_lock_irqsave(&chip->reg_lock, flags); - outl(addr1, chip->codec_port+reg_offs+IDX_IO_PLAY_DMA_START_1); - outl(addr2, chip->codec_port+reg_offs+IDX_IO_PLAY_DMA_START_2); - outw(count1, chip->codec_port+reg_offs+IDX_IO_PLAY_DMA_LEN_1); - outw(count2, chip->codec_port+reg_offs+IDX_IO_PLAY_DMA_LEN_2); + outl(addr, portbase + IDX_IO_PLAY_DMA_START_1); + outl(addr_area2, portbase + IDX_IO_PLAY_DMA_START_2); + outl(count_areas, portbase + IDX_IO_PLAY_DMA_LEN_1); spin_unlock_irqrestore(&chip->reg_lock, flags); } snd_azf3328_dbgcallleave(); } -static int snd_azf3328_playback_prepare(snd_pcm_substream_t *substream) +static int +snd_azf3328_playback_prepare(snd_pcm_substream_t *substream) { #if 0 azf3328_t *chip = snd_pcm_substream_chip(substream); @@ -752,14 +853,18 @@ static int snd_azf3328_playback_prepare(snd_pcm_substream_t *substream) snd_azf3328_dbgcallenter(); #if 0 - snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, runtime->rate, snd_pcm_format_width(runtime->format), runtime->channels); + snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, + runtime->rate, + snd_pcm_format_width(runtime->format), + runtime->channels); snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, 0); #endif snd_azf3328_dbgcallleave(); return 0; } -static int snd_azf3328_capture_prepare(snd_pcm_substream_t * substream) +static int +snd_azf3328_capture_prepare(snd_pcm_substream_t * substream) { #if 0 azf3328_t *chip = snd_pcm_substream_chip(substream); @@ -770,14 +875,18 @@ static int snd_azf3328_capture_prepare(snd_pcm_substream_t * substream) snd_azf3328_dbgcallenter(); #if 0 - snd_azf3328_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, runtime->rate, snd_pcm_format_width(runtime->format), runtime->channels); + snd_azf3328_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, + runtime->rate, + snd_pcm_format_width(runtime->format), + runtime->channels); snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, 1); #endif snd_azf3328_dbgcallleave(); return 0; } -static int snd_azf3328_playback_trigger(snd_pcm_substream_t * substream, int cmd) +static int +snd_azf3328_playback_trigger(snd_pcm_substream_t * substream, int cmd) { azf3328_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; @@ -785,79 +894,98 @@ static int snd_azf3328_playback_trigger(snd_pcm_substream_t * substream, int cmd unsigned int status1; snd_azf3328_dbgcalls("snd_azf3328_playback_trigger cmd %d\n", cmd); + switch (cmd) { case SNDRV_PCM_TRIGGER_START: - - snd_azf3328_dbgio(chip, "trigger1"); + snd_azf3328_dbgplay("START PLAYBACK\n"); /* mute WaveOut */ snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); - snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, runtime->rate, snd_pcm_format_width(runtime->format), runtime->channels); + snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, + runtime->rate, + snd_pcm_format_width(runtime->format), + runtime->channels); spin_lock(&chip->reg_lock); /* stop playback */ - status1 = inw(chip->codec_port+IDX_IO_PLAY_FLAGS); + status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS); status1 &= ~DMA_RESUME; - outw(status1, chip->codec_port+IDX_IO_PLAY_FLAGS); + snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); /* FIXME: clear interrupts or what??? */ - outw(0xffff, chip->codec_port+IDX_IO_PLAY_IRQMASK); + snd_azf3328_codec_outw(chip, IDX_IO_PLAY_IRQTYPE, 0xffff); spin_unlock(&chip->reg_lock); - snd_azf3328_setdmaa(chip, runtime->dma_addr, snd_pcm_lib_period_bytes(substream), snd_pcm_lib_buffer_bytes(substream), 0); + snd_azf3328_setdmaa(chip, runtime->dma_addr, + snd_pcm_lib_period_bytes(substream), + snd_pcm_lib_buffer_bytes(substream), + 0); spin_lock(&chip->reg_lock); #ifdef WIN9X /* FIXME: enable playback/recording??? */ status1 |= DMA_PLAY_SOMETHING1 | DMA_PLAY_SOMETHING2; - outw(status1, chip->codec_port+IDX_IO_PLAY_FLAGS); + snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); /* start playback again */ /* FIXME: what is this value (0x0010)??? */ status1 |= DMA_RESUME | DMA_EPILOGUE_SOMETHING; - outw(status1, chip->codec_port+IDX_IO_PLAY_FLAGS); + snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); #else /* NT4 */ - outw(0x00, chip->codec_port+IDX_IO_PLAY_FLAGS); - outw(DMA_PLAY_SOMETHING1, chip->codec_port+IDX_IO_PLAY_FLAGS); - outw(DMA_PLAY_SOMETHING1|DMA_PLAY_SOMETHING2, chip->codec_port+IDX_IO_PLAY_FLAGS); - outw(DMA_RESUME|SOMETHING_ALMOST_ALWAYS_SET|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE, chip->codec_port+IDX_IO_PLAY_FLAGS); + snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, + 0x0000); + snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, + DMA_PLAY_SOMETHING1); + snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, + DMA_PLAY_SOMETHING1 | + DMA_PLAY_SOMETHING2); + snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, + DMA_RESUME | + SOMETHING_ALMOST_ALWAYS_SET | + DMA_EPILOGUE_SOMETHING | + DMA_SOMETHING_ELSE); #endif spin_unlock(&chip->reg_lock); /* now unmute WaveOut */ snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); - snd_azf3328_dbgio(chip, "trigger2"); chip->is_playing = 1; + snd_azf3328_dbgplay("STARTED PLAYBACK\n"); break; - case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_STOP: + snd_azf3328_dbgplay("STOP PLAYBACK\n"); + /* mute WaveOut */ snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); spin_lock(&chip->reg_lock); /* stop playback */ - status1 = inw(chip->codec_port+IDX_IO_PLAY_FLAGS); + status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS); status1 &= ~DMA_RESUME; - outw(status1, chip->codec_port+IDX_IO_PLAY_FLAGS); + snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); + /* hmm, is this really required? we're resetting the same bit + * immediately thereafter... */ status1 |= DMA_PLAY_SOMETHING1; - outw(status1, chip->codec_port+IDX_IO_PLAY_FLAGS); + snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); status1 &= ~DMA_PLAY_SOMETHING1; - outw(status1, chip->codec_port+IDX_IO_PLAY_FLAGS); + snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); spin_unlock(&chip->reg_lock); /* now unmute WaveOut */ snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); chip->is_playing = 0; + snd_azf3328_dbgplay("STOPPED PLAYBACK\n"); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - snd_printk("FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); + snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - snd_printk("FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); + snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); break; default: return -EINVAL; @@ -869,7 +997,8 @@ static int snd_azf3328_playback_trigger(snd_pcm_substream_t * substream, int cmd /* this is just analogous to playback; I'm not quite sure whether recording * should actually be triggered like that */ -static int snd_azf3328_capture_trigger(snd_pcm_substream_t * substream, int cmd) +static int +snd_azf3328_capture_trigger(snd_pcm_substream_t * substream, int cmd) { azf3328_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; @@ -877,68 +1006,86 @@ static int snd_azf3328_capture_trigger(snd_pcm_substream_t * substream, int cmd) unsigned int status1; snd_azf3328_dbgcalls("snd_azf3328_capture_trigger cmd %d\n", cmd); + switch (cmd) { case SNDRV_PCM_TRIGGER_START: - snd_azf3328_dbgio(chip, "trigger1"); + snd_azf3328_dbgplay("START CAPTURE\n"); - snd_azf3328_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, runtime->rate, snd_pcm_format_width(runtime->format), runtime->channels); + snd_azf3328_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, + runtime->rate, + snd_pcm_format_width(runtime->format), + runtime->channels); spin_lock(&chip->reg_lock); /* stop recording */ - status1 = inw(chip->codec_port+IDX_IO_REC_FLAGS); + status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS); status1 &= ~DMA_RESUME; - outw(status1, chip->codec_port+IDX_IO_REC_FLAGS); + snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); /* FIXME: clear interrupts or what??? */ - outw(0xffff, chip->codec_port+IDX_IO_REC_IRQMASK); + snd_azf3328_codec_outw(chip, IDX_IO_REC_IRQTYPE, 0xffff); spin_unlock(&chip->reg_lock); - snd_azf3328_setdmaa(chip, runtime->dma_addr, snd_pcm_lib_period_bytes(substream), snd_pcm_lib_buffer_bytes(substream), 1); + snd_azf3328_setdmaa(chip, runtime->dma_addr, + snd_pcm_lib_period_bytes(substream), + snd_pcm_lib_buffer_bytes(substream), + 1); spin_lock(&chip->reg_lock); #ifdef WIN9X /* FIXME: enable playback/recording??? */ status1 |= DMA_PLAY_SOMETHING1 | DMA_PLAY_SOMETHING2; - outw(status1, chip->codec_port+IDX_IO_REC_FLAGS); + snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); - /* start playback again */ + /* start capture again */ /* FIXME: what is this value (0x0010)??? */ status1 |= DMA_RESUME | DMA_EPILOGUE_SOMETHING; - outw(status1, chip->codec_port+IDX_IO_REC_FLAGS); + snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); #else - outw(0x00, chip->codec_port+IDX_IO_REC_FLAGS); - outw(DMA_PLAY_SOMETHING1, chip->codec_port+IDX_IO_REC_FLAGS); - outw(DMA_PLAY_SOMETHING1|DMA_PLAY_SOMETHING2, chip->codec_port+IDX_IO_REC_FLAGS); - outw(DMA_RESUME|SOMETHING_ALMOST_ALWAYS_SET|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE, chip->codec_port+IDX_IO_REC_FLAGS); + snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, + 0x0000); + snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, + DMA_PLAY_SOMETHING1); + snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, + DMA_PLAY_SOMETHING1 | + DMA_PLAY_SOMETHING2); + snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, + DMA_RESUME | + SOMETHING_ALMOST_ALWAYS_SET | + DMA_EPILOGUE_SOMETHING | + DMA_SOMETHING_ELSE); #endif spin_unlock(&chip->reg_lock); - snd_azf3328_dbgio(chip, "trigger2"); - chip->is_playing = 1; + chip->is_recording = 1; + snd_azf3328_dbgplay("STARTED CAPTURE\n"); break; case SNDRV_PCM_TRIGGER_STOP: + snd_azf3328_dbgplay("STOP CAPTURE\n"); + spin_lock(&chip->reg_lock); /* stop recording */ - status1 = inw(chip->codec_port+IDX_IO_REC_FLAGS); + status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS); status1 &= ~DMA_RESUME; - outw(status1, chip->codec_port+IDX_IO_REC_FLAGS); + snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); status1 |= DMA_PLAY_SOMETHING1; - outw(status1, chip->codec_port+IDX_IO_REC_FLAGS); + snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); status1 &= ~DMA_PLAY_SOMETHING1; - outw(status1, chip->codec_port+IDX_IO_REC_FLAGS); + snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); spin_unlock(&chip->reg_lock); - chip->is_playing = 0; + chip->is_recording = 0; + snd_azf3328_dbgplay("STOPPED CAPTURE\n"); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - snd_printk("FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); + snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - snd_printk("FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); + snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); break; default: return -EINVAL; @@ -948,11 +1095,11 @@ static int snd_azf3328_capture_trigger(snd_pcm_substream_t * substream, int cmd) return result; } -static snd_pcm_uframes_t snd_azf3328_playback_pointer(snd_pcm_substream_t * substream) +static snd_pcm_uframes_t +snd_azf3328_playback_pointer(snd_pcm_substream_t * substream) { azf3328_t *chip = snd_pcm_substream_chip(substream); - unsigned long bufptr, playptr; - unsigned long result; + unsigned long bufptr, result; snd_pcm_uframes_t frmres; #ifdef QUERY_HARDWARE @@ -960,19 +1107,20 @@ static snd_pcm_uframes_t snd_azf3328_playback_pointer(snd_pcm_substream_t * subs #else bufptr = substream->runtime->dma_addr; #endif - playptr = inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS); + result = inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS); - result = playptr - bufptr; - frmres = bytes_to_frames( substream->runtime, result ); - snd_azf3328_dbgplay("result %lx, playptr %lx (base %x), frames %ld\n", result, playptr, substream->runtime->dma_addr, frmres); + /* calculate offset */ + result -= bufptr; + frmres = bytes_to_frames( substream->runtime, result); + snd_azf3328_dbgplay("PLAY @ 0x%8lx, frames %8ld\n", result, frmres); return frmres; } -static snd_pcm_uframes_t snd_azf3328_capture_pointer(snd_pcm_substream_t * substream) +static snd_pcm_uframes_t +snd_azf3328_capture_pointer(snd_pcm_substream_t * substream) { azf3328_t *chip = snd_pcm_substream_chip(substream); - unsigned long bufptr, recptr; - unsigned long result; + unsigned long bufptr, result; snd_pcm_uframes_t frmres; #ifdef QUERY_HARDWARE @@ -980,96 +1128,116 @@ static snd_pcm_uframes_t snd_azf3328_capture_pointer(snd_pcm_substream_t * subst #else bufptr = substream->runtime->dma_addr; #endif - recptr = inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS); + result = inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS); - result = recptr - bufptr; - frmres = bytes_to_frames( substream->runtime, result ); - snd_azf3328_dbgplay("result %lx, rec ptr %lx (base %x), frames %ld\n", result, recptr, substream->runtime->dma_addr, frmres); + /* calculate offset */ + result -= bufptr; + frmres = bytes_to_frames( substream->runtime, result); + snd_azf3328_dbgplay("REC @ 0x%8lx, frames %8ld\n", result, frmres); return frmres; } -static irqreturn_t snd_azf3328_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t +snd_azf3328_interrupt(int irq, void *dev_id, struct pt_regs *regs) { azf3328_t *chip = dev_id; - unsigned int status, which; - static unsigned long count; + u8 status, which; + static unsigned long irq_count; - status = inw(chip->codec_port+IDX_IO_IRQSTATUS); + status = snd_azf3328_codec_inb(chip, IDX_IO_IRQSTATUS); /* fast path out, to ease interrupt sharing */ - if (!(status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_MPU401|IRQ_SOMEIRQ))) + if (!(status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_MPU401|IRQ_TIMER))) return IRQ_NONE; /* must be interrupt for another device */ - snd_azf3328_dbgplay("Interrupt %ld!\nIDX_IO_PLAY_FLAGS %04x, IDX_IO_PLAY_IRQMASK %04x, IDX_IO_IRQSTATUS %04x\n", count, inw(chip->codec_port+IDX_IO_PLAY_FLAGS), inw(chip->codec_port+IDX_IO_PLAY_IRQMASK), inw(chip->codec_port+IDX_IO_IRQSTATUS)); + snd_azf3328_dbgplay("Interrupt %ld!\nIDX_IO_PLAY_FLAGS %04x, IDX_IO_PLAY_IRQTYPE %04x, IDX_IO_IRQSTATUS %04x\n", + irq_count, + snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS), + snd_azf3328_codec_inw(chip, IDX_IO_PLAY_IRQTYPE), + status); + if (status & IRQ_TIMER) + { + /* snd_azf3328_dbgplay("timer %ld\n", inl(chip->codec_port+IDX_IO_TIMER_VALUE) & TIMER_VALUE_MASK); */ + if (chip->timer) + snd_timer_interrupt(chip->timer, chip->timer->sticks); + /* ACK timer */ + spin_lock(&chip->reg_lock); + snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x07); + spin_unlock(&chip->reg_lock); + snd_azf3328_dbgplay("azt3328: timer IRQ\n"); + } if (status & IRQ_PLAYBACK) { spin_lock(&chip->reg_lock); - which = inw(chip->codec_port+IDX_IO_PLAY_IRQMASK); - if (which & IRQ_FINISHED_PLAYBUF_1) - /* ack IRQ */ - outw(which | IRQ_FINISHED_PLAYBUF_1, chip->codec_port+IDX_IO_PLAY_IRQMASK); - if (which & IRQ_FINISHED_PLAYBUF_2) - /* ack IRQ */ - outw(which | IRQ_FINISHED_PLAYBUF_2, chip->codec_port+IDX_IO_PLAY_IRQMASK); - if (which & IRQ_PLAY_SOMETHING) - { - snd_azf3328_dbgplay("azt3328: unknown play IRQ type occurred, please report!\n"); - } + which = snd_azf3328_codec_inb(chip, IDX_IO_PLAY_IRQTYPE); + /* ack all IRQ types immediately */ + snd_azf3328_codec_outb(chip, IDX_IO_PLAY_IRQTYPE, which); + spin_unlock(&chip->reg_lock); + if (chip->pcm && chip->playback_substream) { - snd_azf3328_dbgplay("which %x, playptr %lx\n", which, inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS)); snd_pcm_period_elapsed(chip->playback_substream); - snd_azf3328_dbgplay("period done, playptr %lx.\n", inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS)); + snd_azf3328_dbgplay("PLAY period done (#%x), @ %x\n", + which, + inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS)); } else snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n"); - spin_unlock(&chip->reg_lock); + if (which & IRQ_PLAY_SOMETHING) + snd_azf3328_dbgplay("azt3328: unknown play IRQ type occurred, please report!\n"); } if (status & IRQ_RECORDING) { spin_lock(&chip->reg_lock); - which = inw(chip->codec_port+IDX_IO_REC_IRQMASK); - if (which & IRQ_FINISHED_RECBUF_1) - /* ack interrupt */ - outw(which | IRQ_FINISHED_RECBUF_1, chip->codec_port+IDX_IO_REC_IRQMASK); - if (which & IRQ_FINISHED_RECBUF_2) - /* ack interrupt */ - outw(which | IRQ_FINISHED_RECBUF_2, chip->codec_port+IDX_IO_REC_IRQMASK); - if (which & IRQ_REC_SOMETHING) - { - snd_azf3328_dbgplay("azt3328: unknown rec IRQ type occurred, please report!\n"); - } + which = snd_azf3328_codec_inb(chip, IDX_IO_REC_IRQTYPE); + /* ack all IRQ types immediately */ + snd_azf3328_codec_outb(chip, IDX_IO_REC_IRQTYPE, which); + spin_unlock(&chip->reg_lock); + if (chip->pcm && chip->capture_substream) { - snd_azf3328_dbgplay("which %x, recptr %lx\n", which, inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS)); - spin_unlock(&chip->reg_lock); snd_pcm_period_elapsed(chip->capture_substream); - spin_lock(&chip->reg_lock); - snd_azf3328_dbgplay("period done, recptr %lx.\n", inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS)); + snd_azf3328_dbgplay("REC period done (#%x), @ %x\n", + which, + inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS)); } - spin_unlock(&chip->reg_lock); + else + snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n"); + if (which & IRQ_REC_SOMETHING) + snd_azf3328_dbgplay("azt3328: unknown rec IRQ type occurred, please report!\n"); } + /* MPU401 has less critical IRQ requirements + * than timer and playback/recording, right? */ if (status & IRQ_MPU401) + { snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs); - if (status & IRQ_SOMEIRQ) - snd_azf3328_dbgplay("azt3328: unknown IRQ type occurred, please report!\n"); - count++; + + /* hmm, do we have to ack the IRQ here somehow? + * If so, then I don't know how... */ + snd_azf3328_dbgplay("azt3328: MPU401 IRQ\n"); + } + irq_count++; return IRQ_HANDLED; } /*****************************************************************/ -static snd_pcm_hardware_t snd_azf3328_playback = +static const snd_pcm_hardware_t snd_azf3328_playback = { /* FIXME!! Correct? */ - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID), - .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | - SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE, - .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_64000 | SNDRV_PCM_RATE_KNOT, - .rate_min = 5512, - .rate_max = 64000, + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_U16_LE, + .rates = SNDRV_PCM_RATE_5512 | + SNDRV_PCM_RATE_8000_48000 | + SNDRV_PCM_RATE_KNOT, + .rate_min = 4000, + .rate_max = 66200, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 65536, @@ -1083,16 +1251,21 @@ static snd_pcm_hardware_t snd_azf3328_playback = .fifo_size = 0, }; -static snd_pcm_hardware_t snd_azf3328_capture = +static const snd_pcm_hardware_t snd_azf3328_capture = { /* FIXME */ - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID), - .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | - SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE, - .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_64000 | SNDRV_PCM_RATE_KNOT, - .rate_min = 5512, - .rate_max = 64000, + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_S8 | + SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_U16_LE, + .rates = SNDRV_PCM_RATE_5512 | + SNDRV_PCM_RATE_8000_48000 | + SNDRV_PCM_RATE_KNOT, + .rate_min = 4000, + .rate_max = 66200, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 65536, @@ -1105,8 +1278,8 @@ static snd_pcm_hardware_t snd_azf3328_capture = static unsigned int snd_azf3328_fixed_rates[] = { - 5512, 6620, 8000, 9600, 11025, 16000, 22050, 32000, 44100, 48000, 64000 -}; + 4000, 4800, 5512, 6620, 8000, 9600, 11025, 13240, 16000, 22050, 32000, + 44100, 48000, 66200 }; static snd_pcm_hw_constraint_list_t snd_azf3328_hw_constraints_rates = { .count = ARRAY_SIZE(snd_azf3328_fixed_rates), .list = snd_azf3328_fixed_rates, @@ -1115,7 +1288,8 @@ static snd_pcm_hw_constraint_list_t snd_azf3328_hw_constraints_rates = { /*****************************************************************/ -static int snd_azf3328_playback_open(snd_pcm_substream_t * substream) +static int +snd_azf3328_playback_open(snd_pcm_substream_t * substream) { azf3328_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; @@ -1129,7 +1303,8 @@ static int snd_azf3328_playback_open(snd_pcm_substream_t * substream) return 0; } -static int snd_azf3328_capture_open(snd_pcm_substream_t * substream) +static int +snd_azf3328_capture_open(snd_pcm_substream_t * substream) { azf3328_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; @@ -1143,7 +1318,8 @@ static int snd_azf3328_capture_open(snd_pcm_substream_t * substream) return 0; } -static int snd_azf3328_playback_close(snd_pcm_substream_t * substream) +static int +snd_azf3328_playback_close(snd_pcm_substream_t * substream) { azf3328_t *chip = snd_pcm_substream_chip(substream); @@ -1154,7 +1330,8 @@ static int snd_azf3328_playback_close(snd_pcm_substream_t * substream) return 0; } -static int snd_azf3328_capture_close(snd_pcm_substream_t * substream) +static int +snd_azf3328_capture_close(snd_pcm_substream_t * substream) { azf3328_t *chip = snd_pcm_substream_chip(substream); @@ -1188,14 +1365,16 @@ static snd_pcm_ops_t snd_azf3328_capture_ops = { .pointer = snd_azf3328_capture_pointer }; -static void snd_azf3328_pcm_free(snd_pcm_t *pcm) +static void +snd_azf3328_pcm_free(snd_pcm_t *pcm) { azf3328_t *chip = pcm->private_data; chip->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm); } -static int __devinit snd_azf3328_pcm(azf3328_t *chip, int device) +static int __devinit +snd_azf3328_pcm(azf3328_t *chip, int device) { snd_pcm_t *pcm; int err; @@ -1222,7 +1401,8 @@ static int __devinit snd_azf3328_pcm(azf3328_t *chip, int device) /******************************************************************/ #ifdef SUPPORT_JOYSTICK -static int __devinit snd_azf3328_config_joystick(azf3328_t *chip, int dev) +static int __devinit +snd_azf3328_config_joystick(azf3328_t *chip, int dev) { struct gameport *gp; struct resource *r; @@ -1238,8 +1418,7 @@ static int __devinit snd_azf3328_config_joystick(azf3328_t *chip, int dev) chip->gameport = gp = gameport_allocate_port(); if (!gp) { printk(KERN_ERR "azt3328: cannot allocate memory for gameport\n"); - release_resource(r); - kfree_nocheck(r); + release_and_free_resource(r); return -ENOMEM; } @@ -1249,15 +1428,16 @@ static int __devinit snd_azf3328_config_joystick(azf3328_t *chip, int dev) gp->io = 0x200; gameport_set_port_data(gp, r); - snd_azf3328_io2_write(chip, IDX_IO2_LEGACY_ADDR, - snd_azf3328_io2_read(chip, IDX_IO2_LEGACY_ADDR) | LEGACY_JOY); + snd_azf3328_io2_outb(chip, IDX_IO2_LEGACY_ADDR, + snd_azf3328_io2_inb(chip, IDX_IO2_LEGACY_ADDR) | LEGACY_JOY); gameport_register_port(chip->gameport); return 0; } -static void snd_azf3328_free_joystick(azf3328_t *chip) +static void +snd_azf3328_free_joystick(azf3328_t *chip) { if (chip->gameport) { struct resource *r = gameport_get_port_data(chip->gameport); @@ -1265,33 +1445,36 @@ static void snd_azf3328_free_joystick(azf3328_t *chip) gameport_unregister_port(chip->gameport); chip->gameport = NULL; /* disable gameport */ - snd_azf3328_io2_write(chip, IDX_IO2_LEGACY_ADDR, - snd_azf3328_io2_read(chip, IDX_IO2_LEGACY_ADDR) & ~LEGACY_JOY); - release_resource(r); - kfree_nocheck(r); + snd_azf3328_io2_outb(chip, IDX_IO2_LEGACY_ADDR, + snd_azf3328_io2_inb(chip, IDX_IO2_LEGACY_ADDR) & ~LEGACY_JOY); + release_and_free_resource(r); } } #else -static inline int snd_azf3328_config_joystick(azf3328_t *chip, int dev) { return -ENOSYS; } -static inline void snd_azf3328_free_joystick(azf3328_t *chip) { } +static inline int +snd_azf3328_config_joystick(azf3328_t *chip, int dev) { return -ENOSYS; } +static inline void +snd_azf3328_free_joystick(azf3328_t *chip) { } #endif /******************************************************************/ -static int snd_azf3328_free(azf3328_t *chip) +static int +snd_azf3328_free(azf3328_t *chip) { if (chip->irq < 0) goto __end_hw; /* reset (close) mixer */ snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); /* first mute master volume */ - snd_azf3328_mixer_write(chip, IDX_MIXER_RESET, 0x0, WORD_VALUE); + snd_azf3328_mixer_outw(chip, IDX_MIXER_RESET, 0x0000); - /* interrupt setup - mask everything */ - /* FIXME */ + /* interrupt setup - mask everything (FIXME!) */ + /* well, at least we know how to disable the timer IRQ */ + snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x00); synchronize_irq(chip->irq); - __end_hw: +__end_hw: snd_azf3328_free_joystick(chip); if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); @@ -1302,15 +1485,129 @@ static int snd_azf3328_free(azf3328_t *chip) return 0; } -static int snd_azf3328_dev_free(snd_device_t *device) +static int +snd_azf3328_dev_free(snd_device_t *device) { azf3328_t *chip = device->device_data; return snd_azf3328_free(chip); } +/******************************************************************/ + +/*** NOTE: the physical timer resolution actually is 1024000 ticks per second, + *** but announcing those attributes to user-space would make programs + *** configure the timer to a 1 tick value, resulting in an absolutely fatal + *** timer IRQ storm. + *** Thus I chose to announce a down-scaled virtual timer to the outside and + *** calculate real timer countdown values internally. + *** (the scale factor can be set via module parameter "seqtimer_scaling"). + ***/ + +static int +snd_azf3328_timer_start(snd_timer_t *timer) +{ + azf3328_t *chip; + unsigned long flags; + unsigned int delay; + + snd_azf3328_dbgcallenter(); + chip = snd_timer_chip(timer); + delay = ((timer->sticks * seqtimer_scaling) - 1) & TIMER_VALUE_MASK; + if (delay < 49) + { + /* uhoh, that's not good, since user-space won't know about + * this timing tweak + * (we need to do it to avoid a lockup, though) */ + + snd_azf3328_dbgtimer("delay was too low (%d)!\n", delay); + delay = 49; /* minimum time is 49 ticks */ + } + snd_azf3328_dbgtimer("setting timer countdown value %d, add COUNTDOWN|IRQ\n", delay); + delay |= TIMER_ENABLE_COUNTDOWN | TIMER_ENABLE_IRQ; + spin_lock_irqsave(&chip->reg_lock, flags); + snd_azf3328_codec_outl(chip, IDX_IO_TIMER_VALUE, delay); + spin_unlock_irqrestore(&chip->reg_lock, flags); + snd_azf3328_dbgcallleave(); + return 0; +} + +static int +snd_azf3328_timer_stop(snd_timer_t *timer) +{ + azf3328_t *chip; + unsigned long flags; + + snd_azf3328_dbgcallenter(); + chip = snd_timer_chip(timer); + spin_lock_irqsave(&chip->reg_lock, flags); + /* disable timer countdown and interrupt */ + /* FIXME: should we write TIMER_ACK_IRQ here? */ + snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0); + spin_unlock_irqrestore(&chip->reg_lock, flags); + snd_azf3328_dbgcallleave(); + return 0; +} + + +static int +snd_azf3328_timer_precise_resolution(snd_timer_t *timer, + unsigned long *num, unsigned long *den) +{ + snd_azf3328_dbgcallenter(); + *num = 1; + *den = 1024000 / seqtimer_scaling; + snd_azf3328_dbgcallleave(); + return 0; +} + +static struct _snd_timer_hardware snd_azf3328_timer_hw = { + .flags = SNDRV_TIMER_HW_AUTO, + .resolution = 977, /* 1000000/1024000 = 0.9765625us */ + .ticks = 1024000, /* max tick count, defined by the value register; actually it's not 1024000, but 1048576, but we don't care */ + .start = snd_azf3328_timer_start, + .stop = snd_azf3328_timer_stop, + .precise_resolution = snd_azf3328_timer_precise_resolution, +}; + +static int __devinit +snd_azf3328_timer(azf3328_t *chip, int device) +{ + snd_timer_t *timer = NULL; + snd_timer_id_t tid; + int err; + + snd_azf3328_dbgcallenter(); + tid.dev_class = SNDRV_TIMER_CLASS_CARD; + tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; + tid.card = chip->card->number; + tid.device = device; + tid.subdevice = 0; + + snd_azf3328_timer_hw.resolution *= seqtimer_scaling; + snd_azf3328_timer_hw.ticks /= seqtimer_scaling; + if ((err = snd_timer_new(chip->card, "AZF3328", &tid, &timer)) < 0) { + goto out; + } + + strcpy(timer->name, "AZF3328 timer"); + timer->private_data = chip; + timer->hw = snd_azf3328_timer_hw; + + chip->timer = timer; + + err = 0; + +out: + snd_azf3328_dbgcallleave(); + return err; +} + +/******************************************************************/ + #if 0 /* check whether a bit can be modified */ -static void snd_azf3328_test_bit(unsigned int reg, int bit) +static void +snd_azf3328_test_bit(unsigned int reg, int bit) { unsigned char val, valoff, valon; @@ -1328,7 +1625,26 @@ static void snd_azf3328_test_bit(unsigned int reg, int bit) } #endif -static int __devinit snd_azf3328_create(snd_card_t * card, +static void +snd_azf3328_debug_show_ports(const azf3328_t *chip) +{ +#if DEBUG_MISC + u16 tmp; + + snd_azf3328_dbgmisc("codec_port 0x%lx, io2_port 0x%lx, mpu_port 0x%lx, synth_port 0x%lx, mixer_port 0x%lx, irq %d\n", chip->codec_port, chip->io2_port, chip->mpu_port, chip->synth_port, chip->mixer_port, chip->irq); + + snd_azf3328_dbgmisc("io2 %02x %02x %02x %02x %02x %02x\n", snd_azf3328_io2_inb(chip, 0), snd_azf3328_io2_inb(chip, 1), snd_azf3328_io2_inb(chip, 2), snd_azf3328_io2_inb(chip, 3), snd_azf3328_io2_inb(chip, 4), snd_azf3328_io2_inb(chip, 5)); + + for (tmp=0; tmp <= 0x01; tmp += 1) + snd_azf3328_dbgmisc("0x%02x: opl 0x%04x, mpu300 0x%04x, mpu310 0x%04x, mpu320 0x%04x, mpu330 0x%04x\n", tmp, inb(0x388 + tmp), inb(0x300 + tmp), inb(0x310 + tmp), inb(0x320 + tmp), inb(0x330 + tmp)); + + for (tmp = 0; tmp <= 0x6E; tmp += 2) + snd_azf3328_dbgmisc("0x%02x: 0x%04x\n", tmp, snd_azf3328_codec_inb(chip, tmp)); +#endif +} + +static int __devinit +snd_azf3328_create(snd_card_t * card, struct pci_dev *pci, unsigned long device_type, azf3328_t ** rchip) @@ -1347,8 +1663,8 @@ static int __devinit snd_azf3328_create(snd_card_t * card, chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { - pci_disable_device(pci); - return -ENOMEM; + err = -ENOMEM; + goto out_err; } spin_lock_init(&chip->reg_lock); chip->card = card; @@ -1358,47 +1674,39 @@ static int __devinit snd_azf3328_create(snd_card_t * card, /* check if we can restrict PCI DMA transfers to 24 bits */ if (pci_set_dma_mask(pci, 0x00ffffff) < 0 || pci_set_consistent_dma_mask(pci, 0x00ffffff) < 0) { - snd_printk("architecture does not support 24bit PCI busmaster DMA\n"); - pci_disable_device(pci); - return -ENXIO; + snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n"); + err = -ENXIO; + goto out_err; } if ((err = pci_request_regions(pci, "Aztech AZF3328")) < 0) { - kfree(chip); - pci_disable_device(pci); - return err; + goto out_err; } chip->codec_port = pci_resource_start(pci, 0); - chip->io2_port = pci_resource_start(pci, 1); - chip->mpu_port = pci_resource_start(pci, 2); + chip->io2_port = pci_resource_start(pci, 1); + chip->mpu_port = pci_resource_start(pci, 2); chip->synth_port = pci_resource_start(pci, 3); chip->mixer_port = pci_resource_start(pci, 4); if (request_irq(pci->irq, snd_azf3328_interrupt, SA_INTERRUPT|SA_SHIRQ, card->shortname, (void *)chip)) { - snd_printk("unable to grab IRQ %d\n", pci->irq); - snd_azf3328_free(chip); - return -EBUSY; + snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + err = -EBUSY; + goto out_err; } chip->irq = pci->irq; pci_set_master(pci); synchronize_irq(chip->irq); - snd_azf3328_dbgmisc("codec_port 0x%lx, io2_port 0x%lx, mpu_port 0x%lx, synth_port 0x%lx, mixer_port 0x%lx, irq %d\n", chip->codec_port, chip->io2_port, chip->mpu_port, chip->synth_port, chip->mixer_port, chip->irq); - - snd_azf3328_dbgmisc("io2 %02x %02x %02x %02x %02x %02x\n", snd_azf3328_io2_read(chip, 0), snd_azf3328_io2_read(chip, 1), snd_azf3328_io2_read(chip, 2), snd_azf3328_io2_read(chip, 3), snd_azf3328_io2_read(chip, 4), snd_azf3328_io2_read(chip, 5)); - - for (tmp=0; tmp <= 0x01; tmp += 1) - snd_azf3328_dbgmisc("0x%02x: opl 0x%04x, mpu300 0x%04x, mpu310 0x%04x, mpu320 0x%04x, mpu330 0x%04x\n", tmp, inb(0x388 + tmp), inb(0x300 + tmp), inb(0x310 + tmp), inb(0x320 + tmp), inb(0x330 + tmp)); - + snd_azf3328_debug_show_ports(chip); + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { - snd_azf3328_free(chip); - return err; + goto out_err; } /* create mixer interface & switches */ if ((err = snd_azf3328_mixer_new(chip)) < 0) - return err; + goto out_err; #if 0 /* set very low bitrate to reduce noise and power consumption? */ @@ -1406,22 +1714,34 @@ static int __devinit snd_azf3328_create(snd_card_t * card, #endif /* standard chip init stuff */ - spin_lock_irq(&chip->reg_lock); - outb(DMA_PLAY_SOMETHING2|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE, chip->codec_port + IDX_IO_PLAY_FLAGS); - outb(DMA_PLAY_SOMETHING2|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE, chip->codec_port + IDX_IO_SOMETHING_FLAGS); - outb(DMA_PLAY_SOMETHING2|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE, chip->codec_port + IDX_IO_REC_FLAGS); - outb(0x0, chip->codec_port + IDX_IO_IRQ63H); + /* default IRQ init value */ + tmp = DMA_PLAY_SOMETHING2|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE; + spin_lock_irq(&chip->reg_lock); + snd_azf3328_codec_outb(chip, IDX_IO_PLAY_FLAGS, tmp); + snd_azf3328_codec_outb(chip, IDX_IO_REC_FLAGS, tmp); + snd_azf3328_codec_outb(chip, IDX_IO_SOMETHING_FLAGS, tmp); + snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x00); /* disable timer */ spin_unlock_irq(&chip->reg_lock); snd_card_set_dev(card, &pci->dev); *rchip = chip; - return 0; + + err = 0; + goto out; + +out_err: + if (chip) + snd_azf3328_free(chip); + pci_disable_device(pci); + +out: + return err; } -static int __devinit snd_azf3328_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int __devinit +snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; snd_card_t *card; @@ -1445,63 +1765,70 @@ static int __devinit snd_azf3328_probe(struct pci_dev *pci, strcpy(card->shortname, "Aztech AZF3328 (PCI168)"); if ((err = snd_azf3328_create(card, pci, pci_id->driver_data, &chip)) < 0) { - snd_card_free(card); - return err; + goto out_err; } if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_MPU401, chip->mpu_port, 1, pci->irq, 0, &chip->rmidi)) < 0) { - snd_printk("azf3328: no MPU-401 device at 0x%lx?\n", chip->mpu_port); - snd_card_free(card); - return err; + snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n", chip->mpu_port); + goto out_err; + } + + if ((err = snd_azf3328_timer(chip, 0)) < 0) { + goto out_err; } if ((err = snd_azf3328_pcm(chip, 0)) < 0) { - snd_card_free(card); - return err; + goto out_err; } if (snd_opl3_create(card, chip->synth_port, chip->synth_port+2, OPL3_HW_AUTO, 1, &opl3) < 0) { - snd_printk("azf3328: no OPL3 device at 0x%lx-0x%lx?\n", + snd_printk(KERN_ERR "azf3328: no OPL3 device at 0x%lx-0x%lx?\n", chip->synth_port, chip->synth_port+2 ); } else { if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { - snd_card_free(card); - return err; + goto out_err; } } - snd_azf3328_dbgio(chip, "create"); - sprintf(card->longname, "%s at 0x%lx, irq %i", card->shortname, chip->codec_port, chip->irq); if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); - return err; + goto out_err; } #ifdef MODULE printk( -"azt3328: Experimental driver for Aztech AZF3328-based soundcards such as PCI168.\n" -"azt3328: ZERO support from Aztech: you might think hard about future purchase.\n" -"azt3328: Feel free to contact hw7oshyuv3001@sneakemail.com for bug reports etc.!\n"); +"azt3328: Sound driver for Aztech AZF3328-based soundcards such as PCI168\n" +"azt3328: (hardware was completely undocumented - ZERO support from Aztech).\n" +"azt3328: Feel free to contact andi AT lisas.de for bug reports etc.!\n" +"azt3328: User-scalable sequencer timer set to %dHz (1024000Hz / %d).\n", + 1024000 / seqtimer_scaling, seqtimer_scaling); #endif if (snd_azf3328_config_joystick(chip, dev) < 0) - snd_azf3328_io2_write(chip, IDX_IO2_LEGACY_ADDR, - snd_azf3328_io2_read(chip, IDX_IO2_LEGACY_ADDR) & ~LEGACY_JOY); + snd_azf3328_io2_outb(chip, IDX_IO2_LEGACY_ADDR, + snd_azf3328_io2_inb(chip, IDX_IO2_LEGACY_ADDR) & ~LEGACY_JOY); pci_set_drvdata(pci, card); dev++; + err = 0; + goto out; + +out_err: + snd_card_free(card); + +out: snd_azf3328_dbgcallleave(); - return 0; + return err; } -static void __devexit snd_azf3328_remove(struct pci_dev *pci) +static void __devexit +snd_azf3328_remove(struct pci_dev *pci) { snd_azf3328_dbgcallenter(); snd_card_free(pci_get_drvdata(pci)); @@ -1517,7 +1844,8 @@ static struct pci_driver driver = { .remove = __devexit_p(snd_azf3328_remove), }; -static int __init alsa_card_azf3328_init(void) +static int __init +alsa_card_azf3328_init(void) { int err; snd_azf3328_dbgcallenter(); @@ -1526,7 +1854,8 @@ static int __init alsa_card_azf3328_init(void) return err; } -static void __exit alsa_card_azf3328_exit(void) +static void __exit +alsa_card_azf3328_exit(void) { snd_azf3328_dbgcallenter(); pci_unregister_driver(&driver); diff --git a/sound/pci/azt3328.h b/sound/pci/azt3328.h index 7e0e791809773b1f2e5e5e6aa0a924357d0a01b5..f489bdaf6d40688cdbae526efa752dd497d2730a 100644 --- a/sound/pci/azt3328.h +++ b/sound/pci/azt3328.h @@ -1,19 +1,17 @@ -#ifndef __SOUND_AZF3328_H -#define __SOUND_AZF3328_H +#ifndef __SOUND_AZT3328_H +#define __SOUND_AZT3328_H -/* type argument to use for the I/O functions */ -#define WORD_VALUE 0x1000 -#define DWORD_VALUE 0x2000 -#define BYTE_VALUE 0x4000 +/* "PU" == "power-up value", as tested on PCI168 PCI rev. 10 */ /*** main I/O area port indices ***/ /* (only 0x70 of 0x80 bytes saved/restored by Windows driver) */ -/* the driver initialisation suggests a layout of 3 main areas: - * from 0x00 (playback), from 0x20 (recording) and from 0x40 (maybe DirectX - * timer ???). and probably another area from 0x60 to 0x6f - * (IRQ management, power management etc. ???). */ -/* playback area */ -#define IDX_IO_PLAY_FLAGS 0x00 +/* the driver initialisation suggests a layout of 4 main areas: + * from 0x00 (playback), from 0x20 (recording) and from 0x40 (maybe MPU401??). + * And another area from 0x60 to 0x6f (DirectX timer, IRQ management, + * power management etc.???). */ + +/** playback area **/ +#define IDX_IO_PLAY_FLAGS 0x00 /* PU:0x0000 */ /* able to reactivate output after output muting due to 8/16bit * output change, just like 0x0002. * 0x0001 is the only bit that's able to start the DMA counter */ @@ -29,7 +27,7 @@ #define DMA_EPILOGUE_SOMETHING 0x0010 #define DMA_SOMETHING_ELSE 0x0020 /* ??? */ #define SOMETHING_UNMODIFIABLE 0xffc0 /* unused ? not modifiable */ -#define IDX_IO_PLAY_IRQMASK 0x02 +#define IDX_IO_PLAY_IRQTYPE 0x02 /* PU:0x0001 */ /* write back to flags in case flags are set, in order to ACK IRQ in handler * (bit 1 of port 0x64 indicates interrupt for one of these three types) * sometimes in this case it just writes 0xffff to globally ACK all IRQs @@ -41,36 +39,39 @@ #define IRQMASK_SOME_STATUS_1 0x0008 /* \ related bits */ #define IRQMASK_SOME_STATUS_2 0x0010 /* / (checked together in loop) */ #define IRQMASK_UNMODIFIABLE 0xffe0 /* unused ? not modifiable */ -#define IDX_IO_PLAY_DMA_START_1 0x04 /* start address of 1st DMA play area */ -#define IDX_IO_PLAY_DMA_START_2 0x08 /* start address of 2nd DMA play area */ -#define IDX_IO_PLAY_DMA_LEN_1 0x0c /* length of 1st DMA play area */ -#define IDX_IO_PLAY_DMA_LEN_2 0x0e /* length of 2nd DMA play area */ -#define IDX_IO_PLAY_DMA_CURRPOS 0x10 /* current DMA position */ -#define IDX_IO_PLAY_DMA_CURROFS 0x14 /* offset within current DMA play area */ -#define IDX_IO_PLAY_SOUNDFORMAT 0x16 +#define IDX_IO_PLAY_DMA_START_1 0x04 /* start address of 1st DMA play area, PU:0x00000000 */ +#define IDX_IO_PLAY_DMA_START_2 0x08 /* start address of 2nd DMA play area, PU:0x00000000 */ +#define IDX_IO_PLAY_DMA_LEN_1 0x0c /* length of 1st DMA play area, PU:0x0000 */ +#define IDX_IO_PLAY_DMA_LEN_2 0x0e /* length of 2nd DMA play area, PU:0x0000 */ +#define IDX_IO_PLAY_DMA_CURRPOS 0x10 /* current DMA position, PU:0x00000000 */ +#define IDX_IO_PLAY_DMA_CURROFS 0x14 /* offset within current DMA play area, PU:0x0000 */ +#define IDX_IO_PLAY_SOUNDFORMAT 0x16 /* PU:0x0010 */ /* all unspecified bits can't be modified */ #define SOUNDFORMAT_FREQUENCY_MASK 0x000f + #define SOUNDFORMAT_XTAL1 0x00 + #define SOUNDFORMAT_XTAL2 0x01 /* all _SUSPECTED_ values are not used by Windows drivers, so we don't * have any hard facts, only rough measurements */ - #define SOUNDFORMAT_FREQ_SUSPECTED_4000 0x0c - #define SOUNDFORMAT_FREQ_SUSPECTED_4800 0x0a - #define SOUNDFORMAT_FREQ_5510 0x0d - #define SOUNDFORMAT_FREQ_6620 0x0b - #define SOUNDFORMAT_FREQ_8000 0x00 /* also 0x0e ? */ - #define SOUNDFORMAT_FREQ_9600 0x08 - #define SOUNDFORMAT_FREQ_SUSPECTED_12000 0x09 - #define SOUNDFORMAT_FREQ_11025 0x01 /* also 0x0f ? */ - #define SOUNDFORMAT_FREQ_16000 0x02 - #define SOUNDFORMAT_FREQ_22050 0x03 - #define SOUNDFORMAT_FREQ_32000 0x04 - #define SOUNDFORMAT_FREQ_44100 0x05 - #define SOUNDFORMAT_FREQ_48000 0x06 - #define SOUNDFORMAT_FREQ_SUSPECTED_64000 0x07 + #define SOUNDFORMAT_FREQ_SUSPECTED_4000 0x0c | SOUNDFORMAT_XTAL1 + #define SOUNDFORMAT_FREQ_SUSPECTED_4800 0x0a | SOUNDFORMAT_XTAL1 + #define SOUNDFORMAT_FREQ_5510 0x0c | SOUNDFORMAT_XTAL2 + #define SOUNDFORMAT_FREQ_6620 0x0a | SOUNDFORMAT_XTAL2 + #define SOUNDFORMAT_FREQ_8000 0x00 | SOUNDFORMAT_XTAL1 /* also 0x0e | SOUNDFORMAT_XTAL1? */ + #define SOUNDFORMAT_FREQ_9600 0x08 | SOUNDFORMAT_XTAL1 + #define SOUNDFORMAT_FREQ_11025 0x00 | SOUNDFORMAT_XTAL2 /* also 0x0e | SOUNDFORMAT_XTAL2? */ + #define SOUNDFORMAT_FREQ_SUSPECTED_13240 0x08 | SOUNDFORMAT_XTAL2 /* seems to be 6620 *2 */ + #define SOUNDFORMAT_FREQ_16000 0x02 | SOUNDFORMAT_XTAL1 + #define SOUNDFORMAT_FREQ_22050 0x02 | SOUNDFORMAT_XTAL2 + #define SOUNDFORMAT_FREQ_32000 0x04 | SOUNDFORMAT_XTAL1 + #define SOUNDFORMAT_FREQ_44100 0x04 | SOUNDFORMAT_XTAL2 + #define SOUNDFORMAT_FREQ_48000 0x06 | SOUNDFORMAT_XTAL1 + #define SOUNDFORMAT_FREQ_SUSPECTED_66200 0x06 | SOUNDFORMAT_XTAL2 /* 66200 (13240 * 5); 64000 may have been nicer :-\ */ #define SOUNDFORMAT_FLAG_16BIT 0x0010 #define SOUNDFORMAT_FLAG_2CHANNELS 0x0020 -/* recording area (see also: playback bit flag definitions) */ -#define IDX_IO_REC_FLAGS 0x20 /* ?? */ -#define IDX_IO_REC_IRQMASK 0x22 /* ?? */ + +/** recording area (see also: playback bit flag definitions) **/ +#define IDX_IO_REC_FLAGS 0x20 /* ??, PU:0x0000 */ +#define IDX_IO_REC_IRQTYPE 0x22 /* ??, PU:0x0000 */ #define IRQ_REC_SOMETHING 0x0001 /* something & ACK */ #define IRQ_FINISHED_RECBUF_1 0x0002 /* 1st dmabuf finished & ACK */ #define IRQ_FINISHED_RECBUF_2 0x0004 /* 2nd dmabuf finished & ACK */ @@ -78,39 +79,47 @@ * but OTOH they are most likely at port 0x22 instead */ #define IRQMASK_SOME_STATUS_1 0x0008 /* \ related bits */ #define IRQMASK_SOME_STATUS_2 0x0010 /* / (checked together in loop) */ -#define IDX_IO_REC_DMA_START_1 0x24 -#define IDX_IO_REC_DMA_START_2 0x28 -#define IDX_IO_REC_DMA_LEN_1 0x2c -#define IDX_IO_REC_DMA_LEN_2 0x2e -#define IDX_IO_REC_DMA_CURRPOS 0x30 -#define IDX_IO_REC_DMA_CURROFS 0x34 -#define IDX_IO_REC_SOUNDFORMAT 0x36 -/* some third area ? (after playback and recording) */ -#define IDX_IO_SOMETHING_FLAGS 0x40 /* gets set to 0x34 just like port 0x0 and 0x20 on card init */ +#define IDX_IO_REC_DMA_START_1 0x24 /* PU:0x00000000 */ +#define IDX_IO_REC_DMA_START_2 0x28 /* PU:0x00000000 */ +#define IDX_IO_REC_DMA_LEN_1 0x2c /* PU:0x0000 */ +#define IDX_IO_REC_DMA_LEN_2 0x2e /* PU:0x0000 */ +#define IDX_IO_REC_DMA_CURRPOS 0x30 /* PU:0x00000000 */ +#define IDX_IO_REC_DMA_CURROFS 0x34 /* PU:0x00000000 */ +#define IDX_IO_REC_SOUNDFORMAT 0x36 /* PU:0x0000 */ + +/** hmm, what is this I/O area for? MPU401?? (after playback, recording, ???, timer) **/ +#define IDX_IO_SOMETHING_FLAGS 0x40 /* gets set to 0x34 just like port 0x0 and 0x20 on card init, PU:0x0000 */ /* general */ -#define IDX_IO_60H 0x60 /* writing 0xffff returns 0xffff */ -#define IDX_IO_62H 0x62 /* writing to WORD 0x0062 can hang the box ! --> responsible for IRQ management as a whole ?? */ -#define IDX_IO_IRQ63H 0x63 /* FIXME !! */ - #define IO_IRQ63H_SOMETHING 0x04 /* being set in IRQ handler in case port 0x00 had 0x0020 set upon IRQ handler */ +#define IDX_IO_42H 0x42 /* PU:0x0001 */ + +/** DirectX timer, main interrupt area (FIXME: and something else?) **/ +#define IDX_IO_TIMER_VALUE 0x60 /* found this timer area by pure luck :-) */ + #define TIMER_VALUE_MASK 0x000fffffUL /* timer countdown value; triggers IRQ when timer is finished */ + #define TIMER_ENABLE_COUNTDOWN 0x01000000UL /* activate the timer countdown */ + #define TIMER_ENABLE_IRQ 0x02000000UL /* trigger timer IRQ on zero transition */ + #define TIMER_ACK_IRQ 0x04000000UL /* being set in IRQ handler in case port 0x00 (hmm, not port 0x64!?!?) had 0x0020 set upon IRQ handler */ #define IDX_IO_IRQSTATUS 0x64 #define IRQ_PLAYBACK 0x0001 #define IRQ_RECORDING 0x0002 #define IRQ_MPU401 0x0010 - #define IRQ_SOMEIRQ 0x0020 /* ???? */ - #define IRQ_WHO_KNOWS_UNUSED 0x00e0 /* probably unused */ + #define IRQ_TIMER 0x0020 /* DirectX timer */ + #define IRQ_UNKNOWN1 0x0040 /* probably unused */ + #define IRQ_UNKNOWN2 0x0080 /* probably unused */ #define IDX_IO_66H 0x66 /* writing 0xffff returns 0x0000 */ -#define IDX_IO_SOME_VALUE 0x68 /* this is always set to 0x3ff, and writable; maybe some buffer limit, but I couldn't find out more */ -#define IDX_IO_6AH 0x6A /* this WORD can be set to have bits 0x0028 activated; actually inhibits PCM playback !!! maybe power management ?? */ -#define IDX_IO_6CH 0x6C /* this WORD can have all its bits activated ? */ +#define IDX_IO_SOME_VALUE 0x68 /* this is set to e.g. 0x3ff or 0x300, and writable; maybe some buffer limit, but I couldn't find out more, PU:0x00ff */ +#define IDX_IO_6AH 0x6A /* this WORD can be set to have bits 0x0028 activated; actually inhibits PCM playback!!! maybe power management?? */ +#define IDX_IO_6CH 0x6C #define IDX_IO_6EH 0x6E /* writing 0xffff returns 0x83fe */ /* further I/O indices not saved/restored, so probably not used */ + /*** I/O 2 area port indices ***/ /* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */ #define IDX_IO2_LEGACY_ADDR 0x04 - #define LEGACY_SOMETHING 0x01 /* OPL3 ?? */ + #define LEGACY_SOMETHING 0x01 /* OPL3?? */ #define LEGACY_JOY 0x08 + /*** mixer I/O area port indices ***/ /* (only 0x22 of 0x40 bytes saved/restored by Windows driver) * generally spoken: AC97 register index = AZF3328 mixer reg index + 2 @@ -148,18 +157,18 @@ /* unlisted bits are unmodifiable */ #define MIXER_ADVCTL1_3DWIDTH_MASK 0x000e #define MIXER_ADVCTL1_HIFI3D_MASK 0x0300 -#define IDX_MIXER_ADVCTL2 0x20 /* resembles AC97_GENERAL_PURPOSE reg ! */ +#define IDX_MIXER_ADVCTL2 0x20 /* resembles AC97_GENERAL_PURPOSE reg! */ /* unlisted bits are unmodifiable */ - #define MIXER_ADVCTL2_BIT7 0x0080 /* WaveOut 3D Bypass ? mutes WaveOut at LineOut */ - #define MIXER_ADVCTL2_BIT8 0x0100 /* is this Modem Out Select ? */ - #define MIXER_ADVCTL2_BIT9 0x0200 /* Mono Select Source ? */ - #define MIXER_ADVCTL2_BIT13 0x2000 /* 3D enable ? */ + #define MIXER_ADVCTL2_BIT7 0x0080 /* WaveOut 3D Bypass? mutes WaveOut at LineOut */ + #define MIXER_ADVCTL2_BIT8 0x0100 /* is this Modem Out Select? */ + #define MIXER_ADVCTL2_BIT9 0x0200 /* Mono Select Source? */ + #define MIXER_ADVCTL2_BIT13 0x2000 /* 3D enable? */ #define MIXER_ADVCTL2_BIT15 0x8000 /* unknown */ -#define IDX_MIXER_SOMETHING30H 0x30 /* used, but unknown ??? */ +#define IDX_MIXER_SOMETHING30H 0x30 /* used, but unknown??? */ /* driver internal flags */ #define SET_CHAN_LEFT 1 #define SET_CHAN_RIGHT 2 -#endif /* __SOUND_AZF3328_H */ +#endif /* __SOUND_AZT3328_H */ diff --git a/sound/pci/ca0106/Makefile b/sound/pci/ca0106/Makefile index 89c6ceee21f39d9cfd4a2bfe0c55606f76fc8dfa..dcbae7b31546105c1d37d53ccb45c42d0e2a8d4f 100644 --- a/sound/pci/ca0106/Makefile +++ b/sound/pci/ca0106/Makefile @@ -1,3 +1,3 @@ -snd-ca0106-objs := ca0106_main.o ca0106_proc.o ca0106_mixer.o +snd-ca0106-objs := ca0106_main.o ca0106_proc.o ca0106_mixer.o ca_midi.o obj-$(CONFIG_SND_CA0106) += snd-ca0106.o diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index da09cab405a92748904bd925aba7662b488fc7a7..9a4b6406f7a50ed8054c708deb3521de2439dcaf 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -399,10 +399,24 @@ #define PLAYBACK_VOLUME2 0x6a /* Playback Analog volume per channel. Does not effect AC3 output */ /* Similar to register 0x66, except that the destination is the I2S mixer instead of the SPDIF mixer. I.E. Outputs to the Analog outputs instead of SPDIF. */ #define UNKNOWN6b 0x6b /* Unknown. Readonly. Default 00400000 00400000 00400000 00400000 */ -#define UART_A_DATA 0x6c /* Uart, used in setting sample rates, bits per sample etc. */ -#define UART_A_CMD 0x6d /* Uart, used in setting sample rates, bits per sample etc. */ -#define UART_B_DATA 0x6e /* Uart, Unknown. */ -#define UART_B_CMD 0x6f /* Uart, Unknown. */ +#define MIDI_UART_A_DATA 0x6c /* Midi Uart A Data */ +#define MIDI_UART_A_CMD 0x6d /* Midi Uart A Command/Status */ +#define MIDI_UART_B_DATA 0x6e /* Midi Uart B Data (currently unused) */ +#define MIDI_UART_B_CMD 0x6f /* Midi Uart B Command/Status (currently unused) */ + +/* unique channel identifier for midi->channel */ + +#define CA0106_MIDI_CHAN_A 0x1 +#define CA0106_MIDI_CHAN_B 0x2 + +/* from mpu401 */ + +#define CA0106_MIDI_INPUT_AVAIL 0x80 +#define CA0106_MIDI_OUTPUT_READY 0x40 +#define CA0106_MPU401_RESET 0xff +#define CA0106_MPU401_ENTER_UART 0x3f +#define CA0106_MPU401_ACK 0xfe + #define SAMPLE_RATE_TRACKER_STATUS 0x70 /* Readonly. Default 00108000 00108000 00500000 00500000 */ /* Estimated sample rate [19:0] Relative to 48kHz. 0x8000 = 1.0 * Rate Locked [20] @@ -538,6 +552,8 @@ #define CONTROL_CENTER_LFE_CHANNEL 1 #define CONTROL_UNKNOWN_CHANNEL 2 +#include "ca_midi.h" + typedef struct snd_ca0106_channel ca0106_channel_t; typedef struct snd_ca0106 ca0106_t; typedef struct snd_ca0106_pcm ca0106_pcm_t; @@ -592,6 +608,9 @@ struct snd_ca0106 { int capture_mic_line_in; struct snd_dma_buffer buffer; + + ca_midi_t midi; + ca_midi_t midi2; }; int __devinit snd_ca0106_mixer(ca0106_t *emu); diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index ba07960921d8018f92d92957275b37ccf25105d4..ee58d16002e565520b05ede5342c610e7ad331c1 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -281,7 +281,7 @@ int snd_ca0106_i2c_write(ca0106_t *emu, int retry; if ((reg > 0x7f) || (value > 0x1ff)) { - snd_printk("i2c_write: invalid values.\n"); + snd_printk(KERN_ERR "i2c_write: invalid values.\n"); return -EINVAL; } @@ -319,7 +319,7 @@ int snd_ca0106_i2c_write(ca0106_t *emu, if(retry==10) { - snd_printk("Writing to ADC failed!\n"); + snd_printk(KERN_ERR "Writing to ADC failed!\n"); return -EINVAL; } @@ -338,6 +338,18 @@ static void snd_ca0106_intr_enable(ca0106_t *emu, unsigned int intrenb) spin_unlock_irqrestore(&emu->emu_lock, flags); } +static void snd_ca0106_intr_disable(ca0106_t *emu, unsigned int intrenb) +{ + unsigned long flags; + unsigned int enable; + + spin_lock_irqsave(&emu->emu_lock, flags); + enable = inl(emu->port + INTE) & ~intrenb; + outl(enable, emu->port + INTE); + spin_unlock_irqrestore(&emu->emu_lock, flags); +} + + static void snd_ca0106_pcm_free_substream(snd_pcm_runtime_t *runtime) { kfree(runtime->private_data); @@ -421,7 +433,7 @@ static int snd_ca0106_pcm_open_capture_channel(snd_pcm_substream_t *substream, i epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) { - snd_printk("open_capture_channel: failed epcm alloc\n"); + snd_printk(KERN_ERR "open_capture_channel: failed epcm alloc\n"); return -ENOMEM; } epcm->emu = chip; @@ -969,10 +981,8 @@ static int snd_ca0106_free(ca0106_t *chip) #endif // release the i/o port - if (chip->res_port) { - release_resource(chip->res_port); - kfree_nocheck(chip->res_port); - } + release_and_free_resource(chip->res_port); + // release the irq if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); @@ -1042,6 +1052,15 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id, snd_ca0106_ptr_write(chip, EXTENDED_INT, 0, stat76); spin_lock(&chip->emu_lock); + + if (chip->midi.dev_id && + (status & (chip->midi.ipr_tx|chip->midi.ipr_rx))) { + if (chip->midi.interrupt) + chip->midi.interrupt(&chip->midi, status); + else + chip->midi.interrupt_disable(&chip->midi, chip->midi.tx_enable | chip->midi.rx_enable); + } + // acknowledge the interrupt if necessary outl(status, chip->port+IPR); @@ -1311,6 +1330,88 @@ static int __devinit snd_ca0106_create(snd_card_t *card, return 0; } + +static void ca0106_midi_interrupt_enable(ca_midi_t *midi, int intr) +{ + snd_ca0106_intr_enable((ca0106_t *)(midi->dev_id), intr); +} + +static void ca0106_midi_interrupt_disable(ca_midi_t *midi, int intr) +{ + snd_ca0106_intr_disable((ca0106_t *)(midi->dev_id), intr); +} + +static unsigned char ca0106_midi_read(ca_midi_t *midi, int idx) +{ + return (unsigned char)snd_ca0106_ptr_read((ca0106_t *)(midi->dev_id), midi->port + idx, 0); +} + +static void ca0106_midi_write(ca_midi_t *midi, int data, int idx) +{ + snd_ca0106_ptr_write((ca0106_t *)(midi->dev_id), midi->port + idx, 0, data); +} + +static snd_card_t *ca0106_dev_id_card(void *dev_id) +{ + return ((ca0106_t *)dev_id)->card; +} + +static int ca0106_dev_id_port(void *dev_id) +{ + return ((ca0106_t *)dev_id)->port; +} + +static int __devinit snd_ca0106_midi(ca0106_t *chip, unsigned int channel) +{ + ca_midi_t *midi; + char *name; + int err; + + if(channel==CA0106_MIDI_CHAN_B) { + name = "CA0106 MPU-401 (UART) B"; + midi = &chip->midi2; + midi->tx_enable = INTE_MIDI_TX_B; + midi->rx_enable = INTE_MIDI_RX_B; + midi->ipr_tx = IPR_MIDI_TX_B; + midi->ipr_rx = IPR_MIDI_RX_B; + midi->port = MIDI_UART_B_DATA; + } else { + name = "CA0106 MPU-401 (UART)"; + midi = &chip->midi; + midi->tx_enable = INTE_MIDI_TX_A; + midi->rx_enable = INTE_MIDI_TX_B; + midi->ipr_tx = IPR_MIDI_TX_A; + midi->ipr_rx = IPR_MIDI_RX_A; + midi->port = MIDI_UART_A_DATA; + } + + midi->reset = CA0106_MPU401_RESET; + midi->enter_uart = CA0106_MPU401_ENTER_UART; + midi->ack = CA0106_MPU401_ACK; + + midi->input_avail = CA0106_MIDI_INPUT_AVAIL; + midi->output_ready = CA0106_MIDI_OUTPUT_READY; + + midi->channel = channel; + + midi->interrupt_enable = ca0106_midi_interrupt_enable; + midi->interrupt_disable = ca0106_midi_interrupt_disable; + + midi->read = ca0106_midi_read; + midi->write = ca0106_midi_write; + + midi->get_dev_id_card = ca0106_dev_id_card; + midi->get_dev_id_port = ca0106_dev_id_port; + + midi->dev_id = chip; + + if ((err = ca_midi_init(chip, midi, 0, name)) < 0) + return err; + + return 0; +} + + static int __devinit snd_ca0106_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -1362,6 +1463,14 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, return err; } + snd_printdd("ca0106: probe for MIDI channel A ..."); + if ((err = snd_ca0106_midi(chip,CA0106_MIDI_CHAN_A)) < 0) { + snd_card_free(card); + snd_printdd(" failed, err=0x%x\n",err); + return err; + } + snd_printdd(" done.\n"); + snd_ca0106_proc_init(chip); if ((err = snd_card_register(card)) < 0) { diff --git a/sound/pci/ca0106/ca_midi.c b/sound/pci/ca0106/ca_midi.c new file mode 100644 index 0000000000000000000000000000000000000000..2e08b27b83496011e8b014a1a409a7d5817145f1 --- /dev/null +++ b/sound/pci/ca0106/ca_midi.c @@ -0,0 +1,306 @@ +/* + * Copyright 10/16/2005 Tilman Kranz + * Creative Audio MIDI, for the CA0106 Driver + * Version: 0.0.1 + * + * Changelog: + * Implementation is based on mpu401 and emu10k1x and + * tested with ca0106. + * mpu401: Copyright (c) by Jaroslav Kysela + * emu10k1x: Copyright (c) by Francisco Moraes + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + */ + +#include +#include +#include +#include + +#include "ca_midi.h" + +#define ca_midi_write_data(midi, data) midi->write(midi, data, 0) +#define ca_midi_write_cmd(midi, data) midi->write(midi, data, 1) +#define ca_midi_read_data(midi) midi->read(midi, 0) +#define ca_midi_read_stat(midi) midi->read(midi, 1) +#define ca_midi_input_avail(midi) (!(ca_midi_read_stat(midi) & midi->input_avail)) +#define ca_midi_output_ready(midi) (!(ca_midi_read_stat(midi) & midi->output_ready)) + +static void ca_midi_clear_rx(ca_midi_t *midi) +{ + int timeout = 100000; + for (; timeout > 0 && ca_midi_input_avail(midi); timeout--) + ca_midi_read_data(midi); +#ifdef CONFIG_SND_DEBUG + if (timeout <= 0) + snd_printk(KERN_ERR "ca_midi_clear_rx: timeout (status = 0x%x)\n", ca_midi_read_stat(midi)); +#endif +} + +static void ca_midi_interrupt(ca_midi_t *midi, unsigned int status) { + unsigned char byte; + + if (midi->rmidi == NULL) { + midi->interrupt_disable(midi,midi->tx_enable | midi->rx_enable); + return; + } + + spin_lock(&midi->input_lock); + if ((status & midi->ipr_rx) && ca_midi_input_avail(midi)) { + if (!(midi->midi_mode & CA_MIDI_MODE_INPUT)) { + ca_midi_clear_rx(midi); + } else { + byte = ca_midi_read_data(midi); + if(midi->substream_input) + snd_rawmidi_receive(midi->substream_input, &byte, 1); + + + } + } + spin_unlock(&midi->input_lock); + + spin_lock(&midi->output_lock); + if ((status & midi->ipr_tx) && ca_midi_output_ready(midi)) { + if (midi->substream_output && + snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) { + ca_midi_write_data(midi, byte); + } else { + midi->interrupt_disable(midi,midi->tx_enable); + } + } + spin_unlock(&midi->output_lock); + +} + +static void ca_midi_cmd(ca_midi_t *midi, unsigned char cmd, int ack) +{ + unsigned long flags; + int timeout, ok; + + spin_lock_irqsave(&midi->input_lock, flags); + ca_midi_write_data(midi, 0x00); + /* ca_midi_clear_rx(midi); */ + + ca_midi_write_cmd(midi, cmd); + if (ack) { + ok = 0; + timeout = 10000; + while (!ok && timeout-- > 0) { + if (ca_midi_input_avail(midi)) { + if (ca_midi_read_data(midi) == midi->ack) + ok = 1; + } + } + if (!ok && ca_midi_read_data(midi) == midi->ack) + ok = 1; + } else { + ok = 1; + } + spin_unlock_irqrestore(&midi->input_lock, flags); + if (!ok) + snd_printk(KERN_ERR "ca_midi_cmd: 0x%x failed at 0x%x (status = 0x%x, data = 0x%x)!!!\n", + cmd, + midi->get_dev_id_port(midi->dev_id), + ca_midi_read_stat(midi), + ca_midi_read_data(midi)); +} + +static int ca_midi_input_open(snd_rawmidi_substream_t * substream) +{ + ca_midi_t *midi = (ca_midi_t *)substream->rmidi->private_data; + unsigned long flags; + + snd_assert(midi->dev_id, return -ENXIO); + spin_lock_irqsave(&midi->open_lock, flags); + midi->midi_mode |= CA_MIDI_MODE_INPUT; + midi->substream_input = substream; + if (!(midi->midi_mode & CA_MIDI_MODE_OUTPUT)) { + spin_unlock_irqrestore(&midi->open_lock, flags); + ca_midi_cmd(midi, midi->reset, 1); + ca_midi_cmd(midi, midi->enter_uart, 1); + } else { + spin_unlock_irqrestore(&midi->open_lock, flags); + } + return 0; +} + +static int ca_midi_output_open(snd_rawmidi_substream_t * substream) +{ + ca_midi_t *midi = (ca_midi_t *)substream->rmidi->private_data; + unsigned long flags; + + snd_assert(midi->dev_id, return -ENXIO); + spin_lock_irqsave(&midi->open_lock, flags); + midi->midi_mode |= CA_MIDI_MODE_OUTPUT; + midi->substream_output = substream; + if (!(midi->midi_mode & CA_MIDI_MODE_INPUT)) { + spin_unlock_irqrestore(&midi->open_lock, flags); + ca_midi_cmd(midi, midi->reset, 1); + ca_midi_cmd(midi, midi->enter_uart, 1); + } else { + spin_unlock_irqrestore(&midi->open_lock, flags); + } + return 0; +} + +static int ca_midi_input_close(snd_rawmidi_substream_t * substream) +{ + ca_midi_t *midi = (ca_midi_t *)substream->rmidi->private_data; + unsigned long flags; + + snd_assert(midi->dev_id, return -ENXIO); + spin_lock_irqsave(&midi->open_lock, flags); + midi->interrupt_disable(midi,midi->rx_enable); + midi->midi_mode &= ~CA_MIDI_MODE_INPUT; + midi->substream_input = NULL; + if (!(midi->midi_mode & CA_MIDI_MODE_OUTPUT)) { + spin_unlock_irqrestore(&midi->open_lock, flags); + ca_midi_cmd(midi, midi->reset, 0); + } else { + spin_unlock_irqrestore(&midi->open_lock, flags); + } + return 0; +} + +static int ca_midi_output_close(snd_rawmidi_substream_t * substream) +{ + ca_midi_t *midi = (ca_midi_t *)substream->rmidi->private_data; + unsigned long flags; + snd_assert(midi->dev_id, return -ENXIO); + + spin_lock_irqsave(&midi->open_lock, flags); + + midi->interrupt_disable(midi,midi->tx_enable); + midi->midi_mode &= ~CA_MIDI_MODE_OUTPUT; + midi->substream_output = NULL; + + if (!(midi->midi_mode & CA_MIDI_MODE_INPUT)) { + spin_unlock_irqrestore(&midi->open_lock, flags); + ca_midi_cmd(midi, midi->reset, 0); + } else { + spin_unlock_irqrestore(&midi->open_lock, flags); + } + return 0; +} + +static void ca_midi_input_trigger(snd_rawmidi_substream_t * substream, int up) +{ + ca_midi_t *midi = (ca_midi_t *)substream->rmidi->private_data; + snd_assert(midi->dev_id, return); + + if (up) { + midi->interrupt_enable(midi,midi->rx_enable); + } else { + midi->interrupt_disable(midi, midi->rx_enable); + } +} + +static void ca_midi_output_trigger(snd_rawmidi_substream_t * substream, int up) +{ + ca_midi_t *midi = (ca_midi_t *)substream->rmidi->private_data; + unsigned long flags; + + snd_assert(midi->dev_id, return); + + if (up) { + int max = 4; + unsigned char byte; + + spin_lock_irqsave(&midi->output_lock, flags); + + /* try to send some amount of bytes here before interrupts */ + while (max > 0) { + if (ca_midi_output_ready(midi)) { + if (!(midi->midi_mode & CA_MIDI_MODE_OUTPUT) || + snd_rawmidi_transmit(substream, &byte, 1) != 1) { + /* no more data */ + spin_unlock_irqrestore(&midi->output_lock, flags); + return; + } + ca_midi_write_data(midi, byte); + max--; + } else { + break; + } + } + + spin_unlock_irqrestore(&midi->output_lock, flags); + midi->interrupt_enable(midi,midi->tx_enable); + + } else { + midi->interrupt_disable(midi,midi->tx_enable); + } +} + +static snd_rawmidi_ops_t ca_midi_output = +{ + .open = ca_midi_output_open, + .close = ca_midi_output_close, + .trigger = ca_midi_output_trigger, +}; + +static snd_rawmidi_ops_t ca_midi_input = +{ + .open = ca_midi_input_open, + .close = ca_midi_input_close, + .trigger = ca_midi_input_trigger, +}; + +static void ca_midi_free(ca_midi_t *midi) { + midi->interrupt = NULL; + midi->interrupt_enable = NULL; + midi->interrupt_disable = NULL; + midi->read = NULL; + midi->write = NULL; + midi->get_dev_id_card = NULL; + midi->get_dev_id_port = NULL; + midi->rmidi = NULL; +} + +static void ca_rmidi_free(snd_rawmidi_t *rmidi) +{ + ca_midi_free((ca_midi_t *)rmidi->private_data); +} + +int __devinit ca_midi_init(void *dev_id, ca_midi_t *midi, int device, char *name) +{ + snd_rawmidi_t *rmidi; + int err; + + if ((err = snd_rawmidi_new(midi->get_dev_id_card(midi->dev_id), name, device, 1, 1, &rmidi)) < 0) + return err; + + midi->dev_id = dev_id; + midi->interrupt = ca_midi_interrupt; + + spin_lock_init(&midi->open_lock); + spin_lock_init(&midi->input_lock); + spin_lock_init(&midi->output_lock); + + strcpy(rmidi->name, name); + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &ca_midi_output); + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &ca_midi_input); + rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_INPUT | + SNDRV_RAWMIDI_INFO_DUPLEX; + rmidi->private_data = midi; + rmidi->private_free = ca_rmidi_free; + + midi->rmidi = rmidi; + return 0; +} + diff --git a/sound/pci/ca0106/ca_midi.h b/sound/pci/ca0106/ca_midi.h new file mode 100644 index 0000000000000000000000000000000000000000..b452cec2bf57b38fbcbe833ea5385b390aa74d47 --- /dev/null +++ b/sound/pci/ca0106/ca_midi.h @@ -0,0 +1,69 @@ +/* + * Copyright 10/16/2005 Tilman Kranz + * Creative Audio MIDI, for the CA0106 Driver + * Version: 0.0.1 + * + * Changelog: + * See ca_midi.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include + +#define CA_MIDI_MODE_INPUT MPU401_MODE_INPUT +#define CA_MIDI_MODE_OUTPUT MPU401_MODE_OUTPUT + +typedef struct ca_midi ca_midi_t; +struct ca_midi { + + snd_rawmidi_t *rmidi; + snd_rawmidi_substream_t *substream_input; + snd_rawmidi_substream_t *substream_output; + + void *dev_id; + + spinlock_t input_lock; + spinlock_t output_lock; + spinlock_t open_lock; + + unsigned int channel; + + unsigned int midi_mode; + int port; + int tx_enable, rx_enable; + int ipr_tx, ipr_rx; + + int input_avail, output_ready; + int ack, reset, enter_uart; + + void (*interrupt)(ca_midi_t *midi, unsigned int status); + void (*interrupt_enable)(ca_midi_t *midi, int intr); + void (*interrupt_disable)(ca_midi_t *midi, int intr); + + unsigned char (*read)(ca_midi_t *midi, int idx); + void (*write)(ca_midi_t *midi, int data, int idx); + + /* get info from dev_id */ + snd_card_t *(*get_dev_id_card)(void *dev_id); + int (*get_dev_id_port)(void *dev_id); +}; + +int __devinit ca_midi_init(void *card, ca_midi_t *midi, int device, char *name); + + diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 1eb3315d136dd2e50bbc0aab0168b32ee7cbf4b3..57e8e433d56f9bcdb2cd27bcc3178d2ca273df72 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -446,9 +446,6 @@ struct snd_stru_cmipci { snd_kcontrol_t *mixer_res_ctl[CM_SAVED_MIXERS]; int mixer_res_status[CM_SAVED_MIXERS]; - opl3_t *opl3; - snd_hwdep_t *opl3hwdep; - cmipci_pcm_t channel[2]; /* ch0 - DAC, ch1 - ADC or 2nd DAC */ /* external MIDI */ @@ -2686,8 +2683,7 @@ static int __devinit snd_cmipci_create_gameport(cmipci_t *cm, int dev) cm->gameport = gp = gameport_allocate_port(); if (!gp) { printk(KERN_ERR "cmipci: cannot allocate memory for gameport\n"); - release_resource(r); - kfree_nocheck(r); + release_and_free_resource(r); return -ENOMEM; } gameport_set_name(gp, "C-Media Gameport"); @@ -2712,8 +2708,7 @@ static void snd_cmipci_free_gameport(cmipci_t *cm) cm->gameport = NULL; snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN); - release_resource(r); - kfree_nocheck(r); + release_and_free_resource(r); } } #else @@ -2753,6 +2748,51 @@ static int snd_cmipci_dev_free(snd_device_t *device) return snd_cmipci_free(cm); } +static int __devinit snd_cmipci_create_fm(cmipci_t *cm, long fm_port) +{ + long iosynth; + unsigned int val; + opl3_t *opl3; + int err; + + /* first try FM regs in PCI port range */ + iosynth = cm->iobase + CM_REG_FM_PCI; + err = snd_opl3_create(cm->card, iosynth, iosynth + 2, + OPL3_HW_OPL3, 1, &opl3); + if (err < 0) { + /* then try legacy ports */ + val = snd_cmipci_read(cm, CM_REG_LEGACY_CTRL) & ~CM_FMSEL_MASK; + iosynth = fm_port; + switch (iosynth) { + case 0x3E8: val |= CM_FMSEL_3E8; break; + case 0x3E0: val |= CM_FMSEL_3E0; break; + case 0x3C8: val |= CM_FMSEL_3C8; break; + case 0x388: val |= CM_FMSEL_388; break; + default: + return 0; + } + snd_cmipci_write(cm, CM_REG_LEGACY_CTRL, val); + /* enable FM */ + snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_FM_EN); + + if (snd_opl3_create(cm->card, iosynth, iosynth + 2, + OPL3_HW_OPL3, 0, &opl3) < 0) { + printk(KERN_ERR "cmipci: no OPL device at %#lx, " + "skipping...\n", iosynth); + /* disable FM */ + snd_cmipci_write(cm, CM_REG_LEGACY_CTRL, + val & ~CM_FMSEL_MASK); + snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_FM_EN); + return 0; + } + } + if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { + printk(KERN_ERR "cmipci: cannot create OPL3 hwdep\n"); + return err; + } + return 0; +} + static int __devinit snd_cmipci_create(snd_card_t *card, struct pci_dev *pci, int dev, cmipci_t **rcmipci) { @@ -2762,8 +2802,8 @@ static int __devinit snd_cmipci_create(snd_card_t *card, struct pci_dev *pci, .dev_free = snd_cmipci_dev_free, }; unsigned int val = 0; - long iomidi = mpu_port[dev]; - long iosynth = fm_port[dev]; + long iomidi; + int integrated_midi; int pcm_index, pcm_spdif_index; static struct pci_device_id intel_82437vx[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX) }, @@ -2799,7 +2839,7 @@ static int __devinit snd_cmipci_create(snd_card_t *card, struct pci_dev *pci, cm->iobase = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_cmipci_interrupt, SA_INTERRUPT|SA_SHIRQ, card->driver, (void *)cm)) { - snd_printk("unable to grab IRQ %d\n", pci->irq); + snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_cmipci_free(cm); return -EBUSY; } @@ -2867,52 +2907,28 @@ static int __devinit snd_cmipci_create(snd_card_t *card, struct pci_dev *pci, return err; } - /* set MPU address */ - switch (iomidi) { - case 0x320: val = CM_VMPU_320; break; - case 0x310: val = CM_VMPU_310; break; - case 0x300: val = CM_VMPU_300; break; - case 0x330: val = CM_VMPU_330; break; - default: - iomidi = 0; break; - } - if (iomidi > 0) { - snd_cmipci_write(cm, CM_REG_LEGACY_CTRL, val); - /* enable UART */ - snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_UART_EN); - } - - /* set FM address */ - val = snd_cmipci_read(cm, CM_REG_LEGACY_CTRL) & ~CM_FMSEL_MASK; - switch (iosynth) { - case 0x3E8: val |= CM_FMSEL_3E8; break; - case 0x3E0: val |= CM_FMSEL_3E0; break; - case 0x3C8: val |= CM_FMSEL_3C8; break; - case 0x388: val |= CM_FMSEL_388; break; - default: - iosynth = 0; break; - } - if (iosynth > 0) { - snd_cmipci_write(cm, CM_REG_LEGACY_CTRL, val); - /* enable FM */ - snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_FM_EN); - - if (snd_opl3_create(card, iosynth, iosynth + 2, - OPL3_HW_OPL3, 0, &cm->opl3) < 0) { - printk(KERN_ERR "cmipci: no OPL device at 0x%lx, skipping...\n", iosynth); - iosynth = 0; - } else { - if ((err = snd_opl3_hwdep_new(cm->opl3, 0, 1, &cm->opl3hwdep)) < 0) { - printk(KERN_ERR "cmipci: cannot create OPL3 hwdep\n"); - return err; - } + integrated_midi = snd_cmipci_read_b(cm, CM_REG_MPU_PCI) != 0xff; + if (integrated_midi) + iomidi = cm->iobase + CM_REG_MPU_PCI; + else { + iomidi = mpu_port[dev]; + switch (iomidi) { + case 0x320: val = CM_VMPU_320; break; + case 0x310: val = CM_VMPU_310; break; + case 0x300: val = CM_VMPU_300; break; + case 0x330: val = CM_VMPU_330; break; + default: + iomidi = 0; break; + } + if (iomidi > 0) { + snd_cmipci_write(cm, CM_REG_LEGACY_CTRL, val); + /* enable UART */ + snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_UART_EN); } } - if (! iosynth) { - /* disable FM */ - snd_cmipci_write(cm, CM_REG_LEGACY_CTRL, val & ~CM_FMSEL_MASK); - snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_FM_EN); - } + + if ((err = snd_cmipci_create_fm(cm, fm_port[dev])) < 0) + return err; /* reset mixer */ snd_cmipci_mixer_write(cm, 0, 0); @@ -2941,7 +2957,7 @@ static int __devinit snd_cmipci_create(snd_card_t *card, struct pci_dev *pci, if (iomidi > 0) { if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI, - iomidi, 0, + iomidi, integrated_midi, cm->irq, 0, &cm->rmidi)) < 0) { printk(KERN_ERR "cmipci: no UART401 device at 0x%lx\n", iomidi); } diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index dc87e0144b5adc7fe5b1b452f33e62cf9fbde246..aea2c47712f91068033f13d5e70b3db5f6fcfe36 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -523,8 +523,7 @@ static void snd_cs4281_delay(unsigned int delay) delay = 1; end_time = jiffies + delay; do { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); } else { udelay(delay); @@ -533,8 +532,7 @@ static void snd_cs4281_delay(unsigned int delay) static inline void snd_cs4281_delay_long(void) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } static inline void snd_cs4281_pokeBA0(cs4281_t *chip, unsigned long offset, unsigned int val) diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 6e3855b8b33d9922c0cafcdb59f1fd3df99e9c9f..9b8af5bcbb04c1628eec3a6bb89f50893fb11c6f 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -163,7 +163,7 @@ static unsigned short snd_cs46xx_codec_read(cs46xx_t *chip, goto ok1; } - snd_printk("AC'97 read problem (ACCTL_DCV), reg = 0x%x\n", reg); + snd_printk(KERN_ERR "AC'97 read problem (ACCTL_DCV), reg = 0x%x\n", reg); result = 0xffff; goto end; @@ -182,7 +182,7 @@ static unsigned short snd_cs46xx_codec_read(cs46xx_t *chip, udelay(10); } - snd_printk("AC'97 read problem (ACSTS_VSTS), codec_index %d, reg = 0x%x\n", codec_index, reg); + snd_printk(KERN_ERR "AC'97 read problem (ACSTS_VSTS), codec_index %d, reg = 0x%x\n", codec_index, reg); result = 0xffff; goto end; @@ -281,7 +281,7 @@ static void snd_cs46xx_codec_write(cs46xx_t *chip, goto end; } } - snd_printk("AC'97 write problem, codec_index = %d, reg = 0x%x, val = 0x%x\n", codec_index, reg, val); + snd_printk(KERN_ERR "AC'97 write problem, codec_index = %d, reg = 0x%x, val = 0x%x\n", codec_index, reg, val); end: chip->active_ctrl(chip, -1); } @@ -510,7 +510,7 @@ static void snd_cs46xx_proc_start(cs46xx_t *chip) } if (snd_cs46xx_peek(chip, BA1_SPCR) & SPCR_RUNFR) - snd_printk("SPCR_RUNFR never reset\n"); + snd_printk(KERN_ERR "SPCR_RUNFR never reset\n"); } static void snd_cs46xx_proc_stop(cs46xx_t *chip) @@ -2403,7 +2403,7 @@ static void snd_cs46xx_codec_reset (ac97_t * ac97) msleep(10); } while (time_after_eq(end_time, jiffies)); - snd_printk("CS46xx secondary codec dont respond!\n"); + snd_printk(KERN_ERR "CS46xx secondary codec doesn't respond!\n"); } #endif @@ -2906,10 +2906,7 @@ static int snd_cs46xx_free(cs46xx_t *chip) snd_cs46xx_region_t *region = &chip->region.idx[idx]; if (region->remap_addr) iounmap(region->remap_addr); - if (region->resource) { - release_resource(region->resource); - kfree_nocheck(region->resource); - } + release_and_free_resource(region->resource); } if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); @@ -3075,8 +3072,8 @@ static int snd_cs46xx_chip_init(cs46xx_t *chip) } - snd_printk("create - never read codec ready from AC'97\n"); - snd_printk("it is not probably bug, try to use CS4236 driver\n"); + snd_printk(KERN_ERR "create - never read codec ready from AC'97\n"); + snd_printk(KERN_ERR "it is not probably bug, try to use CS4236 driver\n"); return -EIO; ok1: #ifdef CONFIG_SND_CS46XX_NEW_DSP @@ -3124,17 +3121,17 @@ static int snd_cs46xx_chip_init(cs46xx_t *chip) } #ifndef CONFIG_SND_CS46XX_NEW_DSP - snd_printk("create - never read ISV3 & ISV4 from AC'97\n"); + snd_printk(KERN_ERR "create - never read ISV3 & ISV4 from AC'97\n"); return -EIO; #else /* This may happen on a cold boot with a Terratec SiXPack 5.1. Reloading the driver may help, if there's other soundcards with the same problem I would like to know. (Benny) */ - snd_printk("ERROR: snd-cs46xx: never read ISV3 & ISV4 from AC'97\n"); - snd_printk(" Try reloading the ALSA driver, if you find something\n"); - snd_printk(" broken or not working on your soundcard upon\n"); - snd_printk(" this message please report to alsa-devel@lists.sourceforge.net\n"); + snd_printk(KERN_ERR "ERROR: snd-cs46xx: never read ISV3 & ISV4 from AC'97\n"); + snd_printk(KERN_ERR " Try reloading the ALSA driver, if you find something\n"); + snd_printk(KERN_ERR " broken or not working on your soundcard upon\n"); + snd_printk(KERN_ERR " this message please report to alsa-devel@lists.sourceforge.net\n"); return -EIO; #endif @@ -3215,7 +3212,7 @@ int __devinit snd_cs46xx_start_dsp(cs46xx_t *chip) #else /* old image */ if (snd_cs46xx_download_image(chip) < 0) { - snd_printk("image download error\n"); + snd_printk(KERN_ERR "image download error\n"); return -EIO; } @@ -3790,7 +3787,7 @@ int __devinit snd_cs46xx_create(snd_card_t * card, chip->ba1_addr = pci_resource_start(pci, 1); if (chip->ba0_addr == 0 || chip->ba0_addr == (unsigned long)~0 || chip->ba1_addr == 0 || chip->ba1_addr == (unsigned long)~0) { - snd_printk("wrong address(es) - ba0 = 0x%lx, ba1 = 0x%lx\n", chip->ba0_addr, chip->ba1_addr); + snd_printk(KERN_ERR "wrong address(es) - ba0 = 0x%lx, ba1 = 0x%lx\n", chip->ba0_addr, chip->ba1_addr); snd_cs46xx_free(chip); return -ENOMEM; } @@ -3839,12 +3836,12 @@ int __devinit snd_cs46xx_create(snd_card_t * card, } if (external_amp) { - snd_printk("Crystal EAPD support forced on.\n"); + snd_printk(KERN_INFO "Crystal EAPD support forced on.\n"); chip->amplifier_ctrl = amp_voyetra; } if (thinkpad) { - snd_printk("Activating CLKRUN hack for Thinkpad.\n"); + snd_printk(KERN_INFO "Activating CLKRUN hack for Thinkpad.\n"); chip->active_ctrl = clkrun_hack; clkrun_init(chip); } @@ -3861,20 +3858,20 @@ int __devinit snd_cs46xx_create(snd_card_t * card, for (idx = 0; idx < 5; idx++) { region = &chip->region.idx[idx]; if ((region->resource = request_mem_region(region->base, region->size, region->name)) == NULL) { - snd_printk("unable to request memory region 0x%lx-0x%lx\n", region->base, region->base + region->size - 1); + snd_printk(KERN_ERR "unable to request memory region 0x%lx-0x%lx\n", region->base, region->base + region->size - 1); snd_cs46xx_free(chip); return -EBUSY; } region->remap_addr = ioremap_nocache(region->base, region->size); if (region->remap_addr == NULL) { - snd_printk("%s ioremap problem\n", region->name); + snd_printk(KERN_ERR "%s ioremap problem\n", region->name); snd_cs46xx_free(chip); return -ENOMEM; } } if (request_irq(pci->irq, snd_cs46xx_interrupt, SA_INTERRUPT|SA_SHIRQ, "CS46XX", (void *) chip)) { - snd_printk("unable to grab IRQ %d\n", pci->irq); + snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_cs46xx_free(chip); return -EBUSY; } diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index b0e00f0a7c2f521380027254b8d35f0bc9c958b5..dd1ea9d3b81ae77a4d96555d9ecb4e9aca43ab5a 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -188,7 +188,7 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci, if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH, sizeof(snd_emu10k1_synth_arg_t), &wave) < 0 || wave == NULL) { - snd_printk("can't initialize Emu10k1 wavetable synth\n"); + snd_printk(KERN_WARNING "can't initialize Emu10k1 wavetable synth\n"); } else { snd_emu10k1_synth_arg_t *arg; arg = SNDRV_SEQ_DEVICE_ARGPTR(wave); diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c index 7cf2f908eed9aa6ae5449593234df104672b37ed..6589bf24abcda1bbe540db08a0ddd9d30d50c1f4 100644 --- a/sound/pci/emu10k1/emu10k1_callback.c +++ b/sound/pci/emu10k1/emu10k1_callback.c @@ -241,7 +241,7 @@ lookup_voices(snd_emux_t *emu, emu10k1_t *hw, best_voice_t *best, int active_onl else if (state == SNDRV_EMUX_ST_RELEASED || state == SNDRV_EMUX_ST_PENDING) { bp = best + V_RELEASED; -#if 0 +#if 1 val = snd_emu10k1_ptr_read(hw, CVCF_CURRENTVOL, vp->ch); if (! val) bp = best + V_OFF; @@ -349,7 +349,7 @@ start_voice(snd_emux_voice_t *vp) } /* channel to be silent and idle */ - snd_emu10k1_ptr_write(hw, DCYSUSV, ch, 0x0080); + snd_emu10k1_ptr_write(hw, DCYSUSV, ch, 0x0000); snd_emu10k1_ptr_write(hw, VTFT, ch, 0x0000FFFF); snd_emu10k1_ptr_write(hw, CVCF, ch, 0x0000FFFF); snd_emu10k1_ptr_write(hw, PTRX, ch, 0); diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index ad15755a63c35a788bfbfea7323461713cad7f1a..cbb689474e7d12297981e62b2d23883c5a9bd57e 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -759,10 +759,8 @@ static int snd_emu10k1x_free(emu10k1x_t *chip) outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); // release the i/o port - if (chip->res_port) { - release_resource(chip->res_port); - kfree_nocheck(chip->res_port); - } + release_and_free_resource(chip->res_port); + // release the irq if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 646b5d972e6f3b8cb0281eb6f6266395a750670e..03e8c16789527c217880b59a25cbb20e1a3c6223 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -364,12 +364,18 @@ static int snd_emu10k1_gpr_ctl_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, db_table[val]); break; case EMU10K1_GPR_TRANSLATION_BASS: - snd_runtime_check((ctl->count % 5) == 0 && (ctl->count / 5) == ctl->vcount, change = -EIO; goto __error); + if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) { + change = -EIO; + goto __error; + } for (j = 0; j < 5; j++) snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, bass_table[val][j]); break; case EMU10K1_GPR_TRANSLATION_TREBLE: - snd_runtime_check((ctl->count % 5) == 0 && (ctl->count / 5) == ctl->vcount, change = -EIO; goto __error); + if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) { + change = -EIO; + goto __error; + } for (j = 0; j < 5; j++) snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, treble_table[val][j]); break; @@ -412,8 +418,6 @@ int snd_emu10k1_fx8010_register_irq_handler(emu10k1_t *emu, snd_emu10k1_fx8010_irq_t *irq; unsigned long flags; - snd_runtime_check(emu, return -EINVAL); - snd_runtime_check(handler, return -EINVAL); irq = kmalloc(sizeof(*irq), GFP_ATOMIC); if (irq == NULL) return -ENOMEM; @@ -442,7 +446,6 @@ int snd_emu10k1_fx8010_unregister_irq_handler(emu10k1_t *emu, snd_emu10k1_fx8010_irq_t *tmp; unsigned long flags; - snd_runtime_check(irq, return -EINVAL); spin_lock_irqsave(&emu->fx8010.irq_lock, flags); if ((tmp = emu->fx8010.irq_handlers) == irq) { emu->fx8010.irq_handlers = tmp->next; @@ -717,9 +720,15 @@ static int snd_emu10k1_add_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode err = -EFAULT; goto __error; } - snd_runtime_check(gctl->id.iface == SNDRV_CTL_ELEM_IFACE_MIXER || - gctl->id.iface == SNDRV_CTL_ELEM_IFACE_PCM, err = -EINVAL; goto __error); - snd_runtime_check(gctl->id.name[0] != '\0', err = -EINVAL; goto __error); + if (gctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER && + gctl->id.iface != SNDRV_CTL_ELEM_IFACE_PCM) { + err = -EINVAL; + goto __error; + } + if (! gctl->id.name[0]) { + err = -EINVAL; + goto __error; + } ctl = snd_emu10k1_look_for_ctl(emu, &gctl->id); memset(&knew, 0, sizeof(knew)); knew.iface = gctl->id.iface; @@ -783,7 +792,8 @@ static int snd_emu10k1_del_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode for (i = 0, _id = icode->gpr_del_controls; i < icode->gpr_del_control_count; i++, _id++) { - snd_runtime_check(copy_from_user(&id, _id, sizeof(id)) == 0, return -EFAULT); + if (copy_from_user(&id, _id, sizeof(id))) + return -EFAULT; down_write(&card->controls_rwsem); ctl = snd_emu10k1_look_for_ctl(emu, &id); if (ctl) @@ -964,8 +974,8 @@ static int snd_emu10k1_ipcm_peek(emu10k1_t *emu, emu10k1_fx8010_pcm_t *ipcm) return err; } -#define SND_EMU10K1_GPR_CONTROLS 41 -#define SND_EMU10K1_INPUTS 10 +#define SND_EMU10K1_GPR_CONTROLS 44 +#define SND_EMU10K1_INPUTS 12 #define SND_EMU10K1_PLAYBACK_CHANNELS 8 #define SND_EMU10K1_CAPTURE_CHANNELS 4 @@ -1382,7 +1392,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) A_SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1); if ((z==1) && (emu->card_capabilities->spdif_bug)) { /* Due to a SPDIF output bug on some Audigy cards, this code delays the Right channel by 1 sample */ - snd_printk("Installing spdif_bug patch: %s\n", emu->card_capabilities->name); + snd_printk(KERN_INFO "Installing spdif_bug patch: %s\n", emu->card_capabilities->name); A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(gpr - 3), A_C_00000000, A_C_00000000); A_OP(icode, &ptr, iACC3, A_GPR(gpr - 3), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000); } else { @@ -1527,7 +1537,7 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu) strcpy(icode->name, "SB Live! FX8010 code for ALSA v1.2 by Jaroslav Kysela"); ptr = 0; i = 0; - /* we have 10 inputs */ + /* we have 12 inputs */ playback = SND_EMU10K1_INPUTS; /* we have 6 playback channels and tone control doubles */ capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); @@ -1551,6 +1561,8 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu) OP(icode, &ptr, iMACINT0, GPR(7), C_00000000, FXBUS(FXBUS_PCM_LFE), C_00000004); OP(icode, &ptr, iMACINT0, GPR(8), C_00000000, C_00000000, C_00000000); /* S/PDIF left */ OP(icode, &ptr, iMACINT0, GPR(9), C_00000000, C_00000000, C_00000000); /* S/PDIF right */ + OP(icode, &ptr, iMACINT0, GPR(10), C_00000000, FXBUS(FXBUS_PCM_LEFT_FRONT), C_00000004); + OP(icode, &ptr, iMACINT0, GPR(11), C_00000000, FXBUS(FXBUS_PCM_RIGHT_FRONT), C_00000004); /* Raw S/PDIF PCM */ ipcm->substream = 0; @@ -1697,6 +1709,21 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu) VOLUME_ADD(icode, &ptr, playback + 5, 7, gpr); snd_emu10k1_init_mono_control(controls + i++, "LFE Digital Playback Volume", gpr++, 100); + /* Front Playback Volume */ + for (z = 0; z < 2; z++) + VOLUME_ADD(icode, &ptr, playback + z, 10 + z, gpr + z); + snd_emu10k1_init_stereo_control(controls + i++, "Front Playback Volume", gpr, 100); + gpr += 2; + + /* Front Capture Volume + Switch */ + for (z = 0; z < 2; z++) { + SWITCH(icode, &ptr, tmp + 0, 10 + z, gpr + 2); + VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z); + } + snd_emu10k1_init_stereo_control(controls + i++, "Front Capture Volume", gpr, 0); + snd_emu10k1_init_mono_onoff_control(controls + i++, "Front Capture Switch", gpr + 2, 0); + gpr += 3; + /* * Process inputs */ @@ -2058,14 +2085,16 @@ void snd_emu10k1_free_efx(emu10k1_t *emu) #if 0 // FIXME: who use them? int snd_emu10k1_fx8010_tone_control_activate(emu10k1_t *emu, int output) { - snd_runtime_check(output >= 0 && output < 6, return -EINVAL); + if (output < 0 || output >= 6) + return -EINVAL; snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 1); return 0; } int snd_emu10k1_fx8010_tone_control_deactivate(emu10k1_t *emu, int output) { - snd_runtime_check(output >= 0 && output < 6, return -EINVAL); + if (output < 0 || output >= 6) + return -EINVAL; snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 0); return 0; } diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 66ba27afe962523ea14ef5589d9448c75e9c87f9..bf7490dae09b67f85b6016477f82ad153294f19f 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -965,7 +965,8 @@ static void snd_emu10k1_pcm_mixer_notify1(emu10k1_t *emu, snd_kcontrol_t *kctl, { snd_ctl_elem_id_t id; - snd_runtime_check(kctl != NULL, return); + if (! kctl) + return; if (activate) kctl->vd[idx].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; else diff --git a/sound/pci/emu10k1/irq.c b/sound/pci/emu10k1/irq.c index cd8460d56752d4edfb53a5415111835b7787b5e9..594ea063b1406e29094b29b60802c34c105b307d 100644 --- a/sound/pci/emu10k1/irq.c +++ b/sound/pci/emu10k1/irq.c @@ -41,7 +41,7 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) orig_status = status; handled = 1; if (status & IPR_PCIERROR) { - snd_printk("interrupt: PCI error\n"); + snd_printk(KERN_ERR "interrupt: PCI error\n"); snd_emu10k1_intr_disable(emu, INTE_PCIERRORENABLE); status &= ~IPR_PCIERROR; } diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index 6afeaeab3e13028fea3538084425435485edce5a..d42e4aeaa73a3c081174cbb4bdc7b1f494c42f81 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -232,11 +232,11 @@ search_empty(emu10k1_t *emu, int size) static int is_valid_page(emu10k1_t *emu, dma_addr_t addr) { if (addr & ~emu->dma_mask) { - snd_printk("max memory size is 0x%lx (addr = 0x%lx)!!\n", emu->dma_mask, (unsigned long)addr); + snd_printk(KERN_ERR "max memory size is 0x%lx (addr = 0x%lx)!!\n", emu->dma_mask, (unsigned long)addr); return 0; } if (addr & (EMUPAGESIZE-1)) { - snd_printk("page is not aligned\n"); + snd_printk(KERN_ERR "page is not aligned\n"); return 0; } return 1; @@ -501,7 +501,7 @@ static inline void *offset_ptr(emu10k1_t *emu, int page, int offset) snd_assert(page >= 0 && page < emu->max_cache_pages, return NULL); ptr = emu->page_ptr_table[page]; if (! ptr) { - printk("emu10k1: access to NULL ptr: page = %d\n", page); + printk(KERN_ERR "emu10k1: access to NULL ptr: page = %d\n", page); return NULL; } ptr += offset & (PAGE_SIZE - 1); diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index d59c7f345ad6983eeadf1bbe5ca5b4e287389b9d..e27ebb9bb74a2ecb0ab0cb5a314cde1d2dedb4bb 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -546,7 +546,7 @@ snd_p16v_pcm_pointer_capture(snd_pcm_substream_t *substream) ptr=ptr2; if (ptr >= runtime->buffer_size) { ptr -= runtime->buffer_size; - printk("buffer capture limited!\n"); + printk(KERN_WARNING "buffer capture limited!\n"); } //printk("ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", ptr1, ptr2, ptr, (int)runtime->buffer_size, (int)runtime->period_size, (int)runtime->frame_bits, (int)runtime->rate); diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index bef9a59f46d7d4d2adfc26fc29a396f9c9eb33c0..92ff7c510f2b8453705c5eefccdcbef454e7a3c2 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -508,7 +508,7 @@ static unsigned int snd_es1371_wait_src_ready(ensoniq_t * ensoniq) return r; cond_resched(); } - snd_printk("wait source ready timeout 0x%lx [0x%x]\n", ES_REG(ensoniq, 1371_SMPRATE), r); + snd_printk(KERN_ERR "wait source ready timeout 0x%lx [0x%x]\n", ES_REG(ensoniq, 1371_SMPRATE), r); return 0; } @@ -576,10 +576,9 @@ static void snd_es1370_codec_write(ak4531_t *ak4531, outw(ES_1370_CODEC_WRITE(reg, val), ES_REG(ensoniq, 1370_CODEC)); return; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_after(end_time, jiffies)); - snd_printk("codec write timeout, status = 0x%x\n", inl(ES_REG(ensoniq, STATUS))); + snd_printk(KERN_ERR "codec write timeout, status = 0x%x\n", inl(ES_REG(ensoniq, STATUS))); } #endif /* CHIP1370 */ @@ -620,7 +619,7 @@ static void snd_es1371_codec_write(ac97_t *ac97, } } up(&ensoniq->src_mutex); - snd_printk("codec write timeout at 0x%lx [0x%x]\n", ES_REG(ensoniq, 1371_CODEC), inl(ES_REG(ensoniq, 1371_CODEC))); + snd_printk(KERN_ERR "codec write timeout at 0x%lx [0x%x]\n", ES_REG(ensoniq, 1371_CODEC), inl(ES_REG(ensoniq, 1371_CODEC))); } static unsigned short snd_es1371_codec_read(ac97_t *ac97, @@ -667,14 +666,14 @@ static unsigned short snd_es1371_codec_read(ac97_t *ac97, } up(&ensoniq->src_mutex); if (++fail > 10) { - snd_printk("codec read timeout (final) at 0x%lx, reg = 0x%x [0x%x]\n", ES_REG(ensoniq, 1371_CODEC), reg, inl(ES_REG(ensoniq, 1371_CODEC))); + snd_printk(KERN_ERR "codec read timeout (final) at 0x%lx, reg = 0x%x [0x%x]\n", ES_REG(ensoniq, 1371_CODEC), reg, inl(ES_REG(ensoniq, 1371_CODEC))); return 0; } goto __again; } } up(&ensoniq->src_mutex); - snd_printk("es1371: codec read timeout at 0x%lx [0x%x]\n", ES_REG(ensoniq, 1371_CODEC), inl(ES_REG(ensoniq, 1371_CODEC))); + snd_printk(KERN_ERR "es1371: codec read timeout at 0x%lx [0x%x]\n", ES_REG(ensoniq, 1371_CODEC), inl(ES_REG(ensoniq, 1371_CODEC))); return 0; } @@ -1960,7 +1959,7 @@ static int __devinit snd_ensoniq_create(snd_card_t * card, } ensoniq->port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_audiopci_interrupt, SA_INTERRUPT|SA_SHIRQ, "Ensoniq AudioPCI", (void *)ensoniq)) { - snd_printk("unable to grab IRQ %d\n", pci->irq); + snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_ensoniq_free(ensoniq); return -EBUSY; } @@ -1968,7 +1967,7 @@ static int __devinit snd_ensoniq_create(snd_card_t * card, #ifdef CHIP1370 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 16, &ensoniq->dma_bug) < 0) { - snd_printk("unable to allocate space for phantom area - dma_bug\n"); + snd_printk(KERN_ERR "unable to allocate space for phantom area - dma_bug\n"); snd_ensoniq_free(ensoniq); return -EBUSY; } diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 17fa80c23870b8631b6b2a40d5269ee0d2d531c9..78f90defcab185eca25ac430d8b6c21c69489ea3 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -267,7 +267,7 @@ static void snd_es1938_mixer_write(es1938_t *chip, unsigned char reg, unsigned c outb(val, SLSB_REG(chip, MIXERDATA)); spin_unlock_irqrestore(&chip->mixer_lock, flags); #ifdef REG_DEBUG - snd_printk("Mixer reg %02x set to %02x\n", reg, val); + snd_printk(KERN_DEBUG "Mixer reg %02x set to %02x\n", reg, val); #endif } @@ -283,7 +283,7 @@ static int snd_es1938_mixer_read(es1938_t *chip, unsigned char reg) data = inb(SLSB_REG(chip, MIXERDATA)); spin_unlock_irqrestore(&chip->mixer_lock, flags); #ifdef REG_DEBUG - snd_printk("Mixer reg %02x now is %02x\n", reg, data); + snd_printk(KERN_DEBUG "Mixer reg %02x now is %02x\n", reg, data); #endif return data; } @@ -303,7 +303,8 @@ static int snd_es1938_mixer_bits(es1938_t *chip, unsigned char reg, unsigned cha new = (old & ~mask) | (val & mask); outb(new, SLSB_REG(chip, MIXERDATA)); #ifdef REG_DEBUG - snd_printk("Mixer reg %02x was %02x, set to %02x\n", reg, old, new); + snd_printk(KERN_DEBUG "Mixer reg %02x was %02x, set to %02x\n", + reg, old, new); #endif } spin_unlock_irqrestore(&chip->mixer_lock, flags); @@ -323,7 +324,7 @@ static void snd_es1938_write_cmd(es1938_t *chip, unsigned char cmd) return; } } - printk("snd_es1938_write_cmd timeout (0x02%x/0x02%x)\n", cmd, v); + printk(KERN_ERR "snd_es1938_write_cmd timeout (0x02%x/0x02%x)\n", cmd, v); } /* ----------------------------------------------------------------- @@ -336,7 +337,7 @@ static int snd_es1938_get_byte(es1938_t *chip) for (i = GET_LOOP_TIMEOUT; i; i--) if ((v = inb(SLSB_REG(chip, STATUS))) & 0x80) return inb(SLSB_REG(chip, READDATA)); - snd_printk("get_byte timeout: status 0x02%x\n", v); + snd_printk(KERN_ERR "get_byte timeout: status 0x02%x\n", v); return -ENODEV; } @@ -351,7 +352,7 @@ static void snd_es1938_write(es1938_t *chip, unsigned char reg, unsigned char va snd_es1938_write_cmd(chip, val); spin_unlock_irqrestore(&chip->reg_lock, flags); #ifdef REG_DEBUG - snd_printk("Reg %02x set to %02x\n", reg, val); + snd_printk(KERN_DEBUG "Reg %02x set to %02x\n", reg, val); #endif } @@ -368,7 +369,7 @@ static unsigned char snd_es1938_read(es1938_t *chip, unsigned char reg) val = snd_es1938_get_byte(chip); spin_unlock_irqrestore(&chip->reg_lock, flags); #ifdef REG_DEBUG - snd_printk("Reg %02x now is %02x\n", reg, val); + snd_printk(KERN_DEBUG "Reg %02x now is %02x\n", reg, val); #endif return val; } @@ -390,7 +391,8 @@ static int snd_es1938_bits(es1938_t *chip, unsigned char reg, unsigned char mask new = (old & ~mask) | (val & mask); snd_es1938_write_cmd(chip, new); #ifdef REG_DEBUG - snd_printk("Reg %02x was %02x, set to %02x\n", reg, old, new); + snd_printk(KERN_DEBUG "Reg %02x was %02x, set to %02x\n", + reg, old, new); #endif } spin_unlock_irqrestore(&chip->reg_lock, flags); @@ -413,7 +415,7 @@ static void snd_es1938_reset(es1938_t *chip) goto __next; } } - snd_printk("ESS Solo-1 reset failed\n"); + snd_printk(KERN_ERR "ESS Solo-1 reset failed\n"); __next: snd_es1938_write_cmd(chip, ESS_CMD_ENABLEEXT); @@ -543,10 +545,12 @@ static int snd_es1938_capture_trigger(snd_pcm_substream_t * substream, int val; switch (cmd) { case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: val = 0x0f; chip->active |= ADC1; break; case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: val = 0x00; chip->active &= ~ADC1; break; @@ -563,6 +567,7 @@ static int snd_es1938_playback1_trigger(snd_pcm_substream_t * substream, es1938_t *chip = snd_pcm_substream_chip(substream); switch (cmd) { case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: /* According to the documentation this should be: 0x13 but that value may randomly swap stereo channels */ snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2CONTROL1, 0x92); @@ -575,6 +580,7 @@ static int snd_es1938_playback1_trigger(snd_pcm_substream_t * substream, chip->active |= DAC2; break; case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: outb(0, SLIO_REG(chip, AUDIO2MODE)); snd_es1938_mixer_write(chip, ESSSB_IREG_AUDIO2CONTROL1, 0); chip->active &= ~DAC2; @@ -592,10 +598,12 @@ static int snd_es1938_playback2_trigger(snd_pcm_substream_t * substream, int val; switch (cmd) { case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: val = 5; chip->active |= DAC1; break; case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: val = 0; chip->active &= ~DAC1; break; @@ -1390,7 +1398,8 @@ static int es1938_suspend(snd_card_t *card, pm_message_t state) *d = snd_es1938_reg_read(chip, *s); outb(0x00, SLIO_REG(chip, IRQCONTROL)); /* disable irqs */ - + if (chip->irq >= 0) + free_irq(chip->irq, (void *)chip); pci_disable_device(chip->pci); return 0; } @@ -1401,6 +1410,9 @@ static int es1938_resume(snd_card_t *card) unsigned char *s, *d; pci_enable_device(chip->pci); + request_irq(chip->pci->irq, snd_es1938_interrupt, + SA_INTERRUPT|SA_SHIRQ, "ES1938", (void *)chip); + chip->irq = chip->pci->irq; snd_es1938_chip_init(chip); /* restore mixer-related registers */ @@ -1489,7 +1501,7 @@ static int __devinit snd_es1938_create(snd_card_t * card, /* check, if we can restrict PCI DMA transfers to 24 bits */ if (pci_set_dma_mask(pci, 0x00ffffff) < 0 || pci_set_consistent_dma_mask(pci, 0x00ffffff) < 0) { - snd_printk("architecture does not support 24bit PCI busmaster DMA\n"); + snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -1514,13 +1526,13 @@ static int __devinit snd_es1938_create(snd_card_t * card, chip->mpu_port = pci_resource_start(pci, 3); chip->game_port = pci_resource_start(pci, 4); if (request_irq(pci->irq, snd_es1938_interrupt, SA_INTERRUPT|SA_SHIRQ, "ES1938", (void *)chip)) { - snd_printk("unable to grab IRQ %d\n", pci->irq); + snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_es1938_free(chip); return -EBUSY; } chip->irq = pci->irq; #ifdef ES1938_DDEBUG - snd_printk("create: io: 0x%lx, sb: 0x%lx, vc: 0x%lx, mpu: 0x%lx, game: 0x%lx\n", + snd_printk(KERN_DEBUG "create: io: 0x%lx, sb: 0x%lx, vc: 0x%lx, mpu: 0x%lx, game: 0x%lx\n", chip->io_port, chip->sb_port, chip->vc_port, chip->mpu_port, chip->game_port); #endif diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index ecdcada90ca25945923a938472e506400344fcd6..ac8294e21cc17eeb8ee3a28fe747ba49bdea461b 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -1462,13 +1462,13 @@ snd_es1968_init_dmabuf(es1968_t *chip) snd_dma_pci_data(chip->pci), chip->total_bufsize, &chip->dma); if (err < 0 || ! chip->dma.area) { - snd_printk("es1968: can't allocate dma pages for size %d\n", + snd_printk(KERN_ERR "es1968: can't allocate dma pages for size %d\n", chip->total_bufsize); return -ENOMEM; } if ((chip->dma.addr + chip->dma.bytes - 1) & ~((1 << 28) - 1)) { snd_dma_free_pages(&chip->dma); - snd_printk("es1968: DMA buffer beyond 256MB.\n"); + snd_printk(KERN_ERR "es1968: DMA buffer beyond 256MB.\n"); return -ENOMEM; } } @@ -1741,11 +1741,11 @@ static void __devinit es1968_measure_clock(es1968_t *chip) /* search 2 APUs (although one apu is enough) */ if ((apu = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_PLAY)) < 0) { - snd_printk("Hmm, cannot find empty APU pair!?\n"); + snd_printk(KERN_ERR "Hmm, cannot find empty APU pair!?\n"); return; } if ((memory = snd_es1968_new_memory(chip, CLOCK_MEASURE_BUFSIZE)) == NULL) { - snd_printk("cannot allocate dma buffer - using default clock %d\n", chip->clock); + snd_printk(KERN_ERR "cannot allocate dma buffer - using default clock %d\n", chip->clock); snd_es1968_free_apu_pair(chip, apu); return; } @@ -1806,7 +1806,7 @@ static void __devinit es1968_measure_clock(es1968_t *chip) else t += stop_time.tv_usec - start_time.tv_usec; if (t == 0) { - snd_printk("?? calculation error..\n"); + snd_printk(KERN_ERR "?? calculation error..\n"); } else { offset *= 1000; offset = (offset / t) * 1000 + ((offset % t) * 1000) / t; @@ -2090,7 +2090,7 @@ static void snd_es1968_ac97_reset(es1968_t *chip) outw(inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c); #if 0 /* the loop here needs to be much better if we want it.. */ - snd_printk("trying software reset\n"); + snd_printk(KERN_INFO "trying software reset\n"); /* try and do a software reset */ outb(0x80 | 0x7c, ioaddr + 0x30); for (w = 0;; w++) { @@ -2461,8 +2461,7 @@ static int __devinit snd_es1968_create_gameport(es1968_t *chip, int dev) chip->gameport = gp = gameport_allocate_port(); if (!gp) { printk(KERN_ERR "es1968: cannot allocate memory for gameport\n"); - release_resource(r); - kfree_nocheck(r); + release_and_free_resource(r); return -ENOMEM; } @@ -2488,8 +2487,7 @@ static void snd_es1968_free_gameport(es1968_t *chip) gameport_unregister_port(chip->gameport); chip->gameport = NULL; - release_resource(r); - kfree_nocheck(r); + release_and_free_resource(r); } } #else @@ -2564,7 +2562,7 @@ static int __devinit snd_es1968_create(snd_card_t * card, /* check, if we can restrict PCI DMA transfers to 28 bits */ if (pci_set_dma_mask(pci, 0x0fffffff) < 0 || pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) { - snd_printk("architecture does not support 28bit PCI busmaster DMA\n"); + snd_printk(KERN_ERR "architecture does not support 28bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -2599,7 +2597,7 @@ static int __devinit snd_es1968_create(snd_card_t * card, chip->io_port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_es1968_interrupt, SA_INTERRUPT|SA_SHIRQ, "ESS Maestro", (void*)chip)) { - snd_printk("unable to grab IRQ %d\n", pci->irq); + snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_es1968_free(chip); return -EBUSY; } diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index e5cfa2a0c24639cdf4354e7e2aa30771ec6a63b0..4c7c8d225c7f69825e77b9261675eddd5208b416 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -237,7 +237,7 @@ static void snd_fm801_codec_write(ac97_t *ac97, goto ok1; udelay(10); } - snd_printk("AC'97 interface is busy (1)\n"); + snd_printk(KERN_ERR "AC'97 interface is busy (1)\n"); return; ok1: @@ -252,7 +252,7 @@ static void snd_fm801_codec_write(ac97_t *ac97, return; udelay(10); } - snd_printk("AC'97 interface #%d is busy (2)\n", ac97->num); + snd_printk(KERN_ERR "AC'97 interface #%d is busy (2)\n", ac97->num); } static unsigned short snd_fm801_codec_read(ac97_t *ac97, unsigned short reg) @@ -268,7 +268,7 @@ static unsigned short snd_fm801_codec_read(ac97_t *ac97, unsigned short reg) goto ok1; udelay(10); } - snd_printk("AC'97 interface is busy (1)\n"); + snd_printk(KERN_ERR "AC'97 interface is busy (1)\n"); return 0; ok1: @@ -279,7 +279,7 @@ static unsigned short snd_fm801_codec_read(ac97_t *ac97, unsigned short reg) goto ok2; udelay(10); } - snd_printk("AC'97 interface #%d is busy (2)\n", ac97->num); + snd_printk(KERN_ERR "AC'97 interface #%d is busy (2)\n", ac97->num); return 0; ok2: @@ -288,7 +288,7 @@ static unsigned short snd_fm801_codec_read(ac97_t *ac97, unsigned short reg) goto ok3; udelay(10); } - snd_printk("AC'97 interface #%d is not valid (2)\n", ac97->num); + snd_printk(KERN_ERR "AC'97 interface #%d is not valid (2)\n", ac97->num); return 0; ok3: @@ -1279,7 +1279,7 @@ static int __devinit snd_fm801_create(snd_card_t * card, } chip->port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_fm801_interrupt, SA_INTERRUPT|SA_SHIRQ, "FM801", (void *)chip)) { - snd_printk("unable to grab IRQ %d\n", chip->irq); + snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq); snd_fm801_free(chip); return -EBUSY; } @@ -1303,10 +1303,9 @@ static int __devinit snd_fm801_create(snd_card_t * card, do { if ((inw(FM801_REG(chip, AC97_CMD)) & (3<<8)) == (1<<8)) goto __ac97_secondary; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_after(timeout, jiffies)); - snd_printk("Primary AC'97 codec not found\n"); + snd_printk(KERN_ERR "Primary AC'97 codec not found\n"); snd_fm801_free(chip); return -EIO; @@ -1329,8 +1328,7 @@ static int __devinit snd_fm801_create(snd_card_t * card, goto __ac97_ok; } } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_after(timeout, jiffies)); } @@ -1343,10 +1341,9 @@ static int __devinit snd_fm801_create(snd_card_t * card, do { if ((inw(FM801_REG(chip, AC97_CMD)) & (3<<8)) == (1<<8)) goto __ac97_ok; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_after(timeout, jiffies)); - snd_printk("Primary AC'97 codec not responding\n"); + snd_printk(KERN_ERR "Primary AC'97 codec not responding\n"); snd_fm801_free(chip); return -EIO; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 3815403ed0953249418e2dc86ddf227833cf4970..0dbeeaf6113af4c36aa1a55077a3096bf45b44ac 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -518,6 +518,13 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, return -ENODEV; } + if (! codec->subsystem_id) { + hda_nid_t nid = codec->afg ? codec->afg : codec->mfg; + codec->subsystem_id = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_SUBSYSTEM_ID, + 0); + } + codec->preset = find_codec_preset(codec); if (! *bus->card->mixername) snd_hda_get_codec_name(codec, bus->card->mixername, @@ -813,6 +820,51 @@ int snd_hda_mixer_amp_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t return change; } +/* + * bound volume controls + * + * bind multiple volumes (# indices, from 0) + */ + +#define AMP_VAL_IDX_SHIFT 19 +#define AMP_VAL_IDX_MASK (0x0f<<19) + +int snd_hda_mixer_bind_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned long pval; + int err; + + down(&codec->spdif_mutex); /* reuse spdif_mutex */ + pval = kcontrol->private_value; + kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ + err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); + kcontrol->private_value = pval; + up(&codec->spdif_mutex); + return err; +} + +int snd_hda_mixer_bind_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned long pval; + int i, indices, err = 0, change = 0; + + down(&codec->spdif_mutex); /* reuse spdif_mutex */ + pval = kcontrol->private_value; + indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT; + for (i = 0; i < indices; i++) { + kcontrol->private_value = (pval & ~AMP_VAL_IDX_MASK) | (i << AMP_VAL_IDX_SHIFT); + err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); + if (err < 0) + break; + change |= err; + } + kcontrol->private_value = pval; + up(&codec->spdif_mutex); + return err < 0 ? err : change; +} + /* * SPDIF out controls */ diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index bb53bcf76742ed1ccc77078e2efb4c2cdc275a40..1179d6cfa82a3ae20a36c03c14cecad07494d3a2 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -79,6 +79,8 @@ enum { #define AC_VERB_GET_GPIO_MASK 0x0f16 #define AC_VERB_GET_GPIO_DIRECTION 0x0f17 #define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c +/* f20: AFG/MFG */ +#define AC_VERB_GET_SUBSYSTEM_ID 0x0f20 /* * SET verbs diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 6fe696e53ea6a791494bee31f030f5c613410d11..9d1412a9f2f85f0d93c63913a3cb9eb790b4fd5f 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -47,23 +47,24 @@ #include "hda_codec.h" -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; -static char *model[SNDRV_CARDS]; -static int position_fix[SNDRV_CARDS]; +static int index = SNDRV_DEFAULT_IDX1; +static char *id = SNDRV_DEFAULT_STR1; +static char *model; +static int position_fix; -module_param_array(index, int, NULL, 0444); +module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); -module_param_array(id, charp, NULL, 0444); +module_param(id, charp, 0444); MODULE_PARM_DESC(id, "ID string for Intel HD audio interface."); -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable Intel HD audio interface."); -module_param_array(model, charp, NULL, 0444); +module_param(model, charp, 0444); MODULE_PARM_DESC(model, "Use the given board model."); -module_param_array(position_fix, int, NULL, 0444); +module_param(position_fix, int, 0444); MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)."); +/* just for backward compatibility */ +static int enable; +module_param(enable, bool, 0444); + MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," "{Intel, ICH6M}," @@ -223,6 +224,9 @@ enum { #define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42 #define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02 +/* Defines for Nvidia HDA support */ +#define NVIDIA_HDA_TRANSREG_ADDR 0x4e +#define NVIDIA_HDA_ENABLE_COHBITS 0x0f /* * Use CORB/RIRB for communication from/to codecs. @@ -328,6 +332,7 @@ enum { AZX_DRIVER_VIA, AZX_DRIVER_SIS, AZX_DRIVER_ULI, + AZX_DRIVER_NVIDIA, }; static char *driver_short_names[] __devinitdata = { @@ -335,7 +340,8 @@ static char *driver_short_names[] __devinitdata = { [AZX_DRIVER_ATI] = "HDA ATI SB", [AZX_DRIVER_VIA] = "HDA VIA VT82xx", [AZX_DRIVER_SIS] = "HDA SIS966", - [AZX_DRIVER_ULI] = "HDA ULI M5461" + [AZX_DRIVER_ULI] = "HDA ULI M5461", + [AZX_DRIVER_NVIDIA] = "HDA NVidia", }; /* @@ -710,14 +716,14 @@ static void azx_stream_stop(azx_t *chip, azx_dev_t *azx_dev) */ static void azx_init_chip(azx_t *chip) { - unsigned char tcsel_reg, ati_misc_cntl2; + unsigned char reg; /* Clear bits 0-2 of PCI register TCSEL (at offset 0x44) * TCSEL == Traffic Class Select Register, which sets PCI express QOS * Ensuring these bits are 0 clears playback static on some HD Audio codecs */ - pci_read_config_byte (chip->pci, ICH6_PCIREG_TCSEL, &tcsel_reg); - pci_write_config_byte(chip->pci, ICH6_PCIREG_TCSEL, tcsel_reg & 0xf8); + pci_read_config_byte (chip->pci, ICH6_PCIREG_TCSEL, ®); + pci_write_config_byte(chip->pci, ICH6_PCIREG_TCSEL, reg & 0xf8); /* reset controller */ azx_reset(chip); @@ -733,13 +739,21 @@ static void azx_init_chip(azx_t *chip) azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); - /* For ATI SB450 azalia HD audio, we need to enable snoop */ - if (chip->driver_type == AZX_DRIVER_ATI) { + switch (chip->driver_type) { + case AZX_DRIVER_ATI: + /* For ATI SB450 azalia HD audio, we need to enable snoop */ pci_read_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, - &ati_misc_cntl2); + ®); pci_write_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, - (ati_misc_cntl2 & 0xf8) | ATI_SB450_HDAUDIO_ENABLE_SNOOP); - } + (reg & 0xf8) | ATI_SB450_HDAUDIO_ENABLE_SNOOP); + break; + case AZX_DRIVER_NVIDIA: + /* For NVIDIA HDA, enable snoop */ + pci_read_config_byte(chip->pci,NVIDIA_HDA_TRANSREG_ADDR, ®); + pci_write_config_byte(chip->pci,NVIDIA_HDA_TRANSREG_ADDR, + (reg & 0xf0) | NVIDIA_HDA_ENABLE_COHBITS); + break; + } } @@ -1264,6 +1278,7 @@ static int __devinit azx_pcm_create(azx_t *chip) err = create_codec_pcm(chip, codec, &codec->pcm_info[c], pcm_dev); if (err < 0) return err; + chip->pcm[pcm_dev]->dev_class = SNDRV_PCM_CLASS_MODEM; pcm_dev++; } } @@ -1530,32 +1545,24 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { - static int dev; snd_card_t *card; azx_t *chip; int err = 0; - if (dev >= SNDRV_CARDS) - return -ENODEV; - if (! enable[dev]) { - dev++; - return -ENOENT; - } - - card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + card = snd_card_new(index, id, THIS_MODULE, 0); if (NULL == card) { snd_printk(KERN_ERR SFX "Error creating card!\n"); return -ENOMEM; } - if ((err = azx_create(card, pci, position_fix[dev], pci_id->driver_data, + if ((err = azx_create(card, pci, position_fix, pci_id->driver_data, &chip)) < 0) { snd_card_free(card); return err; } /* create codec instances */ - if ((err = azx_codec_create(chip, model[dev])) < 0) { + if ((err = azx_codec_create(chip, model)) < 0) { snd_card_free(card); return err; } @@ -1581,7 +1588,6 @@ static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id * } pci_set_drvdata(pci, card); - dev++; return err; } @@ -1601,6 +1607,8 @@ static struct pci_device_id azx_ids[] = { { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */ { 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */ { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */ + { 0x10de, 0x026c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA 026c */ + { 0x10de, 0x0371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA 0371 */ { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 810cfd2d9bba29b99d6726edb2fb301a69f534ed..f51a56f813c8f47e348a76ea9383148598e6b716 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -27,28 +27,36 @@ * for mixer controls */ #define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) ((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19)) +/* mono volume with index (index=0,1,...) (channel=1,2) */ #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ .info = snd_hda_mixer_amp_volume_info, \ .get = snd_hda_mixer_amp_volume_get, \ .put = snd_hda_mixer_amp_volume_put, \ .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) } +/* stereo volume with index */ #define HDA_CODEC_VOLUME_IDX(xname, xcidx, nid, xindex, direction) \ HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, 3, xindex, direction) +/* mono volume */ #define HDA_CODEC_VOLUME_MONO(xname, nid, channel, xindex, direction) \ HDA_CODEC_VOLUME_MONO_IDX(xname, 0, nid, channel, xindex, direction) +/* stereo volume */ #define HDA_CODEC_VOLUME(xname, nid, xindex, direction) \ HDA_CODEC_VOLUME_MONO(xname, nid, 3, xindex, direction) +/* mono mute switch with index (index=0,1,...) (channel=1,2) */ #define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ .info = snd_hda_mixer_amp_switch_info, \ .get = snd_hda_mixer_amp_switch_get, \ .put = snd_hda_mixer_amp_switch_put, \ .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) } +/* stereo mute switch with index */ #define HDA_CODEC_MUTE_IDX(xname, xcidx, nid, xindex, direction) \ HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, 3, xindex, direction) +/* mono mute switch */ #define HDA_CODEC_MUTE_MONO(xname, nid, channel, xindex, direction) \ HDA_CODEC_MUTE_MONO_IDX(xname, 0, nid, channel, xindex, direction) +/* stereo mute switch */ #define HDA_CODEC_MUTE(xname, nid, xindex, direction) \ HDA_CODEC_MUTE_MONO(xname, nid, 3, xindex, direction) @@ -59,6 +67,20 @@ int snd_hda_mixer_amp_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t int snd_hda_mixer_amp_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol); int snd_hda_mixer_amp_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol); +/* mono switch binding multiple inputs */ +#define HDA_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ + .info = snd_hda_mixer_amp_switch_info, \ + .get = snd_hda_mixer_bind_switch_get, \ + .put = snd_hda_mixer_bind_switch_put, \ + .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, indices, direction) } + +/* stereo switch binding multiple inputs */ +#define HDA_BIND_MUTE(xname,nid,indices,dir) HDA_BIND_MUTE_MONO(xname,nid,3,indices,dir) + +int snd_hda_mixer_bind_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol); +int snd_hda_mixer_bind_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol); + int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid); int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid); diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 08f6a6efc5e6b75212c2a9c62a2c6a9e735c742d..39ddf1cd901901bab6c19b07b208f7f1480126b8 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -281,6 +281,11 @@ static void print_codec_info(snd_info_entry_t *entry, snd_info_buffer_t *buffer) print_pcm_caps(buffer, codec, nid); } + if (wid_caps & AC_WCAP_POWER) + snd_iprintf(buffer, " Power: 0x%x\n", + snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_POWER_STATE, 0)); + if (wid_caps & AC_WCAP_CONN_LIST) { int c, curr = -1; if (conn_len > 1 && wid_type != AC_WID_AUD_MIX) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index da6874d3988cfdb44dd3d11ec07cbfaf97f3890b..d7d636decef86a92de85238529d0dd5b1ec557e9 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -28,15 +28,38 @@ #include "hda_local.h" struct ad198x_spec { - struct semaphore amp_mutex; /* PCM volume/mute control mutex */ - struct hda_multi_out multiout; /* playback */ - hda_nid_t adc_nid; + snd_kcontrol_new_t *mixers[5]; + int num_mixers; + + const struct hda_verb *init_verbs[3]; /* initialization verbs + * don't forget NULL termination! + */ + unsigned int num_init_verbs; + + /* playback */ + struct hda_multi_out multiout; /* playback set-up + * max_channels, dacs must be set + * dig_out_nid and hp_nid are optional + */ + + /* capture */ + unsigned int num_adc_nids; + hda_nid_t *adc_nids; + hda_nid_t dig_in_nid; /* digital-in NID; optional */ + + /* capture source */ const struct hda_input_mux *input_mux; - unsigned int cur_mux; /* capture source */ + unsigned int cur_mux[3]; + + /* channel model */ + const struct alc_channel_mode *channel_mode; + int num_channel_mode; + + /* PCM information */ + struct hda_pcm pcm_rec[2]; /* used in alc_build_pcms() */ + + struct semaphore amp_mutex; /* PCM volume/mute control mutex */ unsigned int spdif_route; - snd_kcontrol_new_t *mixers; - const struct hda_verb *init_verbs; - struct hda_pcm pcm_rec[2]; /* PCM information */ }; /* @@ -54,8 +77,9 @@ static int ad198x_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ad198x_spec *spec = codec->spec; + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - ucontrol->value.enumerated.item[0] = spec->cur_mux; + ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; return 0; } @@ -63,9 +87,10 @@ static int ad198x_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ad198x_spec *spec = codec->spec; + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, - spec->adc_nid, &spec->cur_mux); + spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]); } /* @@ -74,22 +99,34 @@ static int ad198x_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u static int ad198x_init(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; - snd_hda_sequence_write(codec, spec->init_verbs); + int i; + + for (i = 0; i < spec->num_init_verbs; i++) + snd_hda_sequence_write(codec, spec->init_verbs[i]); return 0; } static int ad198x_build_controls(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; + unsigned int i; int err; - err = snd_hda_add_new_ctls(codec, spec->mixers); - if (err < 0) - return err; - if (spec->multiout.dig_out_nid) + for (i = 0; i < spec->num_mixers; i++) { + err = snd_hda_add_new_ctls(codec, spec->mixers[i]); + if (err < 0) + return err; + } + if (spec->multiout.dig_out_nid) { err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); - if (err < 0) - return err; + if (err < 0) + return err; + } + if (spec->dig_in_nid) { + err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); + if (err < 0) + return err; + } return 0; } @@ -152,7 +189,8 @@ static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo, snd_pcm_substream_t *substream) { struct ad198x_spec *spec = codec->spec; - snd_hda_codec_setup_stream(codec, spec->adc_nid, stream_tag, 0, format); + snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], + stream_tag, 0, format); return 0; } @@ -161,7 +199,8 @@ static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, snd_pcm_substream_t *substream) { struct ad198x_spec *spec = codec->spec; - snd_hda_codec_setup_stream(codec, spec->adc_nid, 0, 0, 0); + snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], + 0, 0, 0); return 0; } @@ -171,7 +210,7 @@ static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, static struct hda_pcm_stream ad198x_pcm_analog_playback = { .substreams = 1, .channels_min = 2, - .channels_max = 6, + .channels_max = 6, /* changed later */ .nid = 0, /* fill later */ .ops = { .open = ad198x_playback_pcm_open, @@ -181,7 +220,7 @@ static struct hda_pcm_stream ad198x_pcm_analog_playback = { }; static struct hda_pcm_stream ad198x_pcm_analog_capture = { - .substreams = 2, + .substreams = 1, .channels_min = 2, .channels_max = 2, .nid = 0, /* fill later */ @@ -202,6 +241,13 @@ static struct hda_pcm_stream ad198x_pcm_digital_playback = { }, }; +static struct hda_pcm_stream ad198x_pcm_digital_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in alc_build_pcms */ +}; + static int ad198x_build_pcms(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; @@ -215,7 +261,8 @@ static int ad198x_build_pcms(struct hda_codec *codec) info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nid; + info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; if (spec->multiout.dig_out_nid) { info++; @@ -223,6 +270,10 @@ static int ad198x_build_pcms(struct hda_codec *codec) info->name = "AD198x Digital"; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; + if (spec->dig_in_nid) { + info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; + } } return 0; @@ -237,10 +288,15 @@ static void ad198x_free(struct hda_codec *codec) static int ad198x_resume(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; + int i; ad198x_init(codec); - snd_hda_resume_ctls(codec, spec->mixers); - snd_hda_resume_spdif_out(codec); + for (i = 0; i < spec->num_mixers; i++) + snd_hda_resume_ctls(codec, spec->mixers[i]); + if (spec->multiout.dig_out_nid) + snd_hda_resume_spdif_out(codec); + if (spec->dig_in_nid) + snd_hda_resume_spdif_in(codec); return 0; } #endif @@ -269,6 +325,7 @@ static struct hda_codec_ops ad198x_patch_ops = { static hda_nid_t ad1986a_dac_nids[3] = { AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC }; +static hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC }; static struct hda_input_mux ad1986a_capture_source = { .num_items = 7, @@ -476,10 +533,13 @@ static int patch_ad1986a(struct hda_codec *codec) spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids); spec->multiout.dac_nids = ad1986a_dac_nids; spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT; - spec->adc_nid = AD1986A_ADC; + spec->num_adc_nids = 1; + spec->adc_nids = ad1986a_adc_nids; spec->input_mux = &ad1986a_capture_source; - spec->mixers = ad1986a_mixers; - spec->init_verbs = ad1986a_init_verbs; + spec->num_mixers = 1; + spec->mixers[0] = ad1986a_mixers; + spec->num_init_verbs = 1; + spec->init_verbs[0] = ad1986a_init_verbs; codec->patch_ops = ad198x_patch_ops; @@ -495,6 +555,7 @@ static int patch_ad1986a(struct hda_codec *codec) #define AD1983_ADC 0x04 static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC }; +static hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC }; static struct hda_input_mux ad1983_capture_source = { .num_items = 4, @@ -619,6 +680,7 @@ static struct hda_verb ad1983_init_verbs[] = { { } /* end */ }; + static int patch_ad1983(struct hda_codec *codec) { struct ad198x_spec *spec; @@ -634,10 +696,13 @@ static int patch_ad1983(struct hda_codec *codec) spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids); spec->multiout.dac_nids = ad1983_dac_nids; spec->multiout.dig_out_nid = AD1983_SPDIF_OUT; - spec->adc_nid = AD1983_ADC; + spec->num_adc_nids = 1; + spec->adc_nids = ad1983_adc_nids; spec->input_mux = &ad1983_capture_source; - spec->mixers = ad1983_mixers; - spec->init_verbs = ad1983_init_verbs; + spec->num_mixers = 1; + spec->mixers[0] = ad1983_mixers; + spec->num_init_verbs = 1; + spec->init_verbs[0] = ad1983_init_verbs; spec->spdif_route = 0; codec->patch_ops = ad198x_patch_ops; @@ -655,6 +720,7 @@ static int patch_ad1983(struct hda_codec *codec) #define AD1981_ADC 0x04 static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC }; +static hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC }; /* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */ static struct hda_input_mux ad1981_capture_source = { @@ -775,10 +841,13 @@ static int patch_ad1981(struct hda_codec *codec) spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids); spec->multiout.dac_nids = ad1981_dac_nids; spec->multiout.dig_out_nid = AD1981_SPDIF_OUT; - spec->adc_nid = AD1981_ADC; + spec->num_adc_nids = 1; + spec->adc_nids = ad1981_adc_nids; spec->input_mux = &ad1981_capture_source; - spec->mixers = ad1981_mixers; - spec->init_verbs = ad1981_init_verbs; + spec->num_mixers = 1; + spec->mixers[0] = ad1981_mixers; + spec->num_init_verbs = 1; + spec->init_verbs[0] = ad1981_init_verbs; spec->spdif_route = 0; codec->patch_ops = ad198x_patch_ops; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 7327deb6df9fef7cdc8e09f8eac7ee4d23236751..cffb83fdcff7a979b80e3e4beabce9afa5461da9 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -57,6 +57,7 @@ enum { enum { ALC260_BASIC, ALC260_HP, + ALC260_FUJITSU_S702x, ALC260_MODEL_LAST /* last tag */ }; @@ -72,6 +73,7 @@ enum { #define PIN_VREF50 0x21 #define PIN_OUT 0x40 #define PIN_HP 0xc0 +#define PIN_HP_AMP 0x80 struct alc_spec { /* codec parameterization */ @@ -113,8 +115,6 @@ struct alc_spec { /* PCM information */ struct hda_pcm pcm_rec[2]; /* used in alc_build_pcms() */ - struct semaphore bind_mutex; /* for bound controls */ - /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; unsigned int num_kctl_alloc, num_kctl_used; @@ -218,72 +218,53 @@ static int alc880_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *uc /* - * bound volume controls - * - * bind multiple volumes (# indices, from 0) + * Control of pin widget settings via the mixer. Only boolean settings are + * supported, so VrefEn can't be controlled using these functions as they + * stand. */ - -#define AMP_VAL_IDX_SHIFT 19 -#define AMP_VAL_IDX_MASK (0x0f<<19) - -static int alc_bind_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +static int alc_pinctl_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - unsigned long pval; - - down(&spec->bind_mutex); - pval = kcontrol->private_value; - kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ - snd_hda_mixer_amp_switch_info(kcontrol, uinfo); - kcontrol->private_value = pval; - up(&spec->bind_mutex); + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; return 0; } -static int alc_bind_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +static int alc_pinctl_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - unsigned long pval; - - down(&spec->bind_mutex); - pval = kcontrol->private_value; - kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */ - snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); - kcontrol->private_value = pval; - up(&spec->bind_mutex); + hda_nid_t nid = kcontrol->private_value & 0xffff; + long mask = (kcontrol->private_value >> 16) & 0xff; + long *valp = ucontrol->value.integer.value; + + *valp = 0; + if (snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00) & mask) + *valp = 1; return 0; } -static int alc_bind_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +static int alc_pinctl_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - unsigned long pval; - int i, indices, change = 0; - - down(&spec->bind_mutex); - pval = kcontrol->private_value; - indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT; - for (i = 0; i < indices; i++) { - kcontrol->private_value = (pval & ~AMP_VAL_IDX_MASK) | (i << AMP_VAL_IDX_SHIFT); - change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); - } - kcontrol->private_value = pval; - up(&spec->bind_mutex); + hda_nid_t nid = kcontrol->private_value & 0xffff; + long mask = (kcontrol->private_value >> 16) & 0xff; + long *valp = ucontrol->value.integer.value; + unsigned int pinctl = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00); + int change = ((pinctl & mask)!=0) != *valp; + + if (change) + snd_hda_codec_write(codec,nid,0,AC_VERB_SET_PIN_WIDGET_CONTROL, + *valp?(pinctl|mask):(pinctl&~mask)); return change; } -#define ALC_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \ +#define ALC_PINCTL_SWITCH(xname, nid, mask) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ - .info = alc_bind_switch_info, \ - .get = alc_bind_switch_get, \ - .put = alc_bind_switch_put, \ - .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, indices, direction) } - -#define ALC_BIND_MUTE(xname,nid,indices,dir) ALC_BIND_MUTE_MONO(xname,nid,3,indices,dir) - + .info = alc_pinctl_switch_info, \ + .get = alc_pinctl_switch_get, \ + .put = alc_pinctl_switch_put, \ + .private_value = (nid) | (mask<<16) } /* * ALC880 3-stack model @@ -354,13 +335,13 @@ static struct alc_channel_mode alc880_threestack_modes[2] = { static snd_kcontrol_new_t alc880_three_stack_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), @@ -441,7 +422,7 @@ static snd_kcontrol_new_t alc880_capture_alt_mixer[] = { /* additional mixers to alc880_three_stack_mixer */ static snd_kcontrol_new_t alc880_five_stack_mixer[] = { HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT), { } /* end */ }; @@ -498,15 +479,15 @@ static struct alc_channel_mode alc880_sixstack_modes[1] = { static snd_kcontrol_new_t alc880_six_stack_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), @@ -566,13 +547,13 @@ static struct alc_channel_mode alc880_w810_modes[1] = { /* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */ static snd_kcontrol_new_t alc880_w810_base_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), { } /* end */ }; @@ -597,9 +578,9 @@ static struct alc_channel_mode alc880_2_jack_modes[1] = { static snd_kcontrol_new_t alc880_z71v_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -623,9 +604,9 @@ static hda_nid_t alc880_f1734_dac_nids[1] = { static snd_kcontrol_new_t alc880_f1734_mixer[] = { HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), @@ -648,13 +629,13 @@ static snd_kcontrol_new_t alc880_f1734_mixer[] = { static snd_kcontrol_new_t alc880_asus_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), @@ -1383,10 +1364,10 @@ static snd_kcontrol_new_t alc880_test_mixer[] = { HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - ALC_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT), - ALC_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), PIN_CTL_TEST("Front Pin Mode", 0x14), PIN_CTL_TEST("Surround Pin Mode", 0x15), PIN_CTL_TEST("CLFE Pin Mode", 0x16), @@ -1769,7 +1750,7 @@ enum { static snd_kcontrol_new_t alc880_control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), HDA_CODEC_MUTE(NULL, 0, 0, 0), - ALC_BIND_MUTE(NULL, 0, 0, 0), + HDA_BIND_MUTE(NULL, 0, 0, 0), }; /* add dynamic controls */ @@ -2087,7 +2068,6 @@ static int patch_alc880(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - init_MUTEX(&spec->bind_mutex); codec->spec = spec; board_config = snd_hda_check_board_config(codec, alc880_cfg_tbl); @@ -2205,6 +2185,17 @@ static struct hda_input_mux alc260_capture_source = { }, }; +/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack + * and the internal CD lines. + */ +static struct hda_input_mux alc260_fujitsu_capture_source = { + .num_items = 2, + .items = { + { "Mic/Line", 0x0 }, + { "CD", 0x4 }, + }, +}; + /* * This is just place-holder, so there's something for alc_build_pcms to look * at when it calculates the maximum number of channels. ALC260 has no mixer @@ -2217,7 +2208,7 @@ static struct alc_channel_mode alc260_modes[1] = { static snd_kcontrol_new_t alc260_base_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), @@ -2229,9 +2220,9 @@ static snd_kcontrol_new_t alc260_base_mixer[] = { HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x07, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x07, 0x05, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT), { @@ -2246,7 +2237,7 @@ static snd_kcontrol_new_t alc260_base_mixer[] = { static snd_kcontrol_new_t alc260_hp_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT), @@ -2256,9 +2247,9 @@ static snd_kcontrol_new_t alc260_hp_mixer[] = { HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT), HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT), HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT), { @@ -2271,6 +2262,30 @@ static snd_kcontrol_new_t alc260_hp_mixer[] = { { } /* end */ }; +static snd_kcontrol_new_t alc260_fujitsu_mixer[] = { + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT), + ALC_PINCTL_SWITCH("Headphone Amp Switch", 0x14, PIN_HP_AMP), + HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT), + HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Internal Speaker Playback Switch", 0x09, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { } /* end */ +}; + static struct hda_verb alc260_init_verbs[] = { /* Line In pin widget for input */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, @@ -2332,6 +2347,60 @@ static struct hda_verb alc260_init_verbs[] = { { } }; +/* Initialisation sequence for ALC260 as configured in Fujitsu S702x + * laptops. + */ +static struct hda_verb alc260_fujitsu_init_verbs[] = { + /* Disable all GPIOs */ + {0x01, AC_VERB_SET_GPIO_MASK, 0}, + /* Internal speaker is connected to headphone pin */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Headphone/Line-out jack connects to Line1 pin; make it an output */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + /* Mic/Line-in jack is connected to mic1 pin, so make it an input */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + /* Ensure all other unused pins are disabled and muted. + * Note: trying to set widget 0x15 to anything blocks all audio + * output for some reason, so just leave that at the default. + */ + {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Disable digital (SPDIF) pins */ + {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0}, + {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0}, + + /* Start with mixer outputs muted */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + + /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute Line1 pin widget amp left and right (no equiv mixer ctrl) */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* Unmute pin widget used for Line-in (no equiv mixer ctrl) */ + {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + /* Mute capture amp left and right */ + {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + /* Set ADC connection select to line in (on mic1 pin) */ + {0x04, AC_VERB_SET_CONNECT_SEL, 0x00}, + + /* Mute all inputs to mixer widget (even unconnected ones) */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ +}; + static struct hda_pcm_stream alc260_pcm_analog_playback = { .substreams = 1, .channels_min = 2, @@ -2347,6 +2416,8 @@ static struct hda_pcm_stream alc260_pcm_analog_capture = { static struct hda_board_config alc260_cfg_tbl[] = { { .modelname = "hp", .config = ALC260_HP }, { .pci_subvendor = 0x103c, .config = ALC260_HP }, + { .modelname = "fujitsu", .config = ALC260_FUJITSU_S702x }, + { .pci_subvendor = 0x10cf, .pci_subdevice = 0x1326, .config = ALC260_FUJITSU_S702x }, {} }; @@ -2359,7 +2430,6 @@ static int patch_alc260(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - init_MUTEX(&spec->bind_mutex); codec->spec = spec; board_config = snd_hda_check_board_config(codec, alc260_cfg_tbl); @@ -2373,14 +2443,23 @@ static int patch_alc260(struct hda_codec *codec) spec->mixers[spec->num_mixers] = alc260_hp_mixer; spec->num_mixers++; break; + case ALC260_FUJITSU_S702x: + spec->mixers[spec->num_mixers] = alc260_fujitsu_mixer; + spec->num_mixers++; + break; default: spec->mixers[spec->num_mixers] = alc260_base_mixer; spec->num_mixers++; break; } - spec->init_verbs[0] = alc260_init_verbs; - spec->num_init_verbs = 1; + if (board_config != ALC260_FUJITSU_S702x) { + spec->init_verbs[0] = alc260_init_verbs; + spec->num_init_verbs = 1; + } else { + spec->init_verbs[0] = alc260_fujitsu_init_verbs; + spec->num_init_verbs = 1; + } spec->channel_mode = alc260_modes; spec->num_channel_mode = ARRAY_SIZE(alc260_modes); @@ -2393,7 +2472,11 @@ static int patch_alc260(struct hda_codec *codec) spec->multiout.num_dacs = ARRAY_SIZE(alc260_dac_nids); spec->multiout.dac_nids = alc260_dac_nids; - spec->input_mux = &alc260_capture_source; + if (board_config != ALC260_FUJITSU_S702x) { + spec->input_mux = &alc260_capture_source; + } else { + spec->input_mux = &alc260_fujitsu_capture_source; + } switch (board_config) { case ALC260_HP: spec->num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids); @@ -2483,15 +2566,15 @@ static int alc882_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *u */ static snd_kcontrol_new_t alc882_base_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - ALC_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - ALC_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), @@ -2609,7 +2692,6 @@ static int patch_alc882(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - init_MUTEX(&spec->bind_mutex); codec->spec = spec; spec->mixers[spec->num_mixers] = alc882_base_mixer; diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index d014b7bb70df8b3b1d582e745aff0bbf0966efb6..9c7fe0b3200a22e7660ca4145b00e0f08c3fc16b 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c @@ -3,7 +3,7 @@ * * HD audio interface patch for Silicon Labs 3054/5 modem codec * - * Copyright (c) 2005 Sasha Khapyorsky + * Copyright (c) 2005 Sasha Khapyorsky * Takashi Iwai * * diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index 2e0a31613ee6c37d065e42521efddf7df50d4559..db12b038286bff3efa686acf885078c11d699340 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c @@ -960,7 +960,7 @@ static int wm_adc_mux_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucont if (change) wm_put(ice, WM_ADC_MUX, nval); snd_ice1712_restore_gpio_status(ice); - return 0; + return change; } /* @@ -1672,9 +1672,9 @@ static int __devinit aureon_add_controls(ice1712_t *ice) snd_ice1712_save_gpio_status(ice); id = aureon_cs8415_get(ice, CS8415_ID); if (id != 0x41) - snd_printk("No CS8415 chip. Skipping CS8415 controls.\n"); + snd_printk(KERN_INFO "No CS8415 chip. Skipping CS8415 controls.\n"); else if ((id & 0x0F) != 0x01) - snd_printk("Detected unsupported CS8415 rev. (%c)\n", (char)((id & 0x0F) + 'A' - 1)); + snd_printk(KERN_INFO "Detected unsupported CS8415 rev. (%c)\n", (char)((id & 0x0F) + 'A' - 1)); else { for (i = 0; i< ARRAY_SIZE(cs8415_controls); i++) { snd_kcontrol_t *kctl; diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index 39fbe662965d85246ed16eec5cd15bf8f1c0ce63..576f69d482c90acd80a8dca531933e899a7011df 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c @@ -546,7 +546,7 @@ static int __devinit snd_ice1712_delta_init(ice1712_t *ice) case ICE1712_SUBDEVICE_DELTA1010LT: case ICE1712_SUBDEVICE_VX442: if ((err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c)) < 0) { - snd_printk("unable to create I2C bus\n"); + snd_printk(KERN_ERR "unable to create I2C bus\n"); return err; } ice->i2c->private_data = ice; diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c index e36efa1bdac3260a12d8d1ce7fdd01a07d0ed47d..c8ec5cac3c175353e9689d72c3437fb113777b27 100644 --- a/sound/pci/ice1712/ews.c +++ b/sound/pci/ice1712/ews.c @@ -438,7 +438,7 @@ static int __devinit snd_ice1712_ews_init(ice1712_t *ice) /* create i2c */ if ((err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c)) < 0) { - snd_printk("unable to create I2C bus\n"); + snd_printk(KERN_ERR "unable to create I2C bus\n"); return err; } ice->i2c->private_data = ice; @@ -448,7 +448,7 @@ static int __devinit snd_ice1712_ews_init(ice1712_t *ice) switch (ice->eeprom.subvendor) { case ICE1712_SUBDEVICE_DMX6FIRE: if ((err = snd_i2c_device_create(ice->i2c, "PCF9554", ICE1712_6FIRE_PCF9554_ADDR, &ice->spec.i2cdevs[EWS_I2C_6FIRE])) < 0) { - snd_printk("PCF9554 initialization failed\n"); + snd_printk(KERN_ERR "PCF9554 initialization failed\n"); return err; } snd_ice1712_6fire_write_pca(ice, PCF9554_REG_CONFIG, 0x80); @@ -791,7 +791,7 @@ static int snd_ice1712_6fire_read_pca(ice1712_t *ice, unsigned char reg) byte = 0; if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_6FIRE], &byte, 1) != 1) { snd_i2c_unlock(ice->i2c); - printk("cannot read pca\n"); + printk(KERN_ERR "cannot read pca\n"); return -EIO; } snd_i2c_unlock(ice->i2c); diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index a6d98013c331fe95bb69771079b88881eb48839e..5aca37798c3233a68fd266eca705b0a53b21d9fb 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -387,7 +387,7 @@ int __devinit snd_ice1712_init_cs8427(ice1712_t *ice, int addr) if ((err = snd_cs8427_create(ice->i2c, addr, (ice->cs8427_timeout * HZ) / 1000, &ice->cs8427)) < 0) { - snd_printk("CS8427 initialization failed\n"); + snd_printk(KERN_ERR "CS8427 initialization failed\n"); return err; } ice->spdif.ops.open = open_cs8427; @@ -2348,12 +2348,12 @@ static int __devinit snd_ice1712_read_eeprom(ice1712_t *ice, const char *modelna if (ice->eeprom.size < 6) ice->eeprom.size = 32; /* FIXME: any cards without the correct size? */ else if (ice->eeprom.size > 32) { - snd_printk("invalid EEPROM (size = %i)\n", ice->eeprom.size); + snd_printk(KERN_ERR "invalid EEPROM (size = %i)\n", ice->eeprom.size); return -EIO; } ice->eeprom.version = snd_ice1712_read_i2c(ice, dev, 0x05); if (ice->eeprom.version != 1) { - snd_printk("invalid EEPROM version %i\n", ice->eeprom.version); + snd_printk(KERN_ERR "invalid EEPROM version %i\n", ice->eeprom.version); /* return -EIO; */ } size = ice->eeprom.size - 6; @@ -2524,7 +2524,7 @@ static int __devinit snd_ice1712_create(snd_card_t * card, /* check, if we can restrict PCI DMA transfers to 28 bits */ if (pci_set_dma_mask(pci, 0x0fffffff) < 0 || pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) { - snd_printk("architecture does not support 28bit PCI busmaster DMA\n"); + snd_printk(KERN_ERR "architecture does not support 28bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -2573,7 +2573,7 @@ static int __devinit snd_ice1712_create(snd_card_t * card, ice->profi_port = pci_resource_start(pci, 3); if (request_irq(pci->irq, snd_ice1712_interrupt, SA_INTERRUPT|SA_SHIRQ, "ICE1712", (void *) ice)) { - snd_printk("unable to grab IRQ %d\n", pci->irq); + snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_ice1712_free(ice); return -EIO; } diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index c3ce8f93740bb9bc77805eed5455896ec21fa785..5b4293f5a6522bad4e254839644573b7db8f90dc 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -675,9 +675,12 @@ static snd_pcm_hardware_t snd_vt1724_spdif = SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START), .formats = SNDRV_PCM_FMTBIT_S32_LE, - .rates = SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, + .rates = (SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_44100| + SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_88200| + SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_176400| + SNDRV_PCM_RATE_192000), .rate_min = 32000, - .rate_max = 48000, + .rate_max = 192000, .channels_min = 2, .channels_max = 2, .buffer_bytes_max = (1UL << 18), /* 16bits dword */ @@ -905,6 +908,10 @@ static void update_spdif_rate(ice1712_t *ice, unsigned int rate) case 44100: break; case 48000: nval |= 2 << 12; break; case 32000: nval |= 3 << 12; break; + case 88200: nval |= 4 << 12; break; + case 96000: nval |= 5 << 12; break; + case 192000: nval |= 6 << 12; break; + case 176400: nval |= 7 << 12; break; } if (val != nval) update_spdif_bits(ice, nval); @@ -1292,22 +1299,32 @@ static int snd_vt1724_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * static unsigned int encode_spdif_bits(snd_aes_iec958_t *diga) { - unsigned int val; + unsigned int val, rbits; val = diga->status[0] & 0x03; /* professional, non-audio */ if (val & 0x01) { /* professional */ if ((diga->status[0] & IEC958_AES0_PRO_EMPHASIS) == IEC958_AES0_PRO_EMPHASIS_5015) val |= 1U << 3; - switch (diga->status[0] & IEC958_AES0_PRO_FS) { - case IEC958_AES0_PRO_FS_44100: - break; - case IEC958_AES0_PRO_FS_32000: - val |= 3U << 12; - break; - default: - val |= 2U << 12; - break; + rbits = (diga->status[4] >> 3) & 0x0f; + if (rbits) { + switch (rbits) { + case 2: val |= 5 << 12; break; /* 96k */ + case 3: val |= 6 << 12; break; /* 192k */ + case 10: val |= 4 << 12; break; /* 88.2k */ + case 11: val |= 7 << 12; break; /* 176.4k */ + } + } else { + switch (diga->status[0] & IEC958_AES0_PRO_FS) { + case IEC958_AES0_PRO_FS_44100: + break; + case IEC958_AES0_PRO_FS_32000: + val |= 3U << 12; + break; + default: + val |= 2U << 12; + break; + } } } else { /* consumer */ @@ -2154,7 +2171,7 @@ static int __devinit snd_vt1724_create(snd_card_t * card, ice->profi_port = pci_resource_start(pci, 1); if (request_irq(pci->irq, snd_vt1724_interrupt, SA_INTERRUPT|SA_SHIRQ, "ICE1724", (void *) ice)) { - snd_printk("unable to grab IRQ %d\n", pci->irq); + snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_vt1724_free(ice); return -EIO; } diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index a5f852b1f575b81d4f14b68e1d63153cef27fbda..773a1ecb75ceecac6612b85d1bb9e2a2988b49a4 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c @@ -794,8 +794,7 @@ static int __devinit pontis_init(ice1712_t *ice) /* initialize WM8776 codec */ for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2) wm_put(ice, wm_inits[i], wm_inits[i+1]); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); for (i = 0; i < ARRAY_SIZE(wm_inits2); i += 2) wm_put(ice, wm_inits2[i], wm_inits2[i+1]); diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c index d48d42524ac509721266f10dc6d2c5f07abd3b7b..1fe21009ca84a287104bf750430701818adade33 100644 --- a/sound/pci/ice1712/revo.c +++ b/sound/pci/ice1712/revo.c @@ -128,17 +128,6 @@ static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = { .mask_flags = 0, }; -static unsigned int rates[] = { - 32000, 44100, 48000, 64000, 88200, 96000, - 176400, 192000, -}; - -static snd_pcm_hw_constraint_list_t revo_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - static int __devinit revo_init(ice1712_t *ice) { akm4xxx_t *ak; @@ -173,8 +162,6 @@ static int __devinit revo_init(ice1712_t *ice) break; } - ice->hw_rates = &revo_rates; /* AK codecs don't support lower than 32k */ - return 0; } diff --git a/sound/pci/ice1712/vt1720_mobo.c b/sound/pci/ice1712/vt1720_mobo.c index ab61e383024f2218315332cac7213a585e902553..90c85cd954793f278bd9664c3ac2c5937c441628 100644 --- a/sound/pci/ice1712/vt1720_mobo.c +++ b/sound/pci/ice1712/vt1720_mobo.c @@ -71,6 +71,22 @@ static unsigned char k8x800_eeprom[] __devinitdata = { 0x00, /* - */ }; +static unsigned char sn25p_eeprom[] __devinitdata = { + 0x01, /* SYSCONF: clock 256, 1ADC, 2DACs */ + 0x02, /* ACLINK: ACLINK, packed */ + 0x00, /* I2S: - */ + 0x41, /* SPDIF: - */ + 0xff, /* GPIO_DIR */ + 0xff, /* GPIO_DIR1 */ + 0x00, /* - */ + 0xff, /* GPIO_MASK */ + 0xff, /* GPIO_MASK1 */ + 0x00, /* - */ + 0x00, /* GPIO_STATE */ + 0x00, /* GPIO_STATE1 */ + 0x00, /* - */ +}; + /* entry point */ struct snd_ice1712_card_info snd_vt1720_mobo_cards[] __devinitdata = { @@ -113,11 +129,11 @@ struct snd_ice1712_card_info snd_vt1720_mobo_cards[] __devinitdata = { { .subvendor = VT1720_SUBDEVICE_SN25P, .name = "Shuttle SN25P", - /* identical with k8x800 */ + .model = "sn25p", .chip_init = k8x800_init, .build_controls = k8x800_add_controls, .eeprom_size = sizeof(k8x800_eeprom), - .eeprom_data = k8x800_eeprom, + .eeprom_data = sn25p_eeprom, }, { } /* terminator */ }; diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 1a96198a17ae618f333691017e3e909293ce1650..0801083f32ddd75544755c03dbe43fd7c463546a 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -64,36 +64,35 @@ MODULE_SUPPORTED_DEVICE("{{Intel,82801AA-ICH}," "{AMD,AMD8111}," "{ALI,M5455}}"); -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ -static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; -static char *ac97_quirk[SNDRV_CARDS]; -static int buggy_semaphore[SNDRV_CARDS]; -static int buggy_irq[SNDRV_CARDS]; -static int xbox[SNDRV_CARDS]; - -#ifdef SUPPORT_MIDI -static int mpu_port[SNDRV_CARDS]; /* disabled */ -#endif - -module_param_array(index, int, NULL, 0444); +static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ +static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ +static int ac97_clock = 0; +static char *ac97_quirk; +static int buggy_semaphore; +static int buggy_irq = -1; /* auto-check */ +static int xbox; + +module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for Intel i8x0 soundcard."); -module_param_array(id, charp, NULL, 0444); +module_param(id, charp, 0444); MODULE_PARM_DESC(id, "ID string for Intel i8x0 soundcard."); -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable Intel i8x0 soundcard."); -module_param_array(ac97_clock, int, NULL, 0444); +module_param(ac97_clock, int, 0444); MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect)."); -module_param_array(ac97_quirk, charp, NULL, 0444); +module_param(ac97_quirk, charp, 0444); MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); -module_param_array(buggy_semaphore, bool, NULL, 0444); +module_param(buggy_semaphore, bool, 0444); MODULE_PARM_DESC(buggy_semaphore, "Enable workaround for hardwares with problematic codec semaphores."); -module_param_array(buggy_irq, bool, NULL, 0444); +module_param(buggy_irq, bool, 0444); MODULE_PARM_DESC(buggy_irq, "Enable workaround for buggy interrupts on some motherboards."); -module_param_array(xbox, bool, NULL, 0444); +module_param(xbox, bool, 0444); MODULE_PARM_DESC(xbox, "Set to 1 for Xbox, if you have problems with the AC'97 codec detection."); +/* just for backward compatibility */ +static int enable; +module_param(enable, bool, 0444); +static int joystick; +module_param(joystick, int, 0444); + /* * Direct registers */ @@ -539,7 +538,7 @@ static int snd_intel8x0_codec_semaphore(intel8x0_t *chip, unsigned int codec) /* access to some forbidden (non existant) ac97 registers will not * reset the semaphore. So even if you don't get the semaphore, still * continue the access. We don't need the semaphore anyway. */ - snd_printk("codec_semaphore: semaphore is not ready [0x%x][0x%x]\n", + snd_printk(KERN_ERR "codec_semaphore: semaphore is not ready [0x%x][0x%x]\n", igetbyte(chip, ICHREG(ACC_SEMA)), igetdword(chip, ICHREG(GLOB_STA))); iagetword(chip, 0); /* clear semaphore flag */ /* I don't care about the semaphore */ @@ -554,7 +553,7 @@ static void snd_intel8x0_codec_write(ac97_t *ac97, if (snd_intel8x0_codec_semaphore(chip, ac97->num) < 0) { if (! chip->in_ac97_init) - snd_printk("codec_write %d: semaphore is not ready for register 0x%x\n", ac97->num, reg); + snd_printk(KERN_ERR "codec_write %d: semaphore is not ready for register 0x%x\n", ac97->num, reg); } iaputword(chip, reg + ac97->num * 0x80, val); } @@ -568,7 +567,7 @@ static unsigned short snd_intel8x0_codec_read(ac97_t *ac97, if (snd_intel8x0_codec_semaphore(chip, ac97->num) < 0) { if (! chip->in_ac97_init) - snd_printk("codec_read %d: semaphore is not ready for register 0x%x\n", ac97->num, reg); + snd_printk(KERN_ERR "codec_read %d: semaphore is not ready for register 0x%x\n", ac97->num, reg); res = 0xffff; } else { res = iagetword(chip, reg + ac97->num * 0x80); @@ -576,7 +575,7 @@ static unsigned short snd_intel8x0_codec_read(ac97_t *ac97, /* reset RCS and preserve other R/WC bits */ iputdword(chip, ICHREG(GLOB_STA), tmp & ~(ICH_SRI|ICH_PRI|ICH_TRI|ICH_GSCI)); if (! chip->in_ac97_init) - snd_printk("codec_read %d: read timeout for register 0x%x\n", ac97->num, reg); + snd_printk(KERN_ERR "codec_read %d: read timeout for register 0x%x\n", ac97->num, reg); res = 0xffff; } } @@ -607,16 +606,19 @@ static int snd_intel8x0_ali_codec_ready(intel8x0_t *chip, int mask) if (val & mask) return 0; } - snd_printd(KERN_WARNING "intel8x0: AC97 codec ready timeout.\n"); + if (! chip->in_ac97_init) + snd_printd(KERN_WARNING "intel8x0: AC97 codec ready timeout.\n"); return -EBUSY; } static int snd_intel8x0_ali_codec_semaphore(intel8x0_t *chip) { int time = 100; + if (chip->buggy_semaphore) + return 0; /* just ignore ... */ while (time-- && (igetdword(chip, ICHREG(ALI_CAS)) & ALI_CAS_SEM_BUSY)) udelay(1); - if (! time) + if (! time && ! chip->in_ac97_init) snd_printk(KERN_WARNING "ali_codec_semaphore timeout\n"); return snd_intel8x0_ali_codec_ready(chip, ALI_CSPSR_CODEC_READY); } @@ -1715,6 +1717,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { .name = "IBM NetVista A30p", /* AD1981B */ .type = AC97_TUNE_HP_ONLY }, + { + .subvendor = 0x1025, + .subdevice = 0x0083, + .name = "Acer Aspire 3003LCi", + .type = AC97_TUNE_HP_ONLY + }, { .subvendor = 0x1028, .subdevice = 0x00d8, @@ -1757,6 +1765,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { .name = "Dell Unknown", /* STAC9750/51 */ .type = AC97_TUNE_HP_ONLY }, + { + .subvendor = 0x1028, + .subdevice = 0x0191, + .name = "Dell Inspiron 8600", + .type = AC97_TUNE_HP_ONLY + }, { .subvendor = 0x103c, .subdevice = 0x006d, @@ -2022,7 +2036,6 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock, const if ((err = snd_ac97_bus(chip->card, 0, ops, chip, &pbus)) < 0) goto __err; pbus->private_free = snd_intel8x0_mixer_free_ac97_bus; - pbus->shared_type = AC97_SHARED_TYPE_ICH; /* shared with modem driver */ if (ac97_clock >= 8000 && ac97_clock <= 48000) pbus->clock = ac97_clock; /* FIXME: my test board doesn't work well with VRA... */ @@ -2131,14 +2144,13 @@ static void do_ali_reset(intel8x0_t *chip) iputdword(chip, ICHREG(ALI_FIFOCR2), 0x83838383); iputdword(chip, ICHREG(ALI_FIFOCR3), 0x83838383); iputdword(chip, ICHREG(ALI_INTERFACECR), - ICH_ALI_IF_MC|ICH_ALI_IF_PI|ICH_ALI_IF_PO); + ICH_ALI_IF_PI|ICH_ALI_IF_PO); iputdword(chip, ICHREG(ALI_INTERRUPTCR), 0x00000000); iputdword(chip, ICHREG(ALI_INTERRUPTSR), 0x00000000); } #define do_delay(chip) do {\ - set_current_state(TASK_UNINTERRUPTIBLE);\ - schedule_timeout(1);\ + schedule_timeout_uninterruptible(1);\ } while (0) static int snd_intel8x0_ich_chip_init(intel8x0_t *chip, int probing) @@ -2166,7 +2178,7 @@ static int snd_intel8x0_ich_chip_init(intel8x0_t *chip, int probing) goto __ok; do_delay(chip); } while (time_after_eq(end_time, jiffies)); - snd_printk("AC'97 warm reset still in progress? [0x%x]\n", igetdword(chip, ICHREG(GLOB_CNT))); + snd_printk(KERN_ERR "AC'97 warm reset still in progress? [0x%x]\n", igetdword(chip, ICHREG(GLOB_CNT))); return -EIO; __ok: @@ -2441,7 +2453,7 @@ static void __devinit intel8x0_measure_ac97_clock(intel8x0_t *chip) subs = chip->pcm[0]->streams[0].substream; if (! subs || subs->dma_buffer.bytes < INTEL8X0_TESTBUF_SIZE) { - snd_printk("no playback buffer allocated - aborting measure ac97 clock\n"); + snd_printk(KERN_WARNING "no playback buffer allocated - aborting measure ac97 clock\n"); return; } ichdev = &chip->ichd[ICHD_PCMOUT]; @@ -2477,7 +2489,7 @@ static void __devinit intel8x0_measure_ac97_clock(intel8x0_t *chip) do_gettimeofday(&stop_time); /* stop */ if (chip->device_type == DEVICE_ALI) { - iputdword(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 8)); + iputdword(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 16)); iputbyte(chip, port + ICH_REG_OFF_CR, 0); while (igetbyte(chip, port + ICH_REG_OFF_CR)) ; @@ -2556,7 +2568,6 @@ struct ich_reg_info { static int __devinit snd_intel8x0_create(snd_card_t * card, struct pci_dev *pci, unsigned long device_type, - int buggy_sem, intel8x0_t ** r_intel8x0) { intel8x0_t *chip; @@ -2614,18 +2625,17 @@ static int __devinit snd_intel8x0_create(snd_card_t * card, chip->card = card; chip->pci = pci; chip->irq = -1; - chip->buggy_semaphore = buggy_sem; + + /* module parameters */ + chip->buggy_irq = buggy_irq; + chip->buggy_semaphore = buggy_semaphore; + if (xbox) + chip->xbox = 1; if (pci->vendor == PCI_VENDOR_ID_INTEL && pci->device == PCI_DEVICE_ID_INTEL_440MX) chip->fix_nocache = 1; /* enable workaround */ - /* some Nforce[2] and ICH boards have problems with IRQ handling. - * Needs to return IRQ_HANDLED for unknown irqs. - */ - if (device_type == DEVICE_NFORCE) - chip->buggy_irq = 1; - if ((err = pci_request_regions(pci, card->shortname)) < 0) { kfree(chip); pci_disable_device(pci); @@ -2644,7 +2654,7 @@ static int __devinit snd_intel8x0_create(snd_card_t * card, chip->remap_addr = ioremap_nocache(chip->addr, pci_resource_len(pci, 2)); if (chip->remap_addr == NULL) { - snd_printk("AC'97 space ioremap problem\n"); + snd_printk(KERN_ERR "AC'97 space ioremap problem\n"); snd_intel8x0_free(chip); return -EIO; } @@ -2657,7 +2667,7 @@ static int __devinit snd_intel8x0_create(snd_card_t * card, chip->remap_bmaddr = ioremap_nocache(chip->bmaddr, pci_resource_len(pci, 3)); if (chip->remap_bmaddr == NULL) { - snd_printk("Controller space ioremap problem\n"); + snd_printk(KERN_ERR "Controller space ioremap problem\n"); snd_intel8x0_free(chip); return -EIO; } @@ -2666,15 +2676,6 @@ static int __devinit snd_intel8x0_create(snd_card_t * card, } port_inited: - if (request_irq(pci->irq, snd_intel8x0_interrupt, SA_INTERRUPT|SA_SHIRQ, card->shortname, (void *)chip)) { - snd_printk("unable to grab IRQ %d\n", pci->irq); - snd_intel8x0_free(chip); - return -EBUSY; - } - chip->irq = pci->irq; - pci_set_master(pci); - synchronize_irq(chip->irq); - chip->bdbars_count = bdbars[device_type]; /* initialize offsets */ @@ -2725,13 +2726,27 @@ static int __devinit snd_intel8x0_create(snd_card_t * card, int_sta_masks = 0; for (i = 0; i < chip->bdbars_count; i++) { ichdev = &chip->ichd[i]; - ichdev->bdbar = ((u32 *)chip->bdbars.area) + (i * ICH_MAX_FRAGS * 2); - ichdev->bdbar_addr = chip->bdbars.addr + (i * sizeof(u32) * ICH_MAX_FRAGS * 2); + ichdev->bdbar = ((u32 *)chip->bdbars.area) + + (i * ICH_MAX_FRAGS * 2); + ichdev->bdbar_addr = chip->bdbars.addr + + (i * sizeof(u32) * ICH_MAX_FRAGS * 2); int_sta_masks |= ichdev->int_sta_mask; } - chip->int_sta_reg = device_type == DEVICE_ALI ? ICH_REG_ALI_INTERRUPTSR : ICH_REG_GLOB_STA; + chip->int_sta_reg = device_type == DEVICE_ALI ? + ICH_REG_ALI_INTERRUPTSR : ICH_REG_GLOB_STA; chip->int_sta_mask = int_sta_masks; + /* request irq after initializaing int_sta_mask, etc */ + if (request_irq(pci->irq, snd_intel8x0_interrupt, + SA_INTERRUPT|SA_SHIRQ, card->shortname, (void *)chip)) { + snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + snd_intel8x0_free(chip); + return -EBUSY; + } + chip->irq = pci->irq; + pci_set_master(pci); + synchronize_irq(chip->irq); + if ((err = snd_intel8x0_chip_init(chip, 1)) < 0) { snd_intel8x0_free(chip); return err; @@ -2782,20 +2797,12 @@ static struct shortname_table { static int __devinit snd_intel8x0_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { - static int dev; snd_card_t *card; intel8x0_t *chip; int err; struct shortname_table *name; - if (dev >= SNDRV_CARDS) - return -ENODEV; - if (!enable[dev]) { - dev++; - return -ENOENT; - } - - card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + card = snd_card_new(index, id, THIS_MODULE, 0); if (card == NULL) return -ENOMEM; @@ -2819,17 +2826,23 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci, } } + if (buggy_irq < 0) { + /* some Nforce[2] and ICH boards have problems with IRQ handling. + * Needs to return IRQ_HANDLED for unknown irqs. + */ + if (pci_id->driver_data == DEVICE_NFORCE) + buggy_irq = 1; + else + buggy_irq = 0; + } + if ((err = snd_intel8x0_create(card, pci, pci_id->driver_data, - buggy_semaphore[dev], &chip)) < 0) { + &chip)) < 0) { snd_card_free(card); return err; } - if (buggy_irq[dev]) - chip->buggy_irq = 1; - if (xbox[dev]) - chip->xbox = 1; - if ((err = snd_intel8x0_mixer(chip, ac97_clock[dev], ac97_quirk[dev])) < 0) { + if ((err = snd_intel8x0_mixer(chip, ac97_clock, ac97_quirk)) < 0) { snd_card_free(card); return err; } @@ -2844,7 +2857,7 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci, "%s with %s at %#lx, irq %i", card->shortname, snd_ac97_get_short_name(chip->ac97[0]), chip->addr, chip->irq); - if (! ac97_clock[dev]) + if (! ac97_clock) intel8x0_measure_ac97_clock(chip); if ((err = snd_card_register(card)) < 0) { @@ -2852,7 +2865,6 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci, return err; } pci_set_drvdata(pci, card); - dev++; return 0; } diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 9e2060d56c244f3f6a35aa25e550c43805dc2f5b..acfb197a833cddc9a17f14f4d80ed71e87e94725 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -3,7 +3,7 @@ * * Copyright (c) 2000 Jaroslav Kysela * - * This is modified (by Sasha Khapyorsky ) version + * This is modified (by Sasha Khapyorsky ) version * of ALSA ICH sound driver intel8x0.c . * * @@ -56,20 +56,21 @@ MODULE_SUPPORTED_DEVICE("{{Intel,82801AA-ICH}," "{NVidia,NForce3 Modem}," "{AMD,AMD768}}"); -static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* Exclude the first card */ -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ -static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; +static int index = -2; /* Exclude the first card */ +static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ +static int ac97_clock = 0; -module_param_array(index, int, NULL, 0444); +module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for Intel i8x0 modemcard."); -module_param_array(id, charp, NULL, 0444); +module_param(id, charp, 0444); MODULE_PARM_DESC(id, "ID string for Intel i8x0 modemcard."); -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable Intel i8x0 modemcard."); -module_param_array(ac97_clock, int, NULL, 0444); +module_param(ac97_clock, int, 0444); MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect)."); +/* just for backward compatibility */ +static int enable; +module_param(enable, bool, 0444); + /* * Direct registers */ @@ -362,7 +363,7 @@ static int snd_intel8x0m_codec_semaphore(intel8x0_t *chip, unsigned int codec) /* access to some forbidden (non existant) ac97 registers will not * reset the semaphore. So even if you don't get the semaphore, still * continue the access. We don't need the semaphore anyway. */ - snd_printk("codec_semaphore: semaphore is not ready [0x%x][0x%x]\n", + snd_printk(KERN_ERR "codec_semaphore: semaphore is not ready [0x%x][0x%x]\n", igetbyte(chip, ICHREG(ACC_SEMA)), igetdword(chip, ICHREG(GLOB_STA))); iagetword(chip, 0); /* clear semaphore flag */ /* I don't care about the semaphore */ @@ -377,7 +378,7 @@ static void snd_intel8x0_codec_write(ac97_t *ac97, if (snd_intel8x0m_codec_semaphore(chip, ac97->num) < 0) { if (! chip->in_ac97_init) - snd_printk("codec_write %d: semaphore is not ready for register 0x%x\n", ac97->num, reg); + snd_printk(KERN_ERR "codec_write %d: semaphore is not ready for register 0x%x\n", ac97->num, reg); } iaputword(chip, reg + ac97->num * 0x80, val); } @@ -391,7 +392,7 @@ static unsigned short snd_intel8x0_codec_read(ac97_t *ac97, if (snd_intel8x0m_codec_semaphore(chip, ac97->num) < 0) { if (! chip->in_ac97_init) - snd_printk("codec_read %d: semaphore is not ready for register 0x%x\n", ac97->num, reg); + snd_printk(KERN_ERR "codec_read %d: semaphore is not ready for register 0x%x\n", ac97->num, reg); res = 0xffff; } else { res = iagetword(chip, reg + ac97->num * 0x80); @@ -399,7 +400,7 @@ static unsigned short snd_intel8x0_codec_read(ac97_t *ac97, /* reset RCS and preserve other R/WC bits */ iputdword(chip, ICHREG(GLOB_STA), tmp & ~(ICH_SRI|ICH_PRI|ICH_TRI|ICH_GSCI)); if (! chip->in_ac97_init) - snd_printk("codec_read %d: read timeout for register 0x%x\n", ac97->num, reg); + snd_printk(KERN_ERR "codec_read %d: read timeout for register 0x%x\n", ac97->num, reg); res = 0xffff; } } @@ -746,6 +747,7 @@ static int __devinit snd_intel8x0_pcm1(intel8x0_t *chip, int device, struct ich_ pcm->private_data = chip; pcm->info_flags = 0; + pcm->dev_class = SNDRV_PCM_CLASS_MODEM; if (rec->suffix) sprintf(pcm->name, "%s - %s", chip->card->shortname, rec->suffix); else @@ -854,7 +856,6 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock) if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &pbus)) < 0) goto __err; pbus->private_free = snd_intel8x0_mixer_free_ac97_bus; - pbus->shared_type = AC97_SHARED_TYPE_ICH; /* shared with audio driver */ if (ac97_clock >= 8000 && ac97_clock <= 48000) pbus->clock = ac97_clock; chip->ac97_bus = pbus; @@ -889,8 +890,7 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock) */ #define do_delay(chip) do {\ - set_current_state(TASK_UNINTERRUPTIBLE);\ - schedule_timeout(1);\ + schedule_timeout_uninterruptible(1);\ } while (0) static int snd_intel8x0m_ich_chip_init(intel8x0_t *chip, int probing) @@ -916,7 +916,7 @@ static int snd_intel8x0m_ich_chip_init(intel8x0_t *chip, int probing) goto __ok; do_delay(chip); } while (time_after_eq(end_time, jiffies)); - snd_printk("AC'97 warm reset still in progress? [0x%x]\n", igetdword(chip, ICHREG(GLOB_CNT))); + snd_printk(KERN_ERR "AC'97 warm reset still in progress? [0x%x]\n", igetdword(chip, ICHREG(GLOB_CNT))); return -EIO; __ok: @@ -1142,7 +1142,7 @@ static int __devinit snd_intel8x0m_create(snd_card_t * card, chip->remap_addr = ioremap_nocache(chip->addr, pci_resource_len(pci, 2)); if (chip->remap_addr == NULL) { - snd_printk("AC'97 space ioremap problem\n"); + snd_printk(KERN_ERR "AC'97 space ioremap problem\n"); snd_intel8x0_free(chip); return -EIO; } @@ -1155,7 +1155,7 @@ static int __devinit snd_intel8x0m_create(snd_card_t * card, chip->remap_bmaddr = ioremap_nocache(chip->bmaddr, pci_resource_len(pci, 3)); if (chip->remap_bmaddr == NULL) { - snd_printk("Controller space ioremap problem\n"); + snd_printk(KERN_ERR "Controller space ioremap problem\n"); snd_intel8x0_free(chip); return -EIO; } @@ -1165,7 +1165,7 @@ static int __devinit snd_intel8x0m_create(snd_card_t * card, port_inited: if (request_irq(pci->irq, snd_intel8x0_interrupt, SA_INTERRUPT|SA_SHIRQ, card->shortname, (void *)chip)) { - snd_printk("unable to grab IRQ %d\n", pci->irq); + snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_intel8x0_free(chip); return -EBUSY; } @@ -1263,20 +1263,12 @@ static struct shortname_table { static int __devinit snd_intel8x0m_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { - static int dev; snd_card_t *card; intel8x0_t *chip; int err; struct shortname_table *name; - if (dev >= SNDRV_CARDS) - return -ENODEV; - if (!enable[dev]) { - dev++; - return -ENOENT; - } - - card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + card = snd_card_new(index, id, THIS_MODULE, 0); if (card == NULL) return -ENOMEM; @@ -1295,7 +1287,7 @@ static int __devinit snd_intel8x0m_probe(struct pci_dev *pci, return err; } - if ((err = snd_intel8x0_mixer(chip, ac97_clock[dev])) < 0) { + if ((err = snd_intel8x0_mixer(chip, ac97_clock)) < 0) { snd_card_free(card); return err; } @@ -1314,7 +1306,6 @@ static int __devinit snd_intel8x0m_probe(struct pci_dev *pci, return err; } pci_set_drvdata(pci, card); - dev++; return 0; } diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 2693b6f731f3e27c03c1754a12097e2674574ce0..99eb76c56f81059e6b0709c598108d5c9e18d7d1 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -1492,7 +1492,7 @@ static int snd_m3_pcm_hw_params(snd_pcm_substream_t * substream, /* set buffer address */ s->buffer_addr = substream->runtime->dma_addr; if (s->buffer_addr & 0x3) { - snd_printk("oh my, not aligned\n"); + snd_printk(KERN_ERR "oh my, not aligned\n"); s->buffer_addr = s->buffer_addr & ~0x3; } return 0; @@ -1942,7 +1942,7 @@ static int snd_m3_ac97_wait(m3_t *chip) return 0; } while (i-- > 0); - snd_printk("ac97 serial bus busy\n"); + snd_printk(KERN_ERR "ac97 serial bus busy\n"); return 1; } @@ -2046,8 +2046,7 @@ static void snd_m3_ac97_reset(m3_t *chip) outw(0, io + GPIO_DATA); outw(dir | GPO_PRIMARY_AC97, io + GPIO_DIRECTION); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((delay1 * HZ) / 1000); + schedule_timeout_uninterruptible(msecs_to_jiffies(delay1)); outw(GPO_PRIMARY_AC97, io + GPIO_DATA); udelay(5); @@ -2055,8 +2054,7 @@ static void snd_m3_ac97_reset(m3_t *chip) outw(IO_SRAM_ENABLE | SERIAL_AC_LINK_ENABLE, io + RING_BUS_CTRL_A); outw(~0, io + GPIO_MASK); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((delay2 * HZ) / 1000); + schedule_timeout_uninterruptible(msecs_to_jiffies(delay2)); if (! snd_m3_try_read_vendor(chip)) break; @@ -2101,8 +2099,7 @@ static int __devinit snd_m3_mixer(m3_t *chip) /* seems ac97 PCM needs initialization.. hack hack.. */ snd_ac97_write(chip->ac97, AC97_PCM, 0x8000 | (15 << 8) | 15); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 10); + schedule_timeout_uninterruptible(msecs_to_jiffies(100)); snd_ac97_write(chip->ac97, AC97_PCM, 0); memset(&id, 0, sizeof(id)); @@ -2367,7 +2364,7 @@ static int __devinit snd_m3_assp_client_init(m3_t *chip, m3_dma_t *s, int index) address = 0x1100 + ((data_bytes/2) * index); if ((address + (data_bytes/2)) >= 0x1c00) { - snd_printk("no memory for %d bytes at ind %d (addr 0x%x)\n", + snd_printk(KERN_ERR "no memory for %d bytes at ind %d (addr 0x%x)\n", data_bytes, index, address); return -ENOMEM; } @@ -2476,6 +2473,7 @@ snd_m3_chip_init(m3_t *chip) t |= ASSP_0_WS_ENABLE; outb(t, chip->iobase + ASSP_CONTROL_A); + snd_m3_assp_init(chip); /* download DSP code before starting ASSP below */ outb(RUN_ASSP, chip->iobase + ASSP_CONTROL_B); outb(0x00, io + HARDWARE_VOL_CTRL); @@ -2655,7 +2653,7 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci, /* check, if we can restrict PCI DMA transfers to 28 bits */ if (pci_set_dma_mask(pci, 0x0fffffff) < 0 || pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) { - snd_printk("architecture does not support 28bit PCI busmaster DMA\n"); + snd_printk(KERN_ERR "architecture does not support 28bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -2734,14 +2732,13 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci, snd_m3_ac97_reset(chip); - snd_m3_assp_init(chip); snd_m3_amp_enable(chip, 1); tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip); if (request_irq(pci->irq, snd_m3_interrupt, SA_INTERRUPT|SA_SHIRQ, card->driver, (void *)chip)) { - snd_printk("unable to grab IRQ %d\n", pci->irq); + snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_m3_free(chip); return -ENOMEM; } diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 1a62c7f6c52bb396666d8b13693a4a9c7a2cd3a3..c341c99ec783d97f97dc110c52dfabd99ed88e4a 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -451,8 +451,7 @@ static int mixart_sync_nonblock_events(mixart_mgr_t *mgr) snd_printk(KERN_ERR "mixart: cannot process nonblock events!\n"); return -EBUSY; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } return 0; } diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 5c55a3b1d121b247c46cd8a5d64274a1631c847f..e7aa15178453bf6366afaccaa6a1d31737d0eedb 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -52,37 +52,43 @@ MODULE_SUPPORTED_DEVICE("{{NeoMagic,NM256AV}," * some compile conditions. */ -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; -static int playback_bufsize[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 16}; -static int capture_bufsize[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 16}; -static int force_ac97[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; /* disabled as default */ -static int buffer_top[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; /* not specified */ -static int use_cache[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; /* disabled */ -static int vaio_hack[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; /* disabled */ -static int reset_workaround[SNDRV_CARDS]; - -module_param_array(index, int, NULL, 0444); +static int index = SNDRV_DEFAULT_IDX1; /* Index */ +static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ +static int playback_bufsize = 16; +static int capture_bufsize = 16; +static int force_ac97; /* disabled as default */ +static int buffer_top; /* not specified */ +static int use_cache; /* disabled */ +static int vaio_hack; /* disabled */ +static int reset_workaround; +static int reset_workaround_2; + +module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); -module_param_array(id, charp, NULL, 0444); +module_param(id, charp, 0444); MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable this soundcard."); -module_param_array(playback_bufsize, int, NULL, 0444); +module_param(playback_bufsize, int, 0444); MODULE_PARM_DESC(playback_bufsize, "DAC frame size in kB for " CARD_NAME " soundcard."); -module_param_array(capture_bufsize, int, NULL, 0444); +module_param(capture_bufsize, int, 0444); MODULE_PARM_DESC(capture_bufsize, "ADC frame size in kB for " CARD_NAME " soundcard."); -module_param_array(force_ac97, bool, NULL, 0444); +module_param(force_ac97, bool, 0444); MODULE_PARM_DESC(force_ac97, "Force to use AC97 codec for " CARD_NAME " soundcard."); -module_param_array(buffer_top, int, NULL, 0444); +module_param(buffer_top, int, 0444); MODULE_PARM_DESC(buffer_top, "Set the top address of audio buffer for " CARD_NAME " soundcard."); -module_param_array(use_cache, bool, NULL, 0444); +module_param(use_cache, bool, 0444); MODULE_PARM_DESC(use_cache, "Enable the cache for coefficient table access."); -module_param_array(vaio_hack, bool, NULL, 0444); +module_param(vaio_hack, bool, 0444); MODULE_PARM_DESC(vaio_hack, "Enable workaround for Sony VAIO notebooks."); -module_param_array(reset_workaround, bool, NULL, 0444); +module_param(reset_workaround, bool, 0444); MODULE_PARM_DESC(reset_workaround, "Enable AC97 RESET workaround for some laptops."); +module_param(reset_workaround_2, bool, 0444); +MODULE_PARM_DESC(reset_workaround_2, "Enable extended AC97 RESET workaround for some other laptops."); + +/* just for backward compatibility */ +static int enable; +module_param(enable, bool, 0444); + + /* * hw definitions @@ -226,6 +232,7 @@ struct snd_nm256 { unsigned int coeffs_current: 1; /* coeff. table is loaded? */ unsigned int use_cache: 1; /* use one big coef. table */ unsigned int reset_workaround: 1; /* Workaround for some laptops to avoid freeze */ + unsigned int reset_workaround_2: 1; /* Extended workaround for some other laptops to avoid freeze */ int mixer_base; /* register offset of ac97 mixer */ int mixer_status_offset; /* offset of mixer status reg. */ @@ -313,9 +320,9 @@ static inline void snd_nm256_write_buffer(nm256_t *chip, void *src, int offset, int size) { offset -= chip->buffer_start; -#ifdef SNDRV_CONFIG_DEBUG +#ifdef CONFIG_SND_DEBUG if (offset < 0 || offset >= chip->buffer_size) { - snd_printk("write_buffer invalid offset = %d size = %d\n", offset, size); + snd_printk(KERN_ERR "write_buffer invalid offset = %d size = %d\n", offset, size); return; } #endif @@ -459,7 +466,7 @@ static int snd_nm256_acquire_irq(nm256_t *chip) if (chip->irq < 0) { if (request_irq(chip->pci->irq, chip->interrupt, SA_INTERRUPT|SA_SHIRQ, chip->card->driver, (void*)chip)) { - snd_printk("unable to grab IRQ %d\n", chip->pci->irq); + snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->pci->irq); up(&chip->irq_mutex); return -EBUSY; } @@ -1199,8 +1206,11 @@ snd_nm256_ac97_reset(ac97_t *ac97) /* Dell latitude LS will lock up by this */ snd_nm256_writeb(chip, 0x6cc, 0x87); } - snd_nm256_writeb(chip, 0x6cc, 0x80); - snd_nm256_writeb(chip, 0x6cc, 0x0); + if (! chip->reset_workaround_2) { + /* Dell latitude CSx will lock up by this */ + snd_nm256_writeb(chip, 0x6cc, 0x80); + snd_nm256_writeb(chip, 0x6cc, 0x0); + } } /* create an ac97 mixer interface */ @@ -1263,7 +1273,7 @@ snd_nm256_peek_for_sig(nm256_t *chip) temp = ioremap_nocache(chip->buffer_addr + chip->buffer_end - 0x400, 16); if (temp == NULL) { - snd_printk("Unable to scan for card signature in video RAM\n"); + snd_printk(KERN_ERR "Unable to scan for card signature in video RAM\n"); return -EBUSY; } @@ -1277,7 +1287,7 @@ snd_nm256_peek_for_sig(nm256_t *chip) if (pointer == 0xffffffff || pointer < chip->buffer_size || pointer > chip->buffer_end) { - snd_printk("invalid signature found: 0x%x\n", pointer); + snd_printk(KERN_ERR "invalid signature found: 0x%x\n", pointer); iounmap(temp); return -ENODEV; } else { @@ -1347,14 +1357,8 @@ static int snd_nm256_free(nm256_t *chip) iounmap(chip->cport); if (chip->buffer) iounmap(chip->buffer); - if (chip->res_cport) { - release_resource(chip->res_cport); - kfree_nocheck(chip->res_cport); - } - if (chip->res_buffer) { - release_resource(chip->res_buffer); - kfree_nocheck(chip->res_buffer); - } + release_and_free_resource(chip->res_cport); + release_and_free_resource(chip->res_buffer); if (chip->irq >= 0) free_irq(chip->irq, (void*)chip); @@ -1420,14 +1424,14 @@ snd_nm256_create(snd_card_t *card, struct pci_dev *pci, chip->res_cport = request_mem_region(chip->cport_addr, NM_PORT2_SIZE, card->driver); if (chip->res_cport == NULL) { - snd_printk("memory region 0x%lx (size 0x%x) busy\n", + snd_printk(KERN_ERR "memory region 0x%lx (size 0x%x) busy\n", chip->cport_addr, NM_PORT2_SIZE); err = -EBUSY; goto __error; } chip->cport = ioremap_nocache(chip->cport_addr, NM_PORT2_SIZE); if (chip->cport == NULL) { - snd_printk("unable to map control port %lx\n", chip->cport_addr); + snd_printk(KERN_ERR "unable to map control port %lx\n", chip->cport_addr); err = -ENOMEM; goto __error; } @@ -1485,7 +1489,7 @@ snd_nm256_create(snd_card_t *card, struct pci_dev *pci, chip->buffer_size, card->driver); if (chip->res_buffer == NULL) { - snd_printk("nm256: buffer 0x%lx (size 0x%x) busy\n", + snd_printk(KERN_ERR "nm256: buffer 0x%lx (size 0x%x) busy\n", chip->buffer_addr, chip->buffer_size); err = -EBUSY; goto __error; @@ -1493,7 +1497,7 @@ snd_nm256_create(snd_card_t *card, struct pci_dev *pci, chip->buffer = ioremap_nocache(chip->buffer_addr, chip->buffer_size); if (chip->buffer == NULL) { err = -ENOMEM; - snd_printk("unable to map ring buffer at %lx\n", chip->buffer_addr); + snd_printk(KERN_ERR "unable to map ring buffer at %lx\n", chip->buffer_addr); goto __error; } @@ -1542,7 +1546,7 @@ struct nm256_quirk { int type; }; -enum { NM_BLACKLISTED, NM_RESET_WORKAROUND }; +enum { NM_BLACKLISTED, NM_RESET_WORKAROUND, NM_RESET_WORKAROUND_2 }; static struct nm256_quirk nm256_quirks[] __devinitdata = { /* HP omnibook 4150 has cs4232 codec internally */ @@ -1551,6 +1555,8 @@ static struct nm256_quirk nm256_quirks[] __devinitdata = { { .vendor = 0x104d, .device = 0x8041, .type = NM_RESET_WORKAROUND }, /* Dell Latitude LS */ { .vendor = 0x1028, .device = 0x0080, .type = NM_RESET_WORKAROUND }, + /* Dell Latitude CSx */ + { .vendor = 0x1028, .device = 0x0091, .type = NM_RESET_WORKAROUND_2 }, { } /* terminator */ }; @@ -1558,7 +1564,6 @@ static struct nm256_quirk nm256_quirks[] __devinitdata = { static int __devinit snd_nm256_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { - static int dev; snd_card_t *card; nm256_t *chip; int err; @@ -1566,13 +1571,6 @@ static int __devinit snd_nm256_probe(struct pci_dev *pci, struct nm256_quirk *q; u16 subsystem_vendor, subsystem_device; - if (dev >= SNDRV_CARDS) - return -ENODEV; - if (!enable[dev]) { - dev++; - return -ENOENT; - } - pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device); @@ -1582,14 +1580,17 @@ static int __devinit snd_nm256_probe(struct pci_dev *pci, case NM_BLACKLISTED: printk(KERN_INFO "nm256: The device is blacklisted. Loading stopped\n"); return -ENODEV; + case NM_RESET_WORKAROUND_2: + reset_workaround_2 = 1; + /* Fall-through */ case NM_RESET_WORKAROUND: - reset_workaround[dev] = 1; + reset_workaround = 1; break; } } } - card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + card = snd_card_new(index, id, THIS_MODULE, 0); if (card == NULL) return -ENOMEM; @@ -1604,40 +1605,45 @@ static int __devinit snd_nm256_probe(struct pci_dev *pci, strcpy(card->driver, "NM256XL+"); break; default: - snd_printk("invalid device id 0x%x\n", pci->device); + snd_printk(KERN_ERR "invalid device id 0x%x\n", pci->device); snd_card_free(card); return -EINVAL; } - if (vaio_hack[dev]) + if (vaio_hack) xbuffer_top = 0x25a800; /* this avoids conflicts with XFree86 server */ else - xbuffer_top = buffer_top[dev]; - - if (playback_bufsize[dev] < 4) - playback_bufsize[dev] = 4; - if (playback_bufsize[dev] > 128) - playback_bufsize[dev] = 128; - if (capture_bufsize[dev] < 4) - capture_bufsize[dev] = 4; - if (capture_bufsize[dev] > 128) - capture_bufsize[dev] = 128; + xbuffer_top = buffer_top; + + if (playback_bufsize < 4) + playback_bufsize = 4; + if (playback_bufsize > 128) + playback_bufsize = 128; + if (capture_bufsize < 4) + capture_bufsize = 4; + if (capture_bufsize > 128) + capture_bufsize = 128; if ((err = snd_nm256_create(card, pci, - playback_bufsize[dev] * 1024, /* in bytes */ - capture_bufsize[dev] * 1024, /* in bytes */ - force_ac97[dev], + playback_bufsize * 1024, /* in bytes */ + capture_bufsize * 1024, /* in bytes */ + force_ac97, xbuffer_top, - use_cache[dev], + use_cache, &chip)) < 0) { snd_card_free(card); return err; } - if (reset_workaround[dev]) { + if (reset_workaround) { snd_printdd(KERN_INFO "nm256: reset_workaround activated\n"); chip->reset_workaround = 1; } + if (reset_workaround_2) { + snd_printdd(KERN_INFO "nm256: reset_workaround_2 activated\n"); + chip->reset_workaround_2 = 1; + } + if ((err = snd_nm256_pcm(chip, 0)) < 0 || (err = snd_nm256_mixer(chip)) < 0) { snd_card_free(card); @@ -1655,7 +1661,6 @@ static int __devinit snd_nm256_probe(struct pci_dev *pci, } pci_set_drvdata(pci, card); - dev++; return 0; } diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index cd313af6ebcf226f4ea7f29680923732200d4205..e6627b0e38e40f7136fdeecedbcbe48629063318 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -1369,13 +1369,13 @@ static int __devinit snd_rme32_create(rme32_t * rme32) rme32->port = pci_resource_start(rme32->pci, 0); if (request_irq(pci->irq, snd_rme32_interrupt, SA_INTERRUPT | SA_SHIRQ, "RME32", (void *) rme32)) { - snd_printk("unable to grab IRQ %d\n", pci->irq); + snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); return -EBUSY; } rme32->irq = pci->irq; if ((rme32->iobase = ioremap_nocache(rme32->port, RME32_IO_SIZE)) == 0) { - snd_printk("unable to remap memory region 0x%lx-0x%lx\n", + snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n", rme32->port, rme32->port + RME32_IO_SIZE - 1); return -ENOMEM; } diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index c495cae78dbf39f4d566e99eb888ba2749820b0c..0eddeb16a10f4bbce5aa19c5496ab457a2236eff 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -1570,13 +1570,13 @@ snd_rme96_create(rme96_t *rme96) rme96->port = pci_resource_start(rme96->pci, 0); if (request_irq(pci->irq, snd_rme96_interrupt, SA_INTERRUPT|SA_SHIRQ, "RME96", (void *)rme96)) { - snd_printk("unable to grab IRQ %d\n", pci->irq); + snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); return -EBUSY; } rme96->irq = pci->irq; if ((rme96->iobase = ioremap_nocache(rme96->port, RME96_IO_SIZE)) == 0) { - snd_printk("unable to remap memory region 0x%lx-0x%lx\n", rme96->port, rme96->port + RME96_IO_SIZE - 1); + snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n", rme96->port, rme96->port + RME96_IO_SIZE - 1); return -ENOMEM; } diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 52525eb198c742dcd1f75e0a8970d6c19e3a91b3..845158b01b0295ac089b16b56110bc1f30bf47c3 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -671,11 +671,7 @@ static int snd_hdsp_load_firmware_from_cache(hdsp_t *hdsp) { } } - if ((1000 / HZ) < 3000) { - ssleep(3); - } else { - mdelay(3000); - } + ssleep(3); if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) { snd_printk ("Hammerfall-DSP: timeout at end of firmware loading\n"); @@ -692,7 +688,7 @@ static int snd_hdsp_load_firmware_from_cache(hdsp_t *hdsp) { } if (hdsp->state & HDSP_InitializationComplete) { - snd_printk("Hammerfall-DSP: firmware loaded from cache, restoring defaults\n"); + snd_printk(KERN_INFO "Hammerfall-DSP: firmware loaded from cache, restoring defaults\n"); spin_lock_irqsave(&hdsp->lock, flags); snd_hdsp_set_defaults(hdsp); spin_unlock_irqrestore(&hdsp->lock, flags); @@ -709,9 +705,8 @@ static int hdsp_get_iobox_version (hdsp_t *hdsp) hdsp_write (hdsp, HDSP_control2Reg, HDSP_PROGRAM); hdsp_write (hdsp, HDSP_fifoData, 0); - if (hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT) < 0) { + if (hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT) < 0) return -EIO; - } hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD); hdsp_write (hdsp, HDSP_fifoData, 0); @@ -726,22 +721,30 @@ static int hdsp_get_iobox_version (hdsp_t *hdsp) } } else { /* firmware was already loaded, get iobox type */ - if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1) { + if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1) hdsp->io_type = Multiface; - } else { + else hdsp->io_type = Digiface; - } } return 0; } -static int hdsp_check_for_firmware (hdsp_t *hdsp) +static int hdsp_check_for_firmware (hdsp_t *hdsp, int show_err) { if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0; if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) { - snd_printk("Hammerfall-DSP: firmware not present.\n"); + snd_printk(KERN_ERR "Hammerfall-DSP: firmware not present.\n"); hdsp->state &= ~HDSP_FirmwareLoaded; + if (! show_err) + return -EIO; + /* try to load firmware */ + if (hdsp->state & HDSP_FirmwareCached) { + if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) + snd_printk(KERN_ERR "Hammerfall-DSP: Firmware loading from cache failed, please upload manually.\n"); + } else { + snd_printk(KERN_ERR "Hammerfall-DSP: No firmware loaded nor cached, please upload firmware.\n"); + } return -EIO; } return 0; @@ -775,9 +778,9 @@ static int hdsp_fifo_wait(hdsp_t *hdsp, int count, int timeout) static int hdsp_read_gain (hdsp_t *hdsp, unsigned int addr) { - if (addr >= HDSP_MATRIX_MIXER_SIZE) { + if (addr >= HDSP_MATRIX_MIXER_SIZE) return 0; - } + return hdsp->mixer_matrix[addr]; } @@ -802,13 +805,11 @@ static int hdsp_write_gain(hdsp_t *hdsp, unsigned int addr, unsigned short data) memory." */ - if (hdsp->io_type == H9632 && addr >= 512) { + if (hdsp->io_type == H9632 && addr >= 512) return 0; - } - if (hdsp->io_type == H9652 && addr >= 1352) { + if (hdsp->io_type == H9652 && addr >= 1352) return 0; - } hdsp->mixer_matrix[addr] = data; @@ -832,9 +833,8 @@ static int hdsp_write_gain(hdsp_t *hdsp, unsigned int addr, unsigned short data) ad = (addr << 16) + data; - if (hdsp_fifo_wait(hdsp, 127, HDSP_LONG_WAIT)) { + if (hdsp_fifo_wait(hdsp, 127, HDSP_LONG_WAIT)) return -1; - } hdsp_write (hdsp, HDSP_fifoData, ad); hdsp->mixer_matrix[addr] = data; @@ -851,9 +851,8 @@ static int snd_hdsp_use_is_exclusive(hdsp_t *hdsp) spin_lock_irqsave(&hdsp->lock, flags); if ((hdsp->playback_pid != hdsp->capture_pid) && - (hdsp->playback_pid >= 0) && (hdsp->capture_pid >= 0)) { + (hdsp->playback_pid >= 0) && (hdsp->capture_pid >= 0)) ret = 0; - } spin_unlock_irqrestore(&hdsp->lock, flags); return ret; } @@ -880,9 +879,8 @@ static int hdsp_spdif_sample_rate(hdsp_t *hdsp) unsigned int status = hdsp_read(hdsp, HDSP_statusRegister); unsigned int rate_bits = (status & HDSP_spdifFrequencyMask); - if (status & HDSP_SPDIFErrorFlag) { + if (status & HDSP_SPDIFErrorFlag) return 0; - } switch (rate_bits) { case HDSP_spdifFrequency32KHz: return 32000; @@ -918,9 +916,8 @@ static snd_pcm_uframes_t hdsp_hw_pointer(hdsp_t *hdsp) position = hdsp_read(hdsp, HDSP_statusRegister); - if (!hdsp->precise_ptr) { + if (!hdsp->precise_ptr) return (position & HDSP_BufferID) ? (hdsp->period_bytes / 4) : 0; - } position &= HDSP_BufferPositionMask; position /= 4; @@ -989,19 +986,19 @@ static int hdsp_set_rate(hdsp_t *hdsp, int rate, int called_internally) if (!(hdsp->control_register & HDSP_ClockModeMaster)) { if (called_internally) { /* request from ctl or card initialization */ - snd_printk("Hammerfall-DSP: device is not running as a clock master: cannot set sample rate.\n"); + snd_printk(KERN_ERR "Hammerfall-DSP: device is not running as a clock master: cannot set sample rate.\n"); return -1; } else { /* hw_param request while in AutoSync mode */ int external_freq = hdsp_external_sample_rate(hdsp); int spdif_freq = hdsp_spdif_sample_rate(hdsp); - if ((spdif_freq == external_freq*2) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1)) { - snd_printk("Hammerfall-DSP: Detected ADAT in double speed mode\n"); - } else if (hdsp->io_type == H9632 && (spdif_freq == external_freq*4) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1)) { - snd_printk("Hammerfall-DSP: Detected ADAT in quad speed mode\n"); - } else if (rate != external_freq) { - snd_printk("Hammerfall-DSP: No AutoSync source for requested rate\n"); + if ((spdif_freq == external_freq*2) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1)) + snd_printk(KERN_INFO "Hammerfall-DSP: Detected ADAT in double speed mode\n"); + else if (hdsp->io_type == H9632 && (spdif_freq == external_freq*4) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1)) + snd_printk(KERN_INFO "Hammerfall-DSP: Detected ADAT in quad speed mode\n"); + else if (rate != external_freq) { + snd_printk(KERN_INFO "Hammerfall-DSP: No AutoSync source for requested rate\n"); return -1; } } @@ -1019,63 +1016,53 @@ static int hdsp_set_rate(hdsp_t *hdsp, int rate, int called_internally) exists for externally-driven rate changes. All we can do is to flag rate changes in the read/write routines. */ - if (rate > 96000 && hdsp->io_type != H9632) { + if (rate > 96000 && hdsp->io_type != H9632) return -EINVAL; - } switch (rate) { case 32000: - if (current_rate > 48000) { + if (current_rate > 48000) reject_if_open = 1; - } rate_bits = HDSP_Frequency32KHz; break; case 44100: - if (current_rate > 48000) { + if (current_rate > 48000) reject_if_open = 1; - } rate_bits = HDSP_Frequency44_1KHz; break; case 48000: - if (current_rate > 48000) { + if (current_rate > 48000) reject_if_open = 1; - } rate_bits = HDSP_Frequency48KHz; break; case 64000: - if (current_rate <= 48000 || current_rate > 96000) { + if (current_rate <= 48000 || current_rate > 96000) reject_if_open = 1; - } rate_bits = HDSP_Frequency64KHz; break; case 88200: - if (current_rate <= 48000 || current_rate > 96000) { + if (current_rate <= 48000 || current_rate > 96000) reject_if_open = 1; - } rate_bits = HDSP_Frequency88_2KHz; break; case 96000: - if (current_rate <= 48000 || current_rate > 96000) { + if (current_rate <= 48000 || current_rate > 96000) reject_if_open = 1; - } rate_bits = HDSP_Frequency96KHz; break; case 128000: - if (current_rate < 128000) { + if (current_rate < 128000) reject_if_open = 1; - } rate_bits = HDSP_Frequency128KHz; break; case 176400: - if (current_rate < 128000) { + if (current_rate < 128000) reject_if_open = 1; - } rate_bits = HDSP_Frequency176_4KHz; break; case 192000: - if (current_rate < 128000) { + if (current_rate < 128000) reject_if_open = 1; - } rate_bits = HDSP_Frequency192KHz; break; default: @@ -1096,11 +1083,10 @@ static int hdsp_set_rate(hdsp_t *hdsp, int rate, int called_internally) if (rate >= 128000) { hdsp->channel_map = channel_map_H9632_qs; } else if (rate > 48000) { - if (hdsp->io_type == H9632) { + if (hdsp->io_type == H9632) hdsp->channel_map = channel_map_H9632_ds; - } else { + else hdsp->channel_map = channel_map_ds; - } } else { switch (hdsp->io_type) { case Multiface: @@ -1131,54 +1117,48 @@ static int hdsp_set_rate(hdsp_t *hdsp, int rate, int called_internally) static unsigned char snd_hdsp_midi_read_byte (hdsp_t *hdsp, int id) { /* the hardware already does the relevant bit-mask with 0xff */ - if (id) { + if (id) return hdsp_read(hdsp, HDSP_midiDataIn1); - } else { + else return hdsp_read(hdsp, HDSP_midiDataIn0); - } } static void snd_hdsp_midi_write_byte (hdsp_t *hdsp, int id, int val) { /* the hardware already does the relevant bit-mask with 0xff */ - if (id) { + if (id) hdsp_write(hdsp, HDSP_midiDataOut1, val); - } else { + else hdsp_write(hdsp, HDSP_midiDataOut0, val); - } } static int snd_hdsp_midi_input_available (hdsp_t *hdsp, int id) { - if (id) { + if (id) return (hdsp_read(hdsp, HDSP_midiStatusIn1) & 0xff); - } else { + else return (hdsp_read(hdsp, HDSP_midiStatusIn0) & 0xff); - } } static int snd_hdsp_midi_output_possible (hdsp_t *hdsp, int id) { int fifo_bytes_used; - if (id) { + if (id) fifo_bytes_used = hdsp_read(hdsp, HDSP_midiStatusOut1) & 0xff; - } else { + else fifo_bytes_used = hdsp_read(hdsp, HDSP_midiStatusOut0) & 0xff; - } - if (fifo_bytes_used < 128) { + if (fifo_bytes_used < 128) return 128 - fifo_bytes_used; - } else { + else return 0; - } } static void snd_hdsp_flush_midi_input (hdsp_t *hdsp, int id) { - while (snd_hdsp_midi_input_available (hdsp, id)) { + while (snd_hdsp_midi_input_available (hdsp, id)) snd_hdsp_midi_read_byte (hdsp, id); - } } static int snd_hdsp_midi_output_write (hdsp_midi_t *hmidi) @@ -1219,28 +1199,23 @@ static int snd_hdsp_midi_input_read (hdsp_midi_t *hmidi) spin_lock_irqsave (&hmidi->lock, flags); if ((n_pending = snd_hdsp_midi_input_available (hmidi->hdsp, hmidi->id)) > 0) { if (hmidi->input) { - if (n_pending > (int)sizeof (buf)) { + if (n_pending > (int)sizeof (buf)) n_pending = sizeof (buf); - } - for (i = 0; i < n_pending; ++i) { + for (i = 0; i < n_pending; ++i) buf[i] = snd_hdsp_midi_read_byte (hmidi->hdsp, hmidi->id); - } - if (n_pending) { + if (n_pending) snd_rawmidi_receive (hmidi->input, buf, n_pending); - } } else { /* flush the MIDI input FIFO */ - while (--n_pending) { + while (--n_pending) snd_hdsp_midi_read_byte (hmidi->hdsp, hmidi->id); - } } } hmidi->pending = 0; - if (hmidi->id) { + if (hmidi->id) hmidi->hdsp->control_register |= HDSP_Midi1InterruptEnable; - } else { + else hmidi->hdsp->control_register |= HDSP_Midi0InterruptEnable; - } hdsp_write(hmidi->hdsp, HDSP_controlRegister, hmidi->hdsp->control_register); spin_unlock_irqrestore (&hmidi->lock, flags); return snd_hdsp_midi_output_write (hmidi); @@ -1310,9 +1285,8 @@ static void snd_hdsp_midi_output_trigger(snd_rawmidi_substream_t * substream, in hmidi->istimer++; } } else { - if (hmidi->istimer && --hmidi->istimer <= 0) { + if (hmidi->istimer && --hmidi->istimer <= 0) del_timer (&hmidi->timer); - } } spin_unlock_irqrestore (&hmidi->lock, flags); if (up) @@ -1400,9 +1374,8 @@ static int __devinit snd_hdsp_create_midi (snd_card_t *card, hdsp_t *hdsp, int i spin_lock_init (&hdsp->midi[id].lock); sprintf (buf, "%s MIDI %d", card->shortname, id+1); - if (snd_rawmidi_new (card, buf, id, 1, 1, &hdsp->midi[id].rmidi) < 0) { + if (snd_rawmidi_new (card, buf, id, 1, 1, &hdsp->midi[id].rmidi) < 0) return -1; - } sprintf (hdsp->midi[id].rmidi->name, "%s MIDI %d", card->id, id+1); hdsp->midi[id].rmidi->private_data = &hdsp->midi[id]; @@ -1588,11 +1561,10 @@ static int hdsp_spdif_out(hdsp_t *hdsp) static int hdsp_set_spdif_output(hdsp_t *hdsp, int out) { - if (out) { + if (out) hdsp->control_register |= HDSP_SPDIFOpticalOut; - } else { + else hdsp->control_register &= ~HDSP_SPDIFOpticalOut; - } hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); return 0; } @@ -1642,11 +1614,10 @@ static int hdsp_spdif_professional(hdsp_t *hdsp) static int hdsp_set_spdif_professional(hdsp_t *hdsp, int val) { - if (val) { + if (val) hdsp->control_register |= HDSP_SPDIFProfessional; - } else { + else hdsp->control_register &= ~HDSP_SPDIFProfessional; - } hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); return 0; } @@ -1687,11 +1658,10 @@ static int hdsp_spdif_emphasis(hdsp_t *hdsp) static int hdsp_set_spdif_emphasis(hdsp_t *hdsp, int val) { - if (val) { + if (val) hdsp->control_register |= HDSP_SPDIFEmphasis; - } else { + else hdsp->control_register &= ~HDSP_SPDIFEmphasis; - } hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); return 0; } @@ -1732,11 +1702,10 @@ static int hdsp_spdif_nonaudio(hdsp_t *hdsp) static int hdsp_set_spdif_nonaudio(hdsp_t *hdsp, int val) { - if (val) { + if (val) hdsp->control_register |= HDSP_SPDIFNonAudio; - } else { + else hdsp->control_register &= ~HDSP_SPDIFNonAudio; - } hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); return 0; } @@ -1921,11 +1890,10 @@ static int snd_hdsp_get_autosync_sample_rate(snd_kcontrol_t * kcontrol, snd_ctl_ static int hdsp_system_clock_mode(hdsp_t *hdsp) { - if (hdsp->control_register & HDSP_ClockModeMaster) { + if (hdsp->control_register & HDSP_ClockModeMaster) return 0; - } else if (hdsp_external_sample_rate(hdsp) != hdsp->system_sample_rate) { + else if (hdsp_external_sample_rate(hdsp) != hdsp->system_sample_rate) return 0; - } return 1; } @@ -2074,16 +2042,17 @@ static int snd_hdsp_put_clock_source(snd_kcontrol_t * kcontrol, snd_ctl_elem_val val = ucontrol->value.enumerated.item[0]; if (val < 0) val = 0; if (hdsp->io_type == H9632) { - if (val > 9) val = 9; + if (val > 9) + val = 9; } else { - if (val > 6) val = 6; + if (val > 6) + val = 6; } spin_lock_irq(&hdsp->lock); - if (val != hdsp_clock_source(hdsp)) { + if (val != hdsp_clock_source(hdsp)) change = (hdsp_set_clock_source(hdsp, val) == 0) ? 1 : 0; - } else { + else change = 0; - } spin_unlock_irq(&hdsp->lock); return change; } @@ -2193,11 +2162,10 @@ static int snd_hdsp_put_da_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t if (val < 0) val = 0; if (val > 2) val = 2; spin_lock_irq(&hdsp->lock); - if (val != hdsp_da_gain(hdsp)) { + if (val != hdsp_da_gain(hdsp)) change = (hdsp_set_da_gain(hdsp, val) == 0) ? 1 : 0; - } else { + else change = 0; - } spin_unlock_irq(&hdsp->lock); return change; } @@ -2279,11 +2247,10 @@ static int snd_hdsp_put_ad_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t if (val < 0) val = 0; if (val > 2) val = 2; spin_lock_irq(&hdsp->lock); - if (val != hdsp_ad_gain(hdsp)) { + if (val != hdsp_ad_gain(hdsp)) change = (hdsp_set_ad_gain(hdsp, val) == 0) ? 1 : 0; - } else { + else change = 0; - } spin_unlock_irq(&hdsp->lock); return change; } @@ -2365,11 +2332,10 @@ static int snd_hdsp_put_phone_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value if (val < 0) val = 0; if (val > 2) val = 2; spin_lock_irq(&hdsp->lock); - if (val != hdsp_phone_gain(hdsp)) { + if (val != hdsp_phone_gain(hdsp)) change = (hdsp_set_phone_gain(hdsp, val) == 0) ? 1 : 0; - } else { + else change = 0; - } spin_unlock_irq(&hdsp->lock); return change; } @@ -2385,19 +2351,17 @@ static int snd_hdsp_put_phone_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value static int hdsp_xlr_breakout_cable(hdsp_t *hdsp) { - if (hdsp->control_register & HDSP_XLRBreakoutCable) { + if (hdsp->control_register & HDSP_XLRBreakoutCable) return 1; - } return 0; } static int hdsp_set_xlr_breakout_cable(hdsp_t *hdsp, int mode) { - if (mode) { + if (mode) hdsp->control_register |= HDSP_XLRBreakoutCable; - } else { + else hdsp->control_register &= ~HDSP_XLRBreakoutCable; - } hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); return 0; } @@ -2450,19 +2414,17 @@ static int snd_hdsp_put_xlr_breakout_cable(snd_kcontrol_t * kcontrol, snd_ctl_el static int hdsp_aeb(hdsp_t *hdsp) { - if (hdsp->control_register & HDSP_AnalogExtensionBoard) { + if (hdsp->control_register & HDSP_AnalogExtensionBoard) return 1; - } return 0; } static int hdsp_set_aeb(hdsp_t *hdsp, int mode) { - if (mode) { + if (mode) hdsp->control_register |= HDSP_AnalogExtensionBoard; - } else { + else hdsp->control_register &= ~HDSP_AnalogExtensionBoard; - } hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); return 0; } @@ -2705,11 +2667,10 @@ static int hdsp_line_out(hdsp_t *hdsp) static int hdsp_set_line_output(hdsp_t *hdsp, int out) { - if (out) { + if (out) hdsp->control_register |= HDSP_LineOut; - } else { + else hdsp->control_register &= ~HDSP_LineOut; - } hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); return 0; } @@ -2760,11 +2721,10 @@ static int snd_hdsp_put_line_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t static int hdsp_set_precise_pointer(hdsp_t *hdsp, int precise) { - if (precise) { + if (precise) hdsp->precise_ptr = 1; - } else { + else hdsp->precise_ptr = 0; - } return 0; } @@ -2814,11 +2774,10 @@ static int snd_hdsp_put_precise_pointer(snd_kcontrol_t * kcontrol, snd_ctl_elem_ static int hdsp_set_use_midi_tasklet(hdsp_t *hdsp, int use_tasklet) { - if (use_tasklet) { + if (use_tasklet) hdsp->use_midi_tasklet = 1; - } else { + else hdsp->use_midi_tasklet = 0; - } return 0; } @@ -2889,11 +2848,10 @@ static int snd_hdsp_get_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * source = ucontrol->value.integer.value[0]; destination = ucontrol->value.integer.value[1]; - if (source >= hdsp->max_channels) { + if (source >= hdsp->max_channels) addr = hdsp_playback_to_output_key(hdsp,source-hdsp->max_channels,destination); - } else { + else addr = hdsp_input_to_output_key(hdsp,source, destination); - } spin_lock_irq(&hdsp->lock); ucontrol->value.integer.value[2] = hdsp_read_gain (hdsp, addr); @@ -2916,11 +2874,10 @@ static int snd_hdsp_put_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * source = ucontrol->value.integer.value[0]; destination = ucontrol->value.integer.value[1]; - if (source >= hdsp->max_channels) { + if (source >= hdsp->max_channels) addr = hdsp_playback_to_output_key(hdsp,source-hdsp->max_channels, destination); - } else { + else addr = hdsp_input_to_output_key(hdsp,source, destination); - } gain = ucontrol->value.integer.value[2]; @@ -2957,14 +2914,12 @@ static int hdsp_wc_sync_check(hdsp_t *hdsp) { int status2 = hdsp_read(hdsp, HDSP_status2Register); if (status2 & HDSP_wc_lock) { - if (status2 & HDSP_wc_sync) { + if (status2 & HDSP_wc_sync) return 2; - } else { + else return 1; - } - } else { + } else return 0; - } return 0; } @@ -2988,14 +2943,13 @@ static int snd_hdsp_get_wc_sync_check(snd_kcontrol_t * kcontrol, snd_ctl_elem_va static int hdsp_spdif_sync_check(hdsp_t *hdsp) { int status = hdsp_read(hdsp, HDSP_statusRegister); - if (status & HDSP_SPDIFErrorFlag) { + if (status & HDSP_SPDIFErrorFlag) return 0; - } else { - if (status & HDSP_SPDIFSync) { + else { + if (status & HDSP_SPDIFSync) return 2; - } else { + else return 1; - } } return 0; } @@ -3021,14 +2975,12 @@ static int hdsp_adatsync_sync_check(hdsp_t *hdsp) { int status = hdsp_read(hdsp, HDSP_statusRegister); if (status & HDSP_TimecodeLock) { - if (status & HDSP_TimecodeSync) { + if (status & HDSP_TimecodeSync) return 2; - } else { + else return 1; - } - } else { + } else return 0; - } } static int snd_hdsp_get_adatsync_sync_check(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) @@ -3051,14 +3003,12 @@ static int hdsp_adat_sync_check(hdsp_t *hdsp, int idx) int status = hdsp_read(hdsp, HDSP_statusRegister); if (status & (HDSP_Lock0>>idx)) { - if (status & (HDSP_Sync0>>idx)) { + if (status & (HDSP_Sync0>>idx)) return 2; - } else { + else return 1; - } - } else { + } else return 0; - } } static int snd_hdsp_get_adat_sync_check(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) @@ -3171,9 +3121,8 @@ static int snd_hdsp_create_controls(snd_card_t *card, hdsp_t *hdsp) snd_kcontrol_t *kctl; for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_controls); idx++) { - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_controls[idx], hdsp))) < 0) { + if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_controls[idx], hdsp))) < 0) return err; - } if (idx == 1) /* IEC958 (S/PDIF) Stream */ hdsp->spdif_ctl = kctl; } @@ -3181,32 +3130,28 @@ static int snd_hdsp_create_controls(snd_card_t *card, hdsp_t *hdsp) /* ADAT SyncCheck status */ snd_hdsp_adat_sync_check.name = "ADAT Lock Status"; snd_hdsp_adat_sync_check.index = 1; - if ((err = snd_ctl_add (card, kctl = snd_ctl_new1(&snd_hdsp_adat_sync_check, hdsp)))) { + if ((err = snd_ctl_add (card, kctl = snd_ctl_new1(&snd_hdsp_adat_sync_check, hdsp)))) return err; - } if (hdsp->io_type == Digiface || hdsp->io_type == H9652) { for (idx = 1; idx < 3; ++idx) { snd_hdsp_adat_sync_check.index = idx+1; - if ((err = snd_ctl_add (card, kctl = snd_ctl_new1(&snd_hdsp_adat_sync_check, hdsp)))) { + if ((err = snd_ctl_add (card, kctl = snd_ctl_new1(&snd_hdsp_adat_sync_check, hdsp)))) return err; - } } } /* DA, AD and Phone gain and XLR breakout cable controls for H9632 cards */ if (hdsp->io_type == H9632) { for (idx = 0; idx < ARRAY_SIZE(snd_hdsp_9632_controls); idx++) { - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_9632_controls[idx], hdsp))) < 0) { + if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_9632_controls[idx], hdsp))) < 0) return err; - } } } /* AEB control for H96xx card */ if (hdsp->io_type == H9632 || hdsp->io_type == H9652) { - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_96xx_aeb, hdsp))) < 0) { + if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_96xx_aeb, hdsp))) < 0) return err; - } } return 0; @@ -3228,12 +3173,11 @@ snd_hdsp_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) char *clock_source; int x; - if (hdsp_check_for_iobox (hdsp)) { + if (hdsp_check_for_iobox (hdsp)) snd_iprintf(buffer, "No I/O box connected.\nPlease connect one and upload firmware.\n"); return; - } - if (hdsp_check_for_firmware(hdsp)) { + if (hdsp_check_for_firmware(hdsp, 0)) { if (hdsp->state & HDSP_FirmwareCached) { if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) { snd_iprintf(buffer, "Firmware loading from cache failed, please upload manually.\n"); @@ -3314,11 +3258,10 @@ snd_hdsp_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) } snd_iprintf (buffer, "Sample Clock Source: %s\n", clock_source); - if (hdsp_system_clock_mode(hdsp)) { + if (hdsp_system_clock_mode(hdsp)) system_clock_mode = "Slave"; - } else { + else system_clock_mode = "Master"; - } switch (hdsp_pref_sync_ref (hdsp)) { case HDSP_SYNC_FROM_WORD: @@ -3400,85 +3343,75 @@ snd_hdsp_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) break; } - if (hdsp->control_register & HDSP_SPDIFOpticalOut) { + if (hdsp->control_register & HDSP_SPDIFOpticalOut) snd_iprintf(buffer, "IEC958 output: Coaxial & ADAT1\n"); - } else { + else snd_iprintf(buffer, "IEC958 output: Coaxial only\n"); - } - if (hdsp->control_register & HDSP_SPDIFProfessional) { + if (hdsp->control_register & HDSP_SPDIFProfessional) snd_iprintf(buffer, "IEC958 quality: Professional\n"); - } else { + else snd_iprintf(buffer, "IEC958 quality: Consumer\n"); - } - if (hdsp->control_register & HDSP_SPDIFEmphasis) { + if (hdsp->control_register & HDSP_SPDIFEmphasis) snd_iprintf(buffer, "IEC958 emphasis: on\n"); - } else { + else snd_iprintf(buffer, "IEC958 emphasis: off\n"); - } - if (hdsp->control_register & HDSP_SPDIFNonAudio) { + if (hdsp->control_register & HDSP_SPDIFNonAudio) snd_iprintf(buffer, "IEC958 NonAudio: on\n"); - } else { + else snd_iprintf(buffer, "IEC958 NonAudio: off\n"); - } - if ((x = hdsp_spdif_sample_rate (hdsp)) != 0) { + if ((x = hdsp_spdif_sample_rate (hdsp)) != 0) snd_iprintf (buffer, "IEC958 sample rate: %d\n", x); - } else { + else snd_iprintf (buffer, "IEC958 sample rate: Error flag set\n"); - } snd_iprintf(buffer, "\n"); /* Sync Check */ x = status & HDSP_Sync0; - if (status & HDSP_Lock0) { + if (status & HDSP_Lock0) snd_iprintf(buffer, "ADAT1: %s\n", x ? "Sync" : "Lock"); - } else { + else snd_iprintf(buffer, "ADAT1: No Lock\n"); - } switch (hdsp->io_type) { case Digiface: case H9652: x = status & HDSP_Sync1; - if (status & HDSP_Lock1) { + if (status & HDSP_Lock1) snd_iprintf(buffer, "ADAT2: %s\n", x ? "Sync" : "Lock"); - } else { + else snd_iprintf(buffer, "ADAT2: No Lock\n"); - } x = status & HDSP_Sync2; - if (status & HDSP_Lock2) { + if (status & HDSP_Lock2) snd_iprintf(buffer, "ADAT3: %s\n", x ? "Sync" : "Lock"); - } else { + else snd_iprintf(buffer, "ADAT3: No Lock\n"); - } + break; default: /* relax */ break; } x = status & HDSP_SPDIFSync; - if (status & HDSP_SPDIFErrorFlag) { + if (status & HDSP_SPDIFErrorFlag) snd_iprintf (buffer, "SPDIF: No Lock\n"); - } else { + else snd_iprintf (buffer, "SPDIF: %s\n", x ? "Sync" : "Lock"); - } x = status2 & HDSP_wc_sync; - if (status2 & HDSP_wc_lock) { + if (status2 & HDSP_wc_lock) snd_iprintf (buffer, "Word Clock: %s\n", x ? "Sync" : "Lock"); - } else { + else snd_iprintf (buffer, "Word Clock: No Lock\n"); - } x = status & HDSP_TimecodeSync; - if (status & HDSP_TimecodeLock) { + if (status & HDSP_TimecodeLock) snd_iprintf(buffer, "ADAT Sync: %s\n", x ? "Sync" : "Lock"); - } else { + else snd_iprintf(buffer, "ADAT Sync: No Lock\n"); - } snd_iprintf(buffer, "\n"); @@ -3527,11 +3460,10 @@ snd_hdsp_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) snd_iprintf(buffer, "XLR Breakout Cable : %s\n", hdsp_xlr_breakout_cable(hdsp) ? "yes" : "no"); - if (hdsp->control_register & HDSP_AnalogExtensionBoard) { + if (hdsp->control_register & HDSP_AnalogExtensionBoard) snd_iprintf(buffer, "AEB : on (ADAT1 internal)\n"); - } else { + else snd_iprintf(buffer, "AEB : off (ADAT1 external)\n"); - } snd_iprintf(buffer, "\n"); } @@ -3610,25 +3542,22 @@ static int snd_hdsp_set_defaults(hdsp_t *hdsp) #else hdsp->control2_register = 0; #endif - if (hdsp->io_type == H9652) { + if (hdsp->io_type == H9652) snd_hdsp_9652_enable_mixer (hdsp); - } else { - hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register); - } + else + hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register); hdsp_reset_hw_pointer(hdsp); hdsp_compute_period_size(hdsp); /* silence everything */ - for (i = 0; i < HDSP_MATRIX_MIXER_SIZE; ++i) { + for (i = 0; i < HDSP_MATRIX_MIXER_SIZE; ++i) hdsp->mixer_matrix[i] = MINUS_INFINITY_GAIN; - } for (i = 0; i < ((hdsp->io_type == H9652 || hdsp->io_type == H9632) ? 1352 : HDSP_MATRIX_MIXER_SIZE); ++i) { - if (hdsp_write_gain (hdsp, i, MINUS_INFINITY_GAIN)) { + if (hdsp_write_gain (hdsp, i, MINUS_INFINITY_GAIN)) return -EIO; - } } /* H9632 specific defaults */ @@ -3649,12 +3578,10 @@ static void hdsp_midi_tasklet(unsigned long arg) { hdsp_t *hdsp = (hdsp_t *)arg; - if (hdsp->midi[0].pending) { + if (hdsp->midi[0].pending) snd_hdsp_midi_input_read (&hdsp->midi[0]); - } - if (hdsp->midi[1].pending) { + if (hdsp->midi[1].pending) snd_hdsp_midi_input_read (&hdsp->midi[1]); - } } static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id, struct pt_regs *regs) @@ -3674,9 +3601,8 @@ static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id, struct pt_regs *reg midi0 = status & HDSP_midi0IRQPending; midi1 = status & HDSP_midi1IRQPending; - if (!audio && !midi0 && !midi1) { + if (!audio && !midi0 && !midi1) return IRQ_NONE; - } hdsp_write(hdsp, HDSP_interruptConfirmation, 0); @@ -3684,13 +3610,11 @@ static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id, struct pt_regs *reg midi1status = hdsp_read (hdsp, HDSP_midiStatusIn1) & 0xff; if (audio) { - if (hdsp->capture_substream) { + if (hdsp->capture_substream) snd_pcm_period_elapsed(hdsp->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); - } - if (hdsp->playback_substream) { + if (hdsp->playback_substream) snd_pcm_period_elapsed(hdsp->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream); - } } if (midi0 && midi0status) { @@ -3735,15 +3659,13 @@ static char *hdsp_channel_buffer_location(hdsp_t *hdsp, snd_assert(channel >= 0 && channel < hdsp->max_channels, return NULL); - if ((mapped_channel = hdsp->channel_map[channel]) < 0) { + if ((mapped_channel = hdsp->channel_map[channel]) < 0) return NULL; - } - if (stream == SNDRV_PCM_STREAM_CAPTURE) { + if (stream == SNDRV_PCM_STREAM_CAPTURE) return hdsp->capture_buffer + (mapped_channel * HDSP_CHANNEL_BUFFER_BYTES); - } else { + else return hdsp->playback_buffer + (mapped_channel * HDSP_CHANNEL_BUFFER_BYTES); - } } static int snd_hdsp_playback_copy(snd_pcm_substream_t *substream, int channel, @@ -3824,20 +3746,11 @@ static int snd_hdsp_hw_params(snd_pcm_substream_t *substream, pid_t this_pid; pid_t other_pid; - if (hdsp_check_for_iobox (hdsp)) { + if (hdsp_check_for_iobox (hdsp)) return -EIO; - } - if (hdsp_check_for_firmware(hdsp)) { - if (hdsp->state & HDSP_FirmwareCached) { - if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) { - snd_printk("Hammerfall-DSP: Firmware loading from cache failed, please upload manually.\n"); - } - } else { - snd_printk("Hammerfall-DSP: No firmware loaded nor cached, please upload firmware.\n"); - } + if (hdsp_check_for_firmware(hdsp, 1)) return -EIO; - } spin_lock_irq(&hdsp->lock); @@ -3908,9 +3821,8 @@ static int snd_hdsp_channel_info(snd_pcm_substream_t *substream, snd_assert(info->channel < hdsp->max_channels, return -EINVAL); - if ((mapped_channel = hdsp->channel_map[info->channel]) < 0) { + if ((mapped_channel = hdsp->channel_map[info->channel]) < 0) return -EINVAL; - } info->offset = mapped_channel * HDSP_CHANNEL_BUFFER_BYTES; info->first = 0; @@ -3923,14 +3835,9 @@ static int snd_hdsp_ioctl(snd_pcm_substream_t *substream, { switch (cmd) { case SNDRV_PCM_IOCTL1_RESET: - { return snd_hdsp_reset(substream); - } case SNDRV_PCM_IOCTL1_CHANNEL_INFO: - { - snd_pcm_channel_info_t *info = arg; - return snd_hdsp_channel_info(substream, info); - } + return snd_hdsp_channel_info(substream, arg); default: break; } @@ -3944,20 +3851,11 @@ static int snd_hdsp_trigger(snd_pcm_substream_t *substream, int cmd) snd_pcm_substream_t *other; int running; - if (hdsp_check_for_iobox (hdsp)) { + if (hdsp_check_for_iobox (hdsp)) return -EIO; - } - if (hdsp_check_for_firmware(hdsp)) { - if (hdsp->state & HDSP_FirmwareCached) { - if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) { - snd_printk("Hammerfall-DSP: Firmware loading from cache failed, please upload manually.\n"); - } - } else { - snd_printk("Hammerfall-DSP: No firmware loaded nor cached, please upload firmware.\n"); - } + if (hdsp_check_for_firmware(hdsp, 1)) return -EIO; - } spin_lock(&hdsp->lock); running = hdsp->running; @@ -4022,20 +3920,11 @@ static int snd_hdsp_prepare(snd_pcm_substream_t *substream) hdsp_t *hdsp = snd_pcm_substream_chip(substream); int result = 0; - if (hdsp_check_for_iobox (hdsp)) { + if (hdsp_check_for_iobox (hdsp)) return -EIO; - } - if (hdsp_check_for_firmware(hdsp)) { - if (hdsp->state & HDSP_FirmwareCached) { - if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) { - snd_printk("Hammerfall-DSP: Firmware loading from cache failed, please upload manually.\n"); - } - } else { - snd_printk("Hammerfall-DSP: No firmware loaded nor cached, please upload firmware.\n"); - } + if (hdsp_check_for_firmware(hdsp, 1)) return -EIO; - } spin_lock_irq(&hdsp->lock); if (!hdsp->running) @@ -4285,20 +4174,11 @@ static int snd_hdsp_playback_open(snd_pcm_substream_t *substream) hdsp_t *hdsp = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - if (hdsp_check_for_iobox (hdsp)) { + if (hdsp_check_for_iobox (hdsp)) return -EIO; - } - if (hdsp_check_for_firmware(hdsp)) { - if (hdsp->state & HDSP_FirmwareCached) { - if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) { - snd_printk("Hammerfall-DSP: Firmware loading from cache failed, please upload manually.\n"); - } - } else { - snd_printk("Hammerfall-DSP: No firmware loaded nor cached, please upload firmware.\n"); - } + if (hdsp_check_for_firmware(hdsp, 1)) return -EIO; - } spin_lock_irq(&hdsp->lock); @@ -4367,20 +4247,11 @@ static int snd_hdsp_capture_open(snd_pcm_substream_t *substream) hdsp_t *hdsp = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - if (hdsp_check_for_iobox (hdsp)) { + if (hdsp_check_for_iobox (hdsp)) return -EIO; - } - if (hdsp_check_for_firmware(hdsp)) { - if (hdsp->state & HDSP_FirmwareCached) { - if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) { - snd_printk("Hammerfall-DSP: Firmware loading from cache failed, please upload manually.\n"); - } - } else { - snd_printk("Hammerfall-DSP: No firmware loaded nor cached, please upload firmware.\n"); - } + if (hdsp_check_for_firmware(hdsp, 1)) return -EIO; - } spin_lock_irq(&hdsp->lock); @@ -4589,19 +4460,17 @@ static int snd_hdsp_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, unsigned int int i; if (!(hdsp->state & HDSP_FirmwareLoaded)) { - snd_printk("Hammerfall-DSP: Firmware needs to be uploaded to the card.\n"); + snd_printk(KERN_ERR "Hammerfall-DSP: Firmware needs to be uploaded to the card.\n"); return -EINVAL; } spin_lock_irqsave(&hdsp->lock, flags); info.pref_sync_ref = (unsigned char)hdsp_pref_sync_ref(hdsp); info.wordclock_sync_check = (unsigned char)hdsp_wc_sync_check(hdsp); - if (hdsp->io_type != H9632) { + if (hdsp->io_type != H9632) info.adatsync_sync_check = (unsigned char)hdsp_adatsync_sync_check(hdsp); - } info.spdif_sync_check = (unsigned char)hdsp_spdif_sync_check(hdsp); - for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != H9632) ? 3 : 1); ++i) { + for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != H9632) ? 3 : 1); ++i) info.adat_sync_check[i] = (unsigned char)hdsp_adat_sync_check(hdsp, i); - } info.spdif_in = (unsigned char)hdsp_spdif_in(hdsp); info.spdif_out = (unsigned char)hdsp_spdif_out(hdsp); info.spdif_professional = (unsigned char)hdsp_spdif_professional(hdsp); @@ -4621,9 +4490,8 @@ static int snd_hdsp_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, unsigned int info.xlr_breakout_cable = (unsigned char)hdsp_xlr_breakout_cable(hdsp); } - if (hdsp->io_type == H9632 || hdsp->io_type == H9652) { + if (hdsp->io_type == H9632 || hdsp->io_type == H9652) info.analog_extension_board = (unsigned char)hdsp_aeb(hdsp); - } spin_unlock_irqrestore(&hdsp->lock, flags); if (copy_to_user(argp, &info, sizeof(info))) return -EFAULT; @@ -4645,15 +4513,13 @@ static int snd_hdsp_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, unsigned int if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return -EINVAL; if (hdsp->io_type == Undefined) { - if ((err = hdsp_get_iobox_version(hdsp)) < 0) { + if ((err = hdsp_get_iobox_version(hdsp)) < 0) return err; - } } hdsp_version.io_type = hdsp->io_type; hdsp_version.firmware_rev = hdsp->firmware_rev; - if ((err = copy_to_user(argp, &hdsp_version, sizeof(hdsp_version)))) { + if ((err = copy_to_user(argp, &hdsp_version, sizeof(hdsp_version)))) return -EFAULT; - } break; } case SNDRV_HDSP_IOCTL_UPLOAD_FIRMWARE: { @@ -4668,38 +4534,33 @@ static int snd_hdsp_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, unsigned int if (hdsp->state & (HDSP_FirmwareCached | HDSP_FirmwareLoaded)) return -EBUSY; - snd_printk("Hammerfall-DSP: initializing firmware upload\n"); + snd_printk(KERN_INFO "Hammerfall-DSP: initializing firmware upload\n"); firmware = (hdsp_firmware_t __user *)argp; - if (get_user(firmware_data, &firmware->firmware_data)) { + if (get_user(firmware_data, &firmware->firmware_data)) return -EFAULT; - } - if (hdsp_check_for_iobox (hdsp)) { + if (hdsp_check_for_iobox (hdsp)) return -EIO; - } - if (copy_from_user(hdsp->firmware_cache, firmware_data, sizeof(hdsp->firmware_cache)) != 0) { + if (copy_from_user(hdsp->firmware_cache, firmware_data, sizeof(hdsp->firmware_cache)) != 0) return -EFAULT; - } hdsp->state |= HDSP_FirmwareCached; - if ((err = snd_hdsp_load_firmware_from_cache(hdsp)) < 0) { + if ((err = snd_hdsp_load_firmware_from_cache(hdsp)) < 0) return err; - } if (!(hdsp->state & HDSP_InitializationComplete)) { - if ((err = snd_hdsp_enable_io(hdsp)) < 0) { + if ((err = snd_hdsp_enable_io(hdsp)) < 0) return err; - } snd_hdsp_initialize_channels(hdsp); snd_hdsp_initialize_midi_flush(hdsp); if ((err = snd_hdsp_create_alsa_devices(hdsp->card, hdsp)) < 0) { - snd_printk("Hammerfall-DSP: error creating alsa devices\n"); - return err; + snd_printk(KERN_ERR "Hammerfall-DSP: error creating alsa devices\n"); + return err; } } break; @@ -4790,7 +4651,7 @@ static int snd_hdsp_enable_io (hdsp_t *hdsp) int i; if (hdsp_fifo_wait (hdsp, 0, 100)) { - snd_printk("Hammerfall-DSP: enable_io fifo_wait failed\n"); + snd_printk(KERN_ERR "Hammerfall-DSP: enable_io fifo_wait failed\n"); return -EIO; } @@ -4856,25 +4717,25 @@ static int snd_hdsp_create_alsa_devices(snd_card_t *card, hdsp_t *hdsp) int err; if ((err = snd_hdsp_create_pcm(card, hdsp)) < 0) { - snd_printk("Hammerfall-DSP: Error creating pcm interface\n"); + snd_printk(KERN_ERR "Hammerfall-DSP: Error creating pcm interface\n"); return err; } if ((err = snd_hdsp_create_midi(card, hdsp, 0)) < 0) { - snd_printk("Hammerfall-DSP: Error creating first midi interface\n"); + snd_printk(KERN_ERR "Hammerfall-DSP: Error creating first midi interface\n"); return err; } if (hdsp->io_type == Digiface || hdsp->io_type == H9652) { if ((err = snd_hdsp_create_midi(card, hdsp, 1)) < 0) { - snd_printk("Hammerfall-DSP: Error creating second midi interface\n"); + snd_printk(KERN_ERR "Hammerfall-DSP: Error creating second midi interface\n"); return err; } } if ((err = snd_hdsp_create_controls(card, hdsp)) < 0) { - snd_printk("Hammerfall-DSP: Error creating ctl interface\n"); + snd_printk(KERN_ERR "Hammerfall-DSP: Error creating ctl interface\n"); return err; } @@ -4887,7 +4748,7 @@ static int snd_hdsp_create_alsa_devices(snd_card_t *card, hdsp_t *hdsp) hdsp->playback_substream = NULL; if ((err = snd_hdsp_set_defaults(hdsp)) < 0) { - snd_printk("Hammerfall-DSP: Error setting default values\n"); + snd_printk(KERN_ERR "Hammerfall-DSP: Error setting default values\n"); return err; } @@ -4897,7 +4758,7 @@ static int snd_hdsp_create_alsa_devices(snd_card_t *card, hdsp_t *hdsp) hdsp->port, hdsp->irq); if ((err = snd_card_register(card)) < 0) { - snd_printk("Hammerfall-DSP: error registering card\n"); + snd_printk(KERN_ERR "Hammerfall-DSP: error registering card\n"); return err; } hdsp->state |= HDSP_InitializationComplete; @@ -4963,18 +4824,17 @@ static int __devinit hdsp_request_fw_loader(hdsp_t *hdsp) return err; if (!(hdsp->state & HDSP_InitializationComplete)) { - if ((err = snd_hdsp_enable_io(hdsp)) < 0) { + if ((err = snd_hdsp_enable_io(hdsp)) < 0) return err; - } if ((err = snd_hdsp_create_hwdep(hdsp->card, hdsp)) < 0) { - snd_printk("Hammerfall-DSP: error creating hwdep device\n"); + snd_printk(KERN_ERR "Hammerfall-DSP: error creating hwdep device\n"); return err; } snd_hdsp_initialize_channels(hdsp); snd_hdsp_initialize_midi_flush(hdsp); if ((err = snd_hdsp_create_alsa_devices(hdsp->card, hdsp)) < 0) { - snd_printk("Hammerfall-DSP: error creating alsa devices\n"); + snd_printk(KERN_ERR "Hammerfall-DSP: error creating alsa devices\n"); return err; } } @@ -5029,11 +4889,11 @@ static int __devinit snd_hdsp_create(snd_card_t *card, strcpy(card->driver, "H-DSP"); strcpy(card->mixername, "Xilinx FPGA"); - if (hdsp->firmware_rev < 0xa) { + if (hdsp->firmware_rev < 0xa) return -ENODEV; - } else if (hdsp->firmware_rev < 0x64) { + else if (hdsp->firmware_rev < 0x64) hdsp->card_name = "RME Hammerfall DSP"; - } else if (hdsp->firmware_rev < 0x96) { + else if (hdsp->firmware_rev < 0x96) { hdsp->card_name = "RME HDSP 9652"; is_9652 = 1; } else { @@ -5042,9 +4902,8 @@ static int __devinit snd_hdsp_create(snd_card_t *card, is_9632 = 1; } - if ((err = pci_enable_device(pci)) < 0) { + if ((err = pci_enable_device(pci)) < 0) return err; - } pci_set_master(hdsp->pci); @@ -5052,12 +4911,12 @@ static int __devinit snd_hdsp_create(snd_card_t *card, return err; hdsp->port = pci_resource_start(pci, 0); if ((hdsp->iobase = ioremap_nocache(hdsp->port, HDSP_IO_EXTENT)) == NULL) { - snd_printk("Hammerfall-DSP: unable to remap region 0x%lx-0x%lx\n", hdsp->port, hdsp->port + HDSP_IO_EXTENT - 1); + snd_printk(KERN_ERR "Hammerfall-DSP: unable to remap region 0x%lx-0x%lx\n", hdsp->port, hdsp->port + HDSP_IO_EXTENT - 1); return -EBUSY; } if (request_irq(pci->irq, snd_hdsp_interrupt, SA_INTERRUPT|SA_SHIRQ, "hdsp", (void *)hdsp)) { - snd_printk("Hammerfall-DSP: unable to use IRQ %d\n", pci->irq); + snd_printk(KERN_ERR "Hammerfall-DSP: unable to use IRQ %d\n", pci->irq); return -EBUSY; } @@ -5065,71 +4924,58 @@ static int __devinit snd_hdsp_create(snd_card_t *card, hdsp->precise_ptr = 1; hdsp->use_midi_tasklet = 1; - if ((err = snd_hdsp_initialize_memory(hdsp)) < 0) { + if ((err = snd_hdsp_initialize_memory(hdsp)) < 0) return err; - } if (!is_9652 && !is_9632) { /* we wait 2 seconds to let freshly inserted cardbus cards do their hardware init */ - if ((1000 / HZ) < 2000) { - ssleep(2); - } else { - mdelay(2000); - } + ssleep(2); if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) { #ifdef HDSP_FW_LOADER - if ((err = hdsp_request_fw_loader(hdsp)) < 0) { + if ((err = hdsp_request_fw_loader(hdsp)) < 0) /* we don't fail as this can happen if userspace is not ready for firmware upload */ - snd_printk("Hammerfall-DSP: couldn't get firmware from userspace. try using hdsploader\n"); - } else { + snd_printk(KERN_ERR "Hammerfall-DSP: couldn't get firmware from userspace. try using hdsploader\n"); + else /* init is complete, we return */ return 0; - } #endif /* no iobox connected, we defer initialization */ - snd_printk("Hammerfall-DSP: card initialization pending : waiting for firmware\n"); - if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) { + snd_printk(KERN_INFO "Hammerfall-DSP: card initialization pending : waiting for firmware\n"); + if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) return err; - } return 0; } else { - snd_printk("Hammerfall-DSP: Firmware already present, initializing card.\n"); - if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1) { + snd_printk(KERN_INFO "Hammerfall-DSP: Firmware already present, initializing card.\n"); + if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1) hdsp->io_type = Multiface; - } else { + else hdsp->io_type = Digiface; - } } } - if ((err = snd_hdsp_enable_io(hdsp)) != 0) { + if ((err = snd_hdsp_enable_io(hdsp)) != 0) return err; - } - if (is_9652) { + if (is_9652) hdsp->io_type = H9652; - } - if (is_9632) { + if (is_9632) hdsp->io_type = H9632; - } - if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) { + if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) return err; - } snd_hdsp_initialize_channels(hdsp); snd_hdsp_initialize_midi_flush(hdsp); hdsp->state |= HDSP_FirmwareLoaded; - if ((err = snd_hdsp_create_alsa_devices(card, hdsp)) < 0) { + if ((err = snd_hdsp_create_alsa_devices(card, hdsp)) < 0) return err; - } return 0; } diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index fc3f3283ff37e28ccef26b506a16784cf60f97c3..60a1141f13271241b84daac4a14bed74e790fe8e 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -3563,8 +3563,7 @@ static int snd_hdspm_free(hdspm_t * hdspm) free_irq(hdspm->irq, (void *) hdspm); - if (hdspm->mixer) - kfree(hdspm->mixer); + kfree(hdspm->mixer); if (hdspm->iobase) iounmap(hdspm->iobase); diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index b600f45e183474aca9b8b9ee2bf7a2881f0c293e..59fcef9b6b81d0b7e7859ec3ca6882a3e07cec31 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -779,7 +779,7 @@ static inline int rme9652_spdif_sample_rate(rme9652_t *s) break; default: - snd_printk("%s: unknown S/PDIF input rate (bits = 0x%x)\n", + snd_printk(KERN_ERR "%s: unknown S/PDIF input rate (bits = 0x%x)\n", s->card_name, rate_bits); return 0; break; @@ -2496,12 +2496,12 @@ static int __devinit snd_rme9652_create(snd_card_t *card, rme9652->port = pci_resource_start(pci, 0); rme9652->iobase = ioremap_nocache(rme9652->port, RME9652_IO_EXTENT); if (rme9652->iobase == NULL) { - snd_printk("unable to remap region 0x%lx-0x%lx\n", rme9652->port, rme9652->port + RME9652_IO_EXTENT - 1); + snd_printk(KERN_ERR "unable to remap region 0x%lx-0x%lx\n", rme9652->port, rme9652->port + RME9652_IO_EXTENT - 1); return -EBUSY; } if (request_irq(pci->irq, snd_rme9652_interrupt, SA_INTERRUPT|SA_SHIRQ, "rme9652", (void *)rme9652)) { - snd_printk("unable to request IRQ %d\n", pci->irq); + snd_printk(KERN_ERR "unable to request IRQ %d\n", pci->irq); return -EBUSY; } rme9652->irq = pci->irq; diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index 1f6c2bfd43fdef56faa85973b24e7b70f431d40d..9a35474aad052fcee67e161124fcce5f06437553 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -591,7 +591,7 @@ static irqreturn_t snd_sonicvibes_interrupt(int irq, void *dev_id, struct pt_reg return IRQ_NONE; if (status == 0xff) { /* failure */ outb(sonic->irqmask = ~0, SV_REG(sonic, IRQMASK)); - snd_printk("IRQ failure - interrupts disabled!!\n"); + snd_printk(KERN_ERR "IRQ failure - interrupts disabled!!\n"); return IRQ_HANDLED; } if (sonic->pcm) { @@ -1205,14 +1205,8 @@ static int snd_sonicvibes_free(sonicvibes_t *sonic) pci_write_config_dword(sonic->pci, 0x48, sonic->dmac_port); if (sonic->irq >= 0) free_irq(sonic->irq, (void *)sonic); - if (sonic->res_dmaa) { - release_resource(sonic->res_dmaa); - kfree_nocheck(sonic->res_dmaa); - } - if (sonic->res_dmac) { - release_resource(sonic->res_dmac); - kfree_nocheck(sonic->res_dmac); - } + release_and_free_resource(sonic->res_dmaa); + release_and_free_resource(sonic->res_dmac); pci_release_regions(sonic->pci); pci_disable_device(sonic->pci); kfree(sonic); @@ -1245,7 +1239,7 @@ static int __devinit snd_sonicvibes_create(snd_card_t * card, /* check, if we can restrict PCI DMA transfers to 24 bits */ if (pci_set_dma_mask(pci, 0x00ffffff) < 0 || pci_set_consistent_dma_mask(pci, 0x00ffffff) < 0) { - snd_printk("architecture does not support 24bit PCI busmaster DMA\n"); + snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -1273,7 +1267,7 @@ static int __devinit snd_sonicvibes_create(snd_card_t * card, sonic->game_port = pci_resource_start(pci, 4); if (request_irq(pci->irq, snd_sonicvibes_interrupt, SA_INTERRUPT|SA_SHIRQ, "S3 SonicVibes", (void *)sonic)) { - snd_printk("unable to grab IRQ %d\n", pci->irq); + snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_sonicvibes_free(sonic); return -EBUSY; } @@ -1287,24 +1281,24 @@ static int __devinit snd_sonicvibes_create(snd_card_t * card, if (!dmaa) { dmaa = dmaio; dmaio += 0x10; - snd_printk("BIOS did not allocate DDMA channel A i/o, allocated at 0x%x\n", dmaa); + snd_printk(KERN_INFO "BIOS did not allocate DDMA channel A i/o, allocated at 0x%x\n", dmaa); } if (!dmac) { dmac = dmaio; dmaio += 0x10; - snd_printk("BIOS did not allocate DDMA channel C i/o, allocated at 0x%x\n", dmac); + snd_printk(KERN_INFO "BIOS did not allocate DDMA channel C i/o, allocated at 0x%x\n", dmac); } pci_write_config_dword(pci, 0x40, dmaa); pci_write_config_dword(pci, 0x48, dmac); if ((sonic->res_dmaa = request_region(dmaa, 0x10, "S3 SonicVibes DDMA-A")) == NULL) { snd_sonicvibes_free(sonic); - snd_printk("unable to grab DDMA-A port at 0x%x-0x%x\n", dmaa, dmaa + 0x10 - 1); + snd_printk(KERN_ERR "unable to grab DDMA-A port at 0x%x-0x%x\n", dmaa, dmaa + 0x10 - 1); return -EBUSY; } if ((sonic->res_dmac = request_region(dmac, 0x10, "S3 SonicVibes DDMA-C")) == NULL) { snd_sonicvibes_free(sonic); - snd_printk("unable to grab DDMA-C port at 0x%x-0x%x\n", dmac, dmac + 0x10 - 1); + snd_printk(KERN_ERR "unable to grab DDMA-C port at 0x%x-0x%x\n", dmac, dmac + 0x10 - 1); return -EBUSY; } diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 777da9a7298b570e6cea4f363d416b376beab4e7..b9b93c7faafd65d189b26274519dfa66c3e5b7c6 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -153,7 +153,7 @@ static unsigned short snd_trident_codec_read(ac97_t *ac97, unsigned short reg) } if (count == 0 && !trident->ac97_detect) { - snd_printk("ac97 codec read TIMEOUT [0x%x/0x%x]!!!\n", reg, data); + snd_printk(KERN_ERR "ac97 codec read TIMEOUT [0x%x/0x%x]!!!\n", reg, data); data = 0; } @@ -2893,7 +2893,8 @@ static void snd_trident_notify_pcm_change1(snd_card_t * card, snd_kcontrol_t *kc { snd_ctl_elem_id_t id; - snd_runtime_check(kctl != NULL, return); + if (! kctl) + return; if (activate) kctl->vd[num].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; else @@ -2989,13 +2990,13 @@ static int __devinit snd_trident_mixer(trident_t * trident, int pcm_spdif_device _ac97.num = 1; err = snd_ac97_mixer(trident->ac97_bus, &_ac97, &trident->ac97_sec); if (err < 0) - snd_printk("SI7018: the secondary codec - invalid access\n"); + snd_printk(KERN_ERR "SI7018: the secondary codec - invalid access\n"); #if 0 // only for my testing purpose --jk { ac97_t *mc97; err = snd_ac97_modem(trident->card, &_ac97, &mc97); if (err < 0) - snd_printk("snd_ac97_modem returned error %i\n", err); + snd_printk(KERN_ERR "snd_ac97_modem returned error %i\n", err); } #endif } @@ -3206,8 +3207,7 @@ static inline void snd_trident_free_gameport(trident_t *chip) { } */ static inline void do_delay(trident_t *chip) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } /* @@ -3243,7 +3243,7 @@ static int snd_trident_sis_reset(trident_t *trident) goto __si7018_ok; do_delay(trident); } while (time_after_eq(end_time, jiffies)); - snd_printk("AC'97 codec ready error [0x%x]\n", inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL))); + snd_printk(KERN_ERR "AC'97 codec ready error [0x%x]\n", inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL))); if (r-- > 0) { end_time = jiffies + HZ; do { @@ -3541,7 +3541,7 @@ int __devinit snd_trident_create(snd_card_t * card, /* check, if we can restrict PCI DMA transfers to 30 bits */ if (pci_set_dma_mask(pci, 0x3fffffff) < 0 || pci_set_consistent_dma_mask(pci, 0x3fffffff) < 0) { - snd_printk("architecture does not support 30bit PCI busmaster DMA\n"); + snd_printk(KERN_ERR "architecture does not support 30bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -3578,7 +3578,7 @@ int __devinit snd_trident_create(snd_card_t * card, trident->port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_trident_interrupt, SA_INTERRUPT|SA_SHIRQ, "Trident Audio", (void *) trident)) { - snd_printk("unable to grab IRQ %d\n", pci->irq); + snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_trident_free(trident); return -EBUSY; } diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c index 333d3790692a7efafe6042afc4da72b1de86a6a8..f3e6c546af741fb9c517b3eaac93104d591a5fed 100644 --- a/sound/pci/trident/trident_memory.c +++ b/sound/pci/trident/trident_memory.c @@ -170,11 +170,11 @@ search_empty(snd_util_memhdr_t *hdr, int size) static int is_valid_page(unsigned long ptr) { if (ptr & ~0x3fffffffUL) { - snd_printk("max memory size is 1GB!!\n"); + snd_printk(KERN_ERR "max memory size is 1GB!!\n"); return 0; } if (ptr & (SNDRV_TRIDENT_PAGE_SIZE-1)) { - snd_printk("page is not aligned\n"); + snd_printk(KERN_ERR "page is not aligned\n"); return 0; } return 1; diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 3c0205b91e10bb3b92c8eca5a101523d19714f43..523eace250f7c4e96ad081ea774d494b9776ec36 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -41,6 +41,9 @@ * device for applications. * - clean up the code, separate low-level initialization * routines for each chipset. + * + * Sep. 26, 2005 Karsten Wiese + * - Optimize position calculation for the 823x chips. */ #include @@ -73,36 +76,37 @@ MODULE_SUPPORTED_DEVICE("{{VIA,VT82C686A/B/C,pci},{VIA,VT8233A/C,8235}}"); #define SUPPORT_JOYSTICK 1 #endif -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ -static long mpu_port[SNDRV_CARDS]; +static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ +static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ +static long mpu_port; #ifdef SUPPORT_JOYSTICK -static int joystick[SNDRV_CARDS]; +static int joystick; #endif -static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 48000}; -static char *ac97_quirk[SNDRV_CARDS]; -static int dxs_support[SNDRV_CARDS]; +static int ac97_clock = 48000; +static char *ac97_quirk; +static int dxs_support; -module_param_array(index, int, NULL, 0444); +module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for VIA 82xx bridge."); -module_param_array(id, charp, NULL, 0444); +module_param(id, charp, 0444); MODULE_PARM_DESC(id, "ID string for VIA 82xx bridge."); -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable audio part of VIA 82xx bridge."); -module_param_array(mpu_port, long, NULL, 0444); +module_param(mpu_port, long, 0444); MODULE_PARM_DESC(mpu_port, "MPU-401 port. (VT82C686x only)"); #ifdef SUPPORT_JOYSTICK -module_param_array(joystick, bool, NULL, 0444); +module_param(joystick, bool, 0444); MODULE_PARM_DESC(joystick, "Enable joystick. (VT82C686x only)"); #endif -module_param_array(ac97_clock, int, NULL, 0444); +module_param(ac97_clock, int, 0444); MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz)."); -module_param_array(ac97_quirk, charp, NULL, 0444); +module_param(ac97_quirk, charp, 0444); MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); -module_param_array(dxs_support, int, NULL, 0444); +module_param(dxs_support, int, 0444); MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA, 5 = enable any sample rate)"); +/* just for backward compatibility */ +static int enable; +module_param(enable, bool, 0444); + /* revision numbers for via686 */ #define VIA_REV_686_A 0x10 @@ -130,6 +134,7 @@ MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 /* common offsets */ #define VIA_REG_OFFSET_STATUS 0x00 /* byte - channel status */ #define VIA_REG_STAT_ACTIVE 0x80 /* RO */ +#define VIA8233_SHADOW_STAT_ACTIVE 0x08 /* RO */ #define VIA_REG_STAT_PAUSED 0x40 /* RO */ #define VIA_REG_STAT_TRIGGER_QUEUED 0x08 /* RO */ #define VIA_REG_STAT_STOPPED 0x04 /* RWC */ @@ -328,6 +333,9 @@ struct via_dev { unsigned int fragsize; unsigned int bufsize; unsigned int bufsize2; + int hwptr_done; /* processed frame position in the buffer */ + int in_interrupt; + int shadow_shift; }; @@ -360,7 +368,8 @@ struct _snd_via82xx { unsigned int mpu_port_saved; #endif - unsigned char playback_volume[2]; /* for VIA8233/C/8235; default = 0 */ + unsigned char playback_volume[4][2]; /* for VIA8233/C/8235; default = 0 */ + unsigned char playback_volume_c[2]; /* for VIA8233/C/8235; default = 0 */ unsigned int intr_mask; /* SGD_SHADOW mask to check interrupts */ @@ -393,8 +402,10 @@ struct _snd_via82xx { }; static struct pci_device_id snd_via82xx_ids[] = { - { 0x1106, 0x3058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_CARD_VIA686, }, /* 686A */ - { 0x1106, 0x3059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_CARD_VIA8233, }, /* VT8233 */ + /* 0x1106, 0x3058 */ + { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_CARD_VIA686, }, /* 686A */ + /* 0x1106, 0x3059 */ + { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_CARD_VIA8233, }, /* VT8233 */ { 0, } }; @@ -548,7 +559,7 @@ static void snd_via82xx_codec_write(ac97_t *ac97, { via82xx_t *chip = ac97->private_data; unsigned int xval; - + xval = !ac97->num ? VIA_REG_AC97_CODEC_ID_PRIMARY : VIA_REG_AC97_CODEC_ID_SECONDARY; xval <<= VIA_REG_AC97_CODEC_ID_SHIFT; xval |= reg << VIA_REG_AC97_CMD_SHIFT; @@ -596,14 +607,15 @@ static void snd_via82xx_channel_reset(via82xx_t *chip, viadev_t *viadev) outb(0x00, VIADEV_REG(viadev, OFFSET_TYPE)); /* for via686 */ // outl(0, VIADEV_REG(viadev, OFFSET_CURR_PTR)); viadev->lastpos = 0; + viadev->hwptr_done = 0; } /* * Interrupt handler + * Used for 686 and 8233A */ - -static irqreturn_t snd_via82xx_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_via686_interrupt(int irq, void *dev_id, struct pt_regs *regs) { via82xx_t *chip = dev_id; unsigned int status; @@ -622,13 +634,23 @@ static irqreturn_t snd_via82xx_interrupt(int irq, void *dev_id, struct pt_regs * for (i = 0; i < chip->num_devs; i++) { viadev_t *viadev = &chip->devs[i]; unsigned char c_status = inb(VIADEV_REG(viadev, OFFSET_STATUS)); - c_status &= (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG|VIA_REG_STAT_STOPPED); - if (! c_status) + if (! (c_status & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG|VIA_REG_STAT_STOPPED))) continue; if (viadev->substream && viadev->running) { + /* + * Update hwptr_done based on 'period elapsed' + * interrupts. We'll use it, when the chip returns 0 + * for OFFSET_CURR_COUNT. + */ + if (c_status & VIA_REG_STAT_EOL) + viadev->hwptr_done = 0; + else + viadev->hwptr_done += viadev->fragsize; + viadev->in_interrupt = c_status; spin_unlock(&chip->reg_lock); snd_pcm_period_elapsed(viadev->substream); spin_lock(&chip->reg_lock); + viadev->in_interrupt = 0; } outb(c_status, VIADEV_REG(viadev, OFFSET_STATUS)); /* ack */ } @@ -636,6 +658,60 @@ static irqreturn_t snd_via82xx_interrupt(int irq, void *dev_id, struct pt_regs * return IRQ_HANDLED; } +/* + * Interrupt handler + */ +static irqreturn_t snd_via8233_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + via82xx_t *chip = dev_id; + unsigned int status; + unsigned int i; + int irqreturn = 0; + + /* check status for each stream */ + spin_lock(&chip->reg_lock); + status = inl(VIAREG(chip, SGD_SHADOW)); + + for (i = 0; i < chip->num_devs; i++) { + viadev_t *viadev = &chip->devs[i]; + snd_pcm_substream_t *substream; + unsigned char c_status, shadow_status; + + shadow_status = (status >> viadev->shadow_shift) & + (VIA8233_SHADOW_STAT_ACTIVE|VIA_REG_STAT_EOL| + VIA_REG_STAT_FLAG); + c_status = shadow_status & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG); + if (!c_status) + continue; + + substream = viadev->substream; + if (substream && viadev->running) { + /* + * Update hwptr_done based on 'period elapsed' + * interrupts. We'll use it, when the chip returns 0 + * for OFFSET_CURR_COUNT. + */ + if (c_status & VIA_REG_STAT_EOL) + viadev->hwptr_done = 0; + else + viadev->hwptr_done += viadev->fragsize; + viadev->in_interrupt = c_status; + if (shadow_status & VIA8233_SHADOW_STAT_ACTIVE) + viadev->in_interrupt |= VIA_REG_STAT_ACTIVE; + spin_unlock(&chip->reg_lock); + + snd_pcm_period_elapsed(substream); + + spin_lock(&chip->reg_lock); + viadev->in_interrupt = 0; + } + outb(c_status, VIADEV_REG(viadev, OFFSET_STATUS)); /* ack */ + irqreturn = 1; + } + spin_unlock(&chip->reg_lock); + return IRQ_RETVAL(irqreturn); +} + /* * PCM callbacks */ @@ -699,6 +775,8 @@ static inline unsigned int calc_linear_pos(viadev_t *viadev, unsigned int idx, u size = viadev->idx_table[idx].size; base = viadev->idx_table[idx].offset; res = base + size - count; + if (res >= viadev->bufsize) + res -= viadev->bufsize; /* check the validity of the calculated position */ if (size < count) { @@ -728,9 +806,6 @@ static inline unsigned int calc_linear_pos(viadev_t *viadev, unsigned int idx, u } } } - viadev->lastpos = res; /* remember the last position */ - if (res >= viadev->bufsize) - res -= viadev->bufsize; return res; } @@ -758,6 +833,7 @@ static snd_pcm_uframes_t snd_via686_pcm_pointer(snd_pcm_substream_t *substream) else /* CURR_PTR holds the address + 8 */ idx = ((ptr - (unsigned int)viadev->table.addr) / 8 - 1) % viadev->tbl_entries; res = calc_linear_pos(viadev, idx, count); + viadev->lastpos = res; /* remember the last position */ spin_unlock(&chip->reg_lock); return bytes_to_frames(substream->runtime, res); @@ -771,30 +847,44 @@ static snd_pcm_uframes_t snd_via8233_pcm_pointer(snd_pcm_substream_t *substream) via82xx_t *chip = snd_pcm_substream_chip(substream); viadev_t *viadev = (viadev_t *)substream->runtime->private_data; unsigned int idx, count, res; - int timeout = 5000; + int status; snd_assert(viadev->tbl_entries, return 0); - if (!(inb(VIADEV_REG(viadev, OFFSET_STATUS)) & VIA_REG_STAT_ACTIVE)) - return 0; + spin_lock(&chip->reg_lock); - do { - count = inl(VIADEV_REG(viadev, OFFSET_CURR_COUNT)); - /* some mobos read 0 count */ - if ((count & 0xffffff) || ! viadev->running) - break; - } while (--timeout); - if (! timeout) - snd_printd(KERN_ERR "zero position is read\n"); - idx = count >> 24; - if (idx >= viadev->tbl_entries) { + count = inl(VIADEV_REG(viadev, OFFSET_CURR_COUNT)); + status = viadev->in_interrupt; + if (!status) + status = inb(VIADEV_REG(viadev, OFFSET_STATUS)); + + if (!(status & VIA_REG_STAT_ACTIVE)) { + res = 0; + goto unlock; + } + if (count & 0xffffff) { + idx = count >> 24; + if (idx >= viadev->tbl_entries) { #ifdef POINTER_DEBUG - printk("fail: invalid idx = %i/%i\n", idx, viadev->tbl_entries); + printk(KERN_DEBUG "fail: invalid idx = %i/%i\n", idx, viadev->tbl_entries); #endif - res = viadev->lastpos; + res = viadev->lastpos; + } else { + count &= 0xffffff; + res = calc_linear_pos(viadev, idx, count); + } } else { - count &= 0xffffff; - res = calc_linear_pos(viadev, idx, count); - } + res = viadev->hwptr_done; + if (!viadev->in_interrupt) { + if (status & VIA_REG_STAT_EOL) { + res = 0; + } else + if (status & VIA_REG_STAT_FLAG) { + res += viadev->fragsize; + } + } + } +unlock: + viadev->lastpos = res; spin_unlock(&chip->reg_lock); return bytes_to_frames(substream->runtime, res); @@ -936,8 +1026,8 @@ static int snd_via8233_playback_prepare(snd_pcm_substream_t *substream) snd_assert((rbits & ~0xfffff) == 0, return -EINVAL); snd_via82xx_channel_reset(chip, viadev); snd_via82xx_set_table_ptr(chip, viadev); - outb(chip->playback_volume[0], VIADEV_REG(viadev, OFS_PLAYBACK_VOLUME_L)); - outb(chip->playback_volume[1], VIADEV_REG(viadev, OFS_PLAYBACK_VOLUME_R)); + outb(chip->playback_volume[viadev->reg_offset / 0x10][0], VIADEV_REG(viadev, OFS_PLAYBACK_VOLUME_L)); + outb(chip->playback_volume[viadev->reg_offset / 0x10][1], VIADEV_REG(viadev, OFS_PLAYBACK_VOLUME_R)); outl((runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA8233_REG_TYPE_16BIT : 0) | /* format */ (runtime->channels > 1 ? VIA8233_REG_TYPE_STEREO : 0) | /* stereo */ rbits | /* rate */ @@ -1239,9 +1329,10 @@ static snd_pcm_ops_t snd_via8233_capture_ops = { }; -static void init_viadev(via82xx_t *chip, int idx, unsigned int reg_offset, int direction) +static void init_viadev(via82xx_t *chip, int idx, unsigned int reg_offset, int shadow_pos, int direction) { chip->devs[idx].reg_offset = reg_offset; + chip->devs[idx].shadow_shift = shadow_pos * 4; chip->devs[idx].direction = direction; chip->devs[idx].port = chip->port + reg_offset; } @@ -1271,9 +1362,9 @@ static int __devinit snd_via8233_pcm_new(via82xx_t *chip) chip->pcms[0] = pcm; /* set up playbacks */ for (i = 0; i < 4; i++) - init_viadev(chip, i, 0x10 * i, 0); + init_viadev(chip, i, 0x10 * i, i, 0); /* capture */ - init_viadev(chip, chip->capture_devno, VIA_REG_CAPTURE_8233_STATUS, 1); + init_viadev(chip, chip->capture_devno, VIA_REG_CAPTURE_8233_STATUS, 6, 1); if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(chip->pci), 64*1024, 128*1024)) < 0) @@ -1289,9 +1380,9 @@ static int __devinit snd_via8233_pcm_new(via82xx_t *chip) strcpy(pcm->name, chip->card->shortname); chip->pcms[1] = pcm; /* set up playback */ - init_viadev(chip, chip->multi_devno, VIA_REG_MULTPLAY_STATUS, 0); + init_viadev(chip, chip->multi_devno, VIA_REG_MULTPLAY_STATUS, 4, 0); /* set up capture */ - init_viadev(chip, chip->capture_devno + 1, VIA_REG_CAPTURE_8233_STATUS + 0x10, 1); + init_viadev(chip, chip->capture_devno + 1, VIA_REG_CAPTURE_8233_STATUS + 0x10, 7, 1); if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(chip->pci), 64*1024, 128*1024)) < 0) @@ -1324,9 +1415,9 @@ static int __devinit snd_via8233a_pcm_new(via82xx_t *chip) strcpy(pcm->name, chip->card->shortname); chip->pcms[0] = pcm; /* set up playback */ - init_viadev(chip, chip->multi_devno, VIA_REG_MULTPLAY_STATUS, 0); + init_viadev(chip, chip->multi_devno, VIA_REG_MULTPLAY_STATUS, 4, 0); /* capture */ - init_viadev(chip, chip->capture_devno, VIA_REG_CAPTURE_8233_STATUS, 1); + init_viadev(chip, chip->capture_devno, VIA_REG_CAPTURE_8233_STATUS, 6, 1); if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(chip->pci), 64*1024, 128*1024)) < 0) @@ -1345,7 +1436,7 @@ static int __devinit snd_via8233a_pcm_new(via82xx_t *chip) strcpy(pcm->name, chip->card->shortname); chip->pcms[1] = pcm; /* set up playback */ - init_viadev(chip, chip->playback_devno, 0x30, 0); + init_viadev(chip, chip->playback_devno, 0x30, 3, 0); if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(chip->pci), 64*1024, 128*1024)) < 0) @@ -1375,8 +1466,8 @@ static int __devinit snd_via686_pcm_new(via82xx_t *chip) pcm->private_data = chip; strcpy(pcm->name, chip->card->shortname); chip->pcms[0] = pcm; - init_viadev(chip, 0, VIA_REG_PLAYBACK_STATUS, 0); - init_viadev(chip, 1, VIA_REG_CAPTURE_STATUS, 1); + init_viadev(chip, 0, VIA_REG_PLAYBACK_STATUS, 0, 0); + init_viadev(chip, 1, VIA_REG_CAPTURE_STATUS, 0, 1); if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(chip->pci), 64*1024, 128*1024)) < 0) @@ -1497,12 +1588,44 @@ static int snd_via8233_dxs_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_in static int snd_via8233_dxs_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { via82xx_t *chip = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = VIA_DXS_MAX_VOLUME - chip->playback_volume[0]; - ucontrol->value.integer.value[1] = VIA_DXS_MAX_VOLUME - chip->playback_volume[1]; + unsigned int idx = snd_ctl_get_ioff(kcontrol, &ucontrol->id); + + ucontrol->value.integer.value[0] = VIA_DXS_MAX_VOLUME - chip->playback_volume[idx][0]; + ucontrol->value.integer.value[1] = VIA_DXS_MAX_VOLUME - chip->playback_volume[idx][1]; + return 0; +} + +static int snd_via8233_pcmdxs_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + via82xx_t *chip = snd_kcontrol_chip(kcontrol); + ucontrol->value.integer.value[0] = VIA_DXS_MAX_VOLUME - chip->playback_volume_c[0]; + ucontrol->value.integer.value[1] = VIA_DXS_MAX_VOLUME - chip->playback_volume_c[1]; return 0; } static int snd_via8233_dxs_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + via82xx_t *chip = snd_kcontrol_chip(kcontrol); + unsigned int idx = snd_ctl_get_ioff(kcontrol, &ucontrol->id); + unsigned long port = chip->port + 0x10 * idx; + unsigned char val; + int i, change = 0; + + for (i = 0; i < 2; i++) { + val = ucontrol->value.integer.value[i]; + if (val > VIA_DXS_MAX_VOLUME) + val = VIA_DXS_MAX_VOLUME; + val = VIA_DXS_MAX_VOLUME - val; + change |= val != chip->playback_volume[idx][i]; + if (change) { + chip->playback_volume[idx][i] = val; + outb(val, port + VIA_REG_OFS_PLAYBACK_VOLUME_L + i); + } + } + return change; +} + +static int snd_via8233_pcmdxs_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { via82xx_t *chip = snd_kcontrol_chip(kcontrol); unsigned int idx; @@ -1514,11 +1637,12 @@ static int snd_via8233_dxs_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_val if (val > VIA_DXS_MAX_VOLUME) val = VIA_DXS_MAX_VOLUME; val = VIA_DXS_MAX_VOLUME - val; - if (val != chip->playback_volume[i]) { + if (val != chip->playback_volume_c[i]) { change = 1; - chip->playback_volume[i] = val; + chip->playback_volume_c[i] = val; for (idx = 0; idx < 4; idx++) { unsigned long port = chip->port + 0x10 * idx; + chip->playback_volume[idx][i] = val; outb(val, port + VIA_REG_OFS_PLAYBACK_VOLUME_L + i); } } @@ -1526,10 +1650,19 @@ static int snd_via8233_dxs_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_val return change; } -static snd_kcontrol_new_t snd_via8233_dxs_volume_control __devinitdata = { +static snd_kcontrol_new_t snd_via8233_pcmdxs_volume_control __devinitdata = { .name = "PCM Playback Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .info = snd_via8233_dxs_volume_info, + .get = snd_via8233_pcmdxs_volume_get, + .put = snd_via8233_pcmdxs_volume_put, +}; + +static snd_kcontrol_new_t snd_via8233_dxs_volume_control __devinitdata = { + .name = "VIA DXS Playback Volume", + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .count = 4, + .info = snd_via8233_dxs_volume_info, .get = snd_via8233_dxs_volume_get, .put = snd_via8233_dxs_volume_put, }; @@ -1616,12 +1749,12 @@ static int __devinit snd_via82xx_mixer_new(via82xx_t *chip, const char *quirk_ov return err; chip->ac97_bus->private_free = snd_via82xx_mixer_free_ac97_bus; chip->ac97_bus->clock = chip->ac97_clock; - chip->ac97_bus->shared_type = AC97_SHARED_TYPE_VIA; memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; ac97.private_free = snd_via82xx_mixer_free_ac97; ac97.pci = chip->pci; + ac97.scaps = AC97_SCAP_SKIP_MODEM; if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) return err; @@ -1637,12 +1770,12 @@ static int __devinit snd_via82xx_mixer_new(via82xx_t *chip, const char *quirk_ov #ifdef SUPPORT_JOYSTICK #define JOYSTICK_ADDR 0x200 -static int __devinit snd_via686_create_gameport(via82xx_t *chip, int dev, unsigned char *legacy) +static int __devinit snd_via686_create_gameport(via82xx_t *chip, unsigned char *legacy) { struct gameport *gp; struct resource *r; - if (!joystick[dev]) + if (!joystick) return -ENODEV; r = request_region(JOYSTICK_ADDR, 8, "VIA686 gameport"); @@ -1654,8 +1787,7 @@ static int __devinit snd_via686_create_gameport(via82xx_t *chip, int dev, unsign chip->gameport = gp = gameport_allocate_port(); if (!gp) { printk(KERN_ERR "via82xx: cannot allocate memory for gameport\n"); - release_resource(r); - kfree_nocheck(r); + release_and_free_resource(r); return -ENOMEM; } @@ -1681,12 +1813,11 @@ static void snd_via686_free_gameport(via82xx_t *chip) gameport_unregister_port(chip->gameport); chip->gameport = NULL; - release_resource(r); - kfree_nocheck(r); + release_and_free_resource(r); } } #else -static inline int snd_via686_create_gameport(via82xx_t *chip, int dev, unsigned char *legacy) +static inline int snd_via686_create_gameport(via82xx_t *chip, unsigned char *legacy) { return -ENOSYS; } @@ -1698,7 +1829,7 @@ static inline void snd_via686_free_gameport(via82xx_t *chip) { } * */ -static int __devinit snd_via8233_init_misc(via82xx_t *chip, int dev) +static int __devinit snd_via8233_init_misc(via82xx_t *chip) { int i, err, caps; unsigned char val; @@ -1724,12 +1855,19 @@ static int __devinit snd_via8233_init_misc(via82xx_t *chip, int dev) strcpy(sid.name, "PCM Playback Volume"); sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; if (! snd_ctl_find_id(chip->card, &sid)) { + snd_printd(KERN_INFO "Using DXS as PCM Playback\n"); + err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_pcmdxs_volume_control, chip)); + if (err < 0) + return err; + } + else /* Using DXS when PCM emulation is enabled is really weird */ + { + /* Standalone DXS controls */ err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_dxs_volume_control, chip)); if (err < 0) return err; } } - /* select spdif data slot 10/11 */ pci_read_config_byte(chip->pci, VIA8233_SPDIF_CTRL, &val); val = (val & ~VIA8233_SPDIF_SLOT_MASK) | VIA8233_SPDIF_SLOT_1011; @@ -1739,7 +1877,7 @@ static int __devinit snd_via8233_init_misc(via82xx_t *chip, int dev) return 0; } -static int __devinit snd_via686_init_misc(via82xx_t *chip, int dev) +static int __devinit snd_via686_init_misc(via82xx_t *chip) { unsigned char legacy, legacy_cfg; int rev_h = 0; @@ -1750,32 +1888,33 @@ static int __devinit snd_via686_init_misc(via82xx_t *chip, int dev) legacy &= ~VIA_FUNC_ENABLE_GAME; /* disable joystick */ if (chip->revision >= VIA_REV_686_H) { rev_h = 1; - if (mpu_port[dev] >= 0x200) { /* force MIDI */ - mpu_port[dev] &= 0xfffc; - pci_write_config_dword(chip->pci, 0x18, mpu_port[dev] | 0x01); + if (mpu_port >= 0x200) { /* force MIDI */ + mpu_port &= 0xfffc; + pci_write_config_dword(chip->pci, 0x18, mpu_port | 0x01); #ifdef CONFIG_PM - chip->mpu_port_saved = mpu_port[dev]; + chip->mpu_port_saved = mpu_port; #endif } else { - mpu_port[dev] = pci_resource_start(chip->pci, 2); + mpu_port = pci_resource_start(chip->pci, 2); } } else { - switch (mpu_port[dev]) { /* force MIDI */ + switch (mpu_port) { /* force MIDI */ case 0x300: case 0x310: case 0x320: case 0x330: legacy_cfg &= ~(3 << 2); - legacy_cfg |= (mpu_port[dev] & 0x0030) >> 2; + legacy_cfg |= (mpu_port & 0x0030) >> 2; break; default: /* no, use BIOS settings */ if (legacy & VIA_FUNC_ENABLE_MIDI) - mpu_port[dev] = 0x300 + ((legacy_cfg & 0x000c) << 2); + mpu_port = 0x300 + ((legacy_cfg & 0x000c) << 2); break; } } - if (mpu_port[dev] >= 0x200 && - (chip->mpu_res = request_region(mpu_port[dev], 2, "VIA82xx MPU401")) != NULL) { + if (mpu_port >= 0x200 && + (chip->mpu_res = request_region(mpu_port, 2, "VIA82xx MPU401")) + != NULL) { if (rev_h) legacy |= VIA_FUNC_MIDI_PNP; /* enable PCI I/O 2 */ legacy |= VIA_FUNC_ENABLE_MIDI; @@ -1783,16 +1922,17 @@ static int __devinit snd_via686_init_misc(via82xx_t *chip, int dev) if (rev_h) legacy &= ~VIA_FUNC_MIDI_PNP; /* disable PCI I/O 2 */ legacy &= ~VIA_FUNC_ENABLE_MIDI; - mpu_port[dev] = 0; + mpu_port = 0; } pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, legacy); pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, legacy_cfg); if (chip->mpu_res) { if (snd_mpu401_uart_new(chip->card, 0, MPU401_HW_VIA686A, - mpu_port[dev], 1, + mpu_port, 1, chip->irq, 0, &chip->rmidi) < 0) { - printk(KERN_WARNING "unable to initialize MPU-401 at 0x%lx, skipping\n", mpu_port[dev]); + printk(KERN_WARNING "unable to initialize MPU-401" + " at 0x%lx, skipping\n", mpu_port); legacy &= ~VIA_FUNC_ENABLE_MIDI; } else { legacy &= ~VIA_FUNC_MIDI_IRQMASK; /* enable MIDI interrupt */ @@ -1800,7 +1940,7 @@ static int __devinit snd_via686_init_misc(via82xx_t *chip, int dev) pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, legacy); } - snd_via686_create_gameport(chip, dev, &legacy); + snd_via686_create_gameport(chip, &legacy); #ifdef CONFIG_PM chip->legacy_saved = legacy; @@ -1887,12 +2027,11 @@ static int snd_via82xx_chip_init(via82xx_t *chip) pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval); if (pval & VIA_ACLINK_C00_READY) /* primary codec ready */ break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_before(jiffies, end_time)); if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY) - snd_printk("AC'97 codec is not ready [0x%x]\n", val); + snd_printk(KERN_ERR "AC'97 codec is not ready [0x%x]\n", val); #if 0 /* FIXME: we don't support the second codec yet so skip the detection now.. */ snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ | @@ -1907,8 +2046,7 @@ static int snd_via82xx_chip_init(via82xx_t *chip) chip->ac97_secondary = 1; goto __ac97_ok2; } - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_interruptible(1); } while (time_before(jiffies, end_time)); /* This is ok, the most of motherboards have only one codec */ @@ -1940,8 +2078,10 @@ static int snd_via82xx_chip_init(via82xx_t *chip) int i, idx; for (idx = 0; idx < 4; idx++) { unsigned long port = chip->port + 0x10 * idx; - for (i = 0; i < 2; i++) - outb(chip->playback_volume[i], port + VIA_REG_OFS_PLAYBACK_VOLUME_L + i); + for (i = 0; i < 2; i++) { + chip->playback_volume[idx][i]=chip->playback_volume_c[i]; + outb(chip->playback_volume_c[i], port + VIA_REG_OFS_PLAYBACK_VOLUME_L + i); + } } } @@ -2020,10 +2160,7 @@ static int snd_via82xx_free(via82xx_t *chip) __end_hw: if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); - if (chip->mpu_res) { - release_resource(chip->mpu_res); - kfree_nocheck(chip->mpu_res); - } + release_and_free_resource(chip->mpu_res); pci_release_regions(chip->pci); if (chip->chip_type == TYPE_VIA686) { @@ -2084,9 +2221,12 @@ static int __devinit snd_via82xx_create(snd_card_t * card, return err; } chip->port = pci_resource_start(pci, 0); - if (request_irq(pci->irq, snd_via82xx_interrupt, SA_INTERRUPT|SA_SHIRQ, + if (request_irq(pci->irq, + chip_type == TYPE_VIA8233 ? + snd_via8233_interrupt : snd_via686_interrupt, + SA_INTERRUPT|SA_SHIRQ, card->driver, (void *)chip)) { - snd_printk("unable to grab IRQ %d\n", pci->irq); + snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_via82xx_free(chip); return -EBUSY; } @@ -2178,6 +2318,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci) { .subvendor = 0x147b, .subdevice = 0x1415, .action = VIA_DXS_NO_VRA }, /* Abit AV8 */ { .subvendor = 0x14ff, .subdevice = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */ { .subvendor = 0x14ff, .subdevice = 0x0408, .action = VIA_DXS_SRC }, /* Twinhead laptop */ + { .subvendor = 0x1558, .subdevice = 0x4701, .action = VIA_DXS_SRC }, /* Clevo D470 */ { .subvendor = 0x1584, .subdevice = 0x8120, .action = VIA_DXS_ENABLE }, /* Gericom/Targa/Vobis/Uniwill laptop */ { .subvendor = 0x1584, .subdevice = 0x8123, .action = VIA_DXS_NO_VRA }, /* Uniwill (Targa Visionary XP-210) */ { .subvendor = 0x161f, .subdevice = 0x202b, .action = VIA_DXS_NO_VRA }, /* Amira Note book */ @@ -2221,7 +2362,6 @@ static int __devinit check_dxs_list(struct pci_dev *pci) static int __devinit snd_via82xx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { - static int dev; snd_card_t *card; via82xx_t *chip; unsigned char revision; @@ -2229,14 +2369,7 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci, unsigned int i; int err; - if (dev >= SNDRV_CARDS) - return -ENODEV; - if (!enable[dev]) { - dev++; - return -ENOENT; - } - - card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + card = snd_card_new(index, id, THIS_MODULE, 0); if (card == NULL) return -ENOMEM; @@ -2259,12 +2392,12 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci, } } if (chip_type != TYPE_VIA8233A) { - if (dxs_support[dev] == VIA_DXS_AUTO) - dxs_support[dev] = check_dxs_list(pci); + if (dxs_support == VIA_DXS_AUTO) + dxs_support = check_dxs_list(pci); /* force to use VIA8233 or 8233A model according to * dxs_support module option */ - if (dxs_support[dev] == VIA_DXS_DISABLE) + if (dxs_support == VIA_DXS_DISABLE) chip_type = TYPE_VIA8233A; else chip_type = TYPE_VIA8233; @@ -2282,14 +2415,15 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci, goto __error; } - if ((err = snd_via82xx_create(card, pci, chip_type, revision, ac97_clock[dev], &chip)) < 0) + if ((err = snd_via82xx_create(card, pci, chip_type, revision, + ac97_clock, &chip)) < 0) goto __error; - if ((err = snd_via82xx_mixer_new(chip, ac97_quirk[dev])) < 0) + if ((err = snd_via82xx_mixer_new(chip, ac97_quirk)) < 0) goto __error; if (chip_type == TYPE_VIA686) { if ((err = snd_via686_pcm_new(chip)) < 0 || - (err = snd_via686_init_misc(chip, dev)) < 0) + (err = snd_via686_init_misc(chip)) < 0) goto __error; } else { if (chip_type == TYPE_VIA8233A) { @@ -2299,16 +2433,16 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci, } else { if ((err = snd_via8233_pcm_new(chip)) < 0) goto __error; - if (dxs_support[dev] == VIA_DXS_48K) + if (dxs_support == VIA_DXS_48K) chip->dxs_fixed = 1; - else if (dxs_support[dev] == VIA_DXS_NO_VRA) + else if (dxs_support == VIA_DXS_NO_VRA) chip->no_vra = 1; - else if (dxs_support[dev] == VIA_DXS_SRC) { + else if (dxs_support == VIA_DXS_SRC) { chip->no_vra = 1; chip->dxs_src = 1; } } - if ((err = snd_via8233_init_misc(chip, dev)) < 0) + if ((err = snd_via8233_init_misc(chip)) < 0) goto __error; } @@ -2329,7 +2463,6 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci, return err; } pci_set_drvdata(pci, card); - dev++; return 0; __error: diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 7eac6f6ac737fee70fee677edd319a7123030ca4..011f0fb63bf9e5b288675b77df5bbb4841039b38 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -26,7 +26,7 @@ /* * Changes: * - * Sep. 2, 2004 Sasha Khapyorsky + * Sep. 2, 2004 Sasha Khapyorsky * Modified from original audio driver 'via82xx.c' to support AC97 * modems. */ @@ -55,20 +55,21 @@ MODULE_DESCRIPTION("VIA VT82xx modem"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{VIA,VT82C686A/B/C modem,pci}}"); -static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* Exclude the first card */ -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ -static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 48000}; +static int index = -2; /* Exclude the first card */ +static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ +static int ac97_clock = 48000; -module_param_array(index, int, NULL, 0444); +module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for VIA 82xx bridge."); -module_param_array(id, charp, NULL, 0444); +module_param(id, charp, 0444); MODULE_PARM_DESC(id, "ID string for VIA 82xx bridge."); -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable modem part of VIA 82xx bridge."); -module_param_array(ac97_clock, int, NULL, 0444); +module_param(ac97_clock, int, 0444); MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz)."); +/* just for backward compatibility */ +static int enable; +module_param(enable, bool, 0444); + /* * Direct registers @@ -569,7 +570,7 @@ static inline unsigned int calc_linear_pos(viadev_t *viadev, unsigned int idx, u res = viadev->lastpos; } else if (check_invalid_pos(viadev, res)) { #ifdef POINTER_DEBUG - printk("fail: idx = %i/%i, lastpos = 0x%x, bufsize2 = 0x%x, offsize = 0x%x, size = 0x%x, count = 0x%x\n", idx, viadev->tbl_entries, viadev->lastpos, viadev->bufsize2, viadev->idx_table[idx].offset, viadev->idx_table[idx].size, count); + printk(KERN_DEBUG "fail: idx = %i/%i, lastpos = 0x%x, bufsize2 = 0x%x, offsize = 0x%x, size = 0x%x, count = 0x%x\n", idx, viadev->tbl_entries, viadev->lastpos, viadev->bufsize2, viadev->idx_table[idx].offset, viadev->idx_table[idx].size, count); #endif if (count && size < count) { snd_printd(KERN_ERR "invalid via82xx_cur_ptr, using last valid pointer\n"); @@ -832,6 +833,7 @@ static int __devinit snd_via686_pcm_new(via82xx_t *chip) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via686_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via686_capture_ops); + pcm->dev_class = SNDRV_PCM_CLASS_MODEM; pcm->private_data = chip; strcpy(pcm->name, chip->card->shortname); chip->pcms[0] = pcm; @@ -878,7 +880,6 @@ static int __devinit snd_via82xx_mixer_new(via82xx_t *chip) return err; chip->ac97_bus->private_free = snd_via82xx_mixer_free_ac97_bus; chip->ac97_bus->clock = chip->ac97_clock; - chip->ac97_bus->shared_type = AC97_SHARED_TYPE_VIA; memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; @@ -967,12 +968,11 @@ static int snd_via82xx_chip_init(via82xx_t *chip) pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval); if (pval & VIA_ACLINK_C00_READY) /* primary codec ready */ break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_before(jiffies, end_time)); if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY) - snd_printk("AC'97 codec is not ready [0x%x]\n", val); + snd_printk(KERN_ERR "AC'97 codec is not ready [0x%x]\n", val); snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ | VIA_REG_AC97_SECONDARY_VALID | @@ -986,8 +986,7 @@ static int snd_via82xx_chip_init(via82xx_t *chip) chip->ac97_secondary = 1; goto __ac97_ok2; } - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_interruptible(1); } while (time_before(jiffies, end_time)); /* This is ok, the most of motherboards have only one codec */ @@ -1101,7 +1100,7 @@ static int __devinit snd_via82xx_create(snd_card_t * card, chip->port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_via82xx_interrupt, SA_INTERRUPT|SA_SHIRQ, card->driver, (void *)chip)) { - snd_printk("unable to grab IRQ %d\n", pci->irq); + snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_via82xx_free(chip); return -EBUSY; } @@ -1135,7 +1134,6 @@ static int __devinit snd_via82xx_create(snd_card_t * card, static int __devinit snd_via82xx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { - static int dev; snd_card_t *card; via82xx_t *chip; unsigned char revision; @@ -1143,14 +1141,7 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci, unsigned int i; int err; - if (dev >= SNDRV_CARDS) - return -ENODEV; - if (!enable[dev]) { - dev++; - return -ENOENT; - } - - card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + card = snd_card_new(index, id, THIS_MODULE, 0); if (card == NULL) return -ENOMEM; @@ -1167,7 +1158,8 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci, goto __error; } - if ((err = snd_via82xx_create(card, pci, chip_type, revision, ac97_clock[dev], &chip)) < 0) + if ((err = snd_via82xx_create(card, pci, chip_type, revision, + ac97_clock, &chip)) < 0) goto __error; if ((err = snd_via82xx_mixer_new(chip)) < 0) goto __error; @@ -1191,7 +1183,6 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci, return err; } pci_set_drvdata(pci, card); - dev++; return 0; __error: diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index 2e69abe51aa985dbc0947689946a2659d2cd374b..1bbba32517ff7c08f89593502d52df4c417a64a6 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c @@ -130,8 +130,7 @@ static int __devinit snd_ymfpci_create_gameport(ymfpci_t *chip, int dev, chip->gameport = gp = gameport_allocate_port(); if (!gp) { printk(KERN_ERR "ymfpci: cannot allocate memory for gameport\n"); - release_resource(r); - kfree_nocheck(r); + release_and_free_resource(r); return -ENOMEM; } @@ -161,8 +160,7 @@ void snd_ymfpci_free_gameport(ymfpci_t *chip) gameport_unregister_port(chip->gameport); chip->gameport = NULL; - release_resource(r); - kfree_nocheck(r); + release_and_free_resource(r); } } #else @@ -267,14 +265,8 @@ static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci, old_legacy_ctrl, &chip)) < 0) { snd_card_free(card); - if (mpu_res) { - release_resource(mpu_res); - kfree_nocheck(mpu_res); - } - if (fm_res) { - release_resource(fm_res); - kfree_nocheck(fm_res); - } + release_and_free_resource(mpu_res); + release_and_free_resource(fm_res); return err; } chip->fm_res = fm_res; @@ -328,7 +320,7 @@ static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci, pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl); } else if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { snd_card_free(card); - snd_printk("cannot create opl3 hwdep\n"); + snd_printk(KERN_ERR "cannot create opl3 hwdep\n"); return err; } } diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 27fa523639aea48ae451d2e73828ce6017e07f2a..88a43e091d77e96aa05c9d694a8ad4a02104868c 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -92,9 +92,9 @@ static int snd_ymfpci_codec_ready(ymfpci_t *chip, int secondary) if ((snd_ymfpci_readw(chip, reg) & 0x8000) == 0) return 0; set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_before(jiffies, end_time)); - snd_printk("codec_ready: codec %i is not ready [0x%x]\n", secondary, snd_ymfpci_readw(chip, reg)); + snd_printk(KERN_ERR "codec_ready: codec %i is not ready [0x%x]\n", secondary, snd_ymfpci_readw(chip, reg)); return -EBUSY; } @@ -728,8 +728,7 @@ static void snd_ymfpci_irq_wait(ymfpci_t *chip) init_waitqueue_entry(&wait, current); add_wait_queue(&chip->interrupt_sleep, &wait); atomic_inc(&chip->interrupt_sleep_count); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/20); + schedule_timeout_uninterruptible(msecs_to_jiffies(50)); remove_wait_queue(&chip->interrupt_sleep, &wait); } } @@ -1421,15 +1420,18 @@ static snd_kcontrol_new_t snd_ymfpci_drec_source __devinitdata = { * Mixer controls */ -#define YMFPCI_SINGLE(xname, xindex, reg) \ +#define YMFPCI_SINGLE(xname, xindex, reg, shift) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ .info = snd_ymfpci_info_single, \ .get = snd_ymfpci_get_single, .put = snd_ymfpci_put_single, \ - .private_value = reg } + .private_value = ((reg) | ((shift) << 16)) } -static int snd_ymfpci_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +static int snd_ymfpci_info_single(snd_kcontrol_t *kcontrol, + snd_ctl_elem_info_t *uinfo) { - switch (kcontrol->private_value) { + int reg = kcontrol->private_value & 0xffff; + + switch (reg) { case YDSXGR_SPDIFOUTCTRL: break; case YDSXGR_SPDIFINCTRL: break; default: return -EINVAL; @@ -1441,30 +1443,35 @@ static int snd_ymfpci_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t return 0; } -static int snd_ymfpci_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int snd_ymfpci_get_single(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) { ymfpci_t *chip = snd_kcontrol_chip(kcontrol); - int reg = kcontrol->private_value; - unsigned int shift = 0, mask = 1; + int reg = kcontrol->private_value & 0xffff; + unsigned int shift = (kcontrol->private_value >> 16) & 0xff; + unsigned int mask = 1; - switch (kcontrol->private_value) { + switch (reg) { case YDSXGR_SPDIFOUTCTRL: break; case YDSXGR_SPDIFINCTRL: break; default: return -EINVAL; } - ucontrol->value.integer.value[0] = (snd_ymfpci_readl(chip, reg) >> shift) & mask; + ucontrol->value.integer.value[0] = + (snd_ymfpci_readl(chip, reg) >> shift) & mask; return 0; } -static int snd_ymfpci_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int snd_ymfpci_put_single(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) { ymfpci_t *chip = snd_kcontrol_chip(kcontrol); - int reg = kcontrol->private_value; - unsigned int shift = 0, mask = 1; + int reg = kcontrol->private_value & 0xffff; + unsigned int shift = (kcontrol->private_value >> 16) & 0xff; + unsigned int mask = 1; int change; unsigned int val, oval; - switch (kcontrol->private_value) { + switch (reg) { case YDSXGR_SPDIFOUTCTRL: break; case YDSXGR_SPDIFINCTRL: break; default: return -EINVAL; @@ -1583,8 +1590,9 @@ YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("AC97 ", PLAYBACK,VOLUME), 0, YDSXGR_ZVOUTVO YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("", CAPTURE,VOLUME), 0, YDSXGR_ZVLOOPVOL), YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("AC97 ",PLAYBACK,VOLUME), 1, YDSXGR_SPDIFOUTVOL), YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,VOLUME), 1, YDSXGR_SPDIFLOOPVOL), -YMFPCI_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), 0, YDSXGR_SPDIFOUTCTRL), -YMFPCI_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0, YDSXGR_SPDIFINCTRL), +YMFPCI_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), 0, YDSXGR_SPDIFOUTCTRL, 0), +YMFPCI_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0, YDSXGR_SPDIFINCTRL, 0), +YMFPCI_SINGLE(SNDRV_CTL_NAME_IEC958("Loop",NONE,NONE), 0, YDSXGR_SPDIFINCTRL, 4), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "4ch Duplication", @@ -1842,9 +1850,7 @@ static int snd_ymfpci_timer_start(snd_timer_t *timer) unsigned int count; chip = snd_timer_chip(timer); - count = timer->sticks - 1; - if (count == 0) /* minimum time is 20.8 us */ - count = 1; + count = (timer->sticks << 1) - 1; spin_lock_irqsave(&chip->reg_lock, flags); snd_ymfpci_writew(chip, YDSXGR_TIMERCOUNT, count); snd_ymfpci_writeb(chip, YDSXGR_TIMERCTRL, 0x03); @@ -1868,14 +1874,14 @@ static int snd_ymfpci_timer_precise_resolution(snd_timer_t *timer, unsigned long *num, unsigned long *den) { *num = 1; - *den = 96000; + *den = 48000; return 0; } static struct _snd_timer_hardware snd_ymfpci_timer_hw = { .flags = SNDRV_TIMER_HW_AUTO, - .resolution = 10417, /* 1/2fs = 10.41666...us */ - .ticks = 65536, + .resolution = 20833, /* 1/fs = 20.8333...us */ + .ticks = 0x8000, .start = snd_ymfpci_timer_start, .stop = snd_ymfpci_timer_stop, .precise_resolution = snd_ymfpci_timer_precise_resolution, @@ -2142,14 +2148,8 @@ static int snd_ymfpci_free(ymfpci_t *chip) #ifdef CONFIG_PM vfree(chip->saved_regs); #endif - if (chip->mpu_res) { - release_resource(chip->mpu_res); - kfree_nocheck(chip->mpu_res); - } - if (chip->fm_res) { - release_resource(chip->fm_res); - kfree_nocheck(chip->fm_res); - } + release_and_free_resource(chip->mpu_res); + release_and_free_resource(chip->fm_res); snd_ymfpci_free_gameport(chip); if (chip->reg_area_virt) iounmap(chip->reg_area_virt); @@ -2158,10 +2158,7 @@ static int snd_ymfpci_free(ymfpci_t *chip) if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); - if (chip->res_reg_area) { - release_resource(chip->res_reg_area); - kfree_nocheck(chip->res_reg_area); - } + release_and_free_resource(chip->res_reg_area); pci_write_config_word(chip->pci, 0x40, chip->old_legacy_ctrl); @@ -2290,12 +2287,12 @@ int __devinit snd_ymfpci_create(snd_card_t * card, pci_set_master(pci); if ((chip->res_reg_area = request_mem_region(chip->reg_area_phys, 0x8000, "YMFPCI")) == NULL) { - snd_printk("unable to grab memory region 0x%lx-0x%lx\n", chip->reg_area_phys, chip->reg_area_phys + 0x8000 - 1); + snd_printk(KERN_ERR "unable to grab memory region 0x%lx-0x%lx\n", chip->reg_area_phys, chip->reg_area_phys + 0x8000 - 1); snd_ymfpci_free(chip); return -EBUSY; } if (request_irq(pci->irq, snd_ymfpci_interrupt, SA_INTERRUPT|SA_SHIRQ, "YMFPCI", (void *) chip)) { - snd_printk("unable to grab IRQ %d\n", pci->irq); + snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_ymfpci_free(chip); return -EBUSY; } diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c index 0a954dc11b7396ec65d34797bcd496c6e7387936..20b86d8df7a3066b2fcc845cc573d1483c615255 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c @@ -50,9 +50,9 @@ static int snd_pcm_alloc_vmalloc_buffer(snd_pcm_substream_t *subs, size_t size) if (runtime->dma_area) { if (runtime->dma_bytes >= size) return 0; /* already enough large */ - vfree_nocheck(runtime->dma_area); + vfree(runtime->dma_area); } - runtime->dma_area = vmalloc_nocheck(size); + runtime->dma_area = vmalloc_32(size); if (! runtime->dma_area) return -ENOMEM; runtime->dma_bytes = size; @@ -67,7 +67,7 @@ static int snd_pcm_free_vmalloc_buffer(snd_pcm_substream_t *subs) { snd_pcm_runtime_t *runtime = subs->runtime; if (runtime->dma_area) { - vfree_nocheck(runtime->dma_area); + vfree(runtime->dma_area); runtime->dma_area = NULL; } return 0; diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c index 1681ee13efbb81fdeae0e19aa73485daa08dc69b..d4ec6cc3f1c51cd24669997cbd50f84beeb0e65a 100644 --- a/sound/ppc/beep.c +++ b/sound/ppc/beep.c @@ -171,8 +171,6 @@ static int snd_pmac_beep_event(struct input_dev *dev, unsigned int type, unsigne * beep volume mixer */ -#define chip_t pmac_t - static int snd_pmac_info_beep(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 392b2abd9f13c1ec0b9aa71d2bf4cc4eb2122a33..db2f1815fc30b9896c1ec7d93eb05a9b0ee77668 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -220,7 +220,8 @@ static int snd_pmac_pcm_prepare(pmac_t *chip, pmac_stream_t *rec, snd_pcm_substr /* set up constraints */ astr = snd_pmac_get_stream(chip, another_stream(rec->stream)); - snd_runtime_check(astr, return -EINVAL); + if (! astr) + return -EINVAL; astr->cur_freqs = 1 << rate_index; astr->cur_formats = 1 << runtime->format; chip->rate_index = rate_index; @@ -467,7 +468,8 @@ static int snd_pmac_hw_rule_rate(snd_pcm_hw_params_t *params, pmac_stream_t *rec = snd_pmac_get_stream(chip, rule->deps[0]); int i, freq_table[8], num_freqs; - snd_runtime_check(rec, return -EINVAL); + if (! rec) + return -EINVAL; num_freqs = 0; for (i = chip->num_freqs - 1; i >= 0; i--) { if (rec->cur_freqs & (1 << i)) @@ -484,7 +486,8 @@ static int snd_pmac_hw_rule_format(snd_pcm_hw_params_t *params, pmac_t *chip = rule->private; pmac_stream_t *rec = snd_pmac_get_stream(chip, rule->deps[0]); - snd_runtime_check(rec, return -EINVAL); + if (! rec) + return -EINVAL; return snd_mask_refine_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), rec->cur_formats); } @@ -569,7 +572,8 @@ static int snd_pmac_pcm_close(pmac_t *chip, pmac_stream_t *rec, snd_pcm_substrea snd_pmac_dma_stop(rec); astr = snd_pmac_get_stream(chip, another_stream(rec->stream)); - snd_runtime_check(astr, return -EINVAL); + if (! astr) + return -EINVAL; /* reset constraints */ astr->cur_freqs = chip->freqs_ok; @@ -1158,7 +1162,6 @@ int __init snd_pmac_new(snd_card_t *card, pmac_t **chip_return) .dev_free = snd_pmac_dev_free, }; - snd_runtime_check(chip_return, return -EINVAL); *chip_return = NULL; chip = kzalloc(sizeof(*chip), GFP_KERNEL); @@ -1382,7 +1385,8 @@ static int snd_pmac_sleep_notify(struct pmu_sleep_notifier *self, int when) pmac_t *chip; chip = sleeping_pmac; - snd_runtime_check(chip, return 0); + if (! chip) + return 0; switch (when) { case PBOOK_SLEEP_NOW: diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index f4361c518e460565d147542636c5eda196905f1e..1f8d27a6152e24d98d86703b43c009cf89d3449f 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c @@ -61,13 +61,37 @@ MODULE_DESCRIPTION("Sun CS4231"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Sun,CS4231}}"); -typedef struct snd_cs4231 { - spinlock_t lock; - void __iomem *port; +#ifdef SBUS_SUPPORT +typedef struct sbus_dma_info { + spinlock_t lock; + int dir; + void __iomem *regs; +} sbus_dma_info_t; +#endif + +typedef struct snd_cs4231 cs4231_t; + +typedef struct cs4231_dma_control { + void (*prepare)(struct cs4231_dma_control *dma_cont, int dir); + void (*enable)(struct cs4231_dma_control *dma_cont, int on); + int (*request)(struct cs4231_dma_control *dma_cont, dma_addr_t bus_addr, size_t len); + unsigned int (*address)(struct cs4231_dma_control *dma_cont); + void (*reset)(cs4231_t *chip); + void (*preallocate)(cs4231_t *chip, snd_pcm_t *pcm); #ifdef EBUS_SUPPORT - struct ebus_dma_info eb2c; - struct ebus_dma_info eb2p; + struct ebus_dma_info ebus_info; +#endif +#ifdef SBUS_SUPPORT + struct sbus_dma_info sbus_info; #endif +} cs4231_dma_control_t; + +struct snd_cs4231 { + spinlock_t lock; + void __iomem *port; + + cs4231_dma_control_t p_dma; + cs4231_dma_control_t c_dma; u32 flags; #define CS4231_FLAG_EBUS 0x00000001 @@ -106,7 +130,7 @@ typedef struct snd_cs4231 { unsigned int irq[2]; unsigned int regs_size; struct snd_cs4231 *next; -} cs4231_t; +}; static cs4231_t *cs4231_list; @@ -251,6 +275,15 @@ static cs4231_t *cs4231_list; #define APCPNVA 0x38UL /* APC Play DMA Next Address */ #define APCPNC 0x3cUL /* APC Play Next Count */ +/* Defines for SBUS DMA-routines */ + +#define APCVA 0x0UL /* APC DMA Address */ +#define APCC 0x4UL /* APC Count */ +#define APCNVA 0x8UL /* APC DMA Next Address */ +#define APCNC 0xcUL /* APC Next Count */ +#define APC_PLAY 0x30UL /* Play registers start at 0x30 */ +#define APC_RECORD 0x20UL /* Record registers start at 0x20 */ + /* APCCSR bits */ #define APC_INT_PENDING 0x800000 /* Interrupt Pending */ @@ -569,8 +602,7 @@ static void snd_cs4231_mce_down(cs4231_t *chip) spin_unlock_irqrestore(&chip->lock, flags); } -#ifdef EBUS_SUPPORT -static void snd_cs4231_ebus_advance_dma(struct ebus_dma_info *p, snd_pcm_substream_t *substream, unsigned int *periods_sent) +static void snd_cs4231_advance_dma(struct cs4231_dma_control *dma_cont, snd_pcm_substream_t *substream, unsigned int *periods_sent) { snd_pcm_runtime_t *runtime = substream->runtime; @@ -581,129 +613,41 @@ static void snd_cs4231_ebus_advance_dma(struct ebus_dma_info *p, snd_pcm_substre if (period_size >= (1 << 24)) BUG(); - if (ebus_dma_request(p, runtime->dma_addr + offset, period_size)) + if (dma_cont->request(dma_cont, runtime->dma_addr + offset, period_size)) return; (*periods_sent) = ((*periods_sent) + 1) % runtime->periods; } } -#endif - -#ifdef SBUS_SUPPORT -static void snd_cs4231_sbus_advance_dma(snd_pcm_substream_t *substream, unsigned int *periods_sent) -{ - cs4231_t *chip = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; - - unsigned int period_size = snd_pcm_lib_period_bytes(substream); - unsigned int offset = period_size * (*periods_sent % runtime->periods); - - if (runtime->period_size > 0xffff + 1) - BUG(); - - switch (substream->stream) { - case SNDRV_PCM_STREAM_PLAYBACK: - sbus_writel(runtime->dma_addr + offset, chip->port + APCPNVA); - sbus_writel(period_size, chip->port + APCPNC); - break; - case SNDRV_PCM_STREAM_CAPTURE: - sbus_writel(runtime->dma_addr + offset, chip->port + APCCNVA); - sbus_writel(period_size, chip->port + APCCNC); - break; - } - - (*periods_sent) = (*periods_sent + 1) % runtime->periods; -} -#endif static void cs4231_dma_trigger(snd_pcm_substream_t *substream, unsigned int what, int on) { cs4231_t *chip = snd_pcm_substream_chip(substream); + cs4231_dma_control_t *dma_cont; -#ifdef EBUS_SUPPORT - if (chip->flags & CS4231_FLAG_EBUS) { - if (what & CS4231_PLAYBACK_ENABLE) { - if (on) { - ebus_dma_prepare(&chip->eb2p, 0); - ebus_dma_enable(&chip->eb2p, 1); - snd_cs4231_ebus_advance_dma(&chip->eb2p, - chip->playback_substream, - &chip->p_periods_sent); - } else { - ebus_dma_enable(&chip->eb2p, 0); - } - } - if (what & CS4231_RECORD_ENABLE) { - if (on) { - ebus_dma_prepare(&chip->eb2c, 1); - ebus_dma_enable(&chip->eb2c, 1); - snd_cs4231_ebus_advance_dma(&chip->eb2c, - chip->capture_substream, - &chip->c_periods_sent); - } else { - ebus_dma_enable(&chip->eb2c, 0); - } - } - } else { -#endif -#ifdef SBUS_SUPPORT - u32 csr = sbus_readl(chip->port + APCCSR); - /* I don't know why, but on sbus the period counter must - * only start counting after the first period is sent. - * Therefore this dummy thing. - */ - unsigned int dummy = 0; - - switch (what) { - case CS4231_PLAYBACK_ENABLE: + if (what & CS4231_PLAYBACK_ENABLE) { + dma_cont = &chip->p_dma; if (on) { - csr &= ~APC_XINT_PLAY; - sbus_writel(csr, chip->port + APCCSR); - - csr &= ~APC_PPAUSE; - sbus_writel(csr, chip->port + APCCSR); - - snd_cs4231_sbus_advance_dma(substream, &dummy); - - csr |= APC_GENL_INT | APC_PLAY_INT | APC_XINT_ENA | - APC_XINT_PLAY | APC_XINT_EMPT | APC_XINT_GENL | - APC_XINT_PENA | APC_PDMA_READY; - sbus_writel(csr, chip->port + APCCSR); + dma_cont->prepare(dma_cont, 0); + dma_cont->enable(dma_cont, 1); + snd_cs4231_advance_dma(dma_cont, + chip->playback_substream, + &chip->p_periods_sent); } else { - csr |= APC_PPAUSE; - sbus_writel(csr, chip->port + APCCSR); - - csr &= ~APC_PDMA_READY; - sbus_writel(csr, chip->port + APCCSR); + dma_cont->enable(dma_cont, 0); } - break; - case CS4231_RECORD_ENABLE: + } + if (what & CS4231_RECORD_ENABLE) { + dma_cont = &chip->c_dma; if (on) { - csr &= ~APC_XINT_CAPT; - sbus_writel(csr, chip->port + APCCSR); - - csr &= ~APC_CPAUSE; - sbus_writel(csr, chip->port + APCCSR); - - snd_cs4231_sbus_advance_dma(substream, &dummy); - - csr |= APC_GENL_INT | APC_CAPT_INT | APC_XINT_ENA | - APC_XINT_CAPT | APC_XINT_CEMP | APC_XINT_GENL | - APC_CDMA_READY; - - sbus_writel(csr, chip->port + APCCSR); + dma_cont->prepare(dma_cont, 1); + dma_cont->enable(dma_cont, 1); + snd_cs4231_advance_dma(dma_cont, + chip->capture_substream, + &chip->c_periods_sent); } else { - csr |= APC_CPAUSE; - sbus_writel(csr, chip->port + APCCSR); - - csr &= ~APC_CDMA_READY; - sbus_writel(csr, chip->port + APCCSR); + dma_cont->enable(dma_cont, 0); } - break; - } -#endif -#ifdef EBUS_SUPPORT } -#endif } static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd) @@ -1136,10 +1080,7 @@ static int snd_cs4231_playback_prepare(snd_pcm_substream_t *substream) if (runtime->period_size > 0xffff + 1) BUG(); - snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, (runtime->period_size - 1) & 0x00ff); - snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, (runtime->period_size - 1) >> 8 & 0x00ff); chip->p_periods_sent = 0; - spin_unlock_irqrestore(&chip->lock, flags); return 0; @@ -1171,16 +1112,14 @@ static int snd_cs4231_capture_hw_free(snd_pcm_substream_t *substream) static int snd_cs4231_capture_prepare(snd_pcm_substream_t *substream) { cs4231_t *chip = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; unsigned long flags; spin_lock_irqsave(&chip->lock, flags); chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | CS4231_RECORD_PIO); - snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (runtime->period_size - 1) & 0x00ff); - snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (runtime->period_size - 1) >> 8 & 0x00ff); + chip->c_periods_sent = 0; spin_unlock_irqrestore(&chip->lock, flags); return 0; @@ -1199,134 +1138,55 @@ static void snd_cs4231_overrange(cs4231_t *chip) chip->capture_substream->runtime->overrange++; } -static irqreturn_t snd_cs4231_generic_interrupt(cs4231_t *chip) -{ - unsigned long flags; - unsigned char status; - - /*This is IRQ is not raised by the cs4231*/ - if (!(__cs4231_readb(chip, CS4231P(chip, STATUS)) & CS4231_GLOBALIRQ)) - return IRQ_NONE; - - status = snd_cs4231_in(chip, CS4231_IRQ_STATUS); - - if (status & CS4231_TIMER_IRQ) { - if (chip->timer) - snd_timer_interrupt(chip->timer, chip->timer->sticks); - } - - if (status & CS4231_RECORD_IRQ) - snd_cs4231_overrange(chip); - - /* ACK the CS4231 interrupt. */ - spin_lock_irqsave(&chip->lock, flags); - snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0); - spin_unlock_irqrestore(&chip->lock, flags); - - return 0; -} - -#ifdef SBUS_SUPPORT -static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - cs4231_t *chip = dev_id; - - /* ACK the APC interrupt. */ - u32 csr = sbus_readl(chip->port + APCCSR); - - sbus_writel(csr, chip->port + APCCSR); - - if ((chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE) && - (csr & APC_PLAY_INT) && - (csr & APC_XINT_PNVA) && - !(csr & APC_XINT_EMPT)) { - snd_cs4231_sbus_advance_dma(chip->playback_substream, - &chip->p_periods_sent); - snd_pcm_period_elapsed(chip->playback_substream); - } - - if ((chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) && - (csr & APC_CAPT_INT) && - (csr & APC_XINT_CNVA)) { - snd_cs4231_sbus_advance_dma(chip->capture_substream, - &chip->c_periods_sent); - snd_pcm_period_elapsed(chip->capture_substream); - } - - return snd_cs4231_generic_interrupt(chip); -} -#endif - -#ifdef EBUS_SUPPORT -static void snd_cs4231_ebus_play_callback(struct ebus_dma_info *p, int event, void *cookie) +static void snd_cs4231_play_callback(cs4231_t *cookie) { cs4231_t *chip = cookie; if (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE) { snd_pcm_period_elapsed(chip->playback_substream); - snd_cs4231_ebus_advance_dma(p, chip->playback_substream, + snd_cs4231_advance_dma(&chip->p_dma, chip->playback_substream, &chip->p_periods_sent); } } -static void snd_cs4231_ebus_capture_callback(struct ebus_dma_info *p, int event, void *cookie) +static void snd_cs4231_capture_callback(cs4231_t *cookie) { cs4231_t *chip = cookie; if (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) { snd_pcm_period_elapsed(chip->capture_substream); - snd_cs4231_ebus_advance_dma(p, chip->capture_substream, + snd_cs4231_advance_dma(&chip->c_dma, chip->capture_substream, &chip->c_periods_sent); } } -#endif static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substream) { cs4231_t *chip = snd_pcm_substream_chip(substream); - size_t ptr, residue, period_bytes; - + cs4231_dma_control_t *dma_cont = &chip->p_dma; + size_t ptr; + if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) return 0; - period_bytes = snd_pcm_lib_period_bytes(substream); - ptr = period_bytes * chip->p_periods_sent; -#ifdef EBUS_SUPPORT - if (chip->flags & CS4231_FLAG_EBUS) { - residue = ebus_dma_residue(&chip->eb2p); - } else { -#endif -#ifdef SBUS_SUPPORT - residue = sbus_readl(chip->port + APCPC); -#endif -#ifdef EBUS_SUPPORT - } -#endif - ptr += period_bytes - residue; - + ptr = dma_cont->address(dma_cont); + if (ptr != 0) + ptr -= substream->runtime->dma_addr; + return bytes_to_frames(substream->runtime, ptr); } static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substream) { cs4231_t *chip = snd_pcm_substream_chip(substream); - size_t ptr, residue, period_bytes; + cs4231_dma_control_t *dma_cont = &chip->c_dma; + size_t ptr; if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE)) return 0; - period_bytes = snd_pcm_lib_period_bytes(substream); - ptr = period_bytes * chip->c_periods_sent; -#ifdef EBUS_SUPPORT - if (chip->flags & CS4231_FLAG_EBUS) { - residue = ebus_dma_residue(&chip->eb2c); - } else { -#endif -#ifdef SBUS_SUPPORT - residue = sbus_readl(chip->port + APCCC); -#endif -#ifdef EBUS_SUPPORT - } -#endif - ptr += period_bytes - residue; + ptr = dma_cont->address(dma_cont); + if (ptr != 0) + ptr -= substream->runtime->dma_addr; + return bytes_to_frames(substream->runtime, ptr); } @@ -1362,30 +1222,8 @@ static int snd_cs4231_probe(cs4231_t *chip) spin_lock_irqsave(&chip->lock, flags); - /* Reset DMA engine. */ -#ifdef EBUS_SUPPORT - if (chip->flags & CS4231_FLAG_EBUS) { - /* Done by ebus_dma_register */ - } else { -#endif -#ifdef SBUS_SUPPORT - sbus_writel(APC_CHIP_RESET, chip->port + APCCSR); - sbus_writel(0x00, chip->port + APCCSR); - sbus_writel(sbus_readl(chip->port + APCCSR) | APC_CDC_RESET, - chip->port + APCCSR); - - udelay(20); - - sbus_writel(sbus_readl(chip->port + APCCSR) & ~APC_CDC_RESET, - chip->port + APCCSR); - sbus_writel(sbus_readl(chip->port + APCCSR) | (APC_XINT_ENA | - APC_XINT_PENA | - APC_XINT_CENA), - chip->port + APCCSR); -#endif -#ifdef EBUS_SUPPORT - } -#endif + /* Reset DMA engine (sbus only). */ + chip->p_dma.reset(chip); __cs4231_readb(chip, CS4231P(chip, STATUS)); /* clear any pendings IRQ */ __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); @@ -1505,8 +1343,8 @@ static int snd_cs4231_playback_close(snd_pcm_substream_t *substream) { cs4231_t *chip = snd_pcm_substream_chip(substream); - chip->playback_substream = NULL; snd_cs4231_close(chip, CS4231_MODE_PLAY); + chip->playback_substream = NULL; return 0; } @@ -1515,8 +1353,8 @@ static int snd_cs4231_capture_close(snd_pcm_substream_t *substream) { cs4231_t *chip = snd_pcm_substream_chip(substream); - chip->capture_substream = NULL; snd_cs4231_close(chip, CS4231_MODE_RECORD); + chip->capture_substream = NULL; return 0; } @@ -1571,21 +1409,7 @@ int snd_cs4231_pcm(cs4231_t *chip) pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; strcpy(pcm->name, "CS4231"); -#ifdef EBUS_SUPPORT - if (chip->flags & CS4231_FLAG_EBUS) { - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->dev_u.pdev), - 64*1024, 128*1024); - } else { -#endif -#ifdef SBUS_SUPPORT - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_SBUS, - snd_dma_sbus_data(chip->dev_u.sdev), - 64*1024, 128*1024); -#endif -#ifdef EBUS_SUPPORT - } -#endif + chip->p_dma.preallocate(chip, pcm); chip->pcm = pcm; @@ -1942,6 +1766,180 @@ static int cs4231_attach_finish(snd_card_t *card, cs4231_t *chip) } #ifdef SBUS_SUPPORT + +static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long flags; + unsigned char status; + u32 csr; + cs4231_t *chip = dev_id; + + /*This is IRQ is not raised by the cs4231*/ + if (!(__cs4231_readb(chip, CS4231P(chip, STATUS)) & CS4231_GLOBALIRQ)) + return IRQ_NONE; + + /* ACK the APC interrupt. */ + csr = sbus_readl(chip->port + APCCSR); + + sbus_writel(csr, chip->port + APCCSR); + + if ((csr & APC_PDMA_READY) && + (csr & APC_PLAY_INT) && + (csr & APC_XINT_PNVA) && + !(csr & APC_XINT_EMPT)) + snd_cs4231_play_callback(chip); + + if ((csr & APC_CDMA_READY) && + (csr & APC_CAPT_INT) && + (csr & APC_XINT_CNVA) && + !(csr & APC_XINT_EMPT)) + snd_cs4231_capture_callback(chip); + + status = snd_cs4231_in(chip, CS4231_IRQ_STATUS); + + if (status & CS4231_TIMER_IRQ) { + if (chip->timer) + snd_timer_interrupt(chip->timer, chip->timer->sticks); + } + + if ((status & CS4231_RECORD_IRQ) && (csr & APC_CDMA_READY)) + snd_cs4231_overrange(chip); + + /* ACK the CS4231 interrupt. */ + spin_lock_irqsave(&chip->lock, flags); + snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0); + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +/* + * SBUS DMA routines + */ + +int sbus_dma_request(struct cs4231_dma_control *dma_cont, dma_addr_t bus_addr, size_t len) +{ + unsigned long flags; + u32 test, csr; + int err; + sbus_dma_info_t *base = &dma_cont->sbus_info; + + if (len >= (1 << 24)) + return -EINVAL; + spin_lock_irqsave(&base->lock, flags); + csr = sbus_readl(base->regs + APCCSR); + err = -EINVAL; + test = APC_CDMA_READY; + if ( base->dir == APC_PLAY ) + test = APC_PDMA_READY; + if (!(csr & test)) + goto out; + err = -EBUSY; + csr = sbus_readl(base->regs + APCCSR); + test = APC_XINT_CNVA; + if ( base->dir == APC_PLAY ) + test = APC_XINT_PNVA; + if (!(csr & test)) + goto out; + err = 0; + sbus_writel(bus_addr, base->regs + base->dir + APCNVA); + sbus_writel(len, base->regs + base->dir + APCNC); +out: + spin_unlock_irqrestore(&base->lock, flags); + return err; +} + +void sbus_dma_prepare(struct cs4231_dma_control *dma_cont, int d) +{ + unsigned long flags; + u32 csr, test; + sbus_dma_info_t *base = &dma_cont->sbus_info; + + spin_lock_irqsave(&base->lock, flags); + csr = sbus_readl(base->regs + APCCSR); + test = APC_GENL_INT | APC_PLAY_INT | APC_XINT_ENA | + APC_XINT_PLAY | APC_XINT_PEMP | APC_XINT_GENL | + APC_XINT_PENA; + if ( base->dir == APC_RECORD ) + test = APC_GENL_INT | APC_CAPT_INT | APC_XINT_ENA | + APC_XINT_CAPT | APC_XINT_CEMP | APC_XINT_GENL; + csr |= test; + sbus_writel(csr, base->regs + APCCSR); + spin_unlock_irqrestore(&base->lock, flags); +} + +void sbus_dma_enable(struct cs4231_dma_control *dma_cont, int on) +{ + unsigned long flags; + u32 csr, shift; + sbus_dma_info_t *base = &dma_cont->sbus_info; + + spin_lock_irqsave(&base->lock, flags); + if (!on) { + if (base->dir == APC_PLAY) { + sbus_writel(0, base->regs + base->dir + APCNVA); + sbus_writel(1, base->regs + base->dir + APCC); + } + else + { + sbus_writel(0, base->regs + base->dir + APCNC); + sbus_writel(0, base->regs + base->dir + APCVA); + } + } + udelay(600); + csr = sbus_readl(base->regs + APCCSR); + shift = 0; + if ( base->dir == APC_PLAY ) + shift = 1; + if (on) + csr &= ~(APC_CPAUSE << shift); + else + csr |= (APC_CPAUSE << shift); + sbus_writel(csr, base->regs + APCCSR); + if (on) + csr |= (APC_CDMA_READY << shift); + else + csr &= ~(APC_CDMA_READY << shift); + sbus_writel(csr, base->regs + APCCSR); + + spin_unlock_irqrestore(&base->lock, flags); +} + +unsigned int sbus_dma_addr(struct cs4231_dma_control *dma_cont) +{ + sbus_dma_info_t *base = &dma_cont->sbus_info; + + return sbus_readl(base->regs + base->dir + APCVA); +} + +void sbus_dma_reset(cs4231_t *chip) +{ + sbus_writel(APC_CHIP_RESET, chip->port + APCCSR); + sbus_writel(0x00, chip->port + APCCSR); + sbus_writel(sbus_readl(chip->port + APCCSR) | APC_CDC_RESET, + chip->port + APCCSR); + + udelay(20); + + sbus_writel(sbus_readl(chip->port + APCCSR) & ~APC_CDC_RESET, + chip->port + APCCSR); + sbus_writel(sbus_readl(chip->port + APCCSR) | (APC_XINT_ENA | + APC_XINT_PENA | + APC_XINT_CENA), + chip->port + APCCSR); +} + +void sbus_dma_preallocate(cs4231_t *chip, snd_pcm_t *pcm) +{ + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_SBUS, + snd_dma_sbus_data(chip->dev_u.sdev), + 64*1024, 128*1024); +} + +/* + * Init and exit routines + */ + static int snd_cs4231_sbus_free(cs4231_t *chip) { if (chip->irq[0]) @@ -1983,6 +1981,8 @@ static int __init snd_cs4231_sbus_create(snd_card_t *card, return -ENOMEM; spin_lock_init(&chip->lock); + spin_lock_init(&chip->c_dma.sbus_info.lock); + spin_lock_init(&chip->p_dma.sbus_info.lock); init_MUTEX(&chip->mce_mutex); init_MUTEX(&chip->open_mutex); chip->card = card; @@ -1998,6 +1998,25 @@ static int __init snd_cs4231_sbus_create(snd_card_t *card, return -EIO; } + chip->c_dma.sbus_info.regs = chip->port; + chip->p_dma.sbus_info.regs = chip->port; + chip->c_dma.sbus_info.dir = APC_RECORD; + chip->p_dma.sbus_info.dir = APC_PLAY; + + chip->p_dma.prepare = sbus_dma_prepare; + chip->p_dma.enable = sbus_dma_enable; + chip->p_dma.request = sbus_dma_request; + chip->p_dma.address = sbus_dma_addr; + chip->p_dma.reset = sbus_dma_reset; + chip->p_dma.preallocate = sbus_dma_preallocate; + + chip->c_dma.prepare = sbus_dma_prepare; + chip->c_dma.enable = sbus_dma_enable; + chip->c_dma.request = sbus_dma_request; + chip->c_dma.address = sbus_dma_addr; + chip->c_dma.reset = sbus_dma_reset; + chip->c_dma.preallocate = sbus_dma_preallocate; + if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt, SA_SHIRQ, "cs4231", chip)) { snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %s\n", @@ -2051,15 +2070,70 @@ static int cs4231_sbus_attach(struct sbus_dev *sdev) #endif #ifdef EBUS_SUPPORT + +static void snd_cs4231_ebus_play_callback(struct ebus_dma_info *p, int event, void *cookie) +{ + cs4231_t *chip = cookie; + + snd_cs4231_play_callback(chip); +} + +static void snd_cs4231_ebus_capture_callback(struct ebus_dma_info *p, int event, void *cookie) +{ + cs4231_t *chip = cookie; + + snd_cs4231_capture_callback(chip); +} + +/* + * EBUS DMA wrappers + */ + +int _ebus_dma_request(struct cs4231_dma_control *dma_cont, dma_addr_t bus_addr, size_t len) +{ + return ebus_dma_request(&dma_cont->ebus_info, bus_addr, len); +} + +void _ebus_dma_enable(struct cs4231_dma_control *dma_cont, int on) +{ + ebus_dma_enable(&dma_cont->ebus_info, on); +} + +void _ebus_dma_prepare(struct cs4231_dma_control *dma_cont, int dir) +{ + ebus_dma_prepare(&dma_cont->ebus_info, dir); +} + +unsigned int _ebus_dma_addr(struct cs4231_dma_control *dma_cont) +{ + return ebus_dma_addr(&dma_cont->ebus_info); +} + +void _ebus_dma_reset(cs4231_t *chip) +{ + return; +} + +void _ebus_dma_preallocate(cs4231_t *chip, snd_pcm_t *pcm) +{ + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->dev_u.pdev), + 64*1024, 128*1024); +} + +/* + * Init and exit routines + */ + static int snd_cs4231_ebus_free(cs4231_t *chip) { - if (chip->eb2c.regs) { - ebus_dma_unregister(&chip->eb2c); - iounmap(chip->eb2c.regs); + if (chip->c_dma.ebus_info.regs) { + ebus_dma_unregister(&chip->c_dma.ebus_info); + iounmap(chip->c_dma.ebus_info.regs); } - if (chip->eb2p.regs) { - ebus_dma_unregister(&chip->eb2p); - iounmap(chip->eb2p.regs); + if (chip->p_dma.ebus_info.regs) { + ebus_dma_unregister(&chip->p_dma.ebus_info); + iounmap(chip->p_dma.ebus_info.regs); } if (chip->port) @@ -2097,8 +2171,8 @@ static int __init snd_cs4231_ebus_create(snd_card_t *card, return -ENOMEM; spin_lock_init(&chip->lock); - spin_lock_init(&chip->eb2c.lock); - spin_lock_init(&chip->eb2p.lock); + spin_lock_init(&chip->c_dma.ebus_info.lock); + spin_lock_init(&chip->p_dma.ebus_info.lock); init_MUTEX(&chip->mce_mutex); init_MUTEX(&chip->open_mutex); chip->flags |= CS4231_FLAG_EBUS; @@ -2106,43 +2180,57 @@ static int __init snd_cs4231_ebus_create(snd_card_t *card, chip->dev_u.pdev = edev->bus->self; memcpy(&chip->image, &snd_cs4231_original_image, sizeof(snd_cs4231_original_image)); - strcpy(chip->eb2c.name, "cs4231(capture)"); - chip->eb2c.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER; - chip->eb2c.callback = snd_cs4231_ebus_capture_callback; - chip->eb2c.client_cookie = chip; - chip->eb2c.irq = edev->irqs[0]; - strcpy(chip->eb2p.name, "cs4231(play)"); - chip->eb2p.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER; - chip->eb2p.callback = snd_cs4231_ebus_play_callback; - chip->eb2p.client_cookie = chip; - chip->eb2p.irq = edev->irqs[1]; + strcpy(chip->c_dma.ebus_info.name, "cs4231(capture)"); + chip->c_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER; + chip->c_dma.ebus_info.callback = snd_cs4231_ebus_capture_callback; + chip->c_dma.ebus_info.client_cookie = chip; + chip->c_dma.ebus_info.irq = edev->irqs[0]; + strcpy(chip->p_dma.ebus_info.name, "cs4231(play)"); + chip->p_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER; + chip->p_dma.ebus_info.callback = snd_cs4231_ebus_play_callback; + chip->p_dma.ebus_info.client_cookie = chip; + chip->p_dma.ebus_info.irq = edev->irqs[1]; + + chip->p_dma.prepare = _ebus_dma_prepare; + chip->p_dma.enable = _ebus_dma_enable; + chip->p_dma.request = _ebus_dma_request; + chip->p_dma.address = _ebus_dma_addr; + chip->p_dma.reset = _ebus_dma_reset; + chip->p_dma.preallocate = _ebus_dma_preallocate; + + chip->c_dma.prepare = _ebus_dma_prepare; + chip->c_dma.enable = _ebus_dma_enable; + chip->c_dma.request = _ebus_dma_request; + chip->c_dma.address = _ebus_dma_addr; + chip->c_dma.reset = _ebus_dma_reset; + chip->c_dma.preallocate = _ebus_dma_preallocate; chip->port = ioremap(edev->resource[0].start, 0x10); - chip->eb2p.regs = ioremap(edev->resource[1].start, 0x10); - chip->eb2c.regs = ioremap(edev->resource[2].start, 0x10); - if (!chip->port || !chip->eb2p.regs || !chip->eb2c.regs) { + chip->p_dma.ebus_info.regs = ioremap(edev->resource[1].start, 0x10); + chip->c_dma.ebus_info.regs = ioremap(edev->resource[2].start, 0x10); + if (!chip->port || !chip->p_dma.ebus_info.regs || !chip->c_dma.ebus_info.regs) { snd_cs4231_ebus_free(chip); snd_printdd("cs4231-%d: Unable to map chip registers.\n", dev); return -EIO; } - if (ebus_dma_register(&chip->eb2c)) { + if (ebus_dma_register(&chip->c_dma.ebus_info)) { snd_cs4231_ebus_free(chip); snd_printdd("cs4231-%d: Unable to register EBUS capture DMA\n", dev); return -EBUSY; } - if (ebus_dma_irq_enable(&chip->eb2c, 1)) { + if (ebus_dma_irq_enable(&chip->c_dma.ebus_info, 1)) { snd_cs4231_ebus_free(chip); snd_printdd("cs4231-%d: Unable to enable EBUS capture IRQ\n", dev); return -EBUSY; } - if (ebus_dma_register(&chip->eb2p)) { + if (ebus_dma_register(&chip->p_dma.ebus_info)) { snd_cs4231_ebus_free(chip); snd_printdd("cs4231-%d: Unable to register EBUS play DMA\n", dev); return -EBUSY; } - if (ebus_dma_irq_enable(&chip->eb2p, 1)) { + if (ebus_dma_irq_enable(&chip->p_dma.ebus_info, 1)) { snd_cs4231_ebus_free(chip); snd_printdd("cs4231-%d: Unable to enable EBUS play IRQ\n", dev); return -EBUSY; diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index b5c4c15ae7f09ccd620c82a0de7fd1568510f8fc..59a77129470929afb5509060df69703f4cded08f 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -343,9 +343,6 @@ typedef struct snd_dbri { struct snd_dbri *next; } snd_dbri_t; -/* Needed for the ALSA macros to work */ -#define chip_t snd_dbri_t - #define DBRI_MAX_VOLUME 63 /* Output volume */ #define DBRI_MAX_GAIN 15 /* Input gain */ #define DBRI_RIGHT_BALANCE 255 @@ -1767,7 +1764,7 @@ static void xmit_descs(unsigned long data) spin_unlock_irqrestore(&dbri->lock, flags); } -DECLARE_TASKLET(xmit_descs_task, xmit_descs, 0); +static DECLARE_TASKLET(xmit_descs_task, xmit_descs, 0); /* transmission_complete_intr() * diff --git a/sound/synth/emux/emux_synth.c b/sound/synth/emux/emux_synth.c index 751bf1272af3bc77917d5ba3f66427ca76cdd09a..bd71b73be6571fecb3027952ec6c8a1d360c87f6 100644 --- a/sound/synth/emux/emux_synth.c +++ b/sound/synth/emux/emux_synth.c @@ -171,7 +171,6 @@ snd_emux_note_off(void *p, int note, int vel, snd_midi_channel_t *chan) vp = &emu->voices[ch]; if (STATE_IS_PLAYING(vp->state) && vp->chan == chan && vp->key == note) { - vp->time = emu->use_time++; vp->state = SNDRV_EMUX_ST_RELEASED; if (vp->ontime == jiffies) { /* if note-off is sent too shortly after diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 2ead878bcb8f4793113db63a685caa026955b2eb..99dae024b640bfd9f3ddadbf4de227cd5daca95c 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -185,7 +184,6 @@ struct snd_usb_substream { unsigned int num_formats; /* number of supported audio formats (list) */ struct list_head fmt_list; /* format list */ spinlock_t lock; - struct tasklet_struct start_period_elapsed; /* for start trigger */ struct snd_urb_ops ops; /* callbacks (must be filled at init) */ }; @@ -479,6 +477,28 @@ static int retire_playback_sync_urb_hs(snd_usb_substream_t *subs, return 0; } +/* + * Prepare urb for streaming before playback starts. + * + * We don't care about (or have) any data, so we just send a transfer delimiter. + */ +static int prepare_startup_playback_urb(snd_usb_substream_t *subs, + snd_pcm_runtime_t *runtime, + struct urb *urb) +{ + unsigned int i; + snd_urb_ctx_t *ctx = urb->context; + + urb->dev = ctx->subs->dev; + urb->number_of_packets = subs->packs_per_ms; + for (i = 0; i < subs->packs_per_ms; ++i) { + urb->iso_frame_desc[i].offset = 0; + urb->iso_frame_desc[i].length = 0; + } + urb->transfer_buffer_length = 0; + return 0; +} + /* * prepare urb for playback data pipe * @@ -568,12 +588,8 @@ static int prepare_playback_urb(snd_usb_substream_t *subs, subs->hwptr_done -= runtime->buffer_size; spin_unlock_irqrestore(&subs->lock, flags); urb->transfer_buffer_length = offs * stride; - if (period_elapsed) { - if (likely(subs->running)) - snd_pcm_period_elapsed(subs->pcm_substream); - else - tasklet_hi_schedule(&subs->start_period_elapsed); - } + if (period_elapsed) + snd_pcm_period_elapsed(subs->pcm_substream); return 0; } @@ -588,22 +604,12 @@ static int retire_playback_urb(snd_usb_substream_t *subs, return 0; } -/* - * Delay the snd_pcm_period_elapsed() call until after the start trigger - * callback so that we're not longer in the substream's lock. - */ -static void start_period_elapsed(unsigned long data) -{ - snd_usb_substream_t *subs = (snd_usb_substream_t *)data; - snd_pcm_period_elapsed(subs->pcm_substream); -} - /* */ static struct snd_urb_ops audio_urb_ops[2] = { { - .prepare = prepare_playback_urb, + .prepare = prepare_startup_playback_urb, .retire = retire_playback_urb, .prepare_sync = prepare_playback_sync_urb, .retire_sync = retire_playback_sync_urb, @@ -618,7 +624,7 @@ static struct snd_urb_ops audio_urb_ops[2] = { static struct snd_urb_ops audio_urb_ops_high_speed[2] = { { - .prepare = prepare_playback_urb, + .prepare = prepare_startup_playback_urb, .retire = retire_playback_urb, .prepare_sync = prepare_playback_sync_urb_hs, .retire_sync = retire_playback_sync_urb_hs, @@ -692,9 +698,9 @@ static int snd_pcm_alloc_vmalloc_buffer(snd_pcm_substream_t *subs, size_t size) if (runtime->dma_area) { if (runtime->dma_bytes >= size) return 0; /* already large enough */ - vfree_nocheck(runtime->dma_area); + vfree(runtime->dma_area); } - runtime->dma_area = vmalloc_nocheck(size); + runtime->dma_area = vmalloc(size); if (! runtime->dma_area) return -ENOMEM; runtime->dma_bytes = size; @@ -706,7 +712,7 @@ static int snd_pcm_free_vmalloc_buffer(snd_pcm_substream_t *subs) { snd_pcm_runtime_t *runtime = subs->runtime; if (runtime->dma_area) { - vfree_nocheck(runtime->dma_area); + vfree(runtime->dma_area); runtime->dma_area = NULL; } return 0; @@ -838,8 +844,7 @@ static int wait_clear_urbs(snd_usb_substream_t *subs) } if (! alive) break; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); + schedule_timeout_uninterruptible(1); } while (time_before(jiffies, end_time)); if (alive) snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); @@ -864,25 +869,40 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(snd_pcm_substream_t *substream) /* - * start/stop substream + * start/stop playback substream */ -static int snd_usb_pcm_trigger(snd_pcm_substream_t *substream, int cmd) +static int snd_usb_pcm_playback_trigger(snd_pcm_substream_t *substream, + int cmd) { - snd_usb_substream_t *subs = (snd_usb_substream_t *)substream->runtime->private_data; - int err; + snd_usb_substream_t *subs = substream->runtime->private_data; switch (cmd) { case SNDRV_PCM_TRIGGER_START: - err = start_urbs(subs, substream->runtime); - break; + subs->ops.prepare = prepare_playback_urb; + return 0; case SNDRV_PCM_TRIGGER_STOP: - err = deactivate_urbs(subs, 0, 0); - break; + return deactivate_urbs(subs, 0, 0); default: - err = -EINVAL; - break; + return -EINVAL; + } +} + +/* + * start/stop capture substream + */ +static int snd_usb_pcm_capture_trigger(snd_pcm_substream_t *substream, + int cmd) +{ + snd_usb_substream_t *subs = substream->runtime->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + return start_urbs(subs, substream->runtime); + case SNDRV_PCM_TRIGGER_STOP: + return deactivate_urbs(subs, 0, 0); + default: + return -EINVAL; } - return err < 0 ? err : 0; } @@ -1044,7 +1064,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; u->urb->interval = 1 << subs->datainterval; u->urb->context = u; - u->urb->complete = snd_usb_complete_callback(snd_complete_urb); + u->urb->complete = snd_complete_urb; } if (subs->syncpipe) { @@ -1070,7 +1090,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by u->urb->number_of_packets = 1; u->urb->interval = 1 << subs->syncinterval; u->urb->context = u; - u->urb->complete = snd_usb_complete_callback(snd_complete_sync_urb); + u->urb->complete = snd_complete_sync_urb; } } return 0; @@ -1414,7 +1434,7 @@ static int snd_usb_hw_free(snd_pcm_substream_t *substream) static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream) { snd_pcm_runtime_t *runtime = substream->runtime; - snd_usb_substream_t *subs = (snd_usb_substream_t *)runtime->private_data; + snd_usb_substream_t *subs = runtime->private_data; if (! subs->cur_audiofmt) { snd_printk(KERN_ERR "usbaudio: no format is specified!\n"); @@ -1434,7 +1454,13 @@ static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream) deactivate_urbs(subs, 0, 1); wait_clear_urbs(subs); - return 0; + /* for playback, submit the URBs now; otherwise, the first hwptr_done + * updates for all URBs would happen at the same time when starting */ + if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) { + subs->ops.prepare = prepare_startup_playback_urb; + return start_urbs(subs, runtime); + } else + return 0; } static snd_pcm_hardware_t snd_usb_playback = @@ -1848,7 +1874,7 @@ static snd_pcm_ops_t snd_usb_playback_ops = { .hw_params = snd_usb_hw_params, .hw_free = snd_usb_hw_free, .prepare = snd_usb_pcm_prepare, - .trigger = snd_usb_pcm_trigger, + .trigger = snd_usb_pcm_playback_trigger, .pointer = snd_usb_pcm_pointer, .page = snd_pcm_get_vmalloc_page, }; @@ -1860,7 +1886,7 @@ static snd_pcm_ops_t snd_usb_capture_ops = { .hw_params = snd_usb_hw_params, .hw_free = snd_usb_hw_free, .prepare = snd_usb_pcm_prepare, - .trigger = snd_usb_pcm_trigger, + .trigger = snd_usb_pcm_capture_trigger, .pointer = snd_usb_pcm_pointer, .page = snd_pcm_get_vmalloc_page, }; @@ -2079,9 +2105,6 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat INIT_LIST_HEAD(&subs->fmt_list); spin_lock_init(&subs->lock); - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - tasklet_init(&subs->start_period_elapsed, start_period_elapsed, - (unsigned long)subs); subs->stream = as; subs->direction = stream; @@ -2755,9 +2778,9 @@ static int create_fixed_stream_quirk(snd_usb_audio_t *chip, /* * create a stream for an interface with proper descriptors */ -static int create_standard_interface_quirk(snd_usb_audio_t *chip, - struct usb_interface *iface, - const snd_usb_audio_quirk_t *quirk) +static int create_standard_audio_quirk(snd_usb_audio_t *chip, + struct usb_interface *iface, + const snd_usb_audio_quirk_t *quirk) { struct usb_host_interface *alts; struct usb_interface_descriptor *altsd; @@ -2765,24 +2788,14 @@ static int create_standard_interface_quirk(snd_usb_audio_t *chip, alts = &iface->altsetting[0]; altsd = get_iface_desc(alts); - switch (quirk->type) { - case QUIRK_AUDIO_STANDARD_INTERFACE: - err = parse_audio_endpoints(chip, altsd->bInterfaceNumber); - if (!err) - usb_set_interface(chip->dev, altsd->bInterfaceNumber, 0); /* reset the current interface */ - break; - case QUIRK_MIDI_STANDARD_INTERFACE: - err = snd_usb_create_midi_interface(chip, iface, NULL); - break; - default: - snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type); - return -ENXIO; - } + err = parse_audio_endpoints(chip, altsd->bInterfaceNumber); if (err < 0) { snd_printk(KERN_ERR "cannot setup if %d: error %d\n", altsd->bInterfaceNumber, err); return err; } + /* reset the current interface */ + usb_set_interface(chip->dev, altsd->bInterfaceNumber, 0); return 0; } @@ -3044,7 +3057,7 @@ static int snd_usb_create_quirk(snd_usb_audio_t *chip, [QUIRK_MIDI_RAW] = snd_usb_create_midi_interface, [QUIRK_MIDI_EMAGIC] = snd_usb_create_midi_interface, [QUIRK_MIDI_MIDITECH] = snd_usb_create_midi_interface, - [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_interface_quirk, + [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, [QUIRK_AUDIO_EDIROL_UA700_UA25] = create_ua700_ua25_quirk, [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk, @@ -3222,7 +3235,6 @@ static void *snd_usb_audio_probe(struct usb_device *dev, struct usb_interface *intf, const struct usb_device_id *usb_id) { - struct usb_host_config *config = dev->actconfig; const snd_usb_audio_quirk_t *quirk = (const snd_usb_audio_quirk_t *)usb_id->driver_info; int i, err; snd_usb_audio_t *chip; @@ -3243,7 +3255,6 @@ static void *snd_usb_audio_probe(struct usb_device *dev, if (id == USB_ID(0x041e, 0x3000)) { if (snd_usb_extigy_boot_quirk(dev, intf) < 0) goto __err_val; - config = dev->actconfig; } /* SB Audigy 2 NX needs its own boot-up magic, too */ if (id == USB_ID(0x041e, 0x3020)) { @@ -3272,11 +3283,6 @@ static void *snd_usb_audio_probe(struct usb_device *dev, /* it's a fresh one. * now look for an empty slot and create a new card instance */ - /* first, set the current configuration for this device */ - if (usb_reset_configuration(dev) < 0) { - snd_printk(KERN_ERR "cannot reset configuration (value 0x%x)\n", get_cfg_desc(config)->bConfigurationValue); - goto __error; - } for (i = 0; i < SNDRV_CARDS; i++) if (enable[i] && ! usb_chip[i] && (vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) && diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index ad9eab211d8fc3970f20baa47d20242812dd8866..b5802022bb194ba7be57d8df7a185a60271887f4 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -249,14 +249,6 @@ void snd_usbmidi_disconnect(struct list_head *p); #define get_cfg_desc(cfg) (&(cfg)->desc) #endif -#ifndef usb_pipe_needs_resubmit -#define usb_pipe_needs_resubmit(pipe) 1 -#endif - -#ifndef snd_usb_complete_callback -#define snd_usb_complete_callback(x) (x) -#endif - #ifndef snd_usb_get_speed #define snd_usb_get_speed(dev) ((dev)->speed) #endif diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index f1a2e2c2e02fa8c1b679695fb20d4d5e892c936b..f8aa662562a04298b59acca8d0796da608364226 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -47,7 +47,6 @@ #include #include #include -#include #include #include "usbaudio.h" @@ -246,10 +245,8 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb, struct pt_regs *regs) } } - if (usb_pipe_needs_resubmit(urb->pipe)) { - urb->dev = ep->umidi->chip->dev; - snd_usbmidi_submit_urb(urb, GFP_ATOMIC); - } + urb->dev = ep->umidi->chip->dev; + snd_usbmidi_submit_urb(urb, GFP_ATOMIC); } static void snd_usbmidi_out_urb_complete(struct urb* urb, struct pt_regs *regs) @@ -863,13 +860,12 @@ static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi, return -ENOMEM; } if (ep_info->in_interval) - usb_fill_int_urb(ep->urb, umidi->chip->dev, pipe, buffer, length, - snd_usb_complete_callback(snd_usbmidi_in_urb_complete), - ep, ep_info->in_interval); + usb_fill_int_urb(ep->urb, umidi->chip->dev, pipe, buffer, + length, snd_usbmidi_in_urb_complete, ep, + ep_info->in_interval); else - usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer, length, - snd_usb_complete_callback(snd_usbmidi_in_urb_complete), - ep); + usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer, + length, snd_usbmidi_in_urb_complete, ep); ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; rep->in = ep; @@ -933,8 +929,7 @@ static int snd_usbmidi_out_endpoint_create(snd_usb_midi_t* umidi, return -ENOMEM; } usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer, - ep->max_transfer, - snd_usb_complete_callback(snd_usbmidi_out_urb_complete), ep); + ep->max_transfer, snd_usbmidi_out_urb_complete, ep); ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; spin_lock_init(&ep->buffer_lock); @@ -1550,46 +1545,45 @@ int snd_usb_create_midi_interface(snd_usb_audio_t* chip, /* detect the endpoint(s) to use */ memset(endpoints, 0, sizeof(endpoints)); - if (!quirk) { + switch (quirk ? quirk->type : QUIRK_MIDI_STANDARD_INTERFACE) { + case QUIRK_MIDI_STANDARD_INTERFACE: err = snd_usbmidi_get_ms_info(umidi, endpoints); - } else { - switch (quirk->type) { - case QUIRK_MIDI_FIXED_ENDPOINT: - memcpy(&endpoints[0], quirk->data, - sizeof(snd_usb_midi_endpoint_info_t)); - err = snd_usbmidi_detect_endpoints(umidi, &endpoints[0], 1); - break; - case QUIRK_MIDI_YAMAHA: - err = snd_usbmidi_detect_yamaha(umidi, &endpoints[0]); - break; - case QUIRK_MIDI_MIDIMAN: - umidi->usb_protocol_ops = &snd_usbmidi_midiman_ops; - memcpy(&endpoints[0], quirk->data, - sizeof(snd_usb_midi_endpoint_info_t)); - err = 0; - break; - case QUIRK_MIDI_NOVATION: - umidi->usb_protocol_ops = &snd_usbmidi_novation_ops; - err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); - break; - case QUIRK_MIDI_RAW: - umidi->usb_protocol_ops = &snd_usbmidi_raw_ops; - err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); - break; - case QUIRK_MIDI_EMAGIC: - umidi->usb_protocol_ops = &snd_usbmidi_emagic_ops; - memcpy(&endpoints[0], quirk->data, - sizeof(snd_usb_midi_endpoint_info_t)); - err = snd_usbmidi_detect_endpoints(umidi, &endpoints[0], 1); - break; - case QUIRK_MIDI_MIDITECH: - err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); - break; - default: - snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type); - err = -ENXIO; - break; - } + break; + case QUIRK_MIDI_FIXED_ENDPOINT: + memcpy(&endpoints[0], quirk->data, + sizeof(snd_usb_midi_endpoint_info_t)); + err = snd_usbmidi_detect_endpoints(umidi, &endpoints[0], 1); + break; + case QUIRK_MIDI_YAMAHA: + err = snd_usbmidi_detect_yamaha(umidi, &endpoints[0]); + break; + case QUIRK_MIDI_MIDIMAN: + umidi->usb_protocol_ops = &snd_usbmidi_midiman_ops; + memcpy(&endpoints[0], quirk->data, + sizeof(snd_usb_midi_endpoint_info_t)); + err = 0; + break; + case QUIRK_MIDI_NOVATION: + umidi->usb_protocol_ops = &snd_usbmidi_novation_ops; + err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); + break; + case QUIRK_MIDI_RAW: + umidi->usb_protocol_ops = &snd_usbmidi_raw_ops; + err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); + break; + case QUIRK_MIDI_EMAGIC: + umidi->usb_protocol_ops = &snd_usbmidi_emagic_ops; + memcpy(&endpoints[0], quirk->data, + sizeof(snd_usb_midi_endpoint_info_t)); + err = snd_usbmidi_detect_endpoints(umidi, &endpoints[0], 1); + break; + case QUIRK_MIDI_MIDITECH: + err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); + break; + default: + snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type); + err = -ENXIO; + break; } if (err < 0) { kfree(umidi); diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index c3c08c9cb46edfceca5b018f9f5efe7897201aa0..e570d140258dcadd35f80c9122c52ac1ba854e0c 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -911,7 +911,7 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc, case USB_ID(0x0672, 0x1041): if (!strcmp(kctl->id.name, "PCM Playback Volume") && cval->min == -15616) { - snd_printk("using volume control quirk for the UDA1321/N101 chip\n"); + snd_printk(KERN_INFO "using volume control quirk for the UDA1321/N101 chip\n"); cval->max = -256; } } diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 948759da65638afb12c1aae0a455231c8ba651eb..ba506c3871f443f437ec909998c3885a691cc4d2 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -294,6 +294,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* a later revision uses ID 0x0099 */ USB_DEVICE(0x0582, 0x0005), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", @@ -384,6 +385,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* a later revision uses ID 0x009d */ USB_DEVICE(0x0582, 0x0009), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", @@ -532,6 +534,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* has ID 0x0013 when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x0012), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", @@ -545,6 +548,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* has ID 0x0015 when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x0014), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", @@ -558,6 +562,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* has ID 0x0017 when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x0016), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", @@ -588,6 +593,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* has ID 0x001c when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x001b), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", @@ -618,6 +624,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* has ID 0x001e when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x001d), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", @@ -631,6 +638,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* has ID 0x0024 when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x0023), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", @@ -675,6 +683,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* has ID 0x0028 when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x0027), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", @@ -688,6 +697,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* has ID 0x002a when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x0029), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", @@ -732,6 +742,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* has ID 0x002e when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x002d), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", @@ -745,6 +756,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* has ID 0x0030 when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x002f), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", @@ -758,6 +770,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* has ID 0x0034 when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x0033), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", @@ -770,7 +783,12 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, + /* TODO: add Roland M-1000 support */ { + /* + * Has ID 0x0038 when not in "Advanced Driver" mode; + * later revisions use IDs 0x0054 and 0x00a2. + */ USB_DEVICE(0x0582, 0x0037), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", @@ -815,6 +833,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* has ID 0x0041 when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x0040), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", @@ -828,6 +847,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* has ID 0x0043 when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x0042), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", @@ -871,6 +891,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* has ID 0x004a when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x0048), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", @@ -883,7 +904,9 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, + /* TODO: add Edirol M-100FX support */ { + /* has ID 0x004f when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x004d), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", @@ -931,7 +954,9 @@ YAMAHA_DEVICE(0x7010, "UB99"), .type = QUIRK_MIDI_STANDARD_INTERFACE } }, + /* TODO: add Roland EXR support */ { + /* has ID 0x0067 when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x0065), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", @@ -945,6 +970,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* has ID 0x006b when not in "Advanced Driver" mode */ USB_DEVICE_VENDOR_SPEC(0x0582, 0x006a), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", @@ -958,6 +984,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* has ID 0x006e when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x006d), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", @@ -1002,6 +1029,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* has ID 0x0076 when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x0075), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "BOSS", @@ -1015,10 +1043,11 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { + /* has ID 0x007b when not in "Advanced Driver" mode */ USB_DEVICE_VENDOR_SPEC(0x0582, 0x007a), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "Roland", - /* RD-700SX, RD-300SX */ + /* "RD" or "RD-700SX"? */ .ifnum = 0, .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = & (const snd_usb_midi_endpoint_info_t) { @@ -1048,6 +1077,15 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, + /* TODO: add Edirol UA-101 support */ + /* TODO: add Roland G-70 support */ + /* TODO: add Roland V-SYNTH XT support */ + /* TODO: add BOSS GT-PRO support */ + /* TODO: add Edirol PC-50 support */ + /* TODO: add Edirol PC-80 support */ + /* TODO: add Edirol UA-1EX support */ + /* TODO: add Edirol UM-3 support */ + /* TODO: add Edirol MD-P1 support */ /* Midiman/M-Audio devices */ { diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c index 0281a362857a2b1753af67eb2cfa872a4bfbca8c..8abe08611df60928ad695f5cd1c0424917464401 100644 --- a/sound/usb/usx2y/usX2Yhwdep.c +++ b/sound/usb/usx2y/usX2Yhwdep.c @@ -193,7 +193,7 @@ static int usX2Y_create_alsa_devices(snd_card_t* card) do { if ((err = usX2Y_create_usbmidi(card)) < 0) { - snd_printk("usX2Y_create_alsa_devices: usX2Y_create_usbmidi error %i \n", err); + snd_printk(KERN_ERR "usX2Y_create_alsa_devices: usX2Y_create_usbmidi error %i \n", err); break; } if ((err = usX2Y_audio_create(card)) < 0) @@ -224,7 +224,7 @@ static int snd_usX2Y_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp) } err = usb_set_interface(dev, 0, 1); if (err) - snd_printk("usb_set_interface error \n"); + snd_printk(KERN_ERR "usb_set_interface error \n"); else err = usb_bulk_msg(dev, usb_sndbulkpipe(dev, 2), buf, dsp->length, &lret, 6000); kfree(buf); @@ -235,17 +235,17 @@ static int snd_usX2Y_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp) msleep(250); // give the device some time err = usX2Y_AsyncSeq04_init(priv); if (err) { - snd_printk("usX2Y_AsyncSeq04_init error \n"); + snd_printk(KERN_ERR "usX2Y_AsyncSeq04_init error \n"); return err; } err = usX2Y_In04_init(priv); if (err) { - snd_printk("usX2Y_In04_init error \n"); + snd_printk(KERN_ERR "usX2Y_In04_init error \n"); return err; } err = usX2Y_create_alsa_devices(hw->card); if (err) { - snd_printk("usX2Y_create_alsa_devices error %i \n", err); + snd_printk(KERN_ERR "usX2Y_create_alsa_devices error %i \n", err); snd_card_free(hw->card); return err; } diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index e6e6da1596712633b0383293fd3203a066b37d0b..cf77313c609d9d85dbd69d66dbc9479c620f41f3 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -251,9 +251,8 @@ static void i_usX2Y_In04Int(struct urb* urb, struct pt_regs *regs) } } - if (err) { - snd_printk("In04Int() usb_submit_urb err=%i\n", err); - } + if (err) + snd_printk(KERN_ERR "In04Int() usb_submit_urb err=%i\n", err); urb->dev = usX2Y->chip.dev; usb_submit_urb(urb, GFP_ATOMIC); diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 0f09e0de52dd4cb4a4dc8128217cfe088a95fdfd..affda973cecebc6dc8582c9b04e12ea9a252f7df 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -78,7 +78,7 @@ static int usX2Y_urb_capt_retire(snd_usX2Y_substream_t *subs) for (i = 0; i < nr_of_packs(); i++) { cp = (unsigned char*)urb->transfer_buffer + urb->iso_frame_desc[i].offset; if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */ - snd_printk("activ frame status %i. Most propably some hardware problem.\n", urb->iso_frame_desc[i].status); + snd_printk(KERN_ERR "activ frame status %i. Most propably some hardware problem.\n", urb->iso_frame_desc[i].status); return urb->iso_frame_desc[i].status; } len = urb->iso_frame_desc[i].actual_length / usX2Y->stride; @@ -134,7 +134,7 @@ static int usX2Y_urb_play_prepare(snd_usX2Y_substream_t *subs, counts = cap_urb->iso_frame_desc[pack].actual_length / usX2Y->stride; count += counts; if (counts < 43 || counts > 50) { - snd_printk("should not be here with counts=%i\n", counts); + snd_printk(KERN_ERR "should not be here with counts=%i\n", counts); return -EPIPE; } /* set up descriptor */ @@ -196,7 +196,7 @@ static int usX2Y_urb_submit(snd_usX2Y_substream_t *subs, struct urb *urb, int fr urb->hcpriv = NULL; urb->dev = subs->usX2Y->chip.dev; /* we need to set this at each time */ if ((err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { - snd_printk("usb_submit_urb() returned %i\n", err); + snd_printk(KERN_ERR "usb_submit_urb() returned %i\n", err); return err; } return 0; @@ -283,16 +283,16 @@ static void usX2Y_clients_stop(usX2Ydev_t *usX2Y) static void usX2Y_error_urb_status(usX2Ydev_t *usX2Y, snd_usX2Y_substream_t *subs, struct urb *urb) { - snd_printk("ep=%i stalled with status=%i\n", subs->endpoint, urb->status); + snd_printk(KERN_ERR "ep=%i stalled with status=%i\n", subs->endpoint, urb->status); urb->status = 0; usX2Y_clients_stop(usX2Y); } static void usX2Y_error_sequence(usX2Ydev_t *usX2Y, snd_usX2Y_substream_t *subs, struct urb *urb) { - snd_printk("Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n" - "Most propably some urb of usb-frame %i is still missing.\n" - "Cause could be too long delays in usb-hcd interrupt handling.\n", + snd_printk(KERN_ERR "Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n" + KERN_ERR "Most propably some urb of usb-frame %i is still missing.\n" + KERN_ERR "Cause could be too long delays in usb-hcd interrupt handling.\n", usb_get_current_frame_number(usX2Y->chip.dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", usX2Y->wait_iso_frame, urb->start_frame, usX2Y->wait_iso_frame); usX2Y_clients_stop(usX2Y); @@ -653,9 +653,8 @@ static void i_usX2Y_04Int(struct urb* urb, struct pt_regs *regs) { usX2Ydev_t* usX2Y = urb->context; - if (urb->status) { - snd_printk("snd_usX2Y_04Int() urb->status=%i\n", urb->status); - } + if (urb->status) + snd_printk(KERN_ERR "snd_usX2Y_04Int() urb->status=%i\n", urb->status); if (0 == --usX2Y->US04->len) wake_up(&usX2Y->In04WaitQueue); } @@ -740,7 +739,7 @@ static int usX2Y_format_set(usX2Ydev_t *usX2Y, snd_pcm_format_t format) } usb_kill_urb(usX2Y->In04urb); if ((err = usb_set_interface(usX2Y->chip.dev, 0, alternate))) { - snd_printk("usb_set_interface error \n"); + snd_printk(KERN_ERR "usb_set_interface error \n"); return err; } usX2Y->In04urb->dev = usX2Y->chip.dev; @@ -787,7 +786,7 @@ static int snd_usX2Y_pcm_hw_params(snd_pcm_substream_t *substream, } } if (0 > (err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)))) { - snd_printk("snd_pcm_lib_malloc_pages(%p, %i) returned %i\n", substream, params_buffer_bytes(hw_params), err); + snd_printk(KERN_ERR "snd_pcm_lib_malloc_pages(%p, %i) returned %i\n", substream, params_buffer_bytes(hw_params), err); return err; } return 0; diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index d0199c4e55514dad367e3c51d7b1543180392f40..0dc828ff9e94dea68e8aea8fed84370d37dbd6f8 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -73,7 +73,7 @@ static int usX2Y_usbpcm_urb_capt_retire(snd_usX2Y_substream_t *subs) } for (i = 0; i < nr_of_packs(); i++) { if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */ - snd_printk("activ frame status %i. Most propably some hardware problem.\n", urb->iso_frame_desc[i].status); + snd_printk(KERN_ERR "activ frame status %i. Most propably some hardware problem.\n", urb->iso_frame_desc[i].status); return urb->iso_frame_desc[i].status; } lens += urb->iso_frame_desc[i].actual_length / usX2Y->stride; @@ -126,7 +126,7 @@ static int usX2Y_hwdep_urb_play_prepare(snd_usX2Y_substream_t *subs, /* calculate the size of a packet */ counts = shm->captured_iso[shm->playback_iso_head].length / usX2Y->stride; if (counts < 43 || counts > 50) { - snd_printk("should not be here with counts=%i\n", counts); + snd_printk(KERN_ERR "should not be here with counts=%i\n", counts); return -EPIPE; } /* set up descriptor */