diff --git a/[refs] b/[refs] index 831dda3d91b5..37335832b2ce 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 804ce9866d56130032c9c8afc90a1297b7deed56 +refs/heads/master: 92a8956364233c3b6f930aa00c852c558b70a91e diff --git a/trunk/Documentation/ABI/testing/sysfs-block-rssd b/trunk/Documentation/ABI/testing/sysfs-block-rssd index 679ce3543122..d535757799fe 100644 --- a/trunk/Documentation/ABI/testing/sysfs-block-rssd +++ b/trunk/Documentation/ABI/testing/sysfs-block-rssd @@ -6,21 +6,13 @@ Description: This is a read-only file. Dumps below driver information and hardware registers. - S ACTive - Command Issue + - Allocated - Completed - PORT IRQ STAT - HOST IRQ STAT - - Allocated - - Commands in Q What: /sys/block/rssd*/status Date: April 2012 KernelVersion: 3.4 Contact: Asai Thambi S P -Description: This is a read-only file. Indicates the status of the device. - -What: /sys/block/rssd*/flags -Date: May 2012 -KernelVersion: 3.5 -Contact: Asai Thambi S P -Description: This is a read-only file. Dumps the flags in port and driver - data structure +Description: This is a read-only file. Indicates the status of the device. diff --git a/trunk/Documentation/ABI/testing/sysfs-bus-fcoe b/trunk/Documentation/ABI/testing/sysfs-bus-fcoe deleted file mode 100644 index 469d09c02f6b..000000000000 --- a/trunk/Documentation/ABI/testing/sysfs-bus-fcoe +++ /dev/null @@ -1,77 +0,0 @@ -What: /sys/bus/fcoe/ctlr_X -Date: March 2012 -KernelVersion: TBD -Contact: Robert Love , devel@open-fcoe.org -Description: 'FCoE Controller' instances on the fcoe bus -Attributes: - - fcf_dev_loss_tmo: Device loss timeout peroid (see below). Changing - this value will change the dev_loss_tmo for all - FCFs discovered by this controller. - - lesb_link_fail: Link Error Status Block (LESB) link failure count. - - lesb_vlink_fail: Link Error Status Block (LESB) virtual link - failure count. - - lesb_miss_fka: Link Error Status Block (LESB) missed FCoE - Initialization Protocol (FIP) Keep-Alives (FKA). - - lesb_symb_err: Link Error Status Block (LESB) symbolic error count. - - lesb_err_block: Link Error Status Block (LESB) block error count. - - lesb_fcs_error: Link Error Status Block (LESB) Fibre Channel - Serivces error count. - -Notes: ctlr_X (global increment starting at 0) - -What: /sys/bus/fcoe/fcf_X -Date: March 2012 -KernelVersion: TBD -Contact: Robert Love , devel@open-fcoe.org -Description: 'FCoE FCF' instances on the fcoe bus. A FCF is a Fibre Channel - Forwarder, which is a FCoE switch that can accept FCoE - (Ethernet) packets, unpack them, and forward the embedded - Fibre Channel frames into a FC fabric. It can also take - outbound FC frames and pack them in Ethernet packets to - be sent to their destination on the Ethernet segment. -Attributes: - - fabric_name: Identifies the fabric that the FCF services. - - switch_name: Identifies the FCF. - - priority: The switch's priority amongst other FCFs on the same - fabric. - - selected: 1 indicates that the switch has been selected for use; - 0 indicates that the swich will not be used. - - fc_map: The Fibre Channel MAP - - vfid: The Virtual Fabric ID - - mac: The FCF's MAC address - - fka_peroid: The FIP Keep-Alive peroid - - fabric_state: The internal kernel state - "Unknown" - Initialization value - "Disconnected" - No link to the FCF/fabric - "Connected" - Host is connected to the FCF - "Deleted" - FCF is being removed from the system - - dev_loss_tmo: The device loss timeout peroid for this FCF. - -Notes: A device loss infrastructre similar to the FC Transport's - is present in fcoe_sysfs. It is nice to have so that a - link flapping adapter doesn't continually advance the count - used to identify the discovered FCF. FCFs will exist in a - "Disconnected" state until either the timer expires and the - FCF becomes "Deleted" or the FCF is rediscovered and becomes - "Connected." - - -Users: The first user of this interface will be the fcoeadm application, - which is commonly packaged in the fcoe-utils package. diff --git a/trunk/Documentation/ABI/testing/sysfs-bus-rbd b/trunk/Documentation/ABI/testing/sysfs-bus-rbd index bcd88eb7ebcd..dbedafb095e2 100644 --- a/trunk/Documentation/ABI/testing/sysfs-bus-rbd +++ b/trunk/Documentation/ABI/testing/sysfs-bus-rbd @@ -65,11 +65,11 @@ snap_* Entries under /sys/bus/rbd/devices//snap_ ------------------------------------------------------------- -snap_id +id The rados internal snapshot id assigned for this snapshot -snap_size +size The size of the image when this snapshot was taken. diff --git a/trunk/Documentation/ABI/testing/sysfs-class-mtd b/trunk/Documentation/ABI/testing/sysfs-class-mtd index db1ad7e34fc3..4d55a1888981 100644 --- a/trunk/Documentation/ABI/testing/sysfs-class-mtd +++ b/trunk/Documentation/ABI/testing/sysfs-class-mtd @@ -123,54 +123,3 @@ Description: half page, or a quarter page). In the case of ECC NOR, it is the ECC block size. - -What: /sys/class/mtd/mtdX/ecc_strength -Date: April 2012 -KernelVersion: 3.4 -Contact: linux-mtd@lists.infradead.org -Description: - Maximum number of bit errors that the device is capable of - correcting within each region covering an ecc step. This will - always be a non-negative integer. Note that some devices will - have multiple ecc steps within each writesize region. - - In the case of devices lacking any ECC capability, it is 0. - -What: /sys/class/mtd/mtdX/bitflip_threshold -Date: April 2012 -KernelVersion: 3.4 -Contact: linux-mtd@lists.infradead.org -Description: - This allows the user to examine and adjust the criteria by which - mtd returns -EUCLEAN from mtd_read(). If the maximum number of - bit errors that were corrected on any single region comprising - an ecc step (as reported by the driver) equals or exceeds this - value, -EUCLEAN is returned. Otherwise, absent an error, 0 is - returned. Higher layers (e.g., UBI) use this return code as an - indication that an erase block may be degrading and should be - scrutinized as a candidate for being marked as bad. - - The initial value may be specified by the flash device driver. - If not, then the default value is ecc_strength. - - The introduction of this feature brings a subtle change to the - meaning of the -EUCLEAN return code. Previously, it was - interpreted to mean simply "one or more bit errors were - corrected". Its new interpretation can be phrased as "a - dangerously high number of bit errors were corrected on one or - more regions comprising an ecc step". The precise definition of - "dangerously high" can be adjusted by the user with - bitflip_threshold. Users are discouraged from doing this, - however, unless they know what they are doing and have intimate - knowledge of the properties of their device. Broadly speaking, - bitflip_threshold should be low enough to detect genuine erase - block degradation, but high enough to avoid the consequences of - a persistent return value of -EUCLEAN on devices where sticky - bitflips occur. Note that if bitflip_threshold exceeds - ecc_strength, -EUCLEAN is never returned by mtd_read(). - Conversely, if bitflip_threshold is zero, -EUCLEAN is always - returned, absent a hard error. - - This is generally applicable only to NAND flash devices with ECC - capability. It is ignored on devices lacking ECC capability; - i.e., devices for which ecc_strength is zero. diff --git a/trunk/Documentation/DocBook/mtdnand.tmpl b/trunk/Documentation/DocBook/mtdnand.tmpl index e0aedb7a7827..0c674be0d3c6 100644 --- a/trunk/Documentation/DocBook/mtdnand.tmpl +++ b/trunk/Documentation/DocBook/mtdnand.tmpl @@ -1119,6 +1119,8 @@ in this page These constants are defined in nand.h. They are ored together to describe the chip functionality. +/* Chip can not auto increment pages */ +#define NAND_NO_AUTOINCR 0x00000001 /* Buswitdh is 16 bit */ #define NAND_BUSWIDTH_16 0x00000002 /* Device supports partial programming without padding */ diff --git a/trunk/Documentation/arm/OMAP/DSS b/trunk/Documentation/arm/OMAP/DSS index a564ceea9e98..888ae7b83ae4 100644 --- a/trunk/Documentation/arm/OMAP/DSS +++ b/trunk/Documentation/arm/OMAP/DSS @@ -47,51 +47,6 @@ flexible way to enable non-common multi-display configuration. In addition to modelling the hardware overlays, omapdss supports virtual overlays and overlay managers. These can be used when updating a display with CPU or system DMA. -omapdss driver support for audio --------------------------------- -There exist several display technologies and standards that support audio as -well. Hence, it is relevant to update the DSS device driver to provide an audio -interface that may be used by an audio driver or any other driver interested in -the functionality. - -The audio_enable function is intended to prepare the relevant -IP for playback (e.g., enabling an audio FIFO, taking in/out of reset -some IP, enabling companion chips, etc). It is intended to be called before -audio_start. The audio_disable function performs the reverse operation and is -intended to be called after audio_stop. - -While a given DSS device driver may support audio, it is possible that for -certain configurations audio is not supported (e.g., an HDMI display using a -VESA video timing). The audio_supported function is intended to query whether -the current configuration of the display supports audio. - -The audio_config function is intended to configure all the relevant audio -parameters of the display. In order to make the function independent of any -specific DSS device driver, a struct omap_dss_audio is defined. Its purpose -is to contain all the required parameters for audio configuration. At the -moment, such structure contains pointers to IEC-60958 channel status word -and CEA-861 audio infoframe structures. This should be enough to support -HDMI and DisplayPort, as both are based on CEA-861 and IEC-60958. - -The audio_enable/disable, audio_config and audio_supported functions could be -implemented as functions that may sleep. Hence, they should not be called -while holding a spinlock or a readlock. - -The audio_start/audio_stop function is intended to effectively start/stop audio -playback after the configuration has taken place. These functions are designed -to be used in an atomic context. Hence, audio_start should return quickly and be -called only after all the needed resources for audio playback (audio FIFOs, -DMA channels, companion chips, etc) have been enabled to begin data transfers. -audio_stop is designed to only stop the audio transfers. The resources used -for playback are released using audio_disable. - -The enum omap_dss_audio_state may be used to help the implementations of -the interface to keep track of the audio state. The initial state is _DISABLED; -then, the state transitions to _CONFIGURED, and then, when it is ready to -play audio, to _ENABLED. The state _PLAYING is used when the audio is being -rendered. - - Panel and controller drivers ---------------------------- @@ -201,7 +156,6 @@ timings Display timings (pixclock,xres/hfp/hbp/hsw,yres/vfp/vbp/vsw) "pal" and "ntsc" panel_name tear_elim Tearing elimination 0=off, 1=on -output_type Output type (video encoder only): "composite" or "svideo" There are also some debugfs files at /omapdss/ which show information about clocks and registers. diff --git a/trunk/Documentation/devicetree/bindings/gpio/gpio-mm-lantiq.txt b/trunk/Documentation/devicetree/bindings/gpio/gpio-mm-lantiq.txt deleted file mode 100644 index f93d51478d5a..000000000000 --- a/trunk/Documentation/devicetree/bindings/gpio/gpio-mm-lantiq.txt +++ /dev/null @@ -1,38 +0,0 @@ -Lantiq SoC External Bus memory mapped GPIO controller - -By attaching hardware latches to the EBU it is possible to create output -only gpios. This driver configures a special memory address, which when -written to outputs 16 bit to the latches. - -The node describing the memory mapped GPIOs needs to be a child of the node -describing the "lantiq,localbus". - -Required properties: -- compatible : Should be "lantiq,gpio-mm-lantiq" -- reg : Address and length of the register set for the device -- #gpio-cells : Should be two. The first cell is the pin number and - the second cell is used to specify optional parameters (currently - unused). -- gpio-controller : Marks the device node as a gpio controller. - -Optional properties: -- lantiq,shadow : The default value that we shall assume as already set on the - shift register cascade. - -Example: - -localbus@0 { - #address-cells = <2>; - #size-cells = <1>; - ranges = <0 0 0x0 0x3ffffff /* addrsel0 */ - 1 0 0x4000000 0x4000010>; /* addsel1 */ - compatible = "lantiq,localbus", "simple-bus"; - - gpio_mm0: gpio@4000000 { - compatible = "lantiq,gpio-mm"; - reg = <1 0x0 0x10>; - gpio-controller; - #gpio-cells = <2>; - lantiq,shadow = <0x77f> - }; -} diff --git a/trunk/Documentation/devicetree/bindings/gpio/gpio-stp-xway.txt b/trunk/Documentation/devicetree/bindings/gpio/gpio-stp-xway.txt deleted file mode 100644 index 854de130a971..000000000000 --- a/trunk/Documentation/devicetree/bindings/gpio/gpio-stp-xway.txt +++ /dev/null @@ -1,42 +0,0 @@ -Lantiq SoC Serial To Parallel (STP) GPIO controller - -The Serial To Parallel (STP) is found on MIPS based Lantiq socs. It is a -peripheral controller used to drive external shift register cascades. At most -3 groups of 8 bits can be driven. The hardware is able to allow the DSL modem -to drive the 2 LSBs of the cascade automatically. - - -Required properties: -- compatible : Should be "lantiq,gpio-stp-xway" -- reg : Address and length of the register set for the device -- #gpio-cells : Should be two. The first cell is the pin number and - the second cell is used to specify optional parameters (currently - unused). -- gpio-controller : Marks the device node as a gpio controller. - -Optional properties: -- lantiq,shadow : The default value that we shall assume as already set on the - shift register cascade. -- lantiq,groups : Set the 3 bit mask to select which of the 3 groups are enabled - in the shift register cascade. -- lantiq,dsl : The dsl core can control the 2 LSBs of the gpio cascade. This 2 bit - property can enable this feature. -- lantiq,phy1 : The gphy1 core can control 3 bits of the gpio cascade. -- lantiq,phy2 : The gphy2 core can control 3 bits of the gpio cascade. -- lantiq,rising : use rising instead of falling edge for the shift register - -Example: - -gpio1: stp@E100BB0 { - compatible = "lantiq,gpio-stp-xway"; - reg = <0xE100BB0 0x40>; - #gpio-cells = <2>; - gpio-controller; - - lantiq,shadow = <0xffff>; - lantiq,groups = <0x7>; - lantiq,dsl = <0x3>; - lantiq,phy1 = <0x7>; - lantiq,phy2 = <0x7>; - /* lantiq,rising; */ -}; diff --git a/trunk/Documentation/devicetree/bindings/iommu/nvidia,tegra20-gart.txt b/trunk/Documentation/devicetree/bindings/iommu/nvidia,tegra20-gart.txt deleted file mode 100644 index 099d9362ebc1..000000000000 --- a/trunk/Documentation/devicetree/bindings/iommu/nvidia,tegra20-gart.txt +++ /dev/null @@ -1,14 +0,0 @@ -NVIDIA Tegra 20 GART - -Required properties: -- compatible: "nvidia,tegra20-gart" -- reg: Two pairs of cells specifying the physical address and size of - the memory controller registers and the GART aperture respectively. - -Example: - - gart { - compatible = "nvidia,tegra20-gart"; - reg = <0x7000f024 0x00000018 /* controller registers */ - 0x58000000 0x02000000>; /* GART aperture */ - }; diff --git a/trunk/Documentation/devicetree/bindings/mtd/gpmi-nand.txt b/trunk/Documentation/devicetree/bindings/mtd/gpmi-nand.txt deleted file mode 100644 index 1a5bbd346d22..000000000000 --- a/trunk/Documentation/devicetree/bindings/mtd/gpmi-nand.txt +++ /dev/null @@ -1,33 +0,0 @@ -* Freescale General-Purpose Media Interface (GPMI) - -The GPMI nand controller provides an interface to control the -NAND flash chips. We support only one NAND chip now. - -Required properties: - - compatible : should be "fsl,-gpmi-nand" - - reg : should contain registers location and length for gpmi and bch. - - reg-names: Should contain the reg names "gpmi-nand" and "bch" - - interrupts : The first is the DMA interrupt number for GPMI. - The second is the BCH interrupt number. - - interrupt-names : The interrupt names "gpmi-dma", "bch"; - - fsl,gpmi-dma-channel : Should contain the dma channel it uses. - -The device tree may optionally contain sub-nodes describing partitions of the -address space. See partition.txt for more detail. - -Examples: - -gpmi-nand@8000c000 { - compatible = "fsl,imx28-gpmi-nand"; - #address-cells = <1>; - #size-cells = <1>; - reg = <0x8000c000 2000>, <0x8000a000 2000>; - reg-names = "gpmi-nand", "bch"; - interrupts = <88>, <41>; - interrupt-names = "gpmi-dma", "bch"; - fsl,gpmi-dma-channel = <4>; - - partition@0 { - ... - }; -}; diff --git a/trunk/Documentation/devicetree/bindings/mtd/mxc-nand.txt b/trunk/Documentation/devicetree/bindings/mtd/mxc-nand.txt deleted file mode 100644 index b5833d11c7be..000000000000 --- a/trunk/Documentation/devicetree/bindings/mtd/mxc-nand.txt +++ /dev/null @@ -1,19 +0,0 @@ -* Freescale's mxc_nand - -Required properties: -- compatible: "fsl,imxXX-nand" -- reg: address range of the nfc block -- interrupts: irq to be used -- nand-bus-width: see nand.txt -- nand-ecc-mode: see nand.txt -- nand-on-flash-bbt: see nand.txt - -Example: - - nand@d8000000 { - compatible = "fsl,imx27-nand"; - reg = <0xd8000000 0x1000>; - interrupts = <29>; - nand-bus-width = <8>; - nand-ecc-mode = "hw"; - }; diff --git a/trunk/Documentation/feature-removal-schedule.txt b/trunk/Documentation/feature-removal-schedule.txt index 56000b33340b..ebaffe208ccb 100644 --- a/trunk/Documentation/feature-removal-schedule.txt +++ b/trunk/Documentation/feature-removal-schedule.txt @@ -606,9 +606,3 @@ Why: There are two mci drivers: at91-mci and atmel-mci. The PDC support Who: Ludovic Desroches ---------------------------- - -What: net/wanrouter/ -When: June 2013 -Why: Unsupported/unmaintained/unused since 2.6 - ----------------------------- diff --git a/trunk/Documentation/filesystems/Locking b/trunk/Documentation/filesystems/Locking index 8e2da1e06e3b..d449e632e6a0 100644 --- a/trunk/Documentation/filesystems/Locking +++ b/trunk/Documentation/filesystems/Locking @@ -61,7 +61,6 @@ ata *); ssize_t (*listxattr) (struct dentry *, char *, size_t); int (*removexattr) (struct dentry *, const char *); int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len); - void (*update_time)(struct inode *, struct timespec *, int); locking rules: all may block @@ -88,8 +87,6 @@ getxattr: no listxattr: no removexattr: yes fiemap: no -update_time: no - Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on victim. cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem. diff --git a/trunk/Documentation/filesystems/vfs.txt b/trunk/Documentation/filesystems/vfs.txt index efd23f481704..ef19f91a0f12 100644 --- a/trunk/Documentation/filesystems/vfs.txt +++ b/trunk/Documentation/filesystems/vfs.txt @@ -363,7 +363,6 @@ struct inode_operations { ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); ssize_t (*listxattr) (struct dentry *, char *, size_t); int (*removexattr) (struct dentry *, const char *); - void (*update_time)(struct inode *, struct timespec *, int); }; Again, all methods are called without any locks being held, unless @@ -472,9 +471,6 @@ otherwise noted. removexattr: called by the VFS to remove an extended attribute from a file. This method is called by removexattr(2) system call. - update_time: called by the VFS to update a specific time or the i_version of - an inode. If this is not defined the VFS will update the inode itself - and call mark_inode_dirty_sync. The Address Space Object ======================== diff --git a/trunk/Documentation/i2c/functionality b/trunk/Documentation/i2c/functionality index b0ff2ab596ce..42c17c1fb3cd 100644 --- a/trunk/Documentation/i2c/functionality +++ b/trunk/Documentation/i2c/functionality @@ -18,9 +18,9 @@ For the most up-to-date list of functionality constants, please check adapters typically can not do these) I2C_FUNC_10BIT_ADDR Handles the 10-bit address extensions I2C_FUNC_PROTOCOL_MANGLING Knows about the I2C_M_IGNORE_NAK, - I2C_M_REV_DIR_ADDR and I2C_M_NO_RD_ACK - flags (which modify the I2C protocol!) - I2C_FUNC_NOSTART Can skip repeated start sequence + I2C_M_REV_DIR_ADDR, I2C_M_NOSTART and + I2C_M_NO_RD_ACK flags (which modify the + I2C protocol!) I2C_FUNC_SMBUS_QUICK Handles the SMBus write_quick command I2C_FUNC_SMBUS_READ_BYTE Handles the SMBus read_byte command I2C_FUNC_SMBUS_WRITE_BYTE Handles the SMBus write_byte command @@ -50,9 +50,6 @@ A few combinations of the above flags are also defined for your convenience: emulated by a real I2C adapter (using the transparent emulation layer) -In kernel versions prior to 3.5 I2C_FUNC_NOSTART was implemented as -part of I2C_FUNC_PROTOCOL_MANGLING. - ADAPTER IMPLEMENTATION ---------------------- diff --git a/trunk/Documentation/i2c/i2c-protocol b/trunk/Documentation/i2c/i2c-protocol index 0b3e62d1f77a..10518dd58814 100644 --- a/trunk/Documentation/i2c/i2c-protocol +++ b/trunk/Documentation/i2c/i2c-protocol @@ -49,9 +49,7 @@ a byte read, followed by a byte write: Modified transactions ===================== -The following modifications to the I2C protocol can also be generated, -with the exception of I2C_M_NOSTART these are usually only needed to -work around device issues: +We have found some I2C devices that needs the following modifications: Flag I2C_M_NOSTART: In a combined transaction, no 'S Addr Wr/Rd [A]' is generated at some @@ -62,11 +60,6 @@ work around device issues: we do not generate Addr, but we do generate the startbit S. This will probably confuse all other clients on your bus, so don't try this. - This is often used to gather transmits from multiple data buffers in - system memory into something that appears as a single transfer to the - I2C device but may also be used between direction changes by some - rare devices. - Flags I2C_M_REV_DIR_ADDR This toggles the Rd/Wr flag. That is, if you want to do a write, but need to emit an Rd instead of a Wr, or vice versa, you set this diff --git a/trunk/Documentation/kernel-parameters.txt b/trunk/Documentation/kernel-parameters.txt index c45513d806ab..b40b413db88e 100644 --- a/trunk/Documentation/kernel-parameters.txt +++ b/trunk/Documentation/kernel-parameters.txt @@ -335,12 +335,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted. requirements as needed. This option does not override iommu=pt - amd_iommu_dump= [HW,X86-64] - Enable AMD IOMMU driver option to dump the ACPI table - for AMD IOMMU. With this option enabled, AMD IOMMU - driver will print ACPI tables for AMD IOMMU during - IOMMU initialization. - amijoy.map= [HW,JOY] Amiga joystick support Map of devices attached to JOY0DAT and JOY1DAT Format: , diff --git a/trunk/Documentation/power/charger-manager.txt b/trunk/Documentation/power/charger-manager.txt index b4f7f4b23f64..fdcca991df30 100644 --- a/trunk/Documentation/power/charger-manager.txt +++ b/trunk/Documentation/power/charger-manager.txt @@ -44,16 +44,6 @@ Charger Manager supports the following: Normally, the platform will need to resume and suspend some devices that are used by Charger Manager. -* Support for premature full-battery event handling - If the battery voltage drops by "fullbatt_vchkdrop_uV" after - "fullbatt_vchkdrop_ms" from the full-battery event, the framework - restarts charging. This check is also performed while suspended by - setting wakeup time accordingly and using suspend_again. - -* Support for uevent-notify - With the charger-related events, the device sends - notification to users with UEVENT. - 2. Global Charger-Manager Data related with suspend_again ======================================================== In order to setup Charger Manager with suspend-again feature @@ -65,7 +55,7 @@ if there are multiple batteries. If there are multiple batteries, the multiple instances of Charger Manager share the same charger_global_desc and it will manage in-suspend monitoring for all instances of Charger Manager. -The user needs to provide all the three entries properly in order to activate +The user needs to provide all the two entries properly in order to activate in-suspend monitoring: struct charger_global_desc { @@ -84,11 +74,6 @@ bool (*rtc_only_wakeup)(void); same struct. If there is any other wakeup source triggered the wakeup, it should return false. If the "rtc" is the only wakeup reason, it should return true. - -bool assume_timer_stops_in_suspend; - : if true, Charger Manager assumes that - the timer (CM uses jiffies as timer) stops during suspend. Then, CM - assumes that the suspend-duration is same as the alarm length. }; 3. How to setup suspend_again @@ -126,16 +111,6 @@ enum polling_modes polling_mode; CM_POLL_CHARGING_ONLY: poll this battery if and only if the battery is being charged. -unsigned int fullbatt_vchkdrop_ms; -unsigned int fullbatt_vchkdrop_uV; - : If both have non-zero values, Charger Manager will check the - battery voltage drop fullbatt_vchkdrop_ms after the battery is fully - charged. If the voltage drop is over fullbatt_vchkdrop_uV, Charger - Manager will try to recharge the battery by disabling and enabling - chargers. Recharge with voltage drop condition only (without delay - condition) is needed to be implemented with hardware interrupts from - fuel gauges or charger devices/chips. - unsigned int fullbatt_uV; : If specified with a non-zero value, Charger Manager assumes that the battery is full (capacity = 100) if the battery is not being @@ -147,8 +122,6 @@ unsigned int polling_interval_ms; this battery every polling_interval_ms or more frequently. enum data_source battery_present; - : CM_BATTERY_PRESENT: assume that the battery exists. - CM_NO_BATTERY: assume that the battery does not exists. CM_FUEL_GAUGE: get battery presence information from fuel gauge. CM_CHARGER_STAT: get battery presence from chargers. @@ -178,17 +151,7 @@ bool measure_battery_temp; the value of measure_battery_temp. }; -5. Notify Charger-Manager of charger events: cm_notify_event() -========================================================= -If there is an charger event is required to notify -Charger Manager, a charger device driver that triggers the event can call -cm_notify_event(psy, type, msg) to notify the corresponding Charger Manager. -In the function, psy is the charger driver's power_supply pointer, which is -associated with Charger-Manager. The parameter "type" -is the same as irq's type (enum cm_event_types). The event message "msg" is -optional and is effective only if the event type is "UNDESCRIBED" or "OTHERS". - -6. Other Considerations +5. Other Considerations ======================= At the charger/battery-related events such as battery-pulled-out, diff --git a/trunk/Documentation/power/power_supply_class.txt b/trunk/Documentation/power/power_supply_class.txt index 211831d4095f..9f16c5178b66 100644 --- a/trunk/Documentation/power/power_supply_class.txt +++ b/trunk/Documentation/power/power_supply_class.txt @@ -84,8 +84,6 @@ are already charged or discharging, 'n/a' can be displayed (or HEALTH - represents health of the battery, values corresponds to POWER_SUPPLY_HEALTH_*, defined in battery.h. -VOLTAGE_OCV - open circuit voltage of the battery. - VOLTAGE_MAX_DESIGN, VOLTAGE_MIN_DESIGN - design values for maximal and minimal power supply voltages. Maximal/minimal means values of voltages when battery considered "full"/"empty" at normal conditions. Yes, there is diff --git a/trunk/Documentation/vm/slub.txt b/trunk/Documentation/vm/slub.txt index b0c6d1bbb434..6752870c4970 100644 --- a/trunk/Documentation/vm/slub.txt +++ b/trunk/Documentation/vm/slub.txt @@ -17,7 +17,7 @@ data and perform operation on the slabs. By default slabinfo only lists slabs that have data in them. See "slabinfo -h" for more options when running the command. slabinfo can be compiled with -gcc -o slabinfo tools/vm/slabinfo.c +gcc -o slabinfo tools/slub/slabinfo.c Some of the modes of operation of slabinfo require that slub debugging be enabled on the command line. F.e. no tracking information will be diff --git a/trunk/Documentation/watchdog/watchdog-kernel-api.txt b/trunk/Documentation/watchdog/watchdog-kernel-api.txt index 086638f6c82d..25fe4304f2fc 100644 --- a/trunk/Documentation/watchdog/watchdog-kernel-api.txt +++ b/trunk/Documentation/watchdog/watchdog-kernel-api.txt @@ -1,6 +1,6 @@ The Linux WatchDog Timer Driver Core kernel API. =============================================== -Last reviewed: 22-May-2012 +Last reviewed: 16-Mar-2012 Wim Van Sebroeck @@ -39,10 +39,6 @@ watchdog_device structure. The watchdog device structure looks like this: struct watchdog_device { - int id; - struct cdev cdev; - struct device *dev; - struct device *parent; const struct watchdog_info *info; const struct watchdog_ops *ops; unsigned int bootstatus; @@ -50,20 +46,10 @@ struct watchdog_device { unsigned int min_timeout; unsigned int max_timeout; void *driver_data; - struct mutex lock; unsigned long status; }; It contains following fields: -* id: set by watchdog_register_device, id 0 is special. It has both a - /dev/watchdog0 cdev (dynamic major, minor 0) as well as the old - /dev/watchdog miscdev. The id is set automatically when calling - watchdog_register_device. -* cdev: cdev for the dynamic /dev/watchdog device nodes. This - field is also populated by watchdog_register_device. -* dev: device under the watchdog class (created by watchdog_register_device). -* parent: set this to the parent device (or NULL) before calling - watchdog_register_device. * info: a pointer to a watchdog_info structure. This structure gives some additional information about the watchdog timer itself. (Like it's unique name) * ops: a pointer to the list of watchdog operations that the watchdog supports. @@ -75,7 +61,6 @@ It contains following fields: * driver_data: a pointer to the drivers private data of a watchdog device. This data should only be accessed via the watchdog_set_drvdata and watchdog_get_drvdata routines. -* lock: Mutex for WatchDog Timer Driver Core internal use only. * status: this field contains a number of status bits that give extra information about the status of the device (Like: is the watchdog timer running/active, is the nowayout bit set, is the device opened via @@ -93,8 +78,6 @@ struct watchdog_ops { unsigned int (*status)(struct watchdog_device *); int (*set_timeout)(struct watchdog_device *, unsigned int); unsigned int (*get_timeleft)(struct watchdog_device *); - void (*ref)(struct watchdog_device *); - void (*unref)(struct watchdog_device *); long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long); }; @@ -102,21 +85,6 @@ It is important that you first define the module owner of the watchdog timer driver's operations. This module owner will be used to lock the module when the watchdog is active. (This to avoid a system crash when you unload the module and /dev/watchdog is still open). - -If the watchdog_device struct is dynamically allocated, just locking the module -is not enough and a driver also needs to define the ref and unref operations to -ensure the structure holding the watchdog_device does not go away. - -The simplest (and usually sufficient) implementation of this is to: -1) Add a kref struct to the same structure which is holding the watchdog_device -2) Define a release callback for the kref which frees the struct holding both -3) Call kref_init on this kref *before* calling watchdog_register_device() -4) Define a ref operation calling kref_get on this kref -5) Define a unref operation calling kref_put on this kref -6) When it is time to cleanup: - * Do not kfree() the struct holding both, the last kref_put will do this! - * *After* calling watchdog_unregister_device() call kref_put on the kref - Some operations are mandatory and some are optional. The mandatory operations are: * start: this is a pointer to the routine that starts the watchdog timer @@ -157,10 +125,6 @@ they are supported. These optional routines/operations are: (Note: the WDIOF_SETTIMEOUT needs to be set in the options field of the watchdog's info structure). * get_timeleft: this routines returns the time that's left before a reset. -* ref: the operation that calls kref_get on the kref of a dynamically - allocated watchdog_device struct. -* unref: the operation that calls kref_put on the kref of a dynamically - allocated watchdog_device struct. * ioctl: if this routine is present then it will be called first before we do our own internal ioctl call handling. This routine should return -ENOIOCTLCMD if a command is not supported. The parameters that are passed to the ioctl @@ -180,11 +144,6 @@ bit-operations. The status bits that are defined are: (This bit should only be used by the WatchDog Timer Driver Core). * WDOG_NO_WAY_OUT: this bit stores the nowayout setting for the watchdog. If this bit is set then the watchdog timer will not be able to stop. -* WDOG_UNREGISTERED: this bit gets set by the WatchDog Timer Driver Core - after calling watchdog_unregister_device, and then checked before calling - any watchdog_ops, so that you can be sure that no operations (other then - unref) will get called after unregister, even if userspace still holds a - reference to /dev/watchdog To set the WDOG_NO_WAY_OUT status bit (before registering your watchdog timer device) you can either: diff --git a/trunk/Documentation/watchdog/watchdog-parameters.txt b/trunk/Documentation/watchdog/watchdog-parameters.txt index 04fddbacdbde..17ddd822b456 100644 --- a/trunk/Documentation/watchdog/watchdog-parameters.txt +++ b/trunk/Documentation/watchdog/watchdog-parameters.txt @@ -78,11 +78,6 @@ wd0_timeout: Default watchdog0 timeout in 1/10secs wd1_timeout: Default watchdog1 timeout in 1/10secs wd2_timeout: Default watchdog2 timeout in 1/10secs ------------------------------------------------- -da9052wdt: -timeout: Watchdog timeout in seconds. 2<= timeout <=131, default=2.048s -nowayout: Watchdog cannot be stopped once started - (default=kernel config parameter) -------------------------------------------------- davinci_wdt: heartbeat: Watchdog heartbeat period in seconds from 1 to 600, default 60 ------------------------------------------------- diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 55f0fda602ec..a246490c95eb 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -2818,12 +2818,6 @@ F: Documentation/firmware_class/ F: drivers/base/firmware*.c F: include/linux/firmware.h -FLOPPY DRIVER -M: Jiri Kosina -T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/floppy.git -S: Odd fixes -F: drivers/block/floppy.c - FPU EMULATOR M: Bill Metzenthen W: http://floatingpoint.sourceforge.net/emulator/index.html @@ -5337,7 +5331,7 @@ M: David Woodhouse T: git git://git.infradead.org/battery-2.6.git S: Maintained F: include/linux/power_supply.h -F: drivers/power/ +F: drivers/power/power_supply* PNP SUPPORT M: Adam Belay @@ -6657,7 +6651,7 @@ F: include/linux/taskstats* F: kernel/taskstats.c TC CLASSIFIER -M: Jamal Hadi Salim +M: Jamal Hadi Salim L: netdev@vger.kernel.org S: Maintained F: include/linux/pkt_cls.h diff --git a/trunk/arch/alpha/include/asm/posix_types.h b/trunk/arch/alpha/include/asm/posix_types.h index 5a8a48320efe..24779fc95994 100644 --- a/trunk/arch/alpha/include/asm/posix_types.h +++ b/trunk/arch/alpha/include/asm/posix_types.h @@ -10,6 +10,9 @@ typedef unsigned int __kernel_ino_t; #define __kernel_ino_t __kernel_ino_t +typedef unsigned int __kernel_nlink_t; +#define __kernel_nlink_t __kernel_nlink_t + typedef unsigned long __kernel_sigset_t; /* at least 32 bits */ #include diff --git a/trunk/arch/alpha/kernel/signal.c b/trunk/arch/alpha/kernel/signal.c index a8c97d42ec8e..10ab2d74ecbb 100644 --- a/trunk/arch/alpha/kernel/signal.c +++ b/trunk/arch/alpha/kernel/signal.c @@ -226,6 +226,7 @@ do_sigreturn(struct sigcontext __user *sc, struct pt_regs *regs, if (__get_user(set.sig[0], &sc->sc_mask)) goto give_sigsegv; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(sc, regs, sw)) @@ -260,6 +261,7 @@ do_rt_sigreturn(struct rt_sigframe __user *frame, struct pt_regs *regs, if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto give_sigsegv; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(&frame->uc.uc_mcontext, regs, sw)) @@ -466,9 +468,12 @@ static inline void handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, struct pt_regs * regs, struct switch_stack *sw) { - sigset_t *oldset = sigmask_to_save(); + sigset_t *oldset = ¤t->blocked; int ret; + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + if (ka->sa.sa_flags & SA_SIGINFO) ret = setup_rt_frame(sig, ka, info, oldset, regs, sw); else @@ -478,7 +483,12 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, force_sigsegv(sig, current); return; } - signal_delivered(sig, info, ka, regs, 0); + block_sigmask(ka, sig); + /* A signal was successfully delivered, and the + saved sigmask was stored on the signal frame, + and will be restored by sigreturn. So we can + simply clear the restore sigmask flag. */ + clear_thread_flag(TIF_RESTORE_SIGMASK); } static inline void @@ -562,7 +572,9 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw, } /* If there's no signal to deliver, we just restore the saved mask. */ - restore_saved_sigmask(); + if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK)) + set_current_blocked(¤t->saved_sigmask); + if (single_stepping) ptrace_set_bpt(current); /* re-set breakpoint */ } @@ -578,5 +590,7 @@ do_notify_resume(struct pt_regs *regs, struct switch_stack *sw, if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/trunk/arch/arm/Kconfig b/trunk/arch/arm/Kconfig index b649c5904a4f..5e7601301b41 100644 --- a/trunk/arch/arm/Kconfig +++ b/trunk/arch/arm/Kconfig @@ -525,7 +525,7 @@ config ARCH_IXP4XX select ARCH_HAS_DMA_SET_COHERENT_MASK select CLKSRC_MMIO select CPU_XSCALE - select ARCH_REQUIRE_GPIOLIB + select GENERIC_GPIO select GENERIC_CLOCKEVENTS select MIGHT_HAVE_PCI select NEED_MACH_IO_H diff --git a/trunk/arch/arm/boot/dts/db8500.dtsi b/trunk/arch/arm/boot/dts/db8500.dtsi index 4ad5160018cb..881bc3987844 100644 --- a/trunk/arch/arm/boot/dts/db8500.dtsi +++ b/trunk/arch/arm/boot/dts/db8500.dtsi @@ -58,8 +58,6 @@ "st,nomadik-gpio"; reg = <0x8012e000 0x80>; interrupts = <0 119 0x4>; - interrupt-controller; - #interrupt-cells = <2>; supports-sleepmode; gpio-controller; #gpio-cells = <2>; @@ -71,8 +69,6 @@ "st,nomadik-gpio"; reg = <0x8012e080 0x80>; interrupts = <0 120 0x4>; - interrupt-controller; - #interrupt-cells = <2>; supports-sleepmode; gpio-controller; #gpio-cells = <2>; @@ -84,8 +80,6 @@ "st,nomadik-gpio"; reg = <0x8000e000 0x80>; interrupts = <0 121 0x4>; - interrupt-controller; - #interrupt-cells = <2>; supports-sleepmode; gpio-controller; #gpio-cells = <2>; @@ -97,8 +91,6 @@ "st,nomadik-gpio"; reg = <0x8000e080 0x80>; interrupts = <0 122 0x4>; - interrupt-controller; - #interrupt-cells = <2>; supports-sleepmode; gpio-controller; #gpio-cells = <2>; @@ -110,8 +102,6 @@ "st,nomadik-gpio"; reg = <0x8000e100 0x80>; interrupts = <0 123 0x4>; - interrupt-controller; - #interrupt-cells = <2>; supports-sleepmode; gpio-controller; #gpio-cells = <2>; @@ -123,8 +113,6 @@ "st,nomadik-gpio"; reg = <0x8000e180 0x80>; interrupts = <0 124 0x4>; - interrupt-controller; - #interrupt-cells = <2>; supports-sleepmode; gpio-controller; #gpio-cells = <2>; @@ -136,8 +124,6 @@ "st,nomadik-gpio"; reg = <0x8011e000 0x80>; interrupts = <0 125 0x4>; - interrupt-controller; - #interrupt-cells = <2>; supports-sleepmode; gpio-controller; #gpio-cells = <2>; @@ -149,8 +135,6 @@ "st,nomadik-gpio"; reg = <0x8011e080 0x80>; interrupts = <0 126 0x4>; - interrupt-controller; - #interrupt-cells = <2>; supports-sleepmode; gpio-controller; #gpio-cells = <2>; @@ -162,18 +146,12 @@ "st,nomadik-gpio"; reg = <0xa03fe000 0x80>; interrupts = <0 127 0x4>; - interrupt-controller; - #interrupt-cells = <2>; supports-sleepmode; gpio-controller; #gpio-cells = <2>; gpio-bank = <8>; }; - pinctrl { - compatible = "stericsson,nmk_pinctrl"; - }; - usb@a03e0000 { compatible = "stericsson,db8500-musb", "mentor,musb"; @@ -191,195 +169,20 @@ prcmu@80157000 { compatible = "stericsson,db8500-prcmu"; reg = <0x80157000 0x1000>; - interrupts = <0 47 0x4>; + interrupts = <46 47>; #address-cells = <1>; #size-cells = <1>; ranges; - prcmu-timer-4@80157450 { + prcmu-timer-4@80157450 { compatible = "stericsson,db8500-prcmu-timer-4"; reg = <0x80157450 0xC>; }; - db8500-prcmu-regulators { - compatible = "stericsson,db8500-prcmu-regulator"; - - // DB8500_REGULATOR_VAPE - db8500_vape_reg: db8500_vape { - regulator-name = "db8500-vape"; - regulator-always-on; - }; - - // DB8500_REGULATOR_VARM - db8500_varm_reg: db8500_varm { - regulator-name = "db8500-varm"; - }; - - // DB8500_REGULATOR_VMODEM - db8500_vmodem_reg: db8500_vmodem { - regulator-name = "db8500-vmodem"; - }; - - // DB8500_REGULATOR_VPLL - db8500_vpll_reg: db8500_vpll { - regulator-name = "db8500-vpll"; - }; - - // DB8500_REGULATOR_VSMPS1 - db8500_vsmps1_reg: db8500_vsmps1 { - regulator-name = "db8500-vsmps1"; - }; - - // DB8500_REGULATOR_VSMPS2 - db8500_vsmps2_reg: db8500_vsmps2 { - regulator-name = "db8500-vsmps2"; - }; - - // DB8500_REGULATOR_VSMPS3 - db8500_vsmps3_reg: db8500_vsmps3 { - regulator-name = "db8500-vsmps3"; - }; - - // DB8500_REGULATOR_VRF1 - db8500_vrf1_reg: db8500_vrf1 { - regulator-name = "db8500-vrf1"; - }; - - // DB8500_REGULATOR_SWITCH_SVAMMDSP - db8500_sva_mmdsp_reg: db8500_sva_mmdsp { - regulator-name = "db8500-sva-mmdsp"; - }; - - // DB8500_REGULATOR_SWITCH_SVAMMDSPRET - db8500_sva_mmdsp_ret_reg: db8500_sva_mmdsp_ret { - regulator-name = "db8500-sva-mmdsp-ret"; - }; - - // DB8500_REGULATOR_SWITCH_SVAPIPE - db8500_sva_pipe_reg: db8500_sva_pipe { - regulator-name = "db8500_sva_pipe"; - }; - - // DB8500_REGULATOR_SWITCH_SIAMMDSP - db8500_sia_mmdsp_reg: db8500_sia_mmdsp { - regulator-name = "db8500_sia_mmdsp"; - }; - - // DB8500_REGULATOR_SWITCH_SIAMMDSPRET - db8500_sia_mmdsp_ret_reg: db8500_sia_mmdsp_ret { - regulator-name = "db8500-sia-mmdsp-ret"; - }; - - // DB8500_REGULATOR_SWITCH_SIAPIPE - db8500_sia_pipe_reg: db8500_sia_pipe { - regulator-name = "db8500-sia-pipe"; - }; - - // DB8500_REGULATOR_SWITCH_SGA - db8500_sga_reg: db8500_sga { - regulator-name = "db8500-sga"; - vin-supply = <&db8500_vape_reg>; - }; - - // DB8500_REGULATOR_SWITCH_B2R2_MCDE - db8500_b2r2_mcde_reg: db8500_b2r2_mcde { - regulator-name = "db8500-b2r2-mcde"; - vin-supply = <&db8500_vape_reg>; - }; - - // DB8500_REGULATOR_SWITCH_ESRAM12 - db8500_esram12_reg: db8500_esram12 { - regulator-name = "db8500-esram12"; - }; - - // DB8500_REGULATOR_SWITCH_ESRAM12RET - db8500_esram12_ret_reg: db8500_esram12_ret { - regulator-name = "db8500-esram12-ret"; - }; - - // DB8500_REGULATOR_SWITCH_ESRAM34 - db8500_esram34_reg: db8500_esram34 { - regulator-name = "db8500-esram34"; - }; - - // DB8500_REGULATOR_SWITCH_ESRAM34RET - db8500_esram34_ret_reg: db8500_esram34_ret { - regulator-name = "db8500-esram34-ret"; - }; - }; - ab8500@5 { compatible = "stericsson,ab8500"; reg = <5>; /* mailbox 5 is i2c */ interrupts = <0 40 0x4>; - - ab8500-regulators { - compatible = "stericsson,ab8500-regulator"; - - // supplies to the display/camera - ab8500_ldo_aux1_reg: ab8500_ldo_aux1 { - regulator-name = "V-DISPLAY"; - regulator-min-microvolt = <2500000>; - regulator-max-microvolt = <2900000>; - regulator-boot-on; - /* BUG: If turned off MMC will be affected. */ - regulator-always-on; - }; - - // supplies to the on-board eMMC - ab8500_ldo_aux2_reg: ab8500_ldo_aux2 { - regulator-name = "V-eMMC1"; - regulator-min-microvolt = <1100000>; - regulator-max-microvolt = <3300000>; - }; - - // supply for VAUX3; SDcard slots - ab8500_ldo_aux3_reg: ab8500_ldo_aux3 { - regulator-name = "V-MMC-SD"; - regulator-min-microvolt = <1100000>; - regulator-max-microvolt = <3300000>; - }; - - // supply for v-intcore12; VINTCORE12 LDO - ab8500_ldo_initcore_reg: ab8500_ldo_initcore { - regulator-name = "V-INTCORE"; - }; - - // supply for tvout; gpadc; TVOUT LDO - ab8500_ldo_tvout_reg: ab8500_ldo_tvout { - regulator-name = "V-TVOUT"; - }; - - // supply for ab8500-usb; USB LDO - ab8500_ldo_usb_reg: ab8500_ldo_usb { - regulator-name = "dummy"; - }; - - // supply for ab8500-vaudio; VAUDIO LDO - ab8500_ldo_audio_reg: ab8500_ldo_audio { - regulator-name = "V-AUD"; - }; - - // supply for v-anamic1 VAMic1-LDO - ab8500_ldo_anamic1_reg: ab8500_ldo_anamic1 { - regulator-name = "V-AMIC1"; - }; - - // supply for v-amic2; VAMIC2 LDO; reuse constants for AMIC1 - ab8500_ldo_amamic2_reg: ab8500_ldo_amamic2 { - regulator-name = "V-AMIC2"; - }; - - // supply for v-dmic; VDMIC LDO - ab8500_ldo_dmic_reg: ab8500_ldo_dmic { - regulator-name = "V-DMIC"; - }; - - // supply for U8500 CSI/DSI; VANA LDO - ab8500_ldo_ana_reg: ab8500_ldo_ana { - regulator-name = "V-CSI/DSI"; - }; - }; }; }; @@ -432,8 +235,7 @@ status = "disabled"; // Add one of these for each child device - cs-gpios = <&gpio0 31 0x4 &gpio4 14 0x4 &gpio4 16 0x4 - &gpio6 22 0x4 &gpio7 0 0x4>; + cs-gpios = <&gpio0 31 &gpio4 14 &gpio4 16 &gpio6 22 &gpio7 0>; }; diff --git a/trunk/arch/arm/boot/dts/exynos5250.dtsi b/trunk/arch/arm/boot/dts/exynos5250.dtsi index 4272b2949228..5ca0cdb76413 100644 --- a/trunk/arch/arm/boot/dts/exynos5250.dtsi +++ b/trunk/arch/arm/boot/dts/exynos5250.dtsi @@ -30,22 +30,6 @@ reg = <0x10481000 0x1000>, <0x10482000 0x2000>; }; - combiner:interrupt-controller@10440000 { - compatible = "samsung,exynos4210-combiner"; - #interrupt-cells = <2>; - interrupt-controller; - samsung,combiner-nr = <32>; - reg = <0x10440000 0x1000>; - interrupts = <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>, - <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>, - <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>, - <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>, - <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>, - <0 20 0>, <0 21 0>, <0 22 0>, <0 23 0>, - <0 24 0>, <0 25 0>, <0 26 0>, <0 27 0>, - <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>; - }; - watchdog { compatible = "samsung,s3c2410-wdt"; reg = <0x101D0000 0x100>; diff --git a/trunk/arch/arm/boot/dts/imx27.dtsi b/trunk/arch/arm/boot/dts/imx27.dtsi index 386c769c38d1..2b1a166d41f9 100644 --- a/trunk/arch/arm/boot/dts/imx27.dtsi +++ b/trunk/arch/arm/boot/dts/imx27.dtsi @@ -213,14 +213,5 @@ status = "disabled"; }; }; - nand@d8000000 { - #address-cells = <1>; - #size-cells = <1>; - - compatible = "fsl,imx27-nand"; - reg = <0xd8000000 0x1000>; - interrupts = <29>; - status = "disabled"; - }; }; }; diff --git a/trunk/arch/arm/boot/dts/lpc32xx.dtsi b/trunk/arch/arm/boot/dts/lpc32xx.dtsi index 3f5dad801a98..2d696866f71c 100644 --- a/trunk/arch/arm/boot/dts/lpc32xx.dtsi +++ b/trunk/arch/arm/boot/dts/lpc32xx.dtsi @@ -215,8 +215,45 @@ gpio: gpio@40028000 { compatible = "nxp,lpc3220-gpio"; reg = <0x40028000 0x1000>; - gpio-controller; - #gpio-cells = <3>; /* bank, pin, flags */ + /* create a private address space for enumeration */ + #address-cells = <1>; + #size-cells = <0>; + + gpio_p0: gpio-bank@0 { + gpio-controller; + #gpio-cells = <2>; + reg = <0>; + }; + + gpio_p1: gpio-bank@1 { + gpio-controller; + #gpio-cells = <2>; + reg = <1>; + }; + + gpio_p2: gpio-bank@2 { + gpio-controller; + #gpio-cells = <2>; + reg = <2>; + }; + + gpio_p3: gpio-bank@3 { + gpio-controller; + #gpio-cells = <2>; + reg = <3>; + }; + + gpi_p3: gpio-bank@4 { + gpio-controller; + #gpio-cells = <2>; + reg = <4>; + }; + + gpo_p3: gpio-bank@5 { + gpio-controller; + #gpio-cells = <2>; + reg = <5>; + }; }; watchdog@4003C000 { diff --git a/trunk/arch/arm/boot/dts/phy3250.dts b/trunk/arch/arm/boot/dts/phy3250.dts index c4ff6d1a018b..0167e86314c0 100644 --- a/trunk/arch/arm/boot/dts/phy3250.dts +++ b/trunk/arch/arm/boot/dts/phy3250.dts @@ -131,13 +131,13 @@ compatible = "gpio-leds"; led0 { - gpios = <&gpio 5 1 1>; /* GPO_P3 1, GPIO 80, active low */ + gpios = <&gpo_p3 1 1>; /* GPO_P3 1, GPIO 80, active low */ linux,default-trigger = "heartbeat"; default-state = "off"; }; led1 { - gpios = <&gpio 5 14 1>; /* GPO_P3 14, GPIO 93, active low */ + gpios = <&gpo_p3 14 1>; /* GPO_P3 14, GPIO 93, active low */ linux,default-trigger = "timer"; default-state = "off"; }; diff --git a/trunk/arch/arm/boot/dts/snowball.dts b/trunk/arch/arm/boot/dts/snowball.dts index ec3c33975110..d99dc04f0d91 100644 --- a/trunk/arch/arm/boot/dts/snowball.dts +++ b/trunk/arch/arm/boot/dts/snowball.dts @@ -20,16 +20,6 @@ reg = <0x00000000 0x20000000>; }; - en_3v3_reg: en_3v3 { - compatible = "regulator-fixed"; - regulator-name = "en-3v3-fixed-supply"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - gpios = <&gpio0 26 0x4>; // 26 - startup-delay-us = <5000>; - enable-active-high; - }; - gpio_keys { compatible = "gpio-keys"; #address-cells = <1>; @@ -40,35 +30,35 @@ wakeup = <1>; linux,code = <2>; label = "userpb"; - gpios = <&gpio1 0 0x4>; + gpios = <&gpio1 0 0>; }; button@2 { debounce_interval = <50>; wakeup = <1>; linux,code = <3>; label = "extkb1"; - gpios = <&gpio4 23 0x4>; + gpios = <&gpio4 23 0>; }; button@3 { debounce_interval = <50>; wakeup = <1>; linux,code = <4>; label = "extkb2"; - gpios = <&gpio4 24 0x4>; + gpios = <&gpio4 24 0>; }; button@4 { debounce_interval = <50>; wakeup = <1>; linux,code = <5>; label = "extkb3"; - gpios = <&gpio5 1 0x4>; + gpios = <&gpio5 1 0>; }; button@5 { debounce_interval = <50>; wakeup = <1>; linux,code = <6>; label = "extkb4"; - gpios = <&gpio5 2 0x4>; + gpios = <&gpio5 2 0>; }; }; @@ -76,11 +66,12 @@ compatible = "gpio-leds"; used-led { label = "user_led"; - gpios = <&gpio4 14 0x4>; + gpios = <&gpio4 14>; }; }; soc-u9500 { + external-bus@50000000 { status = "okay"; @@ -89,9 +80,6 @@ reg = <0 0x10000>; interrupts = <12 0x1>; interrupt-parent = <&gpio4>; - vdd33a-supply = <&en_3v3_reg>; - vddvario-supply = <&db8500_vape_reg>; - reg-shift = <1>; reg-io-width = <2>; @@ -103,13 +91,11 @@ sdi@80126000 { status = "enabled"; - vmmc-supply = <&ab8500_ldo_aux3_reg>; - cd-gpios = <&gpio6 26 0x4>; // 218 + cd-gpios = <&gpio6 26>; }; sdi@80114000 { status = "enabled"; - vmmc-supply = <&ab8500_ldo_aux2_reg>; }; uart@80120000 { @@ -128,7 +114,7 @@ tc3589x@42 { //compatible = "tc3589x"; reg = <0x42>; - gpios = <&gpio6 25 0x4>; + interrupts = <25>; interrupt-parent = <&gpio6>; }; tps61052@33 { diff --git a/trunk/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts b/trunk/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts index 7e1091d91af8..941b161ab78c 100644 --- a/trunk/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts +++ b/trunk/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts @@ -73,10 +73,7 @@ #address-cells = <0>; interrupt-controller; reg = <0x2c001000 0x1000>, - <0x2c002000 0x1000>, - <0x2c004000 0x2000>, - <0x2c006000 0x2000>; - interrupts = <1 9 0xf04>; + <0x2c002000 0x100>; }; memory-controller@7ffd0000 { @@ -96,14 +93,6 @@ <0 91 4>; }; - timer { - compatible = "arm,armv7-timer"; - interrupts = <1 13 0xf08>, - <1 14 0xf08>, - <1 11 0xf08>, - <1 10 0xf08>; - }; - pmu { compatible = "arm,cortex-a15-pmu", "arm,cortex-a9-pmu"; interrupts = <0 68 4>, diff --git a/trunk/arch/arm/boot/dts/vexpress-v2p-ca5s.dts b/trunk/arch/arm/boot/dts/vexpress-v2p-ca5s.dts index 18917a0f8604..6905e66d4748 100644 --- a/trunk/arch/arm/boot/dts/vexpress-v2p-ca5s.dts +++ b/trunk/arch/arm/boot/dts/vexpress-v2p-ca5s.dts @@ -77,18 +77,13 @@ timer@2c000600 { compatible = "arm,cortex-a5-twd-timer"; - reg = <0x2c000600 0x20>; - interrupts = <1 13 0x304>; - }; - - watchdog@2c000620 { - compatible = "arm,cortex-a5-twd-wdt"; - reg = <0x2c000620 0x20>; - interrupts = <1 14 0x304>; + reg = <0x2c000600 0x38>; + interrupts = <1 2 0x304>, + <1 3 0x304>; }; gic: interrupt-controller@2c001000 { - compatible = "arm,cortex-a5-gic", "arm,cortex-a9-gic"; + compatible = "arm,corex-a5-gic", "arm,cortex-a9-gic"; #interrupt-cells = <3>; #address-cells = <0>; interrupt-controller; diff --git a/trunk/arch/arm/boot/dts/vexpress-v2p-ca9.dts b/trunk/arch/arm/boot/dts/vexpress-v2p-ca9.dts index 3f0c736d31d6..da778693be54 100644 --- a/trunk/arch/arm/boot/dts/vexpress-v2p-ca9.dts +++ b/trunk/arch/arm/boot/dts/vexpress-v2p-ca9.dts @@ -105,13 +105,8 @@ timer@1e000600 { compatible = "arm,cortex-a9-twd-timer"; reg = <0x1e000600 0x20>; - interrupts = <1 13 0xf04>; - }; - - watchdog@1e000620 { - compatible = "arm,cortex-a9-twd-wdt"; - reg = <0x1e000620 0x20>; - interrupts = <1 14 0xf04>; + interrupts = <1 2 0xf04>, + <1 3 0xf04>; }; gic: interrupt-controller@1e001000 { diff --git a/trunk/arch/arm/configs/u8500_defconfig b/trunk/arch/arm/configs/u8500_defconfig index 2d4f661d1cf6..7e84f453e8a6 100644 --- a/trunk/arch/arm/configs/u8500_defconfig +++ b/trunk/arch/arm/configs/u8500_defconfig @@ -75,7 +75,6 @@ CONFIG_AB5500_CORE=y CONFIG_AB8500_CORE=y CONFIG_REGULATOR=y CONFIG_REGULATOR_AB8500=y -CONFIG_REGULATOR_FIXED_VOLTAGE=y # CONFIG_HID_SUPPORT is not set CONFIG_USB_GADGET=y CONFIG_AB8500_USB=y diff --git a/trunk/arch/arm/include/asm/io.h b/trunk/arch/arm/include/asm/io.h index 815c669fec0a..9af5563dd3eb 100644 --- a/trunk/arch/arm/include/asm/io.h +++ b/trunk/arch/arm/include/asm/io.h @@ -47,9 +47,9 @@ extern void __raw_readsb(const void __iomem *addr, void *data, int bytelen); extern void __raw_readsw(const void __iomem *addr, void *data, int wordlen); extern void __raw_readsl(const void __iomem *addr, void *data, int longlen); -#define __raw_writeb(v,a) ((void)(__chk_io_ptr(a), *(volatile unsigned char __force *)(a) = (v))) -#define __raw_writew(v,a) ((void)(__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v))) -#define __raw_writel(v,a) ((void)(__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v))) +#define __raw_writeb(v,a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a) = (v)) +#define __raw_writew(v,a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v)) +#define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v)) #define __raw_readb(a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a)) #define __raw_readw(a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a)) @@ -229,9 +229,11 @@ extern void _memset_io(volatile void __iomem *, int, size_t); #define readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32) \ __raw_readl(c)); __r; }) -#define writeb_relaxed(v,c) __raw_writeb(v,c) -#define writew_relaxed(v,c) __raw_writew((__force u16) cpu_to_le16(v),c) -#define writel_relaxed(v,c) __raw_writel((__force u32) cpu_to_le32(v),c) +#define writeb_relaxed(v,c) ((void)__raw_writeb(v,c)) +#define writew_relaxed(v,c) ((void)__raw_writew((__force u16) \ + cpu_to_le16(v),c)) +#define writel_relaxed(v,c) ((void)__raw_writel((__force u32) \ + cpu_to_le32(v),c)) #define readb(c) ({ u8 __v = readb_relaxed(c); __iormb(); __v; }) #define readw(c) ({ u16 __v = readw_relaxed(c); __iormb(); __v; }) @@ -279,12 +281,12 @@ extern void _memset_io(volatile void __iomem *, int, size_t); #define ioread16be(p) ({ unsigned int __v = be16_to_cpu((__force __be16)__raw_readw(p)); __iormb(); __v; }) #define ioread32be(p) ({ unsigned int __v = be32_to_cpu((__force __be32)__raw_readl(p)); __iormb(); __v; }) -#define iowrite8(v,p) ({ __iowmb(); __raw_writeb(v, p); }) -#define iowrite16(v,p) ({ __iowmb(); __raw_writew((__force __u16)cpu_to_le16(v), p); }) -#define iowrite32(v,p) ({ __iowmb(); __raw_writel((__force __u32)cpu_to_le32(v), p); }) +#define iowrite8(v,p) ({ __iowmb(); (void)__raw_writeb(v, p); }) +#define iowrite16(v,p) ({ __iowmb(); (void)__raw_writew((__force __u16)cpu_to_le16(v), p); }) +#define iowrite32(v,p) ({ __iowmb(); (void)__raw_writel((__force __u32)cpu_to_le32(v), p); }) -#define iowrite16be(v,p) ({ __iowmb(); __raw_writew((__force __u16)cpu_to_be16(v), p); }) -#define iowrite32be(v,p) ({ __iowmb(); __raw_writel((__force __u32)cpu_to_be32(v), p); }) +#define iowrite16be(v,p) ({ __iowmb(); (void)__raw_writew((__force __u16)cpu_to_be16(v), p); }) +#define iowrite32be(v,p) ({ __iowmb(); (void)__raw_writel((__force __u32)cpu_to_be32(v), p); }) #define ioread8_rep(p,d,c) __raw_readsb(p,d,c) #define ioread16_rep(p,d,c) __raw_readsw(p,d,c) diff --git a/trunk/arch/arm/include/asm/posix_types.h b/trunk/arch/arm/include/asm/posix_types.h index d2de9cbbcd9b..efdf99045d87 100644 --- a/trunk/arch/arm/include/asm/posix_types.h +++ b/trunk/arch/arm/include/asm/posix_types.h @@ -22,6 +22,9 @@ typedef unsigned short __kernel_mode_t; #define __kernel_mode_t __kernel_mode_t +typedef unsigned short __kernel_nlink_t; +#define __kernel_nlink_t __kernel_nlink_t + typedef unsigned short __kernel_ipc_pid_t; #define __kernel_ipc_pid_t __kernel_ipc_pid_t diff --git a/trunk/arch/arm/include/asm/thread_info.h b/trunk/arch/arm/include/asm/thread_info.h index b79f8e97f775..68388eb4946b 100644 --- a/trunk/arch/arm/include/asm/thread_info.h +++ b/trunk/arch/arm/include/asm/thread_info.h @@ -148,7 +148,6 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ #define TIF_SYSCALL_TRACE 8 #define TIF_SYSCALL_AUDIT 9 -#define TIF_SYSCALL_RESTARTSYS 10 #define TIF_POLLING_NRFLAG 16 #define TIF_USING_IWMMXT 17 #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ @@ -163,17 +162,16 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) #define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT) +#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) #define _TIF_SECCOMP (1 << TIF_SECCOMP) -#define _TIF_SYSCALL_RESTARTSYS (1 << TIF_SYSCALL_RESTARTSYS) /* Checks for any syscall work in entry-common.S */ -#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \ - _TIF_SYSCALL_RESTARTSYS) +#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT) /* * Change these and you break ASM code in entry-common.S */ -#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | _TIF_NOTIFY_RESUME) +#define _TIF_WORK_MASK 0x000000ff #endif /* __KERNEL__ */ #endif /* __ASM_ARM_THREAD_INFO_H */ diff --git a/trunk/arch/arm/kernel/entry-common.S b/trunk/arch/arm/kernel/entry-common.S index 4afed88d250a..7bd2d3cb8957 100644 --- a/trunk/arch/arm/kernel/entry-common.S +++ b/trunk/arch/arm/kernel/entry-common.S @@ -53,13 +53,9 @@ fast_work_pending: work_pending: tst r1, #_TIF_NEED_RESCHED bne work_resched - /* - * TIF_SIGPENDING or TIF_NOTIFY_RESUME must've been set if we got here - */ - ldr r2, [sp, #S_PSR] + tst r1, #_TIF_SIGPENDING|_TIF_NOTIFY_RESUME + beq no_work_pending mov r0, sp @ 'regs' - tst r2, #15 @ are we returning to user mode? - bne no_work_pending @ no? just leave, then... mov r2, why @ 'syscall' tst r1, #_TIF_SIGPENDING @ delivering a signal? movne why, #0 @ prevent further restarts diff --git a/trunk/arch/arm/kernel/ptrace.c b/trunk/arch/arm/kernel/ptrace.c index 5700a7ae7f0b..14e38261cd31 100644 --- a/trunk/arch/arm/kernel/ptrace.c +++ b/trunk/arch/arm/kernel/ptrace.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include @@ -918,8 +917,6 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3); - if (why == 0 && test_and_clear_thread_flag(TIF_SYSCALL_RESTARTSYS)) - scno = __NR_restart_syscall - __NR_SYSCALL_BASE; if (!test_thread_flag(TIF_SYSCALL_TRACE)) return scno; diff --git a/trunk/arch/arm/kernel/signal.c b/trunk/arch/arm/kernel/signal.c index fd2392a17ac1..4e5fdd9bd9e3 100644 --- a/trunk/arch/arm/kernel/signal.c +++ b/trunk/arch/arm/kernel/signal.c @@ -22,11 +22,14 @@ #include "signal.h" +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + /* * For ARM syscalls, we encode the syscall number into the instruction. */ #define SWI_SYS_SIGRETURN (0xef000000|(__NR_sigreturn)|(__NR_OABI_SYSCALL_BASE)) #define SWI_SYS_RT_SIGRETURN (0xef000000|(__NR_rt_sigreturn)|(__NR_OABI_SYSCALL_BASE)) +#define SWI_SYS_RESTART (0xef000000|__NR_restart_syscall|__NR_OABI_SYSCALL_BASE) /* * With EABI, the syscall number has to be loaded into r7. @@ -46,6 +49,18 @@ const unsigned long sigreturn_codes[7] = { MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN, }; +/* + * Either we support OABI only, or we have EABI with the OABI + * compat layer enabled. In the later case we don't know if + * user space is EABI or not, and if not we must not clobber r7. + * Always using the OABI syscall solves that issue and works for + * all those cases. + */ +const unsigned long syscall_restart_code[2] = { + SWI_SYS_RESTART, /* swi __NR_restart_syscall */ + 0xe49df004, /* ldr pc, [sp], #4 */ +}; + /* * atomically swap in the new signal mask, and wait for a signal. */ @@ -67,10 +82,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, old_sigset_t mask; if (!access_ok(VERIFY_READ, act, sizeof(*act)) || __get_user(new_ka.sa.sa_handler, &act->sa_handler) || - __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) || - __get_user(new_ka.sa.sa_flags, &act->sa_flags) || - __get_user(mask, &act->sa_mask)) + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) return -EFAULT; + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); siginitset(&new_ka.sa.sa_mask, mask); } @@ -79,10 +94,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, if (!ret && oact) { if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) || - __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); } return ret; @@ -208,8 +223,10 @@ static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf) int err; err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set)); - if (err == 0) + if (err == 0) { + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); + } __get_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err); __get_user_error(regs->ARM_r1, &sf->uc.uc_mcontext.arm_r1, err); @@ -524,13 +541,13 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, /* * OK, we're invoking a handler */ -static void +static int handle_signal(unsigned long sig, struct k_sigaction *ka, - siginfo_t *info, struct pt_regs *regs) + siginfo_t *info, sigset_t *oldset, + struct pt_regs * regs) { struct thread_info *thread = current_thread_info(); struct task_struct *tsk = current; - sigset_t *oldset = sigmask_to_save(); int usig = sig; int ret; @@ -555,9 +572,17 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, if (ret != 0) { force_sigsegv(sig, tsk); - return; + return ret; } - signal_delivered(sig, info, ka, regs, 0); + + /* + * Block the signal if we were successful. + */ + block_sigmask(ka, sig); + + tracehook_signal_handler(sig, info, ka, regs, 0); + + return 0; } /* @@ -576,6 +601,15 @@ static void do_signal(struct pt_regs *regs, int syscall) siginfo_t info; int signr; + /* + * We want the common case to go fast, which + * is why we may in certain cases get here from + * kernel mode. Just return without doing anything + * if so. + */ + if (!user_mode(regs)) + return; + /* * If we were from a system call, check for system call restarting... */ @@ -592,39 +626,58 @@ static void do_signal(struct pt_regs *regs, int syscall) case -ERESTARTNOHAND: case -ERESTARTSYS: case -ERESTARTNOINTR: - case -ERESTART_RESTARTBLOCK: regs->ARM_r0 = regs->ARM_ORIG_r0; regs->ARM_pc = restart_addr; break; + case -ERESTART_RESTARTBLOCK: + regs->ARM_r0 = -EINTR; + break; } } + if (try_to_freeze()) + goto no_signal; + /* * Get the signal to deliver. When running under ptrace, at this * point the debugger may change all our registers ... */ signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { + sigset_t *oldset; + /* * Depending on the signal settings we may need to revert the * decision to restart the system call. But skip this if a * debugger has chosen to restart at a different PC. */ if (regs->ARM_pc == restart_addr) { - if (retval == -ERESTARTNOHAND || - retval == -ERESTART_RESTARTBLOCK + if (retval == -ERESTARTNOHAND || (retval == -ERESTARTSYS && !(ka.sa.sa_flags & SA_RESTART))) { regs->ARM_r0 = -EINTR; regs->ARM_pc = continue_addr; } - clear_thread_flag(TIF_SYSCALL_RESTARTSYS); } - handle_signal(signr, &ka, &info, regs); + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + if (handle_signal(signr, &ka, &info, oldset, regs) == 0) { + /* + * A signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TIF_RESTORE_SIGMASK flag. + */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + } return; } + no_signal: if (syscall) { /* * Handle restarting a different system call. As above, @@ -632,11 +685,38 @@ static void do_signal(struct pt_regs *regs, int syscall) * ignore the restart. */ if (retval == -ERESTART_RESTARTBLOCK - && regs->ARM_pc == restart_addr) - set_thread_flag(TIF_SYSCALL_RESTARTSYS); - } + && regs->ARM_pc == continue_addr) { + if (thumb_mode(regs)) { + regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE; + regs->ARM_pc -= 2; + } else { +#if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT) + regs->ARM_r7 = __NR_restart_syscall; + regs->ARM_pc -= 4; +#else + u32 __user *usp; + + regs->ARM_sp -= 4; + usp = (u32 __user *)regs->ARM_sp; + + if (put_user(regs->ARM_pc, usp) == 0) { + regs->ARM_pc = KERN_RESTART_CODE; + } else { + regs->ARM_sp += 4; + force_sigsegv(0, current); + } +#endif + } + } - restore_saved_sigmask(); + /* If there's no signal to deliver, we just put the saved sigmask + * back. + */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } + } } asmlinkage void @@ -648,5 +728,7 @@ do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall) if (thread_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/trunk/arch/arm/kernel/signal.h b/trunk/arch/arm/kernel/signal.h index 5ff067b7c752..6fcfe8398aa4 100644 --- a/trunk/arch/arm/kernel/signal.h +++ b/trunk/arch/arm/kernel/signal.h @@ -8,5 +8,7 @@ * published by the Free Software Foundation. */ #define KERN_SIGRETURN_CODE (CONFIG_VECTORS_BASE + 0x00000500) +#define KERN_RESTART_CODE (KERN_SIGRETURN_CODE + sizeof(sigreturn_codes)) extern const unsigned long sigreturn_codes[7]; +extern const unsigned long syscall_restart_code[2]; diff --git a/trunk/arch/arm/kernel/traps.c b/trunk/arch/arm/kernel/traps.c index 4928d89758f4..3647170e9a16 100644 --- a/trunk/arch/arm/kernel/traps.c +++ b/trunk/arch/arm/kernel/traps.c @@ -820,6 +820,8 @@ void __init early_trap_init(void *vectors_base) */ memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE), sigreturn_codes, sizeof(sigreturn_codes)); + memcpy((void *)(vectors + KERN_RESTART_CODE - CONFIG_VECTORS_BASE), + syscall_restart_code, sizeof(syscall_restart_code)); flush_icache_range(vectors, vectors + PAGE_SIZE); modify_domain(DOMAIN_USER, DOMAIN_CLIENT); diff --git a/trunk/arch/arm/mach-ep93xx/snappercl15.c b/trunk/arch/arm/mach-ep93xx/snappercl15.c index 01abd3516a77..eb282378fa78 100644 --- a/trunk/arch/arm/mach-ep93xx/snappercl15.c +++ b/trunk/arch/arm/mach-ep93xx/snappercl15.c @@ -82,6 +82,8 @@ static int snappercl15_nand_dev_ready(struct mtd_info *mtd) return !!(__raw_readw(NAND_CTRL_ADDR(chip)) & SNAPPERCL15_NAND_RDY); } +static const char *snappercl15_nand_part_probes[] = {"cmdlinepart", NULL}; + static struct mtd_partition snappercl15_nand_parts[] = { { .name = "Kernel", @@ -98,8 +100,10 @@ static struct mtd_partition snappercl15_nand_parts[] = { static struct platform_nand_data snappercl15_nand_data = { .chip = { .nr_chips = 1, + .part_probe_types = snappercl15_nand_part_probes, .partitions = snappercl15_nand_parts, .nr_partitions = ARRAY_SIZE(snappercl15_nand_parts), + .options = NAND_NO_AUTOINCR, .chip_delay = 25, }, .ctrl = { diff --git a/trunk/arch/arm/mach-ep93xx/ts72xx.c b/trunk/arch/arm/mach-ep93xx/ts72xx.c index 75cab2d7ec73..d4ef339d961e 100644 --- a/trunk/arch/arm/mach-ep93xx/ts72xx.c +++ b/trunk/arch/arm/mach-ep93xx/ts72xx.c @@ -105,6 +105,8 @@ static int ts72xx_nand_device_ready(struct mtd_info *mtd) return !!(__raw_readb(addr) & 0x20); } +static const char *ts72xx_nand_part_probes[] = { "cmdlinepart", NULL }; + #define TS72XX_BOOTROM_PART_SIZE (SZ_16K) #define TS72XX_REDBOOT_PART_SIZE (SZ_2M + SZ_1M) @@ -132,6 +134,7 @@ static struct platform_nand_data ts72xx_nand_data = { .nr_chips = 1, .chip_offset = 0, .chip_delay = 15, + .part_probe_types = ts72xx_nand_part_probes, .partitions = ts72xx_nand_parts, .nr_partitions = ARRAY_SIZE(ts72xx_nand_parts), }, diff --git a/trunk/arch/arm/mach-exynos/Kconfig b/trunk/arch/arm/mach-exynos/Kconfig index 573be57d3d28..43ebe9094411 100644 --- a/trunk/arch/arm/mach-exynos/Kconfig +++ b/trunk/arch/arm/mach-exynos/Kconfig @@ -62,8 +62,6 @@ config SOC_EXYNOS5250 default y depends on ARCH_EXYNOS5 select SAMSUNG_DMADEV - select S5P_PM if PM - select S5P_SLEEP if PM help Enable EXYNOS5250 SoC support diff --git a/trunk/arch/arm/mach-exynos/Makefile b/trunk/arch/arm/mach-exynos/Makefile index 9b58024f7d43..440a637c76f1 100644 --- a/trunk/arch/arm/mach-exynos/Makefile +++ b/trunk/arch/arm/mach-exynos/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o -obj-$(CONFIG_ARCH_EXYNOS) += pmu.o +obj-$(CONFIG_ARCH_EXYNOS4) += pmu.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o diff --git a/trunk/arch/arm/mach-exynos/clock-exynos5.c b/trunk/arch/arm/mach-exynos/clock-exynos5.c index fefa336be2b4..5aa460b01fdf 100644 --- a/trunk/arch/arm/mach-exynos/clock-exynos5.c +++ b/trunk/arch/arm/mach-exynos/clock-exynos5.c @@ -30,56 +30,7 @@ #ifdef CONFIG_PM_SLEEP static struct sleep_save exynos5_clock_save[] = { - SAVE_ITEM(EXYNOS5_CLKSRC_MASK_TOP), - SAVE_ITEM(EXYNOS5_CLKSRC_MASK_GSCL), - SAVE_ITEM(EXYNOS5_CLKSRC_MASK_DISP1_0), - SAVE_ITEM(EXYNOS5_CLKSRC_MASK_FSYS), - SAVE_ITEM(EXYNOS5_CLKSRC_MASK_MAUDIO), - SAVE_ITEM(EXYNOS5_CLKSRC_MASK_PERIC0), - SAVE_ITEM(EXYNOS5_CLKSRC_MASK_PERIC1), - SAVE_ITEM(EXYNOS5_CLKGATE_IP_GSCL), - SAVE_ITEM(EXYNOS5_CLKGATE_IP_DISP1), - SAVE_ITEM(EXYNOS5_CLKGATE_IP_MFC), - SAVE_ITEM(EXYNOS5_CLKGATE_IP_G3D), - SAVE_ITEM(EXYNOS5_CLKGATE_IP_GEN), - SAVE_ITEM(EXYNOS5_CLKGATE_IP_FSYS), - SAVE_ITEM(EXYNOS5_CLKGATE_IP_PERIC), - SAVE_ITEM(EXYNOS5_CLKGATE_IP_PERIS), - SAVE_ITEM(EXYNOS5_CLKGATE_BLOCK), - SAVE_ITEM(EXYNOS5_CLKDIV_TOP0), - SAVE_ITEM(EXYNOS5_CLKDIV_TOP1), - SAVE_ITEM(EXYNOS5_CLKDIV_GSCL), - SAVE_ITEM(EXYNOS5_CLKDIV_DISP1_0), - SAVE_ITEM(EXYNOS5_CLKDIV_GEN), - SAVE_ITEM(EXYNOS5_CLKDIV_MAUDIO), - SAVE_ITEM(EXYNOS5_CLKDIV_FSYS0), - SAVE_ITEM(EXYNOS5_CLKDIV_FSYS1), - SAVE_ITEM(EXYNOS5_CLKDIV_FSYS2), - SAVE_ITEM(EXYNOS5_CLKDIV_FSYS3), - SAVE_ITEM(EXYNOS5_CLKDIV_PERIC0), - SAVE_ITEM(EXYNOS5_CLKDIV_PERIC1), - SAVE_ITEM(EXYNOS5_CLKDIV_PERIC2), - SAVE_ITEM(EXYNOS5_CLKDIV_PERIC3), - SAVE_ITEM(EXYNOS5_CLKDIV_PERIC4), - SAVE_ITEM(EXYNOS5_CLKDIV_PERIC5), - SAVE_ITEM(EXYNOS5_SCLK_DIV_ISP), - SAVE_ITEM(EXYNOS5_CLKSRC_TOP0), - SAVE_ITEM(EXYNOS5_CLKSRC_TOP1), - SAVE_ITEM(EXYNOS5_CLKSRC_TOP2), - SAVE_ITEM(EXYNOS5_CLKSRC_TOP3), - SAVE_ITEM(EXYNOS5_CLKSRC_GSCL), - SAVE_ITEM(EXYNOS5_CLKSRC_DISP1_0), - SAVE_ITEM(EXYNOS5_CLKSRC_MAUDIO), - SAVE_ITEM(EXYNOS5_CLKSRC_FSYS), - SAVE_ITEM(EXYNOS5_CLKSRC_PERIC0), - SAVE_ITEM(EXYNOS5_CLKSRC_PERIC1), - SAVE_ITEM(EXYNOS5_SCLK_SRC_ISP), - SAVE_ITEM(EXYNOS5_EPLL_CON0), - SAVE_ITEM(EXYNOS5_EPLL_CON1), - SAVE_ITEM(EXYNOS5_EPLL_CON2), - SAVE_ITEM(EXYNOS5_VPLL_CON0), - SAVE_ITEM(EXYNOS5_VPLL_CON1), - SAVE_ITEM(EXYNOS5_VPLL_CON2), + /* will be implemented */ }; #endif diff --git a/trunk/arch/arm/mach-exynos/cpuidle.c b/trunk/arch/arm/mach-exynos/cpuidle.c index cff0595d0d35..26dac2893b8e 100644 --- a/trunk/arch/arm/mach-exynos/cpuidle.c +++ b/trunk/arch/arm/mach-exynos/cpuidle.c @@ -100,7 +100,7 @@ static int exynos4_enter_core0_aftr(struct cpuidle_device *dev, exynos4_set_wakeupmask(); /* Set value of power down register for aftr mode */ - exynos_sys_powerdown_conf(SYS_AFTR); + exynos4_sys_powerdown_conf(SYS_AFTR); __raw_writel(virt_to_phys(s3c_cpu_resume), REG_DIRECTGO_ADDR); __raw_writel(S5P_CHECK_AFTR, REG_DIRECTGO_FLAG); diff --git a/trunk/arch/arm/mach-exynos/include/mach/pm-core.h b/trunk/arch/arm/mach-exynos/include/mach/pm-core.h index a67ecfaf1216..9d8da51e35ca 100644 --- a/trunk/arch/arm/mach-exynos/include/mach/pm-core.h +++ b/trunk/arch/arm/mach-exynos/include/mach/pm-core.h @@ -33,7 +33,7 @@ static inline void s3c_pm_arch_prepare_irqs(void) __raw_writel(tmp, S5P_WAKEUP_MASK); __raw_writel(s3c_irqwake_intmask, S5P_WAKEUP_MASK); - __raw_writel(s3c_irqwake_eintmask & 0xFFFFFFFE, S5P_EINT_WAKEUP_MASK); + __raw_writel(s3c_irqwake_eintmask, S5P_EINT_WAKEUP_MASK); } static inline void s3c_pm_arch_stop_clocks(void) diff --git a/trunk/arch/arm/mach-exynos/include/mach/pmu.h b/trunk/arch/arm/mach-exynos/include/mach/pmu.h index 7c27c2d4bf44..e76b7faba66b 100644 --- a/trunk/arch/arm/mach-exynos/include/mach/pmu.h +++ b/trunk/arch/arm/mach-exynos/include/mach/pmu.h @@ -23,12 +23,12 @@ enum sys_powerdown { }; extern unsigned long l2x0_regs_phys; -struct exynos_pmu_conf { +struct exynos4_pmu_conf { void __iomem *reg; unsigned int val[NUM_SYS_POWERDOWN]; }; -extern void exynos_sys_powerdown_conf(enum sys_powerdown mode); +extern void exynos4_sys_powerdown_conf(enum sys_powerdown mode); extern void s3c_cpu_resume(void); #endif /* __ASM_ARCH_PMU_H */ diff --git a/trunk/arch/arm/mach-exynos/include/mach/regs-clock.h b/trunk/arch/arm/mach-exynos/include/mach/regs-clock.h index 8c9b38c9c504..b78b5f3ad9c0 100644 --- a/trunk/arch/arm/mach-exynos/include/mach/regs-clock.h +++ b/trunk/arch/arm/mach-exynos/include/mach/regs-clock.h @@ -274,51 +274,36 @@ #define EXYNOS5_CLKDIV_ACP EXYNOS_CLKREG(0x08500) +#define EXYNOS5_CLKSRC_TOP2 EXYNOS_CLKREG(0x10218) #define EXYNOS5_EPLL_CON0 EXYNOS_CLKREG(0x10130) #define EXYNOS5_EPLL_CON1 EXYNOS_CLKREG(0x10134) -#define EXYNOS5_EPLL_CON2 EXYNOS_CLKREG(0x10138) #define EXYNOS5_VPLL_CON0 EXYNOS_CLKREG(0x10140) #define EXYNOS5_VPLL_CON1 EXYNOS_CLKREG(0x10144) -#define EXYNOS5_VPLL_CON2 EXYNOS_CLKREG(0x10148) #define EXYNOS5_CPLL_CON0 EXYNOS_CLKREG(0x10120) #define EXYNOS5_CLKSRC_TOP0 EXYNOS_CLKREG(0x10210) -#define EXYNOS5_CLKSRC_TOP1 EXYNOS_CLKREG(0x10214) -#define EXYNOS5_CLKSRC_TOP2 EXYNOS_CLKREG(0x10218) #define EXYNOS5_CLKSRC_TOP3 EXYNOS_CLKREG(0x1021C) #define EXYNOS5_CLKSRC_GSCL EXYNOS_CLKREG(0x10220) #define EXYNOS5_CLKSRC_DISP1_0 EXYNOS_CLKREG(0x1022C) -#define EXYNOS5_CLKSRC_MAUDIO EXYNOS_CLKREG(0x10240) #define EXYNOS5_CLKSRC_FSYS EXYNOS_CLKREG(0x10244) #define EXYNOS5_CLKSRC_PERIC0 EXYNOS_CLKREG(0x10250) -#define EXYNOS5_CLKSRC_PERIC1 EXYNOS_CLKREG(0x10254) -#define EXYNOS5_SCLK_SRC_ISP EXYNOS_CLKREG(0x10270) #define EXYNOS5_CLKSRC_MASK_TOP EXYNOS_CLKREG(0x10310) #define EXYNOS5_CLKSRC_MASK_GSCL EXYNOS_CLKREG(0x10320) #define EXYNOS5_CLKSRC_MASK_DISP1_0 EXYNOS_CLKREG(0x1032C) -#define EXYNOS5_CLKSRC_MASK_MAUDIO EXYNOS_CLKREG(0x10334) #define EXYNOS5_CLKSRC_MASK_FSYS EXYNOS_CLKREG(0x10340) #define EXYNOS5_CLKSRC_MASK_PERIC0 EXYNOS_CLKREG(0x10350) -#define EXYNOS5_CLKSRC_MASK_PERIC1 EXYNOS_CLKREG(0x10354) #define EXYNOS5_CLKDIV_TOP0 EXYNOS_CLKREG(0x10510) #define EXYNOS5_CLKDIV_TOP1 EXYNOS_CLKREG(0x10514) #define EXYNOS5_CLKDIV_GSCL EXYNOS_CLKREG(0x10520) #define EXYNOS5_CLKDIV_DISP1_0 EXYNOS_CLKREG(0x1052C) #define EXYNOS5_CLKDIV_GEN EXYNOS_CLKREG(0x1053C) -#define EXYNOS5_CLKDIV_MAUDIO EXYNOS_CLKREG(0x10544) #define EXYNOS5_CLKDIV_FSYS0 EXYNOS_CLKREG(0x10548) #define EXYNOS5_CLKDIV_FSYS1 EXYNOS_CLKREG(0x1054C) #define EXYNOS5_CLKDIV_FSYS2 EXYNOS_CLKREG(0x10550) #define EXYNOS5_CLKDIV_FSYS3 EXYNOS_CLKREG(0x10554) #define EXYNOS5_CLKDIV_PERIC0 EXYNOS_CLKREG(0x10558) -#define EXYNOS5_CLKDIV_PERIC1 EXYNOS_CLKREG(0x1055C) -#define EXYNOS5_CLKDIV_PERIC2 EXYNOS_CLKREG(0x10560) -#define EXYNOS5_CLKDIV_PERIC3 EXYNOS_CLKREG(0x10564) -#define EXYNOS5_CLKDIV_PERIC4 EXYNOS_CLKREG(0x10568) -#define EXYNOS5_CLKDIV_PERIC5 EXYNOS_CLKREG(0x1056C) -#define EXYNOS5_SCLK_DIV_ISP EXYNOS_CLKREG(0x10580) #define EXYNOS5_CLKGATE_IP_ACP EXYNOS_CLKREG(0x08800) #define EXYNOS5_CLKGATE_IP_ISP0 EXYNOS_CLKREG(0x0C800) @@ -326,7 +311,6 @@ #define EXYNOS5_CLKGATE_IP_GSCL EXYNOS_CLKREG(0x10920) #define EXYNOS5_CLKGATE_IP_DISP1 EXYNOS_CLKREG(0x10928) #define EXYNOS5_CLKGATE_IP_MFC EXYNOS_CLKREG(0x1092C) -#define EXYNOS5_CLKGATE_IP_G3D EXYNOS_CLKREG(0x10930) #define EXYNOS5_CLKGATE_IP_GEN EXYNOS_CLKREG(0x10934) #define EXYNOS5_CLKGATE_IP_FSYS EXYNOS_CLKREG(0x10944) #define EXYNOS5_CLKGATE_IP_GPS EXYNOS_CLKREG(0x1094C) diff --git a/trunk/arch/arm/mach-exynos/include/mach/regs-pmu.h b/trunk/arch/arm/mach-exynos/include/mach/regs-pmu.h index 43a99e6f56ab..4dbb8629b200 100644 --- a/trunk/arch/arm/mach-exynos/include/mach/regs-pmu.h +++ b/trunk/arch/arm/mach-exynos/include/mach/regs-pmu.h @@ -1,8 +1,9 @@ -/* - * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd. +/* linux/arch/arm/mach-exynos4/include/mach/regs-pmu.h + * + * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * EXYNOS - Power management unit definition + * EXYNOS4 - Power management unit definition * * 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 @@ -228,138 +229,4 @@ #define S5P_DIS_IRQ_CORE3 S5P_PMUREG(0x1034) #define S5P_DIS_IRQ_CENTRAL3 S5P_PMUREG(0x1038) -/* For EXYNOS5 */ - -#define EXYNOS5_USB_CFG S5P_PMUREG(0x0230) - -#define EXYNOS5_ARM_CORE0_SYS_PWR_REG S5P_PMUREG(0x1000) -#define EXYNOS5_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG S5P_PMUREG(0x1004) -#define EXYNOS5_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG S5P_PMUREG(0x1008) -#define EXYNOS5_ARM_CORE1_SYS_PWR_REG S5P_PMUREG(0x1010) -#define EXYNOS5_DIS_IRQ_ARM_CORE1_LOCAL_SYS_PWR_REG S5P_PMUREG(0x1014) -#define EXYNOS5_DIS_IRQ_ARM_CORE1_CENTRAL_SYS_PWR_REG S5P_PMUREG(0x1018) -#define EXYNOS5_FSYS_ARM_SYS_PWR_REG S5P_PMUREG(0x1040) -#define EXYNOS5_DIS_IRQ_FSYS_ARM_CENTRAL_SYS_PWR_REG S5P_PMUREG(0x1048) -#define EXYNOS5_ISP_ARM_SYS_PWR_REG S5P_PMUREG(0x1050) -#define EXYNOS5_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG S5P_PMUREG(0x1054) -#define EXYNOS5_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG S5P_PMUREG(0x1058) -#define EXYNOS5_ARM_COMMON_SYS_PWR_REG S5P_PMUREG(0x1080) -#define EXYNOS5_ARM_L2_SYS_PWR_REG S5P_PMUREG(0x10C0) -#define EXYNOS5_CMU_ACLKSTOP_SYS_PWR_REG S5P_PMUREG(0x1100) -#define EXYNOS5_CMU_SCLKSTOP_SYS_PWR_REG S5P_PMUREG(0x1104) -#define EXYNOS5_CMU_RESET_SYS_PWR_REG S5P_PMUREG(0x110C) -#define EXYNOS5_CMU_ACLKSTOP_SYSMEM_SYS_PWR_REG S5P_PMUREG(0x1120) -#define EXYNOS5_CMU_SCLKSTOP_SYSMEM_SYS_PWR_REG S5P_PMUREG(0x1124) -#define EXYNOS5_CMU_RESET_SYSMEM_SYS_PWR_REG S5P_PMUREG(0x112C) -#define EXYNOS5_DRAM_FREQ_DOWN_SYS_PWR_REG S5P_PMUREG(0x1130) -#define EXYNOS5_DDRPHY_DLLOFF_SYS_PWR_REG S5P_PMUREG(0x1134) -#define EXYNOS5_DDRPHY_DLLLOCK_SYS_PWR_REG S5P_PMUREG(0x1138) -#define EXYNOS5_APLL_SYSCLK_SYS_PWR_REG S5P_PMUREG(0x1140) -#define EXYNOS5_MPLL_SYSCLK_SYS_PWR_REG S5P_PMUREG(0x1144) -#define EXYNOS5_VPLL_SYSCLK_SYS_PWR_REG S5P_PMUREG(0x1148) -#define EXYNOS5_EPLL_SYSCLK_SYS_PWR_REG S5P_PMUREG(0x114C) -#define EXYNOS5_BPLL_SYSCLK_SYS_PWR_REG S5P_PMUREG(0x1150) -#define EXYNOS5_CPLL_SYSCLK_SYS_PWR_REG S5P_PMUREG(0x1154) -#define EXYNOS5_MPLLUSER_SYSCLK_SYS_PWR_REG S5P_PMUREG(0x1164) -#define EXYNOS5_BPLLUSER_SYSCLK_SYS_PWR_REG S5P_PMUREG(0x1170) -#define EXYNOS5_TOP_BUS_SYS_PWR_REG S5P_PMUREG(0x1180) -#define EXYNOS5_TOP_RETENTION_SYS_PWR_REG S5P_PMUREG(0x1184) -#define EXYNOS5_TOP_PWR_SYS_PWR_REG S5P_PMUREG(0x1188) -#define EXYNOS5_TOP_BUS_SYSMEM_SYS_PWR_REG S5P_PMUREG(0x1190) -#define EXYNOS5_TOP_RETENTION_SYSMEM_SYS_PWR_REG S5P_PMUREG(0x1194) -#define EXYNOS5_TOP_PWR_SYSMEM_SYS_PWR_REG S5P_PMUREG(0x1198) -#define EXYNOS5_LOGIC_RESET_SYS_PWR_REG S5P_PMUREG(0x11A0) -#define EXYNOS5_OSCCLK_GATE_SYS_PWR_REG S5P_PMUREG(0x11A4) -#define EXYNOS5_LOGIC_RESET_SYSMEM_SYS_PWR_REG S5P_PMUREG(0x11B0) -#define EXYNOS5_OSCCLK_GATE_SYSMEM_SYS_PWR_REG S5P_PMUREG(0x11B4) -#define EXYNOS5_USBOTG_MEM_SYS_PWR_REG S5P_PMUREG(0x11C0) -#define EXYNOS5_G2D_MEM_SYS_PWR_REG S5P_PMUREG(0x11C8) -#define EXYNOS5_USBDRD_MEM_SYS_PWR_REG S5P_PMUREG(0x11CC) -#define EXYNOS5_SDMMC_MEM_SYS_PWR_REG S5P_PMUREG(0x11D0) -#define EXYNOS5_CSSYS_MEM_SYS_PWR_REG S5P_PMUREG(0x11D4) -#define EXYNOS5_SECSS_MEM_SYS_PWR_REG S5P_PMUREG(0x11D8) -#define EXYNOS5_ROTATOR_MEM_SYS_PWR_REG S5P_PMUREG(0x11DC) -#define EXYNOS5_INTRAM_MEM_SYS_PWR_REG S5P_PMUREG(0x11E0) -#define EXYNOS5_INTROM_MEM_SYS_PWR_REG S5P_PMUREG(0x11E4) -#define EXYNOS5_JPEG_MEM_SYS_PWR_REG S5P_PMUREG(0x11E8) -#define EXYNOS5_HSI_MEM_SYS_PWR_REG S5P_PMUREG(0x11EC) -#define EXYNOS5_MCUIOP_MEM_SYS_PWR_REG S5P_PMUREG(0x11F4) -#define EXYNOS5_SATA_MEM_SYS_PWR_REG S5P_PMUREG(0x11FC) -#define EXYNOS5_PAD_RETENTION_DRAM_SYS_PWR_REG S5P_PMUREG(0x1200) -#define EXYNOS5_PAD_RETENTION_MAU_SYS_PWR_REG S5P_PMUREG(0x1204) -#define EXYNOS5_PAD_RETENTION_EFNAND_SYS_PWR_REG S5P_PMUREG(0x1208) -#define EXYNOS5_PAD_RETENTION_GPIO_SYS_PWR_REG S5P_PMUREG(0x1220) -#define EXYNOS5_PAD_RETENTION_UART_SYS_PWR_REG S5P_PMUREG(0x1224) -#define EXYNOS5_PAD_RETENTION_MMCA_SYS_PWR_REG S5P_PMUREG(0x1228) -#define EXYNOS5_PAD_RETENTION_MMCB_SYS_PWR_REG S5P_PMUREG(0x122C) -#define EXYNOS5_PAD_RETENTION_EBIA_SYS_PWR_REG S5P_PMUREG(0x1230) -#define EXYNOS5_PAD_RETENTION_EBIB_SYS_PWR_REG S5P_PMUREG(0x1234) -#define EXYNOS5_PAD_RETENTION_SPI_SYS_PWR_REG S5P_PMUREG(0x1238) -#define EXYNOS5_PAD_RETENTION_GPIO_SYSMEM_SYS_PWR_REG S5P_PMUREG(0x123C) -#define EXYNOS5_PAD_ISOLATION_SYS_PWR_REG S5P_PMUREG(0x1240) -#define EXYNOS5_PAD_ISOLATION_SYSMEM_SYS_PWR_REG S5P_PMUREG(0x1250) -#define EXYNOS5_PAD_ALV_SEL_SYS_PWR_REG S5P_PMUREG(0x1260) -#define EXYNOS5_XUSBXTI_SYS_PWR_REG S5P_PMUREG(0x1280) -#define EXYNOS5_XXTI_SYS_PWR_REG S5P_PMUREG(0x1284) -#define EXYNOS5_EXT_REGULATOR_SYS_PWR_REG S5P_PMUREG(0x12C0) -#define EXYNOS5_GPIO_MODE_SYS_PWR_REG S5P_PMUREG(0x1300) -#define EXYNOS5_GPIO_MODE_SYSMEM_SYS_PWR_REG S5P_PMUREG(0x1320) -#define EXYNOS5_GPIO_MODE_MAU_SYS_PWR_REG S5P_PMUREG(0x1340) -#define EXYNOS5_TOP_ASB_RESET_SYS_PWR_REG S5P_PMUREG(0x1344) -#define EXYNOS5_TOP_ASB_ISOLATION_SYS_PWR_REG S5P_PMUREG(0x1348) -#define EXYNOS5_GSCL_SYS_PWR_REG S5P_PMUREG(0x1400) -#define EXYNOS5_ISP_SYS_PWR_REG S5P_PMUREG(0x1404) -#define EXYNOS5_MFC_SYS_PWR_REG S5P_PMUREG(0x1408) -#define EXYNOS5_G3D_SYS_PWR_REG S5P_PMUREG(0x140C) -#define EXYNOS5_DISP1_SYS_PWR_REG S5P_PMUREG(0x1414) -#define EXYNOS5_MAU_SYS_PWR_REG S5P_PMUREG(0x1418) -#define EXYNOS5_CMU_CLKSTOP_GSCL_SYS_PWR_REG S5P_PMUREG(0x1480) -#define EXYNOS5_CMU_CLKSTOP_ISP_SYS_PWR_REG S5P_PMUREG(0x1484) -#define EXYNOS5_CMU_CLKSTOP_MFC_SYS_PWR_REG S5P_PMUREG(0x1488) -#define EXYNOS5_CMU_CLKSTOP_G3D_SYS_PWR_REG S5P_PMUREG(0x148C) -#define EXYNOS5_CMU_CLKSTOP_DISP1_SYS_PWR_REG S5P_PMUREG(0x1494) -#define EXYNOS5_CMU_CLKSTOP_MAU_SYS_PWR_REG S5P_PMUREG(0x1498) -#define EXYNOS5_CMU_SYSCLK_GSCL_SYS_PWR_REG S5P_PMUREG(0x14C0) -#define EXYNOS5_CMU_SYSCLK_ISP_SYS_PWR_REG S5P_PMUREG(0x14C4) -#define EXYNOS5_CMU_SYSCLK_MFC_SYS_PWR_REG S5P_PMUREG(0x14C8) -#define EXYNOS5_CMU_SYSCLK_G3D_SYS_PWR_REG S5P_PMUREG(0x14CC) -#define EXYNOS5_CMU_SYSCLK_DISP1_SYS_PWR_REG S5P_PMUREG(0x14D4) -#define EXYNOS5_CMU_SYSCLK_MAU_SYS_PWR_REG S5P_PMUREG(0x14D8) -#define EXYNOS5_CMU_RESET_GSCL_SYS_PWR_REG S5P_PMUREG(0x1580) -#define EXYNOS5_CMU_RESET_ISP_SYS_PWR_REG S5P_PMUREG(0x1584) -#define EXYNOS5_CMU_RESET_MFC_SYS_PWR_REG S5P_PMUREG(0x1588) -#define EXYNOS5_CMU_RESET_G3D_SYS_PWR_REG S5P_PMUREG(0x158C) -#define EXYNOS5_CMU_RESET_DISP1_SYS_PWR_REG S5P_PMUREG(0x1594) -#define EXYNOS5_CMU_RESET_MAU_SYS_PWR_REG S5P_PMUREG(0x1598) - -#define EXYNOS5_ARM_CORE0_OPTION S5P_PMUREG(0x2008) -#define EXYNOS5_ARM_CORE1_OPTION S5P_PMUREG(0x2088) -#define EXYNOS5_FSYS_ARM_OPTION S5P_PMUREG(0x2208) -#define EXYNOS5_ISP_ARM_OPTION S5P_PMUREG(0x2288) -#define EXYNOS5_ARM_COMMON_OPTION S5P_PMUREG(0x2408) -#define EXYNOS5_TOP_PWR_OPTION S5P_PMUREG(0x2C48) -#define EXYNOS5_TOP_PWR_SYSMEM_OPTION S5P_PMUREG(0x2CC8) -#define EXYNOS5_JPEG_MEM_OPTION S5P_PMUREG(0x2F48) -#define EXYNOS5_GSCL_STATUS S5P_PMUREG(0x4004) -#define EXYNOS5_ISP_STATUS S5P_PMUREG(0x4024) -#define EXYNOS5_GSCL_OPTION S5P_PMUREG(0x4008) -#define EXYNOS5_ISP_OPTION S5P_PMUREG(0x4028) -#define EXYNOS5_MFC_OPTION S5P_PMUREG(0x4048) -#define EXYNOS5_G3D_CONFIGURATION S5P_PMUREG(0x4060) -#define EXYNOS5_G3D_STATUS S5P_PMUREG(0x4064) -#define EXYNOS5_G3D_OPTION S5P_PMUREG(0x4068) -#define EXYNOS5_DISP1_OPTION S5P_PMUREG(0x40A8) -#define EXYNOS5_MAU_OPTION S5P_PMUREG(0x40C8) - -#define EXYNOS5_USE_SC_FEEDBACK (1 << 1) -#define EXYNOS5_USE_SC_COUNTER (1 << 0) - -#define EXYNOS5_MANUAL_L2RSTDISABLE_CONTROL (1 << 2) -#define EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN (1 << 7) - -#define EXYNOS5_OPTION_USE_STANDBYWFE (1 << 24) -#define EXYNOS5_OPTION_USE_STANDBYWFI (1 << 16) - -#define EXYNOS5_OPTION_USE_RETENTION (1 << 4) - #endif /* __ASM_ARCH_REGS_PMU_H */ diff --git a/trunk/arch/arm/mach-exynos/mach-nuri.c b/trunk/arch/arm/mach-exynos/mach-nuri.c index 656f8fc9addd..972983e392bc 100644 --- a/trunk/arch/arm/mach-exynos/mach-nuri.c +++ b/trunk/arch/arm/mach-exynos/mach-nuri.c @@ -237,29 +237,25 @@ static struct exynos_drm_fimd_pdata drm_fimd_pdata = { #else /* Frame Buffer */ static struct s3c_fb_pd_win nuri_fb_win0 = { + .win_mode = { + .left_margin = 64, + .right_margin = 16, + .upper_margin = 64, + .lower_margin = 1, + .hsync_len = 48, + .vsync_len = 3, + .xres = 1024, + .yres = 600, + .refresh = 60, + }, .max_bpp = 24, .default_bpp = 16, - .xres = 1024, - .yres = 600, .virtual_x = 1024, .virtual_y = 2 * 600, }; -static struct fb_videomode nuri_lcd_timing = { - .left_margin = 64, - .right_margin = 16, - .upper_margin = 64, - .lower_margin = 1, - .hsync_len = 48, - .vsync_len = 3, - .xres = 1024, - .yres = 600, - .refresh = 60, -}; - static struct s3c_fb_platdata nuri_fb_pdata __initdata = { .win[0] = &nuri_fb_win0, - .vtiming = &nuri_lcd_timing, .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB | VIDCON0_CLKSEL_LCD, .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, diff --git a/trunk/arch/arm/mach-exynos/mach-origen.c b/trunk/arch/arm/mach-exynos/mach-origen.c index f5572be9d7bf..a7f7fd567dde 100644 --- a/trunk/arch/arm/mach-exynos/mach-origen.c +++ b/trunk/arch/arm/mach-exynos/mach-origen.c @@ -604,28 +604,24 @@ static struct exynos_drm_fimd_pdata drm_fimd_pdata = { }; #else static struct s3c_fb_pd_win origen_fb_win0 = { - .xres = 1024, - .yres = 600, + .win_mode = { + .left_margin = 64, + .right_margin = 16, + .upper_margin = 64, + .lower_margin = 16, + .hsync_len = 48, + .vsync_len = 3, + .xres = 1024, + .yres = 600, + }, .max_bpp = 32, .default_bpp = 24, .virtual_x = 1024, .virtual_y = 2 * 600, }; -static struct fb_videomode origen_lcd_timing = { - .left_margin = 64, - .right_margin = 16, - .upper_margin = 64, - .lower_margin = 16, - .hsync_len = 48, - .vsync_len = 3, - .xres = 1024, - .yres = 600, -}; - static struct s3c_fb_platdata origen_lcd_pdata __initdata = { .win[0] = &origen_fb_win0, - .vtiming = &origen_lcd_timing, .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC | VIDCON1_INV_VCLK, diff --git a/trunk/arch/arm/mach-exynos/mach-smdkv310.c b/trunk/arch/arm/mach-exynos/mach-smdkv310.c index 262e9e446a96..70df1a0c2118 100644 --- a/trunk/arch/arm/mach-exynos/mach-smdkv310.c +++ b/trunk/arch/arm/mach-exynos/mach-smdkv310.c @@ -178,26 +178,22 @@ static struct exynos_drm_fimd_pdata drm_fimd_pdata = { }; #else static struct s3c_fb_pd_win smdkv310_fb_win0 = { - .max_bpp = 32, - .default_bpp = 24, - .xres = 800, - .yres = 480, -}; - -static struct fb_videomode smdkv310_lcd_timing = { - .left_margin = 13, - .right_margin = 8, - .upper_margin = 7, - .lower_margin = 5, - .hsync_len = 3, - .vsync_len = 1, - .xres = 800, - .yres = 480, + .win_mode = { + .left_margin = 13, + .right_margin = 8, + .upper_margin = 7, + .lower_margin = 5, + .hsync_len = 3, + .vsync_len = 1, + .xres = 800, + .yres = 480, + }, + .max_bpp = 32, + .default_bpp = 24, }; static struct s3c_fb_platdata smdkv310_lcd0_pdata __initdata = { .win[0] = &smdkv310_fb_win0, - .vtiming = &smdkv310_lcd_timing, .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, .setup_gpio = exynos4_fimd0_gpio_setup_24bpp, diff --git a/trunk/arch/arm/mach-exynos/mach-universal_c210.c b/trunk/arch/arm/mach-exynos/mach-universal_c210.c index cd92fa86ba41..083b44de9c10 100644 --- a/trunk/arch/arm/mach-exynos/mach-universal_c210.c +++ b/trunk/arch/arm/mach-exynos/mach-universal_c210.c @@ -843,29 +843,25 @@ static struct exynos_drm_fimd_pdata drm_fimd_pdata = { #else /* Frame Buffer */ static struct s3c_fb_pd_win universal_fb_win0 = { + .win_mode = { + .left_margin = 16, + .right_margin = 16, + .upper_margin = 2, + .lower_margin = 28, + .hsync_len = 2, + .vsync_len = 1, + .xres = 480, + .yres = 800, + .refresh = 55, + }, .max_bpp = 32, .default_bpp = 16, - .xres = 480, - .yres = 800, .virtual_x = 480, .virtual_y = 2 * 800, }; -static struct fb_videomode universal_lcd_timing = { - .left_margin = 16, - .right_margin = 16, - .upper_margin = 2, - .lower_margin = 28, - .hsync_len = 2, - .vsync_len = 1, - .xres = 480, - .yres = 800, - .refresh = 55, -}; - static struct s3c_fb_platdata universal_lcd_pdata __initdata = { .win[0] = &universal_fb_win0, - .vtiming = &universal_lcd_timing, .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB | VIDCON0_CLKSEL_LCD, .vidcon1 = VIDCON1_INV_VCLK | VIDCON1_INV_VDEN diff --git a/trunk/arch/arm/mach-exynos/pm.c b/trunk/arch/arm/mach-exynos/pm.c index c06c992943a1..563dea9a6dbb 100644 --- a/trunk/arch/arm/mach-exynos/pm.c +++ b/trunk/arch/arm/mach-exynos/pm.c @@ -1,8 +1,9 @@ -/* - * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd. +/* linux/arch/arm/mach-exynos4/pm.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * EXYNOS - Power Management support + * EXYNOS4210 - Power Management support * * Based on arch/arm/mach-s3c2410/pm.c * Copyright (c) 2006 Simtec Electronics @@ -62,7 +63,90 @@ static struct sleep_save exynos4_vpll_save[] = { SAVE_ITEM(EXYNOS4_VPLL_CON1), }; -static struct sleep_save exynos_core_save[] = { +static struct sleep_save exynos4_core_save[] = { + /* GIC side */ + SAVE_ITEM(S5P_VA_GIC_CPU + 0x000), + SAVE_ITEM(S5P_VA_GIC_CPU + 0x004), + SAVE_ITEM(S5P_VA_GIC_CPU + 0x008), + SAVE_ITEM(S5P_VA_GIC_CPU + 0x00C), + SAVE_ITEM(S5P_VA_GIC_CPU + 0x014), + SAVE_ITEM(S5P_VA_GIC_CPU + 0x018), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x000), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x004), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x100), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x104), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x108), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x300), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x304), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x308), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x400), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x404), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x408), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x40C), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x410), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x414), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x418), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x41C), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x420), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x424), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x428), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x42C), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x430), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x434), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x438), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x43C), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x440), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x444), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x448), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x44C), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x450), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x454), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x458), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x45C), + + SAVE_ITEM(S5P_VA_GIC_DIST + 0x800), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x804), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x808), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x80C), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x810), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x814), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x818), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x81C), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x820), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x824), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x828), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x82C), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x830), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x834), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x838), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x83C), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x840), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x844), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x848), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x84C), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x850), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x854), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x858), + SAVE_ITEM(S5P_VA_GIC_DIST + 0x85C), + + SAVE_ITEM(S5P_VA_GIC_DIST + 0xC00), + SAVE_ITEM(S5P_VA_GIC_DIST + 0xC04), + SAVE_ITEM(S5P_VA_GIC_DIST + 0xC08), + SAVE_ITEM(S5P_VA_GIC_DIST + 0xC0C), + SAVE_ITEM(S5P_VA_GIC_DIST + 0xC10), + SAVE_ITEM(S5P_VA_GIC_DIST + 0xC14), + + SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x000), + SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x010), + SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x020), + SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x030), + SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x040), + SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x050), + SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x060), + SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x070), + SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x080), + SAVE_ITEM(S5P_VA_COMBINER_BASE + 0x090), + /* SROM side */ SAVE_ITEM(S5P_SROM_BW), SAVE_ITEM(S5P_SROM_BC0), @@ -75,11 +159,9 @@ static struct sleep_save exynos_core_save[] = { /* For Cortex-A9 Diagnostic and Power control register */ static unsigned int save_arm_register[2]; -static int exynos_cpu_suspend(unsigned long arg) +static int exynos4_cpu_suspend(unsigned long arg) { -#ifdef CONFIG_CACHE_L2X0 outer_flush_all(); -#endif /* issue the standby signal into the pm unit. */ cpu_do_idle(); @@ -88,25 +170,19 @@ static int exynos_cpu_suspend(unsigned long arg) panic("sleep resumed to originator?"); } -static void exynos_pm_prepare(void) +static void exynos4_pm_prepare(void) { - unsigned int tmp; + u32 tmp; - s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); + s3c_pm_do_save(exynos4_core_save, ARRAY_SIZE(exynos4_core_save)); + s3c_pm_do_save(exynos4_epll_save, ARRAY_SIZE(exynos4_epll_save)); + s3c_pm_do_save(exynos4_vpll_save, ARRAY_SIZE(exynos4_vpll_save)); - if (!soc_is_exynos5250()) { - s3c_pm_do_save(exynos4_epll_save, ARRAY_SIZE(exynos4_epll_save)); - s3c_pm_do_save(exynos4_vpll_save, ARRAY_SIZE(exynos4_vpll_save)); - } else { - /* Disable USE_RETENTION of JPEG_MEM_OPTION */ - tmp = __raw_readl(EXYNOS5_JPEG_MEM_OPTION); - tmp &= ~EXYNOS5_OPTION_USE_RETENTION; - __raw_writel(tmp, EXYNOS5_JPEG_MEM_OPTION); - } + tmp = __raw_readl(S5P_INFORM1); /* Set value of power down register for sleep mode */ - exynos_sys_powerdown_conf(SYS_SLEEP); + exynos4_sys_powerdown_conf(SYS_SLEEP); __raw_writel(S5P_CHECK_SLEEP, S5P_INFORM1); /* ensure at least INFORM0 has the resume address */ @@ -115,18 +191,17 @@ static void exynos_pm_prepare(void) /* Before enter central sequence mode, clock src register have to set */ - if (!soc_is_exynos5250()) - s3c_pm_do_restore_core(exynos4_set_clksrc, ARRAY_SIZE(exynos4_set_clksrc)); + s3c_pm_do_restore_core(exynos4_set_clksrc, ARRAY_SIZE(exynos4_set_clksrc)); if (soc_is_exynos4210()) s3c_pm_do_restore_core(exynos4210_set_clksrc, ARRAY_SIZE(exynos4210_set_clksrc)); } -static int exynos_pm_add(struct device *dev, struct subsys_interface *sif) +static int exynos4_pm_add(struct device *dev, struct subsys_interface *sif) { - pm_cpu_prep = exynos_pm_prepare; - pm_cpu_sleep = exynos_cpu_suspend; + pm_cpu_prep = exynos4_pm_prepare; + pm_cpu_sleep = exynos4_cpu_suspend; return 0; } @@ -198,13 +273,13 @@ static void exynos4_restore_pll(void) } while (epll_wait || vpll_wait); } -static struct subsys_interface exynos_pm_interface = { - .name = "exynos_pm", +static struct subsys_interface exynos4_pm_interface = { + .name = "exynos4_pm", .subsys = &exynos_subsys, - .add_dev = exynos_pm_add, + .add_dev = exynos4_pm_add, }; -static __init int exynos_pm_drvinit(void) +static __init int exynos4_pm_drvinit(void) { struct clk *pll_base; unsigned int tmp; @@ -217,20 +292,18 @@ static __init int exynos_pm_drvinit(void) tmp |= ((0xFF << 8) | (0x1F << 1)); __raw_writel(tmp, S5P_WAKEUP_MASK); - if (!soc_is_exynos5250()) { - pll_base = clk_get(NULL, "xtal"); + pll_base = clk_get(NULL, "xtal"); - if (!IS_ERR(pll_base)) { - pll_base_rate = clk_get_rate(pll_base); - clk_put(pll_base); - } + if (!IS_ERR(pll_base)) { + pll_base_rate = clk_get_rate(pll_base); + clk_put(pll_base); } - return subsys_interface_register(&exynos_pm_interface); + return subsys_interface_register(&exynos4_pm_interface); } -arch_initcall(exynos_pm_drvinit); +arch_initcall(exynos4_pm_drvinit); -static int exynos_pm_suspend(void) +static int exynos4_pm_suspend(void) { unsigned long tmp; @@ -240,27 +313,27 @@ static int exynos_pm_suspend(void) tmp &= ~S5P_CENTRAL_LOWPWR_CFG; __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION); - /* Setting SEQ_OPTION register */ - - tmp = (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0); - __raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION); + if (soc_is_exynos4212() || soc_is_exynos4412()) { + tmp = __raw_readl(S5P_CENTRAL_SEQ_OPTION); + tmp &= ~(S5P_USE_STANDBYWFI_ISP_ARM | + S5P_USE_STANDBYWFE_ISP_ARM); + __raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION); + } - if (!soc_is_exynos5250()) { - /* Save Power control register */ - asm ("mrc p15, 0, %0, c15, c0, 0" - : "=r" (tmp) : : "cc"); - save_arm_register[0] = tmp; + /* Save Power control register */ + asm ("mrc p15, 0, %0, c15, c0, 0" + : "=r" (tmp) : : "cc"); + save_arm_register[0] = tmp; - /* Save Diagnostic register */ - asm ("mrc p15, 0, %0, c15, c0, 1" - : "=r" (tmp) : : "cc"); - save_arm_register[1] = tmp; - } + /* Save Diagnostic register */ + asm ("mrc p15, 0, %0, c15, c0, 1" + : "=r" (tmp) : : "cc"); + save_arm_register[1] = tmp; return 0; } -static void exynos_pm_resume(void) +static void exynos4_pm_resume(void) { unsigned long tmp; @@ -277,19 +350,17 @@ static void exynos_pm_resume(void) /* No need to perform below restore code */ goto early_wakeup; } - if (!soc_is_exynos5250()) { - /* Restore Power control register */ - tmp = save_arm_register[0]; - asm volatile ("mcr p15, 0, %0, c15, c0, 0" - : : "r" (tmp) - : "cc"); - - /* Restore Diagnostic register */ - tmp = save_arm_register[1]; - asm volatile ("mcr p15, 0, %0, c15, c0, 1" - : : "r" (tmp) - : "cc"); - } + /* Restore Power control register */ + tmp = save_arm_register[0]; + asm volatile ("mcr p15, 0, %0, c15, c0, 0" + : : "r" (tmp) + : "cc"); + + /* Restore Diagnostic register */ + tmp = save_arm_register[1]; + asm volatile ("mcr p15, 0, %0, c15, c0, 1" + : : "r" (tmp) + : "cc"); /* For release retention */ @@ -301,28 +372,26 @@ static void exynos_pm_resume(void) __raw_writel((1 << 28), S5P_PAD_RET_EBIA_OPTION); __raw_writel((1 << 28), S5P_PAD_RET_EBIB_OPTION); - s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); + s3c_pm_do_restore_core(exynos4_core_save, ARRAY_SIZE(exynos4_core_save)); - if (!soc_is_exynos5250()) { - exynos4_restore_pll(); + exynos4_restore_pll(); #ifdef CONFIG_SMP - scu_enable(S5P_VA_SCU); + scu_enable(S5P_VA_SCU); #endif - } early_wakeup: return; } -static struct syscore_ops exynos_pm_syscore_ops = { - .suspend = exynos_pm_suspend, - .resume = exynos_pm_resume, +static struct syscore_ops exynos4_pm_syscore_ops = { + .suspend = exynos4_pm_suspend, + .resume = exynos4_pm_resume, }; -static __init int exynos_pm_syscore_init(void) +static __init int exynos4_pm_syscore_init(void) { - register_syscore_ops(&exynos_pm_syscore_ops); + register_syscore_ops(&exynos4_pm_syscore_ops); return 0; } -arch_initcall(exynos_pm_syscore_init); +arch_initcall(exynos4_pm_syscore_init); diff --git a/trunk/arch/arm/mach-exynos/pmu.c b/trunk/arch/arm/mach-exynos/pmu.c index 4aacb66f7161..77c6815eebee 100644 --- a/trunk/arch/arm/mach-exynos/pmu.c +++ b/trunk/arch/arm/mach-exynos/pmu.c @@ -1,8 +1,9 @@ -/* - * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd. +/* linux/arch/arm/mach-exynos4/pmu.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * - * EXYNOS - CPU PMU(Power Management Unit) support + * EXYNOS4210 - CPU PMU(Power Management Unit) support * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -11,14 +12,13 @@ #include #include -#include #include #include -static struct exynos_pmu_conf *exynos_pmu_config; +static struct exynos4_pmu_conf *exynos4_pmu_config; -static struct exynos_pmu_conf exynos4210_pmu_config[] = { +static struct exynos4_pmu_conf exynos4210_pmu_config[] = { /* { .reg = address, .val = { AFTR, LPA, SLEEP } */ { S5P_ARM_CORE0_LOWPWR, { 0x0, 0x0, 0x2 } }, { S5P_DIS_IRQ_CORE0, { 0x0, 0x0, 0x0 } }, @@ -94,7 +94,7 @@ static struct exynos_pmu_conf exynos4210_pmu_config[] = { { PMU_TABLE_END,}, }; -static struct exynos_pmu_conf exynos4x12_pmu_config[] = { +static struct exynos4_pmu_conf exynos4x12_pmu_config[] = { { S5P_ARM_CORE0_LOWPWR, { 0x0, 0x0, 0x2 } }, { S5P_DIS_IRQ_CORE0, { 0x0, 0x0, 0x0 } }, { S5P_DIS_IRQ_CENTRAL0, { 0x0, 0x0, 0x0 } }, @@ -202,7 +202,7 @@ static struct exynos_pmu_conf exynos4x12_pmu_config[] = { { PMU_TABLE_END,}, }; -static struct exynos_pmu_conf exynos4412_pmu_config[] = { +static struct exynos4_pmu_conf exynos4412_pmu_config[] = { { S5P_ARM_CORE2_LOWPWR, { 0x0, 0x0, 0x2 } }, { S5P_DIS_IRQ_CORE2, { 0x0, 0x0, 0x0 } }, { S5P_DIS_IRQ_CENTRAL2, { 0x0, 0x0, 0x0 } }, @@ -212,174 +212,13 @@ static struct exynos_pmu_conf exynos4412_pmu_config[] = { { PMU_TABLE_END,}, }; -static struct exynos_pmu_conf exynos5250_pmu_config[] = { - /* { .reg = address, .val = { AFTR, LPA, SLEEP } */ - { EXYNOS5_ARM_CORE0_SYS_PWR_REG, { 0x0, 0x0, 0x2} }, - { EXYNOS5_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, - { EXYNOS5_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, - { EXYNOS5_ARM_CORE1_SYS_PWR_REG, { 0x0, 0x0, 0x2} }, - { EXYNOS5_DIS_IRQ_ARM_CORE1_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, - { EXYNOS5_DIS_IRQ_ARM_CORE1_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, - { EXYNOS5_FSYS_ARM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_DIS_IRQ_FSYS_ARM_CENTRAL_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, - { EXYNOS5_ISP_ARM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, - { EXYNOS5_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, - { EXYNOS5_ARM_COMMON_SYS_PWR_REG, { 0x0, 0x0, 0x2} }, - { EXYNOS5_ARM_L2_SYS_PWR_REG, { 0x3, 0x3, 0x3} }, - { EXYNOS5_CMU_ACLKSTOP_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, - { EXYNOS5_CMU_SCLKSTOP_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, - { EXYNOS5_CMU_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, - { EXYNOS5_CMU_ACLKSTOP_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, - { EXYNOS5_CMU_SCLKSTOP_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, - { EXYNOS5_CMU_RESET_SYSMEM_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, - { EXYNOS5_DRAM_FREQ_DOWN_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, - { EXYNOS5_DDRPHY_DLLOFF_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, - { EXYNOS5_DDRPHY_DLLLOCK_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, - { EXYNOS5_APLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_MPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_VPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_EPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, - { EXYNOS5_BPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_CPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_MPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_BPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_TOP_BUS_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, - { EXYNOS5_TOP_RETENTION_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, - { EXYNOS5_TOP_PWR_SYS_PWR_REG, { 0x3, 0x0, 0x3} }, - { EXYNOS5_TOP_BUS_SYSMEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, - { EXYNOS5_TOP_RETENTION_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, - { EXYNOS5_TOP_PWR_SYSMEM_SYS_PWR_REG, { 0x3, 0x0, 0x3} }, - { EXYNOS5_LOGIC_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, - { EXYNOS5_OSCCLK_GATE_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, - { EXYNOS5_LOGIC_RESET_SYSMEM_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, - { EXYNOS5_OSCCLK_GATE_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, - { EXYNOS5_USBOTG_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, - { EXYNOS5_G2D_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, - { EXYNOS5_USBDRD_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, - { EXYNOS5_SDMMC_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, - { EXYNOS5_CSSYS_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, - { EXYNOS5_SECSS_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, - { EXYNOS5_ROTATOR_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, - { EXYNOS5_INTRAM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, - { EXYNOS5_INTROM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, - { EXYNOS5_JPEG_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, - { EXYNOS5_HSI_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, - { EXYNOS5_MCUIOP_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, - { EXYNOS5_SATA_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, - { EXYNOS5_PAD_RETENTION_DRAM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_PAD_RETENTION_MAU_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, - { EXYNOS5_PAD_RETENTION_GPIO_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_PAD_RETENTION_UART_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_PAD_RETENTION_MMCA_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_PAD_RETENTION_MMCB_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_PAD_RETENTION_EBIA_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_PAD_RETENTION_EBIB_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_PAD_RETENTION_SPI_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_PAD_RETENTION_GPIO_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_PAD_ISOLATION_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_PAD_ISOLATION_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_PAD_ALV_SEL_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_XUSBXTI_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, - { EXYNOS5_XXTI_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, - { EXYNOS5_EXT_REGULATOR_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, - { EXYNOS5_GPIO_MODE_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_GPIO_MODE_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_GPIO_MODE_MAU_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, - { EXYNOS5_TOP_ASB_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, - { EXYNOS5_TOP_ASB_ISOLATION_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, - { EXYNOS5_GSCL_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, - { EXYNOS5_ISP_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, - { EXYNOS5_MFC_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, - { EXYNOS5_G3D_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, - { EXYNOS5_DISP1_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, - { EXYNOS5_MAU_SYS_PWR_REG, { 0x7, 0x7, 0x0} }, - { EXYNOS5_CMU_CLKSTOP_GSCL_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_CMU_CLKSTOP_ISP_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_CMU_CLKSTOP_MFC_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_CMU_CLKSTOP_G3D_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_CMU_CLKSTOP_DISP1_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_CMU_CLKSTOP_MAU_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, - { EXYNOS5_CMU_SYSCLK_GSCL_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_CMU_SYSCLK_ISP_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_CMU_SYSCLK_MFC_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_CMU_SYSCLK_G3D_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_CMU_SYSCLK_DISP1_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_CMU_SYSCLK_MAU_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, - { EXYNOS5_CMU_RESET_GSCL_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_CMU_RESET_ISP_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_CMU_RESET_MFC_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_CMU_RESET_G3D_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_CMU_RESET_DISP1_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, - { EXYNOS5_CMU_RESET_MAU_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, - { PMU_TABLE_END,}, -}; - -void __iomem *exynos5_list_both_cnt_feed[] = { - EXYNOS5_ARM_CORE0_OPTION, - EXYNOS5_ARM_CORE1_OPTION, - EXYNOS5_ARM_COMMON_OPTION, - EXYNOS5_GSCL_OPTION, - EXYNOS5_ISP_OPTION, - EXYNOS5_MFC_OPTION, - EXYNOS5_G3D_OPTION, - EXYNOS5_DISP1_OPTION, - EXYNOS5_MAU_OPTION, - EXYNOS5_TOP_PWR_OPTION, - EXYNOS5_TOP_PWR_SYSMEM_OPTION, -}; - -void __iomem *exynos5_list_diable_wfi_wfe[] = { - EXYNOS5_ARM_CORE1_OPTION, - EXYNOS5_FSYS_ARM_OPTION, - EXYNOS5_ISP_ARM_OPTION, -}; - -static void exynos5_init_pmu(void) +void exynos4_sys_powerdown_conf(enum sys_powerdown mode) { unsigned int i; - unsigned int tmp; - - /* - * Enable both SC_FEEDBACK and SC_COUNTER - */ - for (i = 0 ; i < ARRAY_SIZE(exynos5_list_both_cnt_feed) ; i++) { - tmp = __raw_readl(exynos5_list_both_cnt_feed[i]); - tmp |= (EXYNOS5_USE_SC_FEEDBACK | - EXYNOS5_USE_SC_COUNTER); - __raw_writel(tmp, exynos5_list_both_cnt_feed[i]); - } - - /* - * SKIP_DEACTIVATE_ACEACP_IN_PWDN_BITFIELD Enable - * MANUAL_L2RSTDISABLE_CONTROL_BITFIELD Enable - */ - tmp = __raw_readl(EXYNOS5_ARM_COMMON_OPTION); - tmp |= (EXYNOS5_MANUAL_L2RSTDISABLE_CONTROL | - EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN); - __raw_writel(tmp, EXYNOS5_ARM_COMMON_OPTION); - - /* - * Disable WFI/WFE on XXX_OPTION - */ - for (i = 0 ; i < ARRAY_SIZE(exynos5_list_diable_wfi_wfe) ; i++) { - tmp = __raw_readl(exynos5_list_diable_wfi_wfe[i]); - tmp &= ~(EXYNOS5_OPTION_USE_STANDBYWFE | - EXYNOS5_OPTION_USE_STANDBYWFI); - __raw_writel(tmp, exynos5_list_diable_wfi_wfe[i]); - } -} - -void exynos_sys_powerdown_conf(enum sys_powerdown mode) -{ - unsigned int i; - - if (soc_is_exynos5250()) - exynos5_init_pmu(); - for (i = 0; (exynos_pmu_config[i].reg != PMU_TABLE_END) ; i++) - __raw_writel(exynos_pmu_config[i].val[mode], - exynos_pmu_config[i].reg); + for (i = 0; (exynos4_pmu_config[i].reg != PMU_TABLE_END) ; i++) + __raw_writel(exynos4_pmu_config[i].val[mode], + exynos4_pmu_config[i].reg); if (soc_is_exynos4412()) { for (i = 0; exynos4412_pmu_config[i].reg != PMU_TABLE_END ; i++) @@ -388,23 +227,20 @@ void exynos_sys_powerdown_conf(enum sys_powerdown mode) } } -static int __init exynos_pmu_init(void) +static int __init exynos4_pmu_init(void) { - exynos_pmu_config = exynos4210_pmu_config; + exynos4_pmu_config = exynos4210_pmu_config; if (soc_is_exynos4210()) { - exynos_pmu_config = exynos4210_pmu_config; + exynos4_pmu_config = exynos4210_pmu_config; pr_info("EXYNOS4210 PMU Initialize\n"); } else if (soc_is_exynos4212() || soc_is_exynos4412()) { - exynos_pmu_config = exynos4x12_pmu_config; + exynos4_pmu_config = exynos4x12_pmu_config; pr_info("EXYNOS4x12 PMU Initialize\n"); - } else if (soc_is_exynos5250()) { - exynos_pmu_config = exynos5250_pmu_config; - pr_info("EXYNOS5250 PMU Initialize\n"); } else { - pr_info("EXYNOS: PMU not supported\n"); + pr_info("EXYNOS4: PMU not supported\n"); } return 0; } -arch_initcall(exynos_pmu_init); +arch_initcall(exynos4_pmu_init); diff --git a/trunk/arch/arm/mach-imx/imx27-dt.c b/trunk/arch/arm/mach-imx/imx27-dt.c index eee0cc8d92a4..ed38d03c61f2 100644 --- a/trunk/arch/arm/mach-imx/imx27-dt.c +++ b/trunk/arch/arm/mach-imx/imx27-dt.c @@ -29,7 +29,6 @@ static const struct of_dev_auxdata imx27_auxdata_lookup[] __initconst = { OF_DEV_AUXDATA("fsl,imx27-cspi", MX27_CSPI2_BASE_ADDR, "imx27-cspi.1", NULL), OF_DEV_AUXDATA("fsl,imx27-cspi", MX27_CSPI3_BASE_ADDR, "imx27-cspi.2", NULL), OF_DEV_AUXDATA("fsl,imx27-wdt", MX27_WDOG_BASE_ADDR, "imx2-wdt.0", NULL), - OF_DEV_AUXDATA("fsl,imx27-nand", MX27_NFC_BASE_ADDR, "mxc_nand.0", NULL), { /* sentinel */ } }; diff --git a/trunk/arch/arm/mach-ixp4xx/common.c b/trunk/arch/arm/mach-ixp4xx/common.c index a9f80943d01f..ebbd7fc90eb4 100644 --- a/trunk/arch/arm/mach-ixp4xx/common.c +++ b/trunk/arch/arm/mach-ixp4xx/common.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -108,7 +107,7 @@ static signed char irq2gpio[32] = { 7, 8, 9, 10, 11, 12, -1, -1, }; -static int ixp4xx_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) +int gpio_to_irq(int gpio) { int irq; @@ -118,6 +117,7 @@ static int ixp4xx_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) } return -EINVAL; } +EXPORT_SYMBOL(gpio_to_irq); int irq_to_gpio(unsigned int irq) { @@ -383,56 +383,12 @@ static struct platform_device *ixp46x_devices[] __initdata = { unsigned long ixp4xx_exp_bus_size; EXPORT_SYMBOL(ixp4xx_exp_bus_size); -static int ixp4xx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) -{ - gpio_line_config(gpio, IXP4XX_GPIO_IN); - - return 0; -} - -static int ixp4xx_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, - int level) -{ - gpio_line_set(gpio, level); - gpio_line_config(gpio, IXP4XX_GPIO_OUT); - - return 0; -} - -static int ixp4xx_gpio_get_value(struct gpio_chip *chip, unsigned gpio) -{ - int value; - - gpio_line_get(gpio, &value); - - return value; -} - -static void ixp4xx_gpio_set_value(struct gpio_chip *chip, unsigned gpio, - int value) -{ - gpio_line_set(gpio, value); -} - -static struct gpio_chip ixp4xx_gpio_chip = { - .label = "IXP4XX_GPIO_CHIP", - .direction_input = ixp4xx_gpio_direction_input, - .direction_output = ixp4xx_gpio_direction_output, - .get = ixp4xx_gpio_get_value, - .set = ixp4xx_gpio_set_value, - .to_irq = ixp4xx_gpio_to_irq, - .base = 0, - .ngpio = 16, -}; - void __init ixp4xx_sys_init(void) { ixp4xx_exp_bus_size = SZ_16M; platform_add_devices(ixp4xx_devices, ARRAY_SIZE(ixp4xx_devices)); - gpiochip_add(&ixp4xx_gpio_chip); - if (cpu_is_ixp46x()) { int region; diff --git a/trunk/arch/arm/mach-ixp4xx/include/mach/gpio.h b/trunk/arch/arm/mach-ixp4xx/include/mach/gpio.h index ef37f2635b0e..83d6b4ed60bb 100644 --- a/trunk/arch/arm/mach-ixp4xx/include/mach/gpio.h +++ b/trunk/arch/arm/mach-ixp4xx/include/mach/gpio.h @@ -1,2 +1,79 @@ -/* empty */ +/* + * arch/arm/mach-ixp4xx/include/mach/gpio.h + * + * IXP4XX GPIO wrappers for arch-neutral GPIO calls + * + * Written by Milan Svoboda + * Based on PXA implementation by Philipp Zabel + * + * 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 __ASM_ARCH_IXP4XX_GPIO_H +#define __ASM_ARCH_IXP4XX_GPIO_H + +#include +#include + +#define __ARM_GPIOLIB_COMPLEX + +static inline int gpio_request(unsigned gpio, const char *label) +{ + return 0; +} + +static inline void gpio_free(unsigned gpio) +{ + might_sleep(); + + return; +} + +static inline int gpio_direction_input(unsigned gpio) +{ + gpio_line_config(gpio, IXP4XX_GPIO_IN); + return 0; +} + +static inline int gpio_direction_output(unsigned gpio, int level) +{ + gpio_line_set(gpio, level); + gpio_line_config(gpio, IXP4XX_GPIO_OUT); + return 0; +} + +static inline int gpio_get_value(unsigned gpio) +{ + int value; + + gpio_line_get(gpio, &value); + + return value; +} + +static inline void gpio_set_value(unsigned gpio, int value) +{ + gpio_line_set(gpio, value); +} + +#include /* cansleep wrappers */ + +extern int gpio_to_irq(int gpio); +#define gpio_to_irq gpio_to_irq +extern int irq_to_gpio(unsigned int irq); + +#endif diff --git a/trunk/arch/arm/mach-ixp4xx/ixdp425-setup.c b/trunk/arch/arm/mach-ixp4xx/ixdp425-setup.c index 108a9d3f382d..3d742aee1773 100644 --- a/trunk/arch/arm/mach-ixp4xx/ixdp425-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/ixdp425-setup.c @@ -60,6 +60,8 @@ static struct platform_device ixdp425_flash = { #if defined(CONFIG_MTD_NAND_PLATFORM) || \ defined(CONFIG_MTD_NAND_PLATFORM_MODULE) +const char *part_probes[] = { "cmdlinepart", NULL }; + static struct mtd_partition ixdp425_partitions[] = { { .name = "ixp400 NAND FS 0", @@ -98,6 +100,8 @@ static struct platform_nand_data ixdp425_flash_nand_data = { .chip = { .nr_chips = 1, .chip_delay = 30, + .options = NAND_NO_AUTOINCR, + .part_probe_types = part_probes, .partitions = ixdp425_partitions, .nr_partitions = ARRAY_SIZE(ixdp425_partitions), }, diff --git a/trunk/arch/arm/mach-nomadik/board-nhk8815.c b/trunk/arch/arm/mach-nomadik/board-nhk8815.c index 2e8d3e176bc7..58cacafcf662 100644 --- a/trunk/arch/arm/mach-nomadik/board-nhk8815.c +++ b/trunk/arch/arm/mach-nomadik/board-nhk8815.c @@ -111,7 +111,7 @@ static struct nomadik_nand_platform_data nhk8815_nand_data = { .parts = nhk8815_partitions, .nparts = ARRAY_SIZE(nhk8815_partitions), .options = NAND_COPYBACK | NAND_CACHEPRG | NAND_NO_PADDING \ - | NAND_NO_READRDY, + | NAND_NO_READRDY | NAND_NO_AUTOINCR, .init = nhk8815_nand_init, }; diff --git a/trunk/arch/arm/mach-omap1/board-fsample.c b/trunk/arch/arm/mach-omap1/board-fsample.c index 6872f3fd400f..c7364fdbda05 100644 --- a/trunk/arch/arm/mach-omap1/board-fsample.c +++ b/trunk/arch/arm/mach-omap1/board-fsample.c @@ -192,11 +192,14 @@ static int nand_dev_ready(struct mtd_info *mtd) return gpio_get_value(FSAMPLE_NAND_RB_GPIO_PIN); } +static const char *part_probes[] = { "cmdlinepart", NULL }; + static struct platform_nand_data nand_data = { .chip = { .nr_chips = 1, .chip_offset = 0, .options = NAND_SAMSUNG_LP_OPTIONS, + .part_probe_types = part_probes, }, .ctrl = { .cmd_ctrl = omap1_nand_cmd_ctl, diff --git a/trunk/arch/arm/mach-omap1/board-h2.c b/trunk/arch/arm/mach-omap1/board-h2.c index a28e989a63f4..7e503686f7af 100644 --- a/trunk/arch/arm/mach-omap1/board-h2.c +++ b/trunk/arch/arm/mach-omap1/board-h2.c @@ -186,6 +186,8 @@ static int h2_nand_dev_ready(struct mtd_info *mtd) return gpio_get_value(H2_NAND_RB_GPIO_PIN); } +static const char *h2_part_probes[] = { "cmdlinepart", NULL }; + static struct platform_nand_data h2_nand_platdata = { .chip = { .nr_chips = 1, @@ -193,6 +195,7 @@ static struct platform_nand_data h2_nand_platdata = { .nr_partitions = ARRAY_SIZE(h2_nand_partitions), .partitions = h2_nand_partitions, .options = NAND_SAMSUNG_LP_OPTIONS, + .part_probe_types = h2_part_probes, }, .ctrl = { .cmd_ctrl = omap1_nand_cmd_ctl, diff --git a/trunk/arch/arm/mach-omap1/board-h3.c b/trunk/arch/arm/mach-omap1/board-h3.c index 108a8640fc6f..9fb03f189d93 100644 --- a/trunk/arch/arm/mach-omap1/board-h3.c +++ b/trunk/arch/arm/mach-omap1/board-h3.c @@ -188,6 +188,8 @@ static int nand_dev_ready(struct mtd_info *mtd) return gpio_get_value(H3_NAND_RB_GPIO_PIN); } +static const char *part_probes[] = { "cmdlinepart", NULL }; + static struct platform_nand_data nand_platdata = { .chip = { .nr_chips = 1, @@ -195,6 +197,7 @@ static struct platform_nand_data nand_platdata = { .nr_partitions = ARRAY_SIZE(nand_partitions), .partitions = nand_partitions, .options = NAND_SAMSUNG_LP_OPTIONS, + .part_probe_types = part_probes, }, .ctrl = { .cmd_ctrl = omap1_nand_cmd_ctl, diff --git a/trunk/arch/arm/mach-omap1/board-perseus2.c b/trunk/arch/arm/mach-omap1/board-perseus2.c index 703d55ecffe2..f2cb24387c22 100644 --- a/trunk/arch/arm/mach-omap1/board-perseus2.c +++ b/trunk/arch/arm/mach-omap1/board-perseus2.c @@ -150,11 +150,14 @@ static int nand_dev_ready(struct mtd_info *mtd) return gpio_get_value(P2_NAND_RB_GPIO_PIN); } +static const char *part_probes[] = { "cmdlinepart", NULL }; + static struct platform_nand_data nand_data = { .chip = { .nr_chips = 1, .chip_offset = 0, .options = NAND_SAMSUNG_LP_OPTIONS, + .part_probe_types = part_probes, }, .ctrl = { .cmd_ctrl = omap1_nand_cmd_ctl, diff --git a/trunk/arch/arm/mach-omap2/display.c b/trunk/arch/arm/mach-omap2/display.c index 54d49ddb9b81..db5a88a36c63 100644 --- a/trunk/arch/arm/mach-omap2/display.c +++ b/trunk/arch/arm/mach-omap2/display.c @@ -180,133 +180,16 @@ static void omap_dsi_disable_pads(int dsi_id, unsigned lane_mask) omap4_dsi_mux_pads(dsi_id, 0); } -static int omap_dss_set_min_bus_tput(struct device *dev, unsigned long tput) -{ - return omap_pm_set_min_bus_tput(dev, OCP_INITIATOR_AGENT, tput); -} - -static struct platform_device *create_dss_pdev(const char *pdev_name, - int pdev_id, const char *oh_name, void *pdata, int pdata_len, - struct platform_device *parent) -{ - struct platform_device *pdev; - struct omap_device *od; - struct omap_hwmod *ohs[1]; - struct omap_hwmod *oh; - int r; - - oh = omap_hwmod_lookup(oh_name); - if (!oh) { - pr_err("Could not look up %s\n", oh_name); - r = -ENODEV; - goto err; - } - - pdev = platform_device_alloc(pdev_name, pdev_id); - if (!pdev) { - pr_err("Could not create pdev for %s\n", pdev_name); - r = -ENOMEM; - goto err; - } - - if (parent != NULL) - pdev->dev.parent = &parent->dev; - - if (pdev->id != -1) - dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); - else - dev_set_name(&pdev->dev, "%s", pdev->name); - - ohs[0] = oh; - od = omap_device_alloc(pdev, ohs, 1, NULL, 0); - if (!od) { - pr_err("Could not alloc omap_device for %s\n", pdev_name); - r = -ENOMEM; - goto err; - } - - r = platform_device_add_data(pdev, pdata, pdata_len); - if (r) { - pr_err("Could not set pdata for %s\n", pdev_name); - goto err; - } - - r = omap_device_register(pdev); - if (r) { - pr_err("Could not register omap_device for %s\n", pdev_name); - goto err; - } - - return pdev; - -err: - return ERR_PTR(r); -} - -static struct platform_device *create_simple_dss_pdev(const char *pdev_name, - int pdev_id, void *pdata, int pdata_len, - struct platform_device *parent) -{ - struct platform_device *pdev; - int r; - - pdev = platform_device_alloc(pdev_name, pdev_id); - if (!pdev) { - pr_err("Could not create pdev for %s\n", pdev_name); - r = -ENOMEM; - goto err; - } - - if (parent != NULL) - pdev->dev.parent = &parent->dev; - - if (pdev->id != -1) - dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); - else - dev_set_name(&pdev->dev, "%s", pdev->name); - - r = platform_device_add_data(pdev, pdata, pdata_len); - if (r) { - pr_err("Could not set pdata for %s\n", pdev_name); - goto err; - } - - r = omap_device_register(pdev); - if (r) { - pr_err("Could not register omap_device for %s\n", pdev_name); - goto err; - } - - return pdev; - -err: - return ERR_PTR(r); -} - int __init omap_display_init(struct omap_dss_board_info *board_data) { int r = 0; + struct omap_hwmod *oh; struct platform_device *pdev; int i, oh_count; + struct omap_display_platform_data pdata; const struct omap_dss_hwmod_data *curr_dss_hwmod; - struct platform_device *dss_pdev; - - /* create omapdss device */ - - board_data->dsi_enable_pads = omap_dsi_enable_pads; - board_data->dsi_disable_pads = omap_dsi_disable_pads; - board_data->get_context_loss_count = omap_pm_get_dev_context_loss_count; - board_data->set_min_bus_tput = omap_dss_set_min_bus_tput; - - omap_display_device.dev.platform_data = board_data; - - r = platform_device_register(&omap_display_device); - if (r < 0) { - pr_err("Unable to register omapdss device\n"); - return r; - } - /* create devices for dss hwmods */ + memset(&pdata, 0, sizeof(pdata)); if (cpu_is_omap24xx()) { curr_dss_hwmod = omap2_dss_hwmod_data; @@ -319,58 +202,39 @@ int __init omap_display_init(struct omap_dss_board_info *board_data) oh_count = ARRAY_SIZE(omap4_dss_hwmod_data); } - /* - * First create the pdev for dss_core, which is used as a parent device - * by the other dss pdevs. Note: dss_core has to be the first item in - * the hwmod list. - */ - dss_pdev = create_dss_pdev(curr_dss_hwmod[0].dev_name, - curr_dss_hwmod[0].id, - curr_dss_hwmod[0].oh_name, - board_data, sizeof(*board_data), - NULL); - - if (IS_ERR(dss_pdev)) { - pr_err("Could not build omap_device for %s\n", - curr_dss_hwmod[0].oh_name); - - return PTR_ERR(dss_pdev); - } - - for (i = 1; i < oh_count; i++) { - pdev = create_dss_pdev(curr_dss_hwmod[i].dev_name, - curr_dss_hwmod[i].id, - curr_dss_hwmod[i].oh_name, - board_data, sizeof(*board_data), - dss_pdev); - - if (IS_ERR(pdev)) { - pr_err("Could not build omap_device for %s\n", - curr_dss_hwmod[i].oh_name); - - return PTR_ERR(pdev); + if (board_data->dsi_enable_pads == NULL) + board_data->dsi_enable_pads = omap_dsi_enable_pads; + if (board_data->dsi_disable_pads == NULL) + board_data->dsi_disable_pads = omap_dsi_disable_pads; + + pdata.board_data = board_data; + pdata.board_data->get_context_loss_count = + omap_pm_get_dev_context_loss_count; + + for (i = 0; i < oh_count; i++) { + oh = omap_hwmod_lookup(curr_dss_hwmod[i].oh_name); + if (!oh) { + pr_err("Could not look up %s\n", + curr_dss_hwmod[i].oh_name); + return -ENODEV; } - } - /* Create devices for DPI and SDI */ + pdev = omap_device_build(curr_dss_hwmod[i].dev_name, + curr_dss_hwmod[i].id, oh, &pdata, + sizeof(struct omap_display_platform_data), + NULL, 0, 0); - pdev = create_simple_dss_pdev("omapdss_dpi", -1, - board_data, sizeof(*board_data), dss_pdev); - if (IS_ERR(pdev)) { - pr_err("Could not build platform_device for omapdss_dpi\n"); - return PTR_ERR(pdev); + if (WARN((IS_ERR(pdev)), "Could not build omap_device for %s\n", + curr_dss_hwmod[i].oh_name)) + return -ENODEV; } + omap_display_device.dev.platform_data = board_data; - if (cpu_is_omap34xx()) { - pdev = create_simple_dss_pdev("omapdss_sdi", -1, - board_data, sizeof(*board_data), dss_pdev); - if (IS_ERR(pdev)) { - pr_err("Could not build platform_device for omapdss_sdi\n"); - return PTR_ERR(pdev); - } - } + r = platform_device_register(&omap_display_device); + if (r < 0) + printk(KERN_ERR "Unable to register OMAP-Display device\n"); - return 0; + return r; } static void dispc_disable_outputs(void) diff --git a/trunk/arch/arm/mach-omap2/gpmc.c b/trunk/arch/arm/mach-omap2/gpmc.c index 2286410671e7..46b09dae770e 100644 --- a/trunk/arch/arm/mach-omap2/gpmc.c +++ b/trunk/arch/arm/mach-omap2/gpmc.c @@ -49,7 +49,6 @@ #define GPMC_ECC_CONTROL 0x1f8 #define GPMC_ECC_SIZE_CONFIG 0x1fc #define GPMC_ECC1_RESULT 0x200 -#define GPMC_ECC_BCH_RESULT_0 0x240 /* not available on OMAP2 */ /* GPMC ECC control settings */ #define GPMC_ECC_CTRL_ECCCLEAR 0x100 @@ -936,186 +935,3 @@ int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code) return 0; } EXPORT_SYMBOL_GPL(gpmc_calculate_ecc); - -#ifdef CONFIG_ARCH_OMAP3 - -/** - * gpmc_init_hwecc_bch - initialize hardware BCH ecc functionality - * @cs: chip select number - * @nsectors: how many 512-byte sectors to process - * @nerrors: how many errors to correct per sector (4 or 8) - * - * This function must be executed before any call to gpmc_enable_hwecc_bch. - */ -int gpmc_init_hwecc_bch(int cs, int nsectors, int nerrors) -{ - /* check if ecc module is in use */ - if (gpmc_ecc_used != -EINVAL) - return -EINVAL; - - /* support only OMAP3 class */ - if (!cpu_is_omap34xx()) { - printk(KERN_ERR "BCH ecc is not supported on this CPU\n"); - return -EINVAL; - } - - /* - * For now, assume 4-bit mode is only supported on OMAP3630 ES1.x, x>=1. - * Other chips may be added if confirmed to work. - */ - if ((nerrors == 4) && - (!cpu_is_omap3630() || (GET_OMAP_REVISION() == 0))) { - printk(KERN_ERR "BCH 4-bit mode is not supported on this CPU\n"); - return -EINVAL; - } - - /* sanity check */ - if (nsectors > 8) { - printk(KERN_ERR "BCH cannot process %d sectors (max is 8)\n", - nsectors); - return -EINVAL; - } - - return 0; -} -EXPORT_SYMBOL_GPL(gpmc_init_hwecc_bch); - -/** - * gpmc_enable_hwecc_bch - enable hardware BCH ecc functionality - * @cs: chip select number - * @mode: read/write mode - * @dev_width: device bus width(1 for x16, 0 for x8) - * @nsectors: how many 512-byte sectors to process - * @nerrors: how many errors to correct per sector (4 or 8) - */ -int gpmc_enable_hwecc_bch(int cs, int mode, int dev_width, int nsectors, - int nerrors) -{ - unsigned int val; - - /* check if ecc module is in use */ - if (gpmc_ecc_used != -EINVAL) - return -EINVAL; - - gpmc_ecc_used = cs; - - /* clear ecc and enable bits */ - gpmc_write_reg(GPMC_ECC_CONTROL, 0x1); - - /* - * When using BCH, sector size is hardcoded to 512 bytes. - * Here we are using wrapping mode 6 both for reading and writing, with: - * size0 = 0 (no additional protected byte in spare area) - * size1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area) - */ - gpmc_write_reg(GPMC_ECC_SIZE_CONFIG, (32 << 22) | (0 << 12)); - - /* BCH configuration */ - val = ((1 << 16) | /* enable BCH */ - (((nerrors == 8) ? 1 : 0) << 12) | /* 8 or 4 bits */ - (0x06 << 8) | /* wrap mode = 6 */ - (dev_width << 7) | /* bus width */ - (((nsectors-1) & 0x7) << 4) | /* number of sectors */ - (cs << 1) | /* ECC CS */ - (0x1)); /* enable ECC */ - - gpmc_write_reg(GPMC_ECC_CONFIG, val); - gpmc_write_reg(GPMC_ECC_CONTROL, 0x101); - return 0; -} -EXPORT_SYMBOL_GPL(gpmc_enable_hwecc_bch); - -/** - * gpmc_calculate_ecc_bch4 - Generate 7 ecc bytes per sector of 512 data bytes - * @cs: chip select number - * @dat: The pointer to data on which ecc is computed - * @ecc: The ecc output buffer - */ -int gpmc_calculate_ecc_bch4(int cs, const u_char *dat, u_char *ecc) -{ - int i; - unsigned long nsectors, reg, val1, val2; - - if (gpmc_ecc_used != cs) - return -EINVAL; - - nsectors = ((gpmc_read_reg(GPMC_ECC_CONFIG) >> 4) & 0x7) + 1; - - for (i = 0; i < nsectors; i++) { - - reg = GPMC_ECC_BCH_RESULT_0 + 16*i; - - /* Read hw-computed remainder */ - val1 = gpmc_read_reg(reg + 0); - val2 = gpmc_read_reg(reg + 4); - - /* - * Add constant polynomial to remainder, in order to get an ecc - * sequence of 0xFFs for a buffer filled with 0xFFs; and - * left-justify the resulting polynomial. - */ - *ecc++ = 0x28 ^ ((val2 >> 12) & 0xFF); - *ecc++ = 0x13 ^ ((val2 >> 4) & 0xFF); - *ecc++ = 0xcc ^ (((val2 & 0xF) << 4)|((val1 >> 28) & 0xF)); - *ecc++ = 0x39 ^ ((val1 >> 20) & 0xFF); - *ecc++ = 0x96 ^ ((val1 >> 12) & 0xFF); - *ecc++ = 0xac ^ ((val1 >> 4) & 0xFF); - *ecc++ = 0x7f ^ ((val1 & 0xF) << 4); - } - - gpmc_ecc_used = -EINVAL; - return 0; -} -EXPORT_SYMBOL_GPL(gpmc_calculate_ecc_bch4); - -/** - * gpmc_calculate_ecc_bch8 - Generate 13 ecc bytes per block of 512 data bytes - * @cs: chip select number - * @dat: The pointer to data on which ecc is computed - * @ecc: The ecc output buffer - */ -int gpmc_calculate_ecc_bch8(int cs, const u_char *dat, u_char *ecc) -{ - int i; - unsigned long nsectors, reg, val1, val2, val3, val4; - - if (gpmc_ecc_used != cs) - return -EINVAL; - - nsectors = ((gpmc_read_reg(GPMC_ECC_CONFIG) >> 4) & 0x7) + 1; - - for (i = 0; i < nsectors; i++) { - - reg = GPMC_ECC_BCH_RESULT_0 + 16*i; - - /* Read hw-computed remainder */ - val1 = gpmc_read_reg(reg + 0); - val2 = gpmc_read_reg(reg + 4); - val3 = gpmc_read_reg(reg + 8); - val4 = gpmc_read_reg(reg + 12); - - /* - * Add constant polynomial to remainder, in order to get an ecc - * sequence of 0xFFs for a buffer filled with 0xFFs. - */ - *ecc++ = 0xef ^ (val4 & 0xFF); - *ecc++ = 0x51 ^ ((val3 >> 24) & 0xFF); - *ecc++ = 0x2e ^ ((val3 >> 16) & 0xFF); - *ecc++ = 0x09 ^ ((val3 >> 8) & 0xFF); - *ecc++ = 0xed ^ (val3 & 0xFF); - *ecc++ = 0x93 ^ ((val2 >> 24) & 0xFF); - *ecc++ = 0x9a ^ ((val2 >> 16) & 0xFF); - *ecc++ = 0xc2 ^ ((val2 >> 8) & 0xFF); - *ecc++ = 0x97 ^ (val2 & 0xFF); - *ecc++ = 0x79 ^ ((val1 >> 24) & 0xFF); - *ecc++ = 0xe5 ^ ((val1 >> 16) & 0xFF); - *ecc++ = 0x24 ^ ((val1 >> 8) & 0xFF); - *ecc++ = 0xb5 ^ (val1 & 0xFF); - } - - gpmc_ecc_used = -EINVAL; - return 0; -} -EXPORT_SYMBOL_GPL(gpmc_calculate_ecc_bch8); - -#endif /* CONFIG_ARCH_OMAP3 */ diff --git a/trunk/arch/arm/mach-orion5x/ts78xx-setup.c b/trunk/arch/arm/mach-orion5x/ts78xx-setup.c index b4203277f3cd..a74f3cf54cc5 100644 --- a/trunk/arch/arm/mach-orion5x/ts78xx-setup.c +++ b/trunk/arch/arm/mach-orion5x/ts78xx-setup.c @@ -251,6 +251,8 @@ static void ts78xx_ts_nand_read_buf(struct mtd_info *mtd, readsb(io_base, buf, len); } +const char *ts_nand_part_probes[] = { "cmdlinepart", NULL }; + static struct mtd_partition ts78xx_ts_nand_parts[] = { { .name = "mbr", @@ -275,6 +277,7 @@ static struct mtd_partition ts78xx_ts_nand_parts[] = { static struct platform_nand_data ts78xx_ts_nand_data = { .chip = { .nr_chips = 1, + .part_probe_types = ts_nand_part_probes, .partitions = ts78xx_ts_nand_parts, .nr_partitions = ARRAY_SIZE(ts78xx_ts_nand_parts), .chip_delay = 15, diff --git a/trunk/arch/arm/mach-pxa/balloon3.c b/trunk/arch/arm/mach-pxa/balloon3.c index 9244493dbcb7..56e8cebeb7d5 100644 --- a/trunk/arch/arm/mach-pxa/balloon3.c +++ b/trunk/arch/arm/mach-pxa/balloon3.c @@ -679,6 +679,8 @@ static struct mtd_partition balloon3_partition_info[] = { }, }; +static const char *balloon3_part_probes[] = { "cmdlinepart", NULL }; + struct platform_nand_data balloon3_nand_pdata = { .chip = { .nr_chips = 4, @@ -686,6 +688,7 @@ struct platform_nand_data balloon3_nand_pdata = { .nr_partitions = ARRAY_SIZE(balloon3_partition_info), .partitions = balloon3_partition_info, .chip_delay = 50, + .part_probe_types = balloon3_part_probes, }, .ctrl = { .hwcontrol = 0, diff --git a/trunk/arch/arm/mach-pxa/em-x270.c b/trunk/arch/arm/mach-pxa/em-x270.c index 97f82ad341bf..a3a4a38d4972 100644 --- a/trunk/arch/arm/mach-pxa/em-x270.c +++ b/trunk/arch/arm/mach-pxa/em-x270.c @@ -338,6 +338,8 @@ static struct mtd_partition em_x270_partition_info[] = { }, }; +static const char *em_x270_part_probes[] = { "cmdlinepart", NULL }; + struct platform_nand_data em_x270_nand_platdata = { .chip = { .nr_chips = 1, @@ -345,6 +347,7 @@ struct platform_nand_data em_x270_nand_platdata = { .nr_partitions = ARRAY_SIZE(em_x270_partition_info), .partitions = em_x270_partition_info, .chip_delay = 20, + .part_probe_types = em_x270_part_probes, }, .ctrl = { .hwcontrol = 0, diff --git a/trunk/arch/arm/mach-pxa/palmtx.c b/trunk/arch/arm/mach-pxa/palmtx.c index 0da35dccfd89..9507605ed547 100644 --- a/trunk/arch/arm/mach-pxa/palmtx.c +++ b/trunk/arch/arm/mach-pxa/palmtx.c @@ -268,6 +268,8 @@ static struct mtd_partition palmtx_partition_info[] = { }, }; +static const char *palmtx_part_probes[] = { "cmdlinepart", NULL }; + struct platform_nand_data palmtx_nand_platdata = { .chip = { .nr_chips = 1, @@ -275,6 +277,7 @@ struct platform_nand_data palmtx_nand_platdata = { .nr_partitions = ARRAY_SIZE(palmtx_partition_info), .partitions = palmtx_partition_info, .chip_delay = 20, + .part_probe_types = palmtx_part_probes, }, .ctrl = { .cmd_ctrl = palmtx_nand_cmd_ctl, diff --git a/trunk/arch/arm/mach-s3c24xx/include/mach/irqs.h b/trunk/arch/arm/mach-s3c24xx/include/mach/irqs.h index b7a9f4d469e8..e53b2177319e 100644 --- a/trunk/arch/arm/mach-s3c24xx/include/mach/irqs.h +++ b/trunk/arch/arm/mach-s3c24xx/include/mach/irqs.h @@ -134,17 +134,6 @@ #define IRQ_S32416_WDT S3C2410_IRQSUB(27) #define IRQ_S32416_AC97 S3C2410_IRQSUB(28) -/* second interrupt-register of s3c2416/s3c2450 */ - -#define S3C2416_IRQ(x) S3C2410_IRQ((x) + 54 + 29) -#define IRQ_S3C2416_2D S3C2416_IRQ(0) -#define IRQ_S3C2416_IIC1 S3C2416_IRQ(1) -#define IRQ_S3C2416_RESERVED2 S3C2416_IRQ(2) -#define IRQ_S3C2416_RESERVED3 S3C2416_IRQ(3) -#define IRQ_S3C2416_PCM0 S3C2416_IRQ(4) -#define IRQ_S3C2416_PCM1 S3C2416_IRQ(5) -#define IRQ_S3C2416_I2S0 S3C2416_IRQ(6) -#define IRQ_S3C2416_I2S1 S3C2416_IRQ(7) /* extra irqs for s3c2440 */ @@ -186,9 +175,7 @@ #define IRQ_S3C2443_WDT S3C2410_IRQSUB(27) #define IRQ_S3C2443_AC97 S3C2410_IRQSUB(28) -#if defined(CONFIG_CPU_S3C2416) -#define NR_IRQS (IRQ_S3C2416_I2S1 + 1) -#elif defined(CONFIG_CPU_S3C2443) +#if defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416) #define NR_IRQS (IRQ_S3C2443_AC97+1) #else #define NR_IRQS (IRQ_S3C2440_AC97+1) diff --git a/trunk/arch/arm/mach-s3c24xx/irq-s3c2416.c b/trunk/arch/arm/mach-s3c24xx/irq-s3c2416.c index 23ec97370f32..fd49f35e448e 100644 --- a/trunk/arch/arm/mach-s3c24xx/irq-s3c2416.c +++ b/trunk/arch/arm/mach-s3c24xx/irq-s3c2416.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -193,43 +192,6 @@ static struct irq_chip s3c2416_irq_uart3 = { .irq_ack = s3c2416_irq_uart3_ack, }; -/* second interrupt register */ - -static inline void s3c2416_irq_ack_second(struct irq_data *data) -{ - unsigned long bitval = 1UL << (data->irq - IRQ_S3C2416_2D); - - __raw_writel(bitval, S3C2416_SRCPND2); - __raw_writel(bitval, S3C2416_INTPND2); -} - -static void s3c2416_irq_mask_second(struct irq_data *data) -{ - unsigned long bitval = 1UL << (data->irq - IRQ_S3C2416_2D); - unsigned long mask; - - mask = __raw_readl(S3C2416_INTMSK2); - mask |= bitval; - __raw_writel(mask, S3C2416_INTMSK2); -} - -static void s3c2416_irq_unmask_second(struct irq_data *data) -{ - unsigned long bitval = 1UL << (data->irq - IRQ_S3C2416_2D); - unsigned long mask; - - mask = __raw_readl(S3C2416_INTMSK2); - mask &= ~bitval; - __raw_writel(mask, S3C2416_INTMSK2); -} - -struct irq_chip s3c2416_irq_second = { - .irq_ack = s3c2416_irq_ack_second, - .irq_mask = s3c2416_irq_mask_second, - .irq_unmask = s3c2416_irq_unmask_second, -}; - - /* IRQ initialisation code */ static int __init s3c2416_add_sub(unsigned int base, @@ -251,42 +213,6 @@ static int __init s3c2416_add_sub(unsigned int base, return 0; } -static void __init s3c2416_irq_add_second(void) -{ - unsigned long pend; - unsigned long last; - int irqno; - int i; - - /* first, clear all interrupts pending... */ - last = 0; - for (i = 0; i < 4; i++) { - pend = __raw_readl(S3C2416_INTPND2); - - if (pend == 0 || pend == last) - break; - - __raw_writel(pend, S3C2416_SRCPND2); - __raw_writel(pend, S3C2416_INTPND2); - printk(KERN_INFO "irq: clearing pending status %08x\n", - (int)pend); - last = pend; - } - - for (irqno = IRQ_S3C2416_2D; irqno <= IRQ_S3C2416_I2S1; irqno++) { - switch (irqno) { - case IRQ_S3C2416_RESERVED2: - case IRQ_S3C2416_RESERVED3: - /* no IRQ here */ - break; - default: - irq_set_chip_and_handler(irqno, &s3c2416_irq_second, - handle_edge_irq); - set_irq_flags(irqno, IRQF_VALID); - } - } -} - static int __init s3c2416_irq_add(struct device *dev, struct subsys_interface *sif) { @@ -306,8 +232,6 @@ static int __init s3c2416_irq_add(struct device *dev, &s3c2416_irq_wdtac97, IRQ_S3C2443_WDT, IRQ_S3C2443_AC97); - s3c2416_irq_add_second(); - return 0; } @@ -324,25 +248,3 @@ static int __init s3c2416_irq_init(void) arch_initcall(s3c2416_irq_init); -#ifdef CONFIG_PM -static struct sleep_save irq_save[] = { - SAVE_ITEM(S3C2416_INTMSK2), -}; - -int s3c2416_irq_suspend(void) -{ - s3c_pm_do_save(irq_save, ARRAY_SIZE(irq_save)); - - return 0; -} - -void s3c2416_irq_resume(void) -{ - s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save)); -} - -struct syscore_ops s3c2416_irq_syscore_ops = { - .suspend = s3c2416_irq_suspend, - .resume = s3c2416_irq_resume, -}; -#endif diff --git a/trunk/arch/arm/mach-s3c24xx/mach-smdk2416.c b/trunk/arch/arm/mach-s3c24xx/mach-smdk2416.c index c3100a044fbe..30a44f806e01 100644 --- a/trunk/arch/arm/mach-s3c24xx/mach-smdk2416.c +++ b/trunk/arch/arm/mach-s3c24xx/mach-smdk2416.c @@ -148,25 +148,23 @@ static struct s3c24xx_hsudc_platdata smdk2416_hsudc_platdata = { static struct s3c_fb_pd_win smdk2416_fb_win[] = { [0] = { + /* think this is the same as the smdk6410 */ + .win_mode = { + .pixclock = 41094, + .left_margin = 8, + .right_margin = 13, + .upper_margin = 7, + .lower_margin = 5, + .hsync_len = 3, + .vsync_len = 1, + .xres = 800, + .yres = 480, + }, .default_bpp = 16, .max_bpp = 32, - .xres = 800, - .yres = 480, }, }; -static struct fb_videomode smdk2416_lcd_timing = { - .pixclock = 41094, - .left_margin = 8, - .right_margin = 13, - .upper_margin = 7, - .lower_margin = 5, - .hsync_len = 3, - .vsync_len = 1, - .xres = 800, - .yres = 480, -}; - static void s3c2416_fb_gpio_setup_24bpp(void) { unsigned int gpio; @@ -189,7 +187,6 @@ static void s3c2416_fb_gpio_setup_24bpp(void) static struct s3c_fb_platdata smdk2416_fb_platdata = { .win[0] = &smdk2416_fb_win[0], - .vtiming = &smdk2416_lcd_timing, .setup_gpio = s3c2416_fb_gpio_setup_24bpp, .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, diff --git a/trunk/arch/arm/mach-s3c24xx/s3c2416.c b/trunk/arch/arm/mach-s3c24xx/s3c2416.c index ed5a95ece9eb..7743fade50df 100644 --- a/trunk/arch/arm/mach-s3c24xx/s3c2416.c +++ b/trunk/arch/arm/mach-s3c24xx/s3c2416.c @@ -106,7 +106,6 @@ int __init s3c2416_init(void) register_syscore_ops(&s3c2416_pm_syscore_ops); #endif register_syscore_ops(&s3c24xx_irq_syscore_ops); - register_syscore_ops(&s3c2416_irq_syscore_ops); return device_register(&s3c2416_dev); } diff --git a/trunk/arch/arm/mach-s3c64xx/cpuidle.c b/trunk/arch/arm/mach-s3c64xx/cpuidle.c index acb197ccf3f7..179460f38db7 100644 --- a/trunk/arch/arm/mach-s3c64xx/cpuidle.c +++ b/trunk/arch/arm/mach-s3c64xx/cpuidle.c @@ -27,7 +27,12 @@ static int s3c64xx_enter_idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { + struct timeval before, after; unsigned long tmp; + int idle_time; + + local_irq_disable(); + do_gettimeofday(&before); /* Setup PWRCFG to enter idle mode */ tmp = __raw_readl(S3C64XX_PWR_CFG); @@ -37,32 +42,42 @@ static int s3c64xx_enter_idle(struct cpuidle_device *dev, cpu_do_idle(); + do_gettimeofday(&after); + local_irq_enable(); + idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC + + (after.tv_usec - before.tv_usec); + + dev->last_residency = idle_time; return index; } -static DEFINE_PER_CPU(struct cpuidle_device, s3c64xx_cpuidle_device); +static struct cpuidle_state s3c64xx_cpuidle_set[] = { + [0] = { + .enter = s3c64xx_enter_idle, + .exit_latency = 1, + .target_residency = 1, + .flags = CPUIDLE_FLAG_TIME_VALID, + .name = "IDLE", + .desc = "System active, ARM gated", + }, +}; static struct cpuidle_driver s3c64xx_cpuidle_driver = { - .name = "s3c64xx_cpuidle", - .owner = THIS_MODULE, - .en_core_tk_irqen = 1, - .states = { - { - .enter = s3c64xx_enter_idle, - .exit_latency = 1, - .target_residency = 1, - .flags = CPUIDLE_FLAG_TIME_VALID, - .name = "IDLE", - .desc = "System active, ARM gated", - }, - }, - .state_count = 1, + .name = "s3c64xx_cpuidle", + .owner = THIS_MODULE, + .state_count = ARRAY_SIZE(s3c64xx_cpuidle_set), +}; + +static struct cpuidle_device s3c64xx_cpuidle_device = { + .state_count = ARRAY_SIZE(s3c64xx_cpuidle_set), }; static int __init s3c64xx_init_cpuidle(void) { int ret; + memcpy(s3c64xx_cpuidle_driver.states, s3c64xx_cpuidle_set, + sizeof(s3c64xx_cpuidle_set)); cpuidle_register_driver(&s3c64xx_cpuidle_driver); ret = cpuidle_register_device(&s3c64xx_cpuidle_device); diff --git a/trunk/arch/arm/mach-s3c64xx/mach-anw6410.c b/trunk/arch/arm/mach-s3c64xx/mach-anw6410.c index ffa29ddfdfce..314df0518afd 100644 --- a/trunk/arch/arm/mach-s3c64xx/mach-anw6410.c +++ b/trunk/arch/arm/mach-s3c64xx/mach-anw6410.c @@ -134,27 +134,24 @@ static struct platform_device anw6410_lcd_powerdev = { }; static struct s3c_fb_pd_win anw6410_fb_win0 = { + /* this is to ensure we use win0 */ + .win_mode = { + .left_margin = 8, + .right_margin = 13, + .upper_margin = 7, + .lower_margin = 5, + .hsync_len = 3, + .vsync_len = 1, + .xres = 800, + .yres = 480, + }, .max_bpp = 32, .default_bpp = 16, - .xres = 800, - .yres = 480, -}; - -static struct fb_videomode anw6410_lcd_timing = { - .left_margin = 8, - .right_margin = 13, - .upper_margin = 7, - .lower_margin = 5, - .hsync_len = 3, - .vsync_len = 1, - .xres = 800, - .yres = 480, }; /* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */ static struct s3c_fb_platdata anw6410_lcd_pdata __initdata = { .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, - .vtiming = &anw6410_lcd_timing, .win[0] = &anw6410_fb_win0, .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, diff --git a/trunk/arch/arm/mach-s3c64xx/mach-crag6410-module.c b/trunk/arch/arm/mach-s3c64xx/mach-crag6410-module.c index 7a27f5603c74..0ace108c3e3d 100644 --- a/trunk/arch/arm/mach-s3c64xx/mach-crag6410-module.c +++ b/trunk/arch/arm/mach-s3c64xx/mach-crag6410-module.c @@ -182,11 +182,6 @@ static const struct i2c_board_info wm1277_devs[] = { }, }; -static const struct i2c_board_info wm6230_i2c_devs[] = { - { I2C_BOARD_INFO("wm9081", 0x6c), - .platform_data = &wm9081_pdata, }, -}; - static __devinitdata const struct { u8 id; const char *name; @@ -200,9 +195,7 @@ static __devinitdata const struct { { .id = 0x03, .name = "1252-EV1 Glenlivet" }, { .id = 0x11, .name = "6249-EV2 Glenfarclas", }, { .id = 0x14, .name = "6271-EV1 Lochnagar" }, - { .id = 0x15, .name = "6320-EV1 Bells", - .i2c_devs = wm6230_i2c_devs, - .num_i2c_devs = ARRAY_SIZE(wm6230_i2c_devs) }, + { .id = 0x15, .name = "XXXX-EV1 Bells" }, { .id = 0x21, .name = "1275-EV1 Mortlach" }, { .id = 0x25, .name = "1274-EV1 Glencadam" }, { .id = 0x31, .name = "1253-EV1 Tomatin", diff --git a/trunk/arch/arm/mach-s3c64xx/mach-crag6410.c b/trunk/arch/arm/mach-s3c64xx/mach-crag6410.c index d0c352d861f8..eda5e027b109 100644 --- a/trunk/arch/arm/mach-s3c64xx/mach-crag6410.c +++ b/trunk/arch/arm/mach-s3c64xx/mach-crag6410.c @@ -151,29 +151,26 @@ static struct platform_device crag6410_lcd_powerdev = { /* 640x480 URT */ static struct s3c_fb_pd_win crag6410_fb_win0 = { + /* this is to ensure we use win0 */ + .win_mode = { + .left_margin = 150, + .right_margin = 80, + .upper_margin = 40, + .lower_margin = 5, + .hsync_len = 40, + .vsync_len = 5, + .xres = 640, + .yres = 480, + }, .max_bpp = 32, .default_bpp = 16, - .xres = 640, - .yres = 480, .virtual_y = 480 * 2, .virtual_x = 640, }; -static struct fb_videomode crag6410_lcd_timing = { - .left_margin = 150, - .right_margin = 80, - .upper_margin = 40, - .lower_margin = 5, - .hsync_len = 40, - .vsync_len = 5, - .xres = 640, - .yres = 480, -}; - /* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */ static struct s3c_fb_platdata crag6410_lcd_pdata __initdata = { .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, - .vtiming = &crag6410_lcd_timing, .win[0] = &crag6410_fb_win0, .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, @@ -674,7 +671,6 @@ static struct i2c_board_info i2c_devs1[] __initdata = { .irq = S3C_EINT(0), .platform_data = &glenfarclas_pmic_pdata }, - { I2C_BOARD_INFO("wlf-gf-module", 0x22) }, { I2C_BOARD_INFO("wlf-gf-module", 0x24) }, { I2C_BOARD_INFO("wlf-gf-module", 0x25) }, { I2C_BOARD_INFO("wlf-gf-module", 0x26) }, diff --git a/trunk/arch/arm/mach-s3c64xx/mach-hmt.c b/trunk/arch/arm/mach-s3c64xx/mach-hmt.c index 689088162f77..1bf6b9da20fc 100644 --- a/trunk/arch/arm/mach-s3c64xx/mach-hmt.c +++ b/trunk/arch/arm/mach-s3c64xx/mach-hmt.c @@ -129,27 +129,23 @@ static struct platform_device hmt_backlight_device = { }; static struct s3c_fb_pd_win hmt_fb_win0 = { + .win_mode = { + .left_margin = 8, + .right_margin = 13, + .upper_margin = 7, + .lower_margin = 5, + .hsync_len = 3, + .vsync_len = 1, + .xres = 800, + .yres = 480, + }, .max_bpp = 32, .default_bpp = 16, - .xres = 800, - .yres = 480, -}; - -static struct fb_videomode hmt_lcd_timing = { - .left_margin = 8, - .right_margin = 13, - .upper_margin = 7, - .lower_margin = 5, - .hsync_len = 3, - .vsync_len = 1, - .xres = 800, - .yres = 480, }; /* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */ static struct s3c_fb_platdata hmt_lcd_pdata __initdata = { .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, - .vtiming = &hmt_lcd_timing, .win[0] = &hmt_fb_win0, .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, diff --git a/trunk/arch/arm/mach-s3c64xx/mach-mini6410.c b/trunk/arch/arm/mach-s3c64xx/mach-mini6410.c index 5539a255a704..f8ea61ea3b33 100644 --- a/trunk/arch/arm/mach-s3c64xx/mach-mini6410.c +++ b/trunk/arch/arm/mach-s3c64xx/mach-mini6410.c @@ -140,59 +140,41 @@ static struct s3c2410_platform_nand mini6410_nand_info = { .sets = mini6410_nand_sets, }; -static struct s3c_fb_pd_win mini6410_lcd_type0_fb_win = { - .max_bpp = 32, - .default_bpp = 16, - .xres = 480, - .yres = 272, -}; - -static struct fb_videomode mini6410_lcd_type0_timing = { - /* 4.3" 480x272 */ - .left_margin = 3, - .right_margin = 2, - .upper_margin = 1, - .lower_margin = 1, - .hsync_len = 40, - .vsync_len = 1, - .xres = 480, - .yres = 272, -}; - -static struct s3c_fb_pd_win mini6410_lcd_type1_fb_win = { - .max_bpp = 32, - .default_bpp = 16, - .xres = 800, - .yres = 480, -}; - -static struct fb_videomode mini6410_lcd_type1_timing = { - /* 7.0" 800x480 */ - .left_margin = 8, - .right_margin = 13, - .upper_margin = 7, - .lower_margin = 5, - .hsync_len = 3, - .vsync_len = 1, - .xres = 800, - .yres = 480, -}; - -static struct s3c_fb_platdata mini6410_lcd_pdata[] __initdata = { +static struct s3c_fb_pd_win mini6410_fb_win[] = { { - .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, - .vtiming = &mini6410_lcd_type0_timing, - .win[0] = &mini6410_lcd_type0_fb_win, - .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, - .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, + .win_mode = { /* 4.3" 480x272 */ + .left_margin = 3, + .right_margin = 2, + .upper_margin = 1, + .lower_margin = 1, + .hsync_len = 40, + .vsync_len = 1, + .xres = 480, + .yres = 272, + }, + .max_bpp = 32, + .default_bpp = 16, }, { - .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, - .vtiming = &mini6410_lcd_type1_timing, - .win[0] = &mini6410_lcd_type1_fb_win, - .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, - .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, + .win_mode = { /* 7.0" 800x480 */ + .left_margin = 8, + .right_margin = 13, + .upper_margin = 7, + .lower_margin = 5, + .hsync_len = 3, + .vsync_len = 1, + .xres = 800, + .yres = 480, + }, + .max_bpp = 32, + .default_bpp = 16, }, - { }, +}; + +static struct s3c_fb_platdata mini6410_lcd_pdata __initdata = { + .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, + .win[0] = &mini6410_fb_win[0], + .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, + .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, }; static void mini6410_lcd_power_set(struct plat_lcd_data *pd, @@ -290,7 +272,7 @@ static void mini6410_parse_features( "screen type already set\n", f); } else { int li = f - '0'; - if (li >= ARRAY_SIZE(mini6410_lcd_pdata)) + if (li >= ARRAY_SIZE(mini6410_fb_win)) printk(KERN_INFO "MINI6410: '%c' out " "of range LCD mode\n", f); else { @@ -314,12 +296,14 @@ static void __init mini6410_machine_init(void) /* Parse the feature string */ mini6410_parse_features(&features, mini6410_features_str); + mini6410_lcd_pdata.win[0] = &mini6410_fb_win[features.lcd_index]; + printk(KERN_INFO "MINI6410: selected LCD display is %dx%d\n", - mini6410_lcd_pdata[features.lcd_index].win[0]->xres, - mini6410_lcd_pdata[features.lcd_index].win[0]->yres); + mini6410_lcd_pdata.win[0]->win_mode.xres, + mini6410_lcd_pdata.win[0]->win_mode.yres); s3c_nand_set_platdata(&mini6410_nand_info); - s3c_fb_set_platdata(&mini6410_lcd_pdata[features.lcd_index]); + s3c_fb_set_platdata(&mini6410_lcd_pdata); s3c24xx_ts_set_platdata(NULL); /* configure nCS1 width to 16 bits */ diff --git a/trunk/arch/arm/mach-s3c64xx/mach-real6410.c b/trunk/arch/arm/mach-s3c64xx/mach-real6410.c index 326b21604bc3..b92d8e17d502 100644 --- a/trunk/arch/arm/mach-s3c64xx/mach-real6410.c +++ b/trunk/arch/arm/mach-s3c64xx/mach-real6410.c @@ -106,57 +106,41 @@ static struct platform_device real6410_device_eth = { }, }; -static struct s3c_fb_pd_win real6410_lcd_type0_fb_win = { - .max_bpp = 32, - .default_bpp = 16, - .xres = 480, - .yres = 272, -}; - -static struct fb_videomode real6410_lcd_type0_timing = { - /* 4.3" 480x272 */ - .left_margin = 3, - .right_margin = 2, - .upper_margin = 1, - .lower_margin = 1, - .hsync_len = 40, - .vsync_len = 1, -}; - -static struct s3c_fb_pd_win real6410_lcd_type1_fb_win = { - .max_bpp = 32, - .default_bpp = 16, - .xres = 800, - .yres = 480, -}; - -static struct fb_videomode real6410_lcd_type1_timing = { - /* 7.0" 800x480 */ - .left_margin = 8, - .right_margin = 13, - .upper_margin = 7, - .lower_margin = 5, - .hsync_len = 3, - .vsync_len = 1, - .xres = 800, - .yres = 480, -}; - -static struct s3c_fb_platdata real6410_lcd_pdata[] __initdata = { +static struct s3c_fb_pd_win real6410_fb_win[] = { { - .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, - .vtiming = &real6410_lcd_type0_timing, - .win[0] = &real6410_lcd_type0_fb_win, - .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, - .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, + .win_mode = { /* 4.3" 480x272 */ + .left_margin = 3, + .right_margin = 2, + .upper_margin = 1, + .lower_margin = 1, + .hsync_len = 40, + .vsync_len = 1, + .xres = 480, + .yres = 272, + }, + .max_bpp = 32, + .default_bpp = 16, }, { - .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, - .vtiming = &real6410_lcd_type1_timing, - .win[0] = &real6410_lcd_type1_fb_win, - .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, - .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, + .win_mode = { /* 7.0" 800x480 */ + .left_margin = 8, + .right_margin = 13, + .upper_margin = 7, + .lower_margin = 5, + .hsync_len = 3, + .vsync_len = 1, + .xres = 800, + .yres = 480, + }, + .max_bpp = 32, + .default_bpp = 16, }, - { }, +}; + +static struct s3c_fb_platdata real6410_lcd_pdata __initdata = { + .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, + .win[0] = &real6410_fb_win[0], + .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, + .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, }; static struct mtd_partition real6410_nand_part[] = { @@ -269,7 +253,7 @@ static void real6410_parse_features( "screen type already set\n", f); } else { int li = f - '0'; - if (li >= ARRAY_SIZE(real6410_lcd_pdata)) + if (li >= ARRAY_SIZE(real6410_fb_win)) printk(KERN_INFO "REAL6410: '%c' out " "of range LCD mode\n", f); else { @@ -293,11 +277,13 @@ static void __init real6410_machine_init(void) /* Parse the feature string */ real6410_parse_features(&features, real6410_features_str); + real6410_lcd_pdata.win[0] = &real6410_fb_win[features.lcd_index]; + printk(KERN_INFO "REAL6410: selected LCD display is %dx%d\n", - real6410_lcd_pdata[features.lcd_index].win[0]->xres, - real6410_lcd_pdata[features.lcd_index].win[0]->yres); + real6410_lcd_pdata.win[0]->win_mode.xres, + real6410_lcd_pdata.win[0]->win_mode.yres); - s3c_fb_set_platdata(&real6410_lcd_pdata[features.lcd_index]); + s3c_fb_set_platdata(&real6410_lcd_pdata); s3c_nand_set_platdata(&real6410_nand_info); s3c24xx_ts_set_platdata(NULL); diff --git a/trunk/arch/arm/mach-s3c64xx/mach-smartq5.c b/trunk/arch/arm/mach-s3c64xx/mach-smartq5.c index d6266d8b43c9..c5021d0335c6 100644 --- a/trunk/arch/arm/mach-s3c64xx/mach-smartq5.c +++ b/trunk/arch/arm/mach-s3c64xx/mach-smartq5.c @@ -108,27 +108,23 @@ static struct platform_device smartq5_buttons_device = { }; static struct s3c_fb_pd_win smartq5_fb_win0 = { + .win_mode = { + .left_margin = 216, + .right_margin = 40, + .upper_margin = 35, + .lower_margin = 10, + .hsync_len = 1, + .vsync_len = 1, + .xres = 800, + .yres = 480, + .refresh = 80, + }, .max_bpp = 32, .default_bpp = 16, - .xres = 800, - .yres = 480, -}; - -static struct fb_videomode smartq5_lcd_timing = { - .left_margin = 216, - .right_margin = 40, - .upper_margin = 35, - .lower_margin = 10, - .hsync_len = 1, - .vsync_len = 1, - .xres = 800, - .yres = 480, - .refresh = 80, }; static struct s3c_fb_platdata smartq5_lcd_pdata __initdata = { .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, - .vtiming = &smartq5_lcd_timing, .win[0] = &smartq5_fb_win0, .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC | diff --git a/trunk/arch/arm/mach-s3c64xx/mach-smartq7.c b/trunk/arch/arm/mach-s3c64xx/mach-smartq7.c index 0957d2a980e1..aa9072a4cbef 100644 --- a/trunk/arch/arm/mach-s3c64xx/mach-smartq7.c +++ b/trunk/arch/arm/mach-s3c64xx/mach-smartq7.c @@ -124,27 +124,23 @@ static struct platform_device smartq7_buttons_device = { }; static struct s3c_fb_pd_win smartq7_fb_win0 = { + .win_mode = { + .left_margin = 3, + .right_margin = 5, + .upper_margin = 1, + .lower_margin = 20, + .hsync_len = 10, + .vsync_len = 3, + .xres = 800, + .yres = 480, + .refresh = 80, + }, .max_bpp = 32, .default_bpp = 16, - .xres = 800, - .yres = 480, -}; - -static struct fb_videomode smartq7_lcd_timing = { - .left_margin = 3, - .right_margin = 5, - .upper_margin = 1, - .lower_margin = 20, - .hsync_len = 10, - .vsync_len = 3, - .xres = 800, - .yres = 480, - .refresh = 80, }; static struct s3c_fb_platdata smartq7_lcd_pdata __initdata = { .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, - .vtiming = &smartq7_lcd_timing, .win[0] = &smartq7_fb_win0, .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC | diff --git a/trunk/arch/arm/mach-s3c64xx/mach-smdk6410.c b/trunk/arch/arm/mach-s3c64xx/mach-smdk6410.c index df3103d450e2..d44319b09412 100644 --- a/trunk/arch/arm/mach-s3c64xx/mach-smdk6410.c +++ b/trunk/arch/arm/mach-s3c64xx/mach-smdk6410.c @@ -146,29 +146,26 @@ static struct platform_device smdk6410_lcd_powerdev = { }; static struct s3c_fb_pd_win smdk6410_fb_win0 = { + /* this is to ensure we use win0 */ + .win_mode = { + .left_margin = 8, + .right_margin = 13, + .upper_margin = 7, + .lower_margin = 5, + .hsync_len = 3, + .vsync_len = 1, + .xres = 800, + .yres = 480, + }, .max_bpp = 32, .default_bpp = 16, - .xres = 800, - .yres = 480, .virtual_y = 480 * 2, .virtual_x = 800, }; -static struct fb_videomode smdk6410_lcd_timing = { - .left_margin = 8, - .right_margin = 13, - .upper_margin = 7, - .lower_margin = 5, - .hsync_len = 3, - .vsync_len = 1, - .xres = 800, - .yres = 480, -}; - /* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */ static struct s3c_fb_platdata smdk6410_lcd_pdata __initdata = { .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, - .vtiming = &smdk6410_lcd_timing, .win[0] = &smdk6410_fb_win0, .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, diff --git a/trunk/arch/arm/mach-s5p64x0/mach-smdk6440.c b/trunk/arch/arm/mach-s5p64x0/mach-smdk6440.c index 92fefad505cc..a40e325d62c8 100644 --- a/trunk/arch/arm/mach-s5p64x0/mach-smdk6440.c +++ b/trunk/arch/arm/mach-s5p64x0/mach-smdk6440.c @@ -103,26 +103,22 @@ static struct s3c2410_uartcfg smdk6440_uartcfgs[] __initdata = { /* Frame Buffer */ static struct s3c_fb_pd_win smdk6440_fb_win0 = { + .win_mode = { + .left_margin = 8, + .right_margin = 13, + .upper_margin = 7, + .lower_margin = 5, + .hsync_len = 3, + .vsync_len = 1, + .xres = 800, + .yres = 480, + }, .max_bpp = 32, .default_bpp = 24, - .xres = 800, - .yres = 480, -}; - -static struct fb_videomode smdk6440_lcd_timing = { - .left_margin = 8, - .right_margin = 13, - .upper_margin = 7, - .lower_margin = 5, - .hsync_len = 3, - .vsync_len = 1, - .xres = 800, - .yres = 480, }; static struct s3c_fb_platdata smdk6440_lcd_pdata __initdata = { .win[0] = &smdk6440_fb_win0, - .vtiming = &smdk6440_lcd_timing, .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, .setup_gpio = s5p64x0_fb_gpio_setup_24bpp, diff --git a/trunk/arch/arm/mach-s5p64x0/mach-smdk6450.c b/trunk/arch/arm/mach-s5p64x0/mach-smdk6450.c index e2335ecf6eae..efb69e2f2afe 100644 --- a/trunk/arch/arm/mach-s5p64x0/mach-smdk6450.c +++ b/trunk/arch/arm/mach-s5p64x0/mach-smdk6450.c @@ -121,26 +121,22 @@ static struct s3c2410_uartcfg smdk6450_uartcfgs[] __initdata = { /* Frame Buffer */ static struct s3c_fb_pd_win smdk6450_fb_win0 = { + .win_mode = { + .left_margin = 8, + .right_margin = 13, + .upper_margin = 7, + .lower_margin = 5, + .hsync_len = 3, + .vsync_len = 1, + .xres = 800, + .yres = 480, + }, .max_bpp = 32, .default_bpp = 24, - .xres = 800, - .yres = 480, -}; - -static struct fb_videomode smdk6450_lcd_timing = { - .left_margin = 8, - .right_margin = 13, - .upper_margin = 7, - .lower_margin = 5, - .hsync_len = 3, - .vsync_len = 1, - .xres = 800, - .yres = 480, }; static struct s3c_fb_platdata smdk6450_lcd_pdata __initdata = { .win[0] = &smdk6450_fb_win0, - .vtiming = &smdk6450_lcd_timing, .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, .setup_gpio = s5p64x0_fb_gpio_setup_24bpp, diff --git a/trunk/arch/arm/mach-s5pc100/mach-smdkc100.c b/trunk/arch/arm/mach-s5pc100/mach-smdkc100.c index 0c3ae38d27ca..674d22992f3c 100644 --- a/trunk/arch/arm/mach-s5pc100/mach-smdkc100.c +++ b/trunk/arch/arm/mach-s5pc100/mach-smdkc100.c @@ -136,27 +136,24 @@ static struct platform_device smdkc100_lcd_powerdev = { /* Frame Buffer */ static struct s3c_fb_pd_win smdkc100_fb_win0 = { + /* this is to ensure we use win0 */ + .win_mode = { + .left_margin = 8, + .right_margin = 13, + .upper_margin = 7, + .lower_margin = 5, + .hsync_len = 3, + .vsync_len = 1, + .xres = 800, + .yres = 480, + .refresh = 80, + }, .max_bpp = 32, .default_bpp = 16, - .xres = 800, - .yres = 480, -}; - -static struct fb_videomode smdkc100_lcd_timing = { - .left_margin = 8, - .right_margin = 13, - .upper_margin = 7, - .lower_margin = 5, - .hsync_len = 3, - .vsync_len = 1, - .xres = 800, - .yres = 480, - .refresh = 80, }; static struct s3c_fb_platdata smdkc100_lcd_pdata __initdata = { .win[0] = &smdkc100_fb_win0, - .vtiming = &smdkc100_lcd_timing, .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, .setup_gpio = s5pc100_fb_gpio_setup_24bpp, diff --git a/trunk/arch/arm/mach-s5pv210/mach-aquila.c b/trunk/arch/arm/mach-s5pv210/mach-aquila.c index af528f9e97f9..48d018f2332b 100644 --- a/trunk/arch/arm/mach-s5pv210/mach-aquila.c +++ b/trunk/arch/arm/mach-s5pv210/mach-aquila.c @@ -96,34 +96,38 @@ static struct s3c2410_uartcfg aquila_uartcfgs[] __initdata = { /* Frame Buffer */ static struct s3c_fb_pd_win aquila_fb_win0 = { + .win_mode = { + .left_margin = 16, + .right_margin = 16, + .upper_margin = 3, + .lower_margin = 28, + .hsync_len = 2, + .vsync_len = 2, + .xres = 480, + .yres = 800, + }, .max_bpp = 32, .default_bpp = 16, - .xres = 480, - .yres = 800, }; static struct s3c_fb_pd_win aquila_fb_win1 = { + .win_mode = { + .left_margin = 16, + .right_margin = 16, + .upper_margin = 3, + .lower_margin = 28, + .hsync_len = 2, + .vsync_len = 2, + .xres = 480, + .yres = 800, + }, .max_bpp = 32, .default_bpp = 16, - .xres = 480, - .yres = 800, -}; - -static struct fb_videomode aquila_lcd_timing = { - .left_margin = 16, - .right_margin = 16, - .upper_margin = 3, - .lower_margin = 28, - .hsync_len = 2, - .vsync_len = 2, - .xres = 480, - .yres = 800, }; static struct s3c_fb_platdata aquila_lcd_pdata __initdata = { .win[0] = &aquila_fb_win0, .win[1] = &aquila_fb_win1, - .vtiming = &aquila_lcd_timing, .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC | VIDCON1_INV_VCLK | VIDCON1_INV_VDEN, diff --git a/trunk/arch/arm/mach-s5pv210/mach-goni.c b/trunk/arch/arm/mach-s5pv210/mach-goni.c index bf5087c2b7fe..f20a97c8e411 100644 --- a/trunk/arch/arm/mach-s5pv210/mach-goni.c +++ b/trunk/arch/arm/mach-s5pv210/mach-goni.c @@ -107,29 +107,25 @@ static struct s3c2410_uartcfg goni_uartcfgs[] __initdata = { /* Frame Buffer */ static struct s3c_fb_pd_win goni_fb_win0 = { + .win_mode = { + .left_margin = 16, + .right_margin = 16, + .upper_margin = 2, + .lower_margin = 28, + .hsync_len = 2, + .vsync_len = 1, + .xres = 480, + .yres = 800, + .refresh = 55, + }, .max_bpp = 32, .default_bpp = 16, - .xres = 480, - .yres = 800, .virtual_x = 480, .virtual_y = 2 * 800, }; -static struct fb_videomode goni_lcd_timing = { - .left_margin = 16, - .right_margin = 16, - .upper_margin = 2, - .lower_margin = 28, - .hsync_len = 2, - .vsync_len = 1, - .xres = 480, - .yres = 800, - .refresh = 55, -}; - static struct s3c_fb_platdata goni_lcd_pdata __initdata = { .win[0] = &goni_fb_win0, - .vtiming = &goni_lcd_timing, .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB | VIDCON0_CLKSEL_LCD, .vidcon1 = VIDCON1_INV_VCLK | VIDCON1_INV_VDEN diff --git a/trunk/arch/arm/mach-s5pv210/mach-smdkv210.c b/trunk/arch/arm/mach-s5pv210/mach-smdkv210.c index 0d7ddec88eb7..fa1b61209fd9 100644 --- a/trunk/arch/arm/mach-s5pv210/mach-smdkv210.c +++ b/trunk/arch/arm/mach-s5pv210/mach-smdkv210.c @@ -178,26 +178,22 @@ static struct platform_device smdkv210_lcd_lte480wv = { }; static struct s3c_fb_pd_win smdkv210_fb_win0 = { + .win_mode = { + .left_margin = 13, + .right_margin = 8, + .upper_margin = 7, + .lower_margin = 5, + .hsync_len = 3, + .vsync_len = 1, + .xres = 800, + .yres = 480, + }, .max_bpp = 32, .default_bpp = 24, - .xres = 800, - .yres = 480, -}; - -static struct fb_videomode smdkv210_lcd_timing = { - .left_margin = 13, - .right_margin = 8, - .upper_margin = 7, - .lower_margin = 5, - .hsync_len = 3, - .vsync_len = 1, - .xres = 800, - .yres = 480, }; static struct s3c_fb_platdata smdkv210_lcd0_pdata __initdata = { .win[0] = &smdkv210_fb_win0, - .vtiming = &smdkv210_lcd_timing, .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, .setup_gpio = s5pv210_fb_gpio_setup_24bpp, diff --git a/trunk/arch/arm/mach-sa1100/neponset.c b/trunk/arch/arm/mach-sa1100/neponset.c index 266db873a4e4..6c58f01b358a 100644 --- a/trunk/arch/arm/mach-sa1100/neponset.c +++ b/trunk/arch/arm/mach-sa1100/neponset.c @@ -89,7 +89,6 @@ void neponset_ncr_frob(unsigned int mask, unsigned int val) WARN(1, "nep_base unset\n"); } } -EXPORT_SYMBOL(neponset_ncr_frob); static void neponset_set_mctrl(struct uart_port *port, u_int mctrl) { diff --git a/trunk/arch/arm/mach-ux500/board-mop500-uib.c b/trunk/arch/arm/mach-ux500/board-mop500-uib.c index 1f47d962e3a1..b29a788f498c 100644 --- a/trunk/arch/arm/mach-ux500/board-mop500-uib.c +++ b/trunk/arch/arm/mach-ux500/board-mop500-uib.c @@ -96,7 +96,7 @@ static void __init __mop500_uib_init(struct uib *uib, const char *why) /* * Detect the UIB attached based on the presence or absence of i2c devices. */ -int __init mop500_uib_init(void) +static int __init mop500_uib_init(void) { struct uib *uib = mop500_uib; struct i2c_adapter *i2c0; @@ -131,3 +131,5 @@ int __init mop500_uib_init(void) return 0; } + +module_init(mop500_uib_init); diff --git a/trunk/arch/arm/mach-ux500/board-mop500.c b/trunk/arch/arm/mach-ux500/board-mop500.c index 9c74ac545849..fba8adea421e 100644 --- a/trunk/arch/arm/mach-ux500/board-mop500.c +++ b/trunk/arch/arm/mach-ux500/board-mop500.c @@ -673,15 +673,9 @@ static void __init u8500_cryp1_hash1_init(struct device *parent) static struct platform_device *snowball_platform_devs[] __initdata = { &snowball_led_dev, &snowball_key_dev, - &snowball_sbnet_dev, &ab8500_device, }; -static struct platform_device *snowball_of_platform_devs[] __initdata = { - &snowball_led_dev, - &snowball_key_dev, -}; - static void __init mop500_init_machine(void) { struct device *parent = NULL; @@ -716,8 +710,6 @@ static void __init mop500_init_machine(void) /* This board has full regulator constraints */ regulator_has_full_constraints(); - - mop500_uib_init(); } static void __init snowball_init_machine(void) @@ -782,8 +774,6 @@ static void __init hrefv60_init_machine(void) /* This board has full regulator constraints */ regulator_has_full_constraints(); - - mop500_uib_init(); } MACHINE_START(U8500, "ST-Ericsson MOP500 platform") @@ -844,10 +834,6 @@ struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = { static const struct of_device_id u8500_local_bus_nodes[] = { /* only create devices below soc node */ { .compatible = "stericsson,db8500", }, - { .compatible = "stericsson,db8500-prcmu", }, - { .compatible = "stericsson,db8500-prcmu-regulator", }, - { .compatible = "stericsson,ab8500", }, - { .compatible = "stericsson,ab8500-regulator", }, { .compatible = "simple-bus"}, { }, }; @@ -866,7 +852,7 @@ static void __init u8500_init_machine(void) else if (of_machine_is_compatible("st-ericsson,hrefv60+")) hrefv60_pinmaps_init(); - parent = u8500_of_init_devices(); + parent = u8500_init_devices(); for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++) mop500_platform_devs[i]->dev.parent = parent; @@ -883,23 +869,15 @@ static void __init u8500_init_machine(void) ARRAY_SIZE(mop500_platform_devs)); mop500_sdi_init(parent); + i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices); i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs); i2c_register_board_info(2, mop500_i2c2_devices, ARRAY_SIZE(mop500_i2c2_devices)); - mop500_uib_init(); - } else if (of_machine_is_compatible("calaosystems,snowball-a9500")) { - /* - * Devices to be DT:ed: - * snowball_led_dev = todo - * snowball_key_dev = todo - * snowball_sbnet_dev = done - * ab8500_device = done - */ - platform_add_devices(snowball_of_platform_devs, - ARRAY_SIZE(snowball_of_platform_devs)); + platform_add_devices(snowball_platform_devs, + ARRAY_SIZE(snowball_platform_devs)); snowball_sdi_init(parent); } else if (of_machine_is_compatible("st-ericsson,hrefv60+")) { @@ -920,8 +898,6 @@ static void __init u8500_init_machine(void) i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs); i2c_register_board_info(2, mop500_i2c2_devices, ARRAY_SIZE(mop500_i2c2_devices)); - - mop500_uib_init(); } mop500_i2c_init(parent); diff --git a/trunk/arch/arm/mach-ux500/board-mop500.h b/trunk/arch/arm/mach-ux500/board-mop500.h index 2f87b25a908a..bc44c07c71a9 100644 --- a/trunk/arch/arm/mach-ux500/board-mop500.h +++ b/trunk/arch/arm/mach-ux500/board-mop500.h @@ -89,11 +89,7 @@ void __init mop500_pinmaps_init(void); void __init snowball_pinmaps_init(void); void __init hrefv60_pinmaps_init(void); -int __init mop500_uib_init(void); void mop500_uib_i2c_add(int busnum, struct i2c_board_info *info, unsigned n); -/* TODO: Once all pieces are DT:ed, remove completely. */ -struct device * __init u8500_of_init_devices(void); - #endif diff --git a/trunk/arch/arm/mach-ux500/cpu-db8500.c b/trunk/arch/arm/mach-ux500/cpu-db8500.c index 33275eb4c689..16169c4bf6ca 100644 --- a/trunk/arch/arm/mach-ux500/cpu-db8500.c +++ b/trunk/arch/arm/mach-ux500/cpu-db8500.c @@ -140,6 +140,7 @@ static struct platform_device *platform_devs[] __initdata = { static struct platform_device *of_platform_devs[] __initdata = { &u8500_dma40_device, &db8500_pmu_device, + &db8500_prcmu_device, }; static resource_size_t __initdata db8500_gpio_base[] = { @@ -218,28 +219,6 @@ struct device * __init u8500_init_devices(void) db8500_add_gpios(parent); db8500_add_usb(parent, usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg); - platform_device_register_data(parent, - "cpufreq-u8500", -1, NULL, 0); - - for (i = 0; i < ARRAY_SIZE(platform_devs); i++) - platform_devs[i]->dev.parent = parent; - - platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs)); - - return parent; -} - -/* TODO: Once all pieces are DT:ed, remove completely. */ -struct device * __init u8500_of_init_devices(void) -{ - struct device *parent; - int i; - - parent = db8500_soc_device_init(); - - db8500_add_rtc(parent); - db8500_add_usb(parent, usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg); - platform_device_register_data(parent, "cpufreq-u8500", -1, NULL, 0); @@ -250,7 +229,7 @@ struct device * __init u8500_of_init_devices(void) * Devices to be DT:ed: * u8500_dma40_device = todo * db8500_pmu_device = todo - * db8500_prcmu_device = done + * db8500_prcmu_device = todo */ platform_add_devices(of_platform_devs, ARRAY_SIZE(of_platform_devs)); diff --git a/trunk/arch/arm/mach-vexpress/v2m.c b/trunk/arch/arm/mach-vexpress/v2m.c index fde26adaef32..04dd092211b8 100644 --- a/trunk/arch/arm/mach-vexpress/v2m.c +++ b/trunk/arch/arm/mach-vexpress/v2m.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,7 @@ #include #include #include +#include #include #include diff --git a/trunk/arch/arm/plat-omap/include/plat/gpmc.h b/trunk/arch/arm/plat-omap/include/plat/gpmc.h index f37764a36072..1527929b445a 100644 --- a/trunk/arch/arm/plat-omap/include/plat/gpmc.h +++ b/trunk/arch/arm/plat-omap/include/plat/gpmc.h @@ -92,8 +92,6 @@ enum omap_ecc { OMAP_ECC_HAMMING_CODE_HW, /* gpmc to detect the error */ /* 1-bit ecc: stored at beginning of spare area as romcode */ OMAP_ECC_HAMMING_CODE_HW_ROMCODE, /* gpmc method & romcode layout */ - OMAP_ECC_BCH4_CODE_HW, /* 4-bit BCH ecc code */ - OMAP_ECC_BCH8_CODE_HW, /* 8-bit BCH ecc code */ }; /* @@ -159,13 +157,4 @@ extern int gpmc_nand_write(int cs, int cmd, int wval); int gpmc_enable_hwecc(int cs, int mode, int dev_width, int ecc_size); int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code); - -#ifdef CONFIG_ARCH_OMAP3 -int gpmc_init_hwecc_bch(int cs, int nsectors, int nerrors); -int gpmc_enable_hwecc_bch(int cs, int mode, int dev_width, int nsectors, - int nerrors); -int gpmc_calculate_ecc_bch4(int cs, const u_char *dat, u_char *ecc); -int gpmc_calculate_ecc_bch8(int cs, const u_char *dat, u_char *ecc); -#endif /* CONFIG_ARCH_OMAP3 */ - #endif diff --git a/trunk/arch/arm/plat-samsung/include/plat/fb.h b/trunk/arch/arm/plat-samsung/include/plat/fb.h index 536002ff2ab8..0fedf47fa502 100644 --- a/trunk/arch/arm/plat-samsung/include/plat/fb.h +++ b/trunk/arch/arm/plat-samsung/include/plat/fb.h @@ -24,16 +24,15 @@ /** * struct s3c_fb_pd_win - per window setup data - * @xres : The window X size. - * @yres : The window Y size. + * @win_mode: The display parameters to initialise (not for window 0) * @virtual_x: The virtual X size. * @virtual_y: The virtual Y size. */ struct s3c_fb_pd_win { + struct fb_videomode win_mode; + unsigned short default_bpp; unsigned short max_bpp; - unsigned short xres; - unsigned short yres; unsigned short virtual_x; unsigned short virtual_y; }; @@ -46,7 +45,6 @@ struct s3c_fb_pd_win { * @default_win: default window layer number to be used for UI layer. * @vidcon0: The base vidcon0 values to control the panel data format. * @vidcon1: The base vidcon1 values to control the panel data output. - * @vtiming: Video timing when connected to a RGB type panel. * @win: The setup data for each hardware window, or NULL for unused. * @display_mode: The LCD output display mode. * @@ -60,7 +58,8 @@ struct s3c_fb_platdata { void (*setup_gpio)(void); struct s3c_fb_pd_win *win[S3C_FB_MAX_WIN]; - struct fb_videomode *vtiming; + + u32 default_win; u32 vidcon0; u32 vidcon1; diff --git a/trunk/arch/arm/plat-samsung/include/plat/s3c2416.h b/trunk/arch/arm/plat-samsung/include/plat/s3c2416.h index 7178e338e25e..de2b5bdc5ebd 100644 --- a/trunk/arch/arm/plat-samsung/include/plat/s3c2416.h +++ b/trunk/arch/arm/plat-samsung/include/plat/s3c2416.h @@ -24,9 +24,6 @@ extern void s3c2416_init_clocks(int xtal); extern int s3c2416_baseclk_add(void); extern void s3c2416_restart(char mode, const char *cmd); - -extern struct syscore_ops s3c2416_irq_syscore_ops; - #else #define s3c2416_init_clocks NULL #define s3c2416_init_uarts NULL diff --git a/trunk/arch/avr32/include/asm/posix_types.h b/trunk/arch/avr32/include/asm/posix_types.h index 9ba9e749b3f3..74667bfc88cc 100644 --- a/trunk/arch/avr32/include/asm/posix_types.h +++ b/trunk/arch/avr32/include/asm/posix_types.h @@ -17,6 +17,9 @@ typedef unsigned short __kernel_mode_t; #define __kernel_mode_t __kernel_mode_t +typedef unsigned short __kernel_nlink_t; +#define __kernel_nlink_t __kernel_nlink_t + typedef unsigned short __kernel_ipc_pid_t; #define __kernel_ipc_pid_t __kernel_ipc_pid_t diff --git a/trunk/arch/avr32/kernel/entry-avr32b.S b/trunk/arch/avr32/kernel/entry-avr32b.S index df2884181313..169268c40ae2 100644 --- a/trunk/arch/avr32/kernel/entry-avr32b.S +++ b/trunk/arch/avr32/kernel/entry-avr32b.S @@ -281,7 +281,7 @@ syscall_exit_work: ld.w r1, r0[TI_flags] rjmp 1b -2: mov r2, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME +2: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NOTIFY_RESUME tst r1, r2 breq 3f unmask_interrupts @@ -587,7 +587,7 @@ fault_exit_work: ld.w r1, r0[TI_flags] rjmp fault_exit_work -1: mov r2, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME +1: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK tst r1, r2 breq 2f unmask_interrupts diff --git a/trunk/arch/avr32/kernel/signal.c b/trunk/arch/avr32/kernel/signal.c index c140f9b41dce..ae386c304bee 100644 --- a/trunk/arch/avr32/kernel/signal.c +++ b/trunk/arch/avr32/kernel/signal.c @@ -22,6 +22,8 @@ #include #include +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, struct pt_regs *regs) { @@ -87,6 +89,7 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) @@ -221,27 +224,30 @@ static inline void setup_syscall_restart(struct pt_regs *regs) static inline void handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, - struct pt_regs *regs, int syscall) + sigset_t *oldset, struct pt_regs *regs, int syscall) { int ret; /* * Set up the stack frame */ - ret = setup_rt_frame(sig, ka, info, sigmask_to_save(), regs); + ret = setup_rt_frame(sig, ka, info, oldset, regs); /* * Check that the resulting registers are sane */ ret |= !valid_user_regs(regs); + if (ret != 0) { + force_sigsegv(sig, current); + return; + } + /* * Block the signal if we were successful. */ - if (ret != 0) - force_sigsegv(sig, current); - else - signal_delivered(sig, info, ka, regs, 0); + block_sigmask(ka, sig); + clear_thread_flag(TIF_RESTORE_SIGMASK); } /* @@ -249,7 +255,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, * doesn't want to handle. Thus you cannot kill init even with a * SIGKILL even by mistake. */ -static void do_signal(struct pt_regs *regs, int syscall) +int do_signal(struct pt_regs *regs, sigset_t *oldset, int syscall) { siginfo_t info; int signr; @@ -261,7 +267,12 @@ static void do_signal(struct pt_regs *regs, int syscall) * without doing anything if so. */ if (!user_mode(regs)) - return; + return 0; + + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else if (!oldset) + oldset = ¤t->blocked; signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (syscall) { @@ -286,11 +297,15 @@ static void do_signal(struct pt_regs *regs, int syscall) if (signr == 0) { /* No signal to deliver -- put the saved sigmask back */ - restore_saved_sigmask(); - return; + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } + return 0; } - handle_signal(signr, &ka, &info, regs, syscall); + handle_signal(signr, &ka, &info, oldset, regs, syscall); + return 1; } asmlinkage void do_notify_resume(struct pt_regs *regs, struct thread_info *ti) @@ -300,11 +315,13 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, struct thread_info *ti) if ((sysreg_read(SR) & MODE_MASK) == MODE_SUPERVISOR) syscall = 1; - if (ti->flags & _TIF_SIGPENDING)) - do_signal(regs, syscall); + if (ti->flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) + do_signal(regs, ¤t->blocked, syscall); if (ti->flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/trunk/arch/blackfin/include/asm/posix_types.h b/trunk/arch/blackfin/include/asm/posix_types.h index 1bd3436db6a7..41bc1875c4d7 100644 --- a/trunk/arch/blackfin/include/asm/posix_types.h +++ b/trunk/arch/blackfin/include/asm/posix_types.h @@ -10,6 +10,9 @@ typedef unsigned short __kernel_mode_t; #define __kernel_mode_t __kernel_mode_t +typedef unsigned short __kernel_nlink_t; +#define __kernel_nlink_t __kernel_nlink_t + typedef unsigned int __kernel_ipc_pid_t; #define __kernel_ipc_pid_t __kernel_ipc_pid_t diff --git a/trunk/arch/blackfin/include/asm/thread_info.h b/trunk/arch/blackfin/include/asm/thread_info.h index 53ad10005ae3..02560fd8a121 100644 --- a/trunk/arch/blackfin/include/asm/thread_info.h +++ b/trunk/arch/blackfin/include/asm/thread_info.h @@ -100,6 +100,7 @@ static inline struct thread_info *current_thread_info(void) TIF_NEED_RESCHED */ #define TIF_MEMDIE 4 /* is terminating due to OOM killer */ #define TIF_RESTORE_SIGMASK 5 /* restore signal mask in do_signal() */ +#define TIF_FREEZE 6 /* is freezing for suspend */ #define TIF_IRQ_SYNC 7 /* sync pipeline stage */ #define TIF_NOTIFY_RESUME 8 /* callback before returning to user */ #define TIF_SINGLESTEP 9 @@ -110,6 +111,7 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_NEED_RESCHED (1< #include +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + /* Location of the trace bit in SYSCFG. */ #define TRACE_BITS 0x0001 @@ -96,6 +98,7 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused) if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (rt_restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0)) @@ -187,22 +190,17 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t * info, err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); if (err) - return -EFAULT; + goto give_sigsegv; /* Set up registers for signal handler */ + wrusp((unsigned long)frame); if (current->personality & FDPIC_FUNCPTRS) { struct fdpic_func_descriptor __user *funcptr = (struct fdpic_func_descriptor *) ka->sa.sa_handler; - u32 pc, p3; - err |= __get_user(pc, &funcptr->text); - err |= __get_user(p3, &funcptr->GOT); - if (err) - return -EFAULT; - regs->pc = pc; - regs->p3 = p3; + __get_user(regs->pc, &funcptr->text); + __get_user(regs->p3, &funcptr->GOT); } else regs->pc = (unsigned long)ka->sa.sa_handler; - wrusp((unsigned long)frame); regs->rets = SIGRETURN_STUB; regs->r0 = frame->sig; @@ -210,6 +208,10 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t * info, regs->r2 = (unsigned long)(&frame->uc); return 0; + + give_sigsegv: + force_sigsegv(sig, current); + return -EFAULT; } static inline void @@ -245,21 +247,24 @@ handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) /* * OK, we're invoking a handler */ -static void +static int handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka, - struct pt_regs *regs) + sigset_t *oldset, struct pt_regs *regs) { + int ret; + /* are we from a system call? to see pt_regs->orig_p0 */ if (regs->orig_p0 >= 0) /* If so, check system call restarting.. */ handle_restart(regs, ka, 1); /* set up the stack frame */ - if (setup_rt_frame(sig, ka, info, sigmask_to_save(), regs) < 0) - force_sigsegv(sig, current); - else - signal_delivered(sig, info, ka, regs, - test_thread_flag(TIF_SINGLESTEP)); + ret = setup_rt_frame(sig, ka, info, oldset, regs); + + if (ret == 0) + block_sigmask(ka, sig); + + return ret; } /* @@ -276,16 +281,37 @@ asmlinkage void do_signal(struct pt_regs *regs) siginfo_t info; int signr; struct k_sigaction ka; + sigset_t *oldset; current->thread.esp0 = (unsigned long)regs; + if (try_to_freeze()) + goto no_signal; + + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { /* Whee! Actually deliver the signal. */ - handle_signal(signr, &info, &ka, regs); + if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { + /* a signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TIF_RESTORE_SIGMASK flag */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + + tracehook_signal_handler(signr, &info, &ka, regs, + test_thread_flag(TIF_SINGLESTEP)); + } + return; } + no_signal: /* Did we come from a system call? */ if (regs->orig_p0 >= 0) /* Restart the system call - no handlers present */ @@ -293,7 +319,10 @@ asmlinkage void do_signal(struct pt_regs *regs) /* if there's no signal to deliver, we just put the saved sigmask * back */ - restore_saved_sigmask(); + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } } /* @@ -301,12 +330,14 @@ asmlinkage void do_signal(struct pt_regs *regs) */ asmlinkage void do_notify_resume(struct pt_regs *regs) { - if (test_thread_flag(TIF_SIGPENDING)) + if (test_thread_flag(TIF_SIGPENDING) || test_thread_flag(TIF_RESTORE_SIGMASK)) do_signal(regs); if (test_thread_flag(TIF_NOTIFY_RESUME)) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/trunk/arch/blackfin/mach-bf561/boards/acvilon.c b/trunk/arch/blackfin/mach-bf561/boards/acvilon.c index 0b74218fdd3a..f6ffd6f054c3 100644 --- a/trunk/arch/blackfin/mach-bf561/boards/acvilon.c +++ b/trunk/arch/blackfin/mach-bf561/boards/acvilon.c @@ -248,6 +248,8 @@ static struct platform_device bfin_uart0_device = { #if defined(CONFIG_MTD_NAND_PLATFORM) || defined(CONFIG_MTD_NAND_PLATFORM_MODULE) +const char *part_probes[] = { "cmdlinepart", NULL }; + static struct mtd_partition bfin_plat_nand_partitions[] = { { .name = "params(nand)", @@ -287,6 +289,7 @@ static struct platform_nand_data bfin_plat_nand_data = { .chip = { .nr_chips = 1, .chip_delay = 30, + .part_probe_types = part_probes, .partitions = bfin_plat_nand_partitions, .nr_partitions = ARRAY_SIZE(bfin_plat_nand_partitions), }, diff --git a/trunk/arch/blackfin/mach-common/entry.S b/trunk/arch/blackfin/mach-common/entry.S index 04c2fbe41a7f..80aa2535e2c9 100644 --- a/trunk/arch/blackfin/mach-common/entry.S +++ b/trunk/arch/blackfin/mach-common/entry.S @@ -711,6 +711,8 @@ ENTRY(_system_call) jump .Lresume_userspace_1; .Lsyscall_sigpending: + cc = BITTST(r7, TIF_RESTORE_SIGMASK); + if cc jump .Lsyscall_do_signals; cc = BITTST(r7, TIF_SIGPENDING); if cc jump .Lsyscall_do_signals; cc = BITTST(r7, TIF_NOTIFY_RESUME); diff --git a/trunk/arch/c6x/kernel/signal.c b/trunk/arch/c6x/kernel/signal.c index 3d8f3c22a94f..cf37478c1169 100644 --- a/trunk/arch/c6x/kernel/signal.c +++ b/trunk/arch/c6x/kernel/signal.c @@ -20,6 +20,8 @@ #include +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + /* * Do a signal return, undo the signal stack. */ @@ -85,6 +87,7 @@ asmlinkage int do_rt_sigreturn(struct pt_regs *regs) if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) @@ -245,9 +248,10 @@ handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) /* * handle the actual delivery of a signal to userspace */ -static void handle_signal(int sig, +static int handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka, - struct pt_regs *regs, int syscall) + sigset_t *oldset, struct pt_regs *regs, + int syscall) { int ret; @@ -274,9 +278,11 @@ static void handle_signal(int sig, } /* Set up the stack frame */ - if (setup_rt_frame(sig, ka, info, sigmask_to_save(), regs) < 0) - return; - signal_delivered(sig, info, ka, regs, 0); + ret = setup_rt_frame(sig, ka, info, oldset, regs); + if (ret == 0) + block_sigmask(ka, sig); + + return ret; } /* @@ -286,6 +292,7 @@ static void do_signal(struct pt_regs *regs, int syscall) { struct k_sigaction ka; siginfo_t info; + sigset_t *oldset; int signr; /* we want the common case to go fast, which is why we may in certain @@ -293,9 +300,25 @@ static void do_signal(struct pt_regs *regs, int syscall) if (!user_mode(regs)) return; + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { - handle_signal(signr, &info, &ka, regs, syscall); + if (handle_signal(signr, &info, &ka, oldset, + regs, syscall) == 0) { + /* a signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TIF_RESTORE_SIGMASK flag */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + + tracehook_signal_handler(signr, &info, &ka, regs, 0); + } + return; } @@ -320,7 +343,10 @@ static void do_signal(struct pt_regs *regs, int syscall) /* if there's no signal to deliver, we just put the saved sigmask * back */ - restore_saved_sigmask(); + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } } /* @@ -331,11 +357,14 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags, int syscall) { /* deal with pending signal delivery */ - if (thread_info_flags & (1 << TIF_SIGPENDING)) + if (thread_info_flags & ((1 << TIF_SIGPENDING) | + (1 << TIF_RESTORE_SIGMASK))) do_signal(regs, syscall); if (thread_info_flags & (1 << TIF_NOTIFY_RESUME)) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/trunk/arch/cris/arch-v10/kernel/signal.c b/trunk/arch/cris/arch-v10/kernel/signal.c index 0bb477c13a4e..e16f8f297f61 100644 --- a/trunk/arch/cris/arch-v10/kernel/signal.c +++ b/trunk/arch/cris/arch-v10/kernel/signal.c @@ -31,6 +31,8 @@ #define DEBUG_SIG 0 +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + /* a syscall in Linux/CRIS is a break 13 instruction which is 2 bytes */ /* manipulate regs so that upon return, it will be re-executed */ @@ -174,6 +176,7 @@ asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof, sizeof(frame->extramask)))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(regs, &frame->sc)) @@ -209,6 +212,7 @@ asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13, if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) @@ -411,11 +415,10 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, * OK, we're invoking a handler */ -static inline void handle_signal(int canrestart, unsigned long sig, +static inline int handle_signal(int canrestart, unsigned long sig, siginfo_t *info, struct k_sigaction *ka, - struct pt_regs *regs) + sigset_t *oldset, struct pt_regs *regs) { - sigset_t *oldset = sigmask_to_save(); int ret; /* Are we from a system call? */ @@ -453,7 +456,9 @@ static inline void handle_signal(int canrestart, unsigned long sig, ret = setup_frame(sig, ka, oldset, regs); if (ret == 0) - signal_delivered(sig, info, ka, regs, 0); + block_sigmask(ka, sig); + + return ret; } /* @@ -473,6 +478,7 @@ void do_signal(int canrestart, struct pt_regs *regs) siginfo_t info; int signr; struct k_sigaction ka; + sigset_t *oldset; /* * We want the common case to go fast, which @@ -483,10 +489,23 @@ void do_signal(int canrestart, struct pt_regs *regs) if (!user_mode(regs)) return; + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { /* Whee! Actually deliver the signal. */ - handle_signal(canrestart, signr, &info, &ka, regs); + if (handle_signal(canrestart, signr, &info, &ka, + oldset, regs)) { + /* a signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TIF_RESTORE_SIGMASK flag */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + } return; } @@ -506,5 +525,8 @@ void do_signal(int canrestart, struct pt_regs *regs) /* if there's no signal to deliver, we just put the saved sigmask * back */ - restore_saved_sigmask(); + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } } diff --git a/trunk/arch/cris/arch-v32/kernel/signal.c b/trunk/arch/cris/arch-v32/kernel/signal.c index b60d1b65a426..b338d8fc0c12 100644 --- a/trunk/arch/cris/arch-v32/kernel/signal.c +++ b/trunk/arch/cris/arch-v32/kernel/signal.c @@ -24,6 +24,9 @@ extern unsigned long cris_signal_return_page; +/* Flag to check if a signal is blockable. */ +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + /* * A syscall in CRIS is really a "break 13" instruction, which is 2 * bytes. The registers is manipulated so upon return the instruction @@ -164,6 +167,7 @@ sys_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp, sizeof(frame->extramask)))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(regs, &frame->sc)) @@ -204,6 +208,7 @@ sys_rt_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp, if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) @@ -429,12 +434,11 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, } /* Invoke a signal handler to, well, handle the signal. */ -static inline void +static inline int handle_signal(int canrestart, unsigned long sig, siginfo_t *info, struct k_sigaction *ka, - struct pt_regs * regs) + sigset_t *oldset, struct pt_regs * regs) { - sigset_t *oldset = sigmask_to_save(); int ret; /* Check if this got called from a system call. */ @@ -485,7 +489,9 @@ handle_signal(int canrestart, unsigned long sig, ret = setup_frame(sig, ka, oldset, regs); if (ret == 0) - signal_delivered(sig, info, ka, regs, 0); + block_sigmask(ka, sig); + + return ret; } /* @@ -505,6 +511,7 @@ do_signal(int canrestart, struct pt_regs *regs) int signr; siginfo_t info; struct k_sigaction ka; + sigset_t *oldset; /* * The common case should go fast, which is why this point is @@ -514,11 +521,25 @@ do_signal(int canrestart, struct pt_regs *regs) if (!user_mode(regs)) return; + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { /* Whee! Actually deliver the signal. */ - handle_signal(canrestart, signr, &info, &ka, regs); + if (handle_signal(canrestart, signr, &info, &ka, + oldset, regs)) { + /* a signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TIF_RESTORE_SIGMASK flag */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + } + return; } @@ -539,7 +560,10 @@ do_signal(int canrestart, struct pt_regs *regs) /* if there's no signal to deliver, we just put the saved sigmask * back */ - restore_saved_sigmask(); + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } } asmlinkage void diff --git a/trunk/arch/cris/include/asm/posix_types.h b/trunk/arch/cris/include/asm/posix_types.h index ce4e51793151..234891c74e2b 100644 --- a/trunk/arch/cris/include/asm/posix_types.h +++ b/trunk/arch/cris/include/asm/posix_types.h @@ -15,6 +15,9 @@ typedef unsigned short __kernel_mode_t; #define __kernel_mode_t __kernel_mode_t +typedef unsigned short __kernel_nlink_t; +#define __kernel_nlink_t __kernel_nlink_t + typedef unsigned short __kernel_ipc_pid_t; #define __kernel_ipc_pid_t __kernel_ipc_pid_t diff --git a/trunk/arch/cris/kernel/ptrace.c b/trunk/arch/cris/kernel/ptrace.c index 58d44ee1a71f..d114ad3da9b1 100644 --- a/trunk/arch/cris/kernel/ptrace.c +++ b/trunk/arch/cris/kernel/ptrace.c @@ -40,5 +40,7 @@ void do_notify_resume(int canrestart, struct pt_regs *regs, if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/trunk/arch/frv/include/asm/posix_types.h b/trunk/arch/frv/include/asm/posix_types.h index fe512af74a5a..3f34cb45fbb3 100644 --- a/trunk/arch/frv/include/asm/posix_types.h +++ b/trunk/arch/frv/include/asm/posix_types.h @@ -10,6 +10,9 @@ typedef unsigned short __kernel_mode_t; #define __kernel_mode_t __kernel_mode_t +typedef unsigned short __kernel_nlink_t; +#define __kernel_nlink_t __kernel_nlink_t + typedef unsigned short __kernel_ipc_pid_t; #define __kernel_ipc_pid_t __kernel_ipc_pid_t diff --git a/trunk/arch/frv/include/asm/thread_info.h b/trunk/arch/frv/include/asm/thread_info.h index 0ff03a33c81e..54ab13a0de41 100644 --- a/trunk/arch/frv/include/asm/thread_info.h +++ b/trunk/arch/frv/include/asm/thread_info.h @@ -94,8 +94,8 @@ register struct thread_info *__current_thread_info asm("gr15"); #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ #define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */ #define TIF_RESTORE_SIGMASK 5 /* restore signal mask in do_signal() */ -#define TIF_POLLING_NRFLAG 6 /* true if poll_idle() is polling TIF_NEED_RESCHED */ -#define TIF_MEMDIE 7 /* is terminating due to OOM killer */ +#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ +#define TIF_MEMDIE 17 /* is terminating due to OOM killer */ #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) @@ -105,16 +105,8 @@ register struct thread_info *__current_thread_info asm("gr15"); #define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) -/* work to do on interrupt/exception return */ -#define _TIF_WORK_MASK \ - (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_SINGLESTEP) - -/* work to do on any return to u-space */ -#define _TIF_ALLWORK_MASK (_TIF_WORK_MASK | _TIF_SYSCALL_TRACE) - -#if _TIF_ALLWORK_MASK >= 0x2000 -#error "_TIF_ALLWORK_MASK won't fit in an ANDI now (see entry.S)" -#endif +#define _TIF_WORK_MASK 0x0000FFFE /* work to do on interrupt/exception return */ +#define _TIF_ALLWORK_MASK 0x0000FFFF /* work to do on any return to u-space */ /* * Thread-synchronous status. diff --git a/trunk/arch/frv/kernel/entry.S b/trunk/arch/frv/kernel/entry.S index 7d5e000fd32e..5ba23f715ea5 100644 --- a/trunk/arch/frv/kernel/entry.S +++ b/trunk/arch/frv/kernel/entry.S @@ -905,19 +905,18 @@ __syscall_call: __syscall_exit: LEDS 0x6300 - # keep current PSR in GR23 - movsg psr,gr23 - - ldi @(gr28,#REG_PSR),gr22 - - sti.p gr8,@(gr28,#REG_GR(8)) ; save return value + sti gr8,@(gr28,#REG_GR(8)) ; save return value # rebuild saved psr - execve will change it for init/main.c + ldi @(gr28,#REG_PSR),gr22 srli gr22,#1,gr5 andi.p gr22,#~PSR_PS,gr22 andi gr5,#PSR_PS,gr5 or gr5,gr22,gr22 - ori.p gr22,#PSR_S,gr22 + ori gr22,#PSR_S,gr22 + + # keep current PSR in GR23 + movsg psr,gr23 # make sure we don't miss an interrupt setting need_resched or sigpending between # sampling and the RETT @@ -925,7 +924,9 @@ __syscall_exit: movgs gr23,psr ldi @(gr15,#TI_FLAGS),gr4 - andicc gr4,#_TIF_ALLWORK_MASK,gr0,icc0 + sethi.p %hi(_TIF_ALLWORK_MASK),gr5 + setlo %lo(_TIF_ALLWORK_MASK),gr5 + andcc gr4,gr5,gr0,icc0 bne icc0,#0,__syscall_exit_work # restore all registers and return @@ -1110,7 +1111,9 @@ __entry_resume_userspace: __entry_return_from_user_interrupt: LEDS 0x6402 ldi @(gr15,#TI_FLAGS),gr4 - andicc gr4,#_TIF_WORK_MASK,gr0,icc0 + sethi.p %hi(_TIF_WORK_MASK),gr5 + setlo %lo(_TIF_WORK_MASK),gr5 + andcc gr4,gr5,gr0,icc0 beq icc0,#1,__entry_return_direct __entry_work_pending: @@ -1130,7 +1133,9 @@ __entry_work_resched: LEDS 0x6401 ldi @(gr15,#TI_FLAGS),gr4 - andicc gr4,#_TIF_WORK_MASK,gr0,icc0 + sethi.p %hi(_TIF_WORK_MASK),gr5 + setlo %lo(_TIF_WORK_MASK),gr5 + andcc gr4,gr5,gr0,icc0 beq icc0,#1,__entry_return_direct andicc gr4,#_TIF_NEED_RESCHED,gr0,icc0 bne icc0,#1,__entry_work_resched @@ -1158,9 +1163,7 @@ __syscall_trace_entry: # perform syscall exit tracing __syscall_exit_work: LEDS 0x6340 - andicc gr22,#PSR_PS,gr0,icc1 ; don't handle on return to kernel mode - andicc.p gr4,#_TIF_SYSCALL_TRACE,gr0,icc0 - bne icc1,#0,__entry_return_direct + andicc gr4,#_TIF_SYSCALL_TRACE,gr0,icc0 beq icc0,#1,__entry_work_pending movsg psr,gr23 diff --git a/trunk/arch/frv/kernel/signal.c b/trunk/arch/frv/kernel/signal.c index f3b9064c548c..8cf5dca01758 100644 --- a/trunk/arch/frv/kernel/signal.c +++ b/trunk/arch/frv/kernel/signal.c @@ -28,6 +28,8 @@ #define DEBUG_SIG 0 +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + struct fdpic_func_descriptor { unsigned long text; unsigned long GOT; @@ -147,6 +149,7 @@ asmlinkage int sys_sigreturn(void) __copy_from_user(&set.sig[1], &frame->extramask, sizeof(frame->extramask))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(&frame->sc, &gr8)) @@ -169,6 +172,7 @@ asmlinkage int sys_rt_sigreturn(void) if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(&frame->uc.uc_mcontext, &gr8)) @@ -422,10 +426,9 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, /* * OK, we're invoking a handler */ -static void handle_signal(unsigned long sig, siginfo_t *info, - struct k_sigaction *ka) +static int handle_signal(unsigned long sig, siginfo_t *info, + struct k_sigaction *ka, sigset_t *oldset) { - sigset_t *oldset = sigmask_to_save(); int ret; /* Are we from a system call? */ @@ -457,11 +460,11 @@ static void handle_signal(unsigned long sig, siginfo_t *info, else ret = setup_frame(sig, ka, oldset); - if (ret) - return; + if (ret == 0) + block_sigmask(ka, sig); + + return ret; - signal_delivered(sig, info, ka, __frame, - test_thread_flag(TIF_SINGLESTEP)); } /* end handle_signal() */ /*****************************************************************************/ @@ -474,14 +477,44 @@ static void do_signal(void) { struct k_sigaction ka; siginfo_t info; + sigset_t *oldset; int signr; + /* + * We want the common case to go fast, which + * is why we may in certain cases get here from + * kernel mode. Just return without doing anything + * if so. + */ + if (!user_mode(__frame)) + return; + + if (try_to_freeze()) + goto no_signal; + + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + signr = get_signal_to_deliver(&info, &ka, __frame, NULL); if (signr > 0) { - handle_signal(signr, &info, &ka); + if (handle_signal(signr, &info, &ka, oldset) == 0) { + /* a signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TIF_RESTORE_SIGMASK flag */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + + tracehook_signal_handler(signr, &info, &ka, __frame, + test_thread_flag(TIF_SINGLESTEP)); + } + return; } +no_signal: /* Did we come from a system call? */ if (__frame->syscallno != -1) { /* Restart the system call - no handlers present */ @@ -503,7 +536,11 @@ static void do_signal(void) /* if there's no signal to deliver, we just put the saved sigmask * back */ - restore_saved_sigmask(); + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } + } /* end do_signal() */ /*****************************************************************************/ @@ -518,13 +555,15 @@ asmlinkage void do_notify_resume(__u32 thread_info_flags) clear_thread_flag(TIF_SINGLESTEP); /* deal with pending signal delivery */ - if (thread_info_flags & _TIF_SIGPENDING)) + if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) do_signal(); /* deal with notification on about to resume userspace execution */ if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(__frame); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } /* end do_notify_resume() */ diff --git a/trunk/arch/h8300/include/asm/posix_types.h b/trunk/arch/h8300/include/asm/posix_types.h index 91e62ba4c7b0..bc4c34efb1ad 100644 --- a/trunk/arch/h8300/include/asm/posix_types.h +++ b/trunk/arch/h8300/include/asm/posix_types.h @@ -10,6 +10,9 @@ typedef unsigned short __kernel_mode_t; #define __kernel_mode_t __kernel_mode_t +typedef unsigned short __kernel_nlink_t; +#define __kernel_nlink_t __kernel_nlink_t + typedef unsigned short __kernel_ipc_pid_t; #define __kernel_ipc_pid_t __kernel_ipc_pid_t diff --git a/trunk/arch/h8300/kernel/signal.c b/trunk/arch/h8300/kernel/signal.c index fca10378701b..d4b0555d2904 100644 --- a/trunk/arch/h8300/kernel/signal.c +++ b/trunk/arch/h8300/kernel/signal.c @@ -47,6 +47,8 @@ #include #include +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + /* * Atomically swap in the new signal mask, and wait for a signal. */ @@ -184,6 +186,7 @@ asmlinkage int do_sigreturn(unsigned long __unused,...) sizeof(frame->extramask)))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(regs, &frame->sc, &er0)) @@ -208,6 +211,7 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused,...) if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &er0)) @@ -408,9 +412,8 @@ static int setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, */ static void handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, - struct pt_regs * regs) + sigset_t *oldset, struct pt_regs * regs) { - sigset_t *oldset = sigmask_to_save(); int ret; /* are we from a system call? */ if (regs->orig_er0 >= 0) { @@ -438,8 +441,10 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, else ret = setup_frame(sig, ka, oldset, regs); - if (!ret) - signal_delivered(sig, info, ka, regs, 0); + if (!ret) { + block_sigmask(ka, sig); + clear_thread_flag(TIF_RESTORE_SIGMASK); + } } /* @@ -452,6 +457,7 @@ statis void do_signal(struct pt_regs *regs) siginfo_t info; int signr; struct k_sigaction ka; + sigset_t *oldset; /* * We want the common case to go fast, which @@ -462,14 +468,23 @@ statis void do_signal(struct pt_regs *regs) if ((regs->ccr & 0x10)) return; + if (try_to_freeze()) + goto no_signal; + current->thread.esp0 = (unsigned long) regs; + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { /* Whee! Actually deliver the signal. */ - handle_signal(signr, &info, &ka, regs); + handle_signal(signr, &info, &ka, oldset, regs); return; } + no_signal: /* Did we come from a system call? */ if (regs->orig_er0 >= 0) { /* Restart the system call - no handlers present */ @@ -486,7 +501,8 @@ statis void do_signal(struct pt_regs *regs) } /* If there's no signal to deliver, we just restore the saved mask. */ - restore_saved_sigmask(); + if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK)) + set_current_blocked(¤t->saved_sigmask); } asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags) @@ -497,5 +513,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags) if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/trunk/arch/hexagon/kernel/signal.c b/trunk/arch/hexagon/kernel/signal.c index 304b0808d072..434866eb0f1c 100644 --- a/trunk/arch/hexagon/kernel/signal.c +++ b/trunk/arch/hexagon/kernel/signal.c @@ -31,6 +31,8 @@ #include #include +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + struct rt_sigframe { unsigned long tramp[2]; struct siginfo info; @@ -147,9 +149,11 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, /* * Setup invocation of signal handler */ -static void handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka, - struct pt_regs *regs) +static int handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka, + sigset_t *oldset, struct pt_regs *regs) { + int rc; + /* * If we're handling a signal that aborted a system call, * set up the error return value before adding the signal @@ -182,12 +186,15 @@ static void handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka, * Set up the stack frame; not doing the SA_SIGINFO thing. We * only set up the rt_frame flavor. */ + rc = setup_rt_frame(sig, ka, info, oldset, regs); + /* If there was an error on setup, no signal was delivered. */ - if (setup_rt_frame(sig, ka, info, sigmask_to_save(), regs) < 0) - return; + if (rc) + return rc; + + block_sigmask(ka, sig); - signal_delivered(sig, info, ka, regs, - test_thread_flag(TIF_SINGLESTEP)); + return 0; } /* @@ -202,13 +209,34 @@ static void do_signal(struct pt_regs *regs) if (!user_mode(regs)) return; + if (try_to_freeze()) + goto no_signal; + signo = get_signal_to_deliver(&info, &sigact, regs, NULL); if (signo > 0) { - handle_signal(signo, &info, &sigact, regs); + sigset_t *oldset; + + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + + if (handle_signal(signo, &info, &sigact, oldset, regs) == 0) { + /* + * Successful delivery case. The saved sigmask is + * stored in the signal frame, and will be restored + * by sigreturn. We can clear the TIF flag. + */ + clear_thread_flag(TIF_RESTORE_SIGMASK); + + tracehook_signal_handler(signo, &info, &sigact, regs, + test_thread_flag(TIF_SINGLESTEP)); + } return; } +no_signal: /* * If we came from a system call, handle the restart. */ @@ -231,7 +259,10 @@ static void do_signal(struct pt_regs *regs) no_restart: /* If there's no signal to deliver, put the saved sigmask back */ - restore_saved_sigmask(); + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } } void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) @@ -242,6 +273,8 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } @@ -270,6 +303,7 @@ asmlinkage int sys_rt_sigreturn(void) if (__copy_from_user(&blocked, &frame->uc.uc_sigmask, sizeof(blocked))) goto badframe; + sigdelsetmask(&blocked, ~_BLOCKABLE); set_current_blocked(&blocked); if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) diff --git a/trunk/arch/ia64/include/asm/posix_types.h b/trunk/arch/ia64/include/asm/posix_types.h index 99ee1d6510cf..7323ab9467eb 100644 --- a/trunk/arch/ia64/include/asm/posix_types.h +++ b/trunk/arch/ia64/include/asm/posix_types.h @@ -1,6 +1,9 @@ #ifndef _ASM_IA64_POSIX_TYPES_H #define _ASM_IA64_POSIX_TYPES_H +typedef unsigned int __kernel_nlink_t; +#define __kernel_nlink_t __kernel_nlink_t + typedef unsigned long __kernel_sigset_t; /* at least 32 bits */ #include diff --git a/trunk/arch/ia64/include/asm/thread_info.h b/trunk/arch/ia64/include/asm/thread_info.h index f7ee85378311..310d9734f02d 100644 --- a/trunk/arch/ia64/include/asm/thread_info.h +++ b/trunk/arch/ia64/include/asm/thread_info.h @@ -141,23 +141,7 @@ static inline void set_restore_sigmask(void) { struct thread_info *ti = current_thread_info(); ti->status |= TS_RESTORE_SIGMASK; - WARN_ON(!test_bit(TIF_SIGPENDING, &ti->flags)); -} -static inline void clear_restore_sigmask(void) -{ - current_thread_info()->status &= ~TS_RESTORE_SIGMASK; -} -static inline bool test_restore_sigmask(void) -{ - return current_thread_info()->status & TS_RESTORE_SIGMASK; -} -static inline bool test_and_clear_restore_sigmask(void) -{ - struct thread_info *ti = current_thread_info(); - if (!(ti->status & TS_RESTORE_SIGMASK)) - return false; - ti->status &= ~TS_RESTORE_SIGMASK; - return true; + set_bit(TIF_SIGPENDING, &ti->flags); } #endif /* !__ASSEMBLY__ */ diff --git a/trunk/arch/ia64/kernel/perfmon.c b/trunk/arch/ia64/kernel/perfmon.c index d7f558c1e711..f00ba025375d 100644 --- a/trunk/arch/ia64/kernel/perfmon.c +++ b/trunk/arch/ia64/kernel/perfmon.c @@ -604,6 +604,12 @@ pfm_unprotect_ctx_ctxsw(pfm_context_t *x, unsigned long f) spin_unlock(&(x)->ctx_lock); } +static inline unsigned long +pfm_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags, unsigned long exec) +{ + return get_unmapped_area(file, addr, len, pgoff, flags); +} + /* forward declaration */ static const struct dentry_operations pfmfs_dentry_operations; @@ -2327,8 +2333,8 @@ pfm_smpl_buffer_alloc(struct task_struct *task, struct file *filp, pfm_context_t down_write(&task->mm->mmap_sem); /* find some free area in address space, must have mmap sem held */ - vma->vm_start = get_unmapped_area(NULL, 0, size, 0, MAP_PRIVATE|MAP_ANONYMOUS); - if (IS_ERR_VALUE(vma->vm_start)) { + vma->vm_start = pfm_get_unmapped_area(NULL, 0, size, 0, MAP_PRIVATE|MAP_ANONYMOUS, 0); + if (vma->vm_start == 0UL) { DPRINT(("Cannot find unmapped area for size %ld\n", size)); up_write(&task->mm->mmap_sem); goto error; diff --git a/trunk/arch/ia64/kernel/process.c b/trunk/arch/ia64/kernel/process.c index dd6fc1449741..5e0e86ddb12f 100644 --- a/trunk/arch/ia64/kernel/process.c +++ b/trunk/arch/ia64/kernel/process.c @@ -199,6 +199,8 @@ do_notify_resume_user(sigset_t *unused, struct sigscratch *scr, long in_syscall) if (test_thread_flag(TIF_NOTIFY_RESUME)) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(&scr->pt); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } /* copy user rbs to kernel rbs */ diff --git a/trunk/arch/ia64/kernel/signal.c b/trunk/arch/ia64/kernel/signal.c index a199be1fe619..7523501d3bc0 100644 --- a/trunk/arch/ia64/kernel/signal.c +++ b/trunk/arch/ia64/kernel/signal.c @@ -30,6 +30,7 @@ #define DEBUG_SIG 0 #define STACK_ALIGN 16 /* minimal alignment for stack pointer */ +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) #if _NSIG_WORDS > 1 # define PUT_SIGSET(k,u) __copy_to_user((u)->sig, (k)->sig, sizeof(sigset_t)) @@ -199,6 +200,7 @@ ia64_rt_sigreturn (struct sigscratch *scr) if (GET_SIGSET(&set, &sc->sc_mask)) goto give_sigsegv; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(sc, scr)) @@ -413,13 +415,18 @@ setup_frame (int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, } static long -handle_signal (unsigned long sig, struct k_sigaction *ka, siginfo_t *info, +handle_signal (unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct sigscratch *scr) { - if (!setup_frame(sig, ka, info, sigmask_to_save(), scr)) + if (!setup_frame(sig, ka, info, oldset, scr)) return 0; - signal_delivered(sig, info, ka, &scr->pt, + block_sigmask(ka, sig); + + /* + * Let tracing know that we've done the handler setup. + */ + tracehook_signal_handler(sig, info, ka, &scr->pt, test_thread_flag(TIF_SINGLESTEP)); return 1; @@ -433,6 +440,7 @@ void ia64_do_signal (struct sigscratch *scr, long in_syscall) { struct k_sigaction ka; + sigset_t *oldset; siginfo_t info; long restart = in_syscall; long errno = scr->pt.r8; @@ -445,6 +453,11 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall) if (!user_mode(&scr->pt)) return; + if (current_thread_info()->status & TS_RESTORE_SIGMASK) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + /* * This only loops in the rare cases of handle_signal() failing, in which case we * need to push through a forced SIGSEGV. @@ -494,8 +507,16 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall) * Whee! Actually deliver the signal. If the delivery failed, we need to * continue to iterate in this loop so we can deliver the SIGSEGV... */ - if (handle_signal(signr, &ka, &info, scr)) + if (handle_signal(signr, &ka, &info, oldset, scr)) { + /* + * A signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TS_RESTORE_SIGMASK flag. + */ + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; return; + } } /* Did we come from a system call? */ @@ -517,5 +538,8 @@ ia64_do_signal (struct sigscratch *scr, long in_syscall) /* if there's no signal to deliver, we just put the saved sigmask * back */ - restore_saved_sigmask(); + if (current_thread_info()->status & TS_RESTORE_SIGMASK) { + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } } diff --git a/trunk/arch/ia64/kernel/sys_ia64.c b/trunk/arch/ia64/kernel/sys_ia64.c index d9439ef2f661..609d50056a6c 100644 --- a/trunk/arch/ia64/kernel/sys_ia64.c +++ b/trunk/arch/ia64/kernel/sys_ia64.c @@ -171,9 +171,22 @@ asmlinkage unsigned long ia64_mremap (unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags, unsigned long new_addr) { - addr = sys_mremap(addr, old_len, new_len, flags, new_addr); - if (!IS_ERR((void *) addr)) - force_successful_syscall_return(); + extern unsigned long do_mremap (unsigned long addr, + unsigned long old_len, + unsigned long new_len, + unsigned long flags, + unsigned long new_addr); + + down_write(¤t->mm->mmap_sem); + { + addr = do_mremap(addr, old_len, new_len, flags, new_addr); + } + up_write(¤t->mm->mmap_sem); + + if (IS_ERR((void *) addr)) + return addr; + + force_successful_syscall_return(); return addr; } diff --git a/trunk/arch/m32r/include/asm/posix_types.h b/trunk/arch/m32r/include/asm/posix_types.h index 236de26a409b..0195850e1f88 100644 --- a/trunk/arch/m32r/include/asm/posix_types.h +++ b/trunk/arch/m32r/include/asm/posix_types.h @@ -10,6 +10,9 @@ typedef unsigned short __kernel_mode_t; #define __kernel_mode_t __kernel_mode_t +typedef unsigned short __kernel_nlink_t; +#define __kernel_nlink_t __kernel_nlink_t + typedef unsigned short __kernel_ipc_pid_t; #define __kernel_ipc_pid_t __kernel_ipc_pid_t diff --git a/trunk/arch/m32r/kernel/signal.c b/trunk/arch/m32r/kernel/signal.c index f3fb2c029cfc..f54d96993ea1 100644 --- a/trunk/arch/m32r/kernel/signal.c +++ b/trunk/arch/m32r/kernel/signal.c @@ -28,6 +28,8 @@ #define DEBUG_SIG 0 +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, unsigned long r2, unsigned long r3, unsigned long r4, @@ -109,6 +111,7 @@ sys_rt_sigreturn(unsigned long r0, unsigned long r1, if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &result)) @@ -264,9 +267,9 @@ static int prev_insn(struct pt_regs *regs) * OK, we're invoking a handler */ -static void +static int handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, - struct pt_regs *regs) + sigset_t *oldset, struct pt_regs *regs) { /* Are we from a system call? */ if (regs->syscall_nr >= 0) { @@ -291,10 +294,11 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, } /* Set up the stack frame */ - if (setup_rt_frame(sig, ka, info, sigmask_to_save(), regs)) - return; + if (setup_rt_frame(sig, ka, info, oldset, regs)) + return -EFAULT; - signal_delivered(sig, info, ka, regs, 0); + block_sigmask(ka, sig); + return 0; } /* @@ -307,6 +311,7 @@ static void do_signal(struct pt_regs *regs) siginfo_t info; int signr; struct k_sigaction ka; + sigset_t *oldset; /* * We want the common case to go fast, which @@ -317,6 +322,14 @@ static void do_signal(struct pt_regs *regs) if (!user_mode(regs)) return; + if (try_to_freeze()) + goto no_signal; + + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { /* Re-enable any watchpoints before delivering the @@ -326,11 +339,13 @@ static void do_signal(struct pt_regs *regs) */ /* Whee! Actually deliver the signal. */ - handle_signal(signr, &ka, &info, regs); + if (handle_signal(signr, &ka, &info, oldset, regs) == 0) + clear_thread_flag(TIF_RESTORE_SIGMASK); return; } + no_signal: /* Did we come from a system call? */ if (regs->syscall_nr >= 0) { /* Restart the system call - no handlers present */ @@ -345,7 +360,10 @@ static void do_signal(struct pt_regs *regs) prev_insn(regs); } } - restore_saved_sigmask(); + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } } /* @@ -365,6 +383,8 @@ void do_notify_resume(struct pt_regs *regs, __u32 thread_info_flags) if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } clear_thread_flag(TIF_IRET); diff --git a/trunk/arch/m68k/include/asm/posix_types.h b/trunk/arch/m68k/include/asm/posix_types.h index cf4dbf70fdc7..6373093be72b 100644 --- a/trunk/arch/m68k/include/asm/posix_types.h +++ b/trunk/arch/m68k/include/asm/posix_types.h @@ -10,6 +10,9 @@ typedef unsigned short __kernel_mode_t; #define __kernel_mode_t __kernel_mode_t +typedef unsigned short __kernel_nlink_t; +#define __kernel_nlink_t __kernel_nlink_t + typedef unsigned short __kernel_ipc_pid_t; #define __kernel_ipc_pid_t __kernel_ipc_pid_t diff --git a/trunk/arch/m68k/kernel/signal.c b/trunk/arch/m68k/kernel/signal.c index 710a528b928b..d9f3d1900eed 100644 --- a/trunk/arch/m68k/kernel/signal.c +++ b/trunk/arch/m68k/kernel/signal.c @@ -51,6 +51,8 @@ #include #include +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + #ifdef CONFIG_MMU /* @@ -793,6 +795,7 @@ asmlinkage int do_sigreturn(unsigned long __unused) sizeof(frame->extramask)))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(regs, &frame->sc, frame + 1)) @@ -817,6 +820,7 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused) if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (rt_restore_ucontext(regs, sw, &frame->uc)) @@ -1119,9 +1123,8 @@ handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) */ static void handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, - struct pt_regs *regs) + sigset_t *oldset, struct pt_regs *regs) { - sigset_t *oldset = sigmask_to_save(); int err; /* are we from a system call? */ if (regs->orig_d0 >= 0) @@ -1137,12 +1140,14 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, if (err) return; - signal_delivered(sig, info, ka, regs, 0); + block_sigmask(ka, sig); if (test_thread_flag(TIF_DELAYED_TRACE)) { regs->sr &= ~0x8000; send_sig(SIGTRAP, current, 1); } + + clear_thread_flag(TIF_RESTORE_SIGMASK); } /* @@ -1155,13 +1160,19 @@ static void do_signal(struct pt_regs *regs) siginfo_t info; struct k_sigaction ka; int signr; + sigset_t *oldset; current->thread.esp0 = (unsigned long) regs; + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { /* Whee! Actually deliver the signal. */ - handle_signal(signr, &ka, &info, regs); + handle_signal(signr, &ka, &info, oldset, regs); return; } @@ -1171,7 +1182,10 @@ static void do_signal(struct pt_regs *regs) handle_restart(regs, NULL, 0); /* If there's no signal to deliver, we just restore the saved mask. */ - restore_saved_sigmask(); + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } } void do_notify_resume(struct pt_regs *regs) @@ -1179,6 +1193,9 @@ void do_notify_resume(struct pt_regs *regs) if (test_thread_flag(TIF_SIGPENDING)) do_signal(regs); - if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) + if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) { tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); + } } diff --git a/trunk/arch/microblaze/include/asm/thread_info.h b/trunk/arch/microblaze/include/asm/thread_info.h index 6c610234ffab..1a8ab6a5c03f 100644 --- a/trunk/arch/microblaze/include/asm/thread_info.h +++ b/trunk/arch/microblaze/include/asm/thread_info.h @@ -166,23 +166,7 @@ static inline void set_restore_sigmask(void) { struct thread_info *ti = current_thread_info(); ti->status |= TS_RESTORE_SIGMASK; - WARN_ON(!test_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags)); -} -static inline void clear_restore_sigmask(void) -{ - current_thread_info()->status &= ~TS_RESTORE_SIGMASK; -} -static inline bool test_restore_sigmask(void) -{ - return current_thread_info()->status & TS_RESTORE_SIGMASK; -} -static inline bool test_and_clear_restore_sigmask(void) -{ - struct thread_info *ti = current_thread_info(); - if (!(ti->status & TS_RESTORE_SIGMASK)) - return false; - ti->status &= ~TS_RESTORE_SIGMASK; - return true; + set_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags); } #endif diff --git a/trunk/arch/microblaze/kernel/signal.c b/trunk/arch/microblaze/kernel/signal.c index 76b9722557db..7f4c7bef1642 100644 --- a/trunk/arch/microblaze/kernel/signal.c +++ b/trunk/arch/microblaze/kernel/signal.c @@ -41,6 +41,8 @@ #include #include +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + asmlinkage long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, struct pt_regs *regs) @@ -104,6 +106,7 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &rval)) @@ -307,11 +310,10 @@ handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) * OK, we're invoking a handler */ -static void +static int handle_signal(unsigned long sig, struct k_sigaction *ka, - siginfo_t *info, struct pt_regs *regs) + siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) { - sigset_t *oldset = sigmask_to_save(); int ret; /* Set up the stack frame */ @@ -321,9 +323,11 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, ret = setup_rt_frame(sig, ka, NULL, oldset, regs); if (ret) - return; + return ret; - signal_delivered(sig, info, ka, regs, 0); + block_sigmask(ka, sig); + + return 0; } /* @@ -340,18 +344,33 @@ static void do_signal(struct pt_regs *regs, int in_syscall) siginfo_t info; int signr; struct k_sigaction ka; + sigset_t *oldset; #ifdef DEBUG_SIG printk(KERN_INFO "do signal: %p %d\n", regs, in_syscall); printk(KERN_INFO "do signal2: %lx %lx %ld [%lx]\n", regs->pc, regs->r1, regs->r12, current_thread_info()->flags); #endif + if (current_thread_info()->status & TS_RESTORE_SIGMASK) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { /* Whee! Actually deliver the signal. */ if (in_syscall) handle_restart(regs, &ka, 1); - handle_signal(signr, &ka, &info, regs); + if (!handle_signal(signr, &ka, &info, oldset, regs)) { + /* + * A signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TS_RESTORE_SIGMASK flag. + */ + current_thread_info()->status &= + ~TS_RESTORE_SIGMASK; + } return; } @@ -362,7 +381,10 @@ static void do_signal(struct pt_regs *regs, int in_syscall) * If there's no signal to deliver, we just put the saved sigmask * back. */ - restore_saved_sigmask(); + if (current_thread_info()->status & TS_RESTORE_SIGMASK) { + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } } void do_notify_resume(struct pt_regs *regs, int in_syscall) @@ -379,6 +401,9 @@ void do_notify_resume(struct pt_regs *regs, int in_syscall) if (test_thread_flag(TIF_SIGPENDING)) do_signal(regs, in_syscall); - if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) + if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) { tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); + } } diff --git a/trunk/arch/mips/Kconfig b/trunk/arch/mips/Kconfig index 09ab87ee6fef..77050671eeef 100644 --- a/trunk/arch/mips/Kconfig +++ b/trunk/arch/mips/Kconfig @@ -233,9 +233,8 @@ config LANTIQ select ARCH_REQUIRE_GPIOLIB select SWAP_IO_SPACE select BOOT_RAW - select HAVE_MACH_CLKDEV - select CLKDEV_LOOKUP - select USE_OF + select HAVE_CLK + select MIPS_MACHINE config LASAT bool "LASAT Networks platforms" @@ -1784,12 +1783,10 @@ endchoice config FORCE_MAX_ZONEORDER int "Maximum zone order" - range 14 64 if HUGETLB_PAGE && PAGE_SIZE_64KB - default "14" if HUGETLB_PAGE && PAGE_SIZE_64KB - range 13 64 if HUGETLB_PAGE && PAGE_SIZE_32KB - default "13" if HUGETLB_PAGE && PAGE_SIZE_32KB - range 12 64 if HUGETLB_PAGE && PAGE_SIZE_16KB - default "12" if HUGETLB_PAGE && PAGE_SIZE_16KB + range 13 64 if SYS_SUPPORTS_HUGETLBFS && PAGE_SIZE_32KB + default "13" if SYS_SUPPORTS_HUGETLBFS && PAGE_SIZE_32KB + range 12 64 if SYS_SUPPORTS_HUGETLBFS && PAGE_SIZE_16KB + default "12" if SYS_SUPPORTS_HUGETLBFS && PAGE_SIZE_16KB range 11 64 default "11" help diff --git a/trunk/arch/mips/alchemy/devboards/db1200.c b/trunk/arch/mips/alchemy/devboards/db1200.c index bf2248474fa8..a83302b96c01 100644 --- a/trunk/arch/mips/alchemy/devboards/db1200.c +++ b/trunk/arch/mips/alchemy/devboards/db1200.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -213,6 +212,8 @@ static int au1200_nand_device_ready(struct mtd_info *mtd) return __raw_readl((void __iomem *)MEM_STSTAT) & 1; } +static const char *db1200_part_probes[] = { "cmdlinepart", NULL }; + static struct mtd_partition db1200_nand_parts[] = { { .name = "NAND FS 0", @@ -233,6 +234,7 @@ struct platform_nand_data db1200_nand_platdata = { .nr_partitions = ARRAY_SIZE(db1200_nand_parts), .partitions = db1200_nand_parts, .chip_delay = 20, + .part_probe_types = db1200_part_probes, }, .ctrl = { .dev_ready = au1200_nand_device_ready, diff --git a/trunk/arch/mips/alchemy/devboards/db1300.c b/trunk/arch/mips/alchemy/devboards/db1300.c index c56e0246694e..0893f2af0d01 100644 --- a/trunk/arch/mips/alchemy/devboards/db1300.c +++ b/trunk/arch/mips/alchemy/devboards/db1300.c @@ -145,6 +145,8 @@ static int au1300_nand_device_ready(struct mtd_info *mtd) return __raw_readl((void __iomem *)MEM_STSTAT) & 1; } +static const char *db1300_part_probes[] = { "cmdlinepart", NULL }; + static struct mtd_partition db1300_nand_parts[] = { { .name = "NAND FS 0", @@ -165,6 +167,7 @@ struct platform_nand_data db1300_nand_platdata = { .nr_partitions = ARRAY_SIZE(db1300_nand_parts), .partitions = db1300_nand_parts, .chip_delay = 20, + .part_probe_types = db1300_part_probes, }, .ctrl = { .dev_ready = au1300_nand_device_ready, diff --git a/trunk/arch/mips/alchemy/devboards/db1550.c b/trunk/arch/mips/alchemy/devboards/db1550.c index 9eb79062f46e..6815d0783cd8 100644 --- a/trunk/arch/mips/alchemy/devboards/db1550.c +++ b/trunk/arch/mips/alchemy/devboards/db1550.c @@ -149,6 +149,8 @@ static int au1550_nand_device_ready(struct mtd_info *mtd) return __raw_readl((void __iomem *)MEM_STSTAT) & 1; } +static const char *db1550_part_probes[] = { "cmdlinepart", NULL }; + static struct mtd_partition db1550_nand_parts[] = { { .name = "NAND FS 0", @@ -169,6 +171,7 @@ struct platform_nand_data db1550_nand_platdata = { .nr_partitions = ARRAY_SIZE(db1550_nand_parts), .partitions = db1550_nand_parts, .chip_delay = 20, + .part_probe_types = db1550_part_probes, }, .ctrl = { .dev_ready = au1550_nand_device_ready, diff --git a/trunk/arch/mips/ath79/Kconfig b/trunk/arch/mips/ath79/Kconfig index f44feee2d67f..e0fae8f4442b 100644 --- a/trunk/arch/mips/ath79/Kconfig +++ b/trunk/arch/mips/ath79/Kconfig @@ -26,18 +26,6 @@ config ATH79_MACH_AP81 Say 'Y' here if you want your kernel to support the Atheros AP81 reference board. -config ATH79_MACH_DB120 - bool "Atheros DB120 reference board" - select SOC_AR934X - select ATH79_DEV_GPIO_BUTTONS - select ATH79_DEV_LEDS_GPIO - select ATH79_DEV_SPI - select ATH79_DEV_USB - select ATH79_DEV_WMAC - help - Say 'Y' here if you want your kernel to support the - Atheros DB120 reference board. - config ATH79_MACH_PB44 bool "Atheros PB44 reference board" select SOC_AR71XX @@ -64,14 +52,12 @@ endmenu config SOC_AR71XX select USB_ARCH_HAS_EHCI select USB_ARCH_HAS_OHCI - select HW_HAS_PCI def_bool n config SOC_AR724X select USB_ARCH_HAS_EHCI select USB_ARCH_HAS_OHCI select HW_HAS_PCI - select PCI_AR724X if PCI def_bool n config SOC_AR913X @@ -82,15 +68,6 @@ config SOC_AR933X select USB_ARCH_HAS_EHCI def_bool n -config SOC_AR934X - select USB_ARCH_HAS_EHCI - select HW_HAS_PCI - select PCI_AR724X if PCI - def_bool n - -config PCI_AR724X - def_bool n - config ATH79_DEV_GPIO_BUTTONS def_bool n @@ -104,7 +81,7 @@ config ATH79_DEV_USB def_bool n config ATH79_DEV_WMAC - depends on (SOC_AR913X || SOC_AR933X || SOC_AR934X) + depends on (SOC_AR913X || SOC_AR933X) def_bool n endif diff --git a/trunk/arch/mips/ath79/Makefile b/trunk/arch/mips/ath79/Makefile index 2b54d98263f3..3b911e09dbec 100644 --- a/trunk/arch/mips/ath79/Makefile +++ b/trunk/arch/mips/ath79/Makefile @@ -11,7 +11,6 @@ obj-y := prom.o setup.o irq.o common.o clock.o gpio.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -obj-$(CONFIG_PCI) += pci.o # # Devices @@ -28,6 +27,5 @@ obj-$(CONFIG_ATH79_DEV_WMAC) += dev-wmac.o # obj-$(CONFIG_ATH79_MACH_AP121) += mach-ap121.o obj-$(CONFIG_ATH79_MACH_AP81) += mach-ap81.o -obj-$(CONFIG_ATH79_MACH_DB120) += mach-db120.o obj-$(CONFIG_ATH79_MACH_PB44) += mach-pb44.o obj-$(CONFIG_ATH79_MACH_UBNT_XM) += mach-ubnt-xm.o diff --git a/trunk/arch/mips/ath79/clock.c b/trunk/arch/mips/ath79/clock.c index b91ad3efe29e..54d0eb4db987 100644 --- a/trunk/arch/mips/ath79/clock.c +++ b/trunk/arch/mips/ath79/clock.c @@ -1,11 +1,8 @@ /* * Atheros AR71XX/AR724X/AR913X common routines * - * Copyright (C) 2010-2011 Jaiganesh Narayanan * Copyright (C) 2011 Gabor Juhos * - * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP - * * 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. @@ -166,82 +163,6 @@ static void __init ar933x_clocks_init(void) ath79_uart_clk.rate = ath79_ref_clk.rate; } -static void __init ar934x_clocks_init(void) -{ - u32 pll, out_div, ref_div, nint, frac, clk_ctrl, postdiv; - u32 cpu_pll, ddr_pll; - u32 bootstrap; - - bootstrap = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP); - if (bootstrap & AR934X_BOOTSTRAP_REF_CLK_40) - ath79_ref_clk.rate = 40 * 1000 * 1000; - else - ath79_ref_clk.rate = 25 * 1000 * 1000; - - pll = ath79_pll_rr(AR934X_PLL_CPU_CONFIG_REG); - out_div = (pll >> AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT) & - AR934X_PLL_CPU_CONFIG_OUTDIV_MASK; - ref_div = (pll >> AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT) & - AR934X_PLL_CPU_CONFIG_REFDIV_MASK; - nint = (pll >> AR934X_PLL_CPU_CONFIG_NINT_SHIFT) & - AR934X_PLL_CPU_CONFIG_NINT_MASK; - frac = (pll >> AR934X_PLL_CPU_CONFIG_NFRAC_SHIFT) & - AR934X_PLL_CPU_CONFIG_NFRAC_MASK; - - cpu_pll = nint * ath79_ref_clk.rate / ref_div; - cpu_pll += frac * ath79_ref_clk.rate / (ref_div * (2 << 6)); - cpu_pll /= (1 << out_div); - - pll = ath79_pll_rr(AR934X_PLL_DDR_CONFIG_REG); - out_div = (pll >> AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT) & - AR934X_PLL_DDR_CONFIG_OUTDIV_MASK; - ref_div = (pll >> AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT) & - AR934X_PLL_DDR_CONFIG_REFDIV_MASK; - nint = (pll >> AR934X_PLL_DDR_CONFIG_NINT_SHIFT) & - AR934X_PLL_DDR_CONFIG_NINT_MASK; - frac = (pll >> AR934X_PLL_DDR_CONFIG_NFRAC_SHIFT) & - AR934X_PLL_DDR_CONFIG_NFRAC_MASK; - - ddr_pll = nint * ath79_ref_clk.rate / ref_div; - ddr_pll += frac * ath79_ref_clk.rate / (ref_div * (2 << 10)); - ddr_pll /= (1 << out_div); - - clk_ctrl = ath79_pll_rr(AR934X_PLL_CPU_DDR_CLK_CTRL_REG); - - postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_SHIFT) & - AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_MASK; - - if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_PLL_BYPASS) - ath79_cpu_clk.rate = ath79_ref_clk.rate; - else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_CPUCLK_FROM_CPUPLL) - ath79_cpu_clk.rate = cpu_pll / (postdiv + 1); - else - ath79_cpu_clk.rate = ddr_pll / (postdiv + 1); - - postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_SHIFT) & - AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_MASK; - - if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_PLL_BYPASS) - ath79_ddr_clk.rate = ath79_ref_clk.rate; - else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_DDRCLK_FROM_DDRPLL) - ath79_ddr_clk.rate = ddr_pll / (postdiv + 1); - else - ath79_ddr_clk.rate = cpu_pll / (postdiv + 1); - - postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_SHIFT) & - AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_MASK; - - if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_PLL_BYPASS) - ath79_ahb_clk.rate = ath79_ref_clk.rate; - else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL) - ath79_ahb_clk.rate = ddr_pll / (postdiv + 1); - else - ath79_ahb_clk.rate = cpu_pll / (postdiv + 1); - - ath79_wdt_clk.rate = ath79_ref_clk.rate; - ath79_uart_clk.rate = ath79_ref_clk.rate; -} - void __init ath79_clocks_init(void) { if (soc_is_ar71xx()) @@ -252,8 +173,6 @@ void __init ath79_clocks_init(void) ar913x_clocks_init(); else if (soc_is_ar933x()) ar933x_clocks_init(); - else if (soc_is_ar934x()) - ar934x_clocks_init(); else BUG(); diff --git a/trunk/arch/mips/ath79/common.c b/trunk/arch/mips/ath79/common.c index 5a4adfc9d79d..f0fda982b965 100644 --- a/trunk/arch/mips/ath79/common.c +++ b/trunk/arch/mips/ath79/common.c @@ -1,12 +1,9 @@ /* * Atheros AR71XX/AR724X/AR913X common routines * - * Copyright (C) 2010-2011 Jaiganesh Narayanan - * Copyright (C) 2008-2011 Gabor Juhos + * Copyright (C) 2008-2010 Gabor Juhos * Copyright (C) 2008 Imre Kaloz * - * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP - * * 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. @@ -70,8 +67,6 @@ void ath79_device_reset_set(u32 mask) reg = AR913X_RESET_REG_RESET_MODULE; else if (soc_is_ar933x()) reg = AR933X_RESET_REG_RESET_MODULE; - else if (soc_is_ar934x()) - reg = AR934X_RESET_REG_RESET_MODULE; else BUG(); @@ -96,8 +91,6 @@ void ath79_device_reset_clear(u32 mask) reg = AR913X_RESET_REG_RESET_MODULE; else if (soc_is_ar933x()) reg = AR933X_RESET_REG_RESET_MODULE; - else if (soc_is_ar934x()) - reg = AR934X_RESET_REG_RESET_MODULE; else BUG(); diff --git a/trunk/arch/mips/ath79/dev-common.c b/trunk/arch/mips/ath79/dev-common.c index 45efc63b08b6..f4956f809072 100644 --- a/trunk/arch/mips/ath79/dev-common.c +++ b/trunk/arch/mips/ath79/dev-common.c @@ -89,8 +89,7 @@ void __init ath79_register_uart(void) if (soc_is_ar71xx() || soc_is_ar724x() || - soc_is_ar913x() || - soc_is_ar934x()) { + soc_is_ar913x()) { ath79_uart_data[0].uartclk = clk_get_rate(clk); platform_device_register(&ath79_uart_device); } else if (soc_is_ar933x()) { diff --git a/trunk/arch/mips/ath79/dev-gpio-buttons.c b/trunk/arch/mips/ath79/dev-gpio-buttons.c index 366b35fb164d..4b0168a11c01 100644 --- a/trunk/arch/mips/ath79/dev-gpio-buttons.c +++ b/trunk/arch/mips/ath79/dev-gpio-buttons.c @@ -25,10 +25,12 @@ void __init ath79_register_gpio_keys_polled(int id, struct gpio_keys_button *p; int err; - p = kmemdup(buttons, nbuttons * sizeof(*p), GFP_KERNEL); + p = kmalloc(nbuttons * sizeof(*p), GFP_KERNEL); if (!p) return; + memcpy(p, buttons, nbuttons * sizeof(*p)); + pdev = platform_device_alloc("gpio-keys-polled", id); if (!pdev) goto err_free_buttons; diff --git a/trunk/arch/mips/ath79/dev-leds-gpio.c b/trunk/arch/mips/ath79/dev-leds-gpio.c index dcb1debcefb8..cdade68dcd17 100644 --- a/trunk/arch/mips/ath79/dev-leds-gpio.c +++ b/trunk/arch/mips/ath79/dev-leds-gpio.c @@ -24,10 +24,12 @@ void __init ath79_register_leds_gpio(int id, struct gpio_led *p; int err; - p = kmemdup(leds, num_leds * sizeof(*p), GFP_KERNEL); + p = kmalloc(num_leds * sizeof(*p), GFP_KERNEL); if (!p) return; + memcpy(p, leds, num_leds * sizeof(*p)); + pdev = platform_device_alloc("leds-gpio", id); if (!pdev) goto err_free_leds; diff --git a/trunk/arch/mips/ath79/dev-wmac.c b/trunk/arch/mips/ath79/dev-wmac.c index d6d893c16ad4..9c717bf98ffe 100644 --- a/trunk/arch/mips/ath79/dev-wmac.c +++ b/trunk/arch/mips/ath79/dev-wmac.c @@ -1,12 +1,9 @@ /* * Atheros AR913X/AR933X SoC built-in WMAC device support * - * Copyright (C) 2010-2011 Jaiganesh Narayanan * Copyright (C) 2008-2011 Gabor Juhos * Copyright (C) 2008 Imre Kaloz * - * Parts of this file are based on Atheros 2.6.15/2.6.31 BSP - * * 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. @@ -29,7 +26,8 @@ static struct resource ath79_wmac_resources[] = { /* .start and .end fields are filled dynamically */ .flags = IORESOURCE_MEM, }, { - /* .start and .end fields are filled dynamically */ + .start = ATH79_CPU_IRQ_IP2, + .end = ATH79_CPU_IRQ_IP2, .flags = IORESOURCE_IRQ, }, }; @@ -55,8 +53,6 @@ static void __init ar913x_wmac_setup(void) ath79_wmac_resources[0].start = AR913X_WMAC_BASE; ath79_wmac_resources[0].end = AR913X_WMAC_BASE + AR913X_WMAC_SIZE - 1; - ath79_wmac_resources[1].start = ATH79_CPU_IRQ_IP2; - ath79_wmac_resources[1].end = ATH79_CPU_IRQ_IP2; } @@ -83,8 +79,6 @@ static void __init ar933x_wmac_setup(void) ath79_wmac_resources[0].start = AR933X_WMAC_BASE; ath79_wmac_resources[0].end = AR933X_WMAC_BASE + AR933X_WMAC_SIZE - 1; - ath79_wmac_resources[1].start = ATH79_CPU_IRQ_IP2; - ath79_wmac_resources[1].end = ATH79_CPU_IRQ_IP2; t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP); if (t & AR933X_BOOTSTRAP_REF_CLK_40) @@ -98,32 +92,12 @@ static void __init ar933x_wmac_setup(void) ath79_wmac_data.external_reset = ar933x_wmac_reset; } -static void ar934x_wmac_setup(void) -{ - u32 t; - - ath79_wmac_device.name = "ar934x_wmac"; - - ath79_wmac_resources[0].start = AR934X_WMAC_BASE; - ath79_wmac_resources[0].end = AR934X_WMAC_BASE + AR934X_WMAC_SIZE - 1; - ath79_wmac_resources[1].start = ATH79_IP2_IRQ(1); - ath79_wmac_resources[1].start = ATH79_IP2_IRQ(1); - - t = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP); - if (t & AR934X_BOOTSTRAP_REF_CLK_40) - ath79_wmac_data.is_clk_25mhz = false; - else - ath79_wmac_data.is_clk_25mhz = true; -} - void __init ath79_register_wmac(u8 *cal_data) { if (soc_is_ar913x()) ar913x_wmac_setup(); else if (soc_is_ar933x()) ar933x_wmac_setup(); - else if (soc_is_ar934x()) - ar934x_wmac_setup(); else BUG(); diff --git a/trunk/arch/mips/ath79/early_printk.c b/trunk/arch/mips/ath79/early_printk.c index dc938cb2ba58..6a51ced7a293 100644 --- a/trunk/arch/mips/ath79/early_printk.c +++ b/trunk/arch/mips/ath79/early_printk.c @@ -71,9 +71,6 @@ static void prom_putchar_init(void) case REV_ID_MAJOR_AR7241: case REV_ID_MAJOR_AR7242: case REV_ID_MAJOR_AR913X: - case REV_ID_MAJOR_AR9341: - case REV_ID_MAJOR_AR9342: - case REV_ID_MAJOR_AR9344: _prom_putchar = prom_putchar_ar71xx; break; diff --git a/trunk/arch/mips/ath79/gpio.c b/trunk/arch/mips/ath79/gpio.c index 29054f211832..a2f8ca630ed6 100644 --- a/trunk/arch/mips/ath79/gpio.c +++ b/trunk/arch/mips/ath79/gpio.c @@ -1,12 +1,9 @@ /* * Atheros AR71XX/AR724X/AR913X GPIO API support * - * Copyright (C) 2010-2011 Jaiganesh Narayanan - * Copyright (C) 2008-2011 Gabor Juhos + * Copyright (C) 2008-2010 Gabor Juhos * Copyright (C) 2008 Imre Kaloz * - * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP - * * 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. @@ -92,42 +89,6 @@ static int ath79_gpio_direction_output(struct gpio_chip *chip, return 0; } -static int ar934x_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - void __iomem *base = ath79_gpio_base; - unsigned long flags; - - spin_lock_irqsave(&ath79_gpio_lock, flags); - - __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset), - base + AR71XX_GPIO_REG_OE); - - spin_unlock_irqrestore(&ath79_gpio_lock, flags); - - return 0; -} - -static int ar934x_gpio_direction_output(struct gpio_chip *chip, unsigned offset, - int value) -{ - void __iomem *base = ath79_gpio_base; - unsigned long flags; - - spin_lock_irqsave(&ath79_gpio_lock, flags); - - if (value) - __raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET); - else - __raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR); - - __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset), - base + AR71XX_GPIO_REG_OE); - - spin_unlock_irqrestore(&ath79_gpio_lock, flags); - - return 0; -} - static struct gpio_chip ath79_gpio_chip = { .label = "ath79", .get = ath79_gpio_get_value, @@ -194,17 +155,11 @@ void __init ath79_gpio_init(void) ath79_gpio_count = AR913X_GPIO_COUNT; else if (soc_is_ar933x()) ath79_gpio_count = AR933X_GPIO_COUNT; - else if (soc_is_ar934x()) - ath79_gpio_count = AR934X_GPIO_COUNT; else BUG(); ath79_gpio_base = ioremap_nocache(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE); ath79_gpio_chip.ngpio = ath79_gpio_count; - if (soc_is_ar934x()) { - ath79_gpio_chip.direction_input = ar934x_gpio_direction_input; - ath79_gpio_chip.direction_output = ar934x_gpio_direction_output; - } err = gpiochip_add(&ath79_gpio_chip); if (err) diff --git a/trunk/arch/mips/ath79/irq.c b/trunk/arch/mips/ath79/irq.c index 90d09fc15398..1b073de44680 100644 --- a/trunk/arch/mips/ath79/irq.c +++ b/trunk/arch/mips/ath79/irq.c @@ -1,11 +1,10 @@ /* * Atheros AR71xx/AR724x/AR913x specific interrupt handling * - * Copyright (C) 2010-2011 Jaiganesh Narayanan - * Copyright (C) 2008-2011 Gabor Juhos + * Copyright (C) 2008-2010 Gabor Juhos * Copyright (C) 2008 Imre Kaloz * - * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP + * Parts of this file are based on Atheros' 2.6.15 BSP * * 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 @@ -24,8 +23,8 @@ #include #include "common.h" -static void (*ath79_ip2_handler)(void); -static void (*ath79_ip3_handler)(void); +static unsigned int ath79_ip2_flush_reg; +static unsigned int ath79_ip3_flush_reg; static void ath79_misc_irq_handler(unsigned int irq, struct irq_desc *desc) { @@ -130,7 +129,7 @@ static void __init ath79_misc_irq_init(void) if (soc_is_ar71xx() || soc_is_ar913x()) ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask; - else if (soc_is_ar724x() || soc_is_ar933x() || soc_is_ar934x()) + else if (soc_is_ar724x() || soc_is_ar933x()) ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack; else BUG(); @@ -144,39 +143,6 @@ static void __init ath79_misc_irq_init(void) irq_set_chained_handler(ATH79_CPU_IRQ_MISC, ath79_misc_irq_handler); } -static void ar934x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc) -{ - u32 status; - - disable_irq_nosync(irq); - - status = ath79_reset_rr(AR934X_RESET_REG_PCIE_WMAC_INT_STATUS); - - if (status & AR934X_PCIE_WMAC_INT_PCIE_ALL) { - ath79_ddr_wb_flush(AR934X_DDR_REG_FLUSH_PCIE); - generic_handle_irq(ATH79_IP2_IRQ(0)); - } else if (status & AR934X_PCIE_WMAC_INT_WMAC_ALL) { - ath79_ddr_wb_flush(AR934X_DDR_REG_FLUSH_WMAC); - generic_handle_irq(ATH79_IP2_IRQ(1)); - } else { - spurious_interrupt(); - } - - enable_irq(irq); -} - -static void ar934x_ip2_irq_init(void) -{ - int i; - - for (i = ATH79_IP2_IRQ_BASE; - i < ATH79_IP2_IRQ_BASE + ATH79_IP2_IRQ_COUNT; i++) - irq_set_chip_and_handler(i, &dummy_irq_chip, - handle_level_irq); - - irq_set_chained_handler(ATH79_CPU_IRQ_IP2, ar934x_ip2_irq_dispatch); -} - asmlinkage void plat_irq_dispatch(void) { unsigned long pending; @@ -186,8 +152,10 @@ asmlinkage void plat_irq_dispatch(void) if (pending & STATUSF_IP7) do_IRQ(ATH79_CPU_IRQ_TIMER); - else if (pending & STATUSF_IP2) - ath79_ip2_handler(); + else if (pending & STATUSF_IP2) { + ath79_ddr_wb_flush(ath79_ip2_flush_reg); + do_IRQ(ATH79_CPU_IRQ_IP2); + } else if (pending & STATUSF_IP4) do_IRQ(ATH79_CPU_IRQ_GE0); @@ -195,8 +163,10 @@ asmlinkage void plat_irq_dispatch(void) else if (pending & STATUSF_IP5) do_IRQ(ATH79_CPU_IRQ_GE1); - else if (pending & STATUSF_IP3) - ath79_ip3_handler(); + else if (pending & STATUSF_IP3) { + ath79_ddr_wb_flush(ath79_ip3_flush_reg); + do_IRQ(ATH79_CPU_IRQ_USB); + } else if (pending & STATUSF_IP6) do_IRQ(ATH79_CPU_IRQ_MISC); @@ -205,97 +175,24 @@ asmlinkage void plat_irq_dispatch(void) spurious_interrupt(); } -/* - * The IP2/IP3 lines are tied to a PCI/WMAC/USB device. Drivers for - * these devices typically allocate coherent DMA memory, however the - * DMA controller may still have some unsynchronized data in the FIFO. - * Issue a flush in the handlers to ensure that the driver sees - * the update. - */ -static void ar71xx_ip2_handler(void) -{ - ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_PCI); - do_IRQ(ATH79_CPU_IRQ_IP2); -} - -static void ar724x_ip2_handler(void) -{ - ath79_ddr_wb_flush(AR724X_DDR_REG_FLUSH_PCIE); - do_IRQ(ATH79_CPU_IRQ_IP2); -} - -static void ar913x_ip2_handler(void) -{ - ath79_ddr_wb_flush(AR913X_DDR_REG_FLUSH_WMAC); - do_IRQ(ATH79_CPU_IRQ_IP2); -} - -static void ar933x_ip2_handler(void) -{ - ath79_ddr_wb_flush(AR933X_DDR_REG_FLUSH_WMAC); - do_IRQ(ATH79_CPU_IRQ_IP2); -} - -static void ar934x_ip2_handler(void) -{ - do_IRQ(ATH79_CPU_IRQ_IP2); -} - -static void ar71xx_ip3_handler(void) -{ - ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_USB); - do_IRQ(ATH79_CPU_IRQ_USB); -} - -static void ar724x_ip3_handler(void) -{ - ath79_ddr_wb_flush(AR724X_DDR_REG_FLUSH_USB); - do_IRQ(ATH79_CPU_IRQ_USB); -} - -static void ar913x_ip3_handler(void) -{ - ath79_ddr_wb_flush(AR913X_DDR_REG_FLUSH_USB); - do_IRQ(ATH79_CPU_IRQ_USB); -} - -static void ar933x_ip3_handler(void) -{ - ath79_ddr_wb_flush(AR933X_DDR_REG_FLUSH_USB); - do_IRQ(ATH79_CPU_IRQ_USB); -} - -static void ar934x_ip3_handler(void) -{ - ath79_ddr_wb_flush(AR934X_DDR_REG_FLUSH_USB); - do_IRQ(ATH79_CPU_IRQ_USB); -} - void __init arch_init_irq(void) { if (soc_is_ar71xx()) { - ath79_ip2_handler = ar71xx_ip2_handler; - ath79_ip3_handler = ar71xx_ip3_handler; + ath79_ip2_flush_reg = AR71XX_DDR_REG_FLUSH_PCI; + ath79_ip3_flush_reg = AR71XX_DDR_REG_FLUSH_USB; } else if (soc_is_ar724x()) { - ath79_ip2_handler = ar724x_ip2_handler; - ath79_ip3_handler = ar724x_ip3_handler; + ath79_ip2_flush_reg = AR724X_DDR_REG_FLUSH_PCIE; + ath79_ip3_flush_reg = AR724X_DDR_REG_FLUSH_USB; } else if (soc_is_ar913x()) { - ath79_ip2_handler = ar913x_ip2_handler; - ath79_ip3_handler = ar913x_ip3_handler; + ath79_ip2_flush_reg = AR913X_DDR_REG_FLUSH_WMAC; + ath79_ip3_flush_reg = AR913X_DDR_REG_FLUSH_USB; } else if (soc_is_ar933x()) { - ath79_ip2_handler = ar933x_ip2_handler; - ath79_ip3_handler = ar933x_ip3_handler; - } else if (soc_is_ar934x()) { - ath79_ip2_handler = ar934x_ip2_handler; - ath79_ip3_handler = ar934x_ip3_handler; - } else { + ath79_ip2_flush_reg = AR933X_DDR_REG_FLUSH_WMAC; + ath79_ip3_flush_reg = AR933X_DDR_REG_FLUSH_USB; + } else BUG(); - } cp0_perfcount_irq = ATH79_MISC_IRQ_PERFC; mips_cpu_irq_init(); ath79_misc_irq_init(); - - if (soc_is_ar934x()) - ar934x_ip2_irq_init(); } diff --git a/trunk/arch/mips/ath79/mach-db120.c b/trunk/arch/mips/ath79/mach-db120.c deleted file mode 100644 index 1983e4d2af4b..000000000000 --- a/trunk/arch/mips/ath79/mach-db120.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Atheros DB120 reference board support - * - * Copyright (c) 2011 Qualcomm Atheros - * Copyright (c) 2011 Gabor Juhos - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include -#include - -#include "machtypes.h" -#include "dev-gpio-buttons.h" -#include "dev-leds-gpio.h" -#include "dev-spi.h" -#include "dev-wmac.h" -#include "pci.h" - -#define DB120_GPIO_LED_WLAN_5G 12 -#define DB120_GPIO_LED_WLAN_2G 13 -#define DB120_GPIO_LED_STATUS 14 -#define DB120_GPIO_LED_WPS 15 - -#define DB120_GPIO_BTN_WPS 16 - -#define DB120_KEYS_POLL_INTERVAL 20 /* msecs */ -#define DB120_KEYS_DEBOUNCE_INTERVAL (3 * DB120_KEYS_POLL_INTERVAL) - -#define DB120_WMAC_CALDATA_OFFSET 0x1000 -#define DB120_PCIE_CALDATA_OFFSET 0x5000 - -static struct gpio_led db120_leds_gpio[] __initdata = { - { - .name = "db120:green:status", - .gpio = DB120_GPIO_LED_STATUS, - .active_low = 1, - }, - { - .name = "db120:green:wps", - .gpio = DB120_GPIO_LED_WPS, - .active_low = 1, - }, - { - .name = "db120:green:wlan-5g", - .gpio = DB120_GPIO_LED_WLAN_5G, - .active_low = 1, - }, - { - .name = "db120:green:wlan-2g", - .gpio = DB120_GPIO_LED_WLAN_2G, - .active_low = 1, - }, -}; - -static struct gpio_keys_button db120_gpio_keys[] __initdata = { - { - .desc = "WPS button", - .type = EV_KEY, - .code = KEY_WPS_BUTTON, - .debounce_interval = DB120_KEYS_DEBOUNCE_INTERVAL, - .gpio = DB120_GPIO_BTN_WPS, - .active_low = 1, - }, -}; - -static struct spi_board_info db120_spi_info[] = { - { - .bus_num = 0, - .chip_select = 0, - .max_speed_hz = 25000000, - .modalias = "s25sl064a", - } -}; - -static struct ath79_spi_platform_data db120_spi_data = { - .bus_num = 0, - .num_chipselect = 1, -}; - -#ifdef CONFIG_PCI -static struct ath9k_platform_data db120_ath9k_data; - -static int db120_pci_plat_dev_init(struct pci_dev *dev) -{ - switch (PCI_SLOT(dev->devfn)) { - case 0: - dev->dev.platform_data = &db120_ath9k_data; - break; - } - - return 0; -} - -static void __init db120_pci_init(u8 *eeprom) -{ - memcpy(db120_ath9k_data.eeprom_data, eeprom, - sizeof(db120_ath9k_data.eeprom_data)); - - ath79_pci_set_plat_dev_init(db120_pci_plat_dev_init); - ath79_register_pci(); -} -#else -static inline void db120_pci_init(void) {} -#endif /* CONFIG_PCI */ - -static void __init db120_setup(void) -{ - u8 *art = (u8 *) KSEG1ADDR(0x1fff0000); - - ath79_register_leds_gpio(-1, ARRAY_SIZE(db120_leds_gpio), - db120_leds_gpio); - ath79_register_gpio_keys_polled(-1, DB120_KEYS_POLL_INTERVAL, - ARRAY_SIZE(db120_gpio_keys), - db120_gpio_keys); - ath79_register_spi(&db120_spi_data, db120_spi_info, - ARRAY_SIZE(db120_spi_info)); - ath79_register_wmac(art + DB120_WMAC_CALDATA_OFFSET); - db120_pci_init(art + DB120_PCIE_CALDATA_OFFSET); -} - -MIPS_MACHINE(ATH79_MACH_DB120, "DB120", "Atheros DB120 reference board", - db120_setup); diff --git a/trunk/arch/mips/ath79/mach-pb44.c b/trunk/arch/mips/ath79/mach-pb44.c index c5f0ea5e00c3..fe9701a32291 100644 --- a/trunk/arch/mips/ath79/mach-pb44.c +++ b/trunk/arch/mips/ath79/mach-pb44.c @@ -19,7 +19,6 @@ #include "dev-leds-gpio.h" #include "dev-spi.h" #include "dev-usb.h" -#include "pci.h" #define PB44_GPIO_I2C_SCL 0 #define PB44_GPIO_I2C_SDA 1 @@ -115,7 +114,6 @@ static void __init pb44_init(void) ath79_register_spi(&pb44_spi_data, pb44_spi_info, ARRAY_SIZE(pb44_spi_info)); ath79_register_usb(); - ath79_register_pci(); } MIPS_MACHINE(ATH79_MACH_PB44, "PB44", "Atheros PB44 reference board", diff --git a/trunk/arch/mips/ath79/mach-ubnt-xm.c b/trunk/arch/mips/ath79/mach-ubnt-xm.c index 4a3c60694c75..3c311a539347 100644 --- a/trunk/arch/mips/ath79/mach-ubnt-xm.c +++ b/trunk/arch/mips/ath79/mach-ubnt-xm.c @@ -12,15 +12,16 @@ #include #include -#include -#include +#ifdef CONFIG_PCI +#include +#include +#endif /* CONFIG_PCI */ #include "machtypes.h" #include "dev-gpio-buttons.h" #include "dev-leds-gpio.h" #include "dev-spi.h" -#include "pci.h" #define UBNT_XM_GPIO_LED_L1 0 #define UBNT_XM_GPIO_LED_L2 1 @@ -32,6 +33,7 @@ #define UBNT_XM_KEYS_POLL_INTERVAL 20 #define UBNT_XM_KEYS_DEBOUNCE_INTERVAL (3 * UBNT_XM_KEYS_POLL_INTERVAL) +#define UBNT_XM_PCI_IRQ 48 #define UBNT_XM_EEPROM_ADDR (u8 *) KSEG1ADDR(0x1fff1000) static struct gpio_led ubnt_xm_leds_gpio[] __initdata = { @@ -82,27 +84,12 @@ static struct ath79_spi_platform_data ubnt_xm_spi_data = { #ifdef CONFIG_PCI static struct ath9k_platform_data ubnt_xm_eeprom_data; -static int ubnt_xm_pci_plat_dev_init(struct pci_dev *dev) -{ - switch (PCI_SLOT(dev->devfn)) { - case 0: - dev->dev.platform_data = &ubnt_xm_eeprom_data; - break; - } - - return 0; -} - -static void __init ubnt_xm_pci_init(void) -{ - memcpy(ubnt_xm_eeprom_data.eeprom_data, UBNT_XM_EEPROM_ADDR, - sizeof(ubnt_xm_eeprom_data.eeprom_data)); - - ath79_pci_set_plat_dev_init(ubnt_xm_pci_plat_dev_init); - ath79_register_pci(); -} -#else -static inline void ubnt_xm_pci_init(void) {} +static struct ath724x_pci_data ubnt_xm_pci_data[] = { + { + .irq = UBNT_XM_PCI_IRQ, + .pdata = &ubnt_xm_eeprom_data, + }, +}; #endif /* CONFIG_PCI */ static void __init ubnt_xm_init(void) @@ -117,7 +104,13 @@ static void __init ubnt_xm_init(void) ath79_register_spi(&ubnt_xm_spi_data, ubnt_xm_spi_info, ARRAY_SIZE(ubnt_xm_spi_info)); - ubnt_xm_pci_init(); +#ifdef CONFIG_PCI + memcpy(ubnt_xm_eeprom_data.eeprom_data, UBNT_XM_EEPROM_ADDR, + sizeof(ubnt_xm_eeprom_data.eeprom_data)); + + ath724x_pci_add_data(ubnt_xm_pci_data, ARRAY_SIZE(ubnt_xm_pci_data)); +#endif /* CONFIG_PCI */ + } MIPS_MACHINE(ATH79_MACH_UBNT_XM, diff --git a/trunk/arch/mips/ath79/machtypes.h b/trunk/arch/mips/ath79/machtypes.h index af92e5c30d66..9a1f3826626e 100644 --- a/trunk/arch/mips/ath79/machtypes.h +++ b/trunk/arch/mips/ath79/machtypes.h @@ -18,7 +18,6 @@ enum ath79_mach_type { ATH79_MACH_GENERIC = 0, ATH79_MACH_AP121, /* Atheros AP121 reference board */ ATH79_MACH_AP81, /* Atheros AP81 reference board */ - ATH79_MACH_DB120, /* Atheros DB120 reference board */ ATH79_MACH_PB44, /* Atheros PB44 reference board */ ATH79_MACH_UBNT_XM, /* Ubiquiti Networks XM board rev 1.0 */ }; diff --git a/trunk/arch/mips/ath79/pci.c b/trunk/arch/mips/ath79/pci.c deleted file mode 100644 index ca83abd9d31e..000000000000 --- a/trunk/arch/mips/ath79/pci.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Atheros AR71XX/AR724X specific PCI setup code - * - * Copyright (C) 2011 René Bolldorf - * Copyright (C) 2008-2011 Gabor Juhos - * Copyright (C) 2008 Imre Kaloz - * - * Parts of this file are based on Atheros' 2.6.15 BSP - * - * 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 "pci.h" - -static int (*ath79_pci_plat_dev_init)(struct pci_dev *dev); -static const struct ath79_pci_irq *ath79_pci_irq_map __initdata; -static unsigned ath79_pci_nr_irqs __initdata; - -static const struct ath79_pci_irq ar71xx_pci_irq_map[] __initconst = { - { - .slot = 17, - .pin = 1, - .irq = ATH79_PCI_IRQ(0), - }, { - .slot = 18, - .pin = 1, - .irq = ATH79_PCI_IRQ(1), - }, { - .slot = 19, - .pin = 1, - .irq = ATH79_PCI_IRQ(2), - } -}; - -static const struct ath79_pci_irq ar724x_pci_irq_map[] __initconst = { - { - .slot = 0, - .pin = 1, - .irq = ATH79_PCI_IRQ(0), - } -}; - -int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin) -{ - int irq = -1; - int i; - - if (ath79_pci_nr_irqs == 0 || - ath79_pci_irq_map == NULL) { - if (soc_is_ar71xx()) { - ath79_pci_irq_map = ar71xx_pci_irq_map; - ath79_pci_nr_irqs = ARRAY_SIZE(ar71xx_pci_irq_map); - } else if (soc_is_ar724x() || - soc_is_ar9342() || - soc_is_ar9344()) { - ath79_pci_irq_map = ar724x_pci_irq_map; - ath79_pci_nr_irqs = ARRAY_SIZE(ar724x_pci_irq_map); - } else { - pr_crit("pci %s: invalid irq map\n", - pci_name((struct pci_dev *) dev)); - return irq; - } - } - - for (i = 0; i < ath79_pci_nr_irqs; i++) { - const struct ath79_pci_irq *entry; - - entry = &ath79_pci_irq_map[i]; - if (entry->slot == slot && entry->pin == pin) { - irq = entry->irq; - break; - } - } - - if (irq < 0) - pr_crit("pci %s: no irq found for pin %u\n", - pci_name((struct pci_dev *) dev), pin); - else - pr_info("pci %s: using irq %d for pin %u\n", - pci_name((struct pci_dev *) dev), irq, pin); - - return irq; -} - -int pcibios_plat_dev_init(struct pci_dev *dev) -{ - if (ath79_pci_plat_dev_init) - return ath79_pci_plat_dev_init(dev); - - return 0; -} - -void __init ath79_pci_set_irq_map(unsigned nr_irqs, - const struct ath79_pci_irq *map) -{ - ath79_pci_nr_irqs = nr_irqs; - ath79_pci_irq_map = map; -} - -void __init ath79_pci_set_plat_dev_init(int (*func)(struct pci_dev *dev)) -{ - ath79_pci_plat_dev_init = func; -} - -int __init ath79_register_pci(void) -{ - if (soc_is_ar71xx()) - return ar71xx_pcibios_init(); - - if (soc_is_ar724x()) - return ar724x_pcibios_init(ATH79_CPU_IRQ_IP2); - - if (soc_is_ar9342() || soc_is_ar9344()) { - u32 bootstrap; - - bootstrap = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP); - if (bootstrap & AR934X_BOOTSTRAP_PCIE_RC) - return ar724x_pcibios_init(ATH79_IP2_IRQ(0)); - } - - return -ENODEV; -} diff --git a/trunk/arch/mips/ath79/pci.h b/trunk/arch/mips/ath79/pci.h deleted file mode 100644 index 51c6625dcc6d..000000000000 --- a/trunk/arch/mips/ath79/pci.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Atheros AR71XX/AR724X PCI support - * - * Copyright (C) 2011 René Bolldorf - * Copyright (C) 2008-2011 Gabor Juhos - * Copyright (C) 2008 Imre Kaloz - * - * 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 _ATH79_PCI_H -#define _ATH79_PCI_H - -struct ath79_pci_irq { - u8 slot; - u8 pin; - int irq; -}; - -#ifdef CONFIG_PCI -void ath79_pci_set_irq_map(unsigned nr_irqs, const struct ath79_pci_irq *map); -void ath79_pci_set_plat_dev_init(int (*func)(struct pci_dev *dev)); -int ath79_register_pci(void); -#else -static inline void -ath79_pci_set_irq_map(unsigned nr_irqs, const struct ath79_pci_irq *map) {} -static inline void -ath79_pci_set_plat_dev_init(int (*func)(struct pci_dev *)) {} -static inline int ath79_register_pci(void) { return 0; } -#endif - -#endif /* _ATH79_PCI_H */ diff --git a/trunk/arch/mips/ath79/setup.c b/trunk/arch/mips/ath79/setup.c index 60d212ef8629..80a7d4023d7f 100644 --- a/trunk/arch/mips/ath79/setup.c +++ b/trunk/arch/mips/ath79/setup.c @@ -1,11 +1,10 @@ /* * Atheros AR71XX/AR724X/AR913X specific setup * - * Copyright (C) 2010-2011 Jaiganesh Narayanan * Copyright (C) 2008-2011 Gabor Juhos * Copyright (C) 2008 Imre Kaloz * - * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP + * Parts of this file are based on Atheros' 2.6.15 BSP * * 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 @@ -117,6 +116,18 @@ static void __init ath79_detect_sys_type(void) rev = id & AR724X_REV_ID_REVISION_MASK; break; + case REV_ID_MAJOR_AR9330: + ath79_soc = ATH79_SOC_AR9330; + chip = "9330"; + rev = id & AR933X_REV_ID_REVISION_MASK; + break; + + case REV_ID_MAJOR_AR9331: + ath79_soc = ATH79_SOC_AR9331; + chip = "9331"; + rev = id & AR933X_REV_ID_REVISION_MASK; + break; + case REV_ID_MAJOR_AR913X: minor = id & AR913X_REV_ID_MINOR_MASK; rev = id >> AR913X_REV_ID_REVISION_SHIFT; @@ -134,36 +145,6 @@ static void __init ath79_detect_sys_type(void) } break; - case REV_ID_MAJOR_AR9330: - ath79_soc = ATH79_SOC_AR9330; - chip = "9330"; - rev = id & AR933X_REV_ID_REVISION_MASK; - break; - - case REV_ID_MAJOR_AR9331: - ath79_soc = ATH79_SOC_AR9331; - chip = "9331"; - rev = id & AR933X_REV_ID_REVISION_MASK; - break; - - case REV_ID_MAJOR_AR9341: - ath79_soc = ATH79_SOC_AR9341; - chip = "9341"; - rev = id & AR934X_REV_ID_REVISION_MASK; - break; - - case REV_ID_MAJOR_AR9342: - ath79_soc = ATH79_SOC_AR9342; - chip = "9342"; - rev = id & AR934X_REV_ID_REVISION_MASK; - break; - - case REV_ID_MAJOR_AR9344: - ath79_soc = ATH79_SOC_AR9344; - chip = "9344"; - rev = id & AR934X_REV_ID_REVISION_MASK; - break; - default: panic("ath79: unknown SoC, id:0x%08x", id); } diff --git a/trunk/arch/mips/bcm63xx/boards/Makefile b/trunk/arch/mips/bcm63xx/boards/Makefile index af07c1aa202f..9f64fb414077 100644 --- a/trunk/arch/mips/bcm63xx/boards/Makefile +++ b/trunk/arch/mips/bcm63xx/boards/Makefile @@ -1 +1,3 @@ obj-$(CONFIG_BOARD_BCM963XX) += board_bcm963xx.o + +ccflags-y := -Werror diff --git a/trunk/arch/mips/cavium-octeon/setup.c b/trunk/arch/mips/cavium-octeon/setup.c index 260dc247c052..d3a9f012aa0a 100644 --- a/trunk/arch/mips/cavium-octeon/setup.c +++ b/trunk/arch/mips/cavium-octeon/setup.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/mips/cavium-octeon/smp.c b/trunk/arch/mips/cavium-octeon/smp.c index 4b93048044eb..97e7ce9b50ed 100644 --- a/trunk/arch/mips/cavium-octeon/smp.c +++ b/trunk/arch/mips/cavium-octeon/smp.c @@ -257,6 +257,8 @@ DEFINE_PER_CPU(int, cpu_state); extern void fixup_irqs(void); +static DEFINE_SPINLOCK(smp_reserve_lock); + static int octeon_cpu_disable(void) { unsigned int cpu = smp_processor_id(); @@ -264,6 +266,8 @@ static int octeon_cpu_disable(void) if (cpu == 0) return -EBUSY; + spin_lock(&smp_reserve_lock); + set_cpu_online(cpu, false); cpu_clear(cpu, cpu_callin_map); local_irq_disable(); @@ -273,6 +277,8 @@ static int octeon_cpu_disable(void) flush_cache_all(); local_flush_tlb_all(); + spin_unlock(&smp_reserve_lock); + return 0; } diff --git a/trunk/arch/mips/fw/arc/Makefile b/trunk/arch/mips/fw/arc/Makefile index 4f349ec1ea2d..5314b37aff2c 100644 --- a/trunk/arch/mips/fw/arc/Makefile +++ b/trunk/arch/mips/fw/arc/Makefile @@ -8,3 +8,5 @@ lib-y += cmdline.o env.o file.o identify.o init.o \ lib-$(CONFIG_ARC_MEMORY) += memory.o lib-$(CONFIG_ARC_CONSOLE) += arc_con.o lib-$(CONFIG_ARC_PROMLIB) += promlib.o + +ccflags-y := -Werror diff --git a/trunk/arch/mips/include/asm/clkdev.h b/trunk/arch/mips/include/asm/clkdev.h deleted file mode 100644 index 262475414e5f..000000000000 --- a/trunk/arch/mips/include/asm/clkdev.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * based on arch/arm/include/asm/clkdev.h - * - * Copyright (C) 2008 Russell King. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Helper for the clk API to assist looking up a struct clk. - */ -#ifndef __ASM_CLKDEV_H -#define __ASM_CLKDEV_H - -#include - -#define __clk_get(clk) ({ 1; }) -#define __clk_put(clk) do { } while (0) - -static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) -{ - return kzalloc(size, GFP_KERNEL); -} - -#endif diff --git a/trunk/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/trunk/arch/mips/include/asm/mach-ath79/ar71xx_regs.h index 1caa78ad06d5..2f0becb4ec8f 100644 --- a/trunk/arch/mips/include/asm/mach-ath79/ar71xx_regs.h +++ b/trunk/arch/mips/include/asm/mach-ath79/ar71xx_regs.h @@ -1,11 +1,10 @@ /* * Atheros AR71XX/AR724X/AR913X SoC register definitions * - * Copyright (C) 2010-2011 Jaiganesh Narayanan * Copyright (C) 2008-2010 Gabor Juhos * Copyright (C) 2008 Imre Kaloz * - * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP + * Parts of this file are based on Atheros' 2.6.15 BSP * * 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 @@ -61,9 +60,6 @@ #define AR933X_EHCI_BASE 0x1b000000 #define AR933X_EHCI_SIZE 0x1000 -#define AR934X_WMAC_BASE (AR71XX_APB_BASE + 0x00100000) -#define AR934X_WMAC_SIZE 0x20000 - /* * DDR_CTRL block */ @@ -95,12 +91,6 @@ #define AR933X_DDR_REG_FLUSH_USB 0x84 #define AR933X_DDR_REG_FLUSH_WMAC 0x88 -#define AR934X_DDR_REG_FLUSH_GE0 0x9c -#define AR934X_DDR_REG_FLUSH_GE1 0xa0 -#define AR934X_DDR_REG_FLUSH_USB 0xa4 -#define AR934X_DDR_REG_FLUSH_PCIE 0xa8 -#define AR934X_DDR_REG_FLUSH_WMAC 0xac - /* * PLL block */ @@ -160,41 +150,6 @@ #define AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT 15 #define AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK 0x7 -#define AR934X_PLL_CPU_CONFIG_REG 0x00 -#define AR934X_PLL_DDR_CONFIG_REG 0x04 -#define AR934X_PLL_CPU_DDR_CLK_CTRL_REG 0x08 - -#define AR934X_PLL_CPU_CONFIG_NFRAC_SHIFT 0 -#define AR934X_PLL_CPU_CONFIG_NFRAC_MASK 0x3f -#define AR934X_PLL_CPU_CONFIG_NINT_SHIFT 6 -#define AR934X_PLL_CPU_CONFIG_NINT_MASK 0x3f -#define AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT 12 -#define AR934X_PLL_CPU_CONFIG_REFDIV_MASK 0x1f -#define AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT 19 -#define AR934X_PLL_CPU_CONFIG_OUTDIV_MASK 0x3 - -#define AR934X_PLL_DDR_CONFIG_NFRAC_SHIFT 0 -#define AR934X_PLL_DDR_CONFIG_NFRAC_MASK 0x3ff -#define AR934X_PLL_DDR_CONFIG_NINT_SHIFT 10 -#define AR934X_PLL_DDR_CONFIG_NINT_MASK 0x3f -#define AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT 16 -#define AR934X_PLL_DDR_CONFIG_REFDIV_MASK 0x1f -#define AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT 23 -#define AR934X_PLL_DDR_CONFIG_OUTDIV_MASK 0x7 - -#define AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_PLL_BYPASS BIT(2) -#define AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_PLL_BYPASS BIT(3) -#define AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_PLL_BYPASS BIT(4) -#define AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_SHIFT 5 -#define AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_MASK 0x1f -#define AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_SHIFT 10 -#define AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_MASK 0x1f -#define AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_SHIFT 15 -#define AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_MASK 0x1f -#define AR934X_PLL_CPU_DDR_CLK_CTRL_CPUCLK_FROM_CPUPLL BIT(20) -#define AR934X_PLL_CPU_DDR_CLK_CTRL_DDRCLK_FROM_DDRPLL BIT(21) -#define AR934X_PLL_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL BIT(24) - /* * USB_CONFIG block */ @@ -230,10 +185,6 @@ #define AR933X_RESET_REG_RESET_MODULE 0x1c #define AR933X_RESET_REG_BOOTSTRAP 0xac -#define AR934X_RESET_REG_RESET_MODULE 0x1c -#define AR934X_RESET_REG_BOOTSTRAP 0xb0 -#define AR934X_RESET_REG_PCIE_WMAC_INT_STATUS 0xac - #define MISC_INT_ETHSW BIT(12) #define MISC_INT_TIMER4 BIT(10) #define MISC_INT_TIMER3 BIT(9) @@ -290,40 +241,6 @@ #define AR933X_BOOTSTRAP_REF_CLK_40 BIT(0) -#define AR934X_BOOTSTRAP_SW_OPTION8 BIT(23) -#define AR934X_BOOTSTRAP_SW_OPTION7 BIT(22) -#define AR934X_BOOTSTRAP_SW_OPTION6 BIT(21) -#define AR934X_BOOTSTRAP_SW_OPTION5 BIT(20) -#define AR934X_BOOTSTRAP_SW_OPTION4 BIT(19) -#define AR934X_BOOTSTRAP_SW_OPTION3 BIT(18) -#define AR934X_BOOTSTRAP_SW_OPTION2 BIT(17) -#define AR934X_BOOTSTRAP_SW_OPTION1 BIT(16) -#define AR934X_BOOTSTRAP_USB_MODE_DEVICE BIT(7) -#define AR934X_BOOTSTRAP_PCIE_RC BIT(6) -#define AR934X_BOOTSTRAP_EJTAG_MODE BIT(5) -#define AR934X_BOOTSTRAP_REF_CLK_40 BIT(4) -#define AR934X_BOOTSTRAP_BOOT_FROM_SPI BIT(2) -#define AR934X_BOOTSTRAP_SDRAM_DISABLED BIT(1) -#define AR934X_BOOTSTRAP_DDR1 BIT(0) - -#define AR934X_PCIE_WMAC_INT_WMAC_MISC BIT(0) -#define AR934X_PCIE_WMAC_INT_WMAC_TX BIT(1) -#define AR934X_PCIE_WMAC_INT_WMAC_RXLP BIT(2) -#define AR934X_PCIE_WMAC_INT_WMAC_RXHP BIT(3) -#define AR934X_PCIE_WMAC_INT_PCIE_RC BIT(4) -#define AR934X_PCIE_WMAC_INT_PCIE_RC0 BIT(5) -#define AR934X_PCIE_WMAC_INT_PCIE_RC1 BIT(6) -#define AR934X_PCIE_WMAC_INT_PCIE_RC2 BIT(7) -#define AR934X_PCIE_WMAC_INT_PCIE_RC3 BIT(8) -#define AR934X_PCIE_WMAC_INT_WMAC_ALL \ - (AR934X_PCIE_WMAC_INT_WMAC_MISC | AR934X_PCIE_WMAC_INT_WMAC_TX | \ - AR934X_PCIE_WMAC_INT_WMAC_RXLP | AR934X_PCIE_WMAC_INT_WMAC_RXHP) - -#define AR934X_PCIE_WMAC_INT_PCIE_ALL \ - (AR934X_PCIE_WMAC_INT_PCIE_RC | AR934X_PCIE_WMAC_INT_PCIE_RC0 | \ - AR934X_PCIE_WMAC_INT_PCIE_RC1 | AR934X_PCIE_WMAC_INT_PCIE_RC2 | \ - AR934X_PCIE_WMAC_INT_PCIE_RC3) - #define REV_ID_MAJOR_MASK 0xfff0 #define REV_ID_MAJOR_AR71XX 0x00a0 #define REV_ID_MAJOR_AR913X 0x00b0 @@ -332,9 +249,6 @@ #define REV_ID_MAJOR_AR7242 0x1100 #define REV_ID_MAJOR_AR9330 0x0110 #define REV_ID_MAJOR_AR9331 0x1110 -#define REV_ID_MAJOR_AR9341 0x0120 -#define REV_ID_MAJOR_AR9342 0x1120 -#define REV_ID_MAJOR_AR9344 0x2120 #define AR71XX_REV_ID_MINOR_MASK 0x3 #define AR71XX_REV_ID_MINOR_AR7130 0x0 @@ -353,8 +267,6 @@ #define AR724X_REV_ID_REVISION_MASK 0x3 -#define AR934X_REV_ID_REVISION_MASK 0xf - /* * SPI block */ @@ -396,6 +308,5 @@ #define AR724X_GPIO_COUNT 18 #define AR913X_GPIO_COUNT 22 #define AR933X_GPIO_COUNT 30 -#define AR934X_GPIO_COUNT 23 #endif /* __ASM_MACH_AR71XX_REGS_H */ diff --git a/trunk/arch/mips/include/asm/mach-ath79/ath79.h b/trunk/arch/mips/include/asm/mach-ath79/ath79.h index 4f248c3d7b23..6d0c6c9d5622 100644 --- a/trunk/arch/mips/include/asm/mach-ath79/ath79.h +++ b/trunk/arch/mips/include/asm/mach-ath79/ath79.h @@ -29,9 +29,6 @@ enum ath79_soc_type { ATH79_SOC_AR9132, ATH79_SOC_AR9330, ATH79_SOC_AR9331, - ATH79_SOC_AR9341, - ATH79_SOC_AR9342, - ATH79_SOC_AR9344, }; extern enum ath79_soc_type ath79_soc; @@ -78,26 +75,6 @@ static inline int soc_is_ar933x(void) ath79_soc == ATH79_SOC_AR9331); } -static inline int soc_is_ar9341(void) -{ - return (ath79_soc == ATH79_SOC_AR9341); -} - -static inline int soc_is_ar9342(void) -{ - return (ath79_soc == ATH79_SOC_AR9342); -} - -static inline int soc_is_ar9344(void) -{ - return (ath79_soc == ATH79_SOC_AR9344); -} - -static inline int soc_is_ar934x(void) -{ - return soc_is_ar9341() || soc_is_ar9342() || soc_is_ar9344(); -} - extern void __iomem *ath79_ddr_base; extern void __iomem *ath79_pll_base; extern void __iomem *ath79_reset_base; diff --git a/trunk/arch/mips/include/asm/mach-ath79/irq.h b/trunk/arch/mips/include/asm/mach-ath79/irq.h index 0968f69e2018..519958fe4e3c 100644 --- a/trunk/arch/mips/include/asm/mach-ath79/irq.h +++ b/trunk/arch/mips/include/asm/mach-ath79/irq.h @@ -10,19 +10,11 @@ #define __ASM_MACH_ATH79_IRQ_H #define MIPS_CPU_IRQ_BASE 0 -#define NR_IRQS 48 +#define NR_IRQS 40 #define ATH79_MISC_IRQ_BASE 8 #define ATH79_MISC_IRQ_COUNT 32 -#define ATH79_PCI_IRQ_BASE (ATH79_MISC_IRQ_BASE + ATH79_MISC_IRQ_COUNT) -#define ATH79_PCI_IRQ_COUNT 6 -#define ATH79_PCI_IRQ(_x) (ATH79_PCI_IRQ_BASE + (_x)) - -#define ATH79_IP2_IRQ_BASE (ATH79_PCI_IRQ_BASE + ATH79_PCI_IRQ_COUNT) -#define ATH79_IP2_IRQ_COUNT 2 -#define ATH79_IP2_IRQ(_x) (ATH79_IP2_IRQ_BASE + (_x)) - #define ATH79_CPU_IRQ_IP2 (MIPS_CPU_IRQ_BASE + 2) #define ATH79_CPU_IRQ_USB (MIPS_CPU_IRQ_BASE + 3) #define ATH79_CPU_IRQ_GE0 (MIPS_CPU_IRQ_BASE + 4) diff --git a/trunk/arch/mips/include/asm/mach-ath79/pci-ath724x.h b/trunk/arch/mips/include/asm/mach-ath79/pci-ath724x.h new file mode 100644 index 000000000000..454885fa30c3 --- /dev/null +++ b/trunk/arch/mips/include/asm/mach-ath79/pci-ath724x.h @@ -0,0 +1,21 @@ +/* + * Atheros 724x PCI support + * + * Copyright (C) 2011 René Bolldorf + * + * 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_MACH_ATH79_PCI_ATH724X_H +#define __ASM_MACH_ATH79_PCI_ATH724X_H + +struct ath724x_pci_data { + int irq; + void *pdata; +}; + +void ath724x_pci_add_data(struct ath724x_pci_data *data, int size); + +#endif /* __ASM_MACH_ATH79_PCI_ATH724X_H */ diff --git a/trunk/arch/mips/include/asm/mach-ath79/pci.h b/trunk/arch/mips/include/asm/mach-ath79/pci.h deleted file mode 100644 index 7868f7fa028f..000000000000 --- a/trunk/arch/mips/include/asm/mach-ath79/pci.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Atheros AR71XX/AR724X PCI support - * - * Copyright (C) 2011 René Bolldorf - * Copyright (C) 2008-2011 Gabor Juhos - * Copyright (C) 2008 Imre Kaloz - * - * 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_MACH_ATH79_PCI_H -#define __ASM_MACH_ATH79_PCI_H - -#if defined(CONFIG_PCI) && defined(CONFIG_SOC_AR71XX) -int ar71xx_pcibios_init(void); -#else -static inline int ar71xx_pcibios_init(void) { return 0; } -#endif - -#if defined(CONFIG_PCI_AR724X) -int ar724x_pcibios_init(int irq); -#else -static inline int ar724x_pcibios_init(int irq) { return 0; } -#endif - -#endif /* __ASM_MACH_ATH79_PCI_H */ diff --git a/trunk/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h b/trunk/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h index 1d7dd96aa460..3d5de96d4036 100644 --- a/trunk/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h +++ b/trunk/arch/mips/include/asm/mach-bcm63xx/bcm63xx_gpio.h @@ -2,7 +2,6 @@ #define BCM63XX_GPIO_H #include -#include int __init bcm63xx_gpio_init(void); diff --git a/trunk/arch/mips/include/asm/mach-lantiq/falcon/falcon_irq.h b/trunk/arch/mips/include/asm/mach-lantiq/falcon/falcon_irq.h deleted file mode 100644 index 318f982f04ff..000000000000 --- a/trunk/arch/mips/include/asm/mach-lantiq/falcon/falcon_irq.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2010 Thomas Langer - */ - -#ifndef _FALCON_IRQ__ -#define _FALCON_IRQ__ - -#define INT_NUM_IRQ0 8 -#define INT_NUM_IM0_IRL0 (INT_NUM_IRQ0 + 0) -#define INT_NUM_IM1_IRL0 (INT_NUM_IM0_IRL0 + 32) -#define INT_NUM_IM2_IRL0 (INT_NUM_IM1_IRL0 + 32) -#define INT_NUM_IM3_IRL0 (INT_NUM_IM2_IRL0 + 32) -#define INT_NUM_IM4_IRL0 (INT_NUM_IM3_IRL0 + 32) -#define INT_NUM_EXTRA_START (INT_NUM_IM4_IRL0 + 32) -#define INT_NUM_IM_OFFSET (INT_NUM_IM1_IRL0 - INT_NUM_IM0_IRL0) - -#define MIPS_CPU_TIMER_IRQ 7 - -#endif /* _FALCON_IRQ__ */ diff --git a/trunk/arch/mips/include/asm/mach-lantiq/falcon/irq.h b/trunk/arch/mips/include/asm/mach-lantiq/falcon/irq.h deleted file mode 100644 index 2caccd9f9dbc..000000000000 --- a/trunk/arch/mips/include/asm/mach-lantiq/falcon/irq.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2011 Thomas Langer - */ - -#ifndef __FALCON_IRQ_H -#define __FALCON_IRQ_H - -#include - -#define NR_IRQS 328 - -#include_next - -#endif diff --git a/trunk/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h b/trunk/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h deleted file mode 100644 index b385252584ee..000000000000 --- a/trunk/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2010 John Crispin - */ - -#ifndef _LTQ_FALCON_H__ -#define _LTQ_FALCON_H__ - -#ifdef CONFIG_SOC_FALCON - -#include -#include - -/* Chip IDs */ -#define SOC_ID_FALCON 0x01B8 - -/* SoC Types */ -#define SOC_TYPE_FALCON 0x01 - -/* - * during early_printk no ioremap possible at this early stage - * lets use KSEG1 instead - */ -#define LTQ_ASC0_BASE_ADDR 0x1E100C00 -#define LTQ_EARLY_ASC KSEG1ADDR(LTQ_ASC0_BASE_ADDR) - -/* WDT */ -#define LTQ_RST_CAUSE_WDTRST 0x0002 - -/* CHIP ID */ -#define LTQ_STATUS_BASE_ADDR 0x1E802000 - -#define FALCON_CHIPID ((u32 *)(KSEG1 + LTQ_STATUS_BASE_ADDR + 0x0c)) -#define FALCON_CHIPTYPE ((u32 *)(KSEG1 + LTQ_STATUS_BASE_ADDR + 0x38)) -#define FALCON_CHIPCONF ((u32 *)(KSEG1 + LTQ_STATUS_BASE_ADDR + 0x40)) - -/* SYSCTL - start/stop/restart/configure/... different parts of the Soc */ -#define SYSCTL_SYS1 0 -#define SYSCTL_SYSETH 1 -#define SYSCTL_SYSGPE 2 - -/* BOOT_SEL - find what boot media we have */ -#define BS_FLASH 0x1 -#define BS_SPI 0x4 - -/* global register ranges */ -extern __iomem void *ltq_ebu_membase; -extern __iomem void *ltq_sys1_membase; -#define ltq_ebu_w32(x, y) ltq_w32((x), ltq_ebu_membase + (y)) -#define ltq_ebu_r32(x) ltq_r32(ltq_ebu_membase + (x)) - -#define ltq_sys1_w32(x, y) ltq_w32((x), ltq_sys1_membase + (y)) -#define ltq_sys1_r32(x) ltq_r32(ltq_sys1_membase + (x)) -#define ltq_sys1_w32_mask(clear, set, reg) \ - ltq_sys1_w32((ltq_sys1_r32(reg) & ~(clear)) | (set), reg) - -/* - * to keep the irq code generic we need to define this to 0 as falcon - * has no EIU/EBU - */ -#define LTQ_EBU_PCC_ISTAT 0 - -#endif /* CONFIG_SOC_FALCON */ -#endif /* _LTQ_XWAY_H__ */ diff --git a/trunk/arch/mips/include/asm/mach-lantiq/gpio.h b/trunk/arch/mips/include/asm/mach-lantiq/gpio.h deleted file mode 100644 index f79505b43609..000000000000 --- a/trunk/arch/mips/include/asm/mach-lantiq/gpio.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __ASM_MIPS_MACH_LANTIQ_GPIO_H -#define __ASM_MIPS_MACH_LANTIQ_GPIO_H - -static inline int gpio_to_irq(unsigned int gpio) -{ - return -1; -} - -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value - -#define gpio_cansleep __gpio_cansleep - -#include - -#endif diff --git a/trunk/arch/mips/include/asm/mach-lantiq/lantiq.h b/trunk/arch/mips/include/asm/mach-lantiq/lantiq.h index 5e8a6e965756..ce2f02929d22 100644 --- a/trunk/arch/mips/include/asm/mach-lantiq/lantiq.h +++ b/trunk/arch/mips/include/asm/mach-lantiq/lantiq.h @@ -9,8 +9,6 @@ #define _LANTIQ_H__ #include -#include -#include /* generic reg access functions */ #define ltq_r32(reg) __raw_readl(reg) @@ -23,9 +21,25 @@ /* register access macros for EBU and CGU */ #define ltq_ebu_w32(x, y) ltq_w32((x), ltq_ebu_membase + (y)) #define ltq_ebu_r32(x) ltq_r32(ltq_ebu_membase + (x)) -#define ltq_ebu_w32_mask(x, y, z) \ - ltq_w32_mask(x, y, ltq_ebu_membase + (z)) +#define ltq_cgu_w32(x, y) ltq_w32((x), ltq_cgu_membase + (y)) +#define ltq_cgu_r32(x) ltq_r32(ltq_cgu_membase + (x)) + extern __iomem void *ltq_ebu_membase; +extern __iomem void *ltq_cgu_membase; + +extern unsigned int ltq_get_cpu_ver(void); +extern unsigned int ltq_get_soc_type(void); + +/* clock speeds */ +#define CLOCK_60M 60000000 +#define CLOCK_83M 83333333 +#define CLOCK_111M 111111111 +#define CLOCK_133M 133333333 +#define CLOCK_167M 166666667 +#define CLOCK_200M 200000000 +#define CLOCK_266M 266666666 +#define CLOCK_333M 333333333 +#define CLOCK_400M 400000000 /* spinlock all ebu i/o */ extern spinlock_t ebu_lock; @@ -35,21 +49,15 @@ extern void ltq_disable_irq(struct irq_data *data); extern void ltq_mask_and_ack_irq(struct irq_data *data); extern void ltq_enable_irq(struct irq_data *data); -/* clock handling */ -extern int clk_activate(struct clk *clk); -extern void clk_deactivate(struct clk *clk); -extern struct clk *clk_get_cpu(void); -extern struct clk *clk_get_fpi(void); -extern struct clk *clk_get_io(void); - -/* find out what bootsource we have */ -extern unsigned char ltq_boot_select(void); /* find out what caused the last cpu reset */ extern int ltq_reset_cause(void); +#define LTQ_RST_CAUSE_WDTRST 0x20 #define IOPORT_RESOURCE_START 0x10000000 #define IOPORT_RESOURCE_END 0xffffffff #define IOMEM_RESOURCE_START 0x10000000 #define IOMEM_RESOURCE_END 0xffffffff +#define LTQ_FLASH_START 0x10000000 +#define LTQ_FLASH_MAX 0x04000000 #endif diff --git a/trunk/arch/mips/include/asm/mach-lantiq/lantiq_platform.h b/trunk/arch/mips/include/asm/mach-lantiq/lantiq_platform.h index e23bf7c9a2d0..a305f1d0259e 100644 --- a/trunk/arch/mips/include/asm/mach-lantiq/lantiq_platform.h +++ b/trunk/arch/mips/include/asm/mach-lantiq/lantiq_platform.h @@ -9,8 +9,41 @@ #ifndef _LANTIQ_PLATFORM_H__ #define _LANTIQ_PLATFORM_H__ +#include #include +/* struct used to pass info to the pci core */ +enum { + PCI_CLOCK_INT = 0, + PCI_CLOCK_EXT +}; + +#define PCI_EXIN0 0x0001 +#define PCI_EXIN1 0x0002 +#define PCI_EXIN2 0x0004 +#define PCI_EXIN3 0x0008 +#define PCI_EXIN4 0x0010 +#define PCI_EXIN5 0x0020 +#define PCI_EXIN_MAX 6 + +#define PCI_GNT1 0x0040 +#define PCI_GNT2 0x0080 +#define PCI_GNT3 0x0100 +#define PCI_GNT4 0x0200 + +#define PCI_REQ1 0x0400 +#define PCI_REQ2 0x0800 +#define PCI_REQ3 0x1000 +#define PCI_REQ4 0x2000 +#define PCI_REQ_SHIFT 10 +#define PCI_REQ_MASK 0xf + +struct ltq_pci_data { + int clock; + int gpio; + int irq[16]; +}; + /* struct used to pass info to network drivers */ struct ltq_eth_data { struct sockaddr mac; diff --git a/trunk/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h b/trunk/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h index aa0b3b866f84..b4465a888e20 100644 --- a/trunk/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h +++ b/trunk/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h @@ -17,8 +17,50 @@ #define INT_NUM_IM4_IRL0 (INT_NUM_IRQ0 + 128) #define INT_NUM_IM_OFFSET (INT_NUM_IM1_IRL0 - INT_NUM_IM0_IRL0) +#define LTQ_ASC_TIR(x) (INT_NUM_IM3_IRL0 + (x * 8)) +#define LTQ_ASC_RIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 1) +#define LTQ_ASC_EIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 2) + +#define LTQ_ASC_ASE_TIR INT_NUM_IM2_IRL0 +#define LTQ_ASC_ASE_RIR (INT_NUM_IM2_IRL0 + 2) +#define LTQ_ASC_ASE_EIR (INT_NUM_IM2_IRL0 + 3) + +#define LTQ_SSC_TIR (INT_NUM_IM0_IRL0 + 15) +#define LTQ_SSC_RIR (INT_NUM_IM0_IRL0 + 14) +#define LTQ_SSC_EIR (INT_NUM_IM0_IRL0 + 16) + +#define LTQ_MEI_DYING_GASP_INT (INT_NUM_IM1_IRL0 + 21) +#define LTQ_MEI_INT (INT_NUM_IM1_IRL0 + 23) + +#define LTQ_TIMER6_INT (INT_NUM_IM1_IRL0 + 23) +#define LTQ_USB_INT (INT_NUM_IM1_IRL0 + 22) +#define LTQ_USB_OC_INT (INT_NUM_IM4_IRL0 + 23) + +#define MIPS_CPU_TIMER_IRQ 7 + #define LTQ_DMA_CH0_INT (INT_NUM_IM2_IRL0) +#define LTQ_DMA_CH1_INT (INT_NUM_IM2_IRL0 + 1) +#define LTQ_DMA_CH2_INT (INT_NUM_IM2_IRL0 + 2) +#define LTQ_DMA_CH3_INT (INT_NUM_IM2_IRL0 + 3) +#define LTQ_DMA_CH4_INT (INT_NUM_IM2_IRL0 + 4) +#define LTQ_DMA_CH5_INT (INT_NUM_IM2_IRL0 + 5) +#define LTQ_DMA_CH6_INT (INT_NUM_IM2_IRL0 + 6) +#define LTQ_DMA_CH7_INT (INT_NUM_IM2_IRL0 + 7) +#define LTQ_DMA_CH8_INT (INT_NUM_IM2_IRL0 + 8) +#define LTQ_DMA_CH9_INT (INT_NUM_IM2_IRL0 + 9) +#define LTQ_DMA_CH10_INT (INT_NUM_IM2_IRL0 + 10) +#define LTQ_DMA_CH11_INT (INT_NUM_IM2_IRL0 + 11) +#define LTQ_DMA_CH12_INT (INT_NUM_IM2_IRL0 + 25) +#define LTQ_DMA_CH13_INT (INT_NUM_IM2_IRL0 + 26) +#define LTQ_DMA_CH14_INT (INT_NUM_IM2_IRL0 + 27) +#define LTQ_DMA_CH15_INT (INT_NUM_IM2_IRL0 + 28) +#define LTQ_DMA_CH16_INT (INT_NUM_IM2_IRL0 + 29) +#define LTQ_DMA_CH17_INT (INT_NUM_IM2_IRL0 + 30) +#define LTQ_DMA_CH18_INT (INT_NUM_IM2_IRL0 + 16) +#define LTQ_DMA_CH19_INT (INT_NUM_IM2_IRL0 + 21) + +#define LTQ_PPE_MBOX_INT (INT_NUM_IM2_IRL0 + 24) -#define MIPS_CPU_TIMER_IRQ 7 +#define INT_NUM_IM4_IRL14 (INT_NUM_IM4_IRL0 + 14) #endif diff --git a/trunk/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/trunk/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h index 6a2df709c576..8a3c6be669d2 100644 --- a/trunk/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +++ b/trunk/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h @@ -17,56 +17,38 @@ #define SOC_ID_DANUBE1 0x129 #define SOC_ID_DANUBE2 0x12B #define SOC_ID_TWINPASS 0x12D -#define SOC_ID_AMAZON_SE_1 0x152 /* 50601 */ -#define SOC_ID_AMAZON_SE_2 0x153 /* 50600 */ +#define SOC_ID_AMAZON_SE 0x152 #define SOC_ID_ARX188 0x16C -#define SOC_ID_ARX168_1 0x16D -#define SOC_ID_ARX168_2 0x16E +#define SOC_ID_ARX168 0x16D #define SOC_ID_ARX182 0x16F -#define SOC_ID_GRX188 0x170 -#define SOC_ID_GRX168 0x171 - -#define SOC_ID_VRX288 0x1C0 /* v1.1 */ -#define SOC_ID_VRX282 0x1C1 /* v1.1 */ -#define SOC_ID_VRX268 0x1C2 /* v1.1 */ -#define SOC_ID_GRX268 0x1C8 /* v1.1 */ -#define SOC_ID_GRX288 0x1C9 /* v1.1 */ -#define SOC_ID_VRX288_2 0x00B /* v1.2 */ -#define SOC_ID_VRX268_2 0x00C /* v1.2 */ -#define SOC_ID_GRX288_2 0x00D /* v1.2 */ -#define SOC_ID_GRX282_2 0x00E /* v1.2 */ - - /* SoC Types */ + +/* SoC Types */ #define SOC_TYPE_DANUBE 0x01 #define SOC_TYPE_TWINPASS 0x02 #define SOC_TYPE_AR9 0x03 -#define SOC_TYPE_VR9 0x04 /* v1.1 */ -#define SOC_TYPE_VR9_2 0x05 /* v1.2 */ -#define SOC_TYPE_AMAZON_SE 0x06 - -/* BOOT_SEL - find what boot media we have */ -#define BS_EXT_ROM 0x0 -#define BS_FLASH 0x1 -#define BS_MII0 0x2 -#define BS_PCI 0x3 -#define BS_UART1 0x4 -#define BS_SPI 0x5 -#define BS_NAND 0x6 -#define BS_RMII0 0x7 - -/* helpers used to access the cgu */ -#define ltq_cgu_w32(x, y) ltq_w32((x), ltq_cgu_membase + (y)) -#define ltq_cgu_r32(x) ltq_r32(ltq_cgu_membase + (x)) -extern __iomem void *ltq_cgu_membase; +#define SOC_TYPE_VR9 0x04 +#define SOC_TYPE_AMAZON_SE 0x05 -/* - * during early_printk no ioremap is possible - * lets use KSEG1 instead - */ +/* ASC0/1 - serial port */ +#define LTQ_ASC0_BASE_ADDR 0x1E100400 #define LTQ_ASC1_BASE_ADDR 0x1E100C00 -#define LTQ_EARLY_ASC KSEG1ADDR(LTQ_ASC1_BASE_ADDR) +#define LTQ_ASC_SIZE 0x400 + +/* RCU - reset control unit */ +#define LTQ_RCU_BASE_ADDR 0x1F203000 +#define LTQ_RCU_SIZE 0x1000 + +/* GPTU - general purpose timer unit */ +#define LTQ_GPTU_BASE_ADDR 0x18000300 +#define LTQ_GPTU_SIZE 0x100 /* EBU - external bus unit */ +#define LTQ_EBU_GPIO_START 0x14000000 +#define LTQ_EBU_GPIO_SIZE 0x1000 + +#define LTQ_EBU_BASE_ADDR 0x1E105300 +#define LTQ_EBU_SIZE 0x100 + #define LTQ_EBU_BUSCON0 0x0060 #define LTQ_EBU_PCC_CON 0x0090 #define LTQ_EBU_PCC_IEN 0x00A4 @@ -75,17 +57,85 @@ extern __iomem void *ltq_cgu_membase; #define LTQ_EBU_ADDRSEL1 0x0024 #define EBU_WRDIS 0x80000000 +/* CGU - clock generation unit */ +#define LTQ_CGU_BASE_ADDR 0x1F103000 +#define LTQ_CGU_SIZE 0x1000 + +/* ICU - interrupt control unit */ +#define LTQ_ICU_BASE_ADDR 0x1F880200 +#define LTQ_ICU_SIZE 0x100 + +/* EIU - external interrupt unit */ +#define LTQ_EIU_BASE_ADDR 0x1F101000 +#define LTQ_EIU_SIZE 0x1000 + +/* PMU - power management unit */ +#define LTQ_PMU_BASE_ADDR 0x1F102000 +#define LTQ_PMU_SIZE 0x1000 + +#define PMU_DMA 0x0020 +#define PMU_USB 0x8041 +#define PMU_LED 0x0800 +#define PMU_GPT 0x1000 +#define PMU_PPE 0x2000 +#define PMU_FPI 0x4000 +#define PMU_SWITCH 0x10000000 + +/* ETOP - ethernet */ +#define LTQ_ETOP_BASE_ADDR 0x1E180000 +#define LTQ_ETOP_SIZE 0x40000 + +/* DMA */ +#define LTQ_DMA_BASE_ADDR 0x1E104100 +#define LTQ_DMA_SIZE 0x800 + +/* PCI */ +#define PCI_CR_BASE_ADDR 0x1E105400 +#define PCI_CR_SIZE 0x400 + /* WDT */ -#define LTQ_RST_CAUSE_WDTRST 0x20 +#define LTQ_WDT_BASE_ADDR 0x1F8803F0 +#define LTQ_WDT_SIZE 0x10 + +/* STP - serial to parallel conversion unit */ +#define LTQ_STP_BASE_ADDR 0x1E100BB0 +#define LTQ_STP_SIZE 0x40 + +/* GPIO */ +#define LTQ_GPIO0_BASE_ADDR 0x1E100B10 +#define LTQ_GPIO1_BASE_ADDR 0x1E100B40 +#define LTQ_GPIO2_BASE_ADDR 0x1E100B70 +#define LTQ_GPIO_SIZE 0x30 + +/* SSC */ +#define LTQ_SSC_BASE_ADDR 0x1e100800 +#define LTQ_SSC_SIZE 0x100 + +/* MEI - dsl core */ +#define LTQ_MEI_BASE_ADDR 0x1E116000 + +/* DEU - data encryption unit */ +#define LTQ_DEU_BASE_ADDR 0x1E103100 /* MPS - multi processor unit (voice) */ #define LTQ_MPS_BASE_ADDR (KSEG1 + 0x1F107000) #define LTQ_MPS_CHIPID ((u32 *)(LTQ_MPS_BASE_ADDR + 0x0344)) /* request a non-gpio and set the PIO config */ -#define PMU_PPE BIT(13) +extern int ltq_gpio_request(unsigned int pin, unsigned int alt0, + unsigned int alt1, unsigned int dir, const char *name); extern void ltq_pmu_enable(unsigned int module); extern void ltq_pmu_disable(unsigned int module); +static inline int ltq_is_ar9(void) +{ + return (ltq_get_soc_type() == SOC_TYPE_AR9); +} + +static inline int ltq_is_vr9(void) +{ + return (ltq_get_soc_type() == SOC_TYPE_VR9); +} + #endif /* CONFIG_SOC_TYPE_XWAY */ #endif /* _LTQ_XWAY_H__ */ diff --git a/trunk/arch/mips/include/asm/mips-boards/generic.h b/trunk/arch/mips/include/asm/mips-boards/generic.h index 6e23ceb0ba8c..46c08563e532 100644 --- a/trunk/arch/mips/include/asm/mips-boards/generic.h +++ b/trunk/arch/mips/include/asm/mips-boards/generic.h @@ -93,4 +93,8 @@ extern void mips_pcibios_init(void); #define mips_pcibios_init() do { } while (0) #endif +#ifdef CONFIG_KGDB +extern void kgdb_config(void); +#endif + #endif /* __ASM_MIPS_BOARDS_GENERIC_H */ diff --git a/trunk/arch/mips/include/asm/module.h b/trunk/arch/mips/include/asm/module.h index 530008048c62..7467d1d933d5 100644 --- a/trunk/arch/mips/include/asm/module.h +++ b/trunk/arch/mips/include/asm/module.h @@ -2,7 +2,6 @@ #define _ASM_MODULE_H #include -#include #include struct mod_arch_specific { diff --git a/trunk/arch/mips/include/asm/octeon/cvmx-pcieep-defs.h b/trunk/arch/mips/include/asm/octeon/cvmx-pcieep-defs.h new file mode 100644 index 000000000000..d553f8e88df6 --- /dev/null +++ b/trunk/arch/mips/include/asm/octeon/cvmx-pcieep-defs.h @@ -0,0 +1,1365 @@ +/***********************license start*************** + * Author: Cavium Networks + * + * Contact: support@caviumnetworks.com + * This file is part of the OCTEON SDK + * + * Copyright (c) 2003-2008 Cavium Networks + * + * This file 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 file is distributed in the hope that it will be useful, but + * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or + * NONINFRINGEMENT. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * or visit http://www.gnu.org/licenses/. + * + * This file may also be available under a different license from Cavium. + * Contact Cavium Networks for more information + ***********************license end**************************************/ + +#ifndef __CVMX_PCIEEP_DEFS_H__ +#define __CVMX_PCIEEP_DEFS_H__ + +#define CVMX_PCIEEP_CFG000 \ + (0x0000000000000000ull) +#define CVMX_PCIEEP_CFG001 \ + (0x0000000000000004ull) +#define CVMX_PCIEEP_CFG002 \ + (0x0000000000000008ull) +#define CVMX_PCIEEP_CFG003 \ + (0x000000000000000Cull) +#define CVMX_PCIEEP_CFG004 \ + (0x0000000000000010ull) +#define CVMX_PCIEEP_CFG004_MASK \ + (0x0000000080000010ull) +#define CVMX_PCIEEP_CFG005 \ + (0x0000000000000014ull) +#define CVMX_PCIEEP_CFG005_MASK \ + (0x0000000080000014ull) +#define CVMX_PCIEEP_CFG006 \ + (0x0000000000000018ull) +#define CVMX_PCIEEP_CFG006_MASK \ + (0x0000000080000018ull) +#define CVMX_PCIEEP_CFG007 \ + (0x000000000000001Cull) +#define CVMX_PCIEEP_CFG007_MASK \ + (0x000000008000001Cull) +#define CVMX_PCIEEP_CFG008 \ + (0x0000000000000020ull) +#define CVMX_PCIEEP_CFG008_MASK \ + (0x0000000080000020ull) +#define CVMX_PCIEEP_CFG009 \ + (0x0000000000000024ull) +#define CVMX_PCIEEP_CFG009_MASK \ + (0x0000000080000024ull) +#define CVMX_PCIEEP_CFG010 \ + (0x0000000000000028ull) +#define CVMX_PCIEEP_CFG011 \ + (0x000000000000002Cull) +#define CVMX_PCIEEP_CFG012 \ + (0x0000000000000030ull) +#define CVMX_PCIEEP_CFG012_MASK \ + (0x0000000080000030ull) +#define CVMX_PCIEEP_CFG013 \ + (0x0000000000000034ull) +#define CVMX_PCIEEP_CFG015 \ + (0x000000000000003Cull) +#define CVMX_PCIEEP_CFG016 \ + (0x0000000000000040ull) +#define CVMX_PCIEEP_CFG017 \ + (0x0000000000000044ull) +#define CVMX_PCIEEP_CFG020 \ + (0x0000000000000050ull) +#define CVMX_PCIEEP_CFG021 \ + (0x0000000000000054ull) +#define CVMX_PCIEEP_CFG022 \ + (0x0000000000000058ull) +#define CVMX_PCIEEP_CFG023 \ + (0x000000000000005Cull) +#define CVMX_PCIEEP_CFG028 \ + (0x0000000000000070ull) +#define CVMX_PCIEEP_CFG029 \ + (0x0000000000000074ull) +#define CVMX_PCIEEP_CFG030 \ + (0x0000000000000078ull) +#define CVMX_PCIEEP_CFG031 \ + (0x000000000000007Cull) +#define CVMX_PCIEEP_CFG032 \ + (0x0000000000000080ull) +#define CVMX_PCIEEP_CFG033 \ + (0x0000000000000084ull) +#define CVMX_PCIEEP_CFG034 \ + (0x0000000000000088ull) +#define CVMX_PCIEEP_CFG037 \ + (0x0000000000000094ull) +#define CVMX_PCIEEP_CFG038 \ + (0x0000000000000098ull) +#define CVMX_PCIEEP_CFG039 \ + (0x000000000000009Cull) +#define CVMX_PCIEEP_CFG040 \ + (0x00000000000000A0ull) +#define CVMX_PCIEEP_CFG041 \ + (0x00000000000000A4ull) +#define CVMX_PCIEEP_CFG042 \ + (0x00000000000000A8ull) +#define CVMX_PCIEEP_CFG064 \ + (0x0000000000000100ull) +#define CVMX_PCIEEP_CFG065 \ + (0x0000000000000104ull) +#define CVMX_PCIEEP_CFG066 \ + (0x0000000000000108ull) +#define CVMX_PCIEEP_CFG067 \ + (0x000000000000010Cull) +#define CVMX_PCIEEP_CFG068 \ + (0x0000000000000110ull) +#define CVMX_PCIEEP_CFG069 \ + (0x0000000000000114ull) +#define CVMX_PCIEEP_CFG070 \ + (0x0000000000000118ull) +#define CVMX_PCIEEP_CFG071 \ + (0x000000000000011Cull) +#define CVMX_PCIEEP_CFG072 \ + (0x0000000000000120ull) +#define CVMX_PCIEEP_CFG073 \ + (0x0000000000000124ull) +#define CVMX_PCIEEP_CFG074 \ + (0x0000000000000128ull) +#define CVMX_PCIEEP_CFG448 \ + (0x0000000000000700ull) +#define CVMX_PCIEEP_CFG449 \ + (0x0000000000000704ull) +#define CVMX_PCIEEP_CFG450 \ + (0x0000000000000708ull) +#define CVMX_PCIEEP_CFG451 \ + (0x000000000000070Cull) +#define CVMX_PCIEEP_CFG452 \ + (0x0000000000000710ull) +#define CVMX_PCIEEP_CFG453 \ + (0x0000000000000714ull) +#define CVMX_PCIEEP_CFG454 \ + (0x0000000000000718ull) +#define CVMX_PCIEEP_CFG455 \ + (0x000000000000071Cull) +#define CVMX_PCIEEP_CFG456 \ + (0x0000000000000720ull) +#define CVMX_PCIEEP_CFG458 \ + (0x0000000000000728ull) +#define CVMX_PCIEEP_CFG459 \ + (0x000000000000072Cull) +#define CVMX_PCIEEP_CFG460 \ + (0x0000000000000730ull) +#define CVMX_PCIEEP_CFG461 \ + (0x0000000000000734ull) +#define CVMX_PCIEEP_CFG462 \ + (0x0000000000000738ull) +#define CVMX_PCIEEP_CFG463 \ + (0x000000000000073Cull) +#define CVMX_PCIEEP_CFG464 \ + (0x0000000000000740ull) +#define CVMX_PCIEEP_CFG465 \ + (0x0000000000000744ull) +#define CVMX_PCIEEP_CFG466 \ + (0x0000000000000748ull) +#define CVMX_PCIEEP_CFG467 \ + (0x000000000000074Cull) +#define CVMX_PCIEEP_CFG468 \ + (0x0000000000000750ull) +#define CVMX_PCIEEP_CFG490 \ + (0x00000000000007A8ull) +#define CVMX_PCIEEP_CFG491 \ + (0x00000000000007ACull) +#define CVMX_PCIEEP_CFG492 \ + (0x00000000000007B0ull) +#define CVMX_PCIEEP_CFG516 \ + (0x0000000000000810ull) +#define CVMX_PCIEEP_CFG517 \ + (0x0000000000000814ull) + +union cvmx_pcieep_cfg000 { + uint32_t u32; + struct cvmx_pcieep_cfg000_s { + uint32_t devid:16; + uint32_t vendid:16; + } s; + struct cvmx_pcieep_cfg000_s cn52xx; + struct cvmx_pcieep_cfg000_s cn52xxp1; + struct cvmx_pcieep_cfg000_s cn56xx; + struct cvmx_pcieep_cfg000_s cn56xxp1; +}; + +union cvmx_pcieep_cfg001 { + uint32_t u32; + struct cvmx_pcieep_cfg001_s { + uint32_t dpe:1; + uint32_t sse:1; + uint32_t rma:1; + uint32_t rta:1; + uint32_t sta:1; + uint32_t devt:2; + uint32_t mdpe:1; + uint32_t fbb:1; + uint32_t reserved_22_22:1; + uint32_t m66:1; + uint32_t cl:1; + uint32_t i_stat:1; + uint32_t reserved_11_18:8; + uint32_t i_dis:1; + uint32_t fbbe:1; + uint32_t see:1; + uint32_t ids_wcc:1; + uint32_t per:1; + uint32_t vps:1; + uint32_t mwice:1; + uint32_t scse:1; + uint32_t me:1; + uint32_t msae:1; + uint32_t isae:1; + } s; + struct cvmx_pcieep_cfg001_s cn52xx; + struct cvmx_pcieep_cfg001_s cn52xxp1; + struct cvmx_pcieep_cfg001_s cn56xx; + struct cvmx_pcieep_cfg001_s cn56xxp1; +}; + +union cvmx_pcieep_cfg002 { + uint32_t u32; + struct cvmx_pcieep_cfg002_s { + uint32_t bcc:8; + uint32_t sc:8; + uint32_t pi:8; + uint32_t rid:8; + } s; + struct cvmx_pcieep_cfg002_s cn52xx; + struct cvmx_pcieep_cfg002_s cn52xxp1; + struct cvmx_pcieep_cfg002_s cn56xx; + struct cvmx_pcieep_cfg002_s cn56xxp1; +}; + +union cvmx_pcieep_cfg003 { + uint32_t u32; + struct cvmx_pcieep_cfg003_s { + uint32_t bist:8; + uint32_t mfd:1; + uint32_t chf:7; + uint32_t lt:8; + uint32_t cls:8; + } s; + struct cvmx_pcieep_cfg003_s cn52xx; + struct cvmx_pcieep_cfg003_s cn52xxp1; + struct cvmx_pcieep_cfg003_s cn56xx; + struct cvmx_pcieep_cfg003_s cn56xxp1; +}; + +union cvmx_pcieep_cfg004 { + uint32_t u32; + struct cvmx_pcieep_cfg004_s { + uint32_t lbab:18; + uint32_t reserved_4_13:10; + uint32_t pf:1; + uint32_t typ:2; + uint32_t mspc:1; + } s; + struct cvmx_pcieep_cfg004_s cn52xx; + struct cvmx_pcieep_cfg004_s cn52xxp1; + struct cvmx_pcieep_cfg004_s cn56xx; + struct cvmx_pcieep_cfg004_s cn56xxp1; +}; + +union cvmx_pcieep_cfg004_mask { + uint32_t u32; + struct cvmx_pcieep_cfg004_mask_s { + uint32_t lmask:31; + uint32_t enb:1; + } s; + struct cvmx_pcieep_cfg004_mask_s cn52xx; + struct cvmx_pcieep_cfg004_mask_s cn52xxp1; + struct cvmx_pcieep_cfg004_mask_s cn56xx; + struct cvmx_pcieep_cfg004_mask_s cn56xxp1; +}; + +union cvmx_pcieep_cfg005 { + uint32_t u32; + struct cvmx_pcieep_cfg005_s { + uint32_t ubab:32; + } s; + struct cvmx_pcieep_cfg005_s cn52xx; + struct cvmx_pcieep_cfg005_s cn52xxp1; + struct cvmx_pcieep_cfg005_s cn56xx; + struct cvmx_pcieep_cfg005_s cn56xxp1; +}; + +union cvmx_pcieep_cfg005_mask { + uint32_t u32; + struct cvmx_pcieep_cfg005_mask_s { + uint32_t umask:32; + } s; + struct cvmx_pcieep_cfg005_mask_s cn52xx; + struct cvmx_pcieep_cfg005_mask_s cn52xxp1; + struct cvmx_pcieep_cfg005_mask_s cn56xx; + struct cvmx_pcieep_cfg005_mask_s cn56xxp1; +}; + +union cvmx_pcieep_cfg006 { + uint32_t u32; + struct cvmx_pcieep_cfg006_s { + uint32_t lbab:6; + uint32_t reserved_4_25:22; + uint32_t pf:1; + uint32_t typ:2; + uint32_t mspc:1; + } s; + struct cvmx_pcieep_cfg006_s cn52xx; + struct cvmx_pcieep_cfg006_s cn52xxp1; + struct cvmx_pcieep_cfg006_s cn56xx; + struct cvmx_pcieep_cfg006_s cn56xxp1; +}; + +union cvmx_pcieep_cfg006_mask { + uint32_t u32; + struct cvmx_pcieep_cfg006_mask_s { + uint32_t lmask:31; + uint32_t enb:1; + } s; + struct cvmx_pcieep_cfg006_mask_s cn52xx; + struct cvmx_pcieep_cfg006_mask_s cn52xxp1; + struct cvmx_pcieep_cfg006_mask_s cn56xx; + struct cvmx_pcieep_cfg006_mask_s cn56xxp1; +}; + +union cvmx_pcieep_cfg007 { + uint32_t u32; + struct cvmx_pcieep_cfg007_s { + uint32_t ubab:32; + } s; + struct cvmx_pcieep_cfg007_s cn52xx; + struct cvmx_pcieep_cfg007_s cn52xxp1; + struct cvmx_pcieep_cfg007_s cn56xx; + struct cvmx_pcieep_cfg007_s cn56xxp1; +}; + +union cvmx_pcieep_cfg007_mask { + uint32_t u32; + struct cvmx_pcieep_cfg007_mask_s { + uint32_t umask:32; + } s; + struct cvmx_pcieep_cfg007_mask_s cn52xx; + struct cvmx_pcieep_cfg007_mask_s cn52xxp1; + struct cvmx_pcieep_cfg007_mask_s cn56xx; + struct cvmx_pcieep_cfg007_mask_s cn56xxp1; +}; + +union cvmx_pcieep_cfg008 { + uint32_t u32; + struct cvmx_pcieep_cfg008_s { + uint32_t reserved_4_31:28; + uint32_t pf:1; + uint32_t typ:2; + uint32_t mspc:1; + } s; + struct cvmx_pcieep_cfg008_s cn52xx; + struct cvmx_pcieep_cfg008_s cn52xxp1; + struct cvmx_pcieep_cfg008_s cn56xx; + struct cvmx_pcieep_cfg008_s cn56xxp1; +}; + +union cvmx_pcieep_cfg008_mask { + uint32_t u32; + struct cvmx_pcieep_cfg008_mask_s { + uint32_t lmask:31; + uint32_t enb:1; + } s; + struct cvmx_pcieep_cfg008_mask_s cn52xx; + struct cvmx_pcieep_cfg008_mask_s cn52xxp1; + struct cvmx_pcieep_cfg008_mask_s cn56xx; + struct cvmx_pcieep_cfg008_mask_s cn56xxp1; +}; + +union cvmx_pcieep_cfg009 { + uint32_t u32; + struct cvmx_pcieep_cfg009_s { + uint32_t ubab:25; + uint32_t reserved_0_6:7; + } s; + struct cvmx_pcieep_cfg009_s cn52xx; + struct cvmx_pcieep_cfg009_s cn52xxp1; + struct cvmx_pcieep_cfg009_s cn56xx; + struct cvmx_pcieep_cfg009_s cn56xxp1; +}; + +union cvmx_pcieep_cfg009_mask { + uint32_t u32; + struct cvmx_pcieep_cfg009_mask_s { + uint32_t umask:32; + } s; + struct cvmx_pcieep_cfg009_mask_s cn52xx; + struct cvmx_pcieep_cfg009_mask_s cn52xxp1; + struct cvmx_pcieep_cfg009_mask_s cn56xx; + struct cvmx_pcieep_cfg009_mask_s cn56xxp1; +}; + +union cvmx_pcieep_cfg010 { + uint32_t u32; + struct cvmx_pcieep_cfg010_s { + uint32_t cisp:32; + } s; + struct cvmx_pcieep_cfg010_s cn52xx; + struct cvmx_pcieep_cfg010_s cn52xxp1; + struct cvmx_pcieep_cfg010_s cn56xx; + struct cvmx_pcieep_cfg010_s cn56xxp1; +}; + +union cvmx_pcieep_cfg011 { + uint32_t u32; + struct cvmx_pcieep_cfg011_s { + uint32_t ssid:16; + uint32_t ssvid:16; + } s; + struct cvmx_pcieep_cfg011_s cn52xx; + struct cvmx_pcieep_cfg011_s cn52xxp1; + struct cvmx_pcieep_cfg011_s cn56xx; + struct cvmx_pcieep_cfg011_s cn56xxp1; +}; + +union cvmx_pcieep_cfg012 { + uint32_t u32; + struct cvmx_pcieep_cfg012_s { + uint32_t eraddr:16; + uint32_t reserved_1_15:15; + uint32_t er_en:1; + } s; + struct cvmx_pcieep_cfg012_s cn52xx; + struct cvmx_pcieep_cfg012_s cn52xxp1; + struct cvmx_pcieep_cfg012_s cn56xx; + struct cvmx_pcieep_cfg012_s cn56xxp1; +}; + +union cvmx_pcieep_cfg012_mask { + uint32_t u32; + struct cvmx_pcieep_cfg012_mask_s { + uint32_t mask:31; + uint32_t enb:1; + } s; + struct cvmx_pcieep_cfg012_mask_s cn52xx; + struct cvmx_pcieep_cfg012_mask_s cn52xxp1; + struct cvmx_pcieep_cfg012_mask_s cn56xx; + struct cvmx_pcieep_cfg012_mask_s cn56xxp1; +}; + +union cvmx_pcieep_cfg013 { + uint32_t u32; + struct cvmx_pcieep_cfg013_s { + uint32_t reserved_8_31:24; + uint32_t cp:8; + } s; + struct cvmx_pcieep_cfg013_s cn52xx; + struct cvmx_pcieep_cfg013_s cn52xxp1; + struct cvmx_pcieep_cfg013_s cn56xx; + struct cvmx_pcieep_cfg013_s cn56xxp1; +}; + +union cvmx_pcieep_cfg015 { + uint32_t u32; + struct cvmx_pcieep_cfg015_s { + uint32_t ml:8; + uint32_t mg:8; + uint32_t inta:8; + uint32_t il:8; + } s; + struct cvmx_pcieep_cfg015_s cn52xx; + struct cvmx_pcieep_cfg015_s cn52xxp1; + struct cvmx_pcieep_cfg015_s cn56xx; + struct cvmx_pcieep_cfg015_s cn56xxp1; +}; + +union cvmx_pcieep_cfg016 { + uint32_t u32; + struct cvmx_pcieep_cfg016_s { + uint32_t pmes:5; + uint32_t d2s:1; + uint32_t d1s:1; + uint32_t auxc:3; + uint32_t dsi:1; + uint32_t reserved_20_20:1; + uint32_t pme_clock:1; + uint32_t pmsv:3; + uint32_t ncp:8; + uint32_t pmcid:8; + } s; + struct cvmx_pcieep_cfg016_s cn52xx; + struct cvmx_pcieep_cfg016_s cn52xxp1; + struct cvmx_pcieep_cfg016_s cn56xx; + struct cvmx_pcieep_cfg016_s cn56xxp1; +}; + +union cvmx_pcieep_cfg017 { + uint32_t u32; + struct cvmx_pcieep_cfg017_s { + uint32_t pmdia:8; + uint32_t bpccee:1; + uint32_t bd3h:1; + uint32_t reserved_16_21:6; + uint32_t pmess:1; + uint32_t pmedsia:2; + uint32_t pmds:4; + uint32_t pmeens:1; + uint32_t reserved_4_7:4; + uint32_t nsr:1; + uint32_t reserved_2_2:1; + uint32_t ps:2; + } s; + struct cvmx_pcieep_cfg017_s cn52xx; + struct cvmx_pcieep_cfg017_s cn52xxp1; + struct cvmx_pcieep_cfg017_s cn56xx; + struct cvmx_pcieep_cfg017_s cn56xxp1; +}; + +union cvmx_pcieep_cfg020 { + uint32_t u32; + struct cvmx_pcieep_cfg020_s { + uint32_t reserved_24_31:8; + uint32_t m64:1; + uint32_t mme:3; + uint32_t mmc:3; + uint32_t msien:1; + uint32_t ncp:8; + uint32_t msicid:8; + } s; + struct cvmx_pcieep_cfg020_s cn52xx; + struct cvmx_pcieep_cfg020_s cn52xxp1; + struct cvmx_pcieep_cfg020_s cn56xx; + struct cvmx_pcieep_cfg020_s cn56xxp1; +}; + +union cvmx_pcieep_cfg021 { + uint32_t u32; + struct cvmx_pcieep_cfg021_s { + uint32_t lmsi:30; + uint32_t reserved_0_1:2; + } s; + struct cvmx_pcieep_cfg021_s cn52xx; + struct cvmx_pcieep_cfg021_s cn52xxp1; + struct cvmx_pcieep_cfg021_s cn56xx; + struct cvmx_pcieep_cfg021_s cn56xxp1; +}; + +union cvmx_pcieep_cfg022 { + uint32_t u32; + struct cvmx_pcieep_cfg022_s { + uint32_t umsi:32; + } s; + struct cvmx_pcieep_cfg022_s cn52xx; + struct cvmx_pcieep_cfg022_s cn52xxp1; + struct cvmx_pcieep_cfg022_s cn56xx; + struct cvmx_pcieep_cfg022_s cn56xxp1; +}; + +union cvmx_pcieep_cfg023 { + uint32_t u32; + struct cvmx_pcieep_cfg023_s { + uint32_t reserved_16_31:16; + uint32_t msimd:16; + } s; + struct cvmx_pcieep_cfg023_s cn52xx; + struct cvmx_pcieep_cfg023_s cn52xxp1; + struct cvmx_pcieep_cfg023_s cn56xx; + struct cvmx_pcieep_cfg023_s cn56xxp1; +}; + +union cvmx_pcieep_cfg028 { + uint32_t u32; + struct cvmx_pcieep_cfg028_s { + uint32_t reserved_30_31:2; + uint32_t imn:5; + uint32_t si:1; + uint32_t dpt:4; + uint32_t pciecv:4; + uint32_t ncp:8; + uint32_t pcieid:8; + } s; + struct cvmx_pcieep_cfg028_s cn52xx; + struct cvmx_pcieep_cfg028_s cn52xxp1; + struct cvmx_pcieep_cfg028_s cn56xx; + struct cvmx_pcieep_cfg028_s cn56xxp1; +}; + +union cvmx_pcieep_cfg029 { + uint32_t u32; + struct cvmx_pcieep_cfg029_s { + uint32_t reserved_28_31:4; + uint32_t cspls:2; + uint32_t csplv:8; + uint32_t reserved_16_17:2; + uint32_t rber:1; + uint32_t reserved_12_14:3; + uint32_t el1al:3; + uint32_t el0al:3; + uint32_t etfs:1; + uint32_t pfs:2; + uint32_t mpss:3; + } s; + struct cvmx_pcieep_cfg029_s cn52xx; + struct cvmx_pcieep_cfg029_s cn52xxp1; + struct cvmx_pcieep_cfg029_s cn56xx; + struct cvmx_pcieep_cfg029_s cn56xxp1; +}; + +union cvmx_pcieep_cfg030 { + uint32_t u32; + struct cvmx_pcieep_cfg030_s { + uint32_t reserved_22_31:10; + uint32_t tp:1; + uint32_t ap_d:1; + uint32_t ur_d:1; + uint32_t fe_d:1; + uint32_t nfe_d:1; + uint32_t ce_d:1; + uint32_t reserved_15_15:1; + uint32_t mrrs:3; + uint32_t ns_en:1; + uint32_t ap_en:1; + uint32_t pf_en:1; + uint32_t etf_en:1; + uint32_t mps:3; + uint32_t ro_en:1; + uint32_t ur_en:1; + uint32_t fe_en:1; + uint32_t nfe_en:1; + uint32_t ce_en:1; + } s; + struct cvmx_pcieep_cfg030_s cn52xx; + struct cvmx_pcieep_cfg030_s cn52xxp1; + struct cvmx_pcieep_cfg030_s cn56xx; + struct cvmx_pcieep_cfg030_s cn56xxp1; +}; + +union cvmx_pcieep_cfg031 { + uint32_t u32; + struct cvmx_pcieep_cfg031_s { + uint32_t pnum:8; + uint32_t reserved_22_23:2; + uint32_t lbnc:1; + uint32_t dllarc:1; + uint32_t sderc:1; + uint32_t cpm:1; + uint32_t l1el:3; + uint32_t l0el:3; + uint32_t aslpms:2; + uint32_t mlw:6; + uint32_t mls:4; + } s; + struct cvmx_pcieep_cfg031_s cn52xx; + struct cvmx_pcieep_cfg031_s cn52xxp1; + struct cvmx_pcieep_cfg031_s cn56xx; + struct cvmx_pcieep_cfg031_s cn56xxp1; +}; + +union cvmx_pcieep_cfg032 { + uint32_t u32; + struct cvmx_pcieep_cfg032_s { + uint32_t reserved_30_31:2; + uint32_t dlla:1; + uint32_t scc:1; + uint32_t lt:1; + uint32_t reserved_26_26:1; + uint32_t nlw:6; + uint32_t ls:4; + uint32_t reserved_10_15:6; + uint32_t hawd:1; + uint32_t ecpm:1; + uint32_t es:1; + uint32_t ccc:1; + uint32_t rl:1; + uint32_t ld:1; + uint32_t rcb:1; + uint32_t reserved_2_2:1; + uint32_t aslpc:2; + } s; + struct cvmx_pcieep_cfg032_s cn52xx; + struct cvmx_pcieep_cfg032_s cn52xxp1; + struct cvmx_pcieep_cfg032_s cn56xx; + struct cvmx_pcieep_cfg032_s cn56xxp1; +}; + +union cvmx_pcieep_cfg033 { + uint32_t u32; + struct cvmx_pcieep_cfg033_s { + uint32_t ps_num:13; + uint32_t nccs:1; + uint32_t emip:1; + uint32_t sp_ls:2; + uint32_t sp_lv:8; + uint32_t hp_c:1; + uint32_t hp_s:1; + uint32_t pip:1; + uint32_t aip:1; + uint32_t mrlsp:1; + uint32_t pcp:1; + uint32_t abp:1; + } s; + struct cvmx_pcieep_cfg033_s cn52xx; + struct cvmx_pcieep_cfg033_s cn52xxp1; + struct cvmx_pcieep_cfg033_s cn56xx; + struct cvmx_pcieep_cfg033_s cn56xxp1; +}; + +union cvmx_pcieep_cfg034 { + uint32_t u32; + struct cvmx_pcieep_cfg034_s { + uint32_t reserved_25_31:7; + uint32_t dlls_c:1; + uint32_t emis:1; + uint32_t pds:1; + uint32_t mrlss:1; + uint32_t ccint_d:1; + uint32_t pd_c:1; + uint32_t mrls_c:1; + uint32_t pf_d:1; + uint32_t abp_d:1; + uint32_t reserved_13_15:3; + uint32_t dlls_en:1; + uint32_t emic:1; + uint32_t pcc:1; + uint32_t pic:2; + uint32_t aic:2; + uint32_t hpint_en:1; + uint32_t ccint_en:1; + uint32_t pd_en:1; + uint32_t mrls_en:1; + uint32_t pf_en:1; + uint32_t abp_en:1; + } s; + struct cvmx_pcieep_cfg034_s cn52xx; + struct cvmx_pcieep_cfg034_s cn52xxp1; + struct cvmx_pcieep_cfg034_s cn56xx; + struct cvmx_pcieep_cfg034_s cn56xxp1; +}; + +union cvmx_pcieep_cfg037 { + uint32_t u32; + struct cvmx_pcieep_cfg037_s { + uint32_t reserved_5_31:27; + uint32_t ctds:1; + uint32_t ctrs:4; + } s; + struct cvmx_pcieep_cfg037_s cn52xx; + struct cvmx_pcieep_cfg037_s cn52xxp1; + struct cvmx_pcieep_cfg037_s cn56xx; + struct cvmx_pcieep_cfg037_s cn56xxp1; +}; + +union cvmx_pcieep_cfg038 { + uint32_t u32; + struct cvmx_pcieep_cfg038_s { + uint32_t reserved_5_31:27; + uint32_t ctd:1; + uint32_t ctv:4; + } s; + struct cvmx_pcieep_cfg038_s cn52xx; + struct cvmx_pcieep_cfg038_s cn52xxp1; + struct cvmx_pcieep_cfg038_s cn56xx; + struct cvmx_pcieep_cfg038_s cn56xxp1; +}; + +union cvmx_pcieep_cfg039 { + uint32_t u32; + struct cvmx_pcieep_cfg039_s { + uint32_t reserved_0_31:32; + } s; + struct cvmx_pcieep_cfg039_s cn52xx; + struct cvmx_pcieep_cfg039_s cn52xxp1; + struct cvmx_pcieep_cfg039_s cn56xx; + struct cvmx_pcieep_cfg039_s cn56xxp1; +}; + +union cvmx_pcieep_cfg040 { + uint32_t u32; + struct cvmx_pcieep_cfg040_s { + uint32_t reserved_0_31:32; + } s; + struct cvmx_pcieep_cfg040_s cn52xx; + struct cvmx_pcieep_cfg040_s cn52xxp1; + struct cvmx_pcieep_cfg040_s cn56xx; + struct cvmx_pcieep_cfg040_s cn56xxp1; +}; + +union cvmx_pcieep_cfg041 { + uint32_t u32; + struct cvmx_pcieep_cfg041_s { + uint32_t reserved_0_31:32; + } s; + struct cvmx_pcieep_cfg041_s cn52xx; + struct cvmx_pcieep_cfg041_s cn52xxp1; + struct cvmx_pcieep_cfg041_s cn56xx; + struct cvmx_pcieep_cfg041_s cn56xxp1; +}; + +union cvmx_pcieep_cfg042 { + uint32_t u32; + struct cvmx_pcieep_cfg042_s { + uint32_t reserved_0_31:32; + } s; + struct cvmx_pcieep_cfg042_s cn52xx; + struct cvmx_pcieep_cfg042_s cn52xxp1; + struct cvmx_pcieep_cfg042_s cn56xx; + struct cvmx_pcieep_cfg042_s cn56xxp1; +}; + +union cvmx_pcieep_cfg064 { + uint32_t u32; + struct cvmx_pcieep_cfg064_s { + uint32_t nco:12; + uint32_t cv:4; + uint32_t pcieec:16; + } s; + struct cvmx_pcieep_cfg064_s cn52xx; + struct cvmx_pcieep_cfg064_s cn52xxp1; + struct cvmx_pcieep_cfg064_s cn56xx; + struct cvmx_pcieep_cfg064_s cn56xxp1; +}; + +union cvmx_pcieep_cfg065 { + uint32_t u32; + struct cvmx_pcieep_cfg065_s { + uint32_t reserved_21_31:11; + uint32_t ures:1; + uint32_t ecrces:1; + uint32_t mtlps:1; + uint32_t ros:1; + uint32_t ucs:1; + uint32_t cas:1; + uint32_t cts:1; + uint32_t fcpes:1; + uint32_t ptlps:1; + uint32_t reserved_6_11:6; + uint32_t sdes:1; + uint32_t dlpes:1; + uint32_t reserved_0_3:4; + } s; + struct cvmx_pcieep_cfg065_s cn52xx; + struct cvmx_pcieep_cfg065_s cn52xxp1; + struct cvmx_pcieep_cfg065_s cn56xx; + struct cvmx_pcieep_cfg065_s cn56xxp1; +}; + +union cvmx_pcieep_cfg066 { + uint32_t u32; + struct cvmx_pcieep_cfg066_s { + uint32_t reserved_21_31:11; + uint32_t urem:1; + uint32_t ecrcem:1; + uint32_t mtlpm:1; + uint32_t rom:1; + uint32_t ucm:1; + uint32_t cam:1; + uint32_t ctm:1; + uint32_t fcpem:1; + uint32_t ptlpm:1; + uint32_t reserved_6_11:6; + uint32_t sdem:1; + uint32_t dlpem:1; + uint32_t reserved_0_3:4; + } s; + struct cvmx_pcieep_cfg066_s cn52xx; + struct cvmx_pcieep_cfg066_s cn52xxp1; + struct cvmx_pcieep_cfg066_s cn56xx; + struct cvmx_pcieep_cfg066_s cn56xxp1; +}; + +union cvmx_pcieep_cfg067 { + uint32_t u32; + struct cvmx_pcieep_cfg067_s { + uint32_t reserved_21_31:11; + uint32_t ures:1; + uint32_t ecrces:1; + uint32_t mtlps:1; + uint32_t ros:1; + uint32_t ucs:1; + uint32_t cas:1; + uint32_t cts:1; + uint32_t fcpes:1; + uint32_t ptlps:1; + uint32_t reserved_6_11:6; + uint32_t sdes:1; + uint32_t dlpes:1; + uint32_t reserved_0_3:4; + } s; + struct cvmx_pcieep_cfg067_s cn52xx; + struct cvmx_pcieep_cfg067_s cn52xxp1; + struct cvmx_pcieep_cfg067_s cn56xx; + struct cvmx_pcieep_cfg067_s cn56xxp1; +}; + +union cvmx_pcieep_cfg068 { + uint32_t u32; + struct cvmx_pcieep_cfg068_s { + uint32_t reserved_14_31:18; + uint32_t anfes:1; + uint32_t rtts:1; + uint32_t reserved_9_11:3; + uint32_t rnrs:1; + uint32_t bdllps:1; + uint32_t btlps:1; + uint32_t reserved_1_5:5; + uint32_t res:1; + } s; + struct cvmx_pcieep_cfg068_s cn52xx; + struct cvmx_pcieep_cfg068_s cn52xxp1; + struct cvmx_pcieep_cfg068_s cn56xx; + struct cvmx_pcieep_cfg068_s cn56xxp1; +}; + +union cvmx_pcieep_cfg069 { + uint32_t u32; + struct cvmx_pcieep_cfg069_s { + uint32_t reserved_14_31:18; + uint32_t anfem:1; + uint32_t rttm:1; + uint32_t reserved_9_11:3; + uint32_t rnrm:1; + uint32_t bdllpm:1; + uint32_t btlpm:1; + uint32_t reserved_1_5:5; + uint32_t rem:1; + } s; + struct cvmx_pcieep_cfg069_s cn52xx; + struct cvmx_pcieep_cfg069_s cn52xxp1; + struct cvmx_pcieep_cfg069_s cn56xx; + struct cvmx_pcieep_cfg069_s cn56xxp1; +}; + +union cvmx_pcieep_cfg070 { + uint32_t u32; + struct cvmx_pcieep_cfg070_s { + uint32_t reserved_9_31:23; + uint32_t ce:1; + uint32_t cc:1; + uint32_t ge:1; + uint32_t gc:1; + uint32_t fep:5; + } s; + struct cvmx_pcieep_cfg070_s cn52xx; + struct cvmx_pcieep_cfg070_s cn52xxp1; + struct cvmx_pcieep_cfg070_s cn56xx; + struct cvmx_pcieep_cfg070_s cn56xxp1; +}; + +union cvmx_pcieep_cfg071 { + uint32_t u32; + struct cvmx_pcieep_cfg071_s { + uint32_t dword1:32; + } s; + struct cvmx_pcieep_cfg071_s cn52xx; + struct cvmx_pcieep_cfg071_s cn52xxp1; + struct cvmx_pcieep_cfg071_s cn56xx; + struct cvmx_pcieep_cfg071_s cn56xxp1; +}; + +union cvmx_pcieep_cfg072 { + uint32_t u32; + struct cvmx_pcieep_cfg072_s { + uint32_t dword2:32; + } s; + struct cvmx_pcieep_cfg072_s cn52xx; + struct cvmx_pcieep_cfg072_s cn52xxp1; + struct cvmx_pcieep_cfg072_s cn56xx; + struct cvmx_pcieep_cfg072_s cn56xxp1; +}; + +union cvmx_pcieep_cfg073 { + uint32_t u32; + struct cvmx_pcieep_cfg073_s { + uint32_t dword3:32; + } s; + struct cvmx_pcieep_cfg073_s cn52xx; + struct cvmx_pcieep_cfg073_s cn52xxp1; + struct cvmx_pcieep_cfg073_s cn56xx; + struct cvmx_pcieep_cfg073_s cn56xxp1; +}; + +union cvmx_pcieep_cfg074 { + uint32_t u32; + struct cvmx_pcieep_cfg074_s { + uint32_t dword4:32; + } s; + struct cvmx_pcieep_cfg074_s cn52xx; + struct cvmx_pcieep_cfg074_s cn52xxp1; + struct cvmx_pcieep_cfg074_s cn56xx; + struct cvmx_pcieep_cfg074_s cn56xxp1; +}; + +union cvmx_pcieep_cfg448 { + uint32_t u32; + struct cvmx_pcieep_cfg448_s { + uint32_t rtl:16; + uint32_t rtltl:16; + } s; + struct cvmx_pcieep_cfg448_s cn52xx; + struct cvmx_pcieep_cfg448_s cn52xxp1; + struct cvmx_pcieep_cfg448_s cn56xx; + struct cvmx_pcieep_cfg448_s cn56xxp1; +}; + +union cvmx_pcieep_cfg449 { + uint32_t u32; + struct cvmx_pcieep_cfg449_s { + uint32_t omr:32; + } s; + struct cvmx_pcieep_cfg449_s cn52xx; + struct cvmx_pcieep_cfg449_s cn52xxp1; + struct cvmx_pcieep_cfg449_s cn56xx; + struct cvmx_pcieep_cfg449_s cn56xxp1; +}; + +union cvmx_pcieep_cfg450 { + uint32_t u32; + struct cvmx_pcieep_cfg450_s { + uint32_t lpec:8; + uint32_t reserved_22_23:2; + uint32_t link_state:6; + uint32_t force_link:1; + uint32_t reserved_8_14:7; + uint32_t link_num:8; + } s; + struct cvmx_pcieep_cfg450_s cn52xx; + struct cvmx_pcieep_cfg450_s cn52xxp1; + struct cvmx_pcieep_cfg450_s cn56xx; + struct cvmx_pcieep_cfg450_s cn56xxp1; +}; + +union cvmx_pcieep_cfg451 { + uint32_t u32; + struct cvmx_pcieep_cfg451_s { + uint32_t reserved_30_31:2; + uint32_t l1el:3; + uint32_t l0el:3; + uint32_t n_fts_cc:8; + uint32_t n_fts:8; + uint32_t ack_freq:8; + } s; + struct cvmx_pcieep_cfg451_s cn52xx; + struct cvmx_pcieep_cfg451_s cn52xxp1; + struct cvmx_pcieep_cfg451_s cn56xx; + struct cvmx_pcieep_cfg451_s cn56xxp1; +}; + +union cvmx_pcieep_cfg452 { + uint32_t u32; + struct cvmx_pcieep_cfg452_s { + uint32_t reserved_26_31:6; + uint32_t eccrc:1; + uint32_t reserved_22_24:3; + uint32_t lme:6; + uint32_t reserved_8_15:8; + uint32_t flm:1; + uint32_t reserved_6_6:1; + uint32_t dllle:1; + uint32_t reserved_4_4:1; + uint32_t ra:1; + uint32_t le:1; + uint32_t sd:1; + uint32_t omr:1; + } s; + struct cvmx_pcieep_cfg452_s cn52xx; + struct cvmx_pcieep_cfg452_s cn52xxp1; + struct cvmx_pcieep_cfg452_s cn56xx; + struct cvmx_pcieep_cfg452_s cn56xxp1; +}; + +union cvmx_pcieep_cfg453 { + uint32_t u32; + struct cvmx_pcieep_cfg453_s { + uint32_t dlld:1; + uint32_t reserved_26_30:5; + uint32_t ack_nak:1; + uint32_t fcd:1; + uint32_t ilst:24; + } s; + struct cvmx_pcieep_cfg453_s cn52xx; + struct cvmx_pcieep_cfg453_s cn52xxp1; + struct cvmx_pcieep_cfg453_s cn56xx; + struct cvmx_pcieep_cfg453_s cn56xxp1; +}; + +union cvmx_pcieep_cfg454 { + uint32_t u32; + struct cvmx_pcieep_cfg454_s { + uint32_t reserved_29_31:3; + uint32_t tmfcwt:5; + uint32_t tmanlt:5; + uint32_t tmrt:5; + uint32_t reserved_11_13:3; + uint32_t nskps:3; + uint32_t reserved_4_7:4; + uint32_t ntss:4; + } s; + struct cvmx_pcieep_cfg454_s cn52xx; + struct cvmx_pcieep_cfg454_s cn52xxp1; + struct cvmx_pcieep_cfg454_s cn56xx; + struct cvmx_pcieep_cfg454_s cn56xxp1; +}; + +union cvmx_pcieep_cfg455 { + uint32_t u32; + struct cvmx_pcieep_cfg455_s { + uint32_t m_cfg0_filt:1; + uint32_t m_io_filt:1; + uint32_t msg_ctrl:1; + uint32_t m_cpl_ecrc_filt:1; + uint32_t m_ecrc_filt:1; + uint32_t m_cpl_len_err:1; + uint32_t m_cpl_attr_err:1; + uint32_t m_cpl_tc_err:1; + uint32_t m_cpl_fun_err:1; + uint32_t m_cpl_rid_err:1; + uint32_t m_cpl_tag_err:1; + uint32_t m_lk_filt:1; + uint32_t m_cfg1_filt:1; + uint32_t m_bar_match:1; + uint32_t m_pois_filt:1; + uint32_t m_fun:1; + uint32_t dfcwt:1; + uint32_t reserved_11_14:4; + uint32_t skpiv:11; + } s; + struct cvmx_pcieep_cfg455_s cn52xx; + struct cvmx_pcieep_cfg455_s cn52xxp1; + struct cvmx_pcieep_cfg455_s cn56xx; + struct cvmx_pcieep_cfg455_s cn56xxp1; +}; + +union cvmx_pcieep_cfg456 { + uint32_t u32; + struct cvmx_pcieep_cfg456_s { + uint32_t reserved_2_31:30; + uint32_t m_vend1_drp:1; + uint32_t m_vend0_drp:1; + } s; + struct cvmx_pcieep_cfg456_s cn52xx; + struct cvmx_pcieep_cfg456_s cn52xxp1; + struct cvmx_pcieep_cfg456_s cn56xx; + struct cvmx_pcieep_cfg456_s cn56xxp1; +}; + +union cvmx_pcieep_cfg458 { + uint32_t u32; + struct cvmx_pcieep_cfg458_s { + uint32_t dbg_info_l32:32; + } s; + struct cvmx_pcieep_cfg458_s cn52xx; + struct cvmx_pcieep_cfg458_s cn52xxp1; + struct cvmx_pcieep_cfg458_s cn56xx; + struct cvmx_pcieep_cfg458_s cn56xxp1; +}; + +union cvmx_pcieep_cfg459 { + uint32_t u32; + struct cvmx_pcieep_cfg459_s { + uint32_t dbg_info_u32:32; + } s; + struct cvmx_pcieep_cfg459_s cn52xx; + struct cvmx_pcieep_cfg459_s cn52xxp1; + struct cvmx_pcieep_cfg459_s cn56xx; + struct cvmx_pcieep_cfg459_s cn56xxp1; +}; + +union cvmx_pcieep_cfg460 { + uint32_t u32; + struct cvmx_pcieep_cfg460_s { + uint32_t reserved_20_31:12; + uint32_t tphfcc:8; + uint32_t tpdfcc:12; + } s; + struct cvmx_pcieep_cfg460_s cn52xx; + struct cvmx_pcieep_cfg460_s cn52xxp1; + struct cvmx_pcieep_cfg460_s cn56xx; + struct cvmx_pcieep_cfg460_s cn56xxp1; +}; + +union cvmx_pcieep_cfg461 { + uint32_t u32; + struct cvmx_pcieep_cfg461_s { + uint32_t reserved_20_31:12; + uint32_t tchfcc:8; + uint32_t tcdfcc:12; + } s; + struct cvmx_pcieep_cfg461_s cn52xx; + struct cvmx_pcieep_cfg461_s cn52xxp1; + struct cvmx_pcieep_cfg461_s cn56xx; + struct cvmx_pcieep_cfg461_s cn56xxp1; +}; + +union cvmx_pcieep_cfg462 { + uint32_t u32; + struct cvmx_pcieep_cfg462_s { + uint32_t reserved_20_31:12; + uint32_t tchfcc:8; + uint32_t tcdfcc:12; + } s; + struct cvmx_pcieep_cfg462_s cn52xx; + struct cvmx_pcieep_cfg462_s cn52xxp1; + struct cvmx_pcieep_cfg462_s cn56xx; + struct cvmx_pcieep_cfg462_s cn56xxp1; +}; + +union cvmx_pcieep_cfg463 { + uint32_t u32; + struct cvmx_pcieep_cfg463_s { + uint32_t reserved_3_31:29; + uint32_t rqne:1; + uint32_t trbne:1; + uint32_t rtlpfccnr:1; + } s; + struct cvmx_pcieep_cfg463_s cn52xx; + struct cvmx_pcieep_cfg463_s cn52xxp1; + struct cvmx_pcieep_cfg463_s cn56xx; + struct cvmx_pcieep_cfg463_s cn56xxp1; +}; + +union cvmx_pcieep_cfg464 { + uint32_t u32; + struct cvmx_pcieep_cfg464_s { + uint32_t wrr_vc3:8; + uint32_t wrr_vc2:8; + uint32_t wrr_vc1:8; + uint32_t wrr_vc0:8; + } s; + struct cvmx_pcieep_cfg464_s cn52xx; + struct cvmx_pcieep_cfg464_s cn52xxp1; + struct cvmx_pcieep_cfg464_s cn56xx; + struct cvmx_pcieep_cfg464_s cn56xxp1; +}; + +union cvmx_pcieep_cfg465 { + uint32_t u32; + struct cvmx_pcieep_cfg465_s { + uint32_t wrr_vc7:8; + uint32_t wrr_vc6:8; + uint32_t wrr_vc5:8; + uint32_t wrr_vc4:8; + } s; + struct cvmx_pcieep_cfg465_s cn52xx; + struct cvmx_pcieep_cfg465_s cn52xxp1; + struct cvmx_pcieep_cfg465_s cn56xx; + struct cvmx_pcieep_cfg465_s cn56xxp1; +}; + +union cvmx_pcieep_cfg466 { + uint32_t u32; + struct cvmx_pcieep_cfg466_s { + uint32_t rx_queue_order:1; + uint32_t type_ordering:1; + uint32_t reserved_24_29:6; + uint32_t queue_mode:3; + uint32_t reserved_20_20:1; + uint32_t header_credits:8; + uint32_t data_credits:12; + } s; + struct cvmx_pcieep_cfg466_s cn52xx; + struct cvmx_pcieep_cfg466_s cn52xxp1; + struct cvmx_pcieep_cfg466_s cn56xx; + struct cvmx_pcieep_cfg466_s cn56xxp1; +}; + +union cvmx_pcieep_cfg467 { + uint32_t u32; + struct cvmx_pcieep_cfg467_s { + uint32_t reserved_24_31:8; + uint32_t queue_mode:3; + uint32_t reserved_20_20:1; + uint32_t header_credits:8; + uint32_t data_credits:12; + } s; + struct cvmx_pcieep_cfg467_s cn52xx; + struct cvmx_pcieep_cfg467_s cn52xxp1; + struct cvmx_pcieep_cfg467_s cn56xx; + struct cvmx_pcieep_cfg467_s cn56xxp1; +}; + +union cvmx_pcieep_cfg468 { + uint32_t u32; + struct cvmx_pcieep_cfg468_s { + uint32_t reserved_24_31:8; + uint32_t queue_mode:3; + uint32_t reserved_20_20:1; + uint32_t header_credits:8; + uint32_t data_credits:12; + } s; + struct cvmx_pcieep_cfg468_s cn52xx; + struct cvmx_pcieep_cfg468_s cn52xxp1; + struct cvmx_pcieep_cfg468_s cn56xx; + struct cvmx_pcieep_cfg468_s cn56xxp1; +}; + +union cvmx_pcieep_cfg490 { + uint32_t u32; + struct cvmx_pcieep_cfg490_s { + uint32_t reserved_26_31:6; + uint32_t header_depth:10; + uint32_t reserved_14_15:2; + uint32_t data_depth:14; + } s; + struct cvmx_pcieep_cfg490_s cn52xx; + struct cvmx_pcieep_cfg490_s cn52xxp1; + struct cvmx_pcieep_cfg490_s cn56xx; + struct cvmx_pcieep_cfg490_s cn56xxp1; +}; + +union cvmx_pcieep_cfg491 { + uint32_t u32; + struct cvmx_pcieep_cfg491_s { + uint32_t reserved_26_31:6; + uint32_t header_depth:10; + uint32_t reserved_14_15:2; + uint32_t data_depth:14; + } s; + struct cvmx_pcieep_cfg491_s cn52xx; + struct cvmx_pcieep_cfg491_s cn52xxp1; + struct cvmx_pcieep_cfg491_s cn56xx; + struct cvmx_pcieep_cfg491_s cn56xxp1; +}; + +union cvmx_pcieep_cfg492 { + uint32_t u32; + struct cvmx_pcieep_cfg492_s { + uint32_t reserved_26_31:6; + uint32_t header_depth:10; + uint32_t reserved_14_15:2; + uint32_t data_depth:14; + } s; + struct cvmx_pcieep_cfg492_s cn52xx; + struct cvmx_pcieep_cfg492_s cn52xxp1; + struct cvmx_pcieep_cfg492_s cn56xx; + struct cvmx_pcieep_cfg492_s cn56xxp1; +}; + +union cvmx_pcieep_cfg516 { + uint32_t u32; + struct cvmx_pcieep_cfg516_s { + uint32_t phy_stat:32; + } s; + struct cvmx_pcieep_cfg516_s cn52xx; + struct cvmx_pcieep_cfg516_s cn52xxp1; + struct cvmx_pcieep_cfg516_s cn56xx; + struct cvmx_pcieep_cfg516_s cn56xxp1; +}; + +union cvmx_pcieep_cfg517 { + uint32_t u32; + struct cvmx_pcieep_cfg517_s { + uint32_t phy_ctrl:32; + } s; + struct cvmx_pcieep_cfg517_s cn52xx; + struct cvmx_pcieep_cfg517_s cn52xxp1; + struct cvmx_pcieep_cfg517_s cn56xx; + struct cvmx_pcieep_cfg517_s cn56xxp1; +}; + +#endif diff --git a/trunk/arch/mips/include/asm/pci.h b/trunk/arch/mips/include/asm/pci.h index 90bf3b3fce19..fcd4060f6421 100644 --- a/trunk/arch/mips/include/asm/pci.h +++ b/trunk/arch/mips/include/asm/pci.h @@ -17,7 +17,6 @@ */ #include -#include /* * Each pci channel is a top-level PCI bus seem by CPU. A machine with @@ -27,7 +26,6 @@ struct pci_controller { struct pci_controller *next; struct pci_bus *bus; - struct device_node *of_node; struct pci_ops *pci_ops; struct resource *mem_resource; @@ -144,8 +142,4 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) extern char * (*pcibios_plat_setup)(char *str); -/* this function parses memory ranges from a device node */ -extern void __devinit pci_load_of_ranges(struct pci_controller *hose, - struct device_node *node); - #endif /* _ASM_PCI_H */ diff --git a/trunk/arch/mips/include/asm/posix_types.h b/trunk/arch/mips/include/asm/posix_types.h index fa03ec3fbf89..e0308dcca135 100644 --- a/trunk/arch/mips/include/asm/posix_types.h +++ b/trunk/arch/mips/include/asm/posix_types.h @@ -17,6 +17,11 @@ * assume GCC is being used. */ +#if (_MIPS_SZLONG == 64) +typedef unsigned int __kernel_nlink_t; +#define __kernel_nlink_t __kernel_nlink_t +#endif + typedef long __kernel_daddr_t; #define __kernel_daddr_t __kernel_daddr_t diff --git a/trunk/arch/mips/include/asm/prom.h b/trunk/arch/mips/include/asm/prom.h index 7206d445bab8..7a6e82ef449b 100644 --- a/trunk/arch/mips/include/asm/prom.h +++ b/trunk/arch/mips/include/asm/prom.h @@ -12,9 +12,6 @@ #define __ASM_PROM_H #ifdef CONFIG_OF -#include -#include -#include #include extern int early_init_dt_scan_memory_arch(unsigned long node, @@ -24,29 +21,6 @@ extern int reserve_mem_mach(unsigned long addr, unsigned long size); extern void free_mem_mach(unsigned long addr, unsigned long size); extern void device_tree_init(void); - -static inline unsigned long pci_address_to_pio(phys_addr_t address) -{ - /* - * The ioport address can be directly used by inX() / outX() - */ - BUG_ON(address > IO_SPACE_LIMIT); - - return (unsigned long) address; -} -#define pci_address_to_pio pci_address_to_pio - -struct boot_param_header; - -extern void __dt_setup_arch(struct boot_param_header *bph); - -#define dt_setup_arch(sym) \ -({ \ - extern struct boot_param_header __dtb_##sym##_begin; \ - \ - __dt_setup_arch(&__dtb_##sym##_begin); \ -}) - #else /* CONFIG_OF */ static inline void device_tree_init(void) { } #endif /* CONFIG_OF */ diff --git a/trunk/arch/mips/include/asm/setup.h b/trunk/arch/mips/include/asm/setup.h index 2560b6b6a7d8..6dce6d8d09ab 100644 --- a/trunk/arch/mips/include/asm/setup.h +++ b/trunk/arch/mips/include/asm/setup.h @@ -14,8 +14,7 @@ extern void *set_vi_handler(int n, vi_handler_t addr); extern void *set_except_vector(int n, void *addr); extern unsigned long ebase; -extern void per_cpu_trap_init(bool); -extern void cpu_cache_init(void); +extern void per_cpu_trap_init(void); #endif /* __KERNEL__ */ diff --git a/trunk/arch/mips/include/asm/sparsemem.h b/trunk/arch/mips/include/asm/sparsemem.h index 4461198361c9..7165333ad043 100644 --- a/trunk/arch/mips/include/asm/sparsemem.h +++ b/trunk/arch/mips/include/asm/sparsemem.h @@ -6,11 +6,7 @@ * SECTION_SIZE_BITS 2^N: how big each section will be * MAX_PHYSMEM_BITS 2^N: how much memory we can have in that space */ -#if defined(CONFIG_HUGETLB_PAGE) && defined(CONFIG_PAGE_SIZE_64KB) -# define SECTION_SIZE_BITS 29 -#else -# define SECTION_SIZE_BITS 28 -#endif +#define SECTION_SIZE_BITS 28 #define MAX_PHYSMEM_BITS 35 #endif /* CONFIG_SPARSEMEM */ diff --git a/trunk/arch/mips/include/asm/stat.h b/trunk/arch/mips/include/asm/stat.h index fe9a4c3ec5a1..6e00f751ab6d 100644 --- a/trunk/arch/mips/include/asm/stat.h +++ b/trunk/arch/mips/include/asm/stat.h @@ -20,7 +20,7 @@ struct stat { long st_pad1[3]; /* Reserved for network id */ ino_t st_ino; mode_t st_mode; - __u32 st_nlink; + nlink_t st_nlink; uid_t st_uid; gid_t st_gid; unsigned st_rdev; @@ -55,7 +55,7 @@ struct stat64 { unsigned long long st_ino; mode_t st_mode; - __u32 st_nlink; + nlink_t st_nlink; uid_t st_uid; gid_t st_gid; @@ -96,7 +96,7 @@ struct stat { unsigned long st_ino; mode_t st_mode; - __u32 st_nlink; + nlink_t st_nlink; uid_t st_uid; gid_t st_gid; diff --git a/trunk/arch/mips/include/asm/termios.h b/trunk/arch/mips/include/asm/termios.h index abdd87aaf609..8f77f774a2a0 100644 --- a/trunk/arch/mips/include/asm/termios.h +++ b/trunk/arch/mips/include/asm/termios.h @@ -60,7 +60,7 @@ struct termio { }; #ifdef __KERNEL__ -#include +#include /* * intr=^C quit=^\ erase=del kill=^U diff --git a/trunk/arch/mips/include/asm/traps.h b/trunk/arch/mips/include/asm/traps.h index 420ca06b2f42..ff74aec3561a 100644 --- a/trunk/arch/mips/include/asm/traps.h +++ b/trunk/arch/mips/include/asm/traps.h @@ -25,7 +25,6 @@ extern void (*board_nmi_handler_setup)(void); extern void (*board_ejtag_handler_setup)(void); extern void (*board_bind_eic_interrupt)(int irq, int regset); extern void (*board_ebase_setup)(void); -extern void (*board_cache_error_setup)(void); extern int register_nmi_notifier(struct notifier_block *nb); diff --git a/trunk/arch/mips/include/asm/uasm.h b/trunk/arch/mips/include/asm/uasm.h index 440a21dab575..504d40aedfae 100644 --- a/trunk/arch/mips/include/asm/uasm.h +++ b/trunk/arch/mips/include/asm/uasm.h @@ -11,7 +11,7 @@ #include #ifdef CONFIG_EXPORT_UASM -#include +#include #define __uasminit #define __uasminitdata #define UASM_EXPORT_SYMBOL(sym) EXPORT_SYMBOL(sym) diff --git a/trunk/arch/mips/jz4740/Makefile b/trunk/arch/mips/jz4740/Makefile index e44abea9c209..a9dff3321251 100644 --- a/trunk/arch/mips/jz4740/Makefile +++ b/trunk/arch/mips/jz4740/Makefile @@ -16,3 +16,5 @@ obj-$(CONFIG_JZ4740_QI_LB60) += board-qi_lb60.o # PM support obj-$(CONFIG_PM) += pm.o + +ccflags-y := -Werror -Wall diff --git a/trunk/arch/mips/kernel/cpu-probe.c b/trunk/arch/mips/kernel/cpu-probe.c index 6ae7ce4ac63e..5099201fb7bc 100644 --- a/trunk/arch/mips/kernel/cpu-probe.c +++ b/trunk/arch/mips/kernel/cpu-probe.c @@ -340,7 +340,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) __cpu_name[cpu] = "R2000"; c->isa_level = MIPS_CPU_ISA_I; c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE | - MIPS_CPU_NOFPUEX; + MIPS_CPU_NOFPUEX; if (__cpu_has_fpu()) c->options |= MIPS_CPU_FPU; c->tlbsize = 64; @@ -361,7 +361,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) } c->isa_level = MIPS_CPU_ISA_I; c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE | - MIPS_CPU_NOFPUEX; + MIPS_CPU_NOFPUEX; if (__cpu_has_fpu()) c->options |= MIPS_CPU_FPU; c->tlbsize = 64; @@ -387,8 +387,8 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) c->isa_level = MIPS_CPU_ISA_III; c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | - MIPS_CPU_WATCH | MIPS_CPU_VCE | - MIPS_CPU_LLSC; + MIPS_CPU_WATCH | MIPS_CPU_VCE | + MIPS_CPU_LLSC; c->tlbsize = 48; break; case PRID_IMP_VR41XX: @@ -434,7 +434,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) __cpu_name[cpu] = "R4300"; c->isa_level = MIPS_CPU_ISA_III; c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | - MIPS_CPU_LLSC; + MIPS_CPU_LLSC; c->tlbsize = 32; break; case PRID_IMP_R4600: @@ -446,7 +446,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) c->tlbsize = 48; break; #if 0 - case PRID_IMP_R4650: + case PRID_IMP_R4650: /* * This processor doesn't have an MMU, so it's not * "real easy" to run Linux on it. It is left purely @@ -455,9 +455,9 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) */ c->cputype = CPU_R4650; __cpu_name[cpu] = "R4650"; - c->isa_level = MIPS_CPU_ISA_III; + c->isa_level = MIPS_CPU_ISA_III; c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_LLSC; - c->tlbsize = 48; + c->tlbsize = 48; break; #endif case PRID_IMP_TX39: @@ -488,7 +488,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) __cpu_name[cpu] = "R4700"; c->isa_level = MIPS_CPU_ISA_III; c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | - MIPS_CPU_LLSC; + MIPS_CPU_LLSC; c->tlbsize = 48; break; case PRID_IMP_TX49: @@ -505,7 +505,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) __cpu_name[cpu] = "R5000"; c->isa_level = MIPS_CPU_ISA_IV; c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | - MIPS_CPU_LLSC; + MIPS_CPU_LLSC; c->tlbsize = 48; break; case PRID_IMP_R5432: @@ -513,7 +513,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) __cpu_name[cpu] = "R5432"; c->isa_level = MIPS_CPU_ISA_IV; c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | - MIPS_CPU_WATCH | MIPS_CPU_LLSC; + MIPS_CPU_WATCH | MIPS_CPU_LLSC; c->tlbsize = 48; break; case PRID_IMP_R5500: @@ -521,7 +521,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) __cpu_name[cpu] = "R5500"; c->isa_level = MIPS_CPU_ISA_IV; c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | - MIPS_CPU_WATCH | MIPS_CPU_LLSC; + MIPS_CPU_WATCH | MIPS_CPU_LLSC; c->tlbsize = 48; break; case PRID_IMP_NEVADA: @@ -529,7 +529,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) __cpu_name[cpu] = "Nevada"; c->isa_level = MIPS_CPU_ISA_IV; c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | - MIPS_CPU_DIVEC | MIPS_CPU_LLSC; + MIPS_CPU_DIVEC | MIPS_CPU_LLSC; c->tlbsize = 48; break; case PRID_IMP_R6000: @@ -537,7 +537,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) __cpu_name[cpu] = "R6000"; c->isa_level = MIPS_CPU_ISA_II; c->options = MIPS_CPU_TLB | MIPS_CPU_FPU | - MIPS_CPU_LLSC; + MIPS_CPU_LLSC; c->tlbsize = 32; break; case PRID_IMP_R6000A: @@ -545,7 +545,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) __cpu_name[cpu] = "R6000A"; c->isa_level = MIPS_CPU_ISA_II; c->options = MIPS_CPU_TLB | MIPS_CPU_FPU | - MIPS_CPU_LLSC; + MIPS_CPU_LLSC; c->tlbsize = 32; break; case PRID_IMP_RM7000: @@ -553,7 +553,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) __cpu_name[cpu] = "RM7000"; c->isa_level = MIPS_CPU_ISA_IV; c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | - MIPS_CPU_LLSC; + MIPS_CPU_LLSC; /* * Undocumented RM7000: Bit 29 in the info register of * the RM7000 v2.0 indicates if the TLB has 48 or 64 @@ -569,7 +569,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) __cpu_name[cpu] = "RM9000"; c->isa_level = MIPS_CPU_ISA_IV; c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | - MIPS_CPU_LLSC; + MIPS_CPU_LLSC; /* * Bit 29 in the info register of the RM9000 * indicates if the TLB has 48 or 64 entries. @@ -584,8 +584,8 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) __cpu_name[cpu] = "RM8000"; c->isa_level = MIPS_CPU_ISA_IV; c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX | - MIPS_CPU_FPU | MIPS_CPU_32FPR | - MIPS_CPU_LLSC; + MIPS_CPU_FPU | MIPS_CPU_32FPR | + MIPS_CPU_LLSC; c->tlbsize = 384; /* has weird TLB: 3-way x 128 */ break; case PRID_IMP_R10000: @@ -593,9 +593,9 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) __cpu_name[cpu] = "R10000"; c->isa_level = MIPS_CPU_ISA_IV; c->options = MIPS_CPU_TLB | MIPS_CPU_4K_CACHE | MIPS_CPU_4KEX | - MIPS_CPU_FPU | MIPS_CPU_32FPR | + MIPS_CPU_FPU | MIPS_CPU_32FPR | MIPS_CPU_COUNTER | MIPS_CPU_WATCH | - MIPS_CPU_LLSC; + MIPS_CPU_LLSC; c->tlbsize = 64; break; case PRID_IMP_R12000: @@ -603,9 +603,9 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) __cpu_name[cpu] = "R12000"; c->isa_level = MIPS_CPU_ISA_IV; c->options = MIPS_CPU_TLB | MIPS_CPU_4K_CACHE | MIPS_CPU_4KEX | - MIPS_CPU_FPU | MIPS_CPU_32FPR | + MIPS_CPU_FPU | MIPS_CPU_32FPR | MIPS_CPU_COUNTER | MIPS_CPU_WATCH | - MIPS_CPU_LLSC; + MIPS_CPU_LLSC; c->tlbsize = 64; break; case PRID_IMP_R14000: @@ -613,9 +613,9 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) __cpu_name[cpu] = "R14000"; c->isa_level = MIPS_CPU_ISA_IV; c->options = MIPS_CPU_TLB | MIPS_CPU_4K_CACHE | MIPS_CPU_4KEX | - MIPS_CPU_FPU | MIPS_CPU_32FPR | + MIPS_CPU_FPU | MIPS_CPU_32FPR | MIPS_CPU_COUNTER | MIPS_CPU_WATCH | - MIPS_CPU_LLSC; + MIPS_CPU_LLSC; c->tlbsize = 64; break; case PRID_IMP_LOONGSON2: @@ -739,7 +739,7 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c) if (config3 & MIPS_CONF3_VEIC) c->options |= MIPS_CPU_VEIC; if (config3 & MIPS_CONF3_MT) - c->ases |= MIPS_ASE_MIPSMT; + c->ases |= MIPS_ASE_MIPSMT; if (config3 & MIPS_CONF3_ULRI) c->options |= MIPS_CPU_ULRI; @@ -767,7 +767,7 @@ static void __cpuinit decode_configs(struct cpuinfo_mips *c) /* MIPS32 or MIPS64 compliant CPU. */ c->options = MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER | - MIPS_CPU_DIVEC | MIPS_CPU_LLSC | MIPS_CPU_MCHECK; + MIPS_CPU_DIVEC | MIPS_CPU_LLSC | MIPS_CPU_MCHECK; c->scache.flags = MIPS_CACHE_NOT_PRESENT; diff --git a/trunk/arch/mips/kernel/perf_event_mipsxx.c b/trunk/arch/mips/kernel/perf_event_mipsxx.c index f29099b104c4..ab73fa2fb9b5 100644 --- a/trunk/arch/mips/kernel/perf_event_mipsxx.c +++ b/trunk/arch/mips/kernel/perf_event_mipsxx.c @@ -1532,8 +1532,7 @@ init_hw_perf_events(void) irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR; } else { #endif - if ((cp0_perfcount_irq >= 0) && - (cp0_compare_irq != cp0_perfcount_irq)) + if (cp0_perfcount_irq >= 0) irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; else irq = -1; diff --git a/trunk/arch/mips/kernel/proc.c b/trunk/arch/mips/kernel/proc.c index 5542817c1b49..f8b2c592514d 100644 --- a/trunk/arch/mips/kernel/proc.c +++ b/trunk/arch/mips/kernel/proc.c @@ -41,27 +41,27 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "processor\t\t: %ld\n", n); sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n", - cpu_data[n].options & MIPS_CPU_FPU ? " FPU V%d.%d" : ""); + cpu_data[n].options & MIPS_CPU_FPU ? " FPU V%d.%d" : ""); seq_printf(m, fmt, __cpu_name[n], - (version >> 4) & 0x0f, version & 0x0f, - (fp_vers >> 4) & 0x0f, fp_vers & 0x0f); + (version >> 4) & 0x0f, version & 0x0f, + (fp_vers >> 4) & 0x0f, fp_vers & 0x0f); seq_printf(m, "BogoMIPS\t\t: %u.%02u\n", - cpu_data[n].udelay_val / (500000/HZ), - (cpu_data[n].udelay_val / (5000/HZ)) % 100); + cpu_data[n].udelay_val / (500000/HZ), + (cpu_data[n].udelay_val / (5000/HZ)) % 100); seq_printf(m, "wait instruction\t: %s\n", cpu_wait ? "yes" : "no"); seq_printf(m, "microsecond timers\t: %s\n", - cpu_has_counter ? "yes" : "no"); + cpu_has_counter ? "yes" : "no"); seq_printf(m, "tlb_entries\t\t: %d\n", cpu_data[n].tlbsize); seq_printf(m, "extra interrupt vector\t: %s\n", - cpu_has_divec ? "yes" : "no"); + cpu_has_divec ? "yes" : "no"); seq_printf(m, "hardware watchpoint\t: %s", - cpu_has_watch ? "yes, " : "no\n"); + cpu_has_watch ? "yes, " : "no\n"); if (cpu_has_watch) { seq_printf(m, "count: %d, address/irw mask: [", - cpu_data[n].watch_reg_count); + cpu_data[n].watch_reg_count); for (i = 0; i < cpu_data[n].watch_reg_count; i++) seq_printf(m, "%s0x%04x", i ? ", " : "" , - cpu_data[n].watch_reg_masks[i]); + cpu_data[n].watch_reg_masks[i]); seq_printf(m, "]\n"); } seq_printf(m, "ASEs implemented\t:%s%s%s%s%s%s\n", @@ -73,13 +73,13 @@ static int show_cpuinfo(struct seq_file *m, void *v) cpu_has_mipsmt ? " mt" : "" ); seq_printf(m, "shadow register sets\t: %d\n", - cpu_data[n].srsets); + cpu_data[n].srsets); seq_printf(m, "kscratch registers\t: %d\n", - hweight8(cpu_data[n].kscratch_mask)); + hweight8(cpu_data[n].kscratch_mask)); seq_printf(m, "core\t\t\t: %d\n", cpu_data[n].core); sprintf(fmt, "VCE%%c exceptions\t\t: %s\n", - cpu_has_vce ? "%u" : "not available"); + cpu_has_vce ? "%u" : "not available"); seq_printf(m, fmt, 'D', vced_count); seq_printf(m, fmt, 'I', vcei_count); seq_printf(m, "\n"); diff --git a/trunk/arch/mips/kernel/prom.c b/trunk/arch/mips/kernel/prom.c index f11b2bbb826d..558b5395795d 100644 --- a/trunk/arch/mips/kernel/prom.c +++ b/trunk/arch/mips/kernel/prom.c @@ -95,16 +95,3 @@ void __init device_tree_init(void) /* free the space reserved for the dt blob */ free_mem_mach(base, size); } - -void __init __dt_setup_arch(struct boot_param_header *bph) -{ - if (be32_to_cpu(bph->magic) != OF_DT_HEADER) { - pr_err("DTB has bad magic, ignoring builtin OF DTB\n"); - - return; - } - - initial_boot_params = bph; - - early_init_devtree(initial_boot_params); -} diff --git a/trunk/arch/mips/kernel/setup.c b/trunk/arch/mips/kernel/setup.c index a53f8ec37aac..c504b212f8f3 100644 --- a/trunk/arch/mips/kernel/setup.c +++ b/trunk/arch/mips/kernel/setup.c @@ -605,8 +605,6 @@ void __init setup_arch(char **cmdline_p) resource_init(); plat_smp_setup(); - - cpu_cache_init(); } unsigned long kernelsp[NR_CPUS]; diff --git a/trunk/arch/mips/kernel/signal-common.h b/trunk/arch/mips/kernel/signal-common.h index 9c60d09e62a7..10263b405981 100644 --- a/trunk/arch/mips/kernel/signal-common.h +++ b/trunk/arch/mips/kernel/signal-common.h @@ -19,6 +19,8 @@ # define DEBUGP(fmt, args...) #endif +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + /* * Determine which stack to use.. */ diff --git a/trunk/arch/mips/kernel/signal.c b/trunk/arch/mips/kernel/signal.c index f2c09cfc60ac..17f6ee30ad0d 100644 --- a/trunk/arch/mips/kernel/signal.c +++ b/trunk/arch/mips/kernel/signal.c @@ -339,6 +339,7 @@ asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs) if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked))) goto badframe; + sigdelsetmask(&blocked, ~_BLOCKABLE); set_current_blocked(&blocked); sig = restore_sigcontext(®s, &frame->sf_sc); @@ -374,6 +375,7 @@ asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); sig = restore_sigcontext(®s, &frame->rs_uc.uc_mcontext); @@ -512,10 +514,9 @@ struct mips_abi mips_abi = { .restart = __NR_restart_syscall }; -static void handle_signal(unsigned long sig, siginfo_t *info, - struct k_sigaction *ka, struct pt_regs *regs) +static int handle_signal(unsigned long sig, siginfo_t *info, + struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs) { - sigset_t *oldset = sigmask_to_save(); int ret; struct mips_abi *abi = current->thread.abi; void *vdso = current->mm->context.vdso; @@ -549,14 +550,17 @@ static void handle_signal(unsigned long sig, siginfo_t *info, ka, regs, sig, oldset); if (ret) - return; + return ret; + + block_sigmask(ka, sig); - signal_delivered(sig, info, ka, regs, 0); + return ret; } static void do_signal(struct pt_regs *regs) { struct k_sigaction ka; + sigset_t *oldset; siginfo_t info; int signr; @@ -568,10 +572,25 @@ static void do_signal(struct pt_regs *regs) if (!user_mode(regs)) return; + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { /* Whee! Actually deliver the signal. */ - handle_signal(signr, &info, &ka, regs); + if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { + /* + * A signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TIF_RESTORE_SIGMASK flag. + */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + } + return; } @@ -595,7 +614,10 @@ static void do_signal(struct pt_regs *regs) * If there's no signal to deliver, we just put the saved sigmask * back */ - restore_saved_sigmask(); + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } } /* @@ -608,12 +630,14 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, local_irq_enable(); /* deal with pending signal delivery */ - if (thread_info_flags & _TIF_SIGPENDING) + if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) do_signal(regs); if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/trunk/arch/mips/kernel/signal32.c b/trunk/arch/mips/kernel/signal32.c index da1b56a39ac7..b4fe2eacbd5d 100644 --- a/trunk/arch/mips/kernel/signal32.c +++ b/trunk/arch/mips/kernel/signal32.c @@ -465,6 +465,7 @@ asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs) if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask)) goto badframe; + sigdelsetmask(&blocked, ~_BLOCKABLE); set_current_blocked(&blocked); sig = restore_sigcontext32(®s, &frame->sf_sc); @@ -502,6 +503,7 @@ asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask)) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); sig = restore_sigcontext32(®s, &frame->rs_uc.uc_mcontext); diff --git a/trunk/arch/mips/kernel/signal_n32.c b/trunk/arch/mips/kernel/signal_n32.c index 3574c145511b..63ffac9af7c5 100644 --- a/trunk/arch/mips/kernel/signal_n32.c +++ b/trunk/arch/mips/kernel/signal_n32.c @@ -109,6 +109,7 @@ asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask)) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); sig = restore_sigcontext(®s, &frame->rs_uc.uc_mcontext); diff --git a/trunk/arch/mips/kernel/smp.c b/trunk/arch/mips/kernel/smp.c index 48650c818040..71a95f55a649 100644 --- a/trunk/arch/mips/kernel/smp.c +++ b/trunk/arch/mips/kernel/smp.c @@ -106,7 +106,7 @@ asmlinkage __cpuinit void start_secondary(void) #endif /* CONFIG_MIPS_MT_SMTC */ cpu_probe(); cpu_report(); - per_cpu_trap_init(false); + per_cpu_trap_init(); mips_clockevent_init(); mp_ops->init_secondary(); diff --git a/trunk/arch/mips/kernel/traps.c b/trunk/arch/mips/kernel/traps.c index 2d0c2a277f52..cfdaaa4cffc0 100644 --- a/trunk/arch/mips/kernel/traps.c +++ b/trunk/arch/mips/kernel/traps.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -92,7 +91,7 @@ void (*board_nmi_handler_setup)(void); void (*board_ejtag_handler_setup)(void); void (*board_bind_eic_interrupt)(int irq, int regset); void (*board_ebase_setup)(void); -void __cpuinitdata(*board_cache_error_setup)(void); + static void show_raw_backtrace(unsigned long reg29) { @@ -1491,6 +1490,7 @@ void *set_vi_handler(int n, vi_handler_t addr) return set_vi_srs_handler(n, addr, 0); } +extern void cpu_cache_init(void); extern void tlb_init(void); extern void flush_tlb_handlers(void); @@ -1517,7 +1517,7 @@ static int __init ulri_disable(char *s) } __setup("noulri", ulri_disable); -void __cpuinit per_cpu_trap_init(bool is_boot_cpu) +void __cpuinit per_cpu_trap_init(void) { unsigned int cpu = smp_processor_id(); unsigned int status_set = ST0_CU0; @@ -1616,9 +1616,7 @@ void __cpuinit per_cpu_trap_init(bool is_boot_cpu) #ifdef CONFIG_MIPS_MT_SMTC if (bootTC) { #endif /* CONFIG_MIPS_MT_SMTC */ - /* Boot CPU's cache setup in setup_arch(). */ - if (!is_boot_cpu) - cpu_cache_init(); + cpu_cache_init(); tlb_init(); #ifdef CONFIG_MIPS_MT_SMTC } else if (!secondaryTC) { @@ -1634,7 +1632,7 @@ void __cpuinit per_cpu_trap_init(bool is_boot_cpu) } /* Install CPU exception handler */ -void __cpuinit set_handler(unsigned long offset, void *addr, unsigned long size) +void __init set_handler(unsigned long offset, void *addr, unsigned long size) { memcpy((void *)(ebase + offset), addr, size); local_flush_icache_range(ebase + offset, ebase + offset + size); @@ -1695,7 +1693,7 @@ void __init trap_init(void) if (board_ebase_setup) board_ebase_setup(); - per_cpu_trap_init(true); + per_cpu_trap_init(); /* * Copy the generic exception handlers to their final destination. @@ -1799,9 +1797,6 @@ void __init trap_init(void) set_except_vector(26, handle_dsp); - if (board_cache_error_setup) - board_cache_error_setup(); - if (cpu_has_vce) /* Special exception: R4[04]00 uses also the divec space. */ memcpy((void *)(ebase + 0x180), &except_vec3_r4000, 0x100); diff --git a/trunk/arch/mips/lantiq/Kconfig b/trunk/arch/mips/lantiq/Kconfig index 20bdf40b3efa..3fccf2104513 100644 --- a/trunk/arch/mips/lantiq/Kconfig +++ b/trunk/arch/mips/lantiq/Kconfig @@ -16,22 +16,8 @@ config SOC_XWAY bool "XWAY" select SOC_TYPE_XWAY select HW_HAS_PCI - -config SOC_FALCON - bool "FALCON" - -endchoice - -choice - prompt "Devicetree" - -config DT_EASY50712 - bool "Easy50712" - depends on SOC_XWAY endchoice -config PCI_LANTIQ - bool "PCI Support" - depends on SOC_XWAY && PCI +source "arch/mips/lantiq/xway/Kconfig" endif diff --git a/trunk/arch/mips/lantiq/Makefile b/trunk/arch/mips/lantiq/Makefile index d6bdc579419f..e5dae0e24b00 100644 --- a/trunk/arch/mips/lantiq/Makefile +++ b/trunk/arch/mips/lantiq/Makefile @@ -4,11 +4,8 @@ # under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. -obj-y := irq.o clk.o prom.o - -obj-y += dts/ +obj-y := irq.o setup.o clk.o prom.o devices.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_SOC_TYPE_XWAY) += xway/ -obj-$(CONFIG_SOC_FALCON) += falcon/ diff --git a/trunk/arch/mips/lantiq/Platform b/trunk/arch/mips/lantiq/Platform index b3ec49838fd7..f3dff05722de 100644 --- a/trunk/arch/mips/lantiq/Platform +++ b/trunk/arch/mips/lantiq/Platform @@ -6,4 +6,3 @@ platform-$(CONFIG_LANTIQ) += lantiq/ cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq load-$(CONFIG_LANTIQ) = 0xffffffff80002000 cflags-$(CONFIG_SOC_TYPE_XWAY) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/xway -cflags-$(CONFIG_SOC_FALCON) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/falcon diff --git a/trunk/arch/mips/lantiq/clk.c b/trunk/arch/mips/lantiq/clk.c index d3bcc33f4699..412814fdd3ee 100644 --- a/trunk/arch/mips/lantiq/clk.c +++ b/trunk/arch/mips/lantiq/clk.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -23,32 +22,44 @@ #include #include "clk.h" -#include "prom.h" -/* lantiq socs have 3 static clocks */ -static struct clk cpu_clk_generic[3]; - -void clkdev_add_static(unsigned long cpu, unsigned long fpi, unsigned long io) -{ - cpu_clk_generic[0].rate = cpu; - cpu_clk_generic[1].rate = fpi; - cpu_clk_generic[2].rate = io; -} - -struct clk *clk_get_cpu(void) -{ - return &cpu_clk_generic[0]; -} +struct clk { + const char *name; + unsigned long rate; + unsigned long (*get_rate) (void); +}; -struct clk *clk_get_fpi(void) -{ - return &cpu_clk_generic[1]; -} -EXPORT_SYMBOL_GPL(clk_get_fpi); +static struct clk *cpu_clk; +static int cpu_clk_cnt; -struct clk *clk_get_io(void) +/* lantiq socs have 3 static clocks */ +static struct clk cpu_clk_generic[] = { + { + .name = "cpu", + .get_rate = ltq_get_cpu_hz, + }, { + .name = "fpi", + .get_rate = ltq_get_fpi_hz, + }, { + .name = "io", + .get_rate = ltq_get_io_region_clock, + }, +}; + +static struct resource ltq_cgu_resource = { + .name = "cgu", + .start = LTQ_CGU_BASE_ADDR, + .end = LTQ_CGU_BASE_ADDR + LTQ_CGU_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +/* remapped clock register range */ +void __iomem *ltq_cgu_membase; + +void clk_init(void) { - return &cpu_clk_generic[2]; + cpu_clk = cpu_clk_generic; + cpu_clk_cnt = ARRAY_SIZE(cpu_clk_generic); } static inline int clk_good(struct clk *clk) @@ -71,71 +82,38 @@ unsigned long clk_get_rate(struct clk *clk) } EXPORT_SYMBOL(clk_get_rate); -int clk_set_rate(struct clk *clk, unsigned long rate) +struct clk *clk_get(struct device *dev, const char *id) { - if (unlikely(!clk_good(clk))) - return 0; - if (clk->rates && *clk->rates) { - unsigned long *r = clk->rates; - - while (*r && (*r != rate)) - r++; - if (!*r) { - pr_err("clk %s.%s: trying to set invalid rate %ld\n", - clk->cl.dev_id, clk->cl.con_id, rate); - return -1; - } - } - clk->rate = rate; - return 0; -} -EXPORT_SYMBOL(clk_set_rate); - -int clk_enable(struct clk *clk) -{ - if (unlikely(!clk_good(clk))) - return -1; + int i; - if (clk->enable) - return clk->enable(clk); - - return -1; + for (i = 0; i < cpu_clk_cnt; i++) + if (!strcmp(id, cpu_clk[i].name)) + return &cpu_clk[i]; + BUG(); + return ERR_PTR(-ENOENT); } -EXPORT_SYMBOL(clk_enable); +EXPORT_SYMBOL(clk_get); -void clk_disable(struct clk *clk) +void clk_put(struct clk *clk) { - if (unlikely(!clk_good(clk))) - return; - - if (clk->disable) - clk->disable(clk); + /* not used */ } -EXPORT_SYMBOL(clk_disable); +EXPORT_SYMBOL(clk_put); -int clk_activate(struct clk *clk) +int clk_enable(struct clk *clk) { - if (unlikely(!clk_good(clk))) - return -1; - - if (clk->activate) - return clk->activate(clk); - - return -1; + /* not used */ + return 0; } -EXPORT_SYMBOL(clk_activate); +EXPORT_SYMBOL(clk_enable); -void clk_deactivate(struct clk *clk) +void clk_disable(struct clk *clk) { - if (unlikely(!clk_good(clk))) - return; - - if (clk->deactivate) - clk->deactivate(clk); + /* not used */ } -EXPORT_SYMBOL(clk_deactivate); +EXPORT_SYMBOL(clk_disable); -static inline u32 get_counter_resolution(void) +static inline u32 ltq_get_counter_resolution(void) { u32 res; @@ -155,11 +133,21 @@ void __init plat_time_init(void) { struct clk *clk; - ltq_soc_init(); + if (insert_resource(&iomem_resource, <q_cgu_resource) < 0) + panic("Failed to insert cgu memory"); - clk = clk_get_cpu(); - mips_hpt_frequency = clk_get_rate(clk) / get_counter_resolution(); + if (request_mem_region(ltq_cgu_resource.start, + resource_size(<q_cgu_resource), "cgu") < 0) + panic("Failed to request cgu memory"); + + ltq_cgu_membase = ioremap_nocache(ltq_cgu_resource.start, + resource_size(<q_cgu_resource)); + if (!ltq_cgu_membase) { + pr_err("Failed to remap cgu memory\n"); + unreachable(); + } + clk = clk_get(0, "cpu"); + mips_hpt_frequency = clk_get_rate(clk) / ltq_get_counter_resolution(); write_c0_compare(read_c0_count()); - pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); clk_put(clk); } diff --git a/trunk/arch/mips/lantiq/clk.h b/trunk/arch/mips/lantiq/clk.h index fa670602b91b..3328925f2c3f 100644 --- a/trunk/arch/mips/lantiq/clk.h +++ b/trunk/arch/mips/lantiq/clk.h @@ -9,70 +9,10 @@ #ifndef _LTQ_CLK_H__ #define _LTQ_CLK_H__ -#include +extern void clk_init(void); -/* clock speeds */ -#define CLOCK_33M 33333333 -#define CLOCK_60M 60000000 -#define CLOCK_62_5M 62500000 -#define CLOCK_83M 83333333 -#define CLOCK_83_5M 83500000 -#define CLOCK_98_304M 98304000 -#define CLOCK_100M 100000000 -#define CLOCK_111M 111111111 -#define CLOCK_125M 125000000 -#define CLOCK_133M 133333333 -#define CLOCK_150M 150000000 -#define CLOCK_166M 166666666 -#define CLOCK_167M 166666667 -#define CLOCK_196_608M 196608000 -#define CLOCK_200M 200000000 -#define CLOCK_250M 250000000 -#define CLOCK_266M 266666666 -#define CLOCK_300M 300000000 -#define CLOCK_333M 333333333 -#define CLOCK_393M 393215332 -#define CLOCK_400M 400000000 -#define CLOCK_500M 500000000 -#define CLOCK_600M 600000000 - -/* clock out speeds */ -#define CLOCK_32_768K 32768 -#define CLOCK_1_536M 1536000 -#define CLOCK_2_5M 2500000 -#define CLOCK_12M 12000000 -#define CLOCK_24M 24000000 -#define CLOCK_25M 25000000 -#define CLOCK_30M 30000000 -#define CLOCK_40M 40000000 -#define CLOCK_48M 48000000 -#define CLOCK_50M 50000000 -#define CLOCK_60M 60000000 - -struct clk { - struct clk_lookup cl; - unsigned long rate; - unsigned long *rates; - unsigned int module; - unsigned int bits; - unsigned long (*get_rate) (void); - int (*enable) (struct clk *clk); - void (*disable) (struct clk *clk); - int (*activate) (struct clk *clk); - void (*deactivate) (struct clk *clk); - void (*reboot) (struct clk *clk); -}; - -extern void clkdev_add_static(unsigned long cpu, unsigned long fpi, - unsigned long io); - -extern unsigned long ltq_danube_cpu_hz(void); -extern unsigned long ltq_danube_fpi_hz(void); - -extern unsigned long ltq_ar9_cpu_hz(void); -extern unsigned long ltq_ar9_fpi_hz(void); - -extern unsigned long ltq_vr9_cpu_hz(void); -extern unsigned long ltq_vr9_fpi_hz(void); +extern unsigned long ltq_get_cpu_hz(void); +extern unsigned long ltq_get_fpi_hz(void); +extern unsigned long ltq_get_io_region_clock(void); #endif diff --git a/trunk/arch/mips/lantiq/devices.c b/trunk/arch/mips/lantiq/devices.c new file mode 100644 index 000000000000..de1cb2bcd79a --- /dev/null +++ b/trunk/arch/mips/lantiq/devices.c @@ -0,0 +1,120 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "devices.h" + +/* nor flash */ +static struct resource ltq_nor_resource = { + .name = "nor", + .start = LTQ_FLASH_START, + .end = LTQ_FLASH_START + LTQ_FLASH_MAX - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device ltq_nor = { + .name = "ltq_nor", + .resource = <q_nor_resource, + .num_resources = 1, +}; + +void __init ltq_register_nor(struct physmap_flash_data *data) +{ + ltq_nor.dev.platform_data = data; + platform_device_register(<q_nor); +} + +/* watchdog */ +static struct resource ltq_wdt_resource = { + .name = "watchdog", + .start = LTQ_WDT_BASE_ADDR, + .end = LTQ_WDT_BASE_ADDR + LTQ_WDT_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +void __init ltq_register_wdt(void) +{ + platform_device_register_simple("ltq_wdt", 0, <q_wdt_resource, 1); +} + +/* asc ports */ +static struct resource ltq_asc0_resources[] = { + { + .name = "asc0", + .start = LTQ_ASC0_BASE_ADDR, + .end = LTQ_ASC0_BASE_ADDR + LTQ_ASC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + IRQ_RES(tx, LTQ_ASC_TIR(0)), + IRQ_RES(rx, LTQ_ASC_RIR(0)), + IRQ_RES(err, LTQ_ASC_EIR(0)), +}; + +static struct resource ltq_asc1_resources[] = { + { + .name = "asc1", + .start = LTQ_ASC1_BASE_ADDR, + .end = LTQ_ASC1_BASE_ADDR + LTQ_ASC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + IRQ_RES(tx, LTQ_ASC_TIR(1)), + IRQ_RES(rx, LTQ_ASC_RIR(1)), + IRQ_RES(err, LTQ_ASC_EIR(1)), +}; + +void __init ltq_register_asc(int port) +{ + switch (port) { + case 0: + platform_device_register_simple("ltq_asc", 0, + ltq_asc0_resources, ARRAY_SIZE(ltq_asc0_resources)); + break; + case 1: + platform_device_register_simple("ltq_asc", 1, + ltq_asc1_resources, ARRAY_SIZE(ltq_asc1_resources)); + break; + default: + break; + } +} + +#ifdef CONFIG_PCI +/* pci */ +static struct platform_device ltq_pci = { + .name = "ltq_pci", + .num_resources = 0, +}; + +void __init ltq_register_pci(struct ltq_pci_data *data) +{ + ltq_pci.dev.platform_data = data; + platform_device_register(<q_pci); +} +#else +void __init ltq_register_pci(struct ltq_pci_data *data) +{ + pr_err("kernel is compiled without PCI support\n"); +} +#endif diff --git a/trunk/arch/mips/lantiq/devices.h b/trunk/arch/mips/lantiq/devices.h new file mode 100644 index 000000000000..2947bb19a528 --- /dev/null +++ b/trunk/arch/mips/lantiq/devices.h @@ -0,0 +1,23 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#ifndef _LTQ_DEVICES_H__ +#define _LTQ_DEVICES_H__ + +#include +#include + +#define IRQ_RES(resname, irq) \ + {.name = #resname, .start = (irq), .flags = IORESOURCE_IRQ} + +extern void ltq_register_nor(struct physmap_flash_data *data); +extern void ltq_register_wdt(void); +extern void ltq_register_asc(int port); +extern void ltq_register_pci(struct ltq_pci_data *data); + +#endif diff --git a/trunk/arch/mips/lantiq/dts/Makefile b/trunk/arch/mips/lantiq/dts/Makefile deleted file mode 100644 index 674fca45f72d..000000000000 --- a/trunk/arch/mips/lantiq/dts/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -obj-$(CONFIG_DT_EASY50712) := easy50712.dtb.o - -$(obj)/%.dtb: $(obj)/%.dts - $(call if_changed,dtc) diff --git a/trunk/arch/mips/lantiq/dts/danube.dtsi b/trunk/arch/mips/lantiq/dts/danube.dtsi deleted file mode 100644 index 3a4520f009cf..000000000000 --- a/trunk/arch/mips/lantiq/dts/danube.dtsi +++ /dev/null @@ -1,105 +0,0 @@ -/ { - #address-cells = <1>; - #size-cells = <1>; - compatible = "lantiq,xway", "lantiq,danube"; - - cpus { - cpu@0 { - compatible = "mips,mips24Kc"; - }; - }; - - biu@1F800000 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "lantiq,biu", "simple-bus"; - reg = <0x1F800000 0x800000>; - ranges = <0x0 0x1F800000 0x7FFFFF>; - - icu0: icu@80200 { - #interrupt-cells = <1>; - interrupt-controller; - compatible = "lantiq,icu"; - reg = <0x80200 0x120>; - }; - - watchdog@803F0 { - compatible = "lantiq,wdt"; - reg = <0x803F0 0x10>; - }; - }; - - sram@1F000000 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "lantiq,sram"; - reg = <0x1F000000 0x800000>; - ranges = <0x0 0x1F000000 0x7FFFFF>; - - eiu0: eiu@101000 { - #interrupt-cells = <1>; - interrupt-controller; - interrupt-parent; - compatible = "lantiq,eiu-xway"; - reg = <0x101000 0x1000>; - }; - - pmu0: pmu@102000 { - compatible = "lantiq,pmu-xway"; - reg = <0x102000 0x1000>; - }; - - cgu0: cgu@103000 { - compatible = "lantiq,cgu-xway"; - reg = <0x103000 0x1000>; - #clock-cells = <1>; - }; - - rcu0: rcu@203000 { - compatible = "lantiq,rcu-xway"; - reg = <0x203000 0x1000>; - }; - }; - - fpi@10000000 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "lantiq,fpi", "simple-bus"; - ranges = <0x0 0x10000000 0xEEFFFFF>; - reg = <0x10000000 0xEF00000>; - - gptu@E100A00 { - compatible = "lantiq,gptu-xway"; - reg = <0xE100A00 0x100>; - }; - - serial@E100C00 { - compatible = "lantiq,asc"; - reg = <0xE100C00 0x400>; - interrupt-parent = <&icu0>; - interrupts = <112 113 114>; - }; - - dma0: dma@E104100 { - compatible = "lantiq,dma-xway"; - reg = <0xE104100 0x800>; - }; - - ebu0: ebu@E105300 { - compatible = "lantiq,ebu-xway"; - reg = <0xE105300 0x100>; - }; - - pci0: pci@E105400 { - #address-cells = <3>; - #size-cells = <2>; - #interrupt-cells = <1>; - compatible = "lantiq,pci-xway"; - bus-range = <0x0 0x0>; - ranges = <0x2000000 0 0x8000000 0x8000000 0 0x2000000 /* pci memory */ - 0x1000000 0 0x00000000 0xAE00000 0 0x200000>; /* io space */ - reg = <0x7000000 0x8000 /* config space */ - 0xE105400 0x400>; /* pci bridge */ - }; - }; -}; diff --git a/trunk/arch/mips/lantiq/dts/easy50712.dts b/trunk/arch/mips/lantiq/dts/easy50712.dts deleted file mode 100644 index 68c17310bc82..000000000000 --- a/trunk/arch/mips/lantiq/dts/easy50712.dts +++ /dev/null @@ -1,113 +0,0 @@ -/dts-v1/; - -/include/ "danube.dtsi" - -/ { - chosen { - bootargs = "console=ttyLTQ0,115200 init=/etc/preinit"; - }; - - memory@0 { - reg = <0x0 0x2000000>; - }; - - fpi@10000000 { - #address-cells = <1>; - #size-cells = <1>; - localbus@0 { - #address-cells = <2>; - #size-cells = <1>; - ranges = <0 0 0x0 0x3ffffff /* addrsel0 */ - 1 0 0x4000000 0x4000010>; /* addsel1 */ - compatible = "lantiq,localbus", "simple-bus"; - - nor-boot@0 { - compatible = "lantiq,nor"; - bank-width = <2>; - reg = <0 0x0 0x2000000>; - #address-cells = <1>; - #size-cells = <1>; - - partition@0 { - label = "uboot"; - reg = <0x00000 0x10000>; /* 64 KB */ - }; - - partition@10000 { - label = "uboot_env"; - reg = <0x10000 0x10000>; /* 64 KB */ - }; - - partition@20000 { - label = "linux"; - reg = <0x20000 0x3d0000>; - }; - - partition@400000 { - label = "rootfs"; - reg = <0x400000 0x400000>; - }; - }; - }; - - gpio: pinmux@E100B10 { - compatible = "lantiq,pinctrl-xway"; - pinctrl-names = "default"; - pinctrl-0 = <&state_default>; - - #gpio-cells = <2>; - gpio-controller; - reg = <0xE100B10 0xA0>; - - state_default: pinmux { - stp { - lantiq,groups = "stp"; - lantiq,function = "stp"; - }; - exin { - lantiq,groups = "exin1"; - lantiq,function = "exin"; - }; - pci { - lantiq,groups = "gnt1"; - lantiq,function = "pci"; - }; - conf_out { - lantiq,pins = "io4", "io5", "io6"; /* stp */ - lantiq,open-drain; - lantiq,pull = <0>; - }; - }; - }; - - etop@E180000 { - compatible = "lantiq,etop-xway"; - reg = <0xE180000 0x40000>; - interrupt-parent = <&icu0>; - interrupts = <73 78>; - phy-mode = "rmii"; - mac-address = [ 00 11 22 33 44 55 ]; - }; - - stp0: stp@E100BB0 { - #gpio-cells = <2>; - compatible = "lantiq,gpio-stp-xway"; - gpio-controller; - reg = <0xE100BB0 0x40>; - - lantiq,shadow = <0xfff>; - lantiq,groups = <0x3>; - }; - - pci@E105400 { - lantiq,bus-clock = <33333333>; - interrupt-map-mask = <0xf800 0x0 0x0 0x7>; - interrupt-map = < - 0x7000 0 0 1 &icu0 29 1 // slot 14, irq 29 - >; - gpios-reset = <&gpio 21 0>; - req-mask = <0x1>; /* GNT1 */ - }; - - }; -}; diff --git a/trunk/arch/mips/lantiq/early_printk.c b/trunk/arch/mips/lantiq/early_printk.c index 9b28d0940ef4..972e05f87631 100644 --- a/trunk/arch/mips/lantiq/early_printk.c +++ b/trunk/arch/mips/lantiq/early_printk.c @@ -6,16 +6,17 @@ * Copyright (C) 2010 John Crispin */ +#include #include + +#include #include +/* no ioremap possible at this early stage, lets use KSEG1 instead */ +#define LTQ_ASC_BASE KSEG1ADDR(LTQ_ASC1_BASE_ADDR) #define ASC_BUF 1024 -#define LTQ_ASC_FSTAT ((u32 *)(LTQ_EARLY_ASC + 0x0048)) -#ifdef __BIG_ENDIAN -#define LTQ_ASC_TBUF ((u32 *)(LTQ_EARLY_ASC + 0x0020 + 3)) -#else -#define LTQ_ASC_TBUF ((u32 *)(LTQ_EARLY_ASC + 0x0020)) -#endif +#define LTQ_ASC_FSTAT ((u32 *)(LTQ_ASC_BASE + 0x0048)) +#define LTQ_ASC_TBUF ((u32 *)(LTQ_ASC_BASE + 0x0020)) #define TXMASK 0x3F00 #define TXOFFSET 8 @@ -26,7 +27,7 @@ void prom_putchar(char c) local_irq_save(flags); do { } while ((ltq_r32(LTQ_ASC_FSTAT) & TXMASK) >> TXOFFSET); if (c == '\n') - ltq_w8('\r', LTQ_ASC_TBUF); - ltq_w8(c, LTQ_ASC_TBUF); + ltq_w32('\r', LTQ_ASC_TBUF); + ltq_w32(c, LTQ_ASC_TBUF); local_irq_restore(flags); } diff --git a/trunk/arch/mips/lantiq/falcon/Makefile b/trunk/arch/mips/lantiq/falcon/Makefile deleted file mode 100644 index ff220f97693d..000000000000 --- a/trunk/arch/mips/lantiq/falcon/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-y := prom.o reset.o sysctrl.o diff --git a/trunk/arch/mips/lantiq/falcon/prom.c b/trunk/arch/mips/lantiq/falcon/prom.c deleted file mode 100644 index c1d278f05a3a..000000000000 --- a/trunk/arch/mips/lantiq/falcon/prom.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2012 Thomas Langer - * Copyright (C) 2012 John Crispin - */ - -#include -#include - -#include - -#include "../prom.h" - -#define SOC_FALCON "Falcon" -#define SOC_FALCON_D "Falcon-D" -#define SOC_FALCON_V "Falcon-V" -#define SOC_FALCON_M "Falcon-M" - -#define COMP_FALCON "lantiq,falcon" - -#define PART_SHIFT 12 -#define PART_MASK 0x0FFFF000 -#define REV_SHIFT 28 -#define REV_MASK 0xF0000000 -#define SREV_SHIFT 22 -#define SREV_MASK 0x03C00000 -#define TYPE_SHIFT 26 -#define TYPE_MASK 0x3C000000 - -/* reset, nmi and ejtag exception vectors */ -#define BOOT_REG_BASE (KSEG1 | 0x1F200000) -#define BOOT_RVEC (BOOT_REG_BASE | 0x00) -#define BOOT_NVEC (BOOT_REG_BASE | 0x04) -#define BOOT_EVEC (BOOT_REG_BASE | 0x08) - -void __init ltq_soc_nmi_setup(void) -{ - extern void (*nmi_handler)(void); - - ltq_w32((unsigned long)&nmi_handler, (void *)BOOT_NVEC); -} - -void __init ltq_soc_ejtag_setup(void) -{ - extern void (*ejtag_debug_handler)(void); - - ltq_w32((unsigned long)&ejtag_debug_handler, (void *)BOOT_EVEC); -} - -void __init ltq_soc_detect(struct ltq_soc_info *i) -{ - u32 type; - i->partnum = (ltq_r32(FALCON_CHIPID) & PART_MASK) >> PART_SHIFT; - i->rev = (ltq_r32(FALCON_CHIPID) & REV_MASK) >> REV_SHIFT; - i->srev = ((ltq_r32(FALCON_CHIPCONF) & SREV_MASK) >> SREV_SHIFT); - i->compatible = COMP_FALCON; - i->type = SOC_TYPE_FALCON; - sprintf(i->rev_type, "%c%d%d", (i->srev & 0x4) ? ('B') : ('A'), - i->rev & 0x7, (i->srev & 0x3) + 1); - - switch (i->partnum) { - case SOC_ID_FALCON: - type = (ltq_r32(FALCON_CHIPTYPE) & TYPE_MASK) >> TYPE_SHIFT; - switch (type) { - case 0: - i->name = SOC_FALCON_D; - break; - case 1: - i->name = SOC_FALCON_V; - break; - case 2: - i->name = SOC_FALCON_M; - break; - default: - i->name = SOC_FALCON; - break; - } - break; - - default: - unreachable(); - break; - } -} diff --git a/trunk/arch/mips/lantiq/falcon/reset.c b/trunk/arch/mips/lantiq/falcon/reset.c deleted file mode 100644 index 568248253426..000000000000 --- a/trunk/arch/mips/lantiq/falcon/reset.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2012 Thomas Langer - * Copyright (C) 2012 John Crispin - */ - -#include -#include -#include -#include -#include - -#include - -/* CPU0 Reset Source Register */ -#define SYS1_CPU0RS 0x0040 -/* reset cause mask */ -#define CPU0RS_MASK 0x0003 -/* CPU0 Boot Mode Register */ -#define SYS1_BM 0x00a0 -/* boot mode mask */ -#define BM_MASK 0x0005 - -/* allow platform code to find out what surce we booted from */ -unsigned char ltq_boot_select(void) -{ - return ltq_sys1_r32(SYS1_BM) & BM_MASK; -} - -/* allow the watchdog driver to find out what the boot reason was */ -int ltq_reset_cause(void) -{ - return ltq_sys1_r32(SYS1_CPU0RS) & CPU0RS_MASK; -} -EXPORT_SYMBOL_GPL(ltq_reset_cause); - -#define BOOT_REG_BASE (KSEG1 | 0x1F200000) -#define BOOT_PW1_REG (BOOT_REG_BASE | 0x20) -#define BOOT_PW2_REG (BOOT_REG_BASE | 0x24) -#define BOOT_PW1 0x4C545100 -#define BOOT_PW2 0x0051544C - -#define WDT_REG_BASE (KSEG1 | 0x1F8803F0) -#define WDT_PW1 0x00BE0000 -#define WDT_PW2 0x00DC0000 - -static void machine_restart(char *command) -{ - local_irq_disable(); - - /* reboot magic */ - ltq_w32(BOOT_PW1, (void *)BOOT_PW1_REG); /* 'LTQ\0' */ - ltq_w32(BOOT_PW2, (void *)BOOT_PW2_REG); /* '\0QTL' */ - ltq_w32(0, (void *)BOOT_REG_BASE); /* reset Bootreg RVEC */ - - /* watchdog magic */ - ltq_w32(WDT_PW1, (void *)WDT_REG_BASE); - ltq_w32(WDT_PW2 | - (0x3 << 26) | /* PWL */ - (0x2 << 24) | /* CLKDIV */ - (0x1 << 31) | /* enable */ - (1), /* reload */ - (void *)WDT_REG_BASE); - unreachable(); -} - -static void machine_halt(void) -{ - local_irq_disable(); - unreachable(); -} - -static void machine_power_off(void) -{ - local_irq_disable(); - unreachable(); -} - -static int __init mips_reboot_setup(void) -{ - _machine_restart = machine_restart; - _machine_halt = machine_halt; - pm_power_off = machine_power_off; - return 0; -} - -arch_initcall(mips_reboot_setup); diff --git a/trunk/arch/mips/lantiq/falcon/sysctrl.c b/trunk/arch/mips/lantiq/falcon/sysctrl.c deleted file mode 100644 index ba0123d13d40..000000000000 --- a/trunk/arch/mips/lantiq/falcon/sysctrl.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2011 Thomas Langer - * Copyright (C) 2011 John Crispin - */ - -#include -#include -#include -#include -#include - -#include - -#include "../clk.h" - -/* infrastructure control register */ -#define SYS1_INFRAC 0x00bc -/* Configuration fuses for drivers and pll */ -#define STATUS_CONFIG 0x0040 - -/* GPE frequency selection */ -#define GPPC_OFFSET 24 -#define GPEFREQ_MASK 0x00000C0 -#define GPEFREQ_OFFSET 10 -/* Clock status register */ -#define SYSCTL_CLKS 0x0000 -/* Clock enable register */ -#define SYSCTL_CLKEN 0x0004 -/* Clock clear register */ -#define SYSCTL_CLKCLR 0x0008 -/* Activation Status Register */ -#define SYSCTL_ACTS 0x0020 -/* Activation Register */ -#define SYSCTL_ACT 0x0024 -/* Deactivation Register */ -#define SYSCTL_DEACT 0x0028 -/* reboot Register */ -#define SYSCTL_RBT 0x002c -/* CPU0 Clock Control Register */ -#define SYS1_CPU0CC 0x0040 -/* HRST_OUT_N Control Register */ -#define SYS1_HRSTOUTC 0x00c0 -/* clock divider bit */ -#define CPU0CC_CPUDIV 0x0001 - -/* Activation Status Register */ -#define ACTS_ASC1_ACT 0x00000800 -#define ACTS_I2C_ACT 0x00004000 -#define ACTS_P0 0x00010000 -#define ACTS_P1 0x00010000 -#define ACTS_P2 0x00020000 -#define ACTS_P3 0x00020000 -#define ACTS_P4 0x00040000 -#define ACTS_PADCTRL0 0x00100000 -#define ACTS_PADCTRL1 0x00100000 -#define ACTS_PADCTRL2 0x00200000 -#define ACTS_PADCTRL3 0x00200000 -#define ACTS_PADCTRL4 0x00400000 - -#define sysctl_w32(m, x, y) ltq_w32((x), sysctl_membase[m] + (y)) -#define sysctl_r32(m, x) ltq_r32(sysctl_membase[m] + (x)) -#define sysctl_w32_mask(m, clear, set, reg) \ - sysctl_w32(m, (sysctl_r32(m, reg) & ~(clear)) | (set), reg) - -#define status_w32(x, y) ltq_w32((x), status_membase + (y)) -#define status_r32(x) ltq_r32(status_membase + (x)) - -static void __iomem *sysctl_membase[3], *status_membase; -void __iomem *ltq_sys1_membase, *ltq_ebu_membase; - -void falcon_trigger_hrst(int level) -{ - sysctl_w32(SYSCTL_SYS1, level & 1, SYS1_HRSTOUTC); -} - -static inline void sysctl_wait(struct clk *clk, - unsigned int test, unsigned int reg) -{ - int err = 1000000; - - do {} while (--err && ((sysctl_r32(clk->module, reg) - & clk->bits) != test)); - if (!err) - pr_err("module de/activation failed %d %08X %08X %08X\n", - clk->module, clk->bits, test, - sysctl_r32(clk->module, reg) & clk->bits); -} - -static int sysctl_activate(struct clk *clk) -{ - sysctl_w32(clk->module, clk->bits, SYSCTL_CLKEN); - sysctl_w32(clk->module, clk->bits, SYSCTL_ACT); - sysctl_wait(clk, clk->bits, SYSCTL_ACTS); - return 0; -} - -static void sysctl_deactivate(struct clk *clk) -{ - sysctl_w32(clk->module, clk->bits, SYSCTL_CLKCLR); - sysctl_w32(clk->module, clk->bits, SYSCTL_DEACT); - sysctl_wait(clk, 0, SYSCTL_ACTS); -} - -static int sysctl_clken(struct clk *clk) -{ - sysctl_w32(clk->module, clk->bits, SYSCTL_CLKEN); - sysctl_wait(clk, clk->bits, SYSCTL_CLKS); - return 0; -} - -static void sysctl_clkdis(struct clk *clk) -{ - sysctl_w32(clk->module, clk->bits, SYSCTL_CLKCLR); - sysctl_wait(clk, 0, SYSCTL_CLKS); -} - -static void sysctl_reboot(struct clk *clk) -{ - unsigned int act; - unsigned int bits; - - act = sysctl_r32(clk->module, SYSCTL_ACT); - bits = ~act & clk->bits; - if (bits != 0) { - sysctl_w32(clk->module, bits, SYSCTL_CLKEN); - sysctl_w32(clk->module, bits, SYSCTL_ACT); - sysctl_wait(clk, bits, SYSCTL_ACTS); - } - sysctl_w32(clk->module, act & clk->bits, SYSCTL_RBT); - sysctl_wait(clk, clk->bits, SYSCTL_ACTS); -} - -/* enable the ONU core */ -static void falcon_gpe_enable(void) -{ - unsigned int freq; - unsigned int status; - - /* if if the clock is already enabled */ - status = sysctl_r32(SYSCTL_SYS1, SYS1_INFRAC); - if (status & (1 << (GPPC_OFFSET + 1))) - return; - - if (status_r32(STATUS_CONFIG) == 0) - freq = 1; /* use 625MHz on unfused chip */ - else - freq = (status_r32(STATUS_CONFIG) & - GPEFREQ_MASK) >> - GPEFREQ_OFFSET; - - /* apply new frequency */ - sysctl_w32_mask(SYSCTL_SYS1, 7 << (GPPC_OFFSET + 1), - freq << (GPPC_OFFSET + 2) , SYS1_INFRAC); - udelay(1); - - /* enable new frequency */ - sysctl_w32_mask(SYSCTL_SYS1, 0, 1 << (GPPC_OFFSET + 1), SYS1_INFRAC); - udelay(1); -} - -static inline void clkdev_add_sys(const char *dev, unsigned int module, - unsigned int bits) -{ - struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); - - clk->cl.dev_id = dev; - clk->cl.con_id = NULL; - clk->cl.clk = clk; - clk->module = module; - clk->activate = sysctl_activate; - clk->deactivate = sysctl_deactivate; - clk->enable = sysctl_clken; - clk->disable = sysctl_clkdis; - clk->reboot = sysctl_reboot; - clkdev_add(&clk->cl); -} - -void __init ltq_soc_init(void) -{ - struct device_node *np_status = - of_find_compatible_node(NULL, NULL, "lantiq,status-falcon"); - struct device_node *np_ebu = - of_find_compatible_node(NULL, NULL, "lantiq,ebu-falcon"); - struct device_node *np_sys1 = - of_find_compatible_node(NULL, NULL, "lantiq,sys1-falcon"); - struct device_node *np_syseth = - of_find_compatible_node(NULL, NULL, "lantiq,syseth-falcon"); - struct device_node *np_sysgpe = - of_find_compatible_node(NULL, NULL, "lantiq,sysgpe-falcon"); - struct resource res_status, res_ebu, res_sys[3]; - int i; - - /* check if all the core register ranges are available */ - if (!np_status || !np_ebu || !np_sys1 || !np_syseth || !np_sysgpe) - panic("Failed to load core nodes from devicetree"); - - if (of_address_to_resource(np_status, 0, &res_status) || - of_address_to_resource(np_ebu, 0, &res_ebu) || - of_address_to_resource(np_sys1, 0, &res_sys[0]) || - of_address_to_resource(np_syseth, 0, &res_sys[1]) || - of_address_to_resource(np_sysgpe, 0, &res_sys[2])) - panic("Failed to get core resources"); - - if ((request_mem_region(res_status.start, resource_size(&res_status), - res_status.name) < 0) || - (request_mem_region(res_ebu.start, resource_size(&res_ebu), - res_ebu.name) < 0) || - (request_mem_region(res_sys[0].start, - resource_size(&res_sys[0]), - res_sys[0].name) < 0) || - (request_mem_region(res_sys[1].start, - resource_size(&res_sys[1]), - res_sys[1].name) < 0) || - (request_mem_region(res_sys[2].start, - resource_size(&res_sys[2]), - res_sys[2].name) < 0)) - pr_err("Failed to request core reources"); - - status_membase = ioremap_nocache(res_status.start, - resource_size(&res_status)); - ltq_ebu_membase = ioremap_nocache(res_ebu.start, - resource_size(&res_ebu)); - - if (!status_membase || !ltq_ebu_membase) - panic("Failed to remap core resources"); - - for (i = 0; i < 3; i++) { - sysctl_membase[i] = ioremap_nocache(res_sys[i].start, - resource_size(&res_sys[i])); - if (!sysctl_membase[i]) - panic("Failed to remap sysctrl resources"); - } - ltq_sys1_membase = sysctl_membase[0]; - - falcon_gpe_enable(); - - /* get our 3 static rates for cpu, fpi and io clocks */ - if (ltq_sys1_r32(SYS1_CPU0CC) & CPU0CC_CPUDIV) - clkdev_add_static(CLOCK_200M, CLOCK_100M, CLOCK_200M); - else - clkdev_add_static(CLOCK_400M, CLOCK_100M, CLOCK_200M); - - /* add our clock domains */ - clkdev_add_sys("1d810000.gpio", SYSCTL_SYSETH, ACTS_P0); - clkdev_add_sys("1d810100.gpio", SYSCTL_SYSETH, ACTS_P2); - clkdev_add_sys("1e800100.gpio", SYSCTL_SYS1, ACTS_P1); - clkdev_add_sys("1e800200.gpio", SYSCTL_SYS1, ACTS_P3); - clkdev_add_sys("1e800300.gpio", SYSCTL_SYS1, ACTS_P4); - clkdev_add_sys("1db01000.pad", SYSCTL_SYSETH, ACTS_PADCTRL0); - clkdev_add_sys("1db02000.pad", SYSCTL_SYSETH, ACTS_PADCTRL2); - clkdev_add_sys("1e800400.pad", SYSCTL_SYS1, ACTS_PADCTRL1); - clkdev_add_sys("1e800500.pad", SYSCTL_SYS1, ACTS_PADCTRL3); - clkdev_add_sys("1e800600.pad", SYSCTL_SYS1, ACTS_PADCTRL4); - clkdev_add_sys("1e100C00.serial", SYSCTL_SYS1, ACTS_ASC1_ACT); - clkdev_add_sys("1e200000.i2c", SYSCTL_SYS1, ACTS_I2C_ACT); -} diff --git a/trunk/arch/mips/lantiq/irq.c b/trunk/arch/mips/lantiq/irq.c index 57c1a4e51408..d673731c538a 100644 --- a/trunk/arch/mips/lantiq/irq.c +++ b/trunk/arch/mips/lantiq/irq.c @@ -9,11 +9,6 @@ #include #include -#include -#include -#include -#include -#include #include #include @@ -21,7 +16,7 @@ #include #include -/* register definitions - internal irqs */ +/* register definitions */ #define LTQ_ICU_IM0_ISR 0x0000 #define LTQ_ICU_IM0_IER 0x0008 #define LTQ_ICU_IM0_IOSR 0x0010 @@ -30,7 +25,6 @@ #define LTQ_ICU_IM1_ISR 0x0028 #define LTQ_ICU_OFFSET (LTQ_ICU_IM1_ISR - LTQ_ICU_IM0_ISR) -/* register definitions - external irqs */ #define LTQ_EIU_EXIN_C 0x0000 #define LTQ_EIU_EXIN_INIC 0x0004 #define LTQ_EIU_EXIN_INEN 0x000C @@ -43,14 +37,10 @@ #define LTQ_EIU_IR4 (INT_NUM_IM1_IRL0 + 1) #define LTQ_EIU_IR5 (INT_NUM_IM1_IRL0 + 2) #define LTQ_EIU_IR6 (INT_NUM_IM2_IRL0 + 30) -#define XWAY_EXIN_COUNT 3 -#define MAX_EIU 6 -/* the performance counter */ -#define LTQ_PERF_IRQ (INT_NUM_IM4_IRL0 + 31) +#define MAX_EIU 6 -/* - * irqs generated by devices attached to the EBU need to be acked in +/* irqs generated by device attached to the EBU need to be acked in * a special manner */ #define LTQ_ICU_EBU_IRQ 22 @@ -61,17 +51,6 @@ #define ltq_eiu_w32(x, y) ltq_w32((x), ltq_eiu_membase + (y)) #define ltq_eiu_r32(x) ltq_r32(ltq_eiu_membase + (x)) -/* our 2 ipi interrupts for VSMP */ -#define MIPS_CPU_IPI_RESCHED_IRQ 0 -#define MIPS_CPU_IPI_CALL_IRQ 1 - -/* we have a cascade of 8 irqs */ -#define MIPS_CPU_IRQ_CASCADE 8 - -#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) -int gic_present; -#endif - static unsigned short ltq_eiu_irq[MAX_EIU] = { LTQ_EIU_IR0, LTQ_EIU_IR1, @@ -81,51 +60,64 @@ static unsigned short ltq_eiu_irq[MAX_EIU] = { LTQ_EIU_IR5, }; -static int exin_avail; +static struct resource ltq_icu_resource = { + .name = "icu", + .start = LTQ_ICU_BASE_ADDR, + .end = LTQ_ICU_BASE_ADDR + LTQ_ICU_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static struct resource ltq_eiu_resource = { + .name = "eiu", + .start = LTQ_EIU_BASE_ADDR, + .end = LTQ_EIU_BASE_ADDR + LTQ_ICU_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + static void __iomem *ltq_icu_membase; static void __iomem *ltq_eiu_membase; void ltq_disable_irq(struct irq_data *d) { u32 ier = LTQ_ICU_IM0_IER; - int offset = d->hwirq - MIPS_CPU_IRQ_CASCADE; + int irq_nr = d->irq - INT_NUM_IRQ0; - ier += LTQ_ICU_OFFSET * (offset / INT_NUM_IM_OFFSET); - offset %= INT_NUM_IM_OFFSET; - ltq_icu_w32(ltq_icu_r32(ier) & ~BIT(offset), ier); + ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); + irq_nr %= INT_NUM_IM_OFFSET; + ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier); } void ltq_mask_and_ack_irq(struct irq_data *d) { u32 ier = LTQ_ICU_IM0_IER; u32 isr = LTQ_ICU_IM0_ISR; - int offset = d->hwirq - MIPS_CPU_IRQ_CASCADE; + int irq_nr = d->irq - INT_NUM_IRQ0; - ier += LTQ_ICU_OFFSET * (offset / INT_NUM_IM_OFFSET); - isr += LTQ_ICU_OFFSET * (offset / INT_NUM_IM_OFFSET); - offset %= INT_NUM_IM_OFFSET; - ltq_icu_w32(ltq_icu_r32(ier) & ~BIT(offset), ier); - ltq_icu_w32(BIT(offset), isr); + ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); + isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); + irq_nr %= INT_NUM_IM_OFFSET; + ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier); + ltq_icu_w32((1 << irq_nr), isr); } static void ltq_ack_irq(struct irq_data *d) { u32 isr = LTQ_ICU_IM0_ISR; - int offset = d->hwirq - MIPS_CPU_IRQ_CASCADE; + int irq_nr = d->irq - INT_NUM_IRQ0; - isr += LTQ_ICU_OFFSET * (offset / INT_NUM_IM_OFFSET); - offset %= INT_NUM_IM_OFFSET; - ltq_icu_w32(BIT(offset), isr); + isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); + irq_nr %= INT_NUM_IM_OFFSET; + ltq_icu_w32((1 << irq_nr), isr); } void ltq_enable_irq(struct irq_data *d) { u32 ier = LTQ_ICU_IM0_IER; - int offset = d->hwirq - MIPS_CPU_IRQ_CASCADE; + int irq_nr = d->irq - INT_NUM_IRQ0; - ier += LTQ_ICU_OFFSET * (offset / INT_NUM_IM_OFFSET); - offset %= INT_NUM_IM_OFFSET; - ltq_icu_w32(ltq_icu_r32(ier) | BIT(offset), ier); + ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); + irq_nr %= INT_NUM_IM_OFFSET; + ltq_icu_w32(ltq_icu_r32(ier) | (1 << irq_nr), ier); } static unsigned int ltq_startup_eiu_irq(struct irq_data *d) @@ -134,15 +126,15 @@ static unsigned int ltq_startup_eiu_irq(struct irq_data *d) ltq_enable_irq(d); for (i = 0; i < MAX_EIU; i++) { - if (d->hwirq == ltq_eiu_irq[i]) { + if (d->irq == ltq_eiu_irq[i]) { /* low level - we should really handle set_type */ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) | (0x6 << (i * 4)), LTQ_EIU_EXIN_C); /* clear all pending */ - ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INIC) & ~BIT(i), + ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INIC) & ~(1 << i), LTQ_EIU_EXIN_INIC); /* enable */ - ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | BIT(i), + ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | (1 << i), LTQ_EIU_EXIN_INEN); break; } @@ -157,9 +149,9 @@ static void ltq_shutdown_eiu_irq(struct irq_data *d) ltq_disable_irq(d); for (i = 0; i < MAX_EIU; i++) { - if (d->hwirq == ltq_eiu_irq[i]) { + if (d->irq == ltq_eiu_irq[i]) { /* disable */ - ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~BIT(i), + ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~(1 << i), LTQ_EIU_EXIN_INEN); break; } @@ -196,15 +188,14 @@ static void ltq_hw_irqdispatch(int module) if (irq == 0) return; - /* - * silicon bug causes only the msb set to 1 to be valid. all + /* silicon bug causes only the msb set to 1 to be valid. all * other bits might be bogus */ irq = __fls(irq); - do_IRQ((int)irq + MIPS_CPU_IRQ_CASCADE + (INT_NUM_IM_OFFSET * module)); + do_IRQ((int)irq + INT_NUM_IM0_IRL0 + (INT_NUM_IM_OFFSET * module)); /* if this is a EBU irq, we need to ack it or get a deadlock */ - if ((irq == LTQ_ICU_EBU_IRQ) && (module == 0) && LTQ_EBU_PCC_ISTAT) + if ((irq == LTQ_ICU_EBU_IRQ) && (module == 0)) ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_ISTAT) | 0x10, LTQ_EBU_PCC_ISTAT); } @@ -225,47 +216,6 @@ static void ltq_hw5_irqdispatch(void) do_IRQ(MIPS_CPU_TIMER_IRQ); } -#ifdef CONFIG_MIPS_MT_SMP -void __init arch_init_ipiirq(int irq, struct irqaction *action) -{ - setup_irq(irq, action); - irq_set_handler(irq, handle_percpu_irq); -} - -static void ltq_sw0_irqdispatch(void) -{ - do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ); -} - -static void ltq_sw1_irqdispatch(void) -{ - do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ); -} -static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) -{ - scheduler_ipi(); - return IRQ_HANDLED; -} - -static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) -{ - smp_call_function_interrupt(); - return IRQ_HANDLED; -} - -static struct irqaction irq_resched = { - .handler = ipi_resched_interrupt, - .flags = IRQF_PERCPU, - .name = "IPI_resched" -}; - -static struct irqaction irq_call = { - .handler = ipi_call_interrupt, - .flags = IRQF_PERCPU, - .name = "IPI_call" -}; -#endif - asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; @@ -288,75 +238,45 @@ asmlinkage void plat_irq_dispatch(void) return; } -static int icu_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) -{ - struct irq_chip *chip = <q_irq_type; - int i; - - for (i = 0; i < exin_avail; i++) - if (hw == ltq_eiu_irq[i]) - chip = <q_eiu_type; - - irq_set_chip_and_handler(hw, chip, handle_level_irq); - - return 0; -} - -static const struct irq_domain_ops irq_domain_ops = { - .xlate = irq_domain_xlate_onetwocell, - .map = icu_map, -}; - static struct irqaction cascade = { .handler = no_action, .name = "cascade", }; -int __init icu_of_init(struct device_node *node, struct device_node *parent) +void __init arch_init_irq(void) { - struct device_node *eiu_node; - struct resource res; int i; - if (of_address_to_resource(node, 0, &res)) - panic("Failed to get icu memory range"); + if (insert_resource(&iomem_resource, <q_icu_resource) < 0) + panic("Failed to insert icu memory"); - if (request_mem_region(res.start, resource_size(&res), res.name) < 0) - pr_err("Failed to request icu memory"); + if (request_mem_region(ltq_icu_resource.start, + resource_size(<q_icu_resource), "icu") < 0) + panic("Failed to request icu memory"); - ltq_icu_membase = ioremap_nocache(res.start, resource_size(&res)); + ltq_icu_membase = ioremap_nocache(ltq_icu_resource.start, + resource_size(<q_icu_resource)); if (!ltq_icu_membase) panic("Failed to remap icu memory"); - /* the external interrupts are optional and xway only */ - eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu"); - if (eiu_node && of_address_to_resource(eiu_node, 0, &res)) { - /* find out how many external irq sources we have */ - const __be32 *count = of_get_property(node, - "lantiq,count", NULL); - - if (count) - exin_avail = *count; - if (exin_avail > MAX_EIU) - exin_avail = MAX_EIU; - - if (request_mem_region(res.start, resource_size(&res), - res.name) < 0) - pr_err("Failed to request eiu memory"); - - ltq_eiu_membase = ioremap_nocache(res.start, - resource_size(&res)); - if (!ltq_eiu_membase) - panic("Failed to remap eiu memory"); - } + if (insert_resource(&iomem_resource, <q_eiu_resource) < 0) + panic("Failed to insert eiu memory"); + + if (request_mem_region(ltq_eiu_resource.start, + resource_size(<q_eiu_resource), "eiu") < 0) + panic("Failed to request eiu memory"); + + ltq_eiu_membase = ioremap_nocache(ltq_eiu_resource.start, + resource_size(<q_eiu_resource)); + if (!ltq_eiu_membase) + panic("Failed to remap eiu memory"); - /* turn off all irqs by default */ - for (i = 0; i < 5; i++) { - /* make sure all irqs are turned off by default */ + /* make sure all irqs are turned off by default */ + for (i = 0; i < 5; i++) ltq_icu_w32(0, LTQ_ICU_IM0_IER + (i * LTQ_ICU_OFFSET)); - /* clear all possibly pending interrupts */ - ltq_icu_w32(~0, LTQ_ICU_IM0_ISR + (i * LTQ_ICU_OFFSET)); - } + + /* clear all possibly pending interrupts */ + ltq_icu_w32(~0, LTQ_ICU_IM0_ISR + (i * LTQ_ICU_OFFSET)); mips_cpu_irq_init(); @@ -373,19 +293,20 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent) set_vi_handler(7, ltq_hw5_irqdispatch); } - irq_domain_add_linear(node, 6 * INT_NUM_IM_OFFSET, - &irq_domain_ops, 0); - -#if defined(CONFIG_MIPS_MT_SMP) - if (cpu_has_vint) { - pr_info("Setting up IPI vectored interrupts\n"); - set_vi_handler(MIPS_CPU_IPI_RESCHED_IRQ, ltq_sw0_irqdispatch); - set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ltq_sw1_irqdispatch); - } - arch_init_ipiirq(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ, - &irq_resched); - arch_init_ipiirq(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ, &irq_call); -#endif + for (i = INT_NUM_IRQ0; + i <= (INT_NUM_IRQ0 + (5 * INT_NUM_IM_OFFSET)); i++) + if ((i == LTQ_EIU_IR0) || (i == LTQ_EIU_IR1) || + (i == LTQ_EIU_IR2)) + irq_set_chip_and_handler(i, <q_eiu_type, + handle_level_irq); + /* EIU3-5 only exist on ar9 and vr9 */ + else if (((i == LTQ_EIU_IR3) || (i == LTQ_EIU_IR4) || + (i == LTQ_EIU_IR5)) && (ltq_is_ar9() || ltq_is_vr9())) + irq_set_chip_and_handler(i, <q_eiu_type, + handle_level_irq); + else + irq_set_chip_and_handler(i, <q_irq_type, + handle_level_irq); #if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC) set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | @@ -394,23 +315,9 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent) set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5); #endif - - /* tell oprofile which irq to use */ - cp0_perfcount_irq = LTQ_PERF_IRQ; - return 0; } unsigned int __cpuinit get_c0_compare_int(void) { return CP0_LEGACY_COMPARE_IRQ; } - -static struct of_device_id __initdata of_irq_ids[] = { - { .compatible = "lantiq,icu", .data = icu_of_init }, - {}, -}; - -void __init arch_init_irq(void) -{ - of_irq_init(of_irq_ids); -} diff --git a/trunk/arch/mips/lantiq/machtypes.h b/trunk/arch/mips/lantiq/machtypes.h new file mode 100644 index 000000000000..7e01b8c484eb --- /dev/null +++ b/trunk/arch/mips/lantiq/machtypes.h @@ -0,0 +1,20 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#ifndef _LANTIQ_MACH_H__ +#define _LANTIQ_MACH_H__ + +#include + +enum lantiq_mach_type { + LTQ_MACH_GENERIC = 0, + LTQ_MACH_EASY50712, /* Danube evaluation board */ + LTQ_MACH_EASY50601, /* Amazon SE evaluation board */ +}; + +#endif diff --git a/trunk/arch/mips/lantiq/prom.c b/trunk/arch/mips/lantiq/prom.c index d185e8477fdf..e34fcfd0d5ca 100644 --- a/trunk/arch/mips/lantiq/prom.c +++ b/trunk/arch/mips/lantiq/prom.c @@ -8,7 +8,6 @@ #include #include -#include #include #include @@ -17,16 +16,20 @@ #include "prom.h" #include "clk.h" -/* access to the ebu needs to be locked between different drivers */ -DEFINE_SPINLOCK(ebu_lock); -EXPORT_SYMBOL_GPL(ebu_lock); - -/* - * this struct is filled by the soc specific detection code and holds - * information about the specific soc type, revision and name - */ static struct ltq_soc_info soc_info; +unsigned int ltq_get_cpu_ver(void) +{ + return soc_info.rev; +} +EXPORT_SYMBOL(ltq_get_cpu_ver); + +unsigned int ltq_get_soc_type(void) +{ + return soc_info.type; +} +EXPORT_SYMBOL(ltq_get_soc_type); + const char *get_system_type(void) { return soc_info.sys_type; @@ -42,62 +45,27 @@ static void __init prom_init_cmdline(void) char **argv = (char **) KSEG1ADDR(fw_arg1); int i; - arcs_cmdline[0] = '\0'; - for (i = 0; i < argc; i++) { - char *p = (char *) KSEG1ADDR(argv[i]); + char *p = (char *) KSEG1ADDR(argv[i]); - if (CPHYSADDR(p) && *p) { + if (p && *p) { strlcat(arcs_cmdline, p, sizeof(arcs_cmdline)); strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline)); } } } -void __init plat_mem_setup(void) -{ - ioport_resource.start = IOPORT_RESOURCE_START; - ioport_resource.end = IOPORT_RESOURCE_END; - iomem_resource.start = IOMEM_RESOURCE_START; - iomem_resource.end = IOMEM_RESOURCE_END; - - set_io_port_base((unsigned long) KSEG1); - - /* - * Load the builtin devicetree. This causes the chosen node to be - * parsed resulting in our memory appearing - */ - __dt_setup_arch(&__dtb_start); -} - void __init prom_init(void) { - /* call the soc specific detetcion code and get it to fill soc_info */ + struct clk *clk; + ltq_soc_detect(&soc_info); - snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN - 1, "%s rev %s", - soc_info.name, soc_info.rev_type); + clk_init(); + clk = clk_get(0, "cpu"); + snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN - 1, "%s rev1.%d", + soc_info.name, soc_info.rev); + clk_put(clk); soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0'; pr_info("SoC: %s\n", soc_info.sys_type); prom_init_cmdline(); - -#if defined(CONFIG_MIPS_MT_SMP) - if (register_vsmp_smp_ops()) - panic("failed to register_vsmp_smp_ops()"); -#endif } - -int __init plat_of_setup(void) -{ - static struct of_device_id of_ids[3]; - - if (!of_have_populated_dt()) - panic("device tree not present"); - - strncpy(of_ids[0].compatible, soc_info.compatible, - sizeof(of_ids[0].compatible)); - strncpy(of_ids[1].compatible, "simple-bus", - sizeof(of_ids[1].compatible)); - return of_platform_bus_probe(NULL, of_ids, NULL); -} - -arch_initcall(plat_of_setup); diff --git a/trunk/arch/mips/lantiq/prom.h b/trunk/arch/mips/lantiq/prom.h index a3fa1a2bfaae..b4229d94280f 100644 --- a/trunk/arch/mips/lantiq/prom.h +++ b/trunk/arch/mips/lantiq/prom.h @@ -10,22 +10,16 @@ #define _LTQ_PROM_H__ #define LTQ_SYS_TYPE_LEN 0x100 -#define LTQ_SYS_REV_LEN 0x10 struct ltq_soc_info { unsigned char *name; unsigned int rev; - unsigned char rev_type[LTQ_SYS_REV_LEN]; - unsigned int srev; unsigned int partnum; unsigned int type; unsigned char sys_type[LTQ_SYS_TYPE_LEN]; - unsigned char *compatible; }; extern void ltq_soc_detect(struct ltq_soc_info *i); -extern void ltq_soc_init(void); - -extern struct boot_param_header __dtb_start; +extern void ltq_soc_setup(void); #endif diff --git a/trunk/arch/mips/lantiq/setup.c b/trunk/arch/mips/lantiq/setup.c new file mode 100644 index 000000000000..1ff6c9d6cb93 --- /dev/null +++ b/trunk/arch/mips/lantiq/setup.c @@ -0,0 +1,66 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include +#include + +#include + +#include "machtypes.h" +#include "devices.h" +#include "prom.h" + +void __init plat_mem_setup(void) +{ + /* assume 16M as default incase uboot fails to pass proper ramsize */ + unsigned long memsize = 16; + char **envp = (char **) KSEG1ADDR(fw_arg2); + + ioport_resource.start = IOPORT_RESOURCE_START; + ioport_resource.end = IOPORT_RESOURCE_END; + iomem_resource.start = IOMEM_RESOURCE_START; + iomem_resource.end = IOMEM_RESOURCE_END; + + set_io_port_base((unsigned long) KSEG1); + + while (*envp) { + char *e = (char *)KSEG1ADDR(*envp); + if (!strncmp(e, "memsize=", 8)) { + e += 8; + if (strict_strtoul(e, 0, &memsize)) + pr_warn("bad memsize specified\n"); + } + envp++; + } + memsize *= 1024 * 1024; + add_memory_region(0x00000000, memsize, BOOT_MEM_RAM); +} + +static int __init +lantiq_setup(void) +{ + ltq_soc_setup(); + mips_machine_setup(); + return 0; +} + +arch_initcall(lantiq_setup); + +static void __init +lantiq_generic_init(void) +{ + /* Nothing to do */ +} + +MIPS_MACHINE(LTQ_MACH_GENERIC, + "Generic", + "Generic Lantiq based board", + lantiq_generic_init); diff --git a/trunk/arch/mips/lantiq/xway/Kconfig b/trunk/arch/mips/lantiq/xway/Kconfig new file mode 100644 index 000000000000..2b857de36620 --- /dev/null +++ b/trunk/arch/mips/lantiq/xway/Kconfig @@ -0,0 +1,23 @@ +if SOC_XWAY + +menu "MIPS Machine" + +config LANTIQ_MACH_EASY50712 + bool "Easy50712 - Danube" + default y + +endmenu + +endif + +if SOC_AMAZON_SE + +menu "MIPS Machine" + +config LANTIQ_MACH_EASY50601 + bool "Easy50601 - Amazon SE" + default y + +endmenu + +endif diff --git a/trunk/arch/mips/lantiq/xway/Makefile b/trunk/arch/mips/lantiq/xway/Makefile index dc3194f6ee42..c517f2e77563 100644 --- a/trunk/arch/mips/lantiq/xway/Makefile +++ b/trunk/arch/mips/lantiq/xway/Makefile @@ -1 +1,7 @@ -obj-y := prom.o sysctrl.o clk.o reset.o gpio.o dma.o +obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o + +obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o +obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o + +obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o +obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o diff --git a/trunk/arch/mips/lantiq/xway/clk-ase.c b/trunk/arch/mips/lantiq/xway/clk-ase.c new file mode 100644 index 000000000000..652258309c9c --- /dev/null +++ b/trunk/arch/mips/lantiq/xway/clk-ase.c @@ -0,0 +1,48 @@ +/* + * 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. + * + * Copyright (C) 2011 John Crispin + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +/* cgu registers */ +#define LTQ_CGU_SYS 0x0010 + +unsigned int ltq_get_io_region_clock(void) +{ + return CLOCK_133M; +} +EXPORT_SYMBOL(ltq_get_io_region_clock); + +unsigned int ltq_get_fpi_bus_clock(int fpi) +{ + return CLOCK_133M; +} +EXPORT_SYMBOL(ltq_get_fpi_bus_clock); + +unsigned int ltq_get_cpu_hz(void) +{ + if (ltq_cgu_r32(LTQ_CGU_SYS) & (1 << 5)) + return CLOCK_266M; + else + return CLOCK_133M; +} +EXPORT_SYMBOL(ltq_get_cpu_hz); + +unsigned int ltq_get_fpi_hz(void) +{ + return CLOCK_133M; +} +EXPORT_SYMBOL(ltq_get_fpi_hz); diff --git a/trunk/arch/mips/lantiq/xway/clk-xway.c b/trunk/arch/mips/lantiq/xway/clk-xway.c new file mode 100644 index 000000000000..696b1a3e0642 --- /dev/null +++ b/trunk/arch/mips/lantiq/xway/clk-xway.c @@ -0,0 +1,223 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +static unsigned int ltq_ram_clocks[] = { + CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M }; +#define DDR_HZ ltq_ram_clocks[ltq_cgu_r32(LTQ_CGU_SYS) & 0x3] + +#define BASIC_FREQUENCY_1 35328000 +#define BASIC_FREQUENCY_2 36000000 +#define BASIS_REQUENCY_USB 12000000 + +#define GET_BITS(x, msb, lsb) \ + (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb)) + +#define LTQ_CGU_PLL0_CFG 0x0004 +#define LTQ_CGU_PLL1_CFG 0x0008 +#define LTQ_CGU_PLL2_CFG 0x000C +#define LTQ_CGU_SYS 0x0010 +#define LTQ_CGU_UPDATE 0x0014 +#define LTQ_CGU_IF_CLK 0x0018 +#define LTQ_CGU_OSC_CON 0x001C +#define LTQ_CGU_SMD 0x0020 +#define LTQ_CGU_CT1SR 0x0028 +#define LTQ_CGU_CT2SR 0x002C +#define LTQ_CGU_PCMCR 0x0030 +#define LTQ_CGU_PCI_CR 0x0034 +#define LTQ_CGU_PD_PC 0x0038 +#define LTQ_CGU_FMR 0x003C + +#define CGU_PLL0_PHASE_DIVIDER_ENABLE \ + (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 31)) +#define CGU_PLL0_BYPASS \ + (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 30)) +#define CGU_PLL0_CFG_DSMSEL \ + (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 28)) +#define CGU_PLL0_CFG_FRAC_EN \ + (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 27)) +#define CGU_PLL1_SRC \ + (ltq_cgu_r32(LTQ_CGU_PLL1_CFG) & (1 << 31)) +#define CGU_PLL2_PHASE_DIVIDER_ENABLE \ + (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & (1 << 20)) +#define CGU_SYS_FPI_SEL (1 << 6) +#define CGU_SYS_DDR_SEL 0x3 +#define CGU_PLL0_SRC (1 << 29) + +#define CGU_PLL0_CFG_PLLK GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 26, 17) +#define CGU_PLL0_CFG_PLLN GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 12, 6) +#define CGU_PLL0_CFG_PLLM GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 5, 2) +#define CGU_PLL2_SRC GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 18, 17) +#define CGU_PLL2_CFG_INPUT_DIV GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 16, 13) + +static unsigned int ltq_get_pll0_fdiv(void); + +static inline unsigned int get_input_clock(int pll) +{ + switch (pll) { + case 0: + if (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & CGU_PLL0_SRC) + return BASIS_REQUENCY_USB; + else if (CGU_PLL0_PHASE_DIVIDER_ENABLE) + return BASIC_FREQUENCY_1; + else + return BASIC_FREQUENCY_2; + case 1: + if (CGU_PLL1_SRC) + return BASIS_REQUENCY_USB; + else if (CGU_PLL0_PHASE_DIVIDER_ENABLE) + return BASIC_FREQUENCY_1; + else + return BASIC_FREQUENCY_2; + case 2: + switch (CGU_PLL2_SRC) { + case 0: + return ltq_get_pll0_fdiv(); + case 1: + return CGU_PLL2_PHASE_DIVIDER_ENABLE ? + BASIC_FREQUENCY_1 : + BASIC_FREQUENCY_2; + case 2: + return BASIS_REQUENCY_USB; + } + default: + return 0; + } +} + +static inline unsigned int cal_dsm(int pll, unsigned int num, unsigned int den) +{ + u64 res, clock = get_input_clock(pll); + + res = num * clock; + do_div(res, den); + return res; +} + +static inline unsigned int mash_dsm(int pll, unsigned int M, unsigned int N, + unsigned int K) +{ + unsigned int num = ((N + 1) << 10) + K; + unsigned int den = (M + 1) << 10; + + return cal_dsm(pll, num, den); +} + +static inline unsigned int ssff_dsm_1(int pll, unsigned int M, unsigned int N, + unsigned int K) +{ + unsigned int num = ((N + 1) << 11) + K + 512; + unsigned int den = (M + 1) << 11; + + return cal_dsm(pll, num, den); +} + +static inline unsigned int ssff_dsm_2(int pll, unsigned int M, unsigned int N, + unsigned int K) +{ + unsigned int num = K >= 512 ? + ((N + 1) << 12) + K - 512 : ((N + 1) << 12) + K + 3584; + unsigned int den = (M + 1) << 12; + + return cal_dsm(pll, num, den); +} + +static inline unsigned int dsm(int pll, unsigned int M, unsigned int N, + unsigned int K, unsigned int dsmsel, unsigned int phase_div_en) +{ + if (!dsmsel) + return mash_dsm(pll, M, N, K); + else if (!phase_div_en) + return mash_dsm(pll, M, N, K); + else + return ssff_dsm_2(pll, M, N, K); +} + +static inline unsigned int ltq_get_pll0_fosc(void) +{ + if (CGU_PLL0_BYPASS) + return get_input_clock(0); + else + return !CGU_PLL0_CFG_FRAC_EN + ? dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, 0, + CGU_PLL0_CFG_DSMSEL, + CGU_PLL0_PHASE_DIVIDER_ENABLE) + : dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, + CGU_PLL0_CFG_PLLK, CGU_PLL0_CFG_DSMSEL, + CGU_PLL0_PHASE_DIVIDER_ENABLE); +} + +static unsigned int ltq_get_pll0_fdiv(void) +{ + unsigned int div = CGU_PLL2_CFG_INPUT_DIV + 1; + + return (ltq_get_pll0_fosc() + (div >> 1)) / div; +} + +unsigned int ltq_get_io_region_clock(void) +{ + unsigned int ret = ltq_get_pll0_fosc(); + + switch (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & CGU_SYS_DDR_SEL) { + default: + case 0: + return (ret + 1) / 2; + case 1: + return (ret * 2 + 2) / 5; + case 2: + return (ret + 1) / 3; + case 3: + return (ret + 2) / 4; + } +} +EXPORT_SYMBOL(ltq_get_io_region_clock); + +unsigned int ltq_get_fpi_bus_clock(int fpi) +{ + unsigned int ret = ltq_get_io_region_clock(); + + if ((fpi == 2) && (ltq_cgu_r32(LTQ_CGU_SYS) & CGU_SYS_FPI_SEL)) + ret >>= 1; + return ret; +} +EXPORT_SYMBOL(ltq_get_fpi_bus_clock); + +unsigned int ltq_get_cpu_hz(void) +{ + switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0xc) { + case 0: + return CLOCK_333M; + case 4: + return DDR_HZ; + case 8: + return DDR_HZ << 1; + default: + return DDR_HZ >> 1; + } +} +EXPORT_SYMBOL(ltq_get_cpu_hz); + +unsigned int ltq_get_fpi_hz(void) +{ + unsigned int ddr_clock = DDR_HZ; + + if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40) + return ddr_clock >> 1; + return ddr_clock; +} +EXPORT_SYMBOL(ltq_get_fpi_hz); diff --git a/trunk/arch/mips/lantiq/xway/clk.c b/trunk/arch/mips/lantiq/xway/clk.c deleted file mode 100644 index 9aa17f79a742..000000000000 --- a/trunk/arch/mips/lantiq/xway/clk.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2010 John Crispin - */ - -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "../clk.h" - -static unsigned int ram_clocks[] = { - CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M }; -#define DDR_HZ ram_clocks[ltq_cgu_r32(CGU_SYS) & 0x3] - -/* legacy xway clock */ -#define CGU_SYS 0x10 - -/* vr9 clock */ -#define CGU_SYS_VR9 0x0c -#define CGU_IF_CLK_VR9 0x24 - -unsigned long ltq_danube_fpi_hz(void) -{ - unsigned long ddr_clock = DDR_HZ; - - if (ltq_cgu_r32(CGU_SYS) & 0x40) - return ddr_clock >> 1; - return ddr_clock; -} - -unsigned long ltq_danube_cpu_hz(void) -{ - switch (ltq_cgu_r32(CGU_SYS) & 0xc) { - case 0: - return CLOCK_333M; - case 4: - return DDR_HZ; - case 8: - return DDR_HZ << 1; - default: - return DDR_HZ >> 1; - } -} - -unsigned long ltq_ar9_sys_hz(void) -{ - if (((ltq_cgu_r32(CGU_SYS) >> 3) & 0x3) == 0x2) - return CLOCK_393M; - return CLOCK_333M; -} - -unsigned long ltq_ar9_fpi_hz(void) -{ - unsigned long sys = ltq_ar9_sys_hz(); - - if (ltq_cgu_r32(CGU_SYS) & BIT(0)) - return sys; - return sys >> 1; -} - -unsigned long ltq_ar9_cpu_hz(void) -{ - if (ltq_cgu_r32(CGU_SYS) & BIT(2)) - return ltq_ar9_fpi_hz(); - else - return ltq_ar9_sys_hz(); -} - -unsigned long ltq_vr9_cpu_hz(void) -{ - unsigned int cpu_sel; - unsigned long clk; - - cpu_sel = (ltq_cgu_r32(CGU_SYS_VR9) >> 4) & 0xf; - - switch (cpu_sel) { - case 0: - clk = CLOCK_600M; - break; - case 1: - clk = CLOCK_500M; - break; - case 2: - clk = CLOCK_393M; - break; - case 3: - clk = CLOCK_333M; - break; - case 5: - case 6: - clk = CLOCK_196_608M; - break; - case 7: - clk = CLOCK_167M; - break; - case 4: - case 8: - case 9: - clk = CLOCK_125M; - break; - default: - clk = 0; - break; - } - - return clk; -} - -unsigned long ltq_vr9_fpi_hz(void) -{ - unsigned int ocp_sel, cpu_clk; - unsigned long clk; - - cpu_clk = ltq_vr9_cpu_hz(); - ocp_sel = ltq_cgu_r32(CGU_SYS_VR9) & 0x3; - - switch (ocp_sel) { - case 0: - /* OCP ratio 1 */ - clk = cpu_clk; - break; - case 2: - /* OCP ratio 2 */ - clk = cpu_clk / 2; - break; - case 3: - /* OCP ratio 2.5 */ - clk = (cpu_clk * 2) / 5; - break; - case 4: - /* OCP ratio 3 */ - clk = cpu_clk / 3; - break; - default: - clk = 0; - break; - } - - return clk; -} diff --git a/trunk/arch/mips/lantiq/xway/devices.c b/trunk/arch/mips/lantiq/xway/devices.c new file mode 100644 index 000000000000..d614aa7ff07f --- /dev/null +++ b/trunk/arch/mips/lantiq/xway/devices.c @@ -0,0 +1,119 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "devices.h" + +/* gpio */ +static struct resource ltq_gpio_resource[] = { + { + .name = "gpio0", + .start = LTQ_GPIO0_BASE_ADDR, + .end = LTQ_GPIO0_BASE_ADDR + LTQ_GPIO_SIZE - 1, + .flags = IORESOURCE_MEM, + }, { + .name = "gpio1", + .start = LTQ_GPIO1_BASE_ADDR, + .end = LTQ_GPIO1_BASE_ADDR + LTQ_GPIO_SIZE - 1, + .flags = IORESOURCE_MEM, + }, { + .name = "gpio2", + .start = LTQ_GPIO2_BASE_ADDR, + .end = LTQ_GPIO2_BASE_ADDR + LTQ_GPIO_SIZE - 1, + .flags = IORESOURCE_MEM, + } +}; + +void __init ltq_register_gpio(void) +{ + platform_device_register_simple("ltq_gpio", 0, + <q_gpio_resource[0], 1); + platform_device_register_simple("ltq_gpio", 1, + <q_gpio_resource[1], 1); + + /* AR9 and VR9 have an extra gpio block */ + if (ltq_is_ar9() || ltq_is_vr9()) { + platform_device_register_simple("ltq_gpio", 2, + <q_gpio_resource[2], 1); + } +} + +/* serial to parallel conversion */ +static struct resource ltq_stp_resource = { + .name = "stp", + .start = LTQ_STP_BASE_ADDR, + .end = LTQ_STP_BASE_ADDR + LTQ_STP_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +void __init ltq_register_gpio_stp(void) +{ + platform_device_register_simple("ltq_stp", 0, <q_stp_resource, 1); +} + +/* asc ports - amazon se has its own serial mapping */ +static struct resource ltq_ase_asc_resources[] = { + { + .name = "asc0", + .start = LTQ_ASC1_BASE_ADDR, + .end = LTQ_ASC1_BASE_ADDR + LTQ_ASC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + IRQ_RES(tx, LTQ_ASC_ASE_TIR), + IRQ_RES(rx, LTQ_ASC_ASE_RIR), + IRQ_RES(err, LTQ_ASC_ASE_EIR), +}; + +void __init ltq_register_ase_asc(void) +{ + platform_device_register_simple("ltq_asc", 0, + ltq_ase_asc_resources, ARRAY_SIZE(ltq_ase_asc_resources)); +} + +/* ethernet */ +static struct resource ltq_etop_resources = { + .name = "etop", + .start = LTQ_ETOP_BASE_ADDR, + .end = LTQ_ETOP_BASE_ADDR + LTQ_ETOP_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device ltq_etop = { + .name = "ltq_etop", + .resource = <q_etop_resources, + .num_resources = 1, +}; + +void __init +ltq_register_etop(struct ltq_eth_data *eth) +{ + if (eth) { + ltq_etop.dev.platform_data = eth; + platform_device_register(<q_etop); + } +} diff --git a/trunk/arch/mips/lantiq/xway/devices.h b/trunk/arch/mips/lantiq/xway/devices.h new file mode 100644 index 000000000000..e90493471bc1 --- /dev/null +++ b/trunk/arch/mips/lantiq/xway/devices.h @@ -0,0 +1,20 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#ifndef _LTQ_DEVICES_XWAY_H__ +#define _LTQ_DEVICES_XWAY_H__ + +#include "../devices.h" +#include + +extern void ltq_register_gpio(void); +extern void ltq_register_gpio_stp(void); +extern void ltq_register_ase_asc(void); +extern void ltq_register_etop(struct ltq_eth_data *eth); + +#endif diff --git a/trunk/arch/mips/lantiq/xway/dma.c b/trunk/arch/mips/lantiq/xway/dma.c index 55d2c4fa4714..b210e936c7c3 100644 --- a/trunk/arch/mips/lantiq/xway/dma.c +++ b/trunk/arch/mips/lantiq/xway/dma.c @@ -19,8 +19,7 @@ #include #include #include -#include -#include +#include #include #include @@ -56,6 +55,13 @@ #define ltq_dma_w32_mask(x, y, z) ltq_w32_mask(x, y, \ ltq_dma_membase + (z)) +static struct resource ltq_dma_resource = { + .name = "dma", + .start = LTQ_DMA_BASE_ADDR, + .end = LTQ_DMA_BASE_ADDR + LTQ_DMA_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + static void __iomem *ltq_dma_membase; void @@ -209,28 +215,27 @@ ltq_dma_init_port(int p) } EXPORT_SYMBOL_GPL(ltq_dma_init_port); -static int __devinit -ltq_dma_init(struct platform_device *pdev) +int __init +ltq_dma_init(void) { - struct clk *clk; - struct resource *res; int i; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - panic("Failed to get dma resource"); + /* insert and request the memory region */ + if (insert_resource(&iomem_resource, <q_dma_resource) < 0) + panic("Failed to insert dma memory"); + + if (request_mem_region(ltq_dma_resource.start, + resource_size(<q_dma_resource), "dma") < 0) + panic("Failed to request dma memory"); /* remap dma register range */ - ltq_dma_membase = devm_request_and_ioremap(&pdev->dev, res); + ltq_dma_membase = ioremap_nocache(ltq_dma_resource.start, + resource_size(<q_dma_resource)); if (!ltq_dma_membase) - panic("Failed to remap dma resource"); + panic("Failed to remap dma memory"); /* power up and reset the dma engine */ - clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(clk)) - panic("Failed to get dma clock"); - - clk_enable(clk); + ltq_pmu_enable(PMU_DMA); ltq_dma_w32_mask(0, DMA_RESET, LTQ_DMA_CTRL); /* disable all interrupts */ @@ -243,29 +248,7 @@ ltq_dma_init(struct platform_device *pdev) ltq_dma_w32(DMA_POLL | DMA_CLK_DIV4, LTQ_DMA_CPOLL); ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL); } - dev_info(&pdev->dev, "init done\n"); return 0; } -static const struct of_device_id dma_match[] = { - { .compatible = "lantiq,dma-xway" }, - {}, -}; -MODULE_DEVICE_TABLE(of, dma_match); - -static struct platform_driver dma_driver = { - .probe = ltq_dma_init, - .driver = { - .name = "dma-xway", - .owner = THIS_MODULE, - .of_match_table = dma_match, - }, -}; - -int __init -dma_init(void) -{ - return platform_driver_register(&dma_driver); -} - -postcore_initcall(dma_init); +postcore_initcall(ltq_dma_init); diff --git a/trunk/arch/mips/lantiq/xway/ebu.c b/trunk/arch/mips/lantiq/xway/ebu.c new file mode 100644 index 000000000000..862e3e830680 --- /dev/null +++ b/trunk/arch/mips/lantiq/xway/ebu.c @@ -0,0 +1,52 @@ +/* + * 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. + * + * EBU - the external bus unit attaches PCI, NOR and NAND + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include + +#include + +/* all access to the ebu must be locked */ +DEFINE_SPINLOCK(ebu_lock); +EXPORT_SYMBOL_GPL(ebu_lock); + +static struct resource ltq_ebu_resource = { + .name = "ebu", + .start = LTQ_EBU_BASE_ADDR, + .end = LTQ_EBU_BASE_ADDR + LTQ_EBU_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +/* remapped base addr of the clock unit and external bus unit */ +void __iomem *ltq_ebu_membase; + +static int __init lantiq_ebu_init(void) +{ + /* insert and request the memory region */ + if (insert_resource(&iomem_resource, <q_ebu_resource) < 0) + panic("Failed to insert ebu memory"); + + if (request_mem_region(ltq_ebu_resource.start, + resource_size(<q_ebu_resource), "ebu") < 0) + panic("Failed to request ebu memory"); + + /* remap ebu register range */ + ltq_ebu_membase = ioremap_nocache(ltq_ebu_resource.start, + resource_size(<q_ebu_resource)); + if (!ltq_ebu_membase) + panic("Failed to remap ebu memory"); + + /* make sure to unprotect the memory region where flash is located */ + ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0); + return 0; +} + +postcore_initcall(lantiq_ebu_init); diff --git a/trunk/arch/mips/lantiq/xway/gpio.c b/trunk/arch/mips/lantiq/xway/gpio.c index 2ab39e93d9be..c429a5bc080f 100644 --- a/trunk/arch/mips/lantiq/xway/gpio.c +++ b/trunk/arch/mips/lantiq/xway/gpio.c @@ -36,6 +36,18 @@ struct ltq_gpio { static struct ltq_gpio ltq_gpio_port[MAX_PORTS]; +int gpio_to_irq(unsigned int gpio) +{ + return -EINVAL; +} +EXPORT_SYMBOL(gpio_to_irq); + +int irq_to_gpio(unsigned int gpio) +{ + return -EINVAL; +} +EXPORT_SYMBOL(irq_to_gpio); + int ltq_gpio_request(unsigned int pin, unsigned int alt0, unsigned int alt1, unsigned int dir, const char *name) { diff --git a/trunk/arch/mips/lantiq/xway/gpio_ebu.c b/trunk/arch/mips/lantiq/xway/gpio_ebu.c new file mode 100644 index 000000000000..aae17170472f --- /dev/null +++ b/trunk/arch/mips/lantiq/xway/gpio_ebu.c @@ -0,0 +1,126 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * By attaching hardware latches to the EBU it is possible to create output + * only gpios. This driver configures a special memory address, which when + * written to outputs 16 bit to the latches. + */ + +#define LTQ_EBU_BUSCON 0x1e7ff /* 16 bit access, slowest timing */ +#define LTQ_EBU_WP 0x80000000 /* write protect bit */ + +/* we keep a shadow value of the last value written to the ebu */ +static int ltq_ebu_gpio_shadow = 0x0; +static void __iomem *ltq_ebu_gpio_membase; + +static void ltq_ebu_apply(void) +{ + unsigned long flags; + + spin_lock_irqsave(&ebu_lock, flags); + ltq_ebu_w32(LTQ_EBU_BUSCON, LTQ_EBU_BUSCON1); + *((__u16 *)ltq_ebu_gpio_membase) = ltq_ebu_gpio_shadow; + ltq_ebu_w32(LTQ_EBU_BUSCON | LTQ_EBU_WP, LTQ_EBU_BUSCON1); + spin_unlock_irqrestore(&ebu_lock, flags); +} + +static void ltq_ebu_set(struct gpio_chip *chip, unsigned offset, int value) +{ + if (value) + ltq_ebu_gpio_shadow |= (1 << offset); + else + ltq_ebu_gpio_shadow &= ~(1 << offset); + ltq_ebu_apply(); +} + +static int ltq_ebu_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + ltq_ebu_set(chip, offset, value); + + return 0; +} + +static struct gpio_chip ltq_ebu_chip = { + .label = "ltq_ebu", + .direction_output = ltq_ebu_direction_output, + .set = ltq_ebu_set, + .base = 72, + .ngpio = 16, + .can_sleep = 1, + .owner = THIS_MODULE, +}; + +static int ltq_ebu_probe(struct platform_device *pdev) +{ + int ret = 0; + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (!res) { + dev_err(&pdev->dev, "failed to get memory resource\n"); + return -ENOENT; + } + + res = devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), dev_name(&pdev->dev)); + if (!res) { + dev_err(&pdev->dev, "failed to request memory resource\n"); + return -EBUSY; + } + + ltq_ebu_gpio_membase = devm_ioremap_nocache(&pdev->dev, res->start, + resource_size(res)); + if (!ltq_ebu_gpio_membase) { + dev_err(&pdev->dev, "Failed to ioremap mem region\n"); + return -ENOMEM; + } + + /* grab the default shadow value passed form the platform code */ + ltq_ebu_gpio_shadow = (unsigned int) pdev->dev.platform_data; + + /* tell the ebu controller which memory address we will be using */ + ltq_ebu_w32(pdev->resource->start | 0x1, LTQ_EBU_ADDRSEL1); + + /* write protect the region */ + ltq_ebu_w32(LTQ_EBU_BUSCON | LTQ_EBU_WP, LTQ_EBU_BUSCON1); + + ret = gpiochip_add(<q_ebu_chip); + if (!ret) + ltq_ebu_apply(); + return ret; +} + +static struct platform_driver ltq_ebu_driver = { + .probe = ltq_ebu_probe, + .driver = { + .name = "ltq_ebu", + .owner = THIS_MODULE, + }, +}; + +static int __init ltq_ebu_init(void) +{ + int ret = platform_driver_register(<q_ebu_driver); + + if (ret) + pr_info("ltq_ebu : Error registering platform driver!"); + return ret; +} + +postcore_initcall(ltq_ebu_init); diff --git a/trunk/arch/mips/lantiq/xway/gpio_stp.c b/trunk/arch/mips/lantiq/xway/gpio_stp.c new file mode 100644 index 000000000000..fd07d87adaa9 --- /dev/null +++ b/trunk/arch/mips/lantiq/xway/gpio_stp.c @@ -0,0 +1,157 @@ +/* + * 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. + * + * Copyright (C) 2007 John Crispin + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define LTQ_STP_CON0 0x00 +#define LTQ_STP_CON1 0x04 +#define LTQ_STP_CPU0 0x08 +#define LTQ_STP_CPU1 0x0C +#define LTQ_STP_AR 0x10 + +#define LTQ_STP_CON_SWU (1 << 31) +#define LTQ_STP_2HZ 0 +#define LTQ_STP_4HZ (1 << 23) +#define LTQ_STP_8HZ (2 << 23) +#define LTQ_STP_10HZ (3 << 23) +#define LTQ_STP_SPEED_MASK (0xf << 23) +#define LTQ_STP_UPD_FPI (1 << 31) +#define LTQ_STP_UPD_MASK (3 << 30) +#define LTQ_STP_ADSL_SRC (3 << 24) + +#define LTQ_STP_GROUP0 (1 << 0) + +#define LTQ_STP_RISING 0 +#define LTQ_STP_FALLING (1 << 26) +#define LTQ_STP_EDGE_MASK (1 << 26) + +#define ltq_stp_r32(reg) __raw_readl(ltq_stp_membase + reg) +#define ltq_stp_w32(val, reg) __raw_writel(val, ltq_stp_membase + reg) +#define ltq_stp_w32_mask(clear, set, reg) \ + ltq_w32((ltq_r32(ltq_stp_membase + reg) & ~(clear)) | (set), \ + ltq_stp_membase + (reg)) + +static int ltq_stp_shadow = 0xffff; +static void __iomem *ltq_stp_membase; + +static void ltq_stp_set(struct gpio_chip *chip, unsigned offset, int value) +{ + if (value) + ltq_stp_shadow |= (1 << offset); + else + ltq_stp_shadow &= ~(1 << offset); + ltq_stp_w32(ltq_stp_shadow, LTQ_STP_CPU0); +} + +static int ltq_stp_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + ltq_stp_set(chip, offset, value); + + return 0; +} + +static struct gpio_chip ltq_stp_chip = { + .label = "ltq_stp", + .direction_output = ltq_stp_direction_output, + .set = ltq_stp_set, + .base = 48, + .ngpio = 24, + .can_sleep = 1, + .owner = THIS_MODULE, +}; + +static int ltq_stp_hw_init(void) +{ + /* the 3 pins used to control the external stp */ + ltq_gpio_request(4, 1, 0, 1, "stp-st"); + ltq_gpio_request(5, 1, 0, 1, "stp-d"); + ltq_gpio_request(6, 1, 0, 1, "stp-sh"); + + /* sane defaults */ + ltq_stp_w32(0, LTQ_STP_AR); + ltq_stp_w32(0, LTQ_STP_CPU0); + ltq_stp_w32(0, LTQ_STP_CPU1); + ltq_stp_w32(LTQ_STP_CON_SWU, LTQ_STP_CON0); + ltq_stp_w32(0, LTQ_STP_CON1); + + /* rising or falling edge */ + ltq_stp_w32_mask(LTQ_STP_EDGE_MASK, LTQ_STP_FALLING, LTQ_STP_CON0); + + /* per default stp 15-0 are set */ + ltq_stp_w32_mask(0, LTQ_STP_GROUP0, LTQ_STP_CON1); + + /* stp are update periodically by the FPI bus */ + ltq_stp_w32_mask(LTQ_STP_UPD_MASK, LTQ_STP_UPD_FPI, LTQ_STP_CON1); + + /* set stp update speed */ + ltq_stp_w32_mask(LTQ_STP_SPEED_MASK, LTQ_STP_8HZ, LTQ_STP_CON1); + + /* tell the hardware that pin (led) 0 and 1 are controlled + * by the dsl arc + */ + ltq_stp_w32_mask(0, LTQ_STP_ADSL_SRC, LTQ_STP_CON0); + + ltq_pmu_enable(PMU_LED); + return 0; +} + +static int __devinit ltq_stp_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + int ret = 0; + + if (!res) + return -ENOENT; + res = devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), dev_name(&pdev->dev)); + if (!res) { + dev_err(&pdev->dev, "failed to request STP memory\n"); + return -EBUSY; + } + ltq_stp_membase = devm_ioremap_nocache(&pdev->dev, res->start, + resource_size(res)); + if (!ltq_stp_membase) { + dev_err(&pdev->dev, "failed to remap STP memory\n"); + return -ENOMEM; + } + ret = gpiochip_add(<q_stp_chip); + if (!ret) + ret = ltq_stp_hw_init(); + + return ret; +} + +static struct platform_driver ltq_stp_driver = { + .probe = ltq_stp_probe, + .driver = { + .name = "ltq_stp", + .owner = THIS_MODULE, + }, +}; + +int __init ltq_stp_init(void) +{ + int ret = platform_driver_register(<q_stp_driver); + + if (ret) + pr_info("ltq_stp: error registering platform driver"); + return ret; +} + +postcore_initcall(ltq_stp_init); diff --git a/trunk/arch/mips/lantiq/xway/mach-easy50601.c b/trunk/arch/mips/lantiq/xway/mach-easy50601.c new file mode 100644 index 000000000000..d5aaf637ab19 --- /dev/null +++ b/trunk/arch/mips/lantiq/xway/mach-easy50601.c @@ -0,0 +1,57 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "../machtypes.h" +#include "devices.h" + +static struct mtd_partition easy50601_partitions[] = { + { + .name = "uboot", + .offset = 0x0, + .size = 0x10000, + }, + { + .name = "uboot_env", + .offset = 0x10000, + .size = 0x10000, + }, + { + .name = "linux", + .offset = 0x20000, + .size = 0xE0000, + }, + { + .name = "rootfs", + .offset = 0x100000, + .size = 0x300000, + }, +}; + +static struct physmap_flash_data easy50601_flash_data = { + .nr_parts = ARRAY_SIZE(easy50601_partitions), + .parts = easy50601_partitions, +}; + +static void __init easy50601_init(void) +{ + ltq_register_nor(&easy50601_flash_data); +} + +MIPS_MACHINE(LTQ_MACH_EASY50601, + "EASY50601", + "EASY50601 Eval Board", + easy50601_init); diff --git a/trunk/arch/mips/lantiq/xway/mach-easy50712.c b/trunk/arch/mips/lantiq/xway/mach-easy50712.c new file mode 100644 index 000000000000..ea5027b3239d --- /dev/null +++ b/trunk/arch/mips/lantiq/xway/mach-easy50712.c @@ -0,0 +1,74 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../machtypes.h" +#include "devices.h" + +static struct mtd_partition easy50712_partitions[] = { + { + .name = "uboot", + .offset = 0x0, + .size = 0x10000, + }, + { + .name = "uboot_env", + .offset = 0x10000, + .size = 0x10000, + }, + { + .name = "linux", + .offset = 0x20000, + .size = 0xe0000, + }, + { + .name = "rootfs", + .offset = 0x100000, + .size = 0x300000, + }, +}; + +static struct physmap_flash_data easy50712_flash_data = { + .nr_parts = ARRAY_SIZE(easy50712_partitions), + .parts = easy50712_partitions, +}; + +static struct ltq_pci_data ltq_pci_data = { + .clock = PCI_CLOCK_INT, + .gpio = PCI_GNT1 | PCI_REQ1, + .irq = { + [14] = INT_NUM_IM0_IRL0 + 22, + }, +}; + +static struct ltq_eth_data ltq_eth_data = { + .mii_mode = PHY_INTERFACE_MODE_MII, +}; + +static void __init easy50712_init(void) +{ + ltq_register_gpio_stp(); + ltq_register_nor(&easy50712_flash_data); + ltq_register_pci(<q_pci_data); + ltq_register_etop(<q_eth_data); +} + +MIPS_MACHINE(LTQ_MACH_EASY50712, + "EASY50712", + "EASY50712 Eval Board", + easy50712_init); diff --git a/trunk/arch/mips/lantiq/xway/pmu.c b/trunk/arch/mips/lantiq/xway/pmu.c new file mode 100644 index 000000000000..fe85361e032e --- /dev/null +++ b/trunk/arch/mips/lantiq/xway/pmu.c @@ -0,0 +1,69 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include + +#include + +/* PMU - the power management unit allows us to turn part of the core + * on and off + */ + +/* the enable / disable registers */ +#define LTQ_PMU_PWDCR 0x1C +#define LTQ_PMU_PWDSR 0x20 + +#define ltq_pmu_w32(x, y) ltq_w32((x), ltq_pmu_membase + (y)) +#define ltq_pmu_r32(x) ltq_r32(ltq_pmu_membase + (x)) + +static struct resource ltq_pmu_resource = { + .name = "pmu", + .start = LTQ_PMU_BASE_ADDR, + .end = LTQ_PMU_BASE_ADDR + LTQ_PMU_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static void __iomem *ltq_pmu_membase; + +void ltq_pmu_enable(unsigned int module) +{ + int err = 1000000; + + ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) & ~module, LTQ_PMU_PWDCR); + do {} while (--err && (ltq_pmu_r32(LTQ_PMU_PWDSR) & module)); + + if (!err) + panic("activating PMU module failed!"); +} +EXPORT_SYMBOL(ltq_pmu_enable); + +void ltq_pmu_disable(unsigned int module) +{ + ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) | module, LTQ_PMU_PWDCR); +} +EXPORT_SYMBOL(ltq_pmu_disable); + +int __init ltq_pmu_init(void) +{ + if (insert_resource(&iomem_resource, <q_pmu_resource) < 0) + panic("Failed to insert pmu memory"); + + if (request_mem_region(ltq_pmu_resource.start, + resource_size(<q_pmu_resource), "pmu") < 0) + panic("Failed to request pmu memory"); + + ltq_pmu_membase = ioremap_nocache(ltq_pmu_resource.start, + resource_size(<q_pmu_resource)); + if (!ltq_pmu_membase) + panic("Failed to remap pmu memory"); + return 0; +} + +core_initcall(ltq_pmu_init); diff --git a/trunk/arch/mips/lantiq/xway/prom-ase.c b/trunk/arch/mips/lantiq/xway/prom-ase.c new file mode 100644 index 000000000000..ae4959ae865c --- /dev/null +++ b/trunk/arch/mips/lantiq/xway/prom-ase.c @@ -0,0 +1,39 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include + +#include + +#include "../prom.h" + +#define SOC_AMAZON_SE "Amazon_SE" + +#define PART_SHIFT 12 +#define PART_MASK 0x0FFFFFFF +#define REV_SHIFT 28 +#define REV_MASK 0xF0000000 + +void __init ltq_soc_detect(struct ltq_soc_info *i) +{ + i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT; + i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT; + switch (i->partnum) { + case SOC_ID_AMAZON_SE: + i->name = SOC_AMAZON_SE; + i->type = SOC_TYPE_AMAZON_SE; + break; + + default: + unreachable(); + break; + } +} diff --git a/trunk/arch/mips/lantiq/xway/prom-xway.c b/trunk/arch/mips/lantiq/xway/prom-xway.c new file mode 100644 index 000000000000..2228133ca356 --- /dev/null +++ b/trunk/arch/mips/lantiq/xway/prom-xway.c @@ -0,0 +1,54 @@ +/* + * 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. + * + * Copyright (C) 2010 John Crispin + */ + +#include +#include +#include +#include + +#include + +#include "../prom.h" + +#define SOC_DANUBE "Danube" +#define SOC_TWINPASS "Twinpass" +#define SOC_AR9 "AR9" + +#define PART_SHIFT 12 +#define PART_MASK 0x0FFFFFFF +#define REV_SHIFT 28 +#define REV_MASK 0xF0000000 + +void __init ltq_soc_detect(struct ltq_soc_info *i) +{ + i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT; + i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT; + switch (i->partnum) { + case SOC_ID_DANUBE1: + case SOC_ID_DANUBE2: + i->name = SOC_DANUBE; + i->type = SOC_TYPE_DANUBE; + break; + + case SOC_ID_TWINPASS: + i->name = SOC_TWINPASS; + i->type = SOC_TYPE_DANUBE; + break; + + case SOC_ID_ARX188: + case SOC_ID_ARX168: + case SOC_ID_ARX182: + i->name = SOC_AR9; + i->type = SOC_TYPE_AR9; + break; + + default: + unreachable(); + break; + } +} diff --git a/trunk/arch/mips/lantiq/xway/prom.c b/trunk/arch/mips/lantiq/xway/prom.c deleted file mode 100644 index 248429ab2622..000000000000 --- a/trunk/arch/mips/lantiq/xway/prom.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2010 John Crispin - */ - -#include -#include -#include -#include - -#include - -#include "../prom.h" - -#define SOC_DANUBE "Danube" -#define SOC_TWINPASS "Twinpass" -#define SOC_AMAZON_SE "Amazon_SE" -#define SOC_AR9 "AR9" -#define SOC_GR9 "GR9" -#define SOC_VR9 "VR9" - -#define COMP_DANUBE "lantiq,danube" -#define COMP_TWINPASS "lantiq,twinpass" -#define COMP_AMAZON_SE "lantiq,ase" -#define COMP_AR9 "lantiq,ar9" -#define COMP_GR9 "lantiq,gr9" -#define COMP_VR9 "lantiq,vr9" - -#define PART_SHIFT 12 -#define PART_MASK 0x0FFFFFFF -#define REV_SHIFT 28 -#define REV_MASK 0xF0000000 - -void __init ltq_soc_detect(struct ltq_soc_info *i) -{ - i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT; - i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT; - sprintf(i->rev_type, "1.%d", i->rev); - switch (i->partnum) { - case SOC_ID_DANUBE1: - case SOC_ID_DANUBE2: - i->name = SOC_DANUBE; - i->type = SOC_TYPE_DANUBE; - i->compatible = COMP_DANUBE; - break; - - case SOC_ID_TWINPASS: - i->name = SOC_TWINPASS; - i->type = SOC_TYPE_DANUBE; - i->compatible = COMP_TWINPASS; - break; - - case SOC_ID_ARX188: - case SOC_ID_ARX168_1: - case SOC_ID_ARX168_2: - case SOC_ID_ARX182: - i->name = SOC_AR9; - i->type = SOC_TYPE_AR9; - i->compatible = COMP_AR9; - break; - - case SOC_ID_GRX188: - case SOC_ID_GRX168: - i->name = SOC_GR9; - i->type = SOC_TYPE_AR9; - i->compatible = COMP_GR9; - break; - - case SOC_ID_AMAZON_SE_1: - case SOC_ID_AMAZON_SE_2: -#ifdef CONFIG_PCI - panic("ase is only supported for non pci kernels"); -#endif - i->name = SOC_AMAZON_SE; - i->type = SOC_TYPE_AMAZON_SE; - i->compatible = COMP_AMAZON_SE; - break; - - case SOC_ID_VRX282: - case SOC_ID_VRX268: - case SOC_ID_VRX288: - i->name = SOC_VR9; - i->type = SOC_TYPE_VR9; - i->compatible = COMP_VR9; - break; - - case SOC_ID_GRX268: - case SOC_ID_GRX288: - i->name = SOC_GR9; - i->type = SOC_TYPE_VR9; - i->compatible = COMP_GR9; - break; - - case SOC_ID_VRX268_2: - case SOC_ID_VRX288_2: - i->name = SOC_VR9; - i->type = SOC_TYPE_VR9_2; - i->compatible = COMP_VR9; - break; - - case SOC_ID_GRX282_2: - case SOC_ID_GRX288_2: - i->name = SOC_GR9; - i->type = SOC_TYPE_VR9_2; - i->compatible = COMP_GR9; - break; - - default: - unreachable(); - break; - } -} diff --git a/trunk/arch/mips/lantiq/xway/reset.c b/trunk/arch/mips/lantiq/xway/reset.c index 22c55f73aa9d..8b66bd87f0c1 100644 --- a/trunk/arch/mips/lantiq/xway/reset.c +++ b/trunk/arch/mips/lantiq/xway/reset.c @@ -11,31 +11,26 @@ #include #include #include -#include -#include -#include - #include #include -#include "../prom.h" - #define ltq_rcu_w32(x, y) ltq_w32((x), ltq_rcu_membase + (y)) #define ltq_rcu_r32(x) ltq_r32(ltq_rcu_membase + (x)) -/* reset request register */ -#define RCU_RST_REQ 0x0010 -/* reset status register */ -#define RCU_RST_STAT 0x0014 +/* register definitions */ +#define LTQ_RCU_RST 0x0010 +#define LTQ_RCU_RST_ALL 0x40000000 + +#define LTQ_RCU_RST_STAT 0x0014 +#define LTQ_RCU_STAT_SHIFT 26 -/* reboot bit */ -#define RCU_RD_SRST BIT(30) -/* reset cause */ -#define RCU_STAT_SHIFT 26 -/* boot selection */ -#define RCU_BOOT_SEL_SHIFT 26 -#define RCU_BOOT_SEL_MASK 0x7 +static struct resource ltq_rcu_resource = { + .name = "rcu", + .start = LTQ_RCU_BASE_ADDR, + .end = LTQ_RCU_BASE_ADDR + LTQ_RCU_SIZE - 1, + .flags = IORESOURCE_MEM, +}; /* remapped base addr of the reset control unit */ static void __iomem *ltq_rcu_membase; @@ -43,64 +38,48 @@ static void __iomem *ltq_rcu_membase; /* This function is used by the watchdog driver */ int ltq_reset_cause(void) { - u32 val = ltq_rcu_r32(RCU_RST_STAT); - return val >> RCU_STAT_SHIFT; + u32 val = ltq_rcu_r32(LTQ_RCU_RST_STAT); + return val >> LTQ_RCU_STAT_SHIFT; } EXPORT_SYMBOL_GPL(ltq_reset_cause); -/* allow platform code to find out what source we booted from */ -unsigned char ltq_boot_select(void) -{ - u32 val = ltq_rcu_r32(RCU_RST_STAT); - return (val >> RCU_BOOT_SEL_SHIFT) & RCU_BOOT_SEL_MASK; -} - -/* reset a io domain for u micro seconds */ -void ltq_reset_once(unsigned int module, ulong u) -{ - ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) | module, RCU_RST_REQ); - udelay(u); - ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) & ~module, RCU_RST_REQ); -} - static void ltq_machine_restart(char *command) { + pr_notice("System restart\n"); local_irq_disable(); - ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) | RCU_RD_SRST, RCU_RST_REQ); + ltq_rcu_w32(ltq_rcu_r32(LTQ_RCU_RST) | LTQ_RCU_RST_ALL, LTQ_RCU_RST); unreachable(); } static void ltq_machine_halt(void) { + pr_notice("System halted.\n"); local_irq_disable(); unreachable(); } static void ltq_machine_power_off(void) { + pr_notice("Please turn off the power now.\n"); local_irq_disable(); unreachable(); } static int __init mips_reboot_setup(void) { - struct resource res; - struct device_node *np = - of_find_compatible_node(NULL, NULL, "lantiq,rcu-xway"); - - /* check if all the reset register range is available */ - if (!np) - panic("Failed to load reset resources from devicetree"); - - if (of_address_to_resource(np, 0, &res)) - panic("Failed to get rcu memory range"); + /* insert and request the memory region */ + if (insert_resource(&iomem_resource, <q_rcu_resource) < 0) + panic("Failed to insert rcu memory"); - if (request_mem_region(res.start, resource_size(&res), res.name) < 0) - pr_err("Failed to request rcu memory"); + if (request_mem_region(ltq_rcu_resource.start, + resource_size(<q_rcu_resource), "rcu") < 0) + panic("Failed to request rcu memory"); - ltq_rcu_membase = ioremap_nocache(res.start, resource_size(&res)); + /* remap rcu register range */ + ltq_rcu_membase = ioremap_nocache(ltq_rcu_resource.start, + resource_size(<q_rcu_resource)); if (!ltq_rcu_membase) - panic("Failed to remap core memory"); + panic("Failed to remap rcu memory"); _machine_restart = ltq_machine_restart; _machine_halt = ltq_machine_halt; diff --git a/trunk/arch/mips/lantiq/xway/setup-ase.c b/trunk/arch/mips/lantiq/xway/setup-ase.c new file mode 100644 index 000000000000..f6f326798a39 --- /dev/null +++ b/trunk/arch/mips/lantiq/xway/setup-ase.c @@ -0,0 +1,19 @@ +/* + * 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. + * + * Copyright (C) 2011 John Crispin + */ + +#include + +#include "../prom.h" +#include "devices.h" + +void __init ltq_soc_setup(void) +{ + ltq_register_ase_asc(); + ltq_register_gpio(); + ltq_register_wdt(); +} diff --git a/trunk/arch/mips/lantiq/xway/setup-xway.c b/trunk/arch/mips/lantiq/xway/setup-xway.c new file mode 100644 index 000000000000..c292f643a858 --- /dev/null +++ b/trunk/arch/mips/lantiq/xway/setup-xway.c @@ -0,0 +1,20 @@ +/* + * 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. + * + * Copyright (C) 2011 John Crispin + */ + +#include + +#include "../prom.h" +#include "devices.h" + +void __init ltq_soc_setup(void) +{ + ltq_register_asc(0); + ltq_register_asc(1); + ltq_register_gpio(); + ltq_register_wdt(); +} diff --git a/trunk/arch/mips/lantiq/xway/sysctrl.c b/trunk/arch/mips/lantiq/xway/sysctrl.c deleted file mode 100644 index 83780f7c842b..000000000000 --- a/trunk/arch/mips/lantiq/xway/sysctrl.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2011-2012 John Crispin - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include "../clk.h" -#include "../prom.h" - -/* clock control register */ -#define CGU_IFCCR 0x0018 -/* system clock register */ -#define CGU_SYS 0x0010 -/* pci control register */ -#define CGU_PCICR 0x0034 -/* ephy configuration register */ -#define CGU_EPHY 0x10 -/* power control register */ -#define PMU_PWDCR 0x1C -/* power status register */ -#define PMU_PWDSR 0x20 -/* power control register */ -#define PMU_PWDCR1 0x24 -/* power status register */ -#define PMU_PWDSR1 0x28 -/* power control register */ -#define PWDCR(x) ((x) ? (PMU_PWDCR1) : (PMU_PWDCR)) -/* power status register */ -#define PWDSR(x) ((x) ? (PMU_PWDSR1) : (PMU_PWDSR)) - -/* clock gates that we can en/disable */ -#define PMU_USB0_P BIT(0) -#define PMU_PCI BIT(4) -#define PMU_DMA BIT(5) -#define PMU_USB0 BIT(6) -#define PMU_ASC0 BIT(7) -#define PMU_EPHY BIT(7) /* ase */ -#define PMU_SPI BIT(8) -#define PMU_DFE BIT(9) -#define PMU_EBU BIT(10) -#define PMU_STP BIT(11) -#define PMU_GPT BIT(12) -#define PMU_AHBS BIT(13) /* vr9 */ -#define PMU_FPI BIT(14) -#define PMU_AHBM BIT(15) -#define PMU_ASC1 BIT(17) -#define PMU_PPE_QSB BIT(18) -#define PMU_PPE_SLL01 BIT(19) -#define PMU_PPE_TC BIT(21) -#define PMU_PPE_EMA BIT(22) -#define PMU_PPE_DPLUM BIT(23) -#define PMU_PPE_DPLUS BIT(24) -#define PMU_USB1_P BIT(26) -#define PMU_USB1 BIT(27) -#define PMU_SWITCH BIT(28) -#define PMU_PPE_TOP BIT(29) -#define PMU_GPHY BIT(30) -#define PMU_PCIE_CLK BIT(31) - -#define PMU1_PCIE_PHY BIT(0) -#define PMU1_PCIE_CTL BIT(1) -#define PMU1_PCIE_PDI BIT(4) -#define PMU1_PCIE_MSI BIT(5) - -#define pmu_w32(x, y) ltq_w32((x), pmu_membase + (y)) -#define pmu_r32(x) ltq_r32(pmu_membase + (x)) - -static void __iomem *pmu_membase; -void __iomem *ltq_cgu_membase; -void __iomem *ltq_ebu_membase; - -/* legacy function kept alive to ease clkdev transition */ -void ltq_pmu_enable(unsigned int module) -{ - int err = 1000000; - - pmu_w32(pmu_r32(PMU_PWDCR) & ~module, PMU_PWDCR); - do {} while (--err && (pmu_r32(PMU_PWDSR) & module)); - - if (!err) - panic("activating PMU module failed!"); -} -EXPORT_SYMBOL(ltq_pmu_enable); - -/* legacy function kept alive to ease clkdev transition */ -void ltq_pmu_disable(unsigned int module) -{ - pmu_w32(pmu_r32(PMU_PWDCR) | module, PMU_PWDCR); -} -EXPORT_SYMBOL(ltq_pmu_disable); - -/* enable a hw clock */ -static int cgu_enable(struct clk *clk) -{ - ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) | clk->bits, CGU_IFCCR); - return 0; -} - -/* disable a hw clock */ -static void cgu_disable(struct clk *clk) -{ - ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) & ~clk->bits, CGU_IFCCR); -} - -/* enable a clock gate */ -static int pmu_enable(struct clk *clk) -{ - int retry = 1000000; - - pmu_w32(pmu_r32(PWDCR(clk->module)) & ~clk->bits, - PWDCR(clk->module)); - do {} while (--retry && (pmu_r32(PWDSR(clk->module)) & clk->bits)); - - if (!retry) - panic("activating PMU module failed!\n"); - - return 0; -} - -/* disable a clock gate */ -static void pmu_disable(struct clk *clk) -{ - pmu_w32(pmu_r32(PWDCR(clk->module)) | clk->bits, - PWDCR(clk->module)); -} - -/* the pci enable helper */ -static int pci_enable(struct clk *clk) -{ - unsigned int ifccr = ltq_cgu_r32(CGU_IFCCR); - /* set bus clock speed */ - if (of_machine_is_compatible("lantiq,ar9")) { - ifccr &= ~0x1f00000; - if (clk->rate == CLOCK_33M) - ifccr |= 0xe00000; - else - ifccr |= 0x700000; /* 62.5M */ - } else { - ifccr &= ~0xf00000; - if (clk->rate == CLOCK_33M) - ifccr |= 0x800000; - else - ifccr |= 0x400000; /* 62.5M */ - } - ltq_cgu_w32(ifccr, CGU_IFCCR); - pmu_enable(clk); - return 0; -} - -/* enable the external clock as a source */ -static int pci_ext_enable(struct clk *clk) -{ - ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) & ~(1 << 16), - CGU_IFCCR); - ltq_cgu_w32((1 << 30), CGU_PCICR); - return 0; -} - -/* disable the external clock as a source */ -static void pci_ext_disable(struct clk *clk) -{ - ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) | (1 << 16), - CGU_IFCCR); - ltq_cgu_w32((1 << 31) | (1 << 30), CGU_PCICR); -} - -/* enable a clockout source */ -static int clkout_enable(struct clk *clk) -{ - int i; - - /* get the correct rate */ - for (i = 0; i < 4; i++) { - if (clk->rates[i] == clk->rate) { - int shift = 14 - (2 * clk->module); - unsigned int ifccr = ltq_cgu_r32(CGU_IFCCR); - - ifccr &= ~(3 << shift); - ifccr |= i << shift; - ltq_cgu_w32(ifccr, CGU_IFCCR); - return 0; - } - } - return -1; -} - -/* manage the clock gates via PMU */ -static void clkdev_add_pmu(const char *dev, const char *con, - unsigned int module, unsigned int bits) -{ - struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); - - clk->cl.dev_id = dev; - clk->cl.con_id = con; - clk->cl.clk = clk; - clk->enable = pmu_enable; - clk->disable = pmu_disable; - clk->module = module; - clk->bits = bits; - clkdev_add(&clk->cl); -} - -/* manage the clock generator */ -static void clkdev_add_cgu(const char *dev, const char *con, - unsigned int bits) -{ - struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); - - clk->cl.dev_id = dev; - clk->cl.con_id = con; - clk->cl.clk = clk; - clk->enable = cgu_enable; - clk->disable = cgu_disable; - clk->bits = bits; - clkdev_add(&clk->cl); -} - -/* pci needs its own enable function as the setup is a bit more complex */ -static unsigned long valid_pci_rates[] = {CLOCK_33M, CLOCK_62_5M, 0}; - -static void clkdev_add_pci(void) -{ - struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); - struct clk *clk_ext = kzalloc(sizeof(struct clk), GFP_KERNEL); - - /* main pci clock */ - clk->cl.dev_id = "17000000.pci"; - clk->cl.con_id = NULL; - clk->cl.clk = clk; - clk->rate = CLOCK_33M; - clk->rates = valid_pci_rates; - clk->enable = pci_enable; - clk->disable = pmu_disable; - clk->module = 0; - clk->bits = PMU_PCI; - clkdev_add(&clk->cl); - - /* use internal/external bus clock */ - clk_ext->cl.dev_id = "17000000.pci"; - clk_ext->cl.con_id = "external"; - clk_ext->cl.clk = clk_ext; - clk_ext->enable = pci_ext_enable; - clk_ext->disable = pci_ext_disable; - clkdev_add(&clk_ext->cl); -} - -/* xway socs can generate clocks on gpio pins */ -static unsigned long valid_clkout_rates[4][5] = { - {CLOCK_32_768K, CLOCK_1_536M, CLOCK_2_5M, CLOCK_12M, 0}, - {CLOCK_40M, CLOCK_12M, CLOCK_24M, CLOCK_48M, 0}, - {CLOCK_25M, CLOCK_40M, CLOCK_30M, CLOCK_60M, 0}, - {CLOCK_12M, CLOCK_50M, CLOCK_32_768K, CLOCK_25M, 0}, -}; - -static void clkdev_add_clkout(void) -{ - int i; - - for (i = 0; i < 4; i++) { - struct clk *clk; - char *name; - - name = kzalloc(sizeof("clkout0"), GFP_KERNEL); - sprintf(name, "clkout%d", i); - - clk = kzalloc(sizeof(struct clk), GFP_KERNEL); - clk->cl.dev_id = "1f103000.cgu"; - clk->cl.con_id = name; - clk->cl.clk = clk; - clk->rate = 0; - clk->rates = valid_clkout_rates[i]; - clk->enable = clkout_enable; - clk->module = i; - clkdev_add(&clk->cl); - } -} - -/* bring up all register ranges that we need for basic system control */ -void __init ltq_soc_init(void) -{ - struct resource res_pmu, res_cgu, res_ebu; - struct device_node *np_pmu = - of_find_compatible_node(NULL, NULL, "lantiq,pmu-xway"); - struct device_node *np_cgu = - of_find_compatible_node(NULL, NULL, "lantiq,cgu-xway"); - struct device_node *np_ebu = - of_find_compatible_node(NULL, NULL, "lantiq,ebu-xway"); - - /* check if all the core register ranges are available */ - if (!np_pmu || !np_cgu || !np_ebu) - panic("Failed to load core nodess from devicetree"); - - if (of_address_to_resource(np_pmu, 0, &res_pmu) || - of_address_to_resource(np_cgu, 0, &res_cgu) || - of_address_to_resource(np_ebu, 0, &res_ebu)) - panic("Failed to get core resources"); - - if ((request_mem_region(res_pmu.start, resource_size(&res_pmu), - res_pmu.name) < 0) || - (request_mem_region(res_cgu.start, resource_size(&res_cgu), - res_cgu.name) < 0) || - (request_mem_region(res_ebu.start, resource_size(&res_ebu), - res_ebu.name) < 0)) - pr_err("Failed to request core reources"); - - pmu_membase = ioremap_nocache(res_pmu.start, resource_size(&res_pmu)); - ltq_cgu_membase = ioremap_nocache(res_cgu.start, - resource_size(&res_cgu)); - ltq_ebu_membase = ioremap_nocache(res_ebu.start, - resource_size(&res_ebu)); - if (!pmu_membase || !ltq_cgu_membase || !ltq_ebu_membase) - panic("Failed to remap core resources"); - - /* make sure to unprotect the memory region where flash is located */ - ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0); - - /* add our generic xway clocks */ - clkdev_add_pmu("10000000.fpi", NULL, 0, PMU_FPI); - clkdev_add_pmu("1e100400.serial", NULL, 0, PMU_ASC0); - clkdev_add_pmu("1e100a00.gptu", NULL, 0, PMU_GPT); - clkdev_add_pmu("1e100bb0.stp", NULL, 0, PMU_STP); - clkdev_add_pmu("1e104100.dma", NULL, 0, PMU_DMA); - clkdev_add_pmu("1e100800.spi", NULL, 0, PMU_SPI); - clkdev_add_pmu("1e105300.ebu", NULL, 0, PMU_EBU); - clkdev_add_clkout(); - - /* add the soc dependent clocks */ - if (!of_machine_is_compatible("lantiq,vr9")) - clkdev_add_pmu("1e180000.etop", NULL, 0, PMU_PPE); - - if (!of_machine_is_compatible("lantiq,ase")) { - clkdev_add_pmu("1e100c00.serial", NULL, 0, PMU_ASC1); - clkdev_add_pci(); - } - - if (of_machine_is_compatible("lantiq,ase")) { - if (ltq_cgu_r32(CGU_SYS) & (1 << 5)) - clkdev_add_static(CLOCK_266M, CLOCK_133M, CLOCK_133M); - else - clkdev_add_static(CLOCK_133M, CLOCK_133M, CLOCK_133M); - clkdev_add_cgu("1e180000.etop", "ephycgu", CGU_EPHY), - clkdev_add_pmu("1e180000.etop", "ephy", 0, PMU_EPHY); - } else if (of_machine_is_compatible("lantiq,vr9")) { - clkdev_add_static(ltq_vr9_cpu_hz(), ltq_vr9_fpi_hz(), - ltq_vr9_fpi_hz()); - clkdev_add_pmu("1d900000.pcie", "phy", 1, PMU1_PCIE_PHY); - clkdev_add_pmu("1d900000.pcie", "bus", 0, PMU_PCIE_CLK); - clkdev_add_pmu("1d900000.pcie", "msi", 1, PMU1_PCIE_MSI); - clkdev_add_pmu("1d900000.pcie", "pdi", 1, PMU1_PCIE_PDI); - clkdev_add_pmu("1d900000.pcie", "ctl", 1, PMU1_PCIE_CTL); - clkdev_add_pmu("1d900000.pcie", "ahb", 0, PMU_AHBM | PMU_AHBS); - } else if (of_machine_is_compatible("lantiq,ar9")) { - clkdev_add_static(ltq_ar9_cpu_hz(), ltq_ar9_fpi_hz(), - ltq_ar9_fpi_hz()); - clkdev_add_pmu("1e180000.etop", "switch", 0, PMU_SWITCH); - } else { - clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(), - ltq_danube_fpi_hz()); - } -} diff --git a/trunk/arch/mips/mm/c-octeon.c b/trunk/arch/mips/mm/c-octeon.c index 44e69e7a4519..47037ec5589b 100644 --- a/trunk/arch/mips/mm/c-octeon.c +++ b/trunk/arch/mips/mm/c-octeon.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -249,11 +248,6 @@ static void __cpuinit probe_octeon(void) } } -static void __cpuinit octeon_cache_error_setup(void) -{ - extern char except_vec2_octeon; - set_handler(0x100, &except_vec2_octeon, 0x80); -} /** * Setup the Octeon cache flush routines @@ -261,6 +255,12 @@ static void __cpuinit octeon_cache_error_setup(void) */ void __cpuinit octeon_cache_init(void) { + extern unsigned long ebase; + extern char except_vec2_octeon; + + memcpy((void *)(ebase + 0x100), &except_vec2_octeon, 0x80); + octeon_flush_cache_sigtramp(ebase + 0x100); + probe_octeon(); shm_align_mask = PAGE_SIZE - 1; @@ -280,8 +280,6 @@ void __cpuinit octeon_cache_init(void) build_clear_page(); build_copy_page(); - - board_cache_error_setup = octeon_cache_error_setup; } /** diff --git a/trunk/arch/mips/mm/c-r4k.c b/trunk/arch/mips/mm/c-r4k.c index 5109be96d98d..bda8eb26ece7 100644 --- a/trunk/arch/mips/mm/c-r4k.c +++ b/trunk/arch/mips/mm/c-r4k.c @@ -32,7 +32,7 @@ #include #include #include /* for run_uncached() */ -#include + /* * Special Variant of smp_call_function for use by cache functions: @@ -1385,8 +1385,10 @@ static int __init setcoherentio(char *str) __setup("coherentio", setcoherentio); #endif -static void __cpuinit r4k_cache_error_setup(void) +void __cpuinit r4k_cache_init(void) { + extern void build_clear_page(void); + extern void build_copy_page(void); extern char __weak except_vec2_generic; extern char __weak except_vec2_sb1; struct cpuinfo_mips *c = ¤t_cpu_data; @@ -1401,13 +1403,6 @@ static void __cpuinit r4k_cache_error_setup(void) set_uncached_handler(0x100, &except_vec2_generic, 0x80); break; } -} - -void __cpuinit r4k_cache_init(void) -{ - extern void build_clear_page(void); - extern void build_copy_page(void); - struct cpuinfo_mips *c = ¤t_cpu_data; probe_pcache(); setup_scache(); @@ -1470,5 +1465,4 @@ void __cpuinit r4k_cache_init(void) local_r4k___flush_cache_all(NULL); #endif coherency_setup(); - board_cache_error_setup = r4k_cache_error_setup; } diff --git a/trunk/arch/mips/oprofile/Makefile b/trunk/arch/mips/oprofile/Makefile index 1208c280f77d..29f2f13eb31c 100644 --- a/trunk/arch/mips/oprofile/Makefile +++ b/trunk/arch/mips/oprofile/Makefile @@ -1,3 +1,5 @@ +ccflags-y := -Werror + obj-$(CONFIG_OPROFILE) += oprofile.o DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ diff --git a/trunk/arch/mips/oprofile/op_model_mipsxx.c b/trunk/arch/mips/oprofile/op_model_mipsxx.c index baba3bcaa3c2..54759f1669d3 100644 --- a/trunk/arch/mips/oprofile/op_model_mipsxx.c +++ b/trunk/arch/mips/oprofile/op_model_mipsxx.c @@ -298,11 +298,6 @@ static void reset_counters(void *arg) } } -static irqreturn_t mipsxx_perfcount_int(int irq, void *dev_id) -{ - return mipsxx_perfcount_handler(); -} - static int __init mipsxx_init(void) { int counters; @@ -379,10 +374,6 @@ static int __init mipsxx_init(void) save_perf_irq = perf_irq; perf_irq = mipsxx_perfcount_handler; - if ((cp0_perfcount_irq >= 0) && (cp0_compare_irq != cp0_perfcount_irq)) - return request_irq(cp0_perfcount_irq, mipsxx_perfcount_int, - 0, "Perfcounter", save_perf_irq); - return 0; } @@ -390,9 +381,6 @@ static void mipsxx_exit(void) { int counters = op_model_mipsxx_ops.num_counters; - if ((cp0_perfcount_irq >= 0) && (cp0_compare_irq != cp0_perfcount_irq)) - free_irq(cp0_perfcount_irq, save_perf_irq); - counters = counters_per_cpu_to_total(counters); on_each_cpu(reset_counters, (void *)(long)counters, 1); diff --git a/trunk/arch/mips/pci/Makefile b/trunk/arch/mips/pci/Makefile index c703f43a9914..c3ac4b086eb2 100644 --- a/trunk/arch/mips/pci/Makefile +++ b/trunk/arch/mips/pci/Makefile @@ -19,8 +19,7 @@ obj-$(CONFIG_BCM47XX) += pci-bcm47xx.o obj-$(CONFIG_BCM63XX) += pci-bcm63xx.o fixup-bcm63xx.o \ ops-bcm63xx.o obj-$(CONFIG_MIPS_ALCHEMY) += pci-alchemy.o -obj-$(CONFIG_SOC_AR71XX) += pci-ar71xx.o -obj-$(CONFIG_PCI_AR724X) += pci-ar724x.o +obj-$(CONFIG_SOC_AR724X) += pci-ath724x.o # # These are still pretty much in the old state, watch, go blind. @@ -42,8 +41,7 @@ obj-$(CONFIG_SIBYTE_SB1250) += fixup-sb1250.o pci-sb1250.o obj-$(CONFIG_SIBYTE_BCM112X) += fixup-sb1250.o pci-sb1250.o obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1480.o pci-bcm1480ht.o obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o -obj-$(CONFIG_LANTIQ) += fixup-lantiq.o -obj-$(CONFIG_PCI_LANTIQ) += pci-lantiq.o ops-lantiq.o +obj-$(CONFIG_SOC_XWAY) += pci-lantiq.o ops-lantiq.o obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o diff --git a/trunk/arch/mips/pci/fixup-lantiq.c b/trunk/arch/mips/pci/fixup-lantiq.c deleted file mode 100644 index 6c829df28dc7..000000000000 --- a/trunk/arch/mips/pci/fixup-lantiq.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2012 John Crispin - */ - -#include -#include - -int (*ltq_pci_plat_arch_init)(struct pci_dev *dev) = NULL; -int (*ltq_pci_plat_dev_init)(struct pci_dev *dev) = NULL; - -int pcibios_plat_dev_init(struct pci_dev *dev) -{ - if (ltq_pci_plat_arch_init) - return ltq_pci_plat_arch_init(dev); - - if (ltq_pci_plat_dev_init) - return ltq_pci_plat_dev_init(dev); - - return 0; -} - -int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -{ - struct of_irq dev_irq; - int irq; - - if (of_irq_map_pci(dev, &dev_irq)) { - dev_err(&dev->dev, "trying to map irq for unknown slot:%d pin:%d\n", - slot, pin); - return 0; - } - irq = irq_create_of_mapping(dev_irq.controller, dev_irq.specifier, - dev_irq.size); - dev_info(&dev->dev, "SLOT:%d PIN:%d IRQ:%d\n", slot, pin, irq); - return irq; -} diff --git a/trunk/arch/mips/pci/ops-loongson2.c b/trunk/arch/mips/pci/ops-loongson2.c index afd221122d22..d657ee0bc131 100644 --- a/trunk/arch/mips/pci/ops-loongson2.c +++ b/trunk/arch/mips/pci/ops-loongson2.c @@ -15,7 +15,6 @@ #include #include #include -#include #include diff --git a/trunk/arch/mips/pci/pci-ar71xx.c b/trunk/arch/mips/pci/pci-ar71xx.c deleted file mode 100644 index 1552522b8718..000000000000 --- a/trunk/arch/mips/pci/pci-ar71xx.c +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Atheros AR71xx PCI host controller driver - * - * Copyright (C) 2008-2011 Gabor Juhos - * Copyright (C) 2008 Imre Kaloz - * - * Parts of this file are based on Atheros' 2.6.15 BSP - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define AR71XX_PCI_MEM_BASE 0x10000000 -#define AR71XX_PCI_MEM_SIZE 0x08000000 - -#define AR71XX_PCI_WIN0_OFFS 0x10000000 -#define AR71XX_PCI_WIN1_OFFS 0x11000000 -#define AR71XX_PCI_WIN2_OFFS 0x12000000 -#define AR71XX_PCI_WIN3_OFFS 0x13000000 -#define AR71XX_PCI_WIN4_OFFS 0x14000000 -#define AR71XX_PCI_WIN5_OFFS 0x15000000 -#define AR71XX_PCI_WIN6_OFFS 0x16000000 -#define AR71XX_PCI_WIN7_OFFS 0x07000000 - -#define AR71XX_PCI_CFG_BASE \ - (AR71XX_PCI_MEM_BASE + AR71XX_PCI_WIN7_OFFS + 0x10000) -#define AR71XX_PCI_CFG_SIZE 0x100 - -#define AR71XX_PCI_REG_CRP_AD_CBE 0x00 -#define AR71XX_PCI_REG_CRP_WRDATA 0x04 -#define AR71XX_PCI_REG_CRP_RDDATA 0x08 -#define AR71XX_PCI_REG_CFG_AD 0x0c -#define AR71XX_PCI_REG_CFG_CBE 0x10 -#define AR71XX_PCI_REG_CFG_WRDATA 0x14 -#define AR71XX_PCI_REG_CFG_RDDATA 0x18 -#define AR71XX_PCI_REG_PCI_ERR 0x1c -#define AR71XX_PCI_REG_PCI_ERR_ADDR 0x20 -#define AR71XX_PCI_REG_AHB_ERR 0x24 -#define AR71XX_PCI_REG_AHB_ERR_ADDR 0x28 - -#define AR71XX_PCI_CRP_CMD_WRITE 0x00010000 -#define AR71XX_PCI_CRP_CMD_READ 0x00000000 -#define AR71XX_PCI_CFG_CMD_READ 0x0000000a -#define AR71XX_PCI_CFG_CMD_WRITE 0x0000000b - -#define AR71XX_PCI_INT_CORE BIT(4) -#define AR71XX_PCI_INT_DEV2 BIT(2) -#define AR71XX_PCI_INT_DEV1 BIT(1) -#define AR71XX_PCI_INT_DEV0 BIT(0) - -#define AR71XX_PCI_IRQ_COUNT 5 - -static DEFINE_SPINLOCK(ar71xx_pci_lock); -static void __iomem *ar71xx_pcicfg_base; - -/* Byte lane enable bits */ -static const u8 ar71xx_pci_ble_table[4][4] = { - {0x0, 0xf, 0xf, 0xf}, - {0xe, 0xd, 0xb, 0x7}, - {0xc, 0xf, 0x3, 0xf}, - {0xf, 0xf, 0xf, 0xf}, -}; - -static const u32 ar71xx_pci_read_mask[8] = { - 0, 0xff, 0xffff, 0, 0xffffffff, 0, 0, 0 -}; - -static inline u32 ar71xx_pci_get_ble(int where, int size, int local) -{ - u32 t; - - t = ar71xx_pci_ble_table[size & 3][where & 3]; - BUG_ON(t == 0xf); - t <<= (local) ? 20 : 4; - - return t; -} - -static inline u32 ar71xx_pci_bus_addr(struct pci_bus *bus, unsigned int devfn, - int where) -{ - u32 ret; - - if (!bus->number) { - /* type 0 */ - ret = (1 << PCI_SLOT(devfn)) | (PCI_FUNC(devfn) << 8) | - (where & ~3); - } else { - /* type 1 */ - ret = (bus->number << 16) | (PCI_SLOT(devfn) << 11) | - (PCI_FUNC(devfn) << 8) | (where & ~3) | 1; - } - - return ret; -} - -static int ar71xx_pci_check_error(int quiet) -{ - void __iomem *base = ar71xx_pcicfg_base; - u32 pci_err; - u32 ahb_err; - - pci_err = __raw_readl(base + AR71XX_PCI_REG_PCI_ERR) & 3; - if (pci_err) { - if (!quiet) { - u32 addr; - - addr = __raw_readl(base + AR71XX_PCI_REG_PCI_ERR_ADDR); - pr_crit("ar71xx: %s bus error %d at addr 0x%x\n", - "PCI", pci_err, addr); - } - - /* clear PCI error status */ - __raw_writel(pci_err, base + AR71XX_PCI_REG_PCI_ERR); - } - - ahb_err = __raw_readl(base + AR71XX_PCI_REG_AHB_ERR) & 1; - if (ahb_err) { - if (!quiet) { - u32 addr; - - addr = __raw_readl(base + AR71XX_PCI_REG_AHB_ERR_ADDR); - pr_crit("ar71xx: %s bus error %d at addr 0x%x\n", - "AHB", ahb_err, addr); - } - - /* clear AHB error status */ - __raw_writel(ahb_err, base + AR71XX_PCI_REG_AHB_ERR); - } - - return !!(ahb_err | pci_err); -} - -static inline void ar71xx_pci_local_write(int where, int size, u32 value) -{ - void __iomem *base = ar71xx_pcicfg_base; - u32 ad_cbe; - - value = value << (8 * (where & 3)); - - ad_cbe = AR71XX_PCI_CRP_CMD_WRITE | (where & ~3); - ad_cbe |= ar71xx_pci_get_ble(where, size, 1); - - __raw_writel(ad_cbe, base + AR71XX_PCI_REG_CRP_AD_CBE); - __raw_writel(value, base + AR71XX_PCI_REG_CRP_WRDATA); -} - -static inline int ar71xx_pci_set_cfgaddr(struct pci_bus *bus, - unsigned int devfn, - int where, int size, u32 cmd) -{ - void __iomem *base = ar71xx_pcicfg_base; - u32 addr; - - addr = ar71xx_pci_bus_addr(bus, devfn, where); - - __raw_writel(addr, base + AR71XX_PCI_REG_CFG_AD); - __raw_writel(cmd | ar71xx_pci_get_ble(where, size, 0), - base + AR71XX_PCI_REG_CFG_CBE); - - return ar71xx_pci_check_error(1); -} - -static int ar71xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 *value) -{ - void __iomem *base = ar71xx_pcicfg_base; - unsigned long flags; - u32 data; - int err; - int ret; - - ret = PCIBIOS_SUCCESSFUL; - data = ~0; - - spin_lock_irqsave(&ar71xx_pci_lock, flags); - - err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size, - AR71XX_PCI_CFG_CMD_READ); - if (err) - ret = PCIBIOS_DEVICE_NOT_FOUND; - else - data = __raw_readl(base + AR71XX_PCI_REG_CFG_RDDATA); - - spin_unlock_irqrestore(&ar71xx_pci_lock, flags); - - *value = (data >> (8 * (where & 3))) & ar71xx_pci_read_mask[size & 7]; - - return ret; -} - -static int ar71xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 value) -{ - void __iomem *base = ar71xx_pcicfg_base; - unsigned long flags; - int err; - int ret; - - value = value << (8 * (where & 3)); - ret = PCIBIOS_SUCCESSFUL; - - spin_lock_irqsave(&ar71xx_pci_lock, flags); - - err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size, - AR71XX_PCI_CFG_CMD_WRITE); - if (err) - ret = PCIBIOS_DEVICE_NOT_FOUND; - else - __raw_writel(value, base + AR71XX_PCI_REG_CFG_WRDATA); - - spin_unlock_irqrestore(&ar71xx_pci_lock, flags); - - return ret; -} - -static struct pci_ops ar71xx_pci_ops = { - .read = ar71xx_pci_read_config, - .write = ar71xx_pci_write_config, -}; - -static struct resource ar71xx_pci_io_resource = { - .name = "PCI IO space", - .start = 0, - .end = 0, - .flags = IORESOURCE_IO, -}; - -static struct resource ar71xx_pci_mem_resource = { - .name = "PCI memory space", - .start = AR71XX_PCI_MEM_BASE, - .end = AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1, - .flags = IORESOURCE_MEM -}; - -static struct pci_controller ar71xx_pci_controller = { - .pci_ops = &ar71xx_pci_ops, - .mem_resource = &ar71xx_pci_mem_resource, - .io_resource = &ar71xx_pci_io_resource, -}; - -static void ar71xx_pci_irq_handler(unsigned int irq, struct irq_desc *desc) -{ - void __iomem *base = ath79_reset_base; - u32 pending; - - pending = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_STATUS) & - __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); - - if (pending & AR71XX_PCI_INT_DEV0) - generic_handle_irq(ATH79_PCI_IRQ(0)); - - else if (pending & AR71XX_PCI_INT_DEV1) - generic_handle_irq(ATH79_PCI_IRQ(1)); - - else if (pending & AR71XX_PCI_INT_DEV2) - generic_handle_irq(ATH79_PCI_IRQ(2)); - - else if (pending & AR71XX_PCI_INT_CORE) - generic_handle_irq(ATH79_PCI_IRQ(4)); - - else - spurious_interrupt(); -} - -static void ar71xx_pci_irq_unmask(struct irq_data *d) -{ - unsigned int irq = d->irq - ATH79_PCI_IRQ_BASE; - void __iomem *base = ath79_reset_base; - u32 t; - - t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); - __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE); - - /* flush write */ - __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); -} - -static void ar71xx_pci_irq_mask(struct irq_data *d) -{ - unsigned int irq = d->irq - ATH79_PCI_IRQ_BASE; - void __iomem *base = ath79_reset_base; - u32 t; - - t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); - __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE); - - /* flush write */ - __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); -} - -static struct irq_chip ar71xx_pci_irq_chip = { - .name = "AR71XX PCI", - .irq_mask = ar71xx_pci_irq_mask, - .irq_unmask = ar71xx_pci_irq_unmask, - .irq_mask_ack = ar71xx_pci_irq_mask, -}; - -static __init void ar71xx_pci_irq_init(void) -{ - void __iomem *base = ath79_reset_base; - int i; - - __raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_ENABLE); - __raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_STATUS); - - BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR71XX_PCI_IRQ_COUNT); - - for (i = ATH79_PCI_IRQ_BASE; - i < ATH79_PCI_IRQ_BASE + AR71XX_PCI_IRQ_COUNT; i++) - irq_set_chip_and_handler(i, &ar71xx_pci_irq_chip, - handle_level_irq); - - irq_set_chained_handler(ATH79_CPU_IRQ_IP2, ar71xx_pci_irq_handler); -} - -static __init void ar71xx_pci_reset(void) -{ - void __iomem *ddr_base = ath79_ddr_base; - - ath79_device_reset_set(AR71XX_RESET_PCI_BUS | AR71XX_RESET_PCI_CORE); - mdelay(100); - - ath79_device_reset_clear(AR71XX_RESET_PCI_BUS | AR71XX_RESET_PCI_CORE); - mdelay(100); - - __raw_writel(AR71XX_PCI_WIN0_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN0); - __raw_writel(AR71XX_PCI_WIN1_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN1); - __raw_writel(AR71XX_PCI_WIN2_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN2); - __raw_writel(AR71XX_PCI_WIN3_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN3); - __raw_writel(AR71XX_PCI_WIN4_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN4); - __raw_writel(AR71XX_PCI_WIN5_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN5); - __raw_writel(AR71XX_PCI_WIN6_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN6); - __raw_writel(AR71XX_PCI_WIN7_OFFS, ddr_base + AR71XX_DDR_REG_PCI_WIN7); - - mdelay(100); -} - -__init int ar71xx_pcibios_init(void) -{ - u32 t; - - ar71xx_pcicfg_base = ioremap(AR71XX_PCI_CFG_BASE, AR71XX_PCI_CFG_SIZE); - if (ar71xx_pcicfg_base == NULL) - return -ENOMEM; - - ar71xx_pci_reset(); - - /* setup COMMAND register */ - t = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE - | PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK; - ar71xx_pci_local_write(PCI_COMMAND, 4, t); - - /* clear bus errors */ - ar71xx_pci_check_error(1); - - ar71xx_pci_irq_init(); - - register_pci_controller(&ar71xx_pci_controller); - - return 0; -} diff --git a/trunk/arch/mips/pci/pci-ar724x.c b/trunk/arch/mips/pci/pci-ar724x.c deleted file mode 100644 index 414a7459858d..000000000000 --- a/trunk/arch/mips/pci/pci-ar724x.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Atheros AR724X PCI host controller driver - * - * Copyright (C) 2011 René Bolldorf - * Copyright (C) 2009-2011 Gabor Juhos - * - * 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 - -#define AR724X_PCI_CFG_BASE 0x14000000 -#define AR724X_PCI_CFG_SIZE 0x1000 -#define AR724X_PCI_CTRL_BASE (AR71XX_APB_BASE + 0x000f0000) -#define AR724X_PCI_CTRL_SIZE 0x100 - -#define AR724X_PCI_MEM_BASE 0x10000000 -#define AR724X_PCI_MEM_SIZE 0x08000000 - -#define AR724X_PCI_REG_INT_STATUS 0x4c -#define AR724X_PCI_REG_INT_MASK 0x50 - -#define AR724X_PCI_INT_DEV0 BIT(14) - -#define AR724X_PCI_IRQ_COUNT 1 - -#define AR7240_BAR0_WAR_VALUE 0xffff - -static DEFINE_SPINLOCK(ar724x_pci_lock); -static void __iomem *ar724x_pci_devcfg_base; -static void __iomem *ar724x_pci_ctrl_base; - -static u32 ar724x_pci_bar0_value; -static bool ar724x_pci_bar0_is_cached; - -static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, - int size, uint32_t *value) -{ - unsigned long flags; - void __iomem *base; - u32 data; - - if (devfn) - return PCIBIOS_DEVICE_NOT_FOUND; - - base = ar724x_pci_devcfg_base; - - spin_lock_irqsave(&ar724x_pci_lock, flags); - data = __raw_readl(base + (where & ~3)); - - switch (size) { - case 1: - if (where & 1) - data >>= 8; - if (where & 2) - data >>= 16; - data &= 0xff; - break; - case 2: - if (where & 2) - data >>= 16; - data &= 0xffff; - break; - case 4: - break; - default: - spin_unlock_irqrestore(&ar724x_pci_lock, flags); - - return PCIBIOS_BAD_REGISTER_NUMBER; - } - - spin_unlock_irqrestore(&ar724x_pci_lock, flags); - - if (where == PCI_BASE_ADDRESS_0 && size == 4 && - ar724x_pci_bar0_is_cached) { - /* use the cached value */ - *value = ar724x_pci_bar0_value; - } else { - *value = data; - } - - return PCIBIOS_SUCCESSFUL; -} - -static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, - int size, uint32_t value) -{ - unsigned long flags; - void __iomem *base; - u32 data; - int s; - - if (devfn) - return PCIBIOS_DEVICE_NOT_FOUND; - - if (soc_is_ar7240() && where == PCI_BASE_ADDRESS_0 && size == 4) { - if (value != 0xffffffff) { - /* - * WAR for a hw issue. If the BAR0 register of the - * device is set to the proper base address, the - * memory space of the device is not accessible. - * - * Cache the intended value so it can be read back, - * and write a SoC specific constant value to the - * BAR0 register in order to make the device memory - * accessible. - */ - ar724x_pci_bar0_is_cached = true; - ar724x_pci_bar0_value = value; - - value = AR7240_BAR0_WAR_VALUE; - } else { - ar724x_pci_bar0_is_cached = false; - } - } - - base = ar724x_pci_devcfg_base; - - spin_lock_irqsave(&ar724x_pci_lock, flags); - data = __raw_readl(base + (where & ~3)); - - switch (size) { - case 1: - s = ((where & 3) * 8); - data &= ~(0xff << s); - data |= ((value & 0xff) << s); - break; - case 2: - s = ((where & 2) * 8); - data &= ~(0xffff << s); - data |= ((value & 0xffff) << s); - break; - case 4: - data = value; - break; - default: - spin_unlock_irqrestore(&ar724x_pci_lock, flags); - - return PCIBIOS_BAD_REGISTER_NUMBER; - } - - __raw_writel(data, base + (where & ~3)); - /* flush write */ - __raw_readl(base + (where & ~3)); - spin_unlock_irqrestore(&ar724x_pci_lock, flags); - - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops ar724x_pci_ops = { - .read = ar724x_pci_read, - .write = ar724x_pci_write, -}; - -static struct resource ar724x_io_resource = { - .name = "PCI IO space", - .start = 0, - .end = 0, - .flags = IORESOURCE_IO, -}; - -static struct resource ar724x_mem_resource = { - .name = "PCI memory space", - .start = AR724X_PCI_MEM_BASE, - .end = AR724X_PCI_MEM_BASE + AR724X_PCI_MEM_SIZE - 1, - .flags = IORESOURCE_MEM, -}; - -static struct pci_controller ar724x_pci_controller = { - .pci_ops = &ar724x_pci_ops, - .io_resource = &ar724x_io_resource, - .mem_resource = &ar724x_mem_resource, -}; - -static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc) -{ - void __iomem *base; - u32 pending; - - base = ar724x_pci_ctrl_base; - - pending = __raw_readl(base + AR724X_PCI_REG_INT_STATUS) & - __raw_readl(base + AR724X_PCI_REG_INT_MASK); - - if (pending & AR724X_PCI_INT_DEV0) - generic_handle_irq(ATH79_PCI_IRQ(0)); - - else - spurious_interrupt(); -} - -static void ar724x_pci_irq_unmask(struct irq_data *d) -{ - void __iomem *base; - u32 t; - - base = ar724x_pci_ctrl_base; - - switch (d->irq) { - case ATH79_PCI_IRQ(0): - t = __raw_readl(base + AR724X_PCI_REG_INT_MASK); - __raw_writel(t | AR724X_PCI_INT_DEV0, - base + AR724X_PCI_REG_INT_MASK); - /* flush write */ - __raw_readl(base + AR724X_PCI_REG_INT_MASK); - } -} - -static void ar724x_pci_irq_mask(struct irq_data *d) -{ - void __iomem *base; - u32 t; - - base = ar724x_pci_ctrl_base; - - switch (d->irq) { - case ATH79_PCI_IRQ(0): - t = __raw_readl(base + AR724X_PCI_REG_INT_MASK); - __raw_writel(t & ~AR724X_PCI_INT_DEV0, - base + AR724X_PCI_REG_INT_MASK); - - /* flush write */ - __raw_readl(base + AR724X_PCI_REG_INT_MASK); - - t = __raw_readl(base + AR724X_PCI_REG_INT_STATUS); - __raw_writel(t | AR724X_PCI_INT_DEV0, - base + AR724X_PCI_REG_INT_STATUS); - - /* flush write */ - __raw_readl(base + AR724X_PCI_REG_INT_STATUS); - } -} - -static struct irq_chip ar724x_pci_irq_chip = { - .name = "AR724X PCI ", - .irq_mask = ar724x_pci_irq_mask, - .irq_unmask = ar724x_pci_irq_unmask, - .irq_mask_ack = ar724x_pci_irq_mask, -}; - -static void __init ar724x_pci_irq_init(int irq) -{ - void __iomem *base; - int i; - - base = ar724x_pci_ctrl_base; - - __raw_writel(0, base + AR724X_PCI_REG_INT_MASK); - __raw_writel(0, base + AR724X_PCI_REG_INT_STATUS); - - BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR724X_PCI_IRQ_COUNT); - - for (i = ATH79_PCI_IRQ_BASE; - i < ATH79_PCI_IRQ_BASE + AR724X_PCI_IRQ_COUNT; i++) - irq_set_chip_and_handler(i, &ar724x_pci_irq_chip, - handle_level_irq); - - irq_set_chained_handler(irq, ar724x_pci_irq_handler); -} - -int __init ar724x_pcibios_init(int irq) -{ - int ret; - - ret = -ENOMEM; - - ar724x_pci_devcfg_base = ioremap(AR724X_PCI_CFG_BASE, - AR724X_PCI_CFG_SIZE); - if (ar724x_pci_devcfg_base == NULL) - goto err; - - ar724x_pci_ctrl_base = ioremap(AR724X_PCI_CTRL_BASE, - AR724X_PCI_CTRL_SIZE); - if (ar724x_pci_ctrl_base == NULL) - goto err_unmap_devcfg; - - ar724x_pci_irq_init(irq); - register_pci_controller(&ar724x_pci_controller); - - return PCIBIOS_SUCCESSFUL; - -err_unmap_devcfg: - iounmap(ar724x_pci_devcfg_base); -err: - return ret; -} diff --git a/trunk/arch/mips/pci/pci-ath724x.c b/trunk/arch/mips/pci/pci-ath724x.c new file mode 100644 index 000000000000..a4dd24a4130b --- /dev/null +++ b/trunk/arch/mips/pci/pci-ath724x.c @@ -0,0 +1,174 @@ +/* + * Atheros 724x PCI support + * + * Copyright (C) 2011 René Bolldorf + * + * 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 + +#define reg_read(_phys) (*(unsigned int *) KSEG1ADDR(_phys)) +#define reg_write(_phys, _val) ((*(unsigned int *) KSEG1ADDR(_phys)) = (_val)) + +#define ATH724X_PCI_DEV_BASE 0x14000000 +#define ATH724X_PCI_MEM_BASE 0x10000000 +#define ATH724X_PCI_MEM_SIZE 0x08000000 + +static DEFINE_SPINLOCK(ath724x_pci_lock); +static struct ath724x_pci_data *pci_data; +static int pci_data_size; + +static int ath724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, + int size, uint32_t *value) +{ + unsigned long flags, addr, tval, mask; + + if (devfn) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (where & (size - 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + spin_lock_irqsave(&ath724x_pci_lock, flags); + + switch (size) { + case 1: + addr = where & ~3; + mask = 0xff000000 >> ((where % 4) * 8); + tval = reg_read(ATH724X_PCI_DEV_BASE + addr); + tval = tval & ~mask; + *value = (tval >> ((4 - (where % 4))*8)); + break; + case 2: + addr = where & ~3; + mask = 0xffff0000 >> ((where % 4)*8); + tval = reg_read(ATH724X_PCI_DEV_BASE + addr); + tval = tval & ~mask; + *value = (tval >> ((4 - (where % 4))*8)); + break; + case 4: + *value = reg_read(ATH724X_PCI_DEV_BASE + where); + break; + default: + spin_unlock_irqrestore(&ath724x_pci_lock, flags); + + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + spin_unlock_irqrestore(&ath724x_pci_lock, flags); + + return PCIBIOS_SUCCESSFUL; +} + +static int ath724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, + int size, uint32_t value) +{ + unsigned long flags, tval, addr, mask; + + if (devfn) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (where & (size - 1)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + spin_lock_irqsave(&ath724x_pci_lock, flags); + + switch (size) { + case 1: + addr = (ATH724X_PCI_DEV_BASE + where) & ~3; + mask = 0xff000000 >> ((where % 4)*8); + tval = reg_read(addr); + tval = tval & ~mask; + tval |= (value << ((4 - (where % 4))*8)) & mask; + reg_write(addr, tval); + break; + case 2: + addr = (ATH724X_PCI_DEV_BASE + where) & ~3; + mask = 0xffff0000 >> ((where % 4)*8); + tval = reg_read(addr); + tval = tval & ~mask; + tval |= (value << ((4 - (where % 4))*8)) & mask; + reg_write(addr, tval); + break; + case 4: + reg_write((ATH724X_PCI_DEV_BASE + where), value); + break; + default: + spin_unlock_irqrestore(&ath724x_pci_lock, flags); + + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + spin_unlock_irqrestore(&ath724x_pci_lock, flags); + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops ath724x_pci_ops = { + .read = ath724x_pci_read, + .write = ath724x_pci_write, +}; + +static struct resource ath724x_io_resource = { + .name = "PCI IO space", + .start = 0, + .end = 0, + .flags = IORESOURCE_IO, +}; + +static struct resource ath724x_mem_resource = { + .name = "PCI memory space", + .start = ATH724X_PCI_MEM_BASE, + .end = ATH724X_PCI_MEM_BASE + ATH724X_PCI_MEM_SIZE - 1, + .flags = IORESOURCE_MEM, +}; + +static struct pci_controller ath724x_pci_controller = { + .pci_ops = &ath724x_pci_ops, + .io_resource = &ath724x_io_resource, + .mem_resource = &ath724x_mem_resource, +}; + +void ath724x_pci_add_data(struct ath724x_pci_data *data, int size) +{ + pci_data = data; + pci_data_size = size; +} + +int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin) +{ + unsigned int devfn = dev->devfn; + int irq = -1; + + if (devfn > pci_data_size - 1) + return irq; + + irq = pci_data[devfn].irq; + + return irq; +} + +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + unsigned int devfn = dev->devfn; + + if (devfn > pci_data_size - 1) + return PCIBIOS_DEVICE_NOT_FOUND; + + dev->dev.platform_data = pci_data[devfn].pdata; + + return PCIBIOS_SUCCESSFUL; +} + +static int __init ath724x_pcibios_init(void) +{ + register_pci_controller(&ath724x_pci_controller); + + return PCIBIOS_SUCCESSFUL; +} + +arch_initcall(ath724x_pcibios_init); diff --git a/trunk/arch/mips/pci/pci-lantiq.c b/trunk/arch/mips/pci/pci-lantiq.c index ea453532a33c..030c77e7926e 100644 --- a/trunk/arch/mips/pci/pci-lantiq.c +++ b/trunk/arch/mips/pci/pci-lantiq.c @@ -13,12 +13,8 @@ #include #include #include -#include -#include -#include -#include -#include -#include +#include +#include #include #include @@ -26,9 +22,17 @@ #include #include +#include #include "pci-lantiq.h" +#define LTQ_PCI_CFG_BASE 0x17000000 +#define LTQ_PCI_CFG_SIZE 0x00008000 +#define LTQ_PCI_MEM_BASE 0x18000000 +#define LTQ_PCI_MEM_SIZE 0x02000000 +#define LTQ_PCI_IO_BASE 0x1AE00000 +#define LTQ_PCI_IO_SIZE 0x00200000 + #define PCI_CR_FCI_ADDR_MAP0 0x00C0 #define PCI_CR_FCI_ADDR_MAP1 0x00C4 #define PCI_CR_FCI_ADDR_MAP2 0x00C8 @@ -64,27 +68,79 @@ #define ltq_pci_cfg_w32(x, y) ltq_w32((x), ltq_pci_mapped_cfg + (y)) #define ltq_pci_cfg_r32(x) ltq_r32(ltq_pci_mapped_cfg + (x)) +struct ltq_pci_gpio_map { + int pin; + int alt0; + int alt1; + int dir; + char *name; +}; + +/* the pci core can make use of the following gpios */ +static struct ltq_pci_gpio_map ltq_pci_gpio_map[] = { + { 0, 1, 0, 0, "pci-exin0" }, + { 1, 1, 0, 0, "pci-exin1" }, + { 2, 1, 0, 0, "pci-exin2" }, + { 39, 1, 0, 0, "pci-exin3" }, + { 10, 1, 0, 0, "pci-exin4" }, + { 9, 1, 0, 0, "pci-exin5" }, + { 30, 1, 0, 1, "pci-gnt1" }, + { 23, 1, 0, 1, "pci-gnt2" }, + { 19, 1, 0, 1, "pci-gnt3" }, + { 38, 1, 0, 1, "pci-gnt4" }, + { 29, 1, 0, 0, "pci-req1" }, + { 31, 1, 0, 0, "pci-req2" }, + { 3, 1, 0, 0, "pci-req3" }, + { 37, 1, 0, 0, "pci-req4" }, +}; + __iomem void *ltq_pci_mapped_cfg; static __iomem void *ltq_pci_membase; -static int reset_gpio; -static struct clk *clk_pci, *clk_external; -static struct resource pci_io_resource; -static struct resource pci_mem_resource; -static struct pci_ops pci_ops = { +int (*ltqpci_plat_dev_init)(struct pci_dev *dev) = NULL; + +/* Since the PCI REQ pins can be reused for other functionality, make it + possible to exclude those from interpretation by the PCI controller */ +static int ltq_pci_req_mask = 0xf; + +static int *ltq_pci_irq_map; + +struct pci_ops ltq_pci_ops = { .read = ltq_pci_read_config_dword, .write = ltq_pci_write_config_dword }; -static struct pci_controller pci_controller = { - .pci_ops = &pci_ops, +static struct resource pci_io_resource = { + .name = "pci io space", + .start = LTQ_PCI_IO_BASE, + .end = LTQ_PCI_IO_BASE + LTQ_PCI_IO_SIZE - 1, + .flags = IORESOURCE_IO +}; + +static struct resource pci_mem_resource = { + .name = "pci memory space", + .start = LTQ_PCI_MEM_BASE, + .end = LTQ_PCI_MEM_BASE + LTQ_PCI_MEM_SIZE - 1, + .flags = IORESOURCE_MEM +}; + +static struct pci_controller ltq_pci_controller = { + .pci_ops = <q_pci_ops, .mem_resource = &pci_mem_resource, .mem_offset = 0x00000000UL, .io_resource = &pci_io_resource, .io_offset = 0x00000000UL, }; -static inline u32 ltq_calc_bar11mask(void) +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + if (ltqpci_plat_dev_init) + return ltqpci_plat_dev_init(dev); + + return 0; +} + +static u32 ltq_calc_bar11mask(void) { u32 mem, bar11mask; @@ -95,42 +151,48 @@ static inline u32 ltq_calc_bar11mask(void) return bar11mask; } -static int __devinit ltq_pci_startup(struct platform_device *pdev) +static void ltq_pci_setup_gpio(int gpio) +{ + int i; + for (i = 0; i < ARRAY_SIZE(ltq_pci_gpio_map); i++) { + if (gpio & (1 << i)) { + ltq_gpio_request(ltq_pci_gpio_map[i].pin, + ltq_pci_gpio_map[i].alt0, + ltq_pci_gpio_map[i].alt1, + ltq_pci_gpio_map[i].dir, + ltq_pci_gpio_map[i].name); + } + } + ltq_gpio_request(21, 0, 0, 1, "pci-reset"); + ltq_pci_req_mask = (gpio >> PCI_REQ_SHIFT) & PCI_REQ_MASK; +} + +static int __devinit ltq_pci_startup(struct ltq_pci_data *conf) { - struct device_node *node = pdev->dev.of_node; - const __be32 *req_mask, *bus_clk; u32 temp_buffer; - /* get our clocks */ - clk_pci = clk_get(&pdev->dev, NULL); - if (IS_ERR(clk_pci)) { - dev_err(&pdev->dev, "failed to get pci clock\n"); - return PTR_ERR(clk_pci); + /* set clock to 33Mhz */ + if (ltq_is_ar9()) { + ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~0x1f00000, LTQ_CGU_IFCCR); + ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | 0xe00000, LTQ_CGU_IFCCR); + } else { + ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~0xf00000, LTQ_CGU_IFCCR); + ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | 0x800000, LTQ_CGU_IFCCR); } - clk_external = clk_get(&pdev->dev, "external"); - if (IS_ERR(clk_external)) { - clk_put(clk_pci); - dev_err(&pdev->dev, "failed to get external pci clock\n"); - return PTR_ERR(clk_external); + /* external or internal clock ? */ + if (conf->clock) { + ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~(1 << 16), + LTQ_CGU_IFCCR); + ltq_cgu_w32((1 << 30), LTQ_CGU_PCICR); + } else { + ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | (1 << 16), + LTQ_CGU_IFCCR); + ltq_cgu_w32((1 << 31) | (1 << 30), LTQ_CGU_PCICR); } - /* read the bus speed that we want */ - bus_clk = of_get_property(node, "lantiq,bus-clock", NULL); - if (bus_clk) - clk_set_rate(clk_pci, *bus_clk); - - /* and enable the clocks */ - clk_enable(clk_pci); - if (of_find_property(node, "lantiq,external-clock", NULL)) - clk_enable(clk_external); - else - clk_disable(clk_external); - - /* setup reset gpio used by pci */ - reset_gpio = of_get_named_gpio(node, "gpio-reset", 0); - if (reset_gpio > 0) - devm_gpio_request(&pdev->dev, reset_gpio, "pci-reset"); + /* setup pci clock and gpis used by pci */ + ltq_pci_setup_gpio(conf->gpio); /* enable auto-switching between PCI and EBU */ ltq_pci_w32(0xa, PCI_CR_CLK_CTRL); @@ -143,12 +205,7 @@ static int __devinit ltq_pci_startup(struct platform_device *pdev) /* enable external 2 PCI masters */ temp_buffer = ltq_pci_r32(PCI_CR_PC_ARB); - /* setup the request mask */ - req_mask = of_get_property(node, "req-mask", NULL); - if (req_mask) - temp_buffer &= ~((*req_mask & 0xf) << 16); - else - temp_buffer &= ~0xf0000; + temp_buffer &= (~(ltq_pci_req_mask << 16)); /* enable internal arbiter */ temp_buffer |= (1 << INTERNAL_ARB_ENABLE_BIT); /* enable internal PCI master reqest */ @@ -192,55 +249,47 @@ static int __devinit ltq_pci_startup(struct platform_device *pdev) ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_IEN) | 0x10, LTQ_EBU_PCC_IEN); /* toggle reset pin */ - if (reset_gpio > 0) { - __gpio_set_value(reset_gpio, 0); - wmb(); - mdelay(1); - __gpio_set_value(reset_gpio, 1); - } + __gpio_set_value(21, 0); + wmb(); + mdelay(1); + __gpio_set_value(21, 1); return 0; } -static int __devinit ltq_pci_probe(struct platform_device *pdev) +int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { - struct resource *res_cfg, *res_bridge; + if (ltq_pci_irq_map[slot]) + return ltq_pci_irq_map[slot]; + printk(KERN_ERR "lq_pci: trying to map irq for unknown slot %d\n", + slot); - pci_clear_flags(PCI_PROBE_ONLY); - - res_cfg = platform_get_resource(pdev, IORESOURCE_MEM, 0); - res_bridge = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!res_cfg || !res_bridge) { - dev_err(&pdev->dev, "missing memory reources\n"); - return -EINVAL; - } - - ltq_pci_membase = devm_request_and_ioremap(&pdev->dev, res_bridge); - ltq_pci_mapped_cfg = devm_request_and_ioremap(&pdev->dev, res_cfg); + return 0; +} - if (!ltq_pci_membase || !ltq_pci_mapped_cfg) { - dev_err(&pdev->dev, "failed to remap resources\n"); - return -ENOMEM; - } +static int __devinit ltq_pci_probe(struct platform_device *pdev) +{ + struct ltq_pci_data *ltq_pci_data = + (struct ltq_pci_data *) pdev->dev.platform_data; - ltq_pci_startup(pdev); + pci_clear_flags(PCI_PROBE_ONLY); + ltq_pci_irq_map = ltq_pci_data->irq; + ltq_pci_membase = ioremap_nocache(PCI_CR_BASE_ADDR, PCI_CR_SIZE); + ltq_pci_mapped_cfg = + ioremap_nocache(LTQ_PCI_CFG_BASE, LTQ_PCI_CFG_BASE); + ltq_pci_controller.io_map_base = + (unsigned long)ioremap(LTQ_PCI_IO_BASE, LTQ_PCI_IO_SIZE - 1); + ltq_pci_startup(ltq_pci_data); + register_pci_controller(<q_pci_controller); - pci_load_of_ranges(&pci_controller, pdev->dev.of_node); - register_pci_controller(&pci_controller); return 0; } -static const struct of_device_id ltq_pci_match[] = { - { .compatible = "lantiq,pci-xway" }, - {}, -}; -MODULE_DEVICE_TABLE(of, ltq_pci_match); - -static struct platform_driver ltq_pci_driver = { +static struct platform_driver +ltq_pci_driver = { .probe = ltq_pci_probe, .driver = { - .name = "pci-xway", + .name = "ltq_pci", .owner = THIS_MODULE, - .of_match_table = ltq_pci_match, }, }; @@ -248,7 +297,7 @@ int __init pcibios_init(void) { int ret = platform_driver_register(<q_pci_driver); if (ret) - pr_info("pci-xway: Error registering platform driver!"); + printk(KERN_INFO "ltq_pci: Error registering platfom driver!"); return ret; } diff --git a/trunk/arch/mips/pci/pci.c b/trunk/arch/mips/pci/pci.c index 271e8c4a54c7..0514866fa925 100644 --- a/trunk/arch/mips/pci/pci.c +++ b/trunk/arch/mips/pci/pci.c @@ -16,7 +16,6 @@ #include #include #include -#include #include @@ -115,63 +114,9 @@ static void __devinit pcibios_scanbus(struct pci_controller *hose) pci_bus_assign_resources(bus); pci_enable_bridges(bus); } - bus->dev.of_node = hose->of_node; } } -#ifdef CONFIG_OF -void __devinit pci_load_of_ranges(struct pci_controller *hose, - struct device_node *node) -{ - const __be32 *ranges; - int rlen; - int pna = of_n_addr_cells(node); - int np = pna + 5; - - pr_info("PCI host bridge %s ranges:\n", node->full_name); - ranges = of_get_property(node, "ranges", &rlen); - if (ranges == NULL) - return; - hose->of_node = node; - - while ((rlen -= np * 4) >= 0) { - u32 pci_space; - struct resource *res = NULL; - u64 addr, size; - - pci_space = be32_to_cpup(&ranges[0]); - addr = of_translate_address(node, ranges + 3); - size = of_read_number(ranges + pna + 3, 2); - ranges += np; - switch ((pci_space >> 24) & 0x3) { - case 1: /* PCI IO space */ - pr_info(" IO 0x%016llx..0x%016llx\n", - addr, addr + size - 1); - hose->io_map_base = - (unsigned long)ioremap(addr, size); - res = hose->io_resource; - res->flags = IORESOURCE_IO; - break; - case 2: /* PCI Memory space */ - case 3: /* PCI 64 bits Memory space */ - pr_info(" MEM 0x%016llx..0x%016llx\n", - addr, addr + size - 1); - res = hose->mem_resource; - res->flags = IORESOURCE_MEM; - break; - } - if (res != NULL) { - res->start = addr; - res->name = node->full_name; - res->end = res->start + size - 1; - res->parent = NULL; - res->sibling = NULL; - res->child = NULL; - } - } -} -#endif - static DEFINE_MUTEX(pci_scan_mutex); void __devinit register_pci_controller(struct pci_controller *hose) diff --git a/trunk/arch/mips/pmc-sierra/yosemite/Makefile b/trunk/arch/mips/pmc-sierra/yosemite/Makefile index 5af95ec3319d..02f5fb94ea28 100644 --- a/trunk/arch/mips/pmc-sierra/yosemite/Makefile +++ b/trunk/arch/mips/pmc-sierra/yosemite/Makefile @@ -5,3 +5,5 @@ obj-y += irq.o prom.o py-console.o setup.o obj-$(CONFIG_SMP) += smp.o + +ccflags-y := -Werror diff --git a/trunk/arch/mips/pmc-sierra/yosemite/setup.c b/trunk/arch/mips/pmc-sierra/yosemite/setup.c index b6472fc88a99..3498ac9c35af 100644 --- a/trunk/arch/mips/pmc-sierra/yosemite/setup.c +++ b/trunk/arch/mips/pmc-sierra/yosemite/setup.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/arch/mips/pnx833x/common/platform.c b/trunk/arch/mips/pnx833x/common/platform.c index 05a1d922cd60..87167dcc79fa 100644 --- a/trunk/arch/mips/pnx833x/common/platform.c +++ b/trunk/arch/mips/pnx833x/common/platform.c @@ -244,6 +244,11 @@ static struct platform_device pnx833x_sata_device = { .resource = pnx833x_sata_resources, }; +static const char *part_probes[] = { + "cmdlinepart", + NULL +}; + static void pnx833x_flash_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) { @@ -263,6 +268,7 @@ static struct platform_nand_data pnx833x_flash_nand_data = { .chip = { .nr_chips = 1, .chip_delay = 25, + .part_probe_types = part_probes, }, .ctrl = { .cmd_ctrl = pnx833x_flash_nand_cmd_ctrl diff --git a/trunk/arch/mips/powertv/Makefile b/trunk/arch/mips/powertv/Makefile index 39ca9f8d63ae..348d2e850ef5 100644 --- a/trunk/arch/mips/powertv/Makefile +++ b/trunk/arch/mips/powertv/Makefile @@ -27,3 +27,5 @@ obj-y += init.o ioremap.o memory.o powertv_setup.o reset.o time.o \ asic/ pci/ obj-$(CONFIG_USB) += powertv-usb.o + +ccflags-y := -Wall diff --git a/trunk/arch/mips/powertv/asic/Makefile b/trunk/arch/mips/powertv/asic/Makefile index 35dcc53eb25f..d810a33182a4 100644 --- a/trunk/arch/mips/powertv/asic/Makefile +++ b/trunk/arch/mips/powertv/asic/Makefile @@ -19,3 +19,5 @@ obj-y += asic-calliope.o asic-cronus.o asic-gaia.o asic-zeus.o \ asic_devices.o asic_int.o irq_asic.o prealloc-calliope.o \ prealloc-cronus.o prealloc-cronuslite.o prealloc-gaia.o prealloc-zeus.o + +ccflags-y := -Wall -Werror diff --git a/trunk/arch/mips/powertv/pci/Makefile b/trunk/arch/mips/powertv/pci/Makefile index 2610a6af5b2c..5783201cd2c8 100644 --- a/trunk/arch/mips/powertv/pci/Makefile +++ b/trunk/arch/mips/powertv/pci/Makefile @@ -17,3 +17,5 @@ # obj-$(CONFIG_PCI) += fixup-powertv.o + +ccflags-y := -Wall -Werror diff --git a/trunk/arch/mips/rb532/devices.c b/trunk/arch/mips/rb532/devices.c index 716e9a12f0e7..a969eb826634 100644 --- a/trunk/arch/mips/rb532/devices.c +++ b/trunk/arch/mips/rb532/devices.c @@ -15,7 +15,6 @@ * GNU General Public License for more details. */ #include -#include #include #include #include @@ -293,6 +292,7 @@ static void __init rb532_nand_setup(void) rb532_nand_data.chip.nr_partitions = ARRAY_SIZE(rb532_partition_info); rb532_nand_data.chip.partitions = rb532_partition_info; rb532_nand_data.chip.chip_delay = NAND_CHIP_DELAY; + rb532_nand_data.chip.options = NAND_NO_AUTOINCR; } diff --git a/trunk/arch/mips/sni/setup.c b/trunk/arch/mips/sni/setup.c index 413f17f8e892..d16b462154c3 100644 --- a/trunk/arch/mips/sni/setup.c +++ b/trunk/arch/mips/sni/setup.c @@ -10,7 +10,6 @@ */ #include #include -#include #include #include #include diff --git a/trunk/arch/mn10300/include/asm/posix_types.h b/trunk/arch/mn10300/include/asm/posix_types.h index d31eeea480cf..ab506181ec31 100644 --- a/trunk/arch/mn10300/include/asm/posix_types.h +++ b/trunk/arch/mn10300/include/asm/posix_types.h @@ -20,6 +20,9 @@ typedef unsigned short __kernel_mode_t; #define __kernel_mode_t __kernel_mode_t +typedef unsigned short __kernel_nlink_t; +#define __kernel_nlink_t __kernel_nlink_t + typedef unsigned short __kernel_ipc_pid_t; #define __kernel_ipc_pid_t __kernel_ipc_pid_t diff --git a/trunk/arch/mn10300/kernel/signal.c b/trunk/arch/mn10300/kernel/signal.c index 6ab0bee2a54f..890cf91767cc 100644 --- a/trunk/arch/mn10300/kernel/signal.c +++ b/trunk/arch/mn10300/kernel/signal.c @@ -31,6 +31,8 @@ #define DEBUG_SIG 0 +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + /* * atomically swap in the new signal mask, and wait for a signal. */ @@ -161,6 +163,7 @@ asmlinkage long sys_sigreturn(void) sizeof(frame->extramask))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(current_frame(), &frame->sc, &d0)) @@ -188,6 +191,7 @@ asmlinkage long sys_rt_sigreturn(void) if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(current_frame(), &frame->uc.uc_mcontext, &d0)) @@ -426,9 +430,8 @@ static inline void stepback(struct pt_regs *regs) */ static int handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka, - struct pt_regs *regs) + sigset_t *oldset, struct pt_regs *regs) { - sigset_t *oldset = sigmask_to_save(); int ret; /* Are we from a system call? */ @@ -458,11 +461,11 @@ static int handle_signal(int sig, ret = setup_rt_frame(sig, ka, info, oldset, regs); else ret = setup_frame(sig, ka, oldset, regs); - if (ret) - return; - signal_delivered(sig, info, ka, regs, - test_thread_flag(TIF_SINGLESTEP)); + if (ret == 0) + block_sigmask(ka, sig); + + return ret; } /* @@ -472,6 +475,7 @@ static void do_signal(struct pt_regs *regs) { struct k_sigaction ka; siginfo_t info; + sigset_t *oldset; int signr; /* we want the common case to go fast, which is why we may in certain @@ -479,9 +483,23 @@ static void do_signal(struct pt_regs *regs) if (!user_mode(regs)) return; + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { - if (handle_signal(signr, &info, &ka, regs) == 0) { + if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { + /* a signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TIF_RESTORE_SIGMASK flag */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + + tracehook_signal_handler(signr, &info, &ka, regs, + test_thread_flag(TIF_SINGLESTEP)); } return; @@ -507,7 +525,10 @@ static void do_signal(struct pt_regs *regs) /* if there's no signal to deliver, we just put the saved sigmask * back */ - restore_saved_sigmask(); + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } } /* @@ -527,11 +548,13 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags) } /* deal with pending signal delivery */ - if (thread_info_flags & _TIF_SIGPENDING) + if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) do_signal(regs); if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(current_frame()); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/trunk/arch/openrisc/kernel/signal.c b/trunk/arch/openrisc/kernel/signal.c index 30110297f4f9..e970743251ae 100644 --- a/trunk/arch/openrisc/kernel/signal.c +++ b/trunk/arch/openrisc/kernel/signal.c @@ -33,6 +33,8 @@ #define DEBUG_SIG 0 +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + asmlinkage long _sys_sigaltstack(const stack_t *uss, stack_t *uoss, struct pt_regs *regs) { @@ -99,6 +101,7 @@ asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs) if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) @@ -248,19 +251,20 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, return -EFAULT; } -static inline void +static inline int handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, - struct pt_regs *regs) + sigset_t *oldset, struct pt_regs *regs) { int ret; - ret = setup_rt_frame(sig, ka, info, sigmask_to_save(), regs); + ret = setup_rt_frame(sig, ka, info, oldset, regs); if (ret) - return; + return ret; + + block_sigmask(ka, sig); - signal_delivered(sig, info, ka, regs, - test_thread_flag(TIF_SINGLESTEP)); + return 0; } /* @@ -335,10 +339,30 @@ void do_signal(struct pt_regs *regs) if (signr <= 0) { /* no signal to deliver so we just put the saved sigmask * back */ - restore_saved_sigmask(); + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } + } else { /* signr > 0 */ + sigset_t *oldset; + + if (current_thread_info()->flags & _TIF_RESTORE_SIGMASK) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + /* Whee! Actually deliver the signal. */ - handle_signal(signr, &info, &ka, regs); + if (!handle_signal(signr, &info, &ka, oldset, regs)) { + /* a signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TIF_RESTORE_SIGMASK flag */ + clear_thread_flag(TIF_RESTORE_SIGMASK); + } + + tracehook_signal_handler(signr, &info, &ka, regs, + test_thread_flag(TIF_SINGLESTEP)); } return; @@ -352,5 +376,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs) if (current_thread_info()->flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/trunk/arch/parisc/Kconfig b/trunk/arch/parisc/Kconfig index 3ff21b536f28..ddb8b24b823d 100644 --- a/trunk/arch/parisc/Kconfig +++ b/trunk/arch/parisc/Kconfig @@ -18,7 +18,6 @@ config PARISC select IRQ_PER_CPU select ARCH_HAVE_NMI_SAFE_CMPXCHG select GENERIC_SMP_IDLE_THREAD - select GENERIC_STRNCPY_FROM_USER help The PA-RISC microprocessor is designed by Hewlett-Packard and used diff --git a/trunk/arch/parisc/include/asm/posix_types.h b/trunk/arch/parisc/include/asm/posix_types.h index b9344256f76b..5212b0357daf 100644 --- a/trunk/arch/parisc/include/asm/posix_types.h +++ b/trunk/arch/parisc/include/asm/posix_types.h @@ -10,6 +10,9 @@ typedef unsigned short __kernel_mode_t; #define __kernel_mode_t __kernel_mode_t +typedef unsigned short __kernel_nlink_t; +#define __kernel_nlink_t __kernel_nlink_t + typedef unsigned short __kernel_ipc_pid_t; #define __kernel_ipc_pid_t __kernel_ipc_pid_t diff --git a/trunk/arch/parisc/include/asm/smp.h b/trunk/arch/parisc/include/asm/smp.h index a5dc9066c6d8..e8f8037d872b 100644 --- a/trunk/arch/parisc/include/asm/smp.h +++ b/trunk/arch/parisc/include/asm/smp.h @@ -25,6 +25,7 @@ typedef unsigned long address_t; #define cpu_number_map(cpu) (cpu) #define cpu_logical_map(cpu) (cpu) +extern void smp_send_reschedule(int cpu); extern void smp_send_all_nop(void); extern void arch_send_call_function_single_ipi(int cpu); @@ -49,5 +50,6 @@ static inline void __cpu_die (unsigned int cpu) { while(1) ; } +extern int __cpu_up (unsigned int cpu); #endif /* __ASM_SMP_H */ diff --git a/trunk/arch/parisc/include/asm/stat.h b/trunk/arch/parisc/include/asm/stat.h index d76fbda5d62c..9d5fbbc5c31f 100644 --- a/trunk/arch/parisc/include/asm/stat.h +++ b/trunk/arch/parisc/include/asm/stat.h @@ -7,7 +7,7 @@ struct stat { unsigned int st_dev; /* dev_t is 32 bits on parisc */ ino_t st_ino; /* 32 bits */ mode_t st_mode; /* 16 bits */ - unsigned short st_nlink; /* 16 bits */ + nlink_t st_nlink; /* 16 bits */ unsigned short st_reserved1; /* old st_uid */ unsigned short st_reserved2; /* old st_gid */ unsigned int st_rdev; @@ -42,7 +42,7 @@ struct hpux_stat64 { unsigned int st_dev; /* dev_t is 32 bits on parisc */ ino_t st_ino; /* 32 bits */ mode_t st_mode; /* 16 bits */ - unsigned short st_nlink; /* 16 bits */ + nlink_t st_nlink; /* 16 bits */ unsigned short st_reserved1; /* old st_uid */ unsigned short st_reserved2; /* old st_gid */ unsigned int st_rdev; diff --git a/trunk/arch/parisc/include/asm/thread_info.h b/trunk/arch/parisc/include/asm/thread_info.h index 22b4726dee49..83ae7dd4d99e 100644 --- a/trunk/arch/parisc/include/asm/thread_info.h +++ b/trunk/arch/parisc/include/asm/thread_info.h @@ -74,7 +74,7 @@ struct thread_info { #define _TIF_BLOCKSTEP (1 << TIF_BLOCKSTEP) #define _TIF_USER_WORK_MASK (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | \ - _TIF_NEED_RESCHED) + _TIF_NEED_RESCHED | _TIF_RESTORE_SIGMASK) #endif /* __KERNEL__ */ diff --git a/trunk/arch/parisc/include/asm/uaccess.h b/trunk/arch/parisc/include/asm/uaccess.h index 4ba2c93770f1..9ac066086f03 100644 --- a/trunk/arch/parisc/include/asm/uaccess.h +++ b/trunk/arch/parisc/include/asm/uaccess.h @@ -218,14 +218,15 @@ struct exception_data { extern unsigned long lcopy_to_user(void __user *, const void *, unsigned long); extern unsigned long lcopy_from_user(void *, const void __user *, unsigned long); extern unsigned long lcopy_in_user(void __user *, const void __user *, unsigned long); -extern long strncpy_from_user(char *, const char __user *, long); +extern long lstrncpy_from_user(char *, const char __user *, long); extern unsigned lclear_user(void __user *,unsigned long); extern long lstrnlen_user(const char __user *,long); + /* * Complex access routines -- macros */ -#define user_addr_max() (~0UL) +#define strncpy_from_user lstrncpy_from_user #define strnlen_user lstrnlen_user #define strlen_user(str) lstrnlen_user(str, 0x7fffffffL) #define clear_user lclear_user diff --git a/trunk/arch/parisc/kernel/entry.S b/trunk/arch/parisc/kernel/entry.S index 18670a078849..535034217021 100644 --- a/trunk/arch/parisc/kernel/entry.S +++ b/trunk/arch/parisc/kernel/entry.S @@ -552,7 +552,7 @@ * entry (identifying the physical page) and %r23 up with * the from tlb entry (or nothing if only a to entry---for * clear_user_page_asm) */ - .macro do_alias spc,tmp,tmp1,va,pte,prot,fault,patype + .macro do_alias spc,tmp,tmp1,va,pte,prot,fault cmpib,COND(<>),n 0,\spc,\fault ldil L%(TMPALIAS_MAP_START),\tmp #if defined(CONFIG_64BIT) && (TMPALIAS_MAP_START >= 0x80000000) @@ -581,15 +581,11 @@ */ cmpiclr,= 0x01,\tmp,%r0 ldi (_PAGE_DIRTY|_PAGE_READ|_PAGE_WRITE),\prot -.ifc \patype,20 +#ifdef CONFIG_64BIT depd,z \prot,8,7,\prot -.else -.ifc \patype,11 +#else depw,z \prot,8,7,\prot -.else - .error "undefined PA type to do_alias" -.endif -.endif +#endif /* * OK, it is in the temp alias region, check whether "from" or "to". * Check "subtle" note in pacache.S re: r23/r26. @@ -924,7 +920,7 @@ intr_check_sig: /* As above */ mfctl %cr30,%r1 LDREG TI_FLAGS(%r1),%r19 - ldi (_TIF_SIGPENDING|_TIF_NOTIFY_RESUME), %r20 + ldi (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK|_TIF_NOTIFY_RESUME), %r20 and,COND(<>) %r19, %r20, %r0 b,n intr_restore /* skip past if we've nothing to do */ @@ -1193,7 +1189,7 @@ dtlb_miss_20w: nop dtlb_check_alias_20w: - do_alias spc,t0,t1,va,pte,prot,dtlb_fault,20 + do_alias spc,t0,t1,va,pte,prot,dtlb_fault idtlbt pte,prot @@ -1217,7 +1213,7 @@ nadtlb_miss_20w: nop nadtlb_check_alias_20w: - do_alias spc,t0,t1,va,pte,prot,nadtlb_emulate,20 + do_alias spc,t0,t1,va,pte,prot,nadtlb_emulate idtlbt pte,prot @@ -1249,7 +1245,7 @@ dtlb_miss_11: nop dtlb_check_alias_11: - do_alias spc,t0,t1,va,pte,prot,dtlb_fault,11 + do_alias spc,t0,t1,va,pte,prot,dtlb_fault idtlba pte,(va) idtlbp prot,(va) @@ -1281,7 +1277,7 @@ nadtlb_miss_11: nop nadtlb_check_alias_11: - do_alias spc,t0,t1,va,pte,prot,nadtlb_emulate,11 + do_alias spc,t0,t1,va,pte,prot,nadtlb_emulate idtlba pte,(va) idtlbp prot,(va) @@ -1308,7 +1304,7 @@ dtlb_miss_20: nop dtlb_check_alias_20: - do_alias spc,t0,t1,va,pte,prot,dtlb_fault,20 + do_alias spc,t0,t1,va,pte,prot,dtlb_fault idtlbt pte,prot @@ -1334,7 +1330,7 @@ nadtlb_miss_20: nop nadtlb_check_alias_20: - do_alias spc,t0,t1,va,pte,prot,nadtlb_emulate,20 + do_alias spc,t0,t1,va,pte,prot,nadtlb_emulate idtlbt pte,prot @@ -1461,7 +1457,7 @@ naitlb_miss_20w: nop naitlb_check_alias_20w: - do_alias spc,t0,t1,va,pte,prot,naitlb_fault,20 + do_alias spc,t0,t1,va,pte,prot,naitlb_fault iitlbt pte,prot @@ -1515,7 +1511,7 @@ naitlb_miss_11: nop naitlb_check_alias_11: - do_alias spc,t0,t1,va,pte,prot,itlb_fault,11 + do_alias spc,t0,t1,va,pte,prot,itlb_fault iitlba pte,(%sr0, va) iitlbp prot,(%sr0, va) @@ -1561,7 +1557,7 @@ naitlb_miss_20: nop naitlb_check_alias_20: - do_alias spc,t0,t1,va,pte,prot,naitlb_fault,20 + do_alias spc,t0,t1,va,pte,prot,naitlb_fault iitlbt pte,prot @@ -2032,7 +2028,7 @@ syscall_check_resched: .import do_signal,code syscall_check_sig: LDREG TI_FLAGS-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r19 - ldi (_TIF_SIGPENDING|_TIF_NOTIFY_RESUME), %r26 + ldi (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK), %r26 and,COND(<>) %r19, %r26, %r0 b,n syscall_restore /* skip past if we've nothing to do */ diff --git a/trunk/arch/parisc/kernel/parisc_ksyms.c b/trunk/arch/parisc/kernel/parisc_ksyms.c index ceec85de6290..a7bb757a5497 100644 --- a/trunk/arch/parisc/kernel/parisc_ksyms.c +++ b/trunk/arch/parisc/kernel/parisc_ksyms.c @@ -44,6 +44,7 @@ EXPORT_SYMBOL(__cmpxchg_u64); #endif #include +EXPORT_SYMBOL(lstrncpy_from_user); EXPORT_SYMBOL(lclear_user); EXPORT_SYMBOL(lstrnlen_user); diff --git a/trunk/arch/parisc/kernel/signal.c b/trunk/arch/parisc/kernel/signal.c index 594459bde14e..4b9cb0d546d1 100644 --- a/trunk/arch/parisc/kernel/signal.c +++ b/trunk/arch/parisc/kernel/signal.c @@ -48,6 +48,9 @@ #define DBG(LEVEL, ...) #endif + +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + /* gcc will complain if a pointer is cast to an integer of different * size. If you really need to do this (and we do for an ELF32 user * application in an ELF64 kernel) then you have to do a cast to an @@ -128,6 +131,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) goto give_sigsegv; } + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); /* Good thing we saved the old gr[30], eh? */ @@ -439,9 +443,8 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, static long handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, - struct pt_regs *regs, int in_syscall) + sigset_t *oldset, struct pt_regs *regs, int in_syscall) { - sigset_t *oldset = sigmask_to_save(); DBG(1,"handle_signal: sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p\n", sig, ka, info, oldset, regs); @@ -449,13 +452,12 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall)) return 0; - signal_delivered(sig, info, ka, regs, + block_sigmask(ka, sig); + + tracehook_signal_handler(sig, info, ka, regs, test_thread_flag(TIF_SINGLESTEP) || test_thread_flag(TIF_BLOCKSTEP)); - DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n", - regs->gr[28]); - return 1; } @@ -566,17 +568,28 @@ do_signal(struct pt_regs *regs, long in_syscall) siginfo_t info; struct k_sigaction ka; int signr; + sigset_t *oldset; - DBG(1,"\ndo_signal: regs=0x%p, sr7 %#lx, in_syscall=%d\n", - regs, regs->sr[7], in_syscall); + DBG(1,"\ndo_signal: oldset=0x%p, regs=0x%p, sr7 %#lx, in_syscall=%d\n", + oldset, regs, regs->sr[7], in_syscall); /* Everyone else checks to see if they are in kernel mode at this point and exits if that's the case. I'm not sure why we would be called in that case, but for some reason we are. */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + + DBG(1,"do_signal: oldset %08lx / %08lx\n", + oldset->sig[0], oldset->sig[1]); + + /* May need to force signal if handle_signal failed to deliver */ while (1) { + signr = get_signal_to_deliver(&info, &ka, regs, NULL); DBG(3,"do_signal: signr = %d, regs->gr[28] = %ld\n", signr, regs->gr[28]); @@ -590,8 +603,14 @@ do_signal(struct pt_regs *regs, long in_syscall) /* Whee! Actually deliver the signal. If the delivery failed, we need to continue to iterate in this loop so we can deliver the SIGSEGV... */ - if (handle_signal(signr, &info, &ka, regs, in_syscall)) + if (handle_signal(signr, &info, &ka, oldset, + regs, in_syscall)) { + DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n", + regs->gr[28]); + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); return; + } } /* end of while(1) looping forever if we can't force a signal */ @@ -602,16 +621,24 @@ do_signal(struct pt_regs *regs, long in_syscall) DBG(1,"do_signal: Exit (not delivered), regs->gr[28] = %ld\n", regs->gr[28]); - restore_saved_sigmask(); + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } + + return; } void do_notify_resume(struct pt_regs *regs, long in_syscall) { - if (test_thread_flag(TIF_SIGPENDING)) + if (test_thread_flag(TIF_SIGPENDING) || + test_thread_flag(TIF_RESTORE_SIGMASK)) do_signal(regs, in_syscall); if (test_thread_flag(TIF_NOTIFY_RESUME)) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/trunk/arch/parisc/kernel/signal32.c b/trunk/arch/parisc/kernel/signal32.c index fd49aeda9eb8..e14132430762 100644 --- a/trunk/arch/parisc/kernel/signal32.c +++ b/trunk/arch/parisc/kernel/signal32.c @@ -47,6 +47,8 @@ #define DBG(LEVEL, ...) #endif +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + inline void sigset_32to64(sigset_t *s64, compat_sigset_t *s32) { diff --git a/trunk/arch/parisc/kernel/vmlinux.lds.S b/trunk/arch/parisc/kernel/vmlinux.lds.S index 64a999882e4f..fa6f2b8163e0 100644 --- a/trunk/arch/parisc/kernel/vmlinux.lds.S +++ b/trunk/arch/parisc/kernel/vmlinux.lds.S @@ -50,10 +50,8 @@ SECTIONS . = KERNEL_BINARY_TEXT_START; _text = .; /* Text and read-only data */ - .head ALIGN(16) : { - HEAD_TEXT - } = 0 .text ALIGN(16) : { + HEAD_TEXT TEXT_TEXT SCHED_TEXT LOCK_TEXT @@ -67,7 +65,7 @@ SECTIONS *(.fixup) *(.lock.text) /* out-of-line lock text */ *(.gnu.warning) - } + } = 0 /* End of text section */ _etext = .; diff --git a/trunk/arch/parisc/lib/lusercopy.S b/trunk/arch/parisc/lib/lusercopy.S index 6f2d9355efe2..1bd23ccec17b 100644 --- a/trunk/arch/parisc/lib/lusercopy.S +++ b/trunk/arch/parisc/lib/lusercopy.S @@ -60,6 +60,47 @@ bv %r0(%r1) .endm + /* + * long lstrncpy_from_user(char *dst, const char *src, long n) + * + * Returns -EFAULT if exception before terminator, + * N if the entire buffer filled, + * otherwise strlen (i.e. excludes zero byte) + */ + +ENTRY(lstrncpy_from_user) + .proc + .callinfo NO_CALLS + .entry + comib,= 0,%r24,$lsfu_done + copy %r24,%r23 + get_sr +1: ldbs,ma 1(%sr1,%r25),%r1 +$lsfu_loop: + stbs,ma %r1,1(%r26) + comib,=,n 0,%r1,$lsfu_done + addib,<>,n -1,%r24,$lsfu_loop +2: ldbs,ma 1(%sr1,%r25),%r1 +$lsfu_done: + sub %r23,%r24,%r28 +$lsfu_exit: + bv %r0(%r2) + nop + .exit +ENDPROC(lstrncpy_from_user) + + .section .fixup,"ax" +3: fixup_branch $lsfu_exit + ldi -EFAULT,%r28 + .previous + + .section __ex_table,"aw" + ASM_ULONG_INSN 1b,3b + ASM_ULONG_INSN 2b,3b + .previous + + .procend + /* * unsigned long lclear_user(void *to, unsigned long n) * diff --git a/trunk/arch/powerpc/include/asm/posix_types.h b/trunk/arch/powerpc/include/asm/posix_types.h index 2958c5b97b2d..f1393252bbda 100644 --- a/trunk/arch/powerpc/include/asm/posix_types.h +++ b/trunk/arch/powerpc/include/asm/posix_types.h @@ -16,6 +16,9 @@ typedef int __kernel_ssize_t; typedef long __kernel_ptrdiff_t; #define __kernel_size_t __kernel_size_t +typedef unsigned short __kernel_nlink_t; +#define __kernel_nlink_t __kernel_nlink_t + typedef short __kernel_ipc_pid_t; #define __kernel_ipc_pid_t __kernel_ipc_pid_t #endif diff --git a/trunk/arch/powerpc/include/asm/stat.h b/trunk/arch/powerpc/include/asm/stat.h index 10cfb558e0fd..e4edc510b530 100644 --- a/trunk/arch/powerpc/include/asm/stat.h +++ b/trunk/arch/powerpc/include/asm/stat.h @@ -30,11 +30,11 @@ struct stat { unsigned long st_dev; ino_t st_ino; #ifdef __powerpc64__ - unsigned short st_nlink; + nlink_t st_nlink; mode_t st_mode; #else mode_t st_mode; - unsigned short st_nlink; + nlink_t st_nlink; #endif uid_t st_uid; gid_t st_gid; diff --git a/trunk/arch/powerpc/include/asm/thread_info.h b/trunk/arch/powerpc/include/asm/thread_info.h index 68831e9cf82f..a556ccc16b58 100644 --- a/trunk/arch/powerpc/include/asm/thread_info.h +++ b/trunk/arch/powerpc/include/asm/thread_info.h @@ -140,23 +140,7 @@ static inline void set_restore_sigmask(void) { struct thread_info *ti = current_thread_info(); ti->local_flags |= _TLF_RESTORE_SIGMASK; - WARN_ON(!test_bit(TIF_SIGPENDING, &ti->flags)); -} -static inline void clear_restore_sigmask(void) -{ - current_thread_info()->local_flags &= ~_TLF_RESTORE_SIGMASK; -} -static inline bool test_restore_sigmask(void) -{ - return current_thread_info()->local_flags & _TLF_RESTORE_SIGMASK; -} -static inline bool test_and_clear_restore_sigmask(void) -{ - struct thread_info *ti = current_thread_info(); - if (!(ti->local_flags & _TLF_RESTORE_SIGMASK)) - return false; - ti->local_flags &= ~_TLF_RESTORE_SIGMASK; - return true; + set_bit(TIF_SIGPENDING, &ti->flags); } static inline bool test_thread_local_flags(unsigned int flags) diff --git a/trunk/arch/powerpc/kernel/signal.c b/trunk/arch/powerpc/kernel/signal.c index 5c023c9cf16e..651c5963662b 100644 --- a/trunk/arch/powerpc/kernel/signal.c +++ b/trunk/arch/powerpc/kernel/signal.c @@ -51,6 +51,16 @@ void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, return (void __user *)newsp; } + +/* + * Restore the user process's signal mask + */ +void restore_sigmask(sigset_t *set) +{ + sigdelsetmask(set, ~_BLOCKABLE); + set_current_blocked(set); +} + static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) { @@ -104,21 +114,30 @@ static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka, static int do_signal(struct pt_regs *regs) { - sigset_t *oldset = sigmask_to_save(); + sigset_t *oldset; siginfo_t info; int signr; struct k_sigaction ka; int ret; int is32 = is_32bit_task(); + if (current_thread_info()->local_flags & _TLF_RESTORE_SIGMASK) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); /* Is there any syscall restart business here ? */ check_syscall_restart(regs, &ka, signr > 0); if (signr <= 0) { + struct thread_info *ti = current_thread_info(); /* No signal to deliver -- put the saved sigmask back */ - restore_saved_sigmask(); + if (ti->local_flags & _TLF_RESTORE_SIGMASK) { + ti->local_flags &= ~_TLF_RESTORE_SIGMASK; + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } regs->trap = 0; return 0; /* no signals delivered */ } @@ -148,7 +167,18 @@ static int do_signal(struct pt_regs *regs) regs->trap = 0; if (ret) { - signal_delivered(signr, &info, &ka, regs, + block_sigmask(&ka, signr); + + /* + * A signal was successfully delivered; the saved sigmask is in + * its frame, and we can clear the TLF_RESTORE_SIGMASK flag. + */ + current_thread_info()->local_flags &= ~_TLF_RESTORE_SIGMASK; + + /* + * Let tracing know that we've done the handler setup. + */ + tracehook_signal_handler(signr, &info, &ka, regs, test_thread_flag(TIF_SINGLESTEP)); } @@ -163,6 +193,8 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/trunk/arch/powerpc/kernel/signal.h b/trunk/arch/powerpc/kernel/signal.h index e00acb413934..8dde973aaaf5 100644 --- a/trunk/arch/powerpc/kernel/signal.h +++ b/trunk/arch/powerpc/kernel/signal.h @@ -10,10 +10,13 @@ #ifndef _POWERPC_ARCH_SIGNAL_H #define _POWERPC_ARCH_SIGNAL_H +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + extern void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags); extern void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size, int is_32); +extern void restore_sigmask(sigset_t *set); extern int handle_signal32(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, diff --git a/trunk/arch/powerpc/kernel/signal_32.c b/trunk/arch/powerpc/kernel/signal_32.c index 8b4c049aee20..61f6aff25edc 100644 --- a/trunk/arch/powerpc/kernel/signal_32.c +++ b/trunk/arch/powerpc/kernel/signal_32.c @@ -919,7 +919,7 @@ static int do_setcontext(struct ucontext __user *ucp, struct pt_regs *regs, int if (!access_ok(VERIFY_READ, mcp, sizeof(*mcp))) return -EFAULT; #endif - set_current_blocked(&set); + restore_sigmask(&set); if (restore_user_regs(regs, mcp, sig)) return -EFAULT; @@ -1273,7 +1273,7 @@ long sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, set.sig[0] = sigctx.oldmask; set.sig[1] = sigctx._unused[3]; #endif - set_current_blocked(&set); + restore_sigmask(&set); sr = (struct mcontext __user *)from_user_ptr(sigctx.regs); addr = sr; diff --git a/trunk/arch/powerpc/kernel/signal_64.c b/trunk/arch/powerpc/kernel/signal_64.c index d183f8719a50..2692efdb154e 100644 --- a/trunk/arch/powerpc/kernel/signal_64.c +++ b/trunk/arch/powerpc/kernel/signal_64.c @@ -335,7 +335,7 @@ int sys_swapcontext(struct ucontext __user *old_ctx, if (__copy_from_user(&set, &new_ctx->uc_sigmask, sizeof(set))) do_exit(SIGSEGV); - set_current_blocked(&set); + restore_sigmask(&set); if (restore_sigcontext(regs, NULL, 0, &new_ctx->uc_mcontext)) do_exit(SIGSEGV); @@ -364,7 +364,7 @@ int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5, if (__copy_from_user(&set, &uc->uc_sigmask, sizeof(set))) goto badframe; - set_current_blocked(&set); + restore_sigmask(&set); if (restore_sigcontext(regs, NULL, 1, &uc->uc_mcontext)) goto badframe; diff --git a/trunk/arch/s390/Kconfig b/trunk/arch/s390/Kconfig index a39b4690c171..b403c533432c 100644 --- a/trunk/arch/s390/Kconfig +++ b/trunk/arch/s390/Kconfig @@ -87,7 +87,6 @@ config S390 select ARCH_SAVE_PAGE_KEYS if HIBERNATION select HAVE_MEMBLOCK select HAVE_MEMBLOCK_NODE_MAP - select HAVE_CMPXCHG_LOCAL select ARCH_DISCARD_MEMBLOCK select ARCH_INLINE_SPIN_TRYLOCK select ARCH_INLINE_SPIN_TRYLOCK_BH diff --git a/trunk/arch/s390/include/asm/bitops.h b/trunk/arch/s390/include/asm/bitops.h index a6ff5a83e227..e5beb490959b 100644 --- a/trunk/arch/s390/include/asm/bitops.h +++ b/trunk/arch/s390/include/asm/bitops.h @@ -13,6 +13,8 @@ * */ +#ifdef __KERNEL__ + #ifndef _LINUX_BITOPS_H #error only can be included directly #endif @@ -61,7 +63,7 @@ extern const char _ni_bitmap[]; extern const char _zb_findmap[]; extern const char _sb_findmap[]; -#ifndef CONFIG_64BIT +#ifndef __s390x__ #define __BITOPS_ALIGN 3 #define __BITOPS_WORDSIZE 32 @@ -81,7 +83,7 @@ extern const char _sb_findmap[]; : "d" (__val), "Q" (*(unsigned long *) __addr) \ : "cc"); -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ #define __BITOPS_ALIGN 7 #define __BITOPS_WORDSIZE 64 @@ -101,7 +103,7 @@ extern const char _sb_findmap[]; : "d" (__val), "Q" (*(unsigned long *) __addr) \ : "cc"); -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ #define __BITOPS_WORDS(bits) (((bits)+__BITOPS_WORDSIZE-1)/__BITOPS_WORDSIZE) #define __BITOPS_BARRIER() asm volatile("" : : : "memory") @@ -410,7 +412,7 @@ static inline unsigned long __ffz_word_loop(const unsigned long *addr, unsigned long bytes = 0; asm volatile( -#ifndef CONFIG_64BIT +#ifndef __s390x__ " ahi %1,-1\n" " sra %1,5\n" " jz 1f\n" @@ -447,7 +449,7 @@ static inline unsigned long __ffs_word_loop(const unsigned long *addr, unsigned long bytes = 0; asm volatile( -#ifndef CONFIG_64BIT +#ifndef __s390x__ " ahi %1,-1\n" " sra %1,5\n" " jz 1f\n" @@ -479,7 +481,7 @@ static inline unsigned long __ffs_word_loop(const unsigned long *addr, */ static inline unsigned long __ffz_word(unsigned long nr, unsigned long word) { -#ifdef CONFIG_64BIT +#ifdef __s390x__ if ((word & 0xffffffff) == 0xffffffff) { word >>= 32; nr += 32; @@ -503,7 +505,7 @@ static inline unsigned long __ffz_word(unsigned long nr, unsigned long word) */ static inline unsigned long __ffs_word(unsigned long nr, unsigned long word) { -#ifdef CONFIG_64BIT +#ifdef __s390x__ if ((word & 0xffffffff) == 0) { word >>= 32; nr += 32; @@ -544,7 +546,7 @@ static inline unsigned long __load_ulong_le(const unsigned long *p, unsigned long word; p = (unsigned long *)((unsigned long) p + offset); -#ifndef CONFIG_64BIT +#ifndef __s390x__ asm volatile( " ic %0,%O1(%R1)\n" " icm %0,2,%O1+1(%R1)\n" @@ -832,4 +834,7 @@ static inline int find_next_bit_le(void *vaddr, unsigned long size, #include + +#endif /* __KERNEL__ */ + #endif /* _S390_BITOPS_H */ diff --git a/trunk/arch/s390/include/asm/cio.h b/trunk/arch/s390/include/asm/cio.h index 4c8d4d5b8bd2..fc50a3342da3 100644 --- a/trunk/arch/s390/include/asm/cio.h +++ b/trunk/arch/s390/include/asm/cio.h @@ -10,6 +10,8 @@ #include #include +#ifdef __KERNEL__ + #define LPM_ANYPATH 0xff #define __MAX_CSSID 0 @@ -289,3 +291,5 @@ int chsc_sstpc(void *page, unsigned int op, u16 ctrl); int chsc_sstpi(void *page, void *result, size_t size); #endif + +#endif diff --git a/trunk/arch/s390/include/asm/cmpxchg.h b/trunk/arch/s390/include/asm/cmpxchg.h index 8d798e962b63..81d7908416cf 100644 --- a/trunk/arch/s390/include/asm/cmpxchg.h +++ b/trunk/arch/s390/include/asm/cmpxchg.h @@ -29,7 +29,7 @@ static inline unsigned long __xchg(unsigned long x, void *ptr, int size) " cs %0,0,%4\n" " jl 0b\n" : "=&d" (old), "=Q" (*(int *) addr) - : "d" ((x & 0xff) << shift), "d" (~(0xff << shift)), + : "d" (x << shift), "d" (~(255 << shift)), "Q" (*(int *) addr) : "memory", "cc", "0"); return old >> shift; case 2: @@ -44,7 +44,7 @@ static inline unsigned long __xchg(unsigned long x, void *ptr, int size) " cs %0,0,%4\n" " jl 0b\n" : "=&d" (old), "=Q" (*(int *) addr) - : "d" ((x & 0xffff) << shift), "d" (~(0xffff << shift)), + : "d" (x << shift), "d" (~(65535 << shift)), "Q" (*(int *) addr) : "memory", "cc", "0"); return old >> shift; case 4: @@ -113,10 +113,9 @@ static inline unsigned long __cmpxchg(void *ptr, unsigned long old, " nr %1,%5\n" " jnz 0b\n" "1:" - : "=&d" (prev), "=&d" (tmp), "+Q" (*(int *) addr) - : "d" ((old & 0xff) << shift), - "d" ((new & 0xff) << shift), - "d" (~(0xff << shift)) + : "=&d" (prev), "=&d" (tmp), "=Q" (*(int *) ptr) + : "d" (old << shift), "d" (new << shift), + "d" (~(255 << shift)), "Q" (*(int *) ptr) : "memory", "cc"); return prev >> shift; case 2: @@ -135,10 +134,9 @@ static inline unsigned long __cmpxchg(void *ptr, unsigned long old, " nr %1,%5\n" " jnz 0b\n" "1:" - : "=&d" (prev), "=&d" (tmp), "+Q" (*(int *) addr) - : "d" ((old & 0xffff) << shift), - "d" ((new & 0xffff) << shift), - "d" (~(0xffff << shift)) + : "=&d" (prev), "=&d" (tmp), "=Q" (*(int *) ptr) + : "d" (old << shift), "d" (new << shift), + "d" (~(65535 << shift)), "Q" (*(int *) ptr) : "memory", "cc"); return prev >> shift; case 4: @@ -162,14 +160,9 @@ static inline unsigned long __cmpxchg(void *ptr, unsigned long old, return old; } -#define cmpxchg(ptr, o, n) \ -({ \ - __typeof__(*(ptr)) __ret; \ - __ret = (__typeof__(*(ptr))) \ - __cmpxchg((ptr), (unsigned long)(o), (unsigned long)(n), \ - sizeof(*(ptr))); \ - __ret; \ -}) +#define cmpxchg(ptr, o, n) \ + ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), \ + (unsigned long)(n), sizeof(*(ptr)))) #ifdef CONFIG_64BIT #define cmpxchg64(ptr, o, n) \ @@ -188,19 +181,13 @@ static inline unsigned long long __cmpxchg64(void *ptr, " cds %0,%2,%1" : "+&d" (rp_old), "=Q" (ptr) : "d" (rp_new), "Q" (ptr) - : "memory", "cc"); + : "cc"); return rp_old.pair; } - -#define cmpxchg64(ptr, o, n) \ -({ \ - __typeof__(*(ptr)) __ret; \ - __ret = (__typeof__(*(ptr))) \ - __cmpxchg64((ptr), \ - (unsigned long long)(o), \ - (unsigned long long)(n)); \ - __ret; \ -}) +#define cmpxchg64(ptr, o, n) \ + ((__typeof__(*(ptr)))__cmpxchg64((ptr), \ + (unsigned long long)(o), \ + (unsigned long long)(n))) #endif /* CONFIG_64BIT */ #include @@ -229,13 +216,8 @@ static inline unsigned long __cmpxchg_local(void *ptr, * them available. */ #define cmpxchg_local(ptr, o, n) \ -({ \ - __typeof__(*(ptr)) __ret; \ - __ret = (__typeof__(*(ptr))) \ - __cmpxchg_local((ptr), (unsigned long)(o), \ - (unsigned long)(n), sizeof(*(ptr))); \ - __ret; \ -}) + ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \ + (unsigned long)(n), sizeof(*(ptr)))) #define cmpxchg64_local(ptr, o, n) cmpxchg64((ptr), (o), (n)) diff --git a/trunk/arch/s390/include/asm/cputime.h b/trunk/arch/s390/include/asm/cputime.h index 718374de9c7f..24ef186a1c4f 100644 --- a/trunk/arch/s390/include/asm/cputime.h +++ b/trunk/arch/s390/include/asm/cputime.h @@ -21,15 +21,15 @@ typedef unsigned long long __nocast cputime64_t; static inline unsigned long __div(unsigned long long n, unsigned long base) { -#ifndef CONFIG_64BIT +#ifndef __s390x__ register_pair rp; rp.pair = n >> 1; asm ("dr %0,%1" : "+d" (rp) : "d" (base >> 1)); return rp.subreg.odd; -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ return n / base; -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ } #define cputime_one_jiffy jiffies_to_cputime(1) @@ -100,7 +100,7 @@ static inline void cputime_to_timespec(const cputime_t cputime, struct timespec *value) { unsigned long long __cputime = (__force unsigned long long) cputime; -#ifndef CONFIG_64BIT +#ifndef __s390x__ register_pair rp; rp.pair = __cputime >> 1; @@ -128,7 +128,7 @@ static inline void cputime_to_timeval(const cputime_t cputime, struct timeval *value) { unsigned long long __cputime = (__force unsigned long long) cputime; -#ifndef CONFIG_64BIT +#ifndef __s390x__ register_pair rp; rp.pair = __cputime >> 1; diff --git a/trunk/arch/s390/include/asm/ctl_reg.h b/trunk/arch/s390/include/asm/ctl_reg.h index debfda33d1f8..ecde9417d669 100644 --- a/trunk/arch/s390/include/asm/ctl_reg.h +++ b/trunk/arch/s390/include/asm/ctl_reg.h @@ -7,7 +7,7 @@ #ifndef __ASM_CTL_REG_H #define __ASM_CTL_REG_H -#ifdef CONFIG_64BIT +#ifdef __s390x__ #define __ctl_load(array, low, high) ({ \ typedef struct { char _[sizeof(array)]; } addrtype; \ @@ -25,7 +25,7 @@ : "i" (low), "i" (high)); \ }) -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ #define __ctl_load(array, low, high) ({ \ typedef struct { char _[sizeof(array)]; } addrtype; \ @@ -43,7 +43,7 @@ : "i" (low), "i" (high)); \ }) -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ #define __ctl_set_bit(cr, bit) ({ \ unsigned long __dummy; \ diff --git a/trunk/arch/s390/include/asm/current.h b/trunk/arch/s390/include/asm/current.h index 7a68084ec2f0..83cf36cde2da 100644 --- a/trunk/arch/s390/include/asm/current.h +++ b/trunk/arch/s390/include/asm/current.h @@ -11,10 +11,13 @@ #ifndef _S390_CURRENT_H #define _S390_CURRENT_H +#ifdef __KERNEL__ #include struct task_struct; #define current ((struct task_struct *const)S390_lowcore.current_task) +#endif + #endif /* !(_S390_CURRENT_H) */ diff --git a/trunk/arch/s390/include/asm/elf.h b/trunk/arch/s390/include/asm/elf.h index 06151e6a3098..c4ee39f7a4d6 100644 --- a/trunk/arch/s390/include/asm/elf.h +++ b/trunk/arch/s390/include/asm/elf.h @@ -107,11 +107,11 @@ /* * These are used to set parameters in the core dumps. */ -#ifndef CONFIG_64BIT +#ifndef __s390x__ #define ELF_CLASS ELFCLASS32 -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ #define ELF_CLASS ELFCLASS64 -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ #define ELF_DATA ELFDATA2MSB #define ELF_ARCH EM_S390 @@ -181,9 +181,9 @@ extern unsigned long elf_hwcap; extern char elf_platform[]; #define ELF_PLATFORM (elf_platform) -#ifndef CONFIG_64BIT +#ifndef __s390x__ #define SET_PERSONALITY(ex) set_personality(PER_LINUX) -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ #define SET_PERSONALITY(ex) \ do { \ if (personality(current->personality) != PER_LINUX32) \ @@ -194,7 +194,7 @@ do { \ else \ clear_thread_flag(TIF_31BIT); \ } while (0) -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ #define STACK_RND_MASK 0x7ffUL diff --git a/trunk/arch/s390/include/asm/futex.h b/trunk/arch/s390/include/asm/futex.h index 96bc83ea5c90..81cf36b691f1 100644 --- a/trunk/arch/s390/include/asm/futex.h +++ b/trunk/arch/s390/include/asm/futex.h @@ -1,6 +1,8 @@ #ifndef _ASM_S390_FUTEX_H #define _ASM_S390_FUTEX_H +#ifdef __KERNEL__ + #include #include #include @@ -46,4 +48,5 @@ static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, return uaccess.futex_atomic_cmpxchg(uval, uaddr, oldval, newval); } +#endif /* __KERNEL__ */ #endif /* _ASM_S390_FUTEX_H */ diff --git a/trunk/arch/s390/include/asm/idals.h b/trunk/arch/s390/include/asm/idals.h index aef0dde340d1..aae276d00383 100644 --- a/trunk/arch/s390/include/asm/idals.h +++ b/trunk/arch/s390/include/asm/idals.h @@ -20,7 +20,7 @@ #include #include -#ifdef CONFIG_64BIT +#ifdef __s390x__ #define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */ #else #define IDA_SIZE_LOG 11 /* 11 for 2k , 12 for 4k */ @@ -33,7 +33,7 @@ static inline int idal_is_needed(void *vaddr, unsigned int length) { -#ifdef CONFIG_64BIT +#ifdef __s390x__ return ((__pa(vaddr) + length - 1) >> 31) != 0; #else return 0; @@ -78,7 +78,7 @@ static inline unsigned long *idal_create_words(unsigned long *idaws, static inline int set_normalized_cda(struct ccw1 * ccw, void *vaddr) { -#ifdef CONFIG_64BIT +#ifdef __s390x__ unsigned int nridaws; unsigned long *idal; @@ -105,7 +105,7 @@ set_normalized_cda(struct ccw1 * ccw, void *vaddr) static inline void clear_normalized_cda(struct ccw1 * ccw) { -#ifdef CONFIG_64BIT +#ifdef __s390x__ if (ccw->flags & CCW_FLAG_IDA) { kfree((void *)(unsigned long) ccw->cda); ccw->flags &= ~CCW_FLAG_IDA; @@ -182,7 +182,7 @@ idal_buffer_free(struct idal_buffer *ib) static inline int __idal_buffer_is_needed(struct idal_buffer *ib) { -#ifdef CONFIG_64BIT +#ifdef __s390x__ return ib->size > (4096ul << ib->page_order) || idal_is_needed(ib->data[0], ib->size); #else diff --git a/trunk/arch/s390/include/asm/io.h b/trunk/arch/s390/include/asm/io.h index f81a0975cbea..27216d317991 100644 --- a/trunk/arch/s390/include/asm/io.h +++ b/trunk/arch/s390/include/asm/io.h @@ -11,6 +11,8 @@ #ifndef _S390_IO_H #define _S390_IO_H +#ifdef __KERNEL__ + #include #define IO_SPACE_LIMIT 0xffffffff @@ -44,4 +46,6 @@ void unxlate_dev_mem_ptr(unsigned long phys, void *addr); */ #define xlate_dev_kmem_ptr(p) p +#endif /* __KERNEL__ */ + #endif diff --git a/trunk/arch/s390/include/asm/irq.h b/trunk/arch/s390/include/asm/irq.h index 2b9d41899d21..5289cacd4861 100644 --- a/trunk/arch/s390/include/asm/irq.h +++ b/trunk/arch/s390/include/asm/irq.h @@ -17,8 +17,7 @@ enum interruption_class { EXTINT_VRT, EXTINT_SCP, EXTINT_IUC, - EXTINT_CMS, - EXTINT_CMC, + EXTINT_CPM, IOINT_CIO, IOINT_QAI, IOINT_DAS, diff --git a/trunk/arch/s390/include/asm/kexec.h b/trunk/arch/s390/include/asm/kexec.h index f4f38826eebb..3f30dac804ea 100644 --- a/trunk/arch/s390/include/asm/kexec.h +++ b/trunk/arch/s390/include/asm/kexec.h @@ -10,8 +10,10 @@ #ifndef _S390_KEXEC_H #define _S390_KEXEC_H -#include +#ifdef __KERNEL__ #include +#endif +#include /* * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return. * I.e. Maximum page that is mapped directly into kernel memory, diff --git a/trunk/arch/s390/include/asm/kmap_types.h b/trunk/arch/s390/include/asm/kmap_types.h index 0a88622339ee..94ec3ee07983 100644 --- a/trunk/arch/s390/include/asm/kmap_types.h +++ b/trunk/arch/s390/include/asm/kmap_types.h @@ -1,6 +1,8 @@ +#ifdef __KERNEL__ #ifndef _ASM_KMAP_TYPES_H #define _ASM_KMAP_TYPES_H #include #endif +#endif /* __KERNEL__ */ diff --git a/trunk/arch/s390/include/asm/mmu_context.h b/trunk/arch/s390/include/asm/mmu_context.h index 69bdf72e95ec..5d09e405c54d 100644 --- a/trunk/arch/s390/include/asm/mmu_context.h +++ b/trunk/arch/s390/include/asm/mmu_context.h @@ -49,7 +49,7 @@ static inline int init_new_context(struct task_struct *tsk, #define destroy_context(mm) do { } while (0) -#ifndef CONFIG_64BIT +#ifndef __s390x__ #define LCTL_OPCODE "lctl" #else #define LCTL_OPCODE "lctlg" diff --git a/trunk/arch/s390/include/asm/module.h b/trunk/arch/s390/include/asm/module.h index f0b6b26b6e59..1cc1c5af705a 100644 --- a/trunk/arch/s390/include/asm/module.h +++ b/trunk/arch/s390/include/asm/module.h @@ -28,7 +28,7 @@ struct mod_arch_specific struct mod_arch_syminfo *syminfo; }; -#ifdef CONFIG_64BIT +#ifdef __s390x__ #define ElfW(x) Elf64_ ## x #define ELFW(x) ELF64_ ## x #else diff --git a/trunk/arch/s390/include/asm/os_info.h b/trunk/arch/s390/include/asm/os_info.h index 295f2c4f1c96..d07518af09ea 100644 --- a/trunk/arch/s390/include/asm/os_info.h +++ b/trunk/arch/s390/include/asm/os_info.h @@ -13,6 +13,7 @@ #define OS_INFO_VMCOREINFO 0 #define OS_INFO_REIPL_BLOCK 1 +#define OS_INFO_INIT_FN 2 struct os_info_entry { u64 addr; @@ -27,8 +28,8 @@ struct os_info { u16 version_minor; u64 crashkernel_addr; u64 crashkernel_size; - struct os_info_entry entry[2]; - u8 reserved[4024]; + struct os_info_entry entry[3]; + u8 reserved[4004]; } __packed; void os_info_init(void); diff --git a/trunk/arch/s390/include/asm/percpu.h b/trunk/arch/s390/include/asm/percpu.h index 6537e72e0853..0fbd1899c7b0 100644 --- a/trunk/arch/s390/include/asm/percpu.h +++ b/trunk/arch/s390/include/asm/percpu.h @@ -15,7 +15,7 @@ * per cpu area, use weak definitions to force the compiler to * generate external references. */ -#if defined(CONFIG_SMP) && defined(CONFIG_64BIT) && defined(MODULE) +#if defined(CONFIG_SMP) && defined(__s390x__) && defined(MODULE) #define ARCH_NEEDS_WEAK_PER_CPU #endif diff --git a/trunk/arch/s390/include/asm/pgalloc.h b/trunk/arch/s390/include/asm/pgalloc.h index 43078c194394..78e3041919de 100644 --- a/trunk/arch/s390/include/asm/pgalloc.h +++ b/trunk/arch/s390/include/asm/pgalloc.h @@ -48,7 +48,7 @@ static inline void crst_table_init(unsigned long *crst, unsigned long entry) clear_table(crst, entry, sizeof(unsigned long)*2048); } -#ifndef CONFIG_64BIT +#ifndef __s390x__ static inline unsigned long pgd_entry_type(struct mm_struct *mm) { @@ -64,7 +64,7 @@ static inline unsigned long pgd_entry_type(struct mm_struct *mm) #define pgd_populate(mm, pgd, pud) BUG() #define pud_populate(mm, pud, pmd) BUG() -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ static inline unsigned long pgd_entry_type(struct mm_struct *mm) { @@ -106,7 +106,7 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) pud_val(*pud) = _REGION3_ENTRY | __pa(pmd); } -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ static inline pgd_t *pgd_alloc(struct mm_struct *mm) { diff --git a/trunk/arch/s390/include/asm/pgtable.h b/trunk/arch/s390/include/asm/pgtable.h index b3227415abda..011358c1b18e 100644 --- a/trunk/arch/s390/include/asm/pgtable.h +++ b/trunk/arch/s390/include/asm/pgtable.h @@ -74,15 +74,15 @@ static inline int is_zero_pfn(unsigned long pfn) * table can map * PGDIR_SHIFT determines what a third-level page table entry can map */ -#ifndef CONFIG_64BIT +#ifndef __s390x__ # define PMD_SHIFT 20 # define PUD_SHIFT 20 # define PGDIR_SHIFT 20 -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ # define PMD_SHIFT 20 # define PUD_SHIFT 31 # define PGDIR_SHIFT 42 -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ #define PMD_SIZE (1UL << PMD_SHIFT) #define PMD_MASK (~(PMD_SIZE-1)) @@ -98,13 +98,13 @@ static inline int is_zero_pfn(unsigned long pfn) * that leads to 1024 pte per pgd */ #define PTRS_PER_PTE 256 -#ifndef CONFIG_64BIT +#ifndef __s390x__ #define PTRS_PER_PMD 1 #define PTRS_PER_PUD 1 -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ #define PTRS_PER_PMD 2048 #define PTRS_PER_PUD 2048 -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ #define PTRS_PER_PGD 2048 #define FIRST_USER_ADDRESS 0 @@ -276,7 +276,7 @@ extern struct page *vmemmap; * swap pte is 1011 and 0001, 0011, 0101, 0111 are invalid. */ -#ifndef CONFIG_64BIT +#ifndef __s390x__ /* Bits in the segment table address-space-control-element */ #define _ASCE_SPACE_SWITCH 0x80000000UL /* space switch event */ @@ -308,7 +308,7 @@ extern struct page *vmemmap; #define KVM_UR_BIT 0x00008000UL #define KVM_UC_BIT 0x00004000UL -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ /* Bits in the segment/region table address-space-control-element */ #define _ASCE_ORIGIN ~0xfffUL/* segment table origin */ @@ -363,7 +363,7 @@ extern struct page *vmemmap; #define KVM_UR_BIT 0x0000800000000000UL #define KVM_UC_BIT 0x0000400000000000UL -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ /* * A user page table pointer has the space-switch-event bit, the @@ -424,7 +424,7 @@ static inline int mm_has_pgste(struct mm_struct *mm) /* * pgd/pmd/pte query functions */ -#ifndef CONFIG_64BIT +#ifndef __s390x__ static inline int pgd_present(pgd_t pgd) { return 1; } static inline int pgd_none(pgd_t pgd) { return 0; } @@ -434,7 +434,7 @@ static inline int pud_present(pud_t pud) { return 1; } static inline int pud_none(pud_t pud) { return 0; } static inline int pud_bad(pud_t pud) { return 0; } -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ static inline int pgd_present(pgd_t pgd) { @@ -490,7 +490,7 @@ static inline int pud_bad(pud_t pud) return (pud_val(pud) & mask) != 0; } -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ static inline int pmd_present(pmd_t pmd) { @@ -741,7 +741,7 @@ static inline int pte_young(pte_t pte) static inline void pgd_clear(pgd_t *pgd) { -#ifdef CONFIG_64BIT +#ifdef __s390x__ if ((pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R2) pgd_val(*pgd) = _REGION2_ENTRY_EMPTY; #endif @@ -749,7 +749,7 @@ static inline void pgd_clear(pgd_t *pgd) static inline void pud_clear(pud_t *pud) { -#ifdef CONFIG_64BIT +#ifdef __s390x__ if ((pud_val(*pud) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) pud_val(*pud) = _REGION3_ENTRY_EMPTY; #endif @@ -921,7 +921,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma, static inline void __ptep_ipte(unsigned long address, pte_t *ptep) { if (!(pte_val(*ptep) & _PAGE_INVALID)) { -#ifndef CONFIG_64BIT +#ifndef __s390x__ /* pto must point to the start of the segment table */ pte_t *pto = (pte_t *) (((unsigned long) ptep) & 0x7ffffc00); #else @@ -1116,7 +1116,7 @@ static inline pte_t mk_pte(struct page *page, pgprot_t pgprot) #define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address)) #define pgd_offset_k(address) pgd_offset(&init_mm, address) -#ifndef CONFIG_64BIT +#ifndef __s390x__ #define pmd_deref(pmd) (pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN) #define pud_deref(pmd) ({ BUG(); 0UL; }) @@ -1125,7 +1125,7 @@ static inline pte_t mk_pte(struct page *page, pgprot_t pgprot) #define pud_offset(pgd, address) ((pud_t *) pgd) #define pmd_offset(pud, address) ((pmd_t *) pud + pmd_index(address)) -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ #define pmd_deref(pmd) (pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN) #define pud_deref(pud) (pud_val(pud) & _REGION_ENTRY_ORIGIN) @@ -1147,7 +1147,7 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address) return pmd + pmd_index(address); } -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ #define pfn_pte(pfn,pgprot) mk_pte_phys(__pa((pfn) << PAGE_SHIFT),(pgprot)) #define pte_pfn(x) (pte_val(x) >> PAGE_SHIFT) @@ -1196,7 +1196,7 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address) * 0000000000111111111122222222223333333333444444444455 5555 5 55566 66 * 0123456789012345678901234567890123456789012345678901 2345 6 78901 23 */ -#ifndef CONFIG_64BIT +#ifndef __s390x__ #define __SWP_OFFSET_MASK (~0UL >> 12) #else #define __SWP_OFFSET_MASK (~0UL >> 11) @@ -1217,11 +1217,11 @@ static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -#ifndef CONFIG_64BIT +#ifndef __s390x__ # define PTE_FILE_MAX_BITS 26 -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ # define PTE_FILE_MAX_BITS 59 -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ #define pte_to_pgoff(__pte) \ ((((__pte).pte >> 12) << 7) + (((__pte).pte >> 1) & 0x7f)) diff --git a/trunk/arch/s390/include/asm/posix_types.h b/trunk/arch/s390/include/asm/posix_types.h index 7be104c0f192..edf8527ff08d 100644 --- a/trunk/arch/s390/include/asm/posix_types.h +++ b/trunk/arch/s390/include/asm/posix_types.h @@ -24,6 +24,7 @@ typedef unsigned short __kernel_old_dev_t; typedef unsigned long __kernel_ino_t; typedef unsigned short __kernel_mode_t; +typedef unsigned short __kernel_nlink_t; typedef unsigned short __kernel_ipc_pid_t; typedef unsigned short __kernel_uid_t; typedef unsigned short __kernel_gid_t; @@ -34,6 +35,7 @@ typedef int __kernel_ptrdiff_t; typedef unsigned int __kernel_ino_t; typedef unsigned int __kernel_mode_t; +typedef unsigned int __kernel_nlink_t; typedef int __kernel_ipc_pid_t; typedef unsigned int __kernel_uid_t; typedef unsigned int __kernel_gid_t; @@ -45,6 +47,7 @@ typedef unsigned long __kernel_sigset_t; /* at least 32 bits */ #define __kernel_ino_t __kernel_ino_t #define __kernel_mode_t __kernel_mode_t +#define __kernel_nlink_t __kernel_nlink_t #define __kernel_ipc_pid_t __kernel_ipc_pid_t #define __kernel_uid_t __kernel_uid_t #define __kernel_gid_t __kernel_gid_t diff --git a/trunk/arch/s390/include/asm/processor.h b/trunk/arch/s390/include/asm/processor.h index 20d0585cf905..6cbf31311673 100644 --- a/trunk/arch/s390/include/asm/processor.h +++ b/trunk/arch/s390/include/asm/processor.h @@ -20,6 +20,7 @@ #include #include +#ifdef __KERNEL__ /* * Default implementation of macro that returns current * instruction pointer ("program counter"). @@ -32,33 +33,39 @@ static inline void get_cpu_id(struct cpuid *ptr) } extern void s390_adjust_jiffies(void); +extern int get_cpu_capability(unsigned int *); extern const struct seq_operations cpuinfo_op; extern int sysctl_ieee_emulation_warnings; /* * User space process size: 2GB for 31 bit, 4TB or 8PT for 64 bit. */ -#ifndef CONFIG_64BIT +#ifndef __s390x__ #define TASK_SIZE (1UL << 31) #define TASK_UNMAPPED_BASE (1UL << 30) -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ #define TASK_SIZE_OF(tsk) ((tsk)->mm->context.asce_limit) #define TASK_UNMAPPED_BASE (test_thread_flag(TIF_31BIT) ? \ (1UL << 30) : (1UL << 41)) #define TASK_SIZE TASK_SIZE_OF(current) -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ -#ifndef CONFIG_64BIT +#ifdef __KERNEL__ + +#ifndef __s390x__ #define STACK_TOP (1UL << 31) #define STACK_TOP_MAX (1UL << 31) -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ #define STACK_TOP (1UL << (test_thread_flag(TIF_31BIT) ? 31:42)) #define STACK_TOP_MAX (1UL << 42) -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ + + +#endif #define HAVE_ARCH_PICK_MMAP_LAYOUT @@ -175,7 +182,7 @@ static inline void psw_set_key(unsigned int key) */ static inline void __load_psw(psw_t psw) { -#ifndef CONFIG_64BIT +#ifndef __s390x__ asm volatile("lpsw %0" : : "Q" (psw) : "cc"); #else asm volatile("lpswe %0" : : "Q" (psw) : "cc"); @@ -193,7 +200,7 @@ static inline void __load_psw_mask (unsigned long mask) psw.mask = mask; -#ifndef CONFIG_64BIT +#ifndef __s390x__ asm volatile( " basr %0,0\n" "0: ahi %0,1f-0b\n" @@ -201,14 +208,14 @@ static inline void __load_psw_mask (unsigned long mask) " lpsw %1\n" "1:" : "=&d" (addr), "=Q" (psw) : "Q" (psw) : "memory", "cc"); -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ asm volatile( " larl %0,1f\n" " stg %0,%O1+8(%R1)\n" " lpswe %1\n" "1:" : "=&d" (addr), "=Q" (psw) : "Q" (psw) : "memory", "cc"); -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ } /* @@ -216,7 +223,7 @@ static inline void __load_psw_mask (unsigned long mask) */ static inline unsigned long __rewind_psw(psw_t psw, unsigned long ilc) { -#ifndef CONFIG_64BIT +#ifndef __s390x__ if (psw.addr & PSW_ADDR_AMODE) /* 31 bit mode */ return (psw.addr - ilc) | PSW_ADDR_AMODE; @@ -246,7 +253,7 @@ static inline void __noreturn disabled_wait(unsigned long code) * Store status and then load disabled wait psw, * the processor is dead afterwards */ -#ifndef CONFIG_64BIT +#ifndef __s390x__ asm volatile( " stctl 0,0,0(%2)\n" " ni 0(%2),0xef\n" /* switch off protection */ @@ -265,7 +272,7 @@ static inline void __noreturn disabled_wait(unsigned long code) " lpsw 0(%1)" : "=m" (ctl_buf) : "a" (&dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc"); -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ asm volatile( " stctg 0,0,0(%2)\n" " ni 4(%2),0xef\n" /* switch off protection */ @@ -298,7 +305,7 @@ static inline void __noreturn disabled_wait(unsigned long code) " lpswe 0(%1)" : "=m" (ctl_buf) : "a" (&dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc", "0", "1"); -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ while (1); } @@ -331,10 +338,12 @@ extern void (*s390_base_ext_handler_fn)(void); #define ARCH_LOW_ADDRESS_LIMIT 0x7fffffffUL +#endif + /* * Helper macro for exception table entries */ -#ifndef CONFIG_64BIT +#ifndef __s390x__ #define EX_TABLE(_fault,_target) \ ".section __ex_table,\"a\"\n" \ " .align 4\n" \ diff --git a/trunk/arch/s390/include/asm/rwsem.h b/trunk/arch/s390/include/asm/rwsem.h index 1ceee10264c3..d0eb4653cebd 100644 --- a/trunk/arch/s390/include/asm/rwsem.h +++ b/trunk/arch/s390/include/asm/rwsem.h @@ -41,17 +41,19 @@ #error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead" #endif -#ifndef CONFIG_64BIT +#ifdef __KERNEL__ + +#ifndef __s390x__ #define RWSEM_UNLOCKED_VALUE 0x00000000 #define RWSEM_ACTIVE_BIAS 0x00000001 #define RWSEM_ACTIVE_MASK 0x0000ffff #define RWSEM_WAITING_BIAS (-0x00010000) -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ #define RWSEM_UNLOCKED_VALUE 0x0000000000000000L #define RWSEM_ACTIVE_BIAS 0x0000000000000001L #define RWSEM_ACTIVE_MASK 0x00000000ffffffffL #define RWSEM_WAITING_BIAS (-0x0000000100000000L) -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ #define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) @@ -63,19 +65,19 @@ static inline void __down_read(struct rw_semaphore *sem) signed long old, new; asm volatile( -#ifndef CONFIG_64BIT +#ifndef __s390x__ " l %0,%2\n" "0: lr %1,%0\n" " ahi %1,%4\n" " cs %0,%1,%2\n" " jl 0b" -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ " lg %0,%2\n" "0: lgr %1,%0\n" " aghi %1,%4\n" " csg %0,%1,%2\n" " jl 0b" -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ : "=&d" (old), "=&d" (new), "=Q" (sem->count) : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS) : "cc", "memory"); @@ -91,7 +93,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem) signed long old, new; asm volatile( -#ifndef CONFIG_64BIT +#ifndef __s390x__ " l %0,%2\n" "0: ltr %1,%0\n" " jm 1f\n" @@ -99,7 +101,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem) " cs %0,%1,%2\n" " jl 0b\n" "1:" -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ " lg %0,%2\n" "0: ltgr %1,%0\n" " jm 1f\n" @@ -107,7 +109,7 @@ static inline int __down_read_trylock(struct rw_semaphore *sem) " csg %0,%1,%2\n" " jl 0b\n" "1:" -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ : "=&d" (old), "=&d" (new), "=Q" (sem->count) : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS) : "cc", "memory"); @@ -123,19 +125,19 @@ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) tmp = RWSEM_ACTIVE_WRITE_BIAS; asm volatile( -#ifndef CONFIG_64BIT +#ifndef __s390x__ " l %0,%2\n" "0: lr %1,%0\n" " a %1,%4\n" " cs %0,%1,%2\n" " jl 0b" -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ " lg %0,%2\n" "0: lgr %1,%0\n" " ag %1,%4\n" " csg %0,%1,%2\n" " jl 0b" -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ : "=&d" (old), "=&d" (new), "=Q" (sem->count) : "Q" (sem->count), "m" (tmp) : "cc", "memory"); @@ -156,19 +158,19 @@ static inline int __down_write_trylock(struct rw_semaphore *sem) signed long old; asm volatile( -#ifndef CONFIG_64BIT +#ifndef __s390x__ " l %0,%1\n" "0: ltr %0,%0\n" " jnz 1f\n" " cs %0,%3,%1\n" " jl 0b\n" -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ " lg %0,%1\n" "0: ltgr %0,%0\n" " jnz 1f\n" " csg %0,%3,%1\n" " jl 0b\n" -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ "1:" : "=&d" (old), "=Q" (sem->count) : "Q" (sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS) @@ -184,19 +186,19 @@ static inline void __up_read(struct rw_semaphore *sem) signed long old, new; asm volatile( -#ifndef CONFIG_64BIT +#ifndef __s390x__ " l %0,%2\n" "0: lr %1,%0\n" " ahi %1,%4\n" " cs %0,%1,%2\n" " jl 0b" -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ " lg %0,%2\n" "0: lgr %1,%0\n" " aghi %1,%4\n" " csg %0,%1,%2\n" " jl 0b" -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ : "=&d" (old), "=&d" (new), "=Q" (sem->count) : "Q" (sem->count), "i" (-RWSEM_ACTIVE_READ_BIAS) : "cc", "memory"); @@ -214,19 +216,19 @@ static inline void __up_write(struct rw_semaphore *sem) tmp = -RWSEM_ACTIVE_WRITE_BIAS; asm volatile( -#ifndef CONFIG_64BIT +#ifndef __s390x__ " l %0,%2\n" "0: lr %1,%0\n" " a %1,%4\n" " cs %0,%1,%2\n" " jl 0b" -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ " lg %0,%2\n" "0: lgr %1,%0\n" " ag %1,%4\n" " csg %0,%1,%2\n" " jl 0b" -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ : "=&d" (old), "=&d" (new), "=Q" (sem->count) : "Q" (sem->count), "m" (tmp) : "cc", "memory"); @@ -244,19 +246,19 @@ static inline void __downgrade_write(struct rw_semaphore *sem) tmp = -RWSEM_WAITING_BIAS; asm volatile( -#ifndef CONFIG_64BIT +#ifndef __s390x__ " l %0,%2\n" "0: lr %1,%0\n" " a %1,%4\n" " cs %0,%1,%2\n" " jl 0b" -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ " lg %0,%2\n" "0: lgr %1,%0\n" " ag %1,%4\n" " csg %0,%1,%2\n" " jl 0b" -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ : "=&d" (old), "=&d" (new), "=Q" (sem->count) : "Q" (sem->count), "m" (tmp) : "cc", "memory"); @@ -272,19 +274,19 @@ static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem) signed long old, new; asm volatile( -#ifndef CONFIG_64BIT +#ifndef __s390x__ " l %0,%2\n" "0: lr %1,%0\n" " ar %1,%4\n" " cs %0,%1,%2\n" " jl 0b" -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ " lg %0,%2\n" "0: lgr %1,%0\n" " agr %1,%4\n" " csg %0,%1,%2\n" " jl 0b" -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ : "=&d" (old), "=&d" (new), "=Q" (sem->count) : "Q" (sem->count), "d" (delta) : "cc", "memory"); @@ -298,23 +300,24 @@ static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem) signed long old, new; asm volatile( -#ifndef CONFIG_64BIT +#ifndef __s390x__ " l %0,%2\n" "0: lr %1,%0\n" " ar %1,%4\n" " cs %0,%1,%2\n" " jl 0b" -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ " lg %0,%2\n" "0: lgr %1,%0\n" " agr %1,%4\n" " csg %0,%1,%2\n" " jl 0b" -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ : "=&d" (old), "=&d" (new), "=Q" (sem->count) : "Q" (sem->count), "d" (delta) : "cc", "memory"); return new; } +#endif /* __KERNEL__ */ #endif /* _S390_RWSEM_H */ diff --git a/trunk/arch/s390/include/asm/setup.h b/trunk/arch/s390/include/asm/setup.h index 40eb2ff88e9e..7244e1f64126 100644 --- a/trunk/arch/s390/include/asm/setup.h +++ b/trunk/arch/s390/include/asm/setup.h @@ -22,19 +22,19 @@ #include #include -#ifndef CONFIG_64BIT +#ifndef __s390x__ #define IPL_DEVICE (*(unsigned long *) (0x10404)) #define INITRD_START (*(unsigned long *) (0x1040C)) #define INITRD_SIZE (*(unsigned long *) (0x10414)) #define OLDMEM_BASE (*(unsigned long *) (0x1041C)) #define OLDMEM_SIZE (*(unsigned long *) (0x10424)) -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ #define IPL_DEVICE (*(unsigned long *) (0x10400)) #define INITRD_START (*(unsigned long *) (0x10408)) #define INITRD_SIZE (*(unsigned long *) (0x10410)) #define OLDMEM_BASE (*(unsigned long *) (0x10418)) #define OLDMEM_SIZE (*(unsigned long *) (0x10420)) -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ #define COMMAND_LINE ((char *) (0x10480)) #define CHUNK_READ_WRITE 0 @@ -89,7 +89,7 @@ extern unsigned int user_mode; #define MACHINE_HAS_DIAG9C (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG9C) -#ifndef CONFIG_64BIT +#ifndef __s390x__ #define MACHINE_HAS_IEEE (S390_lowcore.machine_flags & MACHINE_FLAG_IEEE) #define MACHINE_HAS_CSP (S390_lowcore.machine_flags & MACHINE_FLAG_CSP) #define MACHINE_HAS_IDTE (0) @@ -100,7 +100,7 @@ extern unsigned int user_mode; #define MACHINE_HAS_PFMF (0) #define MACHINE_HAS_SPP (0) #define MACHINE_HAS_TOPOLOGY (0) -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ #define MACHINE_HAS_IEEE (1) #define MACHINE_HAS_CSP (1) #define MACHINE_HAS_IDTE (S390_lowcore.machine_flags & MACHINE_FLAG_IDTE) @@ -111,7 +111,7 @@ extern unsigned int user_mode; #define MACHINE_HAS_PFMF (S390_lowcore.machine_flags & MACHINE_FLAG_PFMF) #define MACHINE_HAS_SPP (S390_lowcore.machine_flags & MACHINE_FLAG_SPP) #define MACHINE_HAS_TOPOLOGY (S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY) -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ #define ZFCPDUMP_HSA_SIZE (32UL<<20) #define ZFCPDUMP_HSA_SIZE_MAX (64UL<<20) @@ -153,19 +153,19 @@ extern void (*_machine_power_off)(void); #else /* __ASSEMBLY__ */ -#ifndef CONFIG_64BIT +#ifndef __s390x__ #define IPL_DEVICE 0x10404 #define INITRD_START 0x1040C #define INITRD_SIZE 0x10414 #define OLDMEM_BASE 0x1041C #define OLDMEM_SIZE 0x10424 -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ #define IPL_DEVICE 0x10400 #define INITRD_START 0x10408 #define INITRD_SIZE 0x10410 #define OLDMEM_BASE 0x10418 #define OLDMEM_SIZE 0x10420 -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ #define COMMAND_LINE 0x10480 #endif /* __ASSEMBLY__ */ diff --git a/trunk/arch/s390/include/asm/sfp-util.h b/trunk/arch/s390/include/asm/sfp-util.h index 5959bfb3b693..ca3f8814e361 100644 --- a/trunk/arch/s390/include/asm/sfp-util.h +++ b/trunk/arch/s390/include/asm/sfp-util.h @@ -51,7 +51,7 @@ wl = __wl; \ }) -#ifdef CONFIG_64BIT +#ifdef __s390x__ #define udiv_qrnnd(q, r, n1, n0, d) \ do { unsigned long __n; \ unsigned int __r, __d; \ diff --git a/trunk/arch/s390/include/asm/string.h b/trunk/arch/s390/include/asm/string.h index 8cc160c9e1cb..cd0241db5a46 100644 --- a/trunk/arch/s390/include/asm/string.h +++ b/trunk/arch/s390/include/asm/string.h @@ -9,6 +9,8 @@ #ifndef _S390_STRING_H_ #define _S390_STRING_H_ +#ifdef __KERNEL__ + #ifndef _LINUX_TYPES_H #include #endif @@ -150,4 +152,6 @@ size_t strlen(const char *s); size_t strnlen(const char * s, size_t n); #endif /* !IN_ARCH_STRING_C */ +#endif /* __KERNEL__ */ + #endif /* __S390_STRING_H_ */ diff --git a/trunk/arch/s390/include/asm/thread_info.h b/trunk/arch/s390/include/asm/thread_info.h index 4e40b25cd060..003b04edcff6 100644 --- a/trunk/arch/s390/include/asm/thread_info.h +++ b/trunk/arch/s390/include/asm/thread_info.h @@ -9,13 +9,15 @@ #ifndef _ASM_THREAD_INFO_H #define _ASM_THREAD_INFO_H +#ifdef __KERNEL__ + /* * Size of kernel stack for each process */ -#ifndef CONFIG_64BIT +#ifndef __s390x__ #define THREAD_ORDER 1 #define ASYNC_ORDER 1 -#else /* CONFIG_64BIT */ +#else /* __s390x__ */ #ifndef __SMALL_STACK #define THREAD_ORDER 2 #define ASYNC_ORDER 2 @@ -23,7 +25,7 @@ #define THREAD_ORDER 1 #define ASYNC_ORDER 1 #endif -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ #define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER) #define ASYNC_SIZE (PAGE_SIZE << ASYNC_ORDER) @@ -121,6 +123,8 @@ static inline struct thread_info *current_thread_info(void) #define is_32bit_task() (1) #endif +#endif /* __KERNEL__ */ + #define PREEMPT_ACTIVE 0x4000000 #endif /* _ASM_THREAD_INFO_H */ diff --git a/trunk/arch/s390/include/asm/timer.h b/trunk/arch/s390/include/asm/timer.h index 15d647901e5c..e63069ba39e3 100644 --- a/trunk/arch/s390/include/asm/timer.h +++ b/trunk/arch/s390/include/asm/timer.h @@ -10,6 +10,8 @@ #ifndef _ASM_S390_TIMER_H #define _ASM_S390_TIMER_H +#ifdef __KERNEL__ + #include #define VTIMER_MAX_SLICE (0x7ffffffffffff000LL) @@ -48,4 +50,6 @@ extern void vtime_init(void); extern void vtime_stop_cpu(void); extern void vtime_start_leave(void); +#endif /* __KERNEL__ */ + #endif /* _ASM_S390_TIMER_H */ diff --git a/trunk/arch/s390/include/asm/tlb.h b/trunk/arch/s390/include/asm/tlb.h index 06e5acbc84bd..775a5eea8f9e 100644 --- a/trunk/arch/s390/include/asm/tlb.h +++ b/trunk/arch/s390/include/asm/tlb.h @@ -106,7 +106,7 @@ static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte, static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd, unsigned long address) { -#ifdef CONFIG_64BIT +#ifdef __s390x__ if (tlb->mm->context.asce_limit <= (1UL << 31)) return; if (!tlb->fullmm) @@ -125,7 +125,7 @@ static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd, static inline void pud_free_tlb(struct mmu_gather *tlb, pud_t *pud, unsigned long address) { -#ifdef CONFIG_64BIT +#ifdef __s390x__ if (tlb->mm->context.asce_limit <= (1UL << 42)) return; if (!tlb->fullmm) diff --git a/trunk/arch/s390/include/asm/tlbflush.h b/trunk/arch/s390/include/asm/tlbflush.h index 9fde315f3a7c..1d8648cf2fea 100644 --- a/trunk/arch/s390/include/asm/tlbflush.h +++ b/trunk/arch/s390/include/asm/tlbflush.h @@ -27,12 +27,12 @@ static inline void __tlb_flush_global(void) register unsigned long reg4 asm("4"); long dummy; -#ifndef CONFIG_64BIT +#ifndef __s390x__ if (!MACHINE_HAS_CSP) { smp_ptlb_all(); return; } -#endif /* CONFIG_64BIT */ +#endif /* __s390x__ */ dummy = 0; reg2 = reg3 = 0; diff --git a/trunk/arch/s390/include/asm/types.h b/trunk/arch/s390/include/asm/types.h index 6c8c35f8df14..05ebbcdbbf6b 100644 --- a/trunk/arch/s390/include/asm/types.h +++ b/trunk/arch/s390/include/asm/types.h @@ -28,7 +28,7 @@ typedef __signed__ long saddr_t; #ifndef __ASSEMBLY__ -#ifndef CONFIG_64BIT +#ifndef __s390x__ typedef union { unsigned long long pair; struct { @@ -37,7 +37,7 @@ typedef union { } subreg; } register_pair; -#endif /* ! CONFIG_64BIT */ +#endif /* ! __s390x__ */ #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* _S390_TYPES_H */ diff --git a/trunk/arch/s390/include/asm/uaccess.h b/trunk/arch/s390/include/asm/uaccess.h index 1f3a79bcd262..8f2cada4f7c9 100644 --- a/trunk/arch/s390/include/asm/uaccess.h +++ b/trunk/arch/s390/include/asm/uaccess.h @@ -50,15 +50,10 @@ #define segment_eq(a,b) ((a).ar4 == (b).ar4) -static inline int __range_ok(unsigned long addr, unsigned long size) -{ - return 1; -} - -#define __access_ok(addr, size) \ -({ \ - __chk_user_ptr(addr); \ - __range_ok((unsigned long)(addr), (size)); \ +#define __access_ok(addr, size) \ +({ \ + __chk_user_ptr(addr); \ + 1; \ }) #define access_ok(type, addr, size) __access_ok(addr, size) @@ -382,7 +377,7 @@ clear_user(void __user *to, unsigned long n) } extern int memcpy_real(void *, void *, size_t); -extern void memcpy_absolute(void *, void *, size_t); +extern void copy_to_absolute_zero(void *dest, void *src, size_t count); extern int copy_to_user_real(void __user *dest, void *src, size_t count); extern int copy_from_user_real(void *dest, void __user *src, size_t count); diff --git a/trunk/arch/s390/include/asm/vdso.h b/trunk/arch/s390/include/asm/vdso.h index a73eb2e1e918..c4a11cfad3c8 100644 --- a/trunk/arch/s390/include/asm/vdso.h +++ b/trunk/arch/s390/include/asm/vdso.h @@ -1,6 +1,8 @@ #ifndef __S390_VDSO_H__ #define __S390_VDSO_H__ +#ifdef __KERNEL__ + /* Default link addresses for the vDSOs */ #define VDSO32_LBASE 0 #define VDSO64_LBASE 0 @@ -43,4 +45,7 @@ void vdso_free_per_cpu(struct _lowcore *lowcore); #endif #endif /* __ASSEMBLY__ */ + +#endif /* __KERNEL__ */ + #endif /* __S390_VDSO_H__ */ diff --git a/trunk/arch/s390/kernel/base.S b/trunk/arch/s390/kernel/base.S index c880ff72db44..3aa4d00aaf50 100644 --- a/trunk/arch/s390/kernel/base.S +++ b/trunk/arch/s390/kernel/base.S @@ -88,9 +88,6 @@ ENTRY(diag308_reset) stctg %c0,%c15,0(%r4) larl %r4,.Lfpctl # Floating point control register stfpc 0(%r4) - larl %r4,.Lcontinue_psw # Save PSW flags - epsw %r2,%r3 - stm %r2,%r3,0(%r4) larl %r4,.Lrestart_psw # Setup restart PSW at absolute 0 lghi %r3,0 lg %r4,0(%r4) # Save PSW @@ -106,20 +103,11 @@ ENTRY(diag308_reset) lctlg %c0,%c15,0(%r4) larl %r4,.Lfpctl # Restore floating point ctl register lfpc 0(%r4) - larl %r4,.Lcontinue_psw # Restore PSW flags - lpswe 0(%r4) -.Lcontinue: br %r14 .align 16 .Lrestart_psw: .long 0x00080000,0x80000000 + .Lrestart_part2 - .section .data..nosave,"aw",@progbits -.align 8 -.Lcontinue_psw: - .quad 0,.Lcontinue - .previous - .section .bss .align 8 .Lctlregs: diff --git a/trunk/arch/s390/kernel/compat_signal.c b/trunk/arch/s390/kernel/compat_signal.c index 3c0c19830c37..377c096ca4a7 100644 --- a/trunk/arch/s390/kernel/compat_signal.c +++ b/trunk/arch/s390/kernel/compat_signal.c @@ -32,6 +32,8 @@ #include "compat_ptrace.h" #include "entry.h" +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + typedef struct { __u8 callee_used_stack[__SIGNAL_FRAMESIZE32]; @@ -362,6 +364,7 @@ asmlinkage long sys32_sigreturn(void) goto badframe; if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE32)) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigregs32(regs, &frame->sregs)) goto badframe; @@ -387,6 +390,7 @@ asmlinkage long sys32_rt_sigreturn(void) goto badframe; if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigregs32(regs, &frame->uc.uc_mcontext)) goto badframe; @@ -568,7 +572,7 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info, * OK, we're invoking a handler */ -void handle_signal32(unsigned long sig, struct k_sigaction *ka, +int handle_signal32(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) { int ret; @@ -579,8 +583,8 @@ void handle_signal32(unsigned long sig, struct k_sigaction *ka, else ret = setup_frame32(sig, ka, oldset, regs); if (ret) - return; - signal_delivered(sig, info, ka, regs, - test_thread_flag(TIF_SINGLE_STEP)); + return ret; + block_sigmask(ka, sig); + return 0; } diff --git a/trunk/arch/s390/kernel/early.c b/trunk/arch/s390/kernel/early.c index 6684fff17558..d84181f1f5e8 100644 --- a/trunk/arch/s390/kernel/early.c +++ b/trunk/arch/s390/kernel/early.c @@ -237,7 +237,7 @@ static noinline __init void detect_machine_type(void) S390_lowcore.machine_flags |= MACHINE_FLAG_VM; } -static void early_pgm_check_handler(void) +static __init void early_pgm_check_handler(void) { unsigned long addr; const struct exception_table_entry *fixup; diff --git a/trunk/arch/s390/kernel/entry.h b/trunk/arch/s390/kernel/entry.h index f66a229ab0b3..6cdddac93a2e 100644 --- a/trunk/arch/s390/kernel/entry.h +++ b/trunk/arch/s390/kernel/entry.h @@ -31,7 +31,7 @@ void do_per_trap(struct pt_regs *regs); void syscall_trace(struct pt_regs *regs, int entryexit); void kernel_stack_overflow(struct pt_regs * regs); void do_signal(struct pt_regs *regs); -void handle_signal32(unsigned long sig, struct k_sigaction *ka, +int handle_signal32(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs); void do_notify_resume(struct pt_regs *regs); diff --git a/trunk/arch/s390/kernel/head_kdump.S b/trunk/arch/s390/kernel/head_kdump.S index 796c976b5fdc..e1ac3893e972 100644 --- a/trunk/arch/s390/kernel/head_kdump.S +++ b/trunk/arch/s390/kernel/head_kdump.S @@ -85,6 +85,11 @@ startup_kdump_relocated: basr %r13,0 0: mvc 0(8,%r0),.Lrestart_psw-0b(%r13) # Setup restart PSW + mvc 464(16,%r0),.Lpgm_psw-0b(%r13) # Setup pgm check PSW + lhi %r1,1 # Start new kernel + diag %r1,%r1,0x308 # with diag 308 + +.Lno_diag308: # No diag 308 sam31 # Switch to 31 bit addr mode sr %r1,%r1 # Erase register r1 sr %r2,%r2 # Erase register r2 @@ -93,6 +98,8 @@ startup_kdump_relocated: .align 8 .Lrestart_psw: .long 0x00080000,0x80000000 + startup +.Lpgm_psw: + .quad 0x0000000180000000,0x0000000000000000 + .Lno_diag308 #else .align 2 .Lep_startup_kdump: diff --git a/trunk/arch/s390/kernel/ipl.c b/trunk/arch/s390/kernel/ipl.c index 2f6cfd460cb6..8342e65a140d 100644 --- a/trunk/arch/s390/kernel/ipl.c +++ b/trunk/arch/s390/kernel/ipl.c @@ -1528,15 +1528,12 @@ static struct shutdown_action __refdata dump_action = { static void dump_reipl_run(struct shutdown_trigger *trigger) { - struct { - void *addr; - __u32 csum; - } __packed ipib; - - ipib.csum = csum_partial(reipl_block_actual, - reipl_block_actual->hdr.len, 0); - ipib.addr = reipl_block_actual; - memcpy_absolute(&S390_lowcore.ipib, &ipib, sizeof(ipib)); + u32 csum; + + csum = csum_partial(reipl_block_actual, reipl_block_actual->hdr.len, 0); + copy_to_absolute_zero(&S390_lowcore.ipib_checksum, &csum, sizeof(csum)); + copy_to_absolute_zero(&S390_lowcore.ipib, &reipl_block_actual, + sizeof(reipl_block_actual)); dump_run(trigger); } @@ -1753,7 +1750,6 @@ static struct kobj_attribute on_restart_attr = static void __do_restart(void *ignore) { - __arch_local_irq_stosm(0x04); /* enable DAT */ smp_send_stop(); #ifdef CONFIG_CRASH_DUMP crash_kexec(NULL); diff --git a/trunk/arch/s390/kernel/irq.c b/trunk/arch/s390/kernel/irq.c index b4f4a7133fa1..8a22c27219dd 100644 --- a/trunk/arch/s390/kernel/irq.c +++ b/trunk/arch/s390/kernel/irq.c @@ -42,8 +42,7 @@ static const struct irq_class intrclass_names[] = { {.name = "VRT", .desc = "[EXT] Virtio" }, {.name = "SCP", .desc = "[EXT] Service Call" }, {.name = "IUC", .desc = "[EXT] IUCV" }, - {.name = "CMS", .desc = "[EXT] CPU-Measurement: Sampling" }, - {.name = "CMC", .desc = "[EXT] CPU-Measurement: Counter" }, + {.name = "CPM", .desc = "[EXT] CPU Measurement" }, {.name = "CIO", .desc = "[I/O] Common I/O Layer Interrupt" }, {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt" }, {.name = "DAS", .desc = "[I/O] DASD" }, diff --git a/trunk/arch/s390/kernel/machine_kexec.c b/trunk/arch/s390/kernel/machine_kexec.c index cdacf8f91b2d..bdad47d54478 100644 --- a/trunk/arch/s390/kernel/machine_kexec.c +++ b/trunk/arch/s390/kernel/machine_kexec.c @@ -24,7 +24,6 @@ #include #include #include -#include typedef void (*relocate_kernel_t)(kimage_entry_t *, unsigned long); @@ -80,8 +79,8 @@ static void __do_machine_kdump(void *image) #ifdef CONFIG_CRASH_DUMP int (*start_kdump)(int) = (void *)((struct kimage *) image)->start; - setup_regs(); __load_psw_mask(PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA); + setup_regs(); start_kdump(1); #endif } @@ -115,13 +114,8 @@ static void crash_map_pages(int enable) size % KEXEC_CRASH_MEM_ALIGN); if (enable) vmem_add_mapping(crashk_res.start, size); - else { + else vmem_remove_mapping(crashk_res.start, size); - if (size) - os_info_crashkernel_add(crashk_res.start, size); - else - os_info_crashkernel_add(0, 0); - } } /* @@ -214,7 +208,6 @@ static void __machine_kexec(void *data) { struct kimage *image = data; - __arch_local_irq_stosm(0x04); /* enable DAT */ pfault_fini(); tracing_off(); debug_locks_off(); diff --git a/trunk/arch/s390/kernel/os_info.c b/trunk/arch/s390/kernel/os_info.c index 95fa5ac6c4ce..e8d6c214d498 100644 --- a/trunk/arch/s390/kernel/os_info.c +++ b/trunk/arch/s390/kernel/os_info.c @@ -60,7 +60,7 @@ void __init os_info_init(void) os_info.version_minor = OS_INFO_VERSION_MINOR; os_info.magic = OS_INFO_MAGIC; os_info.csum = os_info_csum(&os_info); - memcpy_absolute(&S390_lowcore.os_info, &ptr, sizeof(ptr)); + copy_to_absolute_zero(&S390_lowcore.os_info, &ptr, sizeof(ptr)); } #ifdef CONFIG_CRASH_DUMP @@ -138,6 +138,7 @@ static void os_info_old_init(void) goto fail_free; os_info_old_alloc(OS_INFO_VMCOREINFO, 1); os_info_old_alloc(OS_INFO_REIPL_BLOCK, 1); + os_info_old_alloc(OS_INFO_INIT_FN, PAGE_SIZE); pr_info("crashkernel: addr=0x%lx size=%lu\n", (unsigned long) os_info_old->crashkernel_addr, (unsigned long) os_info_old->crashkernel_size); diff --git a/trunk/arch/s390/kernel/perf_cpum_cf.c b/trunk/arch/s390/kernel/perf_cpum_cf.c index 9871b1971ed7..cb019f429e88 100644 --- a/trunk/arch/s390/kernel/perf_cpum_cf.c +++ b/trunk/arch/s390/kernel/perf_cpum_cf.c @@ -225,7 +225,7 @@ static void cpumf_measurement_alert(struct ext_code ext_code, if (!(alert & CPU_MF_INT_CF_MASK)) return; - kstat_cpu(smp_processor_id()).irqs[EXTINT_CMC]++; + kstat_cpu(smp_processor_id()).irqs[EXTINT_CPM]++; cpuhw = &__get_cpu_var(cpu_hw_events); /* Measurement alerts are shared and might happen when the PMU diff --git a/trunk/arch/s390/kernel/setup.c b/trunk/arch/s390/kernel/setup.c index 489d1d8d96b0..06264ae8ccd9 100644 --- a/trunk/arch/s390/kernel/setup.c +++ b/trunk/arch/s390/kernel/setup.c @@ -428,12 +428,10 @@ static void __init setup_lowcore(void) lc->restart_fn = (unsigned long) do_restart; lc->restart_data = 0; lc->restart_source = -1UL; - - /* Setup absolute zero lowcore */ - memcpy_absolute(&S390_lowcore.restart_stack, &lc->restart_stack, - 4 * sizeof(unsigned long)); - memcpy_absolute(&S390_lowcore.restart_psw, &lc->restart_psw, - sizeof(lc->restart_psw)); + memcpy(&S390_lowcore.restart_stack, &lc->restart_stack, + 4*sizeof(unsigned long)); + copy_to_absolute_zero(&S390_lowcore.restart_psw, + &lc->restart_psw, sizeof(psw_t)); set_prefix((u32)(unsigned long) lc); lowcore_ptr[0] = lc; @@ -600,7 +598,7 @@ static void __init setup_vmcoreinfo(void) #ifdef CONFIG_KEXEC unsigned long ptr = paddr_vmcoreinfo_note(); - memcpy_absolute(&S390_lowcore.vmcore_info, &ptr, sizeof(ptr)); + copy_to_absolute_zero(&S390_lowcore.vmcore_info, &ptr, sizeof(ptr)); #endif } diff --git a/trunk/arch/s390/kernel/signal.c b/trunk/arch/s390/kernel/signal.c index ac565b44aabb..f626232e216c 100644 --- a/trunk/arch/s390/kernel/signal.c +++ b/trunk/arch/s390/kernel/signal.c @@ -33,6 +33,9 @@ #include #include "entry.h" +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + + typedef struct { __u8 callee_used_stack[__SIGNAL_FRAMESIZE]; @@ -166,6 +169,7 @@ SYSCALL_DEFINE0(sigreturn) goto badframe; if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE)) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigregs(regs, &frame->sregs)) goto badframe; @@ -185,6 +189,7 @@ SYSCALL_DEFINE0(rt_sigreturn) goto badframe; if (__copy_from_user(&set.sig, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigregs(regs, &frame->uc.uc_mcontext)) goto badframe; @@ -362,7 +367,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, return -EFAULT; } -static void handle_signal(unsigned long sig, struct k_sigaction *ka, +static int handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) { @@ -374,9 +379,9 @@ static void handle_signal(unsigned long sig, struct k_sigaction *ka, else ret = setup_frame(sig, ka, oldset, regs); if (ret) - return; - signal_delivered(sig, info, ka, regs, - test_thread_flag(TIF_SINGLE_STEP)); + return ret; + block_sigmask(ka, sig); + return 0; } /* @@ -393,7 +398,12 @@ void do_signal(struct pt_regs *regs) siginfo_t info; int signr; struct k_sigaction ka; - sigset_t *oldset = sigmask_to_save(); + sigset_t *oldset; + + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; /* * Get signal to deliver. When running under ptrace, at this point @@ -431,10 +441,24 @@ void do_signal(struct pt_regs *regs) /* No longer in a system call */ clear_thread_flag(TIF_SYSCALL); - if (is_compat_task()) - handle_signal32(signr, &ka, &info, oldset, regs); - else - handle_signal(signr, &ka, &info, oldset, regs); + if ((is_compat_task() ? + handle_signal32(signr, &ka, &info, oldset, regs) : + handle_signal(signr, &ka, &info, oldset, regs)) == 0) { + /* + * A signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TIF_RESTORE_SIGMASK flag. + */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + + /* + * Let tracing know that we've done the handler setup. + */ + tracehook_signal_handler(signr, &info, &ka, regs, + test_thread_flag(TIF_SINGLE_STEP)); + } return; } @@ -460,11 +484,16 @@ void do_signal(struct pt_regs *regs) /* * If there's no signal to deliver, we just put the saved sigmask back. */ - restore_saved_sigmask(); + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } } void do_notify_resume(struct pt_regs *regs) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } diff --git a/trunk/arch/s390/kernel/smp.c b/trunk/arch/s390/kernel/smp.c index 15cca26ccb6c..647ba9425893 100644 --- a/trunk/arch/s390/kernel/smp.c +++ b/trunk/arch/s390/kernel/smp.c @@ -297,27 +297,26 @@ static void pcpu_start_fn(struct pcpu *pcpu, void (*func)(void *), void *data) static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *), void *data, unsigned long stack) { - struct _lowcore *lc = lowcore_ptr[pcpu - pcpu_devices]; - struct { - unsigned long stack; - void *func; - void *data; - unsigned long source; - } restart = { stack, func, data, stap() }; + struct _lowcore *lc = pcpu->lowcore; + unsigned short this_cpu; __load_psw_mask(psw_kernel_bits); - if (pcpu->address == restart.source) + this_cpu = stap(); + if (pcpu->address == this_cpu) func(data); /* should not return */ /* Stop target cpu (if func returns this stops the current cpu). */ pcpu_sigp_retry(pcpu, sigp_stop, 0); /* Restart func on the target cpu and stop the current cpu. */ - memcpy_absolute(&lc->restart_stack, &restart, sizeof(restart)); + lc->restart_stack = stack; + lc->restart_fn = (unsigned long) func; + lc->restart_data = (unsigned long) data; + lc->restart_source = (unsigned long) this_cpu; asm volatile( "0: sigp 0,%0,6 # sigp restart to target cpu\n" " brc 2,0b # busy, try again\n" "1: sigp 0,%1,5 # sigp stop to current cpu\n" " brc 2,1b # busy, try again\n" - : : "d" (pcpu->address), "d" (restart.source) : "0", "1", "cc"); + : : "d" (pcpu->address), "d" (this_cpu) : "0", "1", "cc"); for (;;) ; } @@ -801,6 +800,17 @@ void __noreturn cpu_die(void) #endif /* CONFIG_HOTPLUG_CPU */ +static void smp_call_os_info_init_fn(void) +{ + int (*init_fn)(void); + unsigned long size; + + init_fn = os_info_old_entry(OS_INFO_INIT_FN, &size); + if (!init_fn) + return; + init_fn(); +} + void __init smp_prepare_cpus(unsigned int max_cpus) { /* request the 0x1201 emergency signal external interrupt */ @@ -809,6 +819,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) /* request the 0x1202 external call external interrupt */ if (register_external_interrupt(0x1202, do_ext_call_interrupt) != 0) panic("Couldn't request external interrupt 0x1202"); + smp_call_os_info_init_fn(); smp_detect_cpus(); } @@ -932,6 +943,19 @@ static struct attribute_group cpu_common_attr_group = { .attrs = cpu_common_attrs, }; +static ssize_t show_capability(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned int capability; + int rc; + + rc = get_cpu_capability(&capability); + if (rc) + return rc; + return sprintf(buf, "%u\n", capability); +} +static DEVICE_ATTR(capability, 0444, show_capability, NULL); + static ssize_t show_idle_count(struct device *dev, struct device_attribute *attr, char *buf) { @@ -969,6 +993,7 @@ static ssize_t show_idle_time(struct device *dev, static DEVICE_ATTR(idle_time_us, 0444, show_idle_time, NULL); static struct attribute *cpu_online_attrs[] = { + &dev_attr_capability.attr, &dev_attr_idle_count.attr, &dev_attr_idle_time_us.attr, NULL, diff --git a/trunk/arch/s390/kernel/sysinfo.c b/trunk/arch/s390/kernel/sysinfo.c index fa0eb238dac7..2a94b774695c 100644 --- a/trunk/arch/s390/kernel/sysinfo.c +++ b/trunk/arch/s390/kernel/sysinfo.c @@ -392,6 +392,27 @@ static __init int create_proc_service_level(void) } subsys_initcall(create_proc_service_level); +/* + * Bogomips calculation based on cpu capability. + */ +int get_cpu_capability(unsigned int *capability) +{ + struct sysinfo_1_2_2 *info; + int rc; + + info = (void *) get_zeroed_page(GFP_KERNEL); + if (!info) + return -ENOMEM; + rc = stsi(info, 1, 2, 2); + if (rc == -ENOSYS) + goto out; + rc = 0; + *capability = info->capability; +out: + free_page((unsigned long) info); + return rc; +} + /* * CPU capability might have changed. Therefore recalculate loops_per_jiffy. */ diff --git a/trunk/arch/s390/lib/uaccess_mvcos.c b/trunk/arch/s390/lib/uaccess_mvcos.c index 58a75a8ae90c..60455f104ea3 100644 --- a/trunk/arch/s390/lib/uaccess_mvcos.c +++ b/trunk/arch/s390/lib/uaccess_mvcos.c @@ -14,7 +14,7 @@ #include #include "uaccess.h" -#ifndef CONFIG_64BIT +#ifndef __s390x__ #define AHI "ahi" #define ALR "alr" #define CLR "clr" diff --git a/trunk/arch/s390/lib/uaccess_std.c b/trunk/arch/s390/lib/uaccess_std.c index 57e94298539b..bb1a7eed42ce 100644 --- a/trunk/arch/s390/lib/uaccess_std.c +++ b/trunk/arch/s390/lib/uaccess_std.c @@ -15,7 +15,7 @@ #include #include "uaccess.h" -#ifndef CONFIG_64BIT +#ifndef __s390x__ #define AHI "ahi" #define ALR "alr" #define CLR "clr" diff --git a/trunk/arch/s390/mm/maccess.c b/trunk/arch/s390/mm/maccess.c index 921fa541dc04..795a0a9bb2eb 100644 --- a/trunk/arch/s390/mm/maccess.c +++ b/trunk/arch/s390/mm/maccess.c @@ -101,27 +101,19 @@ int memcpy_real(void *dest, void *src, size_t count) } /* - * Copy memory in absolute mode (kernel to kernel) + * Copy memory to absolute zero */ -void memcpy_absolute(void *dest, void *src, size_t count) +void copy_to_absolute_zero(void *dest, void *src, size_t count) { - unsigned long cr0, flags, prefix; + unsigned long cr0; - flags = arch_local_irq_save(); + BUG_ON((unsigned long) dest + count >= sizeof(struct _lowcore)); + preempt_disable(); __ctl_store(cr0, 0, 0); __ctl_clear_bit(0, 28); /* disable lowcore protection */ - prefix = store_prefix(); - if (prefix) { - local_mcck_disable(); - set_prefix(0); - memcpy(dest, src, count); - set_prefix(prefix); - local_mcck_enable(); - } else { - memcpy(dest, src, count); - } + memcpy_real(dest + store_prefix(), src, count); __ctl_load(cr0, 0, 0); - arch_local_irq_restore(flags); + preempt_enable(); } /* @@ -195,6 +187,20 @@ static int is_swapped(unsigned long addr) return 0; } +/* + * Return swapped prefix or zero page address + */ +static unsigned long get_swapped(unsigned long addr) +{ + unsigned long prefix = store_prefix(); + + if (addr < sizeof(struct _lowcore)) + return addr + prefix; + if (addr >= prefix && addr < prefix + sizeof(struct _lowcore)) + return addr - prefix; + return addr; +} + /* * Convert a physical pointer for /dev/mem access * @@ -212,7 +218,7 @@ void *xlate_dev_mem_ptr(unsigned long addr) size = PAGE_SIZE - (addr & ~PAGE_MASK); bounce = (void *) __get_free_page(GFP_ATOMIC); if (bounce) - memcpy_absolute(bounce, (void *) addr, size); + memcpy_real(bounce, (void *) get_swapped(addr), size); } preempt_enable(); put_online_cpus(); diff --git a/trunk/arch/s390/mm/vmem.c b/trunk/arch/s390/mm/vmem.c index 71ae20df674e..4799383e2df9 100644 --- a/trunk/arch/s390/mm/vmem.c +++ b/trunk/arch/s390/mm/vmem.c @@ -109,7 +109,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro) pte = mk_pte_phys(address, __pgprot(ro ? _PAGE_RO : 0)); pm_dir = pmd_offset(pu_dir, address); -#ifdef CONFIG_64BIT +#ifdef __s390x__ if (MACHINE_HAS_HPAGE && !(address & ~HPAGE_MASK) && (address + HPAGE_SIZE <= start + size) && (address >= HPAGE_SIZE)) { diff --git a/trunk/arch/s390/oprofile/hwsampler.c b/trunk/arch/s390/oprofile/hwsampler.c index a4a89fa980d6..c6646de07bf4 100644 --- a/trunk/arch/s390/oprofile/hwsampler.c +++ b/trunk/arch/s390/oprofile/hwsampler.c @@ -235,7 +235,7 @@ static void hws_ext_handler(struct ext_code ext_code, if (!(param32 & CPU_MF_INT_SF_MASK)) return; - kstat_cpu(smp_processor_id()).irqs[EXTINT_CMS]++; + kstat_cpu(smp_processor_id()).irqs[EXTINT_CPM]++; atomic_xchg(&cb->ext_params, atomic_read(&cb->ext_params) | param32); if (hws_wq) diff --git a/trunk/arch/score/kernel/signal.c b/trunk/arch/score/kernel/signal.c index e382c52ca0d9..d4a49011c48a 100644 --- a/trunk/arch/score/kernel/signal.c +++ b/trunk/arch/score/kernel/signal.c @@ -34,6 +34,8 @@ #include #include +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + struct rt_sigframe { u32 rs_ass[4]; /* argument save space */ u32 rs_code[2]; /* signal trampoline */ @@ -160,6 +162,7 @@ score_rt_sigreturn(struct pt_regs *regs) if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); sig = restore_sigcontext(regs, &frame->rs_uc.uc_mcontext); @@ -238,9 +241,11 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, return -EFAULT; } -static void handle_signal(unsigned long sig, siginfo_t *info, - struct k_sigaction *ka, struct pt_regs *regs) +static int handle_signal(unsigned long sig, siginfo_t *info, + struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs) { + int ret; + if (regs->is_syscall) { switch (regs->regs[4]) { case ERESTART_RESTARTBLOCK: @@ -264,15 +269,18 @@ static void handle_signal(unsigned long sig, siginfo_t *info, /* * Set up the stack frame */ - if (setup_rt_frame(ka, regs, sig, sigmask_to_save(), info) < 0) - return; + ret = setup_rt_frame(ka, regs, sig, oldset, info); + + if (ret == 0) + block_sigmask(ka, sig); - signal_delivered(sig, info, ka, regs, 0); + return ret; } static void do_signal(struct pt_regs *regs) { struct k_sigaction ka; + sigset_t *oldset; siginfo_t info; int signr; @@ -284,10 +292,25 @@ static void do_signal(struct pt_regs *regs) if (!user_mode(regs)) return; + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { /* Actually deliver the signal. */ - handle_signal(signr, &info, &ka, regs); + if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { + /* + * A signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TIF_RESTORE_SIGMASK flag. + */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + } + return; } @@ -314,7 +337,10 @@ static void do_signal(struct pt_regs *regs) * If there's no signal to deliver, we just put the saved sigmask * back */ - restore_saved_sigmask(); + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } } /* @@ -330,5 +356,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/trunk/arch/sh/boards/mach-migor/setup.c b/trunk/arch/sh/boards/mach-migor/setup.c index a8a1ca741c85..34cd0c5ff2e1 100644 --- a/trunk/arch/sh/boards/mach-migor/setup.c +++ b/trunk/arch/sh/boards/mach-migor/setup.c @@ -188,6 +188,7 @@ static struct platform_nand_data migor_nand_flash_data = { .partitions = migor_nand_flash_partitions, .nr_partitions = ARRAY_SIZE(migor_nand_flash_partitions), .chip_delay = 20, + .part_probe_types = (const char *[]) { "cmdlinepart", NULL }, }, .ctrl = { .dev_ready = migor_nand_flash_ready, diff --git a/trunk/arch/sh/include/asm/posix_types_32.h b/trunk/arch/sh/include/asm/posix_types_32.h index ba0bdc423b07..abda58467ece 100644 --- a/trunk/arch/sh/include/asm/posix_types_32.h +++ b/trunk/arch/sh/include/asm/posix_types_32.h @@ -3,6 +3,8 @@ typedef unsigned short __kernel_mode_t; #define __kernel_mode_t __kernel_mode_t +typedef unsigned short __kernel_nlink_t; +#define __kernel_nlink_t __kernel_nlink_t typedef unsigned short __kernel_ipc_pid_t; #define __kernel_ipc_pid_t __kernel_ipc_pid_t typedef unsigned short __kernel_uid_t; diff --git a/trunk/arch/sh/include/asm/posix_types_64.h b/trunk/arch/sh/include/asm/posix_types_64.h index 244f7e950e17..fcda07b4a616 100644 --- a/trunk/arch/sh/include/asm/posix_types_64.h +++ b/trunk/arch/sh/include/asm/posix_types_64.h @@ -3,6 +3,8 @@ typedef unsigned short __kernel_mode_t; #define __kernel_mode_t __kernel_mode_t +typedef unsigned short __kernel_nlink_t; +#define __kernel_nlink_t __kernel_nlink_t typedef unsigned short __kernel_ipc_pid_t; #define __kernel_ipc_pid_t __kernel_ipc_pid_t typedef unsigned short __kernel_uid_t; diff --git a/trunk/arch/sh/include/asm/thread_info.h b/trunk/arch/sh/include/asm/thread_info.h index bc13b57cdc83..0c04ffc4f12c 100644 --- a/trunk/arch/sh/include/asm/thread_info.h +++ b/trunk/arch/sh/include/asm/thread_info.h @@ -169,7 +169,7 @@ static inline void set_restore_sigmask(void) { struct thread_info *ti = current_thread_info(); ti->status |= TS_RESTORE_SIGMASK; - WARN_ON(!test_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags)); + set_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags); } #define TI_FLAG_FAULT_CODE_SHIFT 24 @@ -189,23 +189,6 @@ static inline unsigned int get_thread_fault_code(void) struct thread_info *ti = current_thread_info(); return ti->flags >> TI_FLAG_FAULT_CODE_SHIFT; } - -static inline void clear_restore_sigmask(void) -{ - current_thread_info()->status &= ~TS_RESTORE_SIGMASK; -} -static inline bool test_restore_sigmask(void) -{ - return current_thread_info()->status & TS_RESTORE_SIGMASK; -} -static inline bool test_and_clear_restore_sigmask(void) -{ - struct thread_info *ti = current_thread_info(); - if (!(ti->status & TS_RESTORE_SIGMASK)) - return false; - ti->status &= ~TS_RESTORE_SIGMASK; - return true; -} #endif /* !__ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/trunk/arch/sh/kernel/signal_32.c b/trunk/arch/sh/kernel/signal_32.c index d6b7b6154f87..cb4172c8af7d 100644 --- a/trunk/arch/sh/kernel/signal_32.c +++ b/trunk/arch/sh/kernel/signal_32.c @@ -32,6 +32,8 @@ #include #include +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + struct fdpic_func_descriptor { unsigned long text; unsigned long GOT; @@ -224,6 +226,7 @@ asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5, sizeof(frame->extramask)))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(regs, &frame->sc, &r0)) @@ -253,6 +256,7 @@ asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5, if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0)) @@ -518,11 +522,10 @@ handle_syscall_restart(unsigned long save_r0, struct pt_regs *regs, /* * OK, we're invoking a handler */ -static void +static int handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, - struct pt_regs *regs, unsigned int save_r0) + sigset_t *oldset, struct pt_regs *regs, unsigned int save_r0) { - sigset_t *oldset = sigmask_to_save(); int ret; /* Set up the stack frame */ @@ -531,10 +534,10 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, else ret = setup_frame(sig, ka, oldset, regs); - if (ret) - return; - signal_delivered(sig, info, ka, regs, - test_thread_flag(TIF_SINGLESTEP)); + if (ret == 0) + block_sigmask(ka, sig); + + return ret; } /* @@ -551,6 +554,7 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0) siginfo_t info; int signr; struct k_sigaction ka; + sigset_t *oldset; /* * We want the common case to go fast, which @@ -561,12 +565,30 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0) if (!user_mode(regs)) return; + if (current_thread_info()->status & TS_RESTORE_SIGMASK) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { handle_syscall_restart(save_r0, regs, &ka.sa); /* Whee! Actually deliver the signal. */ - handle_signal(signr, &ka, &info, regs, save_r0); + if (handle_signal(signr, &ka, &info, oldset, + regs, save_r0) == 0) { + /* + * A signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TS_RESTORE_SIGMASK flag + */ + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; + + tracehook_signal_handler(signr, &info, &ka, regs, + test_thread_flag(TIF_SINGLESTEP)); + } + return; } @@ -588,7 +610,10 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0) * If there's no signal to deliver, we just put the saved sigmask * back. */ - restore_saved_sigmask(); + if (current_thread_info()->status & TS_RESTORE_SIGMASK) { + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } } asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0, @@ -601,5 +626,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0, if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/trunk/arch/sh/kernel/signal_64.c b/trunk/arch/sh/kernel/signal_64.c index 6b5b3dfe886b..b589a354c069 100644 --- a/trunk/arch/sh/kernel/signal_64.c +++ b/trunk/arch/sh/kernel/signal_64.c @@ -41,9 +41,11 @@ #define DEBUG_SIG 0 -static void +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + +static int handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, - struct pt_regs * regs); + sigset_t *oldset, struct pt_regs * regs); static inline void handle_syscall_restart(struct pt_regs *regs, struct sigaction *sa) @@ -86,6 +88,7 @@ static void do_signal(struct pt_regs *regs) siginfo_t info; int signr; struct k_sigaction ka; + sigset_t *oldset; /* * We want the common case to go fast, which @@ -96,13 +99,28 @@ static void do_signal(struct pt_regs *regs) if (!user_mode(regs)) return; + if (current_thread_info()->status & TS_RESTORE_SIGMASK) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + signr = get_signal_to_deliver(&info, &ka, regs, 0); if (signr > 0) { handle_syscall_restart(regs, &ka.sa); /* Whee! Actually deliver the signal. */ - handle_signal(signr, &info, &ka, regs); - return; + if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { + /* + * If a signal was successfully delivered, the + * saved sigmask is in its frame, and we can + * clear the TS_RESTORE_SIGMASK flag. + */ + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; + + tracehook_signal_handler(signr, &info, &ka, regs, + test_thread_flag(TIF_SINGLESTEP)); + return; + } } /* Did we come from a system call? */ @@ -125,7 +143,12 @@ static void do_signal(struct pt_regs *regs) } /* No signal to deliver -- put the saved sigmask back */ - restore_saved_sigmask(); + if (current_thread_info()->status & TS_RESTORE_SIGMASK) { + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } + + return; } /* @@ -328,6 +351,7 @@ asmlinkage int sys_sigreturn(unsigned long r2, unsigned long r3, sizeof(frame->extramask)))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(regs, &frame->sc, &ret)) @@ -360,6 +384,7 @@ asmlinkage int sys_rt_sigreturn(unsigned long r2, unsigned long r3, if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ret)) @@ -634,11 +659,10 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, /* * OK, we're invoking a handler */ -static void +static int handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, - struct pt_regs * regs) + sigset_t *oldset, struct pt_regs * regs) { - sigset_t *oldset = sigmask_to_save(); int ret; /* Set up the stack frame */ @@ -647,11 +671,10 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, else ret = setup_frame(sig, ka, oldset, regs); - if (ret) - return; + if (ret == 0) + block_sigmask(ka, sig); - signal_delivered(sig, info, ka, regs, - test_thread_flag(TIF_SINGLESTEP)); + return ret; } asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) @@ -662,5 +685,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/trunk/arch/sparc/Kconfig b/trunk/arch/sparc/Kconfig index e74ff1377626..83bd051754e1 100644 --- a/trunk/arch/sparc/Kconfig +++ b/trunk/arch/sparc/Kconfig @@ -41,6 +41,7 @@ config SPARC32 def_bool !64BIT select GENERIC_ATOMIC64 select CLZ_TAB + select ARCH_USES_GETTIMEOFFSET config SPARC64 def_bool 64BIT diff --git a/trunk/arch/sparc/include/asm/asi.h b/trunk/arch/sparc/include/asm/asi.h index 61ebe7411ceb..cbb93e5141de 100644 --- a/trunk/arch/sparc/include/asm/asi.h +++ b/trunk/arch/sparc/include/asm/asi.h @@ -40,7 +40,11 @@ #define ASI_M_UNA01 0x01 /* Same here... */ #define ASI_M_MXCC 0x02 /* Access to TI VIKING MXCC registers */ #define ASI_M_FLUSH_PROBE 0x03 /* Reference MMU Flush/Probe; rw, ss */ +#ifndef CONFIG_SPARC_LEON #define ASI_M_MMUREGS 0x04 /* MMU Registers; rw, ss */ +#else +#define ASI_M_MMUREGS 0x19 +#endif /* CONFIG_SPARC_LEON */ #define ASI_M_TLBDIAG 0x05 /* MMU TLB only Diagnostics */ #define ASI_M_DIAGS 0x06 /* Reference MMU Diagnostics */ #define ASI_M_IODIAG 0x07 /* MMU I/O TLB only Diagnostics */ diff --git a/trunk/arch/sparc/include/asm/asmmacro.h b/trunk/arch/sparc/include/asm/asmmacro.h index a0e28ef02558..02a172fb193a 100644 --- a/trunk/arch/sparc/include/asm/asmmacro.h +++ b/trunk/arch/sparc/include/asm/asmmacro.h @@ -20,26 +20,4 @@ /* All traps low-level code here must end with this macro. */ #define RESTORE_ALL b ret_trap_entry; clr %l6; -/* Support for run-time patching of single instructions. - * This is used to handle the differences in the ASI for - * MMUREGS for LEON and SUN. - * - * Sample: - * LEON_PI(lda [%g0] ASI_LEON_MMUREGS, %o0 - * SUN_PI_(lda [%g0] ASI_M_MMUREGS, %o0 - * PI == Patch Instruction - * - * For LEON we will use the first variant, - * and for all other we will use the SUN variant. - * The order is important. - */ -#define LEON_PI(...) \ -662: __VA_ARGS__ - -#define SUN_PI_(...) \ - .section .leon_1insn_patch, "ax"; \ - .word 662b; \ - __VA_ARGS__; \ - .previous - #endif /* !(_SPARC_ASMMACRO_H) */ diff --git a/trunk/arch/sparc/include/asm/dma-mapping.h b/trunk/arch/sparc/include/asm/dma-mapping.h index 8493fd3c7ba5..48a7c65731d2 100644 --- a/trunk/arch/sparc/include/asm/dma-mapping.h +++ b/trunk/arch/sparc/include/asm/dma-mapping.h @@ -12,18 +12,13 @@ extern int dma_supported(struct device *dev, u64 mask); #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) -extern struct dma_map_ops *dma_ops; -extern struct dma_map_ops *leon_dma_ops; -extern struct dma_map_ops pci32_dma_ops; - +extern struct dma_map_ops *dma_ops, pci32_dma_ops; extern struct bus_type pci_bus_type; static inline struct dma_map_ops *get_dma_ops(struct device *dev) { #if defined(CONFIG_SPARC32) && defined(CONFIG_PCI) - if (sparc_cpu_model == sparc_leon) - return leon_dma_ops; - else if (dev->bus == &pci_bus_type) + if (dev->bus == &pci_bus_type) return &pci32_dma_ops; #endif return dma_ops; diff --git a/trunk/arch/sparc/include/asm/leon.h b/trunk/arch/sparc/include/asm/leon.h index 3375c6293893..07659124c140 100644 --- a/trunk/arch/sparc/include/asm/leon.h +++ b/trunk/arch/sparc/include/asm/leon.h @@ -8,6 +8,8 @@ #ifndef LEON_H_INCLUDE #define LEON_H_INCLUDE +#ifdef CONFIG_SPARC_LEON + /* mmu register access, ASI_LEON_MMUREGS */ #define LEON_CNR_CTRL 0x000 #define LEON_CNR_CTXP 0x100 @@ -60,6 +62,15 @@ #ifndef __ASSEMBLY__ +/* do a virtual address read without cache */ +static inline unsigned long leon_readnobuffer_reg(unsigned long paddr) +{ + unsigned long retval; + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r"(retval) : "r"(paddr), "i"(ASI_LEON_NOCACHE)); + return retval; +} + /* do a physical address bypass write, i.e. for 0x80000000 */ static inline void leon_store_reg(unsigned long paddr, unsigned long value) { @@ -76,16 +87,47 @@ static inline unsigned long leon_load_reg(unsigned long paddr) return retval; } +static inline void leon_srmmu_disabletlb(void) +{ + unsigned int retval; + __asm__ __volatile__("lda [%%g0] %2, %0\n\t" : "=r"(retval) : "r"(0), + "i"(ASI_LEON_MMUREGS)); + retval |= LEON_CNR_CTRL_TLBDIS; + __asm__ __volatile__("sta %0, [%%g0] %2\n\t" : : "r"(retval), "r"(0), + "i"(ASI_LEON_MMUREGS) : "memory"); +} + +static inline void leon_srmmu_enabletlb(void) +{ + unsigned int retval; + __asm__ __volatile__("lda [%%g0] %2, %0\n\t" : "=r"(retval) : "r"(0), + "i"(ASI_LEON_MMUREGS)); + retval = retval & ~LEON_CNR_CTRL_TLBDIS; + __asm__ __volatile__("sta %0, [%%g0] %2\n\t" : : "r"(retval), "r"(0), + "i"(ASI_LEON_MMUREGS) : "memory"); +} + /* macro access for leon_load_reg() and leon_store_reg() */ #define LEON3_BYPASS_LOAD_PA(x) (leon_load_reg((unsigned long)(x))) #define LEON3_BYPASS_STORE_PA(x, v) (leon_store_reg((unsigned long)(x), (unsigned long)(v))) +#define LEON3_BYPASS_ANDIN_PA(x, v) LEON3_BYPASS_STORE_PA(x, LEON3_BYPASS_LOAD_PA(x) & v) +#define LEON3_BYPASS_ORIN_PA(x, v) LEON3_BYPASS_STORE_PA(x, LEON3_BYPASS_LOAD_PA(x) | v) #define LEON_BYPASS_LOAD_PA(x) leon_load_reg((unsigned long)(x)) #define LEON_BYPASS_STORE_PA(x, v) leon_store_reg((unsigned long)(x), (unsigned long)(v)) +#define LEON_REGLOAD_PA(x) leon_load_reg((unsigned long)(x)+LEON_PREGS) +#define LEON_REGSTORE_PA(x, v) leon_store_reg((unsigned long)(x)+LEON_PREGS, (unsigned long)(v)) +#define LEON_REGSTORE_OR_PA(x, v) LEON_REGSTORE_PA(x, LEON_REGLOAD_PA(x) | (unsigned long)(v)) +#define LEON_REGSTORE_AND_PA(x, v) LEON_REGSTORE_PA(x, LEON_REGLOAD_PA(x) & (unsigned long)(v)) + +/* macro access for leon_readnobuffer_reg() */ +#define LEON_BYPASSCACHE_LOAD_VA(x) leon_readnobuffer_reg((unsigned long)(x)) extern void leon_init(void); extern void leon_switch_mm(void); extern void leon_init_IRQ(void); +extern unsigned long last_valid_pfn; + static inline unsigned long sparc_leon3_get_dcachecfg(void) { unsigned int retval; @@ -188,6 +230,9 @@ static inline int sparc_leon3_cpuid(void) #error cannot determine LEON_PAGE_SIZE_LEON #endif +#define PAGE_MIN_SHIFT (12) +#define PAGE_MIN_SIZE (1UL << PAGE_MIN_SHIFT) + #define LEON3_XCCR_SETS_MASK 0x07000000UL #define LEON3_XCCR_SSIZE_MASK 0x00f00000UL @@ -197,7 +242,7 @@ static inline int sparc_leon3_cpuid(void) #ifndef __ASSEMBLY__ struct vm_area_struct; -extern unsigned long leon_swprobe(unsigned long vaddr, unsigned long *paddr); +extern unsigned long srmmu_swprobe(unsigned long vaddr, unsigned long *paddr); extern void leon_flush_icache_all(void); extern void leon_flush_dcache_all(void); extern void leon_flush_cache_all(void); @@ -213,7 +258,15 @@ struct leon3_cacheregs { unsigned long dccr; /* 0x0c - Data Cache Configuration Register */ }; -#include +/* struct that hold LEON2 cache configuration register + * & configuration register + */ +struct leon2_cacheregs { + unsigned long ccr, cfg; +}; + +#ifdef __KERNEL__ + #include struct device_node; @@ -239,15 +292,24 @@ extern void leon_smp_done(void); extern void leon_boot_cpus(void); extern int leon_boot_one_cpu(int i, struct task_struct *); void leon_init_smp(void); +extern void cpu_idle(void); +extern void init_IRQ(void); +extern void cpu_panic(void); +extern int __leon_processor_id(void); void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu); extern irqreturn_t leon_percpu_timer_interrupt(int irq, void *unused); +extern unsigned int real_irq_entry[]; extern unsigned int smpleon_ipi[]; -extern unsigned int linux_trap_ipi15_leon[]; +extern unsigned int patchme_maybe_smp_msg[]; +extern unsigned int t_nmi[], linux_trap_ipi15_leon[]; +extern unsigned int linux_trap_ipi15_sun4m[]; extern int leon_ipi_irq; #endif /* CONFIG_SMP */ +#endif /* __KERNEL__ */ + #endif /* __ASSEMBLY__ */ /* macros used in leon_mm.c */ @@ -255,4 +317,18 @@ extern int leon_ipi_irq; #define _pfn_valid(pfn) ((pfn < last_valid_pfn) && (pfn >= PFN(phys_base))) #define _SRMMU_PTE_PMASK_LEON 0xffffffff +#else /* defined(CONFIG_SPARC_LEON) */ + +/* nop definitions for !LEON case */ +#define leon_init() do {} while (0) +#define leon_switch_mm() do {} while (0) +#define leon_init_IRQ() do {} while (0) +#define init_leon() do {} while (0) +#define leon_smp_done() do {} while (0) +#define leon_boot_cpus() do {} while (0) +#define leon_boot_one_cpu(i, t) 1 +#define leon_init_smp() do {} while (0) + +#endif /* !defined(CONFIG_SPARC_LEON) */ + #endif diff --git a/trunk/arch/sparc/include/asm/leon_amba.h b/trunk/arch/sparc/include/asm/leon_amba.h index f3034eddf468..e50f326e71bd 100644 --- a/trunk/arch/sparc/include/asm/leon_amba.h +++ b/trunk/arch/sparc/include/asm/leon_amba.h @@ -87,6 +87,8 @@ struct amba_prom_registers { #define LEON3_GPTIMER_CONFIG_NRTIMERS(c) ((c)->config & 0x7) #define LEON3_GPTIMER_CTRL_ISPENDING(r) (((r)&LEON3_GPTIMER_CTRL_PENDING) ? 1 : 0) +#ifdef CONFIG_SPARC_LEON + #ifndef __ASSEMBLY__ struct leon3_irqctrl_regs_map { @@ -262,4 +264,6 @@ extern unsigned int sparc_leon_eirq; #define amba_device(x) (((x) >> 12) & 0xfff) +#endif /* !defined(CONFIG_SPARC_LEON) */ + #endif diff --git a/trunk/arch/sparc/include/asm/pgtsrmmu.h b/trunk/arch/sparc/include/asm/pgtsrmmu.h index 79da17866fa8..cb828703a63a 100644 --- a/trunk/arch/sparc/include/asm/pgtsrmmu.h +++ b/trunk/arch/sparc/include/asm/pgtsrmmu.h @@ -139,7 +139,6 @@ restore %g0, %g0, %g0; #ifndef __ASSEMBLY__ -extern unsigned long last_valid_pfn; /* This makes sense. Honest it does - Anton */ /* XXX Yes but it's ugly as sin. FIXME. -KMW */ @@ -149,13 +148,67 @@ extern void *srmmu_nocache_pool; #define __nocache_fix(VADDR) __va(__nocache_pa(VADDR)) /* Accessing the MMU control register. */ -unsigned int srmmu_get_mmureg(void); -void srmmu_set_mmureg(unsigned long regval); -void srmmu_set_ctable_ptr(unsigned long paddr); -void srmmu_set_context(int context); -int srmmu_get_context(void); -unsigned int srmmu_get_fstatus(void); -unsigned int srmmu_get_faddr(void); +static inline unsigned int srmmu_get_mmureg(void) +{ + unsigned int retval; + __asm__ __volatile__("lda [%%g0] %1, %0\n\t" : + "=r" (retval) : + "i" (ASI_M_MMUREGS)); + return retval; +} + +static inline void srmmu_set_mmureg(unsigned long regval) +{ + __asm__ __volatile__("sta %0, [%%g0] %1\n\t" : : + "r" (regval), "i" (ASI_M_MMUREGS) : "memory"); + +} + +static inline void srmmu_set_ctable_ptr(unsigned long paddr) +{ + paddr = ((paddr >> 4) & SRMMU_CTX_PMASK); + __asm__ __volatile__("sta %0, [%1] %2\n\t" : : + "r" (paddr), "r" (SRMMU_CTXTBL_PTR), + "i" (ASI_M_MMUREGS) : + "memory"); +} + +static inline void srmmu_set_context(int context) +{ + __asm__ __volatile__("sta %0, [%1] %2\n\t" : : + "r" (context), "r" (SRMMU_CTX_REG), + "i" (ASI_M_MMUREGS) : "memory"); +} + +static inline int srmmu_get_context(void) +{ + register int retval; + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r" (retval) : + "r" (SRMMU_CTX_REG), + "i" (ASI_M_MMUREGS)); + return retval; +} + +static inline unsigned int srmmu_get_fstatus(void) +{ + unsigned int retval; + + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r" (retval) : + "r" (SRMMU_FAULT_STATUS), "i" (ASI_M_MMUREGS)); + return retval; +} + +static inline unsigned int srmmu_get_faddr(void) +{ + unsigned int retval; + + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r" (retval) : + "r" (SRMMU_FAULT_ADDR), "i" (ASI_M_MMUREGS)); + return retval; +} /* This is guaranteed on all SRMMU's. */ static inline void srmmu_flush_whole_tlb(void) @@ -166,6 +219,23 @@ static inline void srmmu_flush_whole_tlb(void) } +/* These flush types are not available on all chips... */ +#ifndef CONFIG_SPARC_LEON +static inline unsigned long srmmu_hwprobe(unsigned long vaddr) +{ + unsigned long retval; + + vaddr &= PAGE_MASK; + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r" (retval) : + "r" (vaddr | 0x400), "i" (ASI_M_FLUSH_PROBE)); + + return retval; +} +#else +#define srmmu_hwprobe(addr) srmmu_swprobe(addr, 0) +#endif + static inline int srmmu_get_pte (unsigned long addr) { diff --git a/trunk/arch/sparc/include/asm/posix_types.h b/trunk/arch/sparc/include/asm/posix_types.h index 156220ed99eb..3070f25ae90a 100644 --- a/trunk/arch/sparc/include/asm/posix_types.h +++ b/trunk/arch/sparc/include/asm/posix_types.h @@ -9,6 +9,8 @@ #if defined(__sparc__) && defined(__arch64__) /* sparc 64 bit */ +typedef unsigned int __kernel_nlink_t; +#define __kernel_nlink_t __kernel_nlink_t typedef unsigned short __kernel_old_uid_t; typedef unsigned short __kernel_old_gid_t; @@ -36,6 +38,9 @@ typedef unsigned short __kernel_gid_t; typedef unsigned short __kernel_mode_t; #define __kernel_mode_t __kernel_mode_t +typedef short __kernel_nlink_t; +#define __kernel_nlink_t __kernel_nlink_t + typedef long __kernel_daddr_t; #define __kernel_daddr_t __kernel_daddr_t diff --git a/trunk/arch/sparc/include/asm/psr.h b/trunk/arch/sparc/include/asm/psr.h index cee7ed9c927d..b8c0e5f0a66b 100644 --- a/trunk/arch/sparc/include/asm/psr.h +++ b/trunk/arch/sparc/include/asm/psr.h @@ -35,14 +35,6 @@ #define PSR_VERS 0x0f000000 /* cpu-version field */ #define PSR_IMPL 0xf0000000 /* cpu-implementation field */ -#define PSR_VERS_SHIFT 24 -#define PSR_IMPL_SHIFT 28 -#define PSR_VERS_SHIFTED_MASK 0xf -#define PSR_IMPL_SHIFTED_MASK 0xf - -#define PSR_IMPL_TI 0x4 -#define PSR_IMPL_LEON 0xf - #ifdef __KERNEL__ #ifndef __ASSEMBLY__ diff --git a/trunk/arch/sparc/include/asm/sections.h b/trunk/arch/sparc/include/asm/sections.h index f300d1a9b2b6..0b0553bbd8a0 100644 --- a/trunk/arch/sparc/include/asm/sections.h +++ b/trunk/arch/sparc/include/asm/sections.h @@ -7,7 +7,4 @@ /* sparc entry point */ extern char _start[]; -extern char __leon_1insn_patch[]; -extern char __leon_1insn_patch_end[]; - #endif diff --git a/trunk/arch/sparc/include/asm/thread_info_32.h b/trunk/arch/sparc/include/asm/thread_info_32.h index e6cd224506a9..5af664932452 100644 --- a/trunk/arch/sparc/include/asm/thread_info_32.h +++ b/trunk/arch/sparc/include/asm/thread_info_32.h @@ -131,7 +131,8 @@ register struct thread_info *current_thread_info_reg asm("g6"); #define _TIF_POLLING_NRFLAG (1<status |= TS_RESTORE_SIGMASK; - WARN_ON(!test_bit(TIF_SIGPENDING, &ti->flags)); -} -static inline void clear_restore_sigmask(void) -{ - current_thread_info()->status &= ~TS_RESTORE_SIGMASK; -} -static inline bool test_restore_sigmask(void) -{ - return current_thread_info()->status & TS_RESTORE_SIGMASK; -} -static inline bool test_and_clear_restore_sigmask(void) -{ - struct thread_info *ti = current_thread_info(); - if (!(ti->status & TS_RESTORE_SIGMASK)) - return false; - ti->status &= ~TS_RESTORE_SIGMASK; - return true; + set_bit(TIF_SIGPENDING, &ti->flags); } #endif /* !__ASSEMBLY__ */ diff --git a/trunk/arch/sparc/kernel/Makefile b/trunk/arch/sparc/kernel/Makefile index 6cf591b7e1c6..72308f9b0096 100644 --- a/trunk/arch/sparc/kernel/Makefile +++ b/trunk/arch/sparc/kernel/Makefile @@ -51,8 +51,8 @@ obj-y += of_device_common.o obj-y += of_device_$(BITS).o obj-$(CONFIG_SPARC64) += prom_irqtrans.o -obj-$(CONFIG_SPARC32) += leon_kernel.o -obj-$(CONFIG_SPARC32) += leon_pmc.o +obj-$(CONFIG_SPARC_LEON)+= leon_kernel.o +obj-$(CONFIG_SPARC_LEON)+= leon_pmc.o obj-$(CONFIG_SPARC64) += reboot.o obj-$(CONFIG_SPARC64) += sysfs.o diff --git a/trunk/arch/sparc/kernel/cpu.c b/trunk/arch/sparc/kernel/cpu.c index a6c94a2bf9d4..2d1819641769 100644 --- a/trunk/arch/sparc/kernel/cpu.c +++ b/trunk/arch/sparc/kernel/cpu.c @@ -121,7 +121,7 @@ static const struct manufacturer_info __initconst manufacturer_info[] = { FPU(-1, NULL) } },{ - PSR_IMPL_TI, + 4, .cpu_info = { CPU(0, "Texas Instruments, Inc. - SuperSparc-(II)"), /* SparcClassic -- borned STP1010TAB-50*/ @@ -191,7 +191,7 @@ static const struct manufacturer_info __initconst manufacturer_info[] = { FPU(-1, NULL) } },{ - PSR_IMPL_LEON, /* Aeroflex Gaisler */ + 0xF, /* Aeroflex Gaisler */ .cpu_info = { CPU(3, "LEON"), CPU(-1, NULL) @@ -440,16 +440,16 @@ static int __init cpu_type_probe(void) int psr_impl, psr_vers, fpu_vers; int psr; - psr_impl = ((get_psr() >> PSR_IMPL_SHIFT) & PSR_IMPL_SHIFTED_MASK); - psr_vers = ((get_psr() >> PSR_VERS_SHIFT) & PSR_VERS_SHIFTED_MASK); + psr_impl = ((get_psr() >> 28) & 0xf); + psr_vers = ((get_psr() >> 24) & 0xf); psr = get_psr(); put_psr(psr | PSR_EF); - - if (psr_impl == PSR_IMPL_LEON) - fpu_vers = get_psr() & PSR_EF ? ((get_fsr() >> 17) & 0x7) : 7; - else - fpu_vers = ((get_fsr() >> 17) & 0x7); +#ifdef CONFIG_SPARC_LEON + fpu_vers = get_psr() & PSR_EF ? ((get_fsr() >> 17) & 0x7) : 7; +#else + fpu_vers = ((get_fsr() >> 17) & 0x7); +#endif put_psr(psr); diff --git a/trunk/arch/sparc/kernel/entry.S b/trunk/arch/sparc/kernel/entry.S index dcaa1cf0de40..2dbe1806e530 100644 --- a/trunk/arch/sparc/kernel/entry.S +++ b/trunk/arch/sparc/kernel/entry.S @@ -393,6 +393,7 @@ linux_trap_ipi15_sun4d: /* FIXME */ 1: b,a 1b +#ifdef CONFIG_SPARC_LEON .globl smpleon_ipi .extern leon_ipi_interrupt /* SMP per-cpu IPI interrupts are handled specially. */ @@ -423,6 +424,8 @@ linux_trap_ipi15_leon: b ret_trap_lockless_ipi clr %l6 +#endif /* CONFIG_SPARC_LEON */ + #endif /* CONFIG_SMP */ /* This routine handles illegal instructions and privileged @@ -767,11 +770,8 @@ srmmu_fault: mov 0x400, %l5 mov 0x300, %l4 -LEON_PI(lda [%l5] ASI_LEON_MMUREGS, %l6) ! read sfar first -SUN_PI_(lda [%l5] ASI_M_MMUREGS, %l6) ! read sfar first - -LEON_PI(lda [%l4] ASI_LEON_MMUREGS, %l5) ! read sfsr last -SUN_PI_(lda [%l4] ASI_M_MMUREGS, %l5) ! read sfsr last + lda [%l5] ASI_M_MMUREGS, %l6 ! read sfar first + lda [%l4] ASI_M_MMUREGS, %l5 ! read sfsr last andn %l6, 0xfff, %l6 srl %l5, 6, %l5 ! and encode all info into l7 diff --git a/trunk/arch/sparc/kernel/etrap_32.S b/trunk/arch/sparc/kernel/etrap_32.S index e3e80d65e39a..84b5f0d2afde 100644 --- a/trunk/arch/sparc/kernel/etrap_32.S +++ b/trunk/arch/sparc/kernel/etrap_32.S @@ -234,8 +234,7 @@ tsetup_srmmu_stackchk: cmp %glob_tmp, %sp bleu,a 1f -LEON_PI( lda [%g0] ASI_LEON_MMUREGS, %glob_tmp) ! read MMU control -SUN_PI_( lda [%g0] ASI_M_MMUREGS, %glob_tmp) ! read MMU control + lda [%g0] ASI_M_MMUREGS, %glob_tmp ! read MMU control trap_setup_user_stack_is_bolixed: /* From user/kernel into invalid window w/bad user @@ -250,25 +249,18 @@ trap_setup_user_stack_is_bolixed: 1: /* Clear the fault status and turn on the no_fault bit. */ or %glob_tmp, 0x2, %glob_tmp ! or in no_fault bit -LEON_PI(sta %glob_tmp, [%g0] ASI_LEON_MMUREGS) ! set it -SUN_PI_(sta %glob_tmp, [%g0] ASI_M_MMUREGS) ! set it + sta %glob_tmp, [%g0] ASI_M_MMUREGS ! set it /* Dump the registers and cross fingers. */ STORE_WINDOW(sp) /* Clear the no_fault bit and check the status. */ andn %glob_tmp, 0x2, %glob_tmp -LEON_PI(sta %glob_tmp, [%g0] ASI_LEON_MMUREGS) -SUN_PI_(sta %glob_tmp, [%g0] ASI_M_MMUREGS) - + sta %glob_tmp, [%g0] ASI_M_MMUREGS mov AC_M_SFAR, %glob_tmp -LEON_PI(lda [%glob_tmp] ASI_LEON_MMUREGS, %g0) -SUN_PI_(lda [%glob_tmp] ASI_M_MMUREGS, %g0) - + lda [%glob_tmp] ASI_M_MMUREGS, %g0 mov AC_M_SFSR, %glob_tmp -LEON_PI(lda [%glob_tmp] ASI_LEON_MMUREGS, %glob_tmp)! save away status of winstore -SUN_PI_(lda [%glob_tmp] ASI_M_MMUREGS, %glob_tmp) ! save away status of winstore - + lda [%glob_tmp] ASI_M_MMUREGS, %glob_tmp ! save away status of winstore andcc %glob_tmp, 0x2, %g0 ! did we fault? bne trap_setup_user_stack_is_bolixed ! failure nop diff --git a/trunk/arch/sparc/kernel/head_32.S b/trunk/arch/sparc/kernel/head_32.S index afeb1d770303..a0f5c20e4b9c 100644 --- a/trunk/arch/sparc/kernel/head_32.S +++ b/trunk/arch/sparc/kernel/head_32.S @@ -30,6 +30,10 @@ * the cpu-type */ .align 4 +cputyp: + .word 1 + + .align 4 .globl cputypval cputypval: .asciz "sun4m" @@ -42,8 +46,8 @@ cputypvar: .align 4 -notsup: - .asciz "Sparc-Linux sun4/sun4c or MMU-less not supported\n\n" +sun4c_notsup: + .asciz "Sparc-Linux sun4/sun4c support does no longer exist.\n\n" .align 4 sun4e_notsup: @@ -119,7 +123,7 @@ current_pc: tst %o0 be no_sun4u_here mov %g4, %o7 /* Previous %o7. */ - + mov %o0, %l0 ! stash away romvec mov %o0, %g7 ! put it here too mov %o1, %l1 ! stash away debug_vec too @@ -128,7 +132,7 @@ current_pc: set current_pc, %g5 cmp %g3, %g5 be already_mapped - nop + nop /* %l6 will hold the offset we have to subtract * from absolute symbols in order to access areas @@ -188,9 +192,9 @@ copy_prom_done: bne not_a_sun4 nop -halt_notsup: +halt_sun4_or_sun4c: ld [%g7 + 0x68], %o1 - set notsup, %o0 + set sun4c_notsup, %o0 sub %o0, %l6, %o0 call %o1 nop @@ -198,31 +202,18 @@ halt_notsup: nop not_a_sun4: - /* It looks like this is a machine we support. - * Now find out what MMU we are dealing with - * LEON - identified by the psr.impl field - * Viking - identified by the psr.impl field - * In all other cases a sun4m srmmu. - * We check that the MMU is enabled in all cases. - */ - - /* Check if this is a LEON CPU */ - rd %psr, %g3 - srl %g3, PSR_IMPL_SHIFT, %g3 - and %g3, PSR_IMPL_SHIFTED_MASK, %g3 - cmp %g3, PSR_IMPL_LEON - be leon_remap /* It is a LEON - jump */ - nop - - /* Sanity-check, is MMU enabled */ lda [%g0] ASI_M_MMUREGS, %g1 andcc %g1, 1, %g0 - be halt_notsup + be halt_sun4_or_sun4c nop - /* Check for a viking (TI) module. */ - cmp %g3, PSR_IMPL_TI - bne srmmu_not_viking +srmmu_remap: + /* First, check for a viking (TI) module. */ + set 0x40000000, %g2 + rd %psr, %g3 + and %g2, %g3, %g3 + subcc %g3, 0x0, %g0 + bz srmmu_nviking nop /* Figure out what kind of viking we are on. @@ -237,14 +228,14 @@ not_a_sun4: lda [%g0] ASI_M_MMUREGS, %g3 ! peek in the control reg and %g2, %g3, %g3 subcc %g3, 0x0, %g0 - bnz srmmu_not_viking ! is in mbus mode + bnz srmmu_nviking ! is in mbus mode nop - + rd %psr, %g3 ! DO NOT TOUCH %g3 andn %g3, PSR_ET, %g2 wr %g2, 0x0, %psr WRITE_PAUSE - + /* Get context table pointer, then convert to * a physical address, which is 36 bits. */ @@ -267,12 +258,12 @@ not_a_sun4: lda [%g4] ASI_M_BYPASS, %o1 ! This is a level 1 ptr srl %o1, 0x4, %o1 ! Clear low 4 bits sll %o1, 0x8, %o1 ! Make physical - + /* Ok, pull in the PTD. */ lda [%o1] ASI_M_BYPASS, %o2 ! This is the 0x0 16MB pgd /* Calculate to KERNBASE entry. */ - add %o1, KERNBASE >> (SRMMU_PGDIR_SHIFT - 2), %o3 + add %o1, KERNBASE >> (SRMMU_PGDIR_SHIFT - 2), %o3 /* Poke the entry into the calculated address. */ sta %o2, [%o3] ASI_M_BYPASS @@ -302,12 +293,12 @@ not_a_sun4: b go_to_highmem nop -srmmu_not_viking: /* This works on viking's in Mbus mode and all * other MBUS modules. It is virtually the same as * the above madness sans turning traps off and flipping * the AC bit. */ +srmmu_nviking: set AC_M_CTPR, %g1 lda [%g1] ASI_M_MMUREGS, %g1 ! get ctx table ptr sll %g1, 0x4, %g1 ! make physical addr @@ -322,29 +313,6 @@ srmmu_not_viking: nop ! wheee.... -leon_remap: - /* Sanity-check, is MMU enabled */ - lda [%g0] ASI_LEON_MMUREGS, %g1 - andcc %g1, 1, %g0 - be halt_notsup - nop - - /* Same code as in the srmmu_not_viking case, - * with the LEON ASI for mmuregs - */ - set AC_M_CTPR, %g1 - lda [%g1] ASI_LEON_MMUREGS, %g1 ! get ctx table ptr - sll %g1, 0x4, %g1 ! make physical addr - lda [%g1] ASI_M_BYPASS, %g1 ! ptr to level 1 pg_table - srl %g1, 0x4, %g1 - sll %g1, 0x8, %g1 ! make phys addr for l1 tbl - - lda [%g1] ASI_M_BYPASS, %g2 ! get level1 entry for 0x0 - add %g1, KERNBASE >> (SRMMU_PGDIR_SHIFT - 2), %g3 - sta %g2, [%g3] ASI_M_BYPASS ! place at KERNBASE entry - b go_to_highmem - nop ! wheee.... - /* Now do a non-relative jump so that PC is in high-memory */ go_to_highmem: set execute_in_high_mem, %g1 @@ -368,9 +336,8 @@ execute_in_high_mem: sethi %hi(linux_dbvec), %g1 st %o1, [%g1 + %lo(linux_dbvec)] - /* Get the machine type via the romvec - * getprops node operation - */ +/* Get the machine type via the mysterious romvec node operations. */ + add %g7, 0x1c, %l1 ld [%l1], %l0 ld [%l0], %l0 @@ -389,42 +356,9 @@ execute_in_high_mem: ! to a buf where above string ! will get stored by the prom. +#ifdef CONFIG_SPARC_LEON + /* no cpu-type check is needed, it is a SPARC-LEON */ - /* Check value of "compatible" property. - * "value" => "model" - * leon => sparc_leon - * sun4m => sun4m - * sun4s => sun4m - * sun4d => sun4d - * sun4e => "no_sun4e_here" - * '*' => "no_sun4u_here" - * Check single letters only - */ - - set cputypval, %o2 - /* If cputypval[0] == 'l' (lower case letter L) this is leon */ - ldub [%o2], %l1 - cmp %l1, 'l' - be leon_init - nop - - /* Check cputypval[4] to find the sun model */ - ldub [%o2 + 0x4], %l1 - - cmp %l1, 'm' - be sun4m_init - cmp %l1, 's' - be sun4m_init - cmp %l1, 'd' - be sun4d_init - cmp %l1, 'e' - be no_sun4e_here ! Could be a sun4e. - nop - b no_sun4u_here ! AIEEE, a V9 sun4u... Get our BIG BROTHER kernel :)) - nop - -leon_init: - /* LEON CPU - set boot_cpu_id */ sethi %hi(boot_cpu_id), %g2 ! boot-cpu index #ifdef CONFIG_SMP @@ -442,6 +376,26 @@ leon_init: ba continue_boot nop +#endif + +/* Check to cputype. We may be booted on a sun4u (64 bit box), + * and sun4d needs special treatment. + */ + + set cputypval, %o2 + ldub [%o2 + 0x4], %l1 + + cmp %l1, 'm' + be sun4m_init + cmp %l1, 's' + be sun4m_init + cmp %l1, 'd' + be sun4d_init + cmp %l1, 'e' + be no_sun4e_here ! Could be a sun4e. + nop + b no_sun4u_here ! AIEEE, a V9 sun4u... Get our BIG BROTHER kernel :)) + nop /* CPUID in bootbus can be found at PA 0xff0140000 */ #define SUN4D_BOOTBUS_CPUID 0xf0140000 @@ -477,9 +431,9 @@ sun4m_init: /* This sucks, apparently this makes Vikings call prom panic, will fix later */ 2: rd %psr, %o1 - srl %o1, PSR_IMPL_SHIFT, %o1 ! Get a type of the CPU + srl %o1, 28, %o1 ! Get a type of the CPU - subcc %o1, PSR_IMPL_TI, %g0 ! TI: Viking or MicroSPARC + subcc %o1, 4, %g0 ! TI: Viking or MicroSPARC be continue_boot nop @@ -505,6 +459,10 @@ continue_boot: /* Aieee, now set PC and nPC, enable traps, give ourselves a stack and it's * show-time! */ + + sethi %hi(cputyp), %o0 + st %g4, [%o0 + %lo(cputyp)] + /* Turn on Supervisor, EnableFloating, and all the PIL bits. * Also puts us in register window zero with traps off. */ @@ -522,7 +480,7 @@ continue_boot: set __bss_start , %o0 ! First address of BSS set _end , %o1 ! Last address of BSS add %o0, 0x1, %o0 -1: +1: stb %g0, [%o0] subcc %o0, %o1, %g0 bl 1b @@ -588,7 +546,7 @@ continue_boot: set dest, %g2; \ ld [%g5], %g4; \ st %g4, [%g2]; - + /* Patch for window spills... */ PATCH_INSN(spnwin_patch1_7win, spnwin_patch1) PATCH_INSN(spnwin_patch2_7win, spnwin_patch2) @@ -639,7 +597,7 @@ continue_boot: st %g4, [%g5 + 0x18] st %g4, [%g5 + 0x1c] -2: +2: sethi %hi(nwindows), %g4 st %g3, [%g4 + %lo(nwindows)] ! store final value sub %g3, 0x1, %g3 @@ -659,12 +617,18 @@ continue_boot: wr %g3, PSR_ET, %psr WRITE_PAUSE - /* Call sparc32_start_kernel(struct linux_romvec *rp) */ + /* First we call prom_init() to set up PROMLIB, then + * off to start_kernel(). + */ + sethi %hi(prom_vector_p), %g5 ld [%g5 + %lo(prom_vector_p)], %o0 - call sparc32_start_kernel + call prom_init nop + call start_kernel + nop + /* We should not get here. */ call halt_me nop @@ -695,7 +659,7 @@ sun4u_5: .asciz "write" .align 4 sun4u_6: - .asciz "\n\rOn sun4u you have to use sparc64 kernel\n\rand not a sparc32 version\n\r\n\r" + .asciz "\n\rOn sun4u you have to use UltraLinux (64bit) kernel\n\rand not a 32bit sun4[cdem] version\n\r\n\r" sun4u_6e: .align 4 sun4u_7: diff --git a/trunk/arch/sparc/kernel/ioport.c b/trunk/arch/sparc/kernel/ioport.c index 0f094db918c7..a2846f5e32d8 100644 --- a/trunk/arch/sparc/kernel/ioport.c +++ b/trunk/arch/sparc/kernel/ioport.c @@ -55,13 +55,17 @@ const struct sparc32_dma_ops *sparc32_dma_ops; /* This function must make sure that caches and memory are coherent after DMA * On LEON systems without cache snooping it flushes the entire D-CACHE. */ +#ifndef CONFIG_SPARC_LEON static inline void dma_make_coherent(unsigned long pa, unsigned long len) { - if (sparc_cpu_model == sparc_leon) { - if (!sparc_leon3_snooping_enabled()) - leon_flush_dcache_all(); - } } +#else +static inline void dma_make_coherent(unsigned long pa, unsigned long len) +{ + if (!sparc_leon3_snooping_enabled()) + leon_flush_dcache_all(); +} +#endif static void __iomem *_sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz); static void __iomem *_sparc_alloc_io(unsigned int busno, unsigned long phys, @@ -423,6 +427,9 @@ arch_initcall(sparc_register_ioport); #endif /* CONFIG_SBUS */ +/* LEON reuses PCI DMA ops */ +#if defined(CONFIG_PCI) || defined(CONFIG_SPARC_LEON) + /* Allocate and map kernel buffer using consistent mode DMA for a device. * hwdev should be valid struct pci_dev pointer for PCI devices. */ @@ -650,11 +657,14 @@ struct dma_map_ops pci32_dma_ops = { }; EXPORT_SYMBOL(pci32_dma_ops); -/* leon re-uses pci32_dma_ops */ -struct dma_map_ops *leon_dma_ops = &pci32_dma_ops; -EXPORT_SYMBOL(leon_dma_ops); +#endif /* CONFIG_PCI || CONFIG_SPARC_LEON */ +#ifdef CONFIG_SPARC_LEON +struct dma_map_ops *dma_ops = &pci32_dma_ops; +#elif defined(CONFIG_SBUS) struct dma_map_ops *dma_ops = &sbus_dma_ops; +#endif + EXPORT_SYMBOL(dma_ops); diff --git a/trunk/arch/sparc/kernel/irq_32.c b/trunk/arch/sparc/kernel/irq_32.c index c145f6fd123b..ae04914f7774 100644 --- a/trunk/arch/sparc/kernel/irq_32.c +++ b/trunk/arch/sparc/kernel/irq_32.c @@ -241,6 +241,9 @@ int sparc_floppy_request_irq(unsigned int irq, irq_handler_t irq_handler) unsigned int cpu_irq; int err; +#if defined CONFIG_SMP && !defined CONFIG_SPARC_LEON + struct tt_entry *trap_table; +#endif err = request_irq(irq, irq_handler, 0, "floppy", NULL); if (err) @@ -261,18 +264,13 @@ int sparc_floppy_request_irq(unsigned int irq, irq_handler_t irq_handler) table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_four = SPARC_NOP; INSTANTIATE(sparc_ttable) - -#if defined CONFIG_SMP - if (sparc_cpu_model != sparc_leon) { - struct tt_entry *trap_table; - - trap_table = &trapbase_cpu1; - INSTANTIATE(trap_table) - trap_table = &trapbase_cpu2; - INSTANTIATE(trap_table) - trap_table = &trapbase_cpu3; - INSTANTIATE(trap_table) - } +#if defined CONFIG_SMP && !defined CONFIG_SPARC_LEON + trap_table = &trapbase_cpu1; + INSTANTIATE(trap_table) + trap_table = &trapbase_cpu2; + INSTANTIATE(trap_table) + trap_table = &trapbase_cpu3; + INSTANTIATE(trap_table) #endif #undef INSTANTIATE /* diff --git a/trunk/arch/sparc/kernel/kernel.h b/trunk/arch/sparc/kernel/kernel.h index 291bb5de9ce0..a86372d34587 100644 --- a/trunk/arch/sparc/kernel/kernel.h +++ b/trunk/arch/sparc/kernel/kernel.h @@ -26,9 +26,6 @@ static inline unsigned long kimage_addr_to_ra(const char *p) #endif #ifdef CONFIG_SPARC32 -/* setup_32.c */ -void sparc32_start_kernel(struct linux_romvec *rp); - /* cpu.c */ extern void cpu_probe(void); diff --git a/trunk/arch/sparc/kernel/leon_kernel.c b/trunk/arch/sparc/kernel/leon_kernel.c index e34e2c40c060..77c1b916e4dd 100644 --- a/trunk/arch/sparc/kernel/leon_kernel.c +++ b/trunk/arch/sparc/kernel/leon_kernel.c @@ -23,7 +23,6 @@ #include #include -#include "kernel.h" #include "prom.h" #include "irq.h" diff --git a/trunk/arch/sparc/kernel/leon_pmc.c b/trunk/arch/sparc/kernel/leon_pmc.c index 4e174321097d..519ca923f59f 100644 --- a/trunk/arch/sparc/kernel/leon_pmc.c +++ b/trunk/arch/sparc/kernel/leon_pmc.c @@ -7,7 +7,6 @@ #include #include -#include #include /* List of Systems that need fixup instructions around power-down instruction */ @@ -66,15 +65,13 @@ void pmc_leon_idle(void) /* Install LEON Power Down function */ static int __init leon_pmc_install(void) { - if (sparc_cpu_model == sparc_leon) { - /* Assign power management IDLE handler */ - if (pmc_leon_need_fixup()) - pm_idle = pmc_leon_idle_fixup; - else - pm_idle = pmc_leon_idle; + /* Assign power management IDLE handler */ + if (pmc_leon_need_fixup()) + pm_idle = pmc_leon_idle_fixup; + else + pm_idle = pmc_leon_idle; - printk(KERN_INFO "leon: power management initialized\n"); - } + printk(KERN_INFO "leon: power management initialized\n"); return 0; } diff --git a/trunk/arch/sparc/kernel/leon_smp.c b/trunk/arch/sparc/kernel/leon_smp.c index 0f3fb6d9c8ef..a469090faf9f 100644 --- a/trunk/arch/sparc/kernel/leon_smp.c +++ b/trunk/arch/sparc/kernel/leon_smp.c @@ -48,13 +48,15 @@ #include "kernel.h" +#ifdef CONFIG_SPARC_LEON + #include "irq.h" extern ctxd_t *srmmu_ctx_table_phys; static int smp_processors_ready; extern volatile unsigned long cpu_callin_map[NR_CPUS]; extern cpumask_t smp_commenced_mask; -void __cpuinit leon_configure_cache_smp(void); +void __init leon_configure_cache_smp(void); static void leon_ipi_init(void); /* IRQ number of LEON IPIs */ @@ -121,7 +123,7 @@ void __cpuinit leon_callin(void) extern struct linux_prom_registers smp_penguin_ctable; -void __cpuinit leon_configure_cache_smp(void) +void __init leon_configure_cache_smp(void) { unsigned long cfg = sparc_leon3_get_dcachecfg(); int me = smp_processor_id(); @@ -505,3 +507,5 @@ void __init leon_init_smp(void) sparc32_ipi_ops = &leon_ipi_ops; } + +#endif /* CONFIG_SPARC_LEON */ diff --git a/trunk/arch/sparc/kernel/process_32.c b/trunk/arch/sparc/kernel/process_32.c index cb36e82dcd5d..fe6787cc62fc 100644 --- a/trunk/arch/sparc/kernel/process_32.c +++ b/trunk/arch/sparc/kernel/process_32.c @@ -65,25 +65,50 @@ extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *); struct task_struct *last_task_used_math = NULL; struct thread_info *current_set[NR_CPUS]; +#ifndef CONFIG_SMP + /* * the idle loop on a Sparc... ;) */ void cpu_idle(void) { - set_thread_flag(TIF_POLLING_NRFLAG); - /* endless idle loop with no priority at all */ for (;;) { - while (!need_resched()) { - if (pm_idle) + if (pm_idle) { + while (!need_resched()) + (*pm_idle)(); + } else { + while (!need_resched()) + cpu_relax(); + } + schedule_preempt_disabled(); + } +} + +#else + +/* This is being executed in task 0 'user space'. */ +void cpu_idle(void) +{ + set_thread_flag(TIF_POLLING_NRFLAG); + /* endless idle loop with no priority at all */ + while(1) { +#ifdef CONFIG_SPARC_LEON + if (pm_idle) { + while (!need_resched()) (*pm_idle)(); - else + } else +#endif + { + while (!need_resched()) cpu_relax(); } schedule_preempt_disabled(); } } +#endif + /* XXX cli/sti -> local_irq_xxx here, check this works once SMP is fixed. */ void machine_halt(void) { diff --git a/trunk/arch/sparc/kernel/prom_common.c b/trunk/arch/sparc/kernel/prom_common.c index 1303021748c8..741df916c124 100644 --- a/trunk/arch/sparc/kernel/prom_common.c +++ b/trunk/arch/sparc/kernel/prom_common.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "prom.h" diff --git a/trunk/arch/sparc/kernel/rtrap_32.S b/trunk/arch/sparc/kernel/rtrap_32.S index 6c34de0c2abd..7abc24e2bf1a 100644 --- a/trunk/arch/sparc/kernel/rtrap_32.S +++ b/trunk/arch/sparc/kernel/rtrap_32.S @@ -231,14 +231,11 @@ srmmu_rett_stackchk: cmp %g1, %fp bleu ret_trap_user_stack_is_bolixed mov AC_M_SFSR, %g1 -LEON_PI(lda [%g1] ASI_LEON_MMUREGS, %g0) -SUN_PI_(lda [%g1] ASI_M_MMUREGS, %g0) + lda [%g1] ASI_M_MMUREGS, %g0 -LEON_PI(lda [%g0] ASI_LEON_MMUREGS, %g1) -SUN_PI_(lda [%g0] ASI_M_MMUREGS, %g1) + lda [%g0] ASI_M_MMUREGS, %g1 or %g1, 0x2, %g1 -LEON_PI(sta %g1, [%g0] ASI_LEON_MMUREGS) -SUN_PI_(sta %g1, [%g0] ASI_M_MMUREGS) + sta %g1, [%g0] ASI_M_MMUREGS restore %g0, %g0, %g0 @@ -247,16 +244,13 @@ SUN_PI_(sta %g1, [%g0] ASI_M_MMUREGS) save %g0, %g0, %g0 andn %g1, 0x2, %g1 -LEON_PI(sta %g1, [%g0] ASI_LEON_MMUREGS) -SUN_PI_(sta %g1, [%g0] ASI_M_MMUREGS) + sta %g1, [%g0] ASI_M_MMUREGS mov AC_M_SFAR, %g2 -LEON_PI(lda [%g2] ASI_LEON_MMUREGS, %g2) -SUN_PI_(lda [%g2] ASI_M_MMUREGS, %g2) + lda [%g2] ASI_M_MMUREGS, %g2 mov AC_M_SFSR, %g1 -LEON_PI(lda [%g1] ASI_LEON_MMUREGS, %g1) -SUN_PI_(lda [%g1] ASI_M_MMUREGS, %g1) + lda [%g1] ASI_M_MMUREGS, %g1 andcc %g1, 0x2, %g0 be ret_trap_userwins_ok nop diff --git a/trunk/arch/sparc/kernel/setup_32.c b/trunk/arch/sparc/kernel/setup_32.c index efe3e64bba38..c052313f4dc5 100644 --- a/trunk/arch/sparc/kernel/setup_32.c +++ b/trunk/arch/sparc/kernel/setup_32.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include @@ -46,7 +45,6 @@ #include #include #include -#include #include "kernel.h" @@ -239,42 +237,28 @@ static void __init per_cpu_patch(void) } } -struct leon_1insn_patch_entry { - unsigned int addr; - unsigned int insn; -}; - enum sparc_cpu sparc_cpu_model; EXPORT_SYMBOL(sparc_cpu_model); -static __init void leon_patch(void) -{ - struct leon_1insn_patch_entry *start = (void *)__leon_1insn_patch; - struct leon_1insn_patch_entry *end = (void *)__leon_1insn_patch_end; +struct tt_entry *sparc_ttable; - /* Default instruction is leon - no patching */ - if (sparc_cpu_model == sparc_leon) - return; +struct pt_regs fake_swapper_regs; - while (start < end) { - unsigned long addr = start->addr; +void __init setup_arch(char **cmdline_p) +{ + int i; + unsigned long highest_paddr; - *(unsigned int *)(addr) = start->insn; - flushi(addr); + sparc_ttable = (struct tt_entry *) &trapbase; - start++; - } -} + /* Initialize PROM console and command line. */ + *cmdline_p = prom_getbootargs(); + strcpy(boot_command_line, *cmdline_p); + parse_early_param(); -struct tt_entry *sparc_ttable; -struct pt_regs fake_swapper_regs; + boot_flags_init(*cmdline_p); -/* Called from head_32.S - before we have setup anything - * in the kernel. Be very careful with what you do here. - */ -void __init sparc32_start_kernel(struct linux_romvec *rp) -{ - prom_init(rp); + register_console(&prom_early_console); /* Set sparc_cpu_model */ sparc_cpu_model = sun_unknown; @@ -291,26 +275,6 @@ void __init sparc32_start_kernel(struct linux_romvec *rp) if (!strncmp(&cputypval[0], "leon" , 4)) sparc_cpu_model = sparc_leon; - leon_patch(); - start_kernel(); -} - -void __init setup_arch(char **cmdline_p) -{ - int i; - unsigned long highest_paddr; - - sparc_ttable = (struct tt_entry *) &trapbase; - - /* Initialize PROM console and command line. */ - *cmdline_p = prom_getbootargs(); - strcpy(boot_command_line, *cmdline_p); - parse_early_param(); - - boot_flags_init(*cmdline_p); - - register_console(&prom_early_console); - printk("ARCH: "); switch(sparc_cpu_model) { case sun4m: diff --git a/trunk/arch/sparc/kernel/signal32.c b/trunk/arch/sparc/kernel/signal32.c index a53e0a5fd3a3..bb1513e45f1a 100644 --- a/trunk/arch/sparc/kernel/signal32.c +++ b/trunk/arch/sparc/kernel/signal32.c @@ -32,6 +32,8 @@ #include "sigutil.h" +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + /* This magic should be in g_upper[0] for all upper parts * to be valid. */ @@ -272,6 +274,7 @@ void do_sigreturn32(struct pt_regs *regs) case 2: set.sig[1] = seta[2] + (((long)seta[3]) << 32); case 1: set.sig[0] = seta[0] + (((long)seta[1]) << 32); } + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); return; @@ -373,6 +376,7 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) case 2: set.sig[1] = seta.sig[2] + (((long)seta.sig[3]) << 32); case 1: set.sig[0] = seta.sig[0] + (((long)seta.sig[1]) << 32); } + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); return; segv: @@ -771,7 +775,7 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs, return -EFAULT; } -static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka, +static inline int handle_signal32(unsigned long signr, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) { @@ -783,9 +787,12 @@ static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka, err = setup_frame32(ka, regs, signr, oldset); if (err) - return; + return err; + + block_sigmask(ka, signr); + tracehook_signal_handler(signr, info, ka, regs, 0); - signal_delivered(signr, info, ka, regs, 0); + return 0; } static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs, @@ -834,7 +841,14 @@ void do_signal32(sigset_t *oldset, struct pt_regs * regs) if (signr > 0) { if (restart_syscall) syscall_restart32(orig_i0, regs, &ka.sa); - handle_signal32(signr, &ka, &info, oldset, regs); + if (handle_signal32(signr, &ka, &info, oldset, regs) == 0) { + /* A signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TS_RESTORE_SIGMASK flag. + */ + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; + } return; } if (restart_syscall && @@ -858,7 +872,10 @@ void do_signal32(sigset_t *oldset, struct pt_regs * regs) /* If there's no signal to deliver, we just put the saved sigmask * back */ - restore_saved_sigmask(); + if (current_thread_info()->status & TS_RESTORE_SIGMASK) { + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; + set_current_blocked(¤t->saved_sigmask); + } } struct sigstack32 { diff --git a/trunk/arch/sparc/kernel/signal_32.c b/trunk/arch/sparc/kernel/signal_32.c index 68f9c8650af4..2b7e849f7c65 100644 --- a/trunk/arch/sparc/kernel/signal_32.c +++ b/trunk/arch/sparc/kernel/signal_32.c @@ -29,6 +29,8 @@ #include "sigutil.h" +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + extern void fpsave(unsigned long *fpregs, unsigned long *fsr, void *fpqueue, unsigned long *fpqdepth); extern void fpload(unsigned long *fpregs, unsigned long *fsr); @@ -128,6 +130,7 @@ asmlinkage void do_sigreturn(struct pt_regs *regs) if (err) goto segv_and_exit; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); return; @@ -194,6 +197,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs) goto segv; } + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); return; segv: @@ -445,11 +449,10 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, return -EFAULT; } -static inline void +static inline int handle_signal(unsigned long signr, struct k_sigaction *ka, - siginfo_t *info, struct pt_regs *regs) + siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) { - sigset_t *oldset = sigmask_to_save(); int err; if (ka->sa.sa_flags & SA_SIGINFO) @@ -458,9 +461,12 @@ handle_signal(unsigned long signr, struct k_sigaction *ka, err = setup_frame(ka, regs, signr, oldset); if (err) - return; + return err; - signal_delivered(signr, info, ka, regs, 0); + block_sigmask(ka, signr); + tracehook_signal_handler(signr, info, ka, regs, 0); + + return 0; } static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, @@ -492,6 +498,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) { struct k_sigaction ka; int restart_syscall; + sigset_t *oldset; siginfo_t info; int signr; @@ -516,6 +523,11 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) regs->u_regs[UREG_G6] = orig_i0; + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); /* If the debugger messes with the program counter, it clears @@ -532,7 +544,15 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) if (signr > 0) { if (restart_syscall) syscall_restart(orig_i0, regs, &ka.sa); - handle_signal(signr, &ka, &info, regs); + if (handle_signal(signr, &ka, &info, oldset, regs) == 0) { + /* a signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TIF_RESTORE_SIGMASK flag. + */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + } return; } if (restart_syscall && @@ -556,17 +576,22 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) /* if there's no signal to deliver, we just put the saved sigmask * back */ - restore_saved_sigmask(); + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + set_current_blocked(¤t->saved_sigmask); + } } void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long thread_info_flags) { - if (thread_info_flags & _TIF_SIGPENDING) + if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) do_signal(regs, orig_i0); if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/trunk/arch/sparc/kernel/signal_64.c b/trunk/arch/sparc/kernel/signal_64.c index 867de2f8189c..eafaab486b2d 100644 --- a/trunk/arch/sparc/kernel/signal_64.c +++ b/trunk/arch/sparc/kernel/signal_64.c @@ -38,6 +38,8 @@ #include "systbls.h" #include "sigutil.h" +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + /* {set, get}context() needed for 64-bit SparcLinux userland. */ asmlinkage void sparc64_set_context(struct pt_regs *regs) { @@ -69,6 +71,7 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs) if (__copy_from_user(&set, &ucp->uc_sigmask, sizeof(sigset_t))) goto do_sigsegv; } + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); } if (test_thread_flag(TIF_32BIT)) { @@ -312,6 +315,7 @@ void do_rt_sigreturn(struct pt_regs *regs) /* Prevent syscall restart. */ pt_regs_clear_syscall(regs); + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); return; segv: @@ -462,7 +466,7 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, return -EFAULT; } -static inline void handle_signal(unsigned long signr, struct k_sigaction *ka, +static inline int handle_signal(unsigned long signr, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) { @@ -471,9 +475,12 @@ static inline void handle_signal(unsigned long signr, struct k_sigaction *ka, err = setup_rt_frame(ka, regs, signr, oldset, (ka->sa.sa_flags & SA_SIGINFO) ? info : NULL); if (err) - return; + return err; - signal_delivered(signr, info, ka, regs, 0); + block_sigmask(ka, signr); + tracehook_signal_handler(signr, info, ka, regs, 0); + + return 0; } static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, @@ -505,7 +512,7 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) { struct k_sigaction ka; int restart_syscall; - sigset_t *oldset = sigmask_to_save(); + sigset_t *oldset; siginfo_t info; int signr; @@ -531,6 +538,11 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) regs->u_regs[UREG_G6] = orig_i0; + if (current_thread_info()->status & TS_RESTORE_SIGMASK) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + #ifdef CONFIG_COMPAT if (test_thread_flag(TIF_32BIT)) { extern void do_signal32(sigset_t *, struct pt_regs *); @@ -551,7 +563,14 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) if (signr > 0) { if (restart_syscall) syscall_restart(orig_i0, regs, &ka.sa); - handle_signal(signr, &ka, &info, oldset, regs); + if (handle_signal(signr, &ka, &info, oldset, regs) == 0) { + /* A signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TS_RESTORE_SIGMASK flag. + */ + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; + } return; } if (restart_syscall && @@ -575,7 +594,10 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) /* If there's no signal to deliver, we just put the saved sigmask * back */ - restore_saved_sigmask(); + if (current_thread_info()->status & TS_RESTORE_SIGMASK) { + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; + set_current_blocked(¤t->saved_sigmask); + } } void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long thread_info_flags) @@ -585,6 +607,8 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/trunk/arch/sparc/kernel/sys_sparc_64.c b/trunk/arch/sparc/kernel/sys_sparc_64.c index 275f74fd6f6a..3ee51f189a55 100644 --- a/trunk/arch/sparc/kernel/sys_sparc_64.c +++ b/trunk/arch/sparc/kernel/sys_sparc_64.c @@ -580,9 +580,16 @@ SYSCALL_DEFINE5(64_mremap, unsigned long, addr, unsigned long, old_len, unsigned long, new_len, unsigned long, flags, unsigned long, new_addr) { + unsigned long ret = -EINVAL; + if (test_thread_flag(TIF_32BIT)) - return -EINVAL; - return sys_mremap(addr, old_len, new_len, flags, new_addr); + goto out; + + down_write(¤t->mm->mmap_sem); + ret = do_mremap(addr, old_len, new_len, flags, new_addr); + up_write(¤t->mm->mmap_sem); +out: + return ret; } /* we come to here via sys_nis_syscall so it can setup the regs argument */ diff --git a/trunk/arch/sparc/kernel/trampoline_32.S b/trunk/arch/sparc/kernel/trampoline_32.S index af27acab4486..7364ddc9e5aa 100644 --- a/trunk/arch/sparc/kernel/trampoline_32.S +++ b/trunk/arch/sparc/kernel/trampoline_32.S @@ -149,6 +149,8 @@ sun4d_cpu_startup: b,a smp_do_cpu_idle +#ifdef CONFIG_SPARC_LEON + __CPUINIT .align 4 .global leon_smp_cpu_startup, smp_penguin_ctable @@ -159,7 +161,7 @@ leon_smp_cpu_startup: ld [%g1+4],%g1 srl %g1,4,%g1 set 0x00000100,%g5 /* SRMMU_CTXTBL_PTR */ - sta %g1, [%g5] ASI_LEON_MMUREGS + sta %g1, [%g5] ASI_M_MMUREGS /* Set up a sane %psr -- PIL<0xf> S<0x1> PS<0x1> CWP<0x0> */ set (PSR_PIL | PSR_S | PSR_PS), %g1 @@ -205,3 +207,5 @@ leon_smp_cpu_startup: nop b,a smp_do_cpu_idle + +#endif diff --git a/trunk/arch/sparc/kernel/traps_64.c b/trunk/arch/sparc/kernel/traps_64.c index 3b05e6697710..c72fdf55e1c1 100644 --- a/trunk/arch/sparc/kernel/traps_64.c +++ b/trunk/arch/sparc/kernel/traps_64.c @@ -2054,7 +2054,7 @@ void do_fpieee(struct pt_regs *regs) do_fpe_common(regs); } -extern int do_mathemu(struct pt_regs *, struct fpustate *, bool); +extern int do_mathemu(struct pt_regs *, struct fpustate *); void do_fpother(struct pt_regs *regs) { @@ -2068,7 +2068,7 @@ void do_fpother(struct pt_regs *regs) switch ((current_thread_info()->xfsr[0] & 0x1c000)) { case (2 << 14): /* unfinished_FPop */ case (3 << 14): /* unimplemented_FPop */ - ret = do_mathemu(regs, f, false); + ret = do_mathemu(regs, f); break; } if (ret) @@ -2308,12 +2308,10 @@ void do_illegal_instruction(struct pt_regs *regs) } else { struct fpustate *f = FPUSTATE; - /* On UltraSPARC T2 and later, FPU insns which - * are not implemented in HW signal an illegal - * instruction trap and do not set the FP Trap - * Trap in the %fsr to unimplemented_FPop. + /* XXX maybe verify XFSR bits like + * XXX do_fpother() does? */ - if (do_mathemu(regs, f, true)) + if (do_mathemu(regs, f)) return; } } diff --git a/trunk/arch/sparc/kernel/vmlinux.lds.S b/trunk/arch/sparc/kernel/vmlinux.lds.S index 89c2c29f154b..0e1605697b49 100644 --- a/trunk/arch/sparc/kernel/vmlinux.lds.S +++ b/trunk/arch/sparc/kernel/vmlinux.lds.S @@ -107,11 +107,6 @@ SECTIONS *(.sun4v_2insn_patch) __sun4v_2insn_patch_end = .; } - .leon_1insn_patch : { - __leon_1insn_patch = .; - *(.leon_1insn_patch) - __leon_1insn_patch_end = .; - } .swapper_tsb_phys_patch : { __swapper_tsb_phys_patch = .; *(.swapper_tsb_phys_patch) diff --git a/trunk/arch/sparc/kernel/wof.S b/trunk/arch/sparc/kernel/wof.S index 28a7bc69f82b..4c2de3cf309b 100644 --- a/trunk/arch/sparc/kernel/wof.S +++ b/trunk/arch/sparc/kernel/wof.S @@ -332,30 +332,24 @@ spwin_srmmu_stackchk: mov AC_M_SFSR, %glob_tmp /* Clear the fault status and turn on the no_fault bit. */ -LEON_PI(lda [%glob_tmp] ASI_LEON_MMUREGS, %g0) ! eat SFSR -SUN_PI_(lda [%glob_tmp] ASI_M_MMUREGS, %g0) ! eat SFSR + lda [%glob_tmp] ASI_M_MMUREGS, %g0 ! eat SFSR -LEON_PI(lda [%g0] ASI_LEON_MMUREGS, %glob_tmp) ! read MMU control -SUN_PI_(lda [%g0] ASI_M_MMUREGS, %glob_tmp) ! read MMU control + lda [%g0] ASI_M_MMUREGS, %glob_tmp ! read MMU control or %glob_tmp, 0x2, %glob_tmp ! or in no_fault bit -LEON_PI(sta %glob_tmp, [%g0] ASI_LEON_MMUREGS) ! set it -SUN_PI_(sta %glob_tmp, [%g0] ASI_M_MMUREGS) ! set it + sta %glob_tmp, [%g0] ASI_M_MMUREGS ! set it /* Dump the registers and cross fingers. */ STORE_WINDOW(sp) /* Clear the no_fault bit and check the status. */ andn %glob_tmp, 0x2, %glob_tmp -LEON_PI(sta %glob_tmp, [%g0] ASI_LEON_MMUREGS) -SUN_PI_(sta %glob_tmp, [%g0] ASI_M_MMUREGS) + sta %glob_tmp, [%g0] ASI_M_MMUREGS mov AC_M_SFAR, %glob_tmp -LEON_PI(lda [%glob_tmp] ASI_LEON_MMUREGS, %g0) -SUN_PI_(lda [%glob_tmp] ASI_M_MMUREGS, %g0) + lda [%glob_tmp] ASI_M_MMUREGS, %g0 mov AC_M_SFSR, %glob_tmp -LEON_PI(lda [%glob_tmp] ASI_LEON_MMUREGS, %glob_tmp) -SUN_PI_(lda [%glob_tmp] ASI_M_MMUREGS, %glob_tmp) + lda [%glob_tmp] ASI_M_MMUREGS, %glob_tmp andcc %glob_tmp, 0x2, %g0 ! did we fault? be,a spwin_finish_up + 0x4 ! cool beans, success restore %g0, %g0, %g0 diff --git a/trunk/arch/sparc/kernel/wuf.S b/trunk/arch/sparc/kernel/wuf.S index 2c21cc59683e..9fde91a249e0 100644 --- a/trunk/arch/sparc/kernel/wuf.S +++ b/trunk/arch/sparc/kernel/wuf.S @@ -254,19 +254,16 @@ srmmu_fwin_stackchk: mov AC_M_SFSR, %l4 cmp %l5, %sp bleu fwin_user_stack_is_bolixed -LEON_PI( lda [%l4] ASI_LEON_MMUREGS, %g0) ! clear fault status -SUN_PI_( lda [%l4] ASI_M_MMUREGS, %g0) ! clear fault status + lda [%l4] ASI_M_MMUREGS, %g0 ! clear fault status /* The technique is, turn off faults on this processor, * just let the load rip, then check the sfsr to see if * a fault did occur. Then we turn on fault traps again * and branch conditionally based upon what happened. */ -LEON_PI(lda [%g0] ASI_LEON_MMUREGS, %l5) ! read mmu-ctrl reg -SUN_PI_(lda [%g0] ASI_M_MMUREGS, %l5) ! read mmu-ctrl reg + lda [%g0] ASI_M_MMUREGS, %l5 ! read mmu-ctrl reg or %l5, 0x2, %l5 ! turn on no-fault bit -LEON_PI(sta %l5, [%g0] ASI_LEON_MMUREGS) ! store it -SUN_PI_(sta %l5, [%g0] ASI_M_MMUREGS) ! store it + sta %l5, [%g0] ASI_M_MMUREGS ! store it /* Cross fingers and go for it. */ LOAD_WINDOW(sp) @@ -278,22 +275,18 @@ SUN_PI_(sta %l5, [%g0] ASI_M_MMUREGS) ! store it /* LOCATION: Window 'T' */ -LEON_PI(lda [%g0] ASI_LEON_MMUREGS, %twin_tmp1) ! load mmu-ctrl again -SUN_PI_(lda [%g0] ASI_M_MMUREGS, %twin_tmp1) ! load mmu-ctrl again - andn %twin_tmp1, 0x2, %twin_tmp1 ! clear no-fault bit -LEON_PI(sta %twin_tmp1, [%g0] ASI_LEON_MMUREGS) ! store it -SUN_PI_(sta %twin_tmp1, [%g0] ASI_M_MMUREGS) ! store it + lda [%g0] ASI_M_MMUREGS, %twin_tmp1 ! load mmu-ctrl again + andn %twin_tmp1, 0x2, %twin_tmp1 ! clear no-fault bit + sta %twin_tmp1, [%g0] ASI_M_MMUREGS ! store it mov AC_M_SFAR, %twin_tmp2 -LEON_PI(lda [%twin_tmp2] ASI_LEON_MMUREGS, %g0) ! read fault address -SUN_PI_(lda [%twin_tmp2] ASI_M_MMUREGS, %g0) ! read fault address + lda [%twin_tmp2] ASI_M_MMUREGS, %g0 ! read fault address mov AC_M_SFSR, %twin_tmp2 -LEON_PI(lda [%twin_tmp2] ASI_LEON_MMUREGS, %twin_tmp2) ! read fault status -SUN_PI_(lda [%twin_tmp2] ASI_M_MMUREGS, %twin_tmp2) ! read fault status - andcc %twin_tmp2, 0x2, %g0 ! did fault occur? + lda [%twin_tmp2] ASI_M_MMUREGS, %twin_tmp2 ! read fault status + andcc %twin_tmp2, 0x2, %g0 ! did fault occur? - bne 1f ! yep, cleanup + bne 1f ! yep, cleanup nop wr %t_psr, 0x0, %psr diff --git a/trunk/arch/sparc/math-emu/math_64.c b/trunk/arch/sparc/math-emu/math_64.c index 1704068da928..2bbe2f28ad23 100644 --- a/trunk/arch/sparc/math-emu/math_64.c +++ b/trunk/arch/sparc/math-emu/math_64.c @@ -163,7 +163,7 @@ typedef union { u64 q[2]; } *argp; -int do_mathemu(struct pt_regs *regs, struct fpustate *f, bool illegal_insn_trap) +int do_mathemu(struct pt_regs *regs, struct fpustate *f) { unsigned long pc = regs->tpc; unsigned long tstate = regs->tstate; @@ -218,7 +218,7 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f, bool illegal_insn_trap) case FSQRTS: { unsigned long x = current_thread_info()->xfsr[0]; - x = (x >> 14) & 0x7; + x = (x >> 14) & 0xf; TYPE(x,1,1,1,1,0,0); break; } @@ -226,7 +226,7 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f, bool illegal_insn_trap) case FSQRTD: { unsigned long x = current_thread_info()->xfsr[0]; - x = (x >> 14) & 0x7; + x = (x >> 14) & 0xf; TYPE(x,2,1,2,1,0,0); break; } @@ -357,17 +357,9 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f, bool illegal_insn_trap) if (type) { argp rs1 = NULL, rs2 = NULL, rd = NULL; - /* Starting with UltraSPARC-T2, the cpu does not set the FP Trap - * Type field in the %fsr to unimplemented_FPop. Nor does it - * use the fp_exception_other trap. Instead it signals an - * illegal instruction and leaves the FP trap type field of - * the %fsr unchanged. - */ - if (!illegal_insn_trap) { - int ftt = (current_thread_info()->xfsr[0] >> 14) & 0x7; - if (ftt != (type >> 9)) - goto err; - } + freg = (current_thread_info()->xfsr[0] >> 14) & 0xf; + if (freg != (type >> 9)) + goto err; current_thread_info()->xfsr[0] &= ~0x1c000; freg = ((insn >> 14) & 0x1f); switch (type & 0x3) { diff --git a/trunk/arch/sparc/mm/Makefile b/trunk/arch/sparc/mm/Makefile index 30c3eccfdf5a..69ffd3112fed 100644 --- a/trunk/arch/sparc/mm/Makefile +++ b/trunk/arch/sparc/mm/Makefile @@ -8,9 +8,8 @@ obj-$(CONFIG_SPARC64) += ultra.o tlb.o tsb.o gup.o obj-y += fault_$(BITS).o obj-y += init_$(BITS).o obj-$(CONFIG_SPARC32) += extable.o srmmu.o iommu.o io-unit.o -obj-$(CONFIG_SPARC32) += srmmu_access.o obj-$(CONFIG_SPARC32) += hypersparc.o viking.o tsunami.o swift.o -obj-$(CONFIG_SPARC32) += leon_mm.o +obj-$(CONFIG_SPARC_LEON)+= leon_mm.o # Only used by sparc64 obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o diff --git a/trunk/arch/sparc/mm/leon_mm.c b/trunk/arch/sparc/mm/leon_mm.c index 5bed085a2c17..4c67ae6e5023 100644 --- a/trunk/arch/sparc/mm/leon_mm.c +++ b/trunk/arch/sparc/mm/leon_mm.c @@ -32,7 +32,7 @@ static inline unsigned long leon_get_ctable_ptr(void) } -unsigned long leon_swprobe(unsigned long vaddr, unsigned long *paddr) +unsigned long srmmu_swprobe(unsigned long vaddr, unsigned long *paddr) { unsigned int ctxtbl; diff --git a/trunk/arch/sparc/mm/srmmu.c b/trunk/arch/sparc/mm/srmmu.c index 62e3f5773303..256db6b22c54 100644 --- a/trunk/arch/sparc/mm/srmmu.c +++ b/trunk/arch/sparc/mm/srmmu.c @@ -646,23 +646,6 @@ static void __init srmmu_allocate_ptable_skeleton(unsigned long start, } } -/* These flush types are not available on all chips... */ -static inline unsigned long srmmu_probe(unsigned long vaddr) -{ - unsigned long retval; - - if (sparc_cpu_model != sparc_leon) { - - vaddr &= PAGE_MASK; - __asm__ __volatile__("lda [%1] %2, %0\n\t" : - "=r" (retval) : - "r" (vaddr | 0x400), "i" (ASI_M_FLUSH_PROBE)); - } else { - retval = leon_swprobe(vaddr, 0); - } - return retval; -} - /* * This is much cleaner than poking around physical address space * looking at the prom's page table directly which is what most @@ -682,7 +665,7 @@ static void __init srmmu_inherit_prom_mappings(unsigned long start, break; /* probably wrap around */ if(start == 0xfef00000) start = KADB_DEBUGGER_BEGVM; - if(!(prompte = srmmu_probe(start))) { + if(!(prompte = srmmu_hwprobe(start))) { start += PAGE_SIZE; continue; } @@ -691,12 +674,12 @@ static void __init srmmu_inherit_prom_mappings(unsigned long start, what = 0; if(!(start & ~(SRMMU_REAL_PMD_MASK))) { - if(srmmu_probe((start-PAGE_SIZE) + SRMMU_REAL_PMD_SIZE) == prompte) + if(srmmu_hwprobe((start-PAGE_SIZE) + SRMMU_REAL_PMD_SIZE) == prompte) what = 1; } if(!(start & ~(SRMMU_PGDIR_MASK))) { - if(srmmu_probe((start-PAGE_SIZE) + SRMMU_PGDIR_SIZE) == + if(srmmu_hwprobe((start-PAGE_SIZE) + SRMMU_PGDIR_SIZE) == prompte) what = 2; } @@ -1173,7 +1156,7 @@ static void turbosparc_flush_page_to_ram(unsigned long page) #ifdef TURBOSPARC_WRITEBACK volatile unsigned long clear; - if (srmmu_probe(page)) + if (srmmu_hwprobe(page)) turbosparc_flush_page_cache(page); clear = srmmu_get_fstatus(); #endif diff --git a/trunk/arch/sparc/mm/srmmu_access.S b/trunk/arch/sparc/mm/srmmu_access.S deleted file mode 100644 index d0a67b2c2383..000000000000 --- a/trunk/arch/sparc/mm/srmmu_access.S +++ /dev/null @@ -1,82 +0,0 @@ -/* Assembler variants of srmmu access functions. - * Implemented in assembler to allow run-time patching. - * LEON uses a different ASI for MMUREGS than SUN. - * - * The leon_1insn_patch infrastructure is used - * for the run-time patching. - */ - -#include - -#include -#include -#include - -/* unsigned int srmmu_get_mmureg(void) */ -ENTRY(srmmu_get_mmureg) -LEON_PI(lda [%g0] ASI_LEON_MMUREGS, %o0) -SUN_PI_(lda [%g0] ASI_M_MMUREGS, %o0) - retl - nop -ENDPROC(srmmu_get_mmureg) - -/* void srmmu_set_mmureg(unsigned long regval) */ -ENTRY(srmmu_set_mmureg) -LEON_PI(sta %o0, [%g0] ASI_LEON_MMUREGS) -SUN_PI_(sta %o0, [%g0] ASI_M_MMUREGS) - retl - nop -ENDPROC(srmmu_set_mmureg) - -/* void srmmu_set_ctable_ptr(unsigned long paddr) */ -ENTRY(srmmu_set_ctable_ptr) - /* paddr = ((paddr >> 4) & SRMMU_CTX_PMASK); */ - srl %o0, 4, %g1 - and %g1, SRMMU_CTX_PMASK, %g1 - - mov SRMMU_CTXTBL_PTR, %g2 -LEON_PI(sta %g1, [%g2] ASI_LEON_MMUREGS) -SUN_PI_(sta %g1, [%g2] ASI_M_MMUREGS) - retl - nop -ENDPROC(srmmu_set_ctable_ptr) - - -/* void srmmu_set_context(int context) */ -ENTRY(srmmu_set_context) - mov SRMMU_CTX_REG, %g1 -LEON_PI(sta %o0, [%g1] ASI_LEON_MMUREGS) -SUN_PI_(sta %o0, [%g1] ASI_M_MMUREGS) - retl - nop -ENDPROC(srmmu_set_context) - - -/* int srmmu_get_context(void) */ -ENTRY(srmmu_get_context) - mov SRMMU_CTX_REG, %o0 -LEON_PI(lda [%o0] ASI_LEON_MMUREGS, %o0) -SUN_PI_(lda [%o0] ASI_M_MMUREGS, %o0) - retl - nop -ENDPROC(srmmu_get_context) - - -/* unsigned int srmmu_get_fstatus(void) */ -ENTRY(srmmu_get_fstatus) - mov SRMMU_FAULT_STATUS, %o0 -LEON_PI(lda [%o0] ASI_LEON_MMUREGS, %o0) -SUN_PI_(lda [%o0] ASI_M_MMUREGS, %o0) - retl - nop -ENDPROC(srmmu_get_fstatus) - - -/* unsigned int srmmu_get_faddr(void) */ -ENTRY(srmmu_get_faddr) - mov SRMMU_FAULT_ADDR, %o0 -LEON_PI(lda [%o0] ASI_LEON_MMUREGS, %o0) -SUN_PI_(lda [%o0] ASI_M_MMUREGS, %o0) - retl - nop -ENDPROC(srmmu_get_faddr) diff --git a/trunk/arch/tile/include/asm/compat.h b/trunk/arch/tile/include/asm/compat.h index 6e74450ff0a1..69adc08d36a5 100644 --- a/trunk/arch/tile/include/asm/compat.h +++ b/trunk/arch/tile/include/asm/compat.h @@ -44,6 +44,7 @@ typedef __kernel_uid32_t __compat_gid32_t; typedef __kernel_mode_t compat_mode_t; typedef __kernel_dev_t compat_dev_t; typedef __kernel_loff_t compat_loff_t; +typedef __kernel_nlink_t compat_nlink_t; typedef __kernel_ipc_pid_t compat_ipc_pid_t; typedef __kernel_daddr_t compat_daddr_t; typedef __kernel_fsid_t compat_fsid_t; diff --git a/trunk/arch/tile/include/asm/thread_info.h b/trunk/arch/tile/include/asm/thread_info.h index 7e1fef36bde6..656c486e64fa 100644 --- a/trunk/arch/tile/include/asm/thread_info.h +++ b/trunk/arch/tile/include/asm/thread_info.h @@ -166,23 +166,7 @@ static inline void set_restore_sigmask(void) { struct thread_info *ti = current_thread_info(); ti->status |= TS_RESTORE_SIGMASK; - WARN_ON(!test_bit(TIF_SIGPENDING, &ti->flags)); -} -static inline void clear_restore_sigmask(void) -{ - current_thread_info()->status &= ~TS_RESTORE_SIGMASK; -} -static inline bool test_restore_sigmask(void) -{ - return current_thread_info()->status & TS_RESTORE_SIGMASK; -} -static inline bool test_and_clear_restore_sigmask(void) -{ - struct thread_info *ti = current_thread_info(); - if (!(ti->status & TS_RESTORE_SIGMASK)) - return false; - ti->status &= ~TS_RESTORE_SIGMASK; - return true; + set_bit(TIF_SIGPENDING, &ti->flags); } #endif /* !__ASSEMBLY__ */ diff --git a/trunk/arch/tile/kernel/compat_signal.c b/trunk/arch/tile/kernel/compat_signal.c index 474571b84085..cdef6e5ec022 100644 --- a/trunk/arch/tile/kernel/compat_signal.c +++ b/trunk/arch/tile/kernel/compat_signal.c @@ -118,6 +118,8 @@ struct compat_rt_sigframe { struct compat_ucontext uc; }; +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + long compat_sys_rt_sigaction(int sig, struct compat_sigaction __user *act, struct compat_sigaction __user *oact, size_t sigsetsize) @@ -300,6 +302,7 @@ long compat_sys_rt_sigreturn(struct pt_regs *regs) if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) diff --git a/trunk/arch/tile/kernel/process.c b/trunk/arch/tile/kernel/process.c index 6be799150501..ba1023d8a021 100644 --- a/trunk/arch/tile/kernel/process.c +++ b/trunk/arch/tile/kernel/process.c @@ -565,6 +565,8 @@ int do_work_pending(struct pt_regs *regs, u32 thread_info_flags) if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); return 1; } if (thread_info_flags & _TIF_SINGLESTEP) { diff --git a/trunk/arch/tile/kernel/signal.c b/trunk/arch/tile/kernel/signal.c index e29b0553211d..f79d4b88c747 100644 --- a/trunk/arch/tile/kernel/signal.c +++ b/trunk/arch/tile/kernel/signal.c @@ -37,6 +37,8 @@ #define DEBUG_SIG 0 +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + SYSCALL_DEFINE3(sigaltstack, const stack_t __user *, uss, stack_t __user *, uoss, struct pt_regs *, regs) { @@ -94,6 +96,7 @@ SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs) if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) @@ -239,11 +242,10 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, * OK, we're invoking a handler */ -static void handle_signal(unsigned long sig, siginfo_t *info, - struct k_sigaction *ka, +static int handle_signal(unsigned long sig, siginfo_t *info, + struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs) { - sigset_t *oldset = sigmask_to_save(); int ret; /* Are we from a system call? */ @@ -276,9 +278,15 @@ static void handle_signal(unsigned long sig, siginfo_t *info, else #endif ret = setup_rt_frame(sig, ka, info, oldset, regs); - if (ret) - return; - signal_delivered(sig, info, ka, regs, 0); + if (ret == 0) { + /* This code is only called from system calls or from + * the work_pending path in the return-to-user code, and + * either way we can re-enable interrupts unconditionally. + */ + block_sigmask(ka, sig); + } + + return ret; } /* @@ -291,6 +299,7 @@ void do_signal(struct pt_regs *regs) siginfo_t info; int signr; struct k_sigaction ka; + sigset_t *oldset; /* * i386 will check if we're coming from kernel mode and bail out @@ -299,10 +308,24 @@ void do_signal(struct pt_regs *regs) * helpful, we can reinstate the check on "!user_mode(regs)". */ + if (current_thread_info()->status & TS_RESTORE_SIGMASK) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { /* Whee! Actually deliver the signal. */ - handle_signal(signr, &info, &ka, regs); + if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { + /* + * A signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TS_RESTORE_SIGMASK flag. + */ + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; + } + goto done; } @@ -327,7 +350,10 @@ void do_signal(struct pt_regs *regs) } /* If there's no signal to deliver, just put the saved sigmask back. */ - restore_saved_sigmask(); + if (current_thread_info()->status & TS_RESTORE_SIGMASK) { + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } done: /* Avoid double syscall restart if there are nested signals. */ diff --git a/trunk/arch/um/include/shared/frame_kern.h b/trunk/arch/um/include/shared/frame_kern.h index e584e40ee832..76078490c258 100644 --- a/trunk/arch/um/include/shared/frame_kern.h +++ b/trunk/arch/um/include/shared/frame_kern.h @@ -6,6 +6,9 @@ #ifndef __FRAME_KERN_H_ #define __FRAME_KERN_H_ +#define _S(nr) (1<<((nr)-1)) +#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) + extern int setup_signal_stack_sc(unsigned long stack_top, int sig, struct k_sigaction *ka, struct pt_regs *regs, diff --git a/trunk/arch/um/kernel/process.c b/trunk/arch/um/kernel/process.c index ccb9a9d283f1..3a2235e0abc3 100644 --- a/trunk/arch/um/kernel/process.c +++ b/trunk/arch/um/kernel/process.c @@ -117,8 +117,11 @@ void interrupt_end(void) schedule(); if (test_thread_flag(TIF_SIGPENDING)) do_signal(); - if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) + if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) { tracehook_notify_resume(¤t->thread.regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); + } } void exit_thread(void) diff --git a/trunk/arch/um/kernel/signal.c b/trunk/arch/um/kernel/signal.c index 7362d58efc29..292e706016c5 100644 --- a/trunk/arch/um/kernel/signal.c +++ b/trunk/arch/um/kernel/signal.c @@ -15,13 +15,17 @@ EXPORT_SYMBOL(block_signals); EXPORT_SYMBOL(unblock_signals); +#define _S(nr) (1<<((nr)-1)) + +#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) + /* * OK, we're invoking a handler */ -static void handle_signal(struct pt_regs *regs, unsigned long signr, - struct k_sigaction *ka, siginfo_t *info) +static int handle_signal(struct pt_regs *regs, unsigned long signr, + struct k_sigaction *ka, siginfo_t *info, + sigset_t *oldset) { - sigset_t *oldset = sigmask_to_save(); unsigned long sp; int err; @@ -61,7 +65,9 @@ static void handle_signal(struct pt_regs *regs, unsigned long signr, if (err) force_sigsegv(signr, current); else - signal_delivered(signr, info, ka, regs, 0); + block_sigmask(ka, signr); + + return err; } static int kern_do_signal(struct pt_regs *regs) @@ -71,9 +77,24 @@ static int kern_do_signal(struct pt_regs *regs) int sig, handled_sig = 0; while ((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0) { + sigset_t *oldset; + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; handled_sig = 1; /* Whee! Actually deliver the signal. */ - handle_signal(regs, sig, &ka_copy, &info); + if (!handle_signal(regs, sig, &ka_copy, &info, oldset)) { + /* + * a signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TIF_RESTORE_SIGMASK flag + */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + break; + } } /* Did we come from a system call? */ @@ -109,8 +130,10 @@ static int kern_do_signal(struct pt_regs *regs) * if there's no signal to deliver, we just put the saved sigmask * back */ - if (!handled_sig) - restore_saved_sigmask(); + if (!handled_sig && test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } return handled_sig; } diff --git a/trunk/arch/unicore32/kernel/signal.c b/trunk/arch/unicore32/kernel/signal.c index 8adedb37720a..7754df6ef7d4 100644 --- a/trunk/arch/unicore32/kernel/signal.c +++ b/trunk/arch/unicore32/kernel/signal.c @@ -21,6 +21,8 @@ #include #include +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + /* * For UniCore syscalls, we encode the syscall number into the instruction. */ @@ -59,8 +61,10 @@ static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf) int err; err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set)); - if (err == 0) + if (err == 0) { + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); + } err |= __get_user(regs->UCreg_00, &sf->uc.uc_mcontext.regs.UCreg_00); err |= __get_user(regs->UCreg_01, &sf->uc.uc_mcontext.regs.UCreg_01); @@ -308,12 +312,13 @@ static inline void setup_syscall_restart(struct pt_regs *regs) /* * OK, we're invoking a handler */ -static void handle_signal(unsigned long sig, struct k_sigaction *ka, - siginfo_t *info, struct pt_regs *regs, int syscall) +static int handle_signal(unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, + struct pt_regs *regs, int syscall) { struct thread_info *thread = current_thread_info(); struct task_struct *tsk = current; - sigset_t *oldset = sigmask_to_save(); + sigset_t blocked; int usig = sig; int ret; @@ -359,10 +364,15 @@ static void handle_signal(unsigned long sig, struct k_sigaction *ka, if (ret != 0) { force_sigsegv(sig, tsk); - return; + return ret; } - signal_delivered(sig, info, ka, regs, 0); + /* + * Block the signal if we were successful. + */ + block_sigmask(ka, sig); + + return 0; } /* @@ -389,12 +399,32 @@ static void do_signal(struct pt_regs *regs, int syscall) if (!user_mode(regs)) return; + if (try_to_freeze()) + goto no_signal; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { - handle_signal(signr, &ka, &info, regs, syscall); + sigset_t *oldset; + + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + if (handle_signal(signr, &ka, &info, oldset, regs, syscall) + == 0) { + /* + * A signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TIF_RESTORE_SIGMASK flag. + */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + } return; } + no_signal: /* * No signal to deliver to the process - restart the syscall. */ @@ -421,7 +451,8 @@ static void do_signal(struct pt_regs *regs, int syscall) /* If there's no signal to deliver, we just put the saved * sigmask back. */ - restore_saved_sigmask(); + if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK)) + set_current_blocked(¤t->saved_sigmask); } asmlinkage void do_notify_resume(struct pt_regs *regs, @@ -433,6 +464,8 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, if (thread_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/trunk/arch/x86/Kbuild b/trunk/arch/x86/Kbuild index e5287d8517aa..0e9dec6cadd1 100644 --- a/trunk/arch/x86/Kbuild +++ b/trunk/arch/x86/Kbuild @@ -1,3 +1,4 @@ + obj-$(CONFIG_KVM) += kvm/ # Xen paravirtualization support @@ -6,7 +7,6 @@ obj-$(CONFIG_XEN) += xen/ # lguest paravirtualization support obj-$(CONFIG_LGUEST_GUEST) += lguest/ -obj-y += realmode/ obj-y += kernel/ obj-y += mm/ diff --git a/trunk/arch/x86/ia32/ia32_signal.c b/trunk/arch/x86/ia32/ia32_signal.c index daeca56211e3..98bd70faccc5 100644 --- a/trunk/arch/x86/ia32/ia32_signal.c +++ b/trunk/arch/x86/ia32/ia32_signal.c @@ -273,6 +273,7 @@ asmlinkage long sys32_sigreturn(struct pt_regs *regs) sizeof(frame->extramask)))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (ia32_restore_sigcontext(regs, &frame->sc, &ax)) @@ -298,6 +299,7 @@ asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs) if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) diff --git a/trunk/arch/x86/include/asm/acpi.h b/trunk/arch/x86/include/asm/acpi.h index 0c44630d1789..610001d385dd 100644 --- a/trunk/arch/x86/include/asm/acpi.h +++ b/trunk/arch/x86/include/asm/acpi.h @@ -29,7 +29,7 @@ #include #include #include -#include +#include #define COMPILER_DEPENDENT_INT64 long long #define COMPILER_DEPENDENT_UINT64 unsigned long long @@ -117,8 +117,11 @@ static inline void acpi_disable_pci(void) /* Low-level suspend routine. */ extern int acpi_suspend_lowlevel(void); -/* Physical address to resume after wakeup */ -#define acpi_wakeup_address ((unsigned long)(real_mode_header->wakeup_start)) +extern const unsigned char acpi_wakeup_code[]; +#define acpi_wakeup_address (__pa(TRAMPOLINE_SYM(acpi_wakeup_code))) + +/* early initialization routine */ +extern void acpi_reserve_wakeup_memory(void); /* * Check if the CPU can handle C2 and deeper diff --git a/trunk/arch/x86/include/asm/bitops.h b/trunk/arch/x86/include/asm/bitops.h index a6983b277220..b97596e2b68c 100644 --- a/trunk/arch/x86/include/asm/bitops.h +++ b/trunk/arch/x86/include/asm/bitops.h @@ -15,8 +15,6 @@ #include #include -#define BIT_64(n) (U64_C(1) << (n)) - /* * These have to be done with inline assembly: that way the bit-setting * is guaranteed to be atomic. All bit operations return 0 if the bit diff --git a/trunk/arch/x86/include/asm/posix_types_32.h b/trunk/arch/x86/include/asm/posix_types_32.h index 8e525059e7d8..99f262e04b91 100644 --- a/trunk/arch/x86/include/asm/posix_types_32.h +++ b/trunk/arch/x86/include/asm/posix_types_32.h @@ -10,6 +10,9 @@ typedef unsigned short __kernel_mode_t; #define __kernel_mode_t __kernel_mode_t +typedef unsigned short __kernel_nlink_t; +#define __kernel_nlink_t __kernel_nlink_t + typedef unsigned short __kernel_ipc_pid_t; #define __kernel_ipc_pid_t __kernel_ipc_pid_t diff --git a/trunk/arch/x86/include/asm/processor.h b/trunk/arch/x86/include/asm/processor.h index 39bc5777211a..7745b257f035 100644 --- a/trunk/arch/x86/include/asm/processor.h +++ b/trunk/arch/x86/include/asm/processor.h @@ -544,16 +544,13 @@ static inline void load_sp0(struct tss_struct *tss, * enable), so that any CPU's that boot up * after us can get the correct flags. */ -extern unsigned long mmu_cr4_features; -extern u32 *trampoline_cr4_features; +extern unsigned long mmu_cr4_features; static inline void set_in_cr4(unsigned long mask) { unsigned long cr4; mmu_cr4_features |= mask; - if (trampoline_cr4_features) - *trampoline_cr4_features = mmu_cr4_features; cr4 = read_cr4(); cr4 |= mask; write_cr4(cr4); @@ -564,8 +561,6 @@ static inline void clear_in_cr4(unsigned long mask) unsigned long cr4; mmu_cr4_features &= ~mask; - if (trampoline_cr4_features) - *trampoline_cr4_features = mmu_cr4_features; cr4 = read_cr4(); cr4 &= ~mask; write_cr4(cr4); diff --git a/trunk/arch/x86/include/asm/realmode.h b/trunk/arch/x86/include/asm/realmode.h deleted file mode 100644 index fce3f4ae5bd6..000000000000 --- a/trunk/arch/x86/include/asm/realmode.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef _ARCH_X86_REALMODE_H -#define _ARCH_X86_REALMODE_H - -#include -#include - -/* This must match data at realmode.S */ -struct real_mode_header { - u32 text_start; - u32 ro_end; - /* SMP trampoline */ - u32 trampoline_start; - u32 trampoline_status; - u32 trampoline_header; -#ifdef CONFIG_X86_64 - u32 trampoline_pgd; -#endif - /* ACPI S3 wakeup */ -#ifdef CONFIG_ACPI_SLEEP - u32 wakeup_start; - u32 wakeup_header; -#endif - /* APM/BIOS reboot */ -#ifdef CONFIG_X86_32 - u32 machine_real_restart_asm; -#endif -}; - -/* This must match data at trampoline_32/64.S */ -struct trampoline_header { -#ifdef CONFIG_X86_32 - u32 start; - u16 gdt_pad; - u16 gdt_limit; - u32 gdt_base; -#else - u64 start; - u64 efer; - u32 cr4; -#endif -}; - -extern struct real_mode_header *real_mode_header; -extern unsigned char real_mode_blob_end[]; - -extern unsigned long init_rsp; -extern unsigned long initial_code; -extern unsigned long initial_gs; - -extern unsigned char real_mode_blob[]; -extern unsigned char real_mode_relocs[]; - -#ifdef CONFIG_X86_32 -extern unsigned char startup_32_smp[]; -extern unsigned char boot_gdt[]; -#else -extern unsigned char secondary_startup_64[]; -#endif - -extern void __init setup_real_mode(void); - -#endif /* _ARCH_X86_REALMODE_H */ diff --git a/trunk/arch/x86/include/asm/sighandling.h b/trunk/arch/x86/include/asm/sighandling.h index beff97f7df37..ada93b3b8c66 100644 --- a/trunk/arch/x86/include/asm/sighandling.h +++ b/trunk/arch/x86/include/asm/sighandling.h @@ -7,6 +7,8 @@ #include +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + #define __FIX_EFLAGS (X86_EFLAGS_AC | X86_EFLAGS_OF | \ X86_EFLAGS_DF | X86_EFLAGS_TF | X86_EFLAGS_SF | \ X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \ diff --git a/trunk/arch/x86/include/asm/thread_info.h b/trunk/arch/x86/include/asm/thread_info.h index 89f794f007ec..5c25de07cba8 100644 --- a/trunk/arch/x86/include/asm/thread_info.h +++ b/trunk/arch/x86/include/asm/thread_info.h @@ -248,23 +248,7 @@ static inline void set_restore_sigmask(void) { struct thread_info *ti = current_thread_info(); ti->status |= TS_RESTORE_SIGMASK; - WARN_ON(!test_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags)); -} -static inline void clear_restore_sigmask(void) -{ - current_thread_info()->status &= ~TS_RESTORE_SIGMASK; -} -static inline bool test_restore_sigmask(void) -{ - return current_thread_info()->status & TS_RESTORE_SIGMASK; -} -static inline bool test_and_clear_restore_sigmask(void) -{ - struct thread_info *ti = current_thread_info(); - if (!(ti->status & TS_RESTORE_SIGMASK)) - return false; - ti->status &= ~TS_RESTORE_SIGMASK; - return true; + set_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags); } static inline bool is_ia32_task(void) diff --git a/trunk/arch/x86/include/asm/trampoline.h b/trunk/arch/x86/include/asm/trampoline.h new file mode 100644 index 000000000000..feca3118a73b --- /dev/null +++ b/trunk/arch/x86/include/asm/trampoline.h @@ -0,0 +1,39 @@ +#ifndef _ASM_X86_TRAMPOLINE_H +#define _ASM_X86_TRAMPOLINE_H + +#ifndef __ASSEMBLY__ + +#include +#include + +/* + * Trampoline 80x86 program as an array. These are in the init rodata + * segment, but that's okay, because we only care about the relative + * addresses of the symbols. + */ +extern const unsigned char x86_trampoline_start []; +extern const unsigned char x86_trampoline_end []; +extern unsigned char *x86_trampoline_base; + +extern unsigned long init_rsp; +extern unsigned long initial_code; +extern unsigned long initial_gs; + +extern void __init setup_trampolines(void); + +extern const unsigned char trampoline_data[]; +extern const unsigned char trampoline_status[]; + +#define TRAMPOLINE_SYM(x) \ + ((void *)(x86_trampoline_base + \ + ((const unsigned char *)(x) - x86_trampoline_start))) + +/* Address of the SMP trampoline */ +static inline unsigned long trampoline_address(void) +{ + return virt_to_phys(TRAMPOLINE_SYM(trampoline_data)); +} + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_X86_TRAMPOLINE_H */ diff --git a/trunk/arch/x86/kernel/Makefile b/trunk/arch/x86/kernel/Makefile index 8215e5652d97..9bba5b79902b 100644 --- a/trunk/arch/x86/kernel/Makefile +++ b/trunk/arch/x86/kernel/Makefile @@ -35,6 +35,7 @@ obj-y += tsc.o io_delay.o rtc.o obj-y += pci-iommu_table.o obj-y += resource.o +obj-y += trampoline.o trampoline_$(BITS).o obj-y += process.o obj-y += i387.o xsave.o obj-y += ptrace.o @@ -47,6 +48,7 @@ obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-y += cpu/ obj-y += acpi/ obj-y += reboot.o +obj-$(CONFIG_X86_32) += reboot_32.o obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_PCI) += early-quirks.o diff --git a/trunk/arch/x86/kernel/acpi/Makefile b/trunk/arch/x86/kernel/acpi/Makefile index 163b22581472..6f35260bb3ef 100644 --- a/trunk/arch/x86/kernel/acpi/Makefile +++ b/trunk/arch/x86/kernel/acpi/Makefile @@ -1,7 +1,14 @@ +subdir- := realmode + obj-$(CONFIG_ACPI) += boot.o -obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_$(BITS).o +obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_rm.o wakeup_$(BITS).o ifneq ($(CONFIG_ACPI_PROCESSOR),) obj-y += cstate.o endif +$(obj)/wakeup_rm.o: $(obj)/realmode/wakeup.bin + +$(obj)/realmode/wakeup.bin: FORCE + $(Q)$(MAKE) $(build)=$(obj)/realmode + diff --git a/trunk/arch/x86/kernel/acpi/realmode/.gitignore b/trunk/arch/x86/kernel/acpi/realmode/.gitignore new file mode 100644 index 000000000000..58f1f48a58f8 --- /dev/null +++ b/trunk/arch/x86/kernel/acpi/realmode/.gitignore @@ -0,0 +1,3 @@ +wakeup.bin +wakeup.elf +wakeup.lds diff --git a/trunk/arch/x86/kernel/acpi/realmode/Makefile b/trunk/arch/x86/kernel/acpi/realmode/Makefile new file mode 100644 index 000000000000..6a564ac67ef5 --- /dev/null +++ b/trunk/arch/x86/kernel/acpi/realmode/Makefile @@ -0,0 +1,59 @@ +# +# arch/x86/kernel/acpi/realmode/Makefile +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# + +always := wakeup.bin +targets := wakeup.elf wakeup.lds + +wakeup-y += wakeup.o wakemain.o video-mode.o copy.o bioscall.o regs.o + +# The link order of the video-*.o modules can matter. In particular, +# video-vga.o *must* be listed first, followed by video-vesa.o. +# Hardware-specific drivers should follow in the order they should be +# probed, and video-bios.o should typically be last. +wakeup-y += video-vga.o +wakeup-y += video-vesa.o +wakeup-y += video-bios.o + +targets += $(wakeup-y) + +bootsrc := $(src)/../../../boot + +# --------------------------------------------------------------------------- + +# How to compile the 16-bit code. Note we always compile for -march=i386, +# that way we can complain to the user if the CPU is insufficient. +# Compile with _SETUP since this is similar to the boot-time setup code. +KBUILD_CFLAGS := $(LINUXINCLUDE) -g -Os -D_SETUP -D_WAKEUP -D__KERNEL__ \ + -I$(srctree)/$(bootsrc) \ + $(cflags-y) \ + -Wall -Wstrict-prototypes \ + -march=i386 -mregparm=3 \ + -include $(srctree)/$(bootsrc)/code16gcc.h \ + -fno-strict-aliasing -fomit-frame-pointer \ + $(call cc-option, -ffreestanding) \ + $(call cc-option, -fno-toplevel-reorder,\ + $(call cc-option, -fno-unit-at-a-time)) \ + $(call cc-option, -fno-stack-protector) \ + $(call cc-option, -mpreferred-stack-boundary=2) +KBUILD_CFLAGS += $(call cc-option, -m32) +KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ +GCOV_PROFILE := n + +WAKEUP_OBJS = $(addprefix $(obj)/,$(wakeup-y)) + +LDFLAGS_wakeup.elf := -T + +CPPFLAGS_wakeup.lds += -P -C + +$(obj)/wakeup.elf: $(obj)/wakeup.lds $(WAKEUP_OBJS) FORCE + $(call if_changed,ld) + +OBJCOPYFLAGS_wakeup.bin := -O binary + +$(obj)/wakeup.bin: $(obj)/wakeup.elf FORCE + $(call if_changed,objcopy) diff --git a/trunk/arch/x86/kernel/acpi/realmode/bioscall.S b/trunk/arch/x86/kernel/acpi/realmode/bioscall.S new file mode 100644 index 000000000000..f51eb0bb56ce --- /dev/null +++ b/trunk/arch/x86/kernel/acpi/realmode/bioscall.S @@ -0,0 +1 @@ +#include "../../../boot/bioscall.S" diff --git a/trunk/arch/x86/kernel/acpi/realmode/copy.S b/trunk/arch/x86/kernel/acpi/realmode/copy.S new file mode 100644 index 000000000000..dc59ebee69d8 --- /dev/null +++ b/trunk/arch/x86/kernel/acpi/realmode/copy.S @@ -0,0 +1 @@ +#include "../../../boot/copy.S" diff --git a/trunk/arch/x86/kernel/acpi/realmode/regs.c b/trunk/arch/x86/kernel/acpi/realmode/regs.c new file mode 100644 index 000000000000..6206033ba202 --- /dev/null +++ b/trunk/arch/x86/kernel/acpi/realmode/regs.c @@ -0,0 +1 @@ +#include "../../../boot/regs.c" diff --git a/trunk/arch/x86/kernel/acpi/realmode/video-bios.c b/trunk/arch/x86/kernel/acpi/realmode/video-bios.c new file mode 100644 index 000000000000..7deabc144a27 --- /dev/null +++ b/trunk/arch/x86/kernel/acpi/realmode/video-bios.c @@ -0,0 +1 @@ +#include "../../../boot/video-bios.c" diff --git a/trunk/arch/x86/kernel/acpi/realmode/video-mode.c b/trunk/arch/x86/kernel/acpi/realmode/video-mode.c new file mode 100644 index 000000000000..328ad209f113 --- /dev/null +++ b/trunk/arch/x86/kernel/acpi/realmode/video-mode.c @@ -0,0 +1 @@ +#include "../../../boot/video-mode.c" diff --git a/trunk/arch/x86/kernel/acpi/realmode/video-vesa.c b/trunk/arch/x86/kernel/acpi/realmode/video-vesa.c new file mode 100644 index 000000000000..9dbb9672226a --- /dev/null +++ b/trunk/arch/x86/kernel/acpi/realmode/video-vesa.c @@ -0,0 +1 @@ +#include "../../../boot/video-vesa.c" diff --git a/trunk/arch/x86/kernel/acpi/realmode/video-vga.c b/trunk/arch/x86/kernel/acpi/realmode/video-vga.c new file mode 100644 index 000000000000..bcc81255f374 --- /dev/null +++ b/trunk/arch/x86/kernel/acpi/realmode/video-vga.c @@ -0,0 +1 @@ +#include "../../../boot/video-vga.c" diff --git a/trunk/arch/x86/realmode/rm/wakemain.c b/trunk/arch/x86/kernel/acpi/realmode/wakemain.c similarity index 98% rename from trunk/arch/x86/realmode/rm/wakemain.c rename to trunk/arch/x86/kernel/acpi/realmode/wakemain.c index 91405d515ec6..883962d9eef2 100644 --- a/trunk/arch/x86/realmode/rm/wakemain.c +++ b/trunk/arch/x86/kernel/acpi/realmode/wakemain.c @@ -65,8 +65,7 @@ void main(void) { /* Kill machine if structures are wrong */ if (wakeup_header.real_magic != 0x12345678) - while (1) - ; + while (1); if (wakeup_header.realmode_flags & 4) send_morse("...-"); diff --git a/trunk/arch/x86/realmode/rm/wakeup_asm.S b/trunk/arch/x86/kernel/acpi/realmode/wakeup.S similarity index 54% rename from trunk/arch/x86/realmode/rm/wakeup_asm.S rename to trunk/arch/x86/kernel/acpi/realmode/wakeup.S index 8905166b0bbb..b4fd836e4053 100644 --- a/trunk/arch/x86/realmode/rm/wakeup_asm.S +++ b/trunk/arch/x86/kernel/acpi/realmode/wakeup.S @@ -1,47 +1,50 @@ /* * ACPI wakeup real mode startup stub */ -#include #include #include #include #include #include -#include "realmode.h" #include "wakeup.h" .code16 + .section ".jump", "ax" + .globl _start +_start: + cli + jmp wakeup_code /* This should match the structure in wakeup.h */ - .section ".data", "aw" - - .balign 16 -GLOBAL(wakeup_header) - video_mode: .short 0 /* Video mode number */ - pmode_entry: .long 0 - pmode_cs: .short __KERNEL_CS - pmode_cr0: .long 0 /* Saved %cr0 */ - pmode_cr3: .long 0 /* Saved %cr3 */ - pmode_cr4: .long 0 /* Saved %cr4 */ - pmode_efer: .quad 0 /* Saved EFER */ - pmode_gdt: .quad 0 - pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */ - pmode_behavior: .long 0 /* Wakeup behavior flags */ - realmode_flags: .long 0 - real_magic: .long 0 - signature: .long WAKEUP_HEADER_SIGNATURE -END(wakeup_header) + .section ".header", "a" + .globl wakeup_header +wakeup_header: +video_mode: .short 0 /* Video mode number */ +pmode_return: .byte 0x66, 0xea /* ljmpl */ + .long 0 /* offset goes here */ + .short __KERNEL_CS +pmode_cr0: .long 0 /* Saved %cr0 */ +pmode_cr3: .long 0 /* Saved %cr3 */ +pmode_cr4: .long 0 /* Saved %cr4 */ +pmode_efer: .quad 0 /* Saved EFER */ +pmode_gdt: .quad 0 +pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */ +pmode_behavior: .long 0 /* Wakeup behavior flags */ +realmode_flags: .long 0 +real_magic: .long 0 +trampoline_segment: .word 0 +_pad1: .byte 0 +wakeup_jmp: .byte 0xea /* ljmpw */ +wakeup_jmp_off: .word 3f +wakeup_jmp_seg: .word 0 +wakeup_gdt: .quad 0, 0, 0 +signature: .long WAKEUP_HEADER_SIGNATURE .text .code16 - - .balign 16 -ENTRY(wakeup_start) - cli +wakeup_code: cld - LJMPW_RM(3f) -3: /* Apparently some dimwit BIOS programmers don't know how to program a PM to RM transition, and we might end up here with junk in the data segment descriptor registers. The only way @@ -51,7 +54,8 @@ ENTRY(wakeup_start) movl %cr0, %eax orb $X86_CR0_PE, %al movl %eax, %cr0 - ljmpw $8, $2f + jmp 1f +1: ljmpw $8, $2f 2: movw %cx, %ds movw %cx, %es @@ -61,19 +65,17 @@ ENTRY(wakeup_start) andb $~X86_CR0_PE, %al movl %eax, %cr0 - LJMPW_RM(3f) + jmp wakeup_jmp 3: /* Set up segments */ movw %cs, %ax - movw %ax, %ss - movl $rm_stack_end, %esp movw %ax, %ds movw %ax, %es - movw %ax, %fs - movw %ax, %gs - + movw %ax, %ss lidtl wakeup_idt + movl $wakeup_stack_end, %esp + /* Clear the EFLAGS */ pushl $0 popfl @@ -85,7 +87,7 @@ ENTRY(wakeup_start) /* Check we really have everything... */ movl end_signature, %eax - cmpl $REALMODE_END_SIGNATURE, %eax + cmpl $WAKEUP_END_SIGNATURE, %eax jne bogus_real_magic /* Call the C code */ @@ -126,13 +128,14 @@ ENTRY(wakeup_start) lgdtl pmode_gdt /* This really couldn't... */ - movl pmode_entry, %eax - movl pmode_cr0, %ecx - movl %ecx, %cr0 - ljmpl $__KERNEL_CS, $pa_startup_32 - /* -> jmp *%eax in trampoline_32.S */ + movl pmode_cr0, %eax + movl %eax, %cr0 + jmp pmode_return #else - jmp trampoline_start + pushw $0 + pushw trampoline_segment + pushw $0 + lret #endif bogus_real_magic: @@ -140,38 +143,28 @@ bogus_real_magic: hlt jmp 1b - .section ".rodata","a" - - /* - * Set up the wakeup GDT. We set these up as Big Real Mode, - * that is, with limits set to 4 GB. At least the Lenovo - * Thinkpad X61 is known to need this for the video BIOS - * initialization quirk to work; this is likely to also - * be the case for other laptops or integrated video devices. - */ - - .balign 16 -GLOBAL(wakeup_gdt) - .word 3*8-1 /* Self-descriptor */ - .long pa_wakeup_gdt - .word 0 - - .word 0xffff /* 16-bit code segment @ real_mode_base */ - .long 0x9b000000 + pa_real_mode_base - .word 0x008f /* big real mode */ - - .word 0xffff /* 16-bit data segment @ real_mode_base */ - .long 0x93000000 + pa_real_mode_base - .word 0x008f /* big real mode */ -END(wakeup_gdt) - - .section ".rodata","a" + .data .balign 8 /* This is the standard real-mode IDT */ - .balign 16 -GLOBAL(wakeup_idt) +wakeup_idt: .word 0xffff /* limit */ .long 0 /* address */ .word 0 -END(wakeup_idt) + + .globl HEAP, heap_end +HEAP: + .long wakeup_heap +heap_end: + .long wakeup_stack + + .bss +wakeup_heap: + .space 2048 +wakeup_stack: + .space 2048 +wakeup_stack_end: + + .section ".signature","a" +end_signature: + .long WAKEUP_END_SIGNATURE diff --git a/trunk/arch/x86/realmode/rm/wakeup.h b/trunk/arch/x86/kernel/acpi/realmode/wakeup.h similarity index 79% rename from trunk/arch/x86/realmode/rm/wakeup.h rename to trunk/arch/x86/kernel/acpi/realmode/wakeup.h index 9317e0042f24..97a29e1430e3 100644 --- a/trunk/arch/x86/realmode/rm/wakeup.h +++ b/trunk/arch/x86/kernel/acpi/realmode/wakeup.h @@ -12,8 +12,9 @@ /* This must match data at wakeup.S */ struct wakeup_header { u16 video_mode; /* Video mode number */ + u16 _jmp1; /* ljmpl opcode, 32-bit only */ u32 pmode_entry; /* Protected mode resume point, 32-bit only */ - u16 pmode_cs; + u16 _jmp2; /* CS value, 32-bit only */ u32 pmode_cr0; /* Protected mode cr0 */ u32 pmode_cr3; /* Protected mode cr3 */ u32 pmode_cr4; /* Protected mode cr4 */ @@ -25,6 +26,12 @@ struct wakeup_header { u32 pmode_behavior; /* Wakeup routine behavior flags */ u32 realmode_flags; u32 real_magic; + u16 trampoline_segment; /* segment with trampoline code, 64-bit only */ + u8 _pad1; + u8 wakeup_jmp; + u16 wakeup_jmp_off; + u16 wakeup_jmp_seg; + u64 wakeup_gdt[3]; u32 signature; /* To check we have correct structure */ } __attribute__((__packed__)); @@ -33,6 +40,7 @@ extern struct wakeup_header wakeup_header; #define WAKEUP_HEADER_OFFSET 8 #define WAKEUP_HEADER_SIGNATURE 0x51ee1111 +#define WAKEUP_END_SIGNATURE 0x65a22c82 /* Wakeup behavior bits */ #define WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE 0 diff --git a/trunk/arch/x86/kernel/acpi/realmode/wakeup.lds.S b/trunk/arch/x86/kernel/acpi/realmode/wakeup.lds.S new file mode 100644 index 000000000000..d4f8010a5b1b --- /dev/null +++ b/trunk/arch/x86/kernel/acpi/realmode/wakeup.lds.S @@ -0,0 +1,62 @@ +/* + * wakeup.ld + * + * Linker script for the real-mode wakeup code + */ +#undef i386 +#include "wakeup.h" + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) + +SECTIONS +{ + . = 0; + .jump : { + *(.jump) + } = 0x90909090 + + . = WAKEUP_HEADER_OFFSET; + .header : { + *(.header) + } + + . = ALIGN(16); + .text : { + *(.text*) + } = 0x90909090 + + . = ALIGN(16); + .rodata : { + *(.rodata*) + } + + .videocards : { + video_cards = .; + *(.videocards) + video_cards_end = .; + } + + . = ALIGN(16); + .data : { + *(.data*) + } + + . = ALIGN(16); + .bss : { + __bss_start = .; + *(.bss) + __bss_end = .; + } + + .signature : { + *(.signature) + } + + _end = .; + + /DISCARD/ : { + *(.note*) + } +} diff --git a/trunk/arch/x86/kernel/acpi/sleep.c b/trunk/arch/x86/kernel/acpi/sleep.c index 95bf99de9058..146a49c763a4 100644 --- a/trunk/arch/x86/kernel/acpi/sleep.c +++ b/trunk/arch/x86/kernel/acpi/sleep.c @@ -14,9 +14,8 @@ #include #include #include -#include -#include "../../realmode/rm/wakeup.h" +#include "realmode/wakeup.h" #include "sleep.h" unsigned long acpi_realmode_flags; @@ -37,9 +36,13 @@ asmlinkage void acpi_enter_s3(void) */ int acpi_suspend_lowlevel(void) { - struct wakeup_header *header = - (struct wakeup_header *) __va(real_mode_header->wakeup_header); + struct wakeup_header *header; + /* address in low memory of the wakeup routine. */ + char *acpi_realmode; + acpi_realmode = TRAMPOLINE_SYM(acpi_wakeup_code); + + header = (struct wakeup_header *)(acpi_realmode + WAKEUP_HEADER_OFFSET); if (header->signature != WAKEUP_HEADER_SIGNATURE) { printk(KERN_ERR "wakeup header does not match\n"); return -EINVAL; @@ -47,6 +50,27 @@ int acpi_suspend_lowlevel(void) header->video_mode = saved_video_mode; + header->wakeup_jmp_seg = acpi_wakeup_address >> 4; + + /* + * Set up the wakeup GDT. We set these up as Big Real Mode, + * that is, with limits set to 4 GB. At least the Lenovo + * Thinkpad X61 is known to need this for the video BIOS + * initialization quirk to work; this is likely to also + * be the case for other laptops or integrated video devices. + */ + + /* GDT[0]: GDT self-pointer */ + header->wakeup_gdt[0] = + (u64)(sizeof(header->wakeup_gdt) - 1) + + ((u64)__pa(&header->wakeup_gdt) << 16); + /* GDT[1]: big real mode-like code segment */ + header->wakeup_gdt[1] = + GDT_ENTRY(0x809b, acpi_wakeup_address, 0xfffff); + /* GDT[2]: big real mode-like data segment */ + header->wakeup_gdt[2] = + GDT_ENTRY(0x8093, acpi_wakeup_address, 0xfffff); + #ifndef CONFIG_64BIT store_gdt((struct desc_ptr *)&header->pmode_gdt); @@ -71,6 +95,7 @@ int acpi_suspend_lowlevel(void) header->pmode_cr3 = (u32)__pa(&initial_page_table); saved_magic = 0x12345678; #else /* CONFIG_64BIT */ + header->trampoline_segment = trampoline_address() >> 4; #ifdef CONFIG_SMP stack_start = (unsigned long)temp_stack + sizeof(temp_stack); early_gdt_descr.address = diff --git a/trunk/arch/x86/kernel/acpi/sleep.h b/trunk/arch/x86/kernel/acpi/sleep.h index 5653a5791ec9..d68677a2a010 100644 --- a/trunk/arch/x86/kernel/acpi/sleep.h +++ b/trunk/arch/x86/kernel/acpi/sleep.h @@ -2,8 +2,8 @@ * Variables and functions used by the code in sleep.c */ +#include #include -#include extern unsigned long saved_video_mode; extern long saved_magic; diff --git a/trunk/arch/x86/kernel/acpi/wakeup_rm.S b/trunk/arch/x86/kernel/acpi/wakeup_rm.S new file mode 100644 index 000000000000..63b8ab524f2c --- /dev/null +++ b/trunk/arch/x86/kernel/acpi/wakeup_rm.S @@ -0,0 +1,12 @@ +/* + * Wrapper script for the realmode binary as a transport object + * before copying to low memory. + */ +#include + + .section ".x86_trampoline","a" + .balign PAGE_SIZE + .globl acpi_wakeup_code +acpi_wakeup_code: + .incbin "arch/x86/kernel/acpi/realmode/wakeup.bin" + .size acpi_wakeup_code, .-acpi_wakeup_code diff --git a/trunk/arch/x86/kernel/cpu/mcheck/mce.c b/trunk/arch/x86/kernel/cpu/mcheck/mce.c index 0a687fd185e6..b772dd6ad450 100644 --- a/trunk/arch/x86/kernel/cpu/mcheck/mce.c +++ b/trunk/arch/x86/kernel/cpu/mcheck/mce.c @@ -1251,15 +1251,15 @@ void mce_log_therm_throt_event(__u64 status) * poller finds an MCE, poll 2x faster. When the poller finds no more * errors, poll 2x slower (up to check_interval seconds). */ -static unsigned long check_interval = 5 * 60; /* 5 minutes */ +static int check_interval = 5 * 60; /* 5 minutes */ -static DEFINE_PER_CPU(unsigned long, mce_next_interval); /* in jiffies */ +static DEFINE_PER_CPU(int, mce_next_interval); /* in jiffies */ static DEFINE_PER_CPU(struct timer_list, mce_timer); -static void mce_timer_fn(unsigned long data) +static void mce_start_timer(unsigned long data) { - struct timer_list *t = &__get_cpu_var(mce_timer); - unsigned long iv; + struct timer_list *t = &per_cpu(mce_timer, data); + int *n; WARN_ON(smp_processor_id() != data); @@ -1272,14 +1272,13 @@ static void mce_timer_fn(unsigned long data) * Alert userspace if needed. If we logged an MCE, reduce the * polling interval, otherwise increase the polling interval. */ - iv = __this_cpu_read(mce_next_interval); + n = &__get_cpu_var(mce_next_interval); if (mce_notify_irq()) - iv = max(iv, (unsigned long) HZ/100); + *n = max(*n/2, HZ/100); else - iv = min(iv * 2, round_jiffies_relative(check_interval * HZ)); - __this_cpu_write(mce_next_interval, iv); + *n = min(*n*2, (int)round_jiffies_relative(check_interval*HZ)); - t->expires = jiffies + iv; + t->expires = jiffies + *n; add_timer_on(t, smp_processor_id()); } @@ -1473,9 +1472,9 @@ static int __cpuinit __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c) rdmsrl(msrs[i], val); /* CntP bit set? */ - if (val & BIT_64(62)) { - val &= ~BIT_64(62); - wrmsrl(msrs[i], val); + if (val & BIT(62)) { + val &= ~BIT(62); + wrmsrl(msrs[i], val); } } @@ -1557,17 +1556,17 @@ static void __mcheck_cpu_init_vendor(struct cpuinfo_x86 *c) static void __mcheck_cpu_init_timer(void) { struct timer_list *t = &__get_cpu_var(mce_timer); - unsigned long iv = __this_cpu_read(mce_next_interval); + int *n = &__get_cpu_var(mce_next_interval); - setup_timer(t, mce_timer_fn, smp_processor_id()); + setup_timer(t, mce_start_timer, smp_processor_id()); if (mce_ignore_ce) return; - __this_cpu_write(mce_next_interval, iv); - if (!iv) + *n = check_interval * HZ; + if (!*n) return; - t->expires = round_jiffies(jiffies + iv); + t->expires = round_jiffies(jiffies + *n); add_timer_on(t, smp_processor_id()); } @@ -2277,7 +2276,7 @@ mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) case CPU_DOWN_FAILED_FROZEN: if (!mce_ignore_ce && check_interval) { t->expires = round_jiffies(jiffies + - per_cpu(mce_next_interval, cpu)); + __get_cpu_var(mce_next_interval)); add_timer_on(t, cpu); } smp_call_function_single(cpu, mce_reenable_cpu, &action, 1); diff --git a/trunk/arch/x86/kernel/cpu/mtrr/cleanup.c b/trunk/arch/x86/kernel/cpu/mtrr/cleanup.c index bdda2e6c673b..ac140c7be396 100644 --- a/trunk/arch/x86/kernel/cpu/mtrr/cleanup.c +++ b/trunk/arch/x86/kernel/cpu/mtrr/cleanup.c @@ -266,7 +266,7 @@ range_to_mtrr(unsigned int reg, unsigned long range_startk, if (align > max_align) align = max_align; - sizek = 1UL << align; + sizek = 1 << align; if (debug_print) { char start_factor = 'K', size_factor = 'K'; unsigned long start_base, size_base; diff --git a/trunk/arch/x86/kernel/entry_32.S b/trunk/arch/x86/kernel/entry_32.S index 623f28837476..01ccf9b71473 100644 --- a/trunk/arch/x86/kernel/entry_32.S +++ b/trunk/arch/x86/kernel/entry_32.S @@ -316,6 +316,7 @@ ret_from_exception: preempt_stop(CLBR_ANY) ret_from_intr: GET_THREAD_INFO(%ebp) +resume_userspace_sig: #ifdef CONFIG_VM86 movl PT_EFLAGS(%esp), %eax # mix EFLAGS and CS movb PT_CS(%esp), %al @@ -614,13 +615,9 @@ work_notifysig: # deal with pending signals and # vm86-space TRACE_IRQS_ON ENABLE_INTERRUPTS(CLBR_NONE) - movb PT_CS(%esp), %bl - andb $SEGMENT_RPL_MASK, %bl - cmpb $USER_RPL, %bl - jb resume_kernel xorl %edx, %edx call do_notify_resume - jmp resume_userspace + jmp resume_userspace_sig ALIGN work_notifysig_v86: @@ -633,13 +630,9 @@ work_notifysig_v86: #endif TRACE_IRQS_ON ENABLE_INTERRUPTS(CLBR_NONE) - movb PT_CS(%esp), %bl - andb $SEGMENT_RPL_MASK, %bl - cmpb $USER_RPL, %bl - jb resume_kernel xorl %edx, %edx call do_notify_resume - jmp resume_userspace + jmp resume_userspace_sig END(work_pending) # perform syscall exit tracing diff --git a/trunk/arch/x86/kernel/head32.c b/trunk/arch/x86/kernel/head32.c index c18f59d10101..51ff18616d50 100644 --- a/trunk/arch/x86/kernel/head32.c +++ b/trunk/arch/x86/kernel/head32.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/arch/x86/kernel/head64.c b/trunk/arch/x86/kernel/head64.c index 037df57a99ac..3a3b779f41d3 100644 --- a/trunk/arch/x86/kernel/head64.c +++ b/trunk/arch/x86/kernel/head64.c @@ -24,6 +24,7 @@ #include #include #include +#include #include static void __init zap_identity_mappings(void) diff --git a/trunk/arch/x86/kernel/head_32.S b/trunk/arch/x86/kernel/head_32.S index d42ab17b7397..463c9797ca6a 100644 --- a/trunk/arch/x86/kernel/head_32.S +++ b/trunk/arch/x86/kernel/head_32.S @@ -274,7 +274,10 @@ num_subarch_entries = (. - subarch_entries) / 4 * If cpu hotplug is not supported then this code can go in init section * which will be freed later */ + __CPUINIT + +#ifdef CONFIG_SMP ENTRY(startup_32_smp) cld movl $(__BOOT_DS),%eax @@ -285,7 +288,7 @@ ENTRY(startup_32_smp) movl pa(stack_start),%ecx movl %eax,%ss leal -__PAGE_OFFSET(%ecx),%esp - +#endif /* CONFIG_SMP */ default_entry: /* diff --git a/trunk/arch/x86/kernel/head_64.S b/trunk/arch/x86/kernel/head_64.S index 94bf9cc2c7ee..7a40f2447321 100644 --- a/trunk/arch/x86/kernel/head_64.S +++ b/trunk/arch/x86/kernel/head_64.S @@ -139,6 +139,10 @@ ident_complete: /* Fixup phys_base */ addq %rbp, phys_base(%rip) + /* Fixup trampoline */ + addq %rbp, trampoline_level4_pgt + 0(%rip) + addq %rbp, trampoline_level4_pgt + (511*8)(%rip) + /* Due to ENTRY(), sometimes the empty space gets filled with * zeros. Better take a jmp than relying on empty space being * filled with 0x90 (nop) diff --git a/trunk/arch/x86/kernel/hpet.c b/trunk/arch/x86/kernel/hpet.c index 1460a5df92f7..9cc7b4392f7c 100644 --- a/trunk/arch/x86/kernel/hpet.c +++ b/trunk/arch/x86/kernel/hpet.c @@ -870,7 +870,7 @@ int __init hpet_enable(void) else pr_warn("HPET initial state will not be saved\n"); cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY); - hpet_writel(cfg, HPET_CFG); + hpet_writel(cfg, HPET_Tn_CFG(i)); if (cfg) pr_warn("HPET: Unrecognized bits %#x set in global cfg\n", cfg); diff --git a/trunk/arch/x86/kernel/mpparse.c b/trunk/arch/x86/kernel/mpparse.c index d2b56489d70f..fbca2e6223bf 100644 --- a/trunk/arch/x86/kernel/mpparse.c +++ b/trunk/arch/x86/kernel/mpparse.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include diff --git a/trunk/arch/x86/kernel/reboot.c b/trunk/arch/x86/kernel/reboot.c index 79c45af81604..77215c23fba1 100644 --- a/trunk/arch/x86/kernel/reboot.c +++ b/trunk/arch/x86/kernel/reboot.c @@ -24,7 +24,6 @@ #ifdef CONFIG_X86_32 # include # include -# include #else # include #endif @@ -157,10 +156,15 @@ static int __init set_bios_reboot(const struct dmi_system_id *d) return 0; } +extern const unsigned char machine_real_restart_asm[]; +extern const u64 machine_real_restart_gdt[3]; + void machine_real_restart(unsigned int type) { - void (*restart_lowmem)(unsigned int) = (void (*)(unsigned int)) - real_mode_header->machine_real_restart_asm; + void *restart_va; + unsigned long restart_pa; + void (*restart_lowmem)(unsigned int); + u64 *lowmem_gdt; local_irq_disable(); @@ -191,6 +195,21 @@ void machine_real_restart(unsigned int type) * too. */ *((unsigned short *)0x472) = reboot_mode; + /* Patch the GDT in the low memory trampoline */ + lowmem_gdt = TRAMPOLINE_SYM(machine_real_restart_gdt); + + restart_va = TRAMPOLINE_SYM(machine_real_restart_asm); + restart_pa = virt_to_phys(restart_va); + restart_lowmem = (void (*)(unsigned int))restart_pa; + + /* GDT[0]: GDT self-pointer */ + lowmem_gdt[0] = + (u64)(sizeof(machine_real_restart_gdt) - 1) + + ((u64)virt_to_phys(lowmem_gdt) << 16); + /* GDT[1]: 64K real mode code segment */ + lowmem_gdt[1] = + GDT_ENTRY(0x009b, restart_pa, 0xffff); + /* Jump to the identity-mapped low memory code */ restart_lowmem(type); } diff --git a/trunk/arch/x86/realmode/rm/reboot_32.S b/trunk/arch/x86/kernel/reboot_32.S similarity index 71% rename from trunk/arch/x86/realmode/rm/reboot_32.S rename to trunk/arch/x86/kernel/reboot_32.S index 114044876b3d..1d5c46df0d78 100644 --- a/trunk/arch/x86/realmode/rm/reboot_32.S +++ b/trunk/arch/x86/kernel/reboot_32.S @@ -2,7 +2,6 @@ #include #include #include -#include "realmode.h" /* * The following code and data reboots the machine by switching to real @@ -14,20 +13,34 @@ * * This code is called with the restart type (0 = BIOS, 1 = APM) in %eax. */ - .section ".text32", "ax" + .section ".x86_trampoline","a" + .balign 16 .code32 - - .balign 16 ENTRY(machine_real_restart_asm) +r_base = . + /* Get our own relocated address */ + call 1f +1: popl %ebx + subl $(1b - r_base), %ebx + + /* Compute the equivalent real-mode segment */ + movl %ebx, %ecx + shrl $4, %ecx + + /* Patch post-real-mode segment jump */ + movw (dispatch_table - r_base)(%ebx,%eax,2),%ax + movw %ax, (101f - r_base)(%ebx) + movw %cx, (102f - r_base)(%ebx) + /* Set up the IDT for real mode. */ - lidtl pa_machine_real_restart_idt + lidtl (machine_real_restart_idt - r_base)(%ebx) /* * Set up a GDT from which we can load segment descriptors for real * mode. The GDT is not used in real mode; it is just needed here to * prepare the descriptors. */ - lgdtl pa_machine_real_restart_gdt + lgdtl (machine_real_restart_gdt - r_base)(%ebx) /* * Load the data segment registers with 16-bit compatible values @@ -38,7 +51,7 @@ ENTRY(machine_real_restart_asm) movl %ecx, %fs movl %ecx, %gs movl %ecx, %ss - ljmpw $8, $1f + ljmpl $8, $1f - r_base /* * This is 16-bit protected mode code to disable paging and the cache, @@ -63,29 +76,27 @@ ENTRY(machine_real_restart_asm) * * Most of this work is probably excessive, but it is what is tested. */ - .text .code16 - - .balign 16 -machine_real_restart_asm16: 1: xorl %ecx, %ecx - movl %cr0, %edx - andl $0x00000011, %edx - orl $0x60000000, %edx - movl %edx, %cr0 + movl %cr0, %eax + andl $0x00000011, %eax + orl $0x60000000, %eax + movl %eax, %cr0 movl %ecx, %cr3 movl %cr0, %edx - testl $0x60000000, %edx /* If no cache bits -> no wbinvd */ + andl $0x60000000, %edx /* If no cache bits -> no wbinvd */ jz 2f wbinvd 2: - andb $0x10, %dl - movl %edx, %cr0 - LJMPW_RM(3f) -3: - andw %ax, %ax - jz bios + andb $0x10, %al + movl %eax, %cr0 + .byte 0xea /* ljmpw */ +101: .word 0 /* Offset */ +102: .word 0 /* Segment */ + +bios: + ljmpw $0xf000, $0xfff0 apm: movw $0x1000, %ax @@ -95,34 +106,26 @@ apm: movw $0x0001, %bx movw $0x0003, %cx int $0x15 - /* This should never return... */ -bios: - ljmpw $0xf000, $0xfff0 +END(machine_real_restart_asm) - .section ".rodata", "a" + .balign 16 + /* These must match #include -#include +#include #include #include #include @@ -909,7 +909,7 @@ void __init setup_arch(char **cmdline_p) printk(KERN_DEBUG "initial memory mapped: [mem 0x00000000-%#010lx]\n", (max_pfn_mapped<= 0) { /* A CPU has %cr4 if and only if it has CPUID */ mmu_cr4_features = read_cr4(); - if (trampoline_cr4_features) - *trampoline_cr4_features = mmu_cr4_features; } #ifdef CONFIG_X86_32 diff --git a/trunk/arch/x86/kernel/signal.c b/trunk/arch/x86/kernel/signal.c index 21af737053aa..965dfda0fd5e 100644 --- a/trunk/arch/x86/kernel/signal.c +++ b/trunk/arch/x86/kernel/signal.c @@ -555,6 +555,7 @@ unsigned long sys_sigreturn(struct pt_regs *regs) sizeof(frame->extramask)))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(regs, &frame->sc, &ax)) @@ -580,6 +581,7 @@ long sys_rt_sigreturn(struct pt_regs *regs) if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) @@ -645,28 +647,42 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, struct pt_regs *regs) { int usig = signr_convert(sig); - sigset_t *set = sigmask_to_save(); + sigset_t *set = ¤t->blocked; + int ret; + + if (current_thread_info()->status & TS_RESTORE_SIGMASK) + set = ¤t->saved_sigmask; /* Set up the stack frame */ if (is_ia32) { if (ka->sa.sa_flags & SA_SIGINFO) - return ia32_setup_rt_frame(usig, ka, info, set, regs); + ret = ia32_setup_rt_frame(usig, ka, info, set, regs); else - return ia32_setup_frame(usig, ka, set, regs); + ret = ia32_setup_frame(usig, ka, set, regs); #ifdef CONFIG_X86_X32_ABI } else if (is_x32) { - return x32_setup_rt_frame(usig, ka, info, + ret = x32_setup_rt_frame(usig, ka, info, (compat_sigset_t *)set, regs); #endif } else { - return __setup_rt_frame(sig, ka, info, set, regs); + ret = __setup_rt_frame(sig, ka, info, set, regs); + } + + if (ret) { + force_sigsegv(sig, current); + return -EFAULT; } + + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; + return ret; } -static void +static int handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, struct pt_regs *regs) { + int ret; + /* Are we from a system call? */ if (syscall_get_nr(current, regs) >= 0) { /* If so, check system call restarting.. */ @@ -697,10 +713,10 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, likely(test_and_clear_thread_flag(TIF_FORCED_TF))) regs->flags &= ~X86_EFLAGS_TF; - if (setup_rt_frame(sig, ka, info, regs) < 0) { - force_sigsegv(sig, current); - return; - } + ret = setup_rt_frame(sig, ka, info, regs); + + if (ret) + return ret; /* * Clear the direction flag as per the ABI for function entry. @@ -715,8 +731,12 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, */ regs->flags &= ~X86_EFLAGS_TF; - signal_delivered(sig, info, ka, regs, - test_thread_flag(TIF_SINGLESTEP)); + block_sigmask(ka, sig); + + tracehook_signal_handler(sig, info, ka, regs, + test_thread_flag(TIF_SINGLESTEP)); + + return 0; } #ifdef CONFIG_X86_32 @@ -737,6 +757,16 @@ static void do_signal(struct pt_regs *regs) siginfo_t info; int signr; + /* + * We want the common case to go fast, which is why we may in certain + * cases get here from kernel mode. Just return without doing anything + * if so. + * X86_32: vm86 regs switched out by assembly code before reaching + * here, so testing against kernel CS suffices. + */ + if (!user_mode(regs)) + return; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { /* Whee! Actually deliver the signal. */ @@ -766,7 +796,10 @@ static void do_signal(struct pt_regs *regs) * If there's no signal to deliver, we just put the saved sigmask * back. */ - restore_saved_sigmask(); + if (current_thread_info()->status & TS_RESTORE_SIGMASK) { + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; + set_current_blocked(¤t->saved_sigmask); + } } /* @@ -794,6 +827,8 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } if (thread_info_flags & _TIF_USER_RETURN_NOTIFY) fire_user_return_notifiers(); @@ -901,6 +936,7 @@ asmlinkage long sys32_x32_rt_sigreturn(struct pt_regs *regs) if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) diff --git a/trunk/arch/x86/kernel/smpboot.c b/trunk/arch/x86/kernel/smpboot.c index f56f96da77f5..433529e29be4 100644 --- a/trunk/arch/x86/kernel/smpboot.c +++ b/trunk/arch/x86/kernel/smpboot.c @@ -57,7 +57,7 @@ #include #include #include -#include +#include #include #include #include @@ -73,8 +73,6 @@ #include #include -#include - /* State of each CPU */ DEFINE_PER_CPU(int, cpu_state) = { 0 }; @@ -662,12 +660,8 @@ static void __cpuinit announce_cpu(int cpu, int apicid) */ static int __cpuinit do_boot_cpu(int apicid, int cpu, struct task_struct *idle) { - volatile u32 *trampoline_status = - (volatile u32 *) __va(real_mode_header->trampoline_status); - /* start_ip had better be page-aligned! */ - unsigned long start_ip = real_mode_header->trampoline_start; - unsigned long boot_error = 0; + unsigned long start_ip; int timeout; alternatives_smp_switch(1); @@ -690,6 +684,9 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu, struct task_struct *idle) initial_code = (unsigned long)start_secondary; stack_start = idle->thread.sp; + /* start_ip had better be page-aligned! */ + start_ip = trampoline_address(); + /* So we see what's up */ announce_cpu(cpu, apicid); @@ -752,7 +749,8 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu, struct task_struct *idle) pr_debug("CPU%d: has booted.\n", cpu); } else { boot_error = 1; - if (*trampoline_status == 0xA5A5A5A5) + if (*(volatile u32 *)TRAMPOLINE_SYM(trampoline_status) + == 0xA5A5A5A5) /* trampoline started but...? */ pr_err("CPU%d: Stuck ??\n", cpu); else @@ -778,7 +776,7 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu, struct task_struct *idle) } /* mark "stuck" area as not stuck */ - *trampoline_status = 0; + *(volatile u32 *)TRAMPOLINE_SYM(trampoline_status) = 0; if (get_uv_system_type() != UV_NON_UNIQUE_APIC) { /* diff --git a/trunk/arch/x86/kernel/tboot.c b/trunk/arch/x86/kernel/tboot.c index f84fe00fad48..6410744ac5cb 100644 --- a/trunk/arch/x86/kernel/tboot.c +++ b/trunk/arch/x86/kernel/tboot.c @@ -32,7 +32,7 @@ #include #include -#include +#include #include #include #include @@ -44,7 +44,7 @@ #include #include -#include "../realmode/rm/wakeup.h" +#include "acpi/realmode/wakeup.h" /* Global pointer to shared data; NULL means no measured launch. */ struct tboot *tboot __read_mostly; @@ -201,8 +201,7 @@ static int tboot_setup_sleep(void) add_mac_region(e820.map[i].addr, e820.map[i].size); } - tboot->acpi_sinfo.kernel_s3_resume_vector = - real_mode_header->wakeup_start; + tboot->acpi_sinfo.kernel_s3_resume_vector = acpi_wakeup_address; return 0; } diff --git a/trunk/arch/x86/kernel/trampoline.c b/trunk/arch/x86/kernel/trampoline.c new file mode 100644 index 000000000000..a73b61055ad6 --- /dev/null +++ b/trunk/arch/x86/kernel/trampoline.c @@ -0,0 +1,42 @@ +#include +#include + +#include +#include +#include + +unsigned char *x86_trampoline_base; + +void __init setup_trampolines(void) +{ + phys_addr_t mem; + size_t size = PAGE_ALIGN(x86_trampoline_end - x86_trampoline_start); + + /* Has to be in very low memory so we can execute real-mode AP code. */ + mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE); + if (!mem) + panic("Cannot allocate trampoline\n"); + + x86_trampoline_base = __va(mem); + memblock_reserve(mem, size); + + printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n", + x86_trampoline_base, (unsigned long long)mem, size); + + memcpy(x86_trampoline_base, x86_trampoline_start, size); +} + +/* + * setup_trampolines() gets called very early, to guarantee the + * availability of low memory. This is before the proper kernel page + * tables are set up, so we cannot set page permissions in that + * function. Thus, we use an arch_initcall instead. + */ +static int __init configure_trampolines(void) +{ + size_t size = PAGE_ALIGN(x86_trampoline_end - x86_trampoline_start); + + set_memory_x((unsigned long)x86_trampoline_base, size >> PAGE_SHIFT); + return 0; +} +arch_initcall(configure_trampolines); diff --git a/trunk/arch/x86/kernel/trampoline_32.S b/trunk/arch/x86/kernel/trampoline_32.S new file mode 100644 index 000000000000..451c0a7ef7fd --- /dev/null +++ b/trunk/arch/x86/kernel/trampoline_32.S @@ -0,0 +1,83 @@ +/* + * + * Trampoline.S Derived from Setup.S by Linus Torvalds + * + * 4 Jan 1997 Michael Chastain: changed to gnu as. + * + * This is only used for booting secondary CPUs in SMP machine + * + * Entry: CS:IP point to the start of our code, we are + * in real mode with no stack, but the rest of the + * trampoline page to make our stack and everything else + * is a mystery. + * + * We jump into arch/x86/kernel/head_32.S. + * + * On entry to trampoline_data, the processor is in real mode + * with 16-bit addressing and 16-bit data. CS has some value + * and IP is zero. Thus, data addresses need to be absolute + * (no relocation) and are taken with regard to r_base. + * + * If you work on this file, check the object module with + * objdump --reloc to make sure there are no relocation + * entries except for: + * + * TYPE VALUE + * R_386_32 startup_32_smp + * R_386_32 boot_gdt + */ + +#include +#include +#include +#include + +#ifdef CONFIG_SMP + + .section ".x86_trampoline","a" + .balign PAGE_SIZE + .code16 + +ENTRY(trampoline_data) +r_base = . + wbinvd # Needed for NUMA-Q should be harmless for others + mov %cs, %ax # Code and data in the same place + mov %ax, %ds + + cli # We should be safe anyway + + movl $0xA5A5A5A5, trampoline_status - r_base + # write marker for master knows we're running + + /* GDT tables in non default location kernel can be beyond 16MB and + * lgdt will not be able to load the address as in real mode default + * operand size is 16bit. Use lgdtl instead to force operand size + * to 32 bit. + */ + + lidtl boot_idt_descr - r_base # load idt with 0, 0 + lgdtl boot_gdt_descr - r_base # load gdt with whatever is appropriate + + xor %ax, %ax + inc %ax # protected mode (PE) bit + lmsw %ax # into protected mode + # flush prefetch and jump to startup_32_smp in arch/i386/kernel/head.S + ljmpl $__BOOT_CS, $(startup_32_smp-__PAGE_OFFSET) + + # These need to be in the same 64K segment as the above; + # hence we don't use the boot_gdt_descr defined in head.S +boot_gdt_descr: + .word __BOOT_DS + 7 # gdt limit + .long boot_gdt - __PAGE_OFFSET # gdt base + +boot_idt_descr: + .word 0 # idt limit = 0 + .long 0 # idt base = 0L + +ENTRY(trampoline_status) + .long 0 + +.globl trampoline_end +trampoline_end: + +#endif /* CONFIG_SMP */ diff --git a/trunk/arch/x86/realmode/rm/trampoline_64.S b/trunk/arch/x86/kernel/trampoline_64.S similarity index 51% rename from trunk/arch/x86/realmode/rm/trampoline_64.S rename to trunk/arch/x86/kernel/trampoline_64.S index bb360dc39d21..09ff51799e96 100644 --- a/trunk/arch/x86/realmode/rm/trampoline_64.S +++ b/trunk/arch/x86/kernel/trampoline_64.S @@ -5,12 +5,12 @@ * 4 Jan 1997 Michael Chastain: changed to gnu as. * 15 Sept 2005 Eric Biederman: 64bit PIC support * - * Entry: CS:IP point to the start of our code, we are - * in real mode with no stack, but the rest of the + * Entry: CS:IP point to the start of our code, we are + * in real mode with no stack, but the rest of the * trampoline page to make our stack and everything else * is a mystery. * - * On entry to trampoline_start, the processor is in real mode + * On entry to trampoline_data, the processor is in real mode * with 16-bit addressing and 16-bit data. CS has some value * and IP is zero. Thus, data addresses need to be absolute * (no relocation) and are taken with regard to r_base. @@ -31,33 +31,43 @@ #include #include #include -#include "realmode.h" - .text + .section ".x86_trampoline","a" + .balign PAGE_SIZE .code16 - .balign PAGE_SIZE -ENTRY(trampoline_start) +ENTRY(trampoline_data) +r_base = . cli # We should be safe anyway wbinvd - - LJMPW_RM(1f) -1: mov %cs, %ax # Code and data in the same place mov %ax, %ds mov %ax, %es mov %ax, %ss - movl $0xA5A5A5A5, trampoline_status - # write marker for master knows we're running - # Setup stack - movl $rm_stack_end, %esp + movl $0xA5A5A5A5, trampoline_status - r_base + # write marker for master knows we're running + + # Setup stack + movw $(trampoline_stack_end - r_base), %sp call verify_cpu # Verify the cpu supports long mode testl %eax, %eax # Check for return code jnz no_longmode + mov %cs, %ax + movzx %ax, %esi # Find the 32bit trampoline location + shll $4, %esi + + # Fixup the absolute vectors + leal (startup_32 - r_base)(%esi), %eax + movl %eax, startup_32_vector - r_base + leal (startup_64 - r_base)(%esi), %eax + movl %eax, startup_64_vector - r_base + leal (tgdt - r_base)(%esi), %eax + movl %eax, (tgdt + 2 - r_base) + /* * GDT tables in non default location kernel can be beyond 16MB and * lgdt will not be able to load the address as in real mode default @@ -65,49 +75,36 @@ ENTRY(trampoline_start) * to 32 bit. */ - lidtl tr_idt # load idt with 0, 0 - lgdtl tr_gdt # load gdt with whatever is appropriate - - movw $__KERNEL_DS, %dx # Data segment descriptor + lidtl tidt - r_base # load idt with 0, 0 + lgdtl tgdt - r_base # load gdt with whatever is appropriate - # Enable protected mode - movl $X86_CR0_PE, %eax # protected mode (PE) bit - movl %eax, %cr0 # into protected mode + mov $X86_CR0_PE, %ax # protected mode (PE) bit + lmsw %ax # into protected mode # flush prefetch and jump to startup_32 - ljmpl $__KERNEL32_CS, $pa_startup_32 + ljmpl *(startup_32_vector - r_base) -no_longmode: - hlt - jmp no_longmode -#include "../kernel/verify_cpu.S" - - .section ".text32","ax" .code32 .balign 4 -ENTRY(startup_32) - movl %edx, %ss - addl $pa_real_mode_base, %esp - movl %edx, %ds - movl %edx, %es - movl %edx, %fs - movl %edx, %gs - - movl pa_tr_cr4, %eax +startup_32: + movl $__KERNEL_DS, %eax # Initialize the %ds segment register + movl %eax, %ds + + movl $X86_CR4_PAE, %eax movl %eax, %cr4 # Enable PAE mode - # Setup trampoline 4 level pagetables - movl $pa_trampoline_pgd, %eax + # Setup trampoline 4 level pagetables + leal (trampoline_level4_pgt - r_base)(%esi), %eax movl %eax, %cr3 - # Set up EFER - movl pa_tr_efer, %eax - movl pa_tr_efer + 4, %edx movl $MSR_EFER, %ecx + movl $(1 << _EFER_LME), %eax # Enable Long Mode + xorl %edx, %edx wrmsr # Enable paging and in turn activate Long Mode - movl $(X86_CR0_PG | X86_CR0_WP | X86_CR0_PE), %eax + # Enable protected mode + movl $(X86_CR0_PG | X86_CR0_PE), %eax movl %eax, %cr0 /* @@ -116,38 +113,59 @@ ENTRY(startup_32) * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use * the new gdt/idt that has __KERNEL_CS with CS.L = 1. */ - ljmpl $__KERNEL_CS, $pa_startup_64 + ljmp *(startup_64_vector - r_base)(%esi) - .section ".text64","ax" .code64 .balign 4 -ENTRY(startup_64) +startup_64: # Now jump into the kernel using virtual addresses - jmpq *tr_start(%rip) + movq $secondary_startup_64, %rax + jmp *%rax + + .code16 +no_longmode: + hlt + jmp no_longmode +#include "verify_cpu.S" + + .balign 4 + # Careful these need to be in the same 64K segment as the above; +tidt: + .word 0 # idt limit = 0 + .word 0, 0 # idt base = 0L - .section ".rodata","a" # Duplicate the global descriptor table # so the kernel can live anywhere - .balign 16 - .globl tr_gdt -tr_gdt: - .short tr_gdt_end - tr_gdt - 1 # gdt limit - .long pa_tr_gdt - .short 0 + .balign 4 +tgdt: + .short tgdt_end - tgdt # gdt limit + .long tgdt - r_base + .short 0 .quad 0x00cf9b000000ffff # __KERNEL32_CS .quad 0x00af9b000000ffff # __KERNEL_CS .quad 0x00cf93000000ffff # __KERNEL_DS -tr_gdt_end: +tgdt_end: - .bss - .balign PAGE_SIZE -GLOBAL(trampoline_pgd) .space PAGE_SIZE + .balign 4 +startup_32_vector: + .long startup_32 - r_base + .word __KERNEL32_CS, 0 - .balign 8 -GLOBAL(trampoline_header) - tr_start: .space 8 - GLOBAL(tr_efer) .space 8 - GLOBAL(tr_cr4) .space 4 -END(trampoline_header) + .balign 4 +startup_64_vector: + .long startup_64 - r_base + .word __KERNEL_CS, 0 -#include "trampoline_common.S" + .balign 4 +ENTRY(trampoline_status) + .long 0 + +trampoline_stack: + .org 0x1000 +trampoline_stack_end: +ENTRY(trampoline_level4_pgt) + .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE + .fill 510,8,0 + .quad level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE + +ENTRY(trampoline_end) diff --git a/trunk/arch/x86/kernel/vmlinux.lds.S b/trunk/arch/x86/kernel/vmlinux.lds.S index 22a1530146a8..0f703f10901a 100644 --- a/trunk/arch/x86/kernel/vmlinux.lds.S +++ b/trunk/arch/x86/kernel/vmlinux.lds.S @@ -197,6 +197,18 @@ SECTIONS INIT_DATA_SECTION(16) + /* + * Code and data for a variety of lowlevel trampolines, to be + * copied into base memory (< 1 MiB) during initialization. + * Since it is copied early, the main copy can be discarded + * afterwards. + */ + .x86_trampoline : AT(ADDR(.x86_trampoline) - LOAD_OFFSET) { + x86_trampoline_start = .; + *(.x86_trampoline) + x86_trampoline_end = .; + } + .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) { __x86_cpu_dev_start = .; *(.x86_cpu_dev.init) diff --git a/trunk/arch/x86/kvm/mmu.c b/trunk/arch/x86/kvm/mmu.c index be3cea4407ff..72102e0ab7cb 100644 --- a/trunk/arch/x86/kvm/mmu.c +++ b/trunk/arch/x86/kvm/mmu.c @@ -2595,7 +2595,8 @@ static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu, *gfnp = gfn; kvm_release_pfn_clean(pfn); pfn &= ~mask; - kvm_get_pfn(pfn); + if (!get_page_unless_zero(pfn_to_page(pfn))) + BUG(); *pfnp = pfn; } } diff --git a/trunk/arch/x86/mm/pat.c b/trunk/arch/x86/mm/pat.c index 3d68ef6d2266..f11729fd019c 100644 --- a/trunk/arch/x86/mm/pat.c +++ b/trunk/arch/x86/mm/pat.c @@ -158,47 +158,31 @@ static unsigned long pat_x_mtrr_type(u64 start, u64 end, unsigned long req_type) return req_type; } -struct pagerange_state { - unsigned long cur_pfn; - int ram; - int not_ram; -}; - -static int -pagerange_is_ram_callback(unsigned long initial_pfn, unsigned long total_nr_pages, void *arg) -{ - struct pagerange_state *state = arg; - - state->not_ram |= initial_pfn > state->cur_pfn; - state->ram |= total_nr_pages > 0; - state->cur_pfn = initial_pfn + total_nr_pages; - - return state->ram && state->not_ram; -} - static int pat_pagerange_is_ram(resource_size_t start, resource_size_t end) { - int ret = 0; - unsigned long start_pfn = start >> PAGE_SHIFT; - unsigned long end_pfn = (end + PAGE_SIZE - 1) >> PAGE_SHIFT; - struct pagerange_state state = {start_pfn, 0, 0}; - - /* - * For legacy reasons, physical address range in the legacy ISA - * region is tracked as non-RAM. This will allow users of - * /dev/mem to map portions of legacy ISA region, even when - * some of those portions are listed(or not even listed) with - * different e820 types(RAM/reserved/..) - */ - if (start_pfn < ISA_END_ADDRESS >> PAGE_SHIFT) - start_pfn = ISA_END_ADDRESS >> PAGE_SHIFT; + int ram_page = 0, not_rampage = 0; + unsigned long page_nr; - if (start_pfn < end_pfn) { - ret = walk_system_ram_range(start_pfn, end_pfn - start_pfn, - &state, pagerange_is_ram_callback); + for (page_nr = (start >> PAGE_SHIFT); page_nr < (end >> PAGE_SHIFT); + ++page_nr) { + /* + * For legacy reasons, physical address range in the legacy ISA + * region is tracked as non-RAM. This will allow users of + * /dev/mem to map portions of legacy ISA region, even when + * some of those portions are listed(or not even listed) with + * different e820 types(RAM/reserved/..) + */ + if (page_nr >= (ISA_END_ADDRESS >> PAGE_SHIFT) && + page_is_ram(page_nr)) + ram_page = 1; + else + not_rampage = 1; + + if (ram_page == not_rampage) + return -1; } - return (ret > 0) ? -1 : (state.ram ? 1 : 0); + return ram_page; } /* diff --git a/trunk/arch/x86/realmode/Makefile b/trunk/arch/x86/realmode/Makefile deleted file mode 100644 index 94f7fbe97b08..000000000000 --- a/trunk/arch/x86/realmode/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# -# arch/x86/realmode/Makefile -# -# This file is subject to the terms and conditions of the GNU General Public -# License. See the file "COPYING" in the main directory of this archive -# for more details. -# -# - -subdir- := rm - -obj-y += init.o -obj-y += rmpiggy.o - -$(obj)/rmpiggy.o: $(obj)/rm/realmode.bin - -$(obj)/rm/realmode.bin: FORCE - $(Q)$(MAKE) $(build)=$(obj)/rm $@ diff --git a/trunk/arch/x86/realmode/init.c b/trunk/arch/x86/realmode/init.c deleted file mode 100644 index cbca565af5bd..000000000000 --- a/trunk/arch/x86/realmode/init.c +++ /dev/null @@ -1,115 +0,0 @@ -#include -#include - -#include -#include -#include - -struct real_mode_header *real_mode_header; -u32 *trampoline_cr4_features; - -void __init setup_real_mode(void) -{ - phys_addr_t mem; - u16 real_mode_seg; - u32 *rel; - u32 count; - u32 *ptr; - u16 *seg; - int i; - unsigned char *base; - struct trampoline_header *trampoline_header; - size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob); -#ifdef CONFIG_X86_64 - u64 *trampoline_pgd; - u64 efer; -#endif - - /* Has to be in very low memory so we can execute real-mode AP code. */ - mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE); - if (!mem) - panic("Cannot allocate trampoline\n"); - - base = __va(mem); - memblock_reserve(mem, size); - real_mode_header = (struct real_mode_header *) base; - printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n", - base, (unsigned long long)mem, size); - - memcpy(base, real_mode_blob, size); - - real_mode_seg = __pa(base) >> 4; - rel = (u32 *) real_mode_relocs; - - /* 16-bit segment relocations. */ - count = rel[0]; - rel = &rel[1]; - for (i = 0; i < count; i++) { - seg = (u16 *) (base + rel[i]); - *seg = real_mode_seg; - } - - /* 32-bit linear relocations. */ - count = rel[i]; - rel = &rel[i + 1]; - for (i = 0; i < count; i++) { - ptr = (u32 *) (base + rel[i]); - *ptr += __pa(base); - } - - /* Must be perfomed *after* relocation. */ - trampoline_header = (struct trampoline_header *) - __va(real_mode_header->trampoline_header); - -#ifdef CONFIG_X86_32 - trampoline_header->start = __pa(startup_32_smp); - trampoline_header->gdt_limit = __BOOT_DS + 7; - trampoline_header->gdt_base = __pa(boot_gdt); -#else - /* - * Some AMD processors will #GP(0) if EFER.LMA is set in WRMSR - * so we need to mask it out. - */ - rdmsrl(MSR_EFER, efer); - trampoline_header->efer = efer & ~EFER_LMA; - - trampoline_header->start = (u64) secondary_startup_64; - trampoline_cr4_features = &trampoline_header->cr4; - *trampoline_cr4_features = read_cr4(); - - trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd); - trampoline_pgd[0] = __pa(level3_ident_pgt) + _KERNPG_TABLE; - trampoline_pgd[511] = __pa(level3_kernel_pgt) + _KERNPG_TABLE; -#endif -} - -/* - * set_real_mode_permissions() gets called very early, to guarantee the - * availability of low memory. This is before the proper kernel page - * tables are set up, so we cannot set page permissions in that - * function. Thus, we use an arch_initcall instead. - */ -static int __init set_real_mode_permissions(void) -{ - unsigned char *base = (unsigned char *) real_mode_header; - size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob); - - size_t ro_size = - PAGE_ALIGN(real_mode_header->ro_end) - - __pa(base); - - size_t text_size = - PAGE_ALIGN(real_mode_header->ro_end) - - real_mode_header->text_start; - - unsigned long text_start = - (unsigned long) __va(real_mode_header->text_start); - - set_memory_nx((unsigned long) base, size >> PAGE_SHIFT); - set_memory_ro((unsigned long) base, ro_size >> PAGE_SHIFT); - set_memory_x((unsigned long) text_start, text_size >> PAGE_SHIFT); - - return 0; -} - -arch_initcall(set_real_mode_permissions); diff --git a/trunk/arch/x86/realmode/rm/.gitignore b/trunk/arch/x86/realmode/rm/.gitignore deleted file mode 100644 index b6ed3a2555cb..000000000000 --- a/trunk/arch/x86/realmode/rm/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -pasyms.h -realmode.lds -realmode.relocs diff --git a/trunk/arch/x86/realmode/rm/Makefile b/trunk/arch/x86/realmode/rm/Makefile deleted file mode 100644 index 5b84a2d30888..000000000000 --- a/trunk/arch/x86/realmode/rm/Makefile +++ /dev/null @@ -1,82 +0,0 @@ -# -# arch/x86/realmode/Makefile -# -# This file is subject to the terms and conditions of the GNU General Public -# License. See the file "COPYING" in the main directory of this archive -# for more details. -# -# - -always := realmode.bin realmode.relocs - -wakeup-objs := wakeup_asm.o wakemain.o video-mode.o -wakeup-objs += copy.o bioscall.o regs.o -# The link order of the video-*.o modules can matter. In particular, -# video-vga.o *must* be listed first, followed by video-vesa.o. -# Hardware-specific drivers should follow in the order they should be -# probed, and video-bios.o should typically be last. -wakeup-objs += video-vga.o -wakeup-objs += video-vesa.o -wakeup-objs += video-bios.o - -realmode-y += header.o -realmode-y += trampoline_$(BITS).o -realmode-y += stack.o -realmode-$(CONFIG_X86_32) += reboot_32.o -realmode-$(CONFIG_ACPI_SLEEP) += $(wakeup-objs) - -targets += $(realmode-y) - -REALMODE_OBJS = $(addprefix $(obj)/,$(realmode-y)) - -sed-pasyms := -n -r -e 's/^([0-9a-fA-F]+) [ABCDGRSTVW] (.+)$$/pa_\2 = \2;/p' - -quiet_cmd_pasyms = PASYMS $@ - cmd_pasyms = $(NM) $(filter-out FORCE,$^) | \ - sed $(sed-pasyms) | sort | uniq > $@ - -targets += pasyms.h -$(obj)/pasyms.h: $(REALMODE_OBJS) FORCE - $(call if_changed,pasyms) - -targets += realmode.lds -$(obj)/realmode.lds: $(obj)/pasyms.h - -LDFLAGS_realmode.elf := --emit-relocs -T -CPPFLAGS_realmode.lds += -P -C -I$(obj) - -targets += realmode.elf -$(obj)/realmode.elf: $(obj)/realmode.lds $(REALMODE_OBJS) FORCE - $(call if_changed,ld) - -OBJCOPYFLAGS_realmode.bin := -O binary - -targets += realmode.bin -$(obj)/realmode.bin: $(obj)/realmode.elf $(obj)/realmode.relocs - $(call if_changed,objcopy) - -quiet_cmd_relocs = RELOCS $@ - cmd_relocs = arch/x86/tools/relocs --realmode $< > $@ - -targets += realmode.relocs -$(obj)/realmode.relocs: $(obj)/realmode.elf FORCE - $(call if_changed,relocs) - -# --------------------------------------------------------------------------- - -# How to compile the 16-bit code. Note we always compile for -march=i386, -# that way we can complain to the user if the CPU is insufficient. -KBUILD_CFLAGS := $(LINUXINCLUDE) -m32 -g -Os -D_SETUP -D__KERNEL__ -D_WAKEUP \ - -I$(srctree)/arch/x86/boot \ - -DDISABLE_BRANCH_PROFILING \ - -Wall -Wstrict-prototypes \ - -march=i386 -mregparm=3 \ - -include $(srctree)/$(src)/../../boot/code16gcc.h \ - -fno-strict-aliasing -fomit-frame-pointer \ - $(call cc-option, -ffreestanding) \ - $(call cc-option, -fno-toplevel-reorder,\ - $(call cc-option, -fno-unit-at-a-time)) \ - $(call cc-option, -fno-stack-protector) \ - $(call cc-option, -mpreferred-stack-boundary=2) -KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ -GCOV_PROFILE := n diff --git a/trunk/arch/x86/realmode/rm/bioscall.S b/trunk/arch/x86/realmode/rm/bioscall.S deleted file mode 100644 index 16162d197918..000000000000 --- a/trunk/arch/x86/realmode/rm/bioscall.S +++ /dev/null @@ -1 +0,0 @@ -#include "../../boot/bioscall.S" diff --git a/trunk/arch/x86/realmode/rm/copy.S b/trunk/arch/x86/realmode/rm/copy.S deleted file mode 100644 index b785e6f38fdd..000000000000 --- a/trunk/arch/x86/realmode/rm/copy.S +++ /dev/null @@ -1 +0,0 @@ -#include "../../boot/copy.S" diff --git a/trunk/arch/x86/realmode/rm/header.S b/trunk/arch/x86/realmode/rm/header.S deleted file mode 100644 index fadf48378ada..000000000000 --- a/trunk/arch/x86/realmode/rm/header.S +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Real-mode blob header; this should match realmode.h and be - * readonly; for mutable data instead add pointers into the .data - * or .bss sections as appropriate. - */ - -#include -#include - -#include "realmode.h" - - .section ".header", "a" - - .balign 16 -GLOBAL(real_mode_header) - .long pa_text_start - .long pa_ro_end - /* SMP trampoline */ - .long pa_trampoline_start - .long pa_trampoline_status - .long pa_trampoline_header -#ifdef CONFIG_X86_64 - .long pa_trampoline_pgd; -#endif - /* ACPI S3 wakeup */ -#ifdef CONFIG_ACPI_SLEEP - .long pa_wakeup_start - .long pa_wakeup_header -#endif - /* APM/BIOS reboot */ -#ifdef CONFIG_X86_32 - .long pa_machine_real_restart_asm -#endif -END(real_mode_header) - - /* End signature, used to verify integrity */ - .section ".signature","a" - .balign 4 -GLOBAL(end_signature) - .long REALMODE_END_SIGNATURE -END(end_signature) diff --git a/trunk/arch/x86/realmode/rm/realmode.h b/trunk/arch/x86/realmode/rm/realmode.h deleted file mode 100644 index d74cff6350ed..000000000000 --- a/trunk/arch/x86/realmode/rm/realmode.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef ARCH_X86_REALMODE_RM_REALMODE_H -#define ARCH_X86_REALMODE_RM_REALMODE_H - -#ifdef __ASSEMBLY__ - -/* - * 16-bit ljmpw to the real_mode_seg - * - * This must be open-coded since gas will choke on using a - * relocatable symbol for the segment portion. - */ -#define LJMPW_RM(to) .byte 0xea ; .word (to), real_mode_seg - -#endif /* __ASSEMBLY__ */ - -/* - * Signature at the end of the realmode region - */ -#define REALMODE_END_SIGNATURE 0x65a22c82 - -#endif /* ARCH_X86_REALMODE_RM_REALMODE_H */ diff --git a/trunk/arch/x86/realmode/rm/realmode.lds.S b/trunk/arch/x86/realmode/rm/realmode.lds.S deleted file mode 100644 index 86b2e8d6b1f1..000000000000 --- a/trunk/arch/x86/realmode/rm/realmode.lds.S +++ /dev/null @@ -1,76 +0,0 @@ -/* - * realmode.lds.S - * - * Linker script for the real-mode code - */ - -#include - -#undef i386 - -OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") -OUTPUT_ARCH(i386) - -SECTIONS -{ - real_mode_seg = 0; - - . = 0; - .header : { - pa_real_mode_base = .; - *(.header) - } - - . = ALIGN(4); - .rodata : { - *(.rodata) - *(.rodata.*) - . = ALIGN(16); - video_cards = .; - *(.videocards) - video_cards_end = .; - } - - . = ALIGN(PAGE_SIZE); - pa_text_start = .; - .text : { - *(.text) - *(.text.*) - } - - .text32 : { - *(.text32) - *(.text32.*) - } - - .text64 : { - *(.text64) - *(.text64.*) - } - pa_ro_end = .; - - . = ALIGN(PAGE_SIZE); - .data : { - *(.data) - *(.data.*) - } - - . = ALIGN(128); - .bss : { - *(.bss*) - } - - /* End signature for integrity checking */ - . = ALIGN(4); - .signature : { - *(.signature) - } - - /DISCARD/ : { - *(.note*) - *(.debug*) - *(.eh_frame*) - } - -#include "pasyms.h" -} diff --git a/trunk/arch/x86/realmode/rm/regs.c b/trunk/arch/x86/realmode/rm/regs.c deleted file mode 100644 index fbb15b9f9ca9..000000000000 --- a/trunk/arch/x86/realmode/rm/regs.c +++ /dev/null @@ -1 +0,0 @@ -#include "../../boot/regs.c" diff --git a/trunk/arch/x86/realmode/rm/stack.S b/trunk/arch/x86/realmode/rm/stack.S deleted file mode 100644 index 867ae87adfae..000000000000 --- a/trunk/arch/x86/realmode/rm/stack.S +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Common heap and stack allocations - */ - -#include - - .data -GLOBAL(HEAP) - .long rm_heap -GLOBAL(heap_end) - .long rm_stack - - .bss - .balign 16 -GLOBAL(rm_heap) - .space 2048 -GLOBAL(rm_stack) - .space 2048 -GLOBAL(rm_stack_end) diff --git a/trunk/arch/x86/realmode/rm/trampoline_32.S b/trunk/arch/x86/realmode/rm/trampoline_32.S deleted file mode 100644 index c1b2791183e7..000000000000 --- a/trunk/arch/x86/realmode/rm/trampoline_32.S +++ /dev/null @@ -1,74 +0,0 @@ -/* - * - * Trampoline.S Derived from Setup.S by Linus Torvalds - * - * 4 Jan 1997 Michael Chastain: changed to gnu as. - * - * This is only used for booting secondary CPUs in SMP machine - * - * Entry: CS:IP point to the start of our code, we are - * in real mode with no stack, but the rest of the - * trampoline page to make our stack and everything else - * is a mystery. - * - * We jump into arch/x86/kernel/head_32.S. - * - * On entry to trampoline_start, the processor is in real mode - * with 16-bit addressing and 16-bit data. CS has some value - * and IP is zero. Thus, we load CS to the physical segment - * of the real mode code before doing anything further. - */ - -#include -#include -#include -#include -#include "realmode.h" - - .text - .code16 - - .balign PAGE_SIZE -ENTRY(trampoline_start) - wbinvd # Needed for NUMA-Q should be harmless for others - - LJMPW_RM(1f) -1: - mov %cs, %ax # Code and data in the same place - mov %ax, %ds - - cli # We should be safe anyway - - movl tr_start, %eax # where we need to go - - movl $0xA5A5A5A5, trampoline_status - # write marker for master knows we're running - - /* - * GDT tables in non default location kernel can be beyond 16MB and - * lgdt will not be able to load the address as in real mode default - * operand size is 16bit. Use lgdtl instead to force operand size - * to 32 bit. - */ - lidtl tr_idt # load idt with 0, 0 - lgdtl tr_gdt # load gdt with whatever is appropriate - - movw $1, %dx # protected mode (PE) bit - lmsw %dx # into protected mode - - ljmpl $__BOOT_CS, $pa_startup_32 - - .section ".text32","ax" - .code32 -ENTRY(startup_32) # note: also used from wakeup_asm.S - jmp *%eax - - .bss - .balign 8 -GLOBAL(trampoline_header) - tr_start: .space 4 - tr_gdt_pad: .space 2 - tr_gdt: .space 6 -END(trampoline_header) - -#include "trampoline_common.S" diff --git a/trunk/arch/x86/realmode/rm/trampoline_common.S b/trunk/arch/x86/realmode/rm/trampoline_common.S deleted file mode 100644 index b1ecdb9692ad..000000000000 --- a/trunk/arch/x86/realmode/rm/trampoline_common.S +++ /dev/null @@ -1,7 +0,0 @@ - .section ".rodata","a" - .balign 16 -tr_idt: .fill 1, 6, 0 - - .bss - .balign 4 -GLOBAL(trampoline_status) .space 4 diff --git a/trunk/arch/x86/realmode/rm/video-bios.c b/trunk/arch/x86/realmode/rm/video-bios.c deleted file mode 100644 index 848b25aaf11b..000000000000 --- a/trunk/arch/x86/realmode/rm/video-bios.c +++ /dev/null @@ -1 +0,0 @@ -#include "../../boot/video-bios.c" diff --git a/trunk/arch/x86/realmode/rm/video-mode.c b/trunk/arch/x86/realmode/rm/video-mode.c deleted file mode 100644 index 2a98b7e2368b..000000000000 --- a/trunk/arch/x86/realmode/rm/video-mode.c +++ /dev/null @@ -1 +0,0 @@ -#include "../../boot/video-mode.c" diff --git a/trunk/arch/x86/realmode/rm/video-vesa.c b/trunk/arch/x86/realmode/rm/video-vesa.c deleted file mode 100644 index 413edddb51e5..000000000000 --- a/trunk/arch/x86/realmode/rm/video-vesa.c +++ /dev/null @@ -1 +0,0 @@ -#include "../../boot/video-vesa.c" diff --git a/trunk/arch/x86/realmode/rm/video-vga.c b/trunk/arch/x86/realmode/rm/video-vga.c deleted file mode 100644 index 3085f5c9d288..000000000000 --- a/trunk/arch/x86/realmode/rm/video-vga.c +++ /dev/null @@ -1 +0,0 @@ -#include "../../boot/video-vga.c" diff --git a/trunk/arch/x86/realmode/rmpiggy.S b/trunk/arch/x86/realmode/rmpiggy.S deleted file mode 100644 index 204c6ece0e97..000000000000 --- a/trunk/arch/x86/realmode/rmpiggy.S +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Wrapper script for the realmode binary as a transport object - * before copying to low memory. - */ -#include -#include - - .section ".init.data","aw" - - .balign PAGE_SIZE - -GLOBAL(real_mode_blob) - .incbin "arch/x86/realmode/rm/realmode.bin" -END(real_mode_blob) - -GLOBAL(real_mode_blob_end); - -GLOBAL(real_mode_relocs) - .incbin "arch/x86/realmode/rm/realmode.relocs" -END(real_mode_relocs) diff --git a/trunk/arch/x86/tools/relocs.c b/trunk/arch/x86/tools/relocs.c index 5a1847d61930..b685296d4464 100644 --- a/trunk/arch/x86/tools/relocs.c +++ b/trunk/arch/x86/tools/relocs.c @@ -77,13 +77,6 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = { static const char * const sym_regex_realmode[S_NSYMTYPES] = { -/* - * These symbols are known to be relative, even if the linker marks them - * as absolute (typically defined outside any section in the linker script.) - */ - [S_REL] = - "^pa_", - /* * These are 16-bit segment symbols when compiling 16-bit code. */ diff --git a/trunk/arch/x86/um/signal.c b/trunk/arch/x86/um/signal.c index a508cea13503..bb0fb03b9f85 100644 --- a/trunk/arch/x86/um/signal.c +++ b/trunk/arch/x86/um/signal.c @@ -486,6 +486,7 @@ long sys_sigreturn(struct pt_regs *regs) copy_from_user(&set.sig[1], extramask, sig_size)) goto segfault; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (copy_sc_from_user(¤t->thread.regs, sc)) @@ -599,6 +600,7 @@ long sys_rt_sigreturn(struct pt_regs *regs) if (copy_from_user(&set, &uc->uc_sigmask, sizeof(set))) goto segfault; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext)) diff --git a/trunk/arch/x86/xen/enlighten.c b/trunk/arch/x86/xen/enlighten.c index e74df9548a02..75f33b2a5933 100644 --- a/trunk/arch/x86/xen/enlighten.c +++ b/trunk/arch/x86/xen/enlighten.c @@ -1116,10 +1116,7 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = { .wbinvd = native_wbinvd, .read_msr = native_read_msr_safe, - .rdmsr_regs = native_rdmsr_safe_regs, .write_msr = xen_write_msr_safe, - .wrmsr_regs = native_wrmsr_safe_regs, - .read_tsc = native_read_tsc, .read_pmc = native_read_pmc, diff --git a/trunk/arch/xtensa/kernel/signal.c b/trunk/arch/xtensa/kernel/signal.c index b9f8e5850d3a..c5e4ec0598d2 100644 --- a/trunk/arch/xtensa/kernel/signal.c +++ b/trunk/arch/xtensa/kernel/signal.c @@ -30,6 +30,8 @@ #define DEBUG_SIG 0 +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + extern struct task_struct *coproc_owners[]; struct rt_sigframe @@ -259,6 +261,7 @@ asmlinkage long xtensa_rt_sigreturn(long a0, long a1, long a2, long a3, if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); set_current_blocked(&set); if (restore_sigcontext(regs, frame)) @@ -449,6 +452,15 @@ static void do_signal(struct pt_regs *regs) siginfo_t info; int signr; struct k_sigaction ka; + sigset_t oldset; + + if (try_to_freeze()) + goto no_signal; + + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; task_pt_regs(current)->icountlevel = 0; @@ -489,17 +501,19 @@ static void do_signal(struct pt_regs *regs) /* Whee! Actually deliver the signal. */ /* Set up the stack frame */ - ret = setup_frame(signr, &ka, &info, sigmask_to_save(), regs); + ret = setup_frame(signr, &ka, &info, oldset, regs); if (ret) return; - signal_delivered(signr, info, ka, regs, 0); + clear_thread_flag(TIF_RESTORE_SIGMASK); + block_sigmask(&ka, signr); if (current->ptrace & PT_SINGLESTEP) task_pt_regs(current)->icountlevel = 1; return; } +no_signal: /* Did we come from a system call? */ if ((signed) regs->syscall >= 0) { /* Restart the system call - no handlers present */ @@ -518,7 +532,8 @@ static void do_signal(struct pt_regs *regs) } /* If there's no signal to deliver, we just restore the saved mask. */ - restore_saved_sigmask(); + if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK)) + set_current_blocked(¤t->saved_sigmask); if (current->ptrace & PT_SINGLESTEP) task_pt_regs(current)->icountlevel = 1; @@ -533,6 +548,9 @@ void do_notify_resume(struct pt_regs *regs) if (test_thread_flag(TIF_SIGPENDING)) do_signal(regs); - if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) + if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) { tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); + } } diff --git a/trunk/block/Kconfig.iosched b/trunk/block/Kconfig.iosched index 421bef9c4c48..3199b76f795d 100644 --- a/trunk/block/Kconfig.iosched +++ b/trunk/block/Kconfig.iosched @@ -23,6 +23,8 @@ config IOSCHED_DEADLINE config IOSCHED_CFQ tristate "CFQ I/O scheduler" + # If BLK_CGROUP is a module, CFQ has to be built as module. + depends on (BLK_CGROUP=m && m) || !BLK_CGROUP || BLK_CGROUP=y default y ---help--- The CFQ I/O scheduler tries to distribute bandwidth equally @@ -32,6 +34,8 @@ config IOSCHED_CFQ This is the default I/O scheduler. + Note: If BLK_CGROUP=m, then CFQ can be built only as module. + config CFQ_GROUP_IOSCHED bool "CFQ Group Scheduling support" depends on IOSCHED_CFQ && BLK_CGROUP diff --git a/trunk/block/blk-cgroup.c b/trunk/block/blk-cgroup.c index 02cf6335e9bd..126c341955de 100644 --- a/trunk/block/blk-cgroup.c +++ b/trunk/block/blk-cgroup.c @@ -11,906 +11,1668 @@ * Nauman Rafique */ #include +#include #include #include #include #include #include -#include -#include -#include #include "blk-cgroup.h" -#include "blk.h" +#include #define MAX_KEY_LEN 100 -static DEFINE_MUTEX(blkcg_pol_mutex); +static DEFINE_SPINLOCK(blkio_list_lock); +static LIST_HEAD(blkio_list); -struct blkcg blkcg_root = { .cfq_weight = 2 * CFQ_WEIGHT_DEFAULT }; -EXPORT_SYMBOL_GPL(blkcg_root); +struct blkio_cgroup blkio_root_cgroup = { .weight = 2*BLKIO_WEIGHT_DEFAULT }; +EXPORT_SYMBOL_GPL(blkio_root_cgroup); -static struct blkcg_policy *blkcg_policy[BLKCG_MAX_POLS]; +/* for encoding cft->private value on file */ +#define BLKIOFILE_PRIVATE(x, val) (((x) << 16) | (val)) +/* What policy owns the file, proportional or throttle */ +#define BLKIOFILE_POLICY(val) (((val) >> 16) & 0xffff) +#define BLKIOFILE_ATTR(val) ((val) & 0xffff) -struct blkcg *cgroup_to_blkcg(struct cgroup *cgroup) +static inline void blkio_policy_insert_node(struct blkio_cgroup *blkcg, + struct blkio_policy_node *pn) { - return container_of(cgroup_subsys_state(cgroup, blkio_subsys_id), - struct blkcg, css); + list_add(&pn->node, &blkcg->policy_list); } -EXPORT_SYMBOL_GPL(cgroup_to_blkcg); -static struct blkcg *task_blkcg(struct task_struct *tsk) +static inline bool cftype_blkg_same_policy(struct cftype *cft, + struct blkio_group *blkg) { - return container_of(task_subsys_state(tsk, blkio_subsys_id), - struct blkcg, css); + enum blkio_policy_id plid = BLKIOFILE_POLICY(cft->private); + + if (blkg->plid == plid) + return 1; + + return 0; } -struct blkcg *bio_blkcg(struct bio *bio) +/* Determines if policy node matches cgroup file being accessed */ +static inline bool pn_matches_cftype(struct cftype *cft, + struct blkio_policy_node *pn) { - if (bio && bio->bi_css) - return container_of(bio->bi_css, struct blkcg, css); - return task_blkcg(current); + enum blkio_policy_id plid = BLKIOFILE_POLICY(cft->private); + int fileid = BLKIOFILE_ATTR(cft->private); + + return (plid == pn->plid && fileid == pn->fileid); } -EXPORT_SYMBOL_GPL(bio_blkcg); -static bool blkcg_policy_enabled(struct request_queue *q, - const struct blkcg_policy *pol) +/* Must be called with blkcg->lock held */ +static inline void blkio_policy_delete_node(struct blkio_policy_node *pn) { - return pol && test_bit(pol->plid, q->blkcg_pols); + list_del(&pn->node); } -/** - * blkg_free - free a blkg - * @blkg: blkg to free - * - * Free @blkg which may be partially allocated. - */ -static void blkg_free(struct blkcg_gq *blkg) +/* Must be called with blkcg->lock held */ +static struct blkio_policy_node * +blkio_policy_search_node(const struct blkio_cgroup *blkcg, dev_t dev, + enum blkio_policy_id plid, int fileid) { - int i; + struct blkio_policy_node *pn; - if (!blkg) - return; + list_for_each_entry(pn, &blkcg->policy_list, node) { + if (pn->dev == dev && pn->plid == plid && pn->fileid == fileid) + return pn; + } - for (i = 0; i < BLKCG_MAX_POLS; i++) { - struct blkcg_policy *pol = blkcg_policy[i]; - struct blkg_policy_data *pd = blkg->pd[i]; + return NULL; +} - if (!pd) - continue; +struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup) +{ + return container_of(cgroup_subsys_state(cgroup, blkio_subsys_id), + struct blkio_cgroup, css); +} +EXPORT_SYMBOL_GPL(cgroup_to_blkio_cgroup); + +struct blkio_cgroup *task_blkio_cgroup(struct task_struct *tsk) +{ + return container_of(task_subsys_state(tsk, blkio_subsys_id), + struct blkio_cgroup, css); +} +EXPORT_SYMBOL_GPL(task_blkio_cgroup); - if (pol && pol->pd_exit_fn) - pol->pd_exit_fn(blkg); +static inline void +blkio_update_group_weight(struct blkio_group *blkg, unsigned int weight) +{ + struct blkio_policy_type *blkiop; - kfree(pd); + list_for_each_entry(blkiop, &blkio_list, list) { + /* If this policy does not own the blkg, do not send updates */ + if (blkiop->plid != blkg->plid) + continue; + if (blkiop->ops.blkio_update_group_weight_fn) + blkiop->ops.blkio_update_group_weight_fn(blkg->key, + blkg, weight); } - - kfree(blkg); } -/** - * blkg_alloc - allocate a blkg - * @blkcg: block cgroup the new blkg is associated with - * @q: request_queue the new blkg is associated with - * - * Allocate a new blkg assocating @blkcg and @q. - */ -static struct blkcg_gq *blkg_alloc(struct blkcg *blkcg, struct request_queue *q) +static inline void blkio_update_group_bps(struct blkio_group *blkg, u64 bps, + int fileid) { - struct blkcg_gq *blkg; - int i; + struct blkio_policy_type *blkiop; - /* alloc and init base part */ - blkg = kzalloc_node(sizeof(*blkg), GFP_ATOMIC, q->node); - if (!blkg) - return NULL; + list_for_each_entry(blkiop, &blkio_list, list) { - blkg->q = q; - INIT_LIST_HEAD(&blkg->q_node); - blkg->blkcg = blkcg; - blkg->refcnt = 1; + /* If this policy does not own the blkg, do not send updates */ + if (blkiop->plid != blkg->plid) + continue; + + if (fileid == BLKIO_THROTL_read_bps_device + && blkiop->ops.blkio_update_group_read_bps_fn) + blkiop->ops.blkio_update_group_read_bps_fn(blkg->key, + blkg, bps); + + if (fileid == BLKIO_THROTL_write_bps_device + && blkiop->ops.blkio_update_group_write_bps_fn) + blkiop->ops.blkio_update_group_write_bps_fn(blkg->key, + blkg, bps); + } +} + +static inline void blkio_update_group_iops(struct blkio_group *blkg, + unsigned int iops, int fileid) +{ + struct blkio_policy_type *blkiop; - for (i = 0; i < BLKCG_MAX_POLS; i++) { - struct blkcg_policy *pol = blkcg_policy[i]; - struct blkg_policy_data *pd; + list_for_each_entry(blkiop, &blkio_list, list) { - if (!blkcg_policy_enabled(q, pol)) + /* If this policy does not own the blkg, do not send updates */ + if (blkiop->plid != blkg->plid) continue; - /* alloc per-policy data and attach it to blkg */ - pd = kzalloc_node(pol->pd_size, GFP_ATOMIC, q->node); - if (!pd) { - blkg_free(blkg); - return NULL; - } + if (fileid == BLKIO_THROTL_read_iops_device + && blkiop->ops.blkio_update_group_read_iops_fn) + blkiop->ops.blkio_update_group_read_iops_fn(blkg->key, + blkg, iops); - blkg->pd[i] = pd; - pd->blkg = blkg; + if (fileid == BLKIO_THROTL_write_iops_device + && blkiop->ops.blkio_update_group_write_iops_fn) + blkiop->ops.blkio_update_group_write_iops_fn(blkg->key, + blkg,iops); } +} - /* invoke per-policy init */ - for (i = 0; i < BLKCG_MAX_POLS; i++) { - struct blkcg_policy *pol = blkcg_policy[i]; +/* + * Add to the appropriate stat variable depending on the request type. + * This should be called with the blkg->stats_lock held. + */ +static void blkio_add_stat(uint64_t *stat, uint64_t add, bool direction, + bool sync) +{ + if (direction) + stat[BLKIO_STAT_WRITE] += add; + else + stat[BLKIO_STAT_READ] += add; + if (sync) + stat[BLKIO_STAT_SYNC] += add; + else + stat[BLKIO_STAT_ASYNC] += add; +} - if (blkcg_policy_enabled(blkg->q, pol)) - pol->pd_init_fn(blkg); +/* + * Decrements the appropriate stat variable if non-zero depending on the + * request type. Panics on value being zero. + * This should be called with the blkg->stats_lock held. + */ +static void blkio_check_and_dec_stat(uint64_t *stat, bool direction, bool sync) +{ + if (direction) { + BUG_ON(stat[BLKIO_STAT_WRITE] == 0); + stat[BLKIO_STAT_WRITE]--; + } else { + BUG_ON(stat[BLKIO_STAT_READ] == 0); + stat[BLKIO_STAT_READ]--; + } + if (sync) { + BUG_ON(stat[BLKIO_STAT_SYNC] == 0); + stat[BLKIO_STAT_SYNC]--; + } else { + BUG_ON(stat[BLKIO_STAT_ASYNC] == 0); + stat[BLKIO_STAT_ASYNC]--; } - - return blkg; } -static struct blkcg_gq *__blkg_lookup(struct blkcg *blkcg, - struct request_queue *q) +#ifdef CONFIG_DEBUG_BLK_CGROUP +/* This should be called with the blkg->stats_lock held. */ +static void blkio_set_start_group_wait_time(struct blkio_group *blkg, + struct blkio_group *curr_blkg) { - struct blkcg_gq *blkg; + if (blkio_blkg_waiting(&blkg->stats)) + return; + if (blkg == curr_blkg) + return; + blkg->stats.start_group_wait_time = sched_clock(); + blkio_mark_blkg_waiting(&blkg->stats); +} - blkg = rcu_dereference(blkcg->blkg_hint); - if (blkg && blkg->q == q) - return blkg; +/* This should be called with the blkg->stats_lock held. */ +static void blkio_update_group_wait_time(struct blkio_group_stats *stats) +{ + unsigned long long now; - /* - * Hint didn't match. Look up from the radix tree. Note that we - * may not be holding queue_lock and thus are not sure whether - * @blkg from blkg_tree has already been removed or not, so we - * can't update hint to the lookup result. Leave it to the caller. - */ - blkg = radix_tree_lookup(&blkcg->blkg_tree, q->id); - if (blkg && blkg->q == q) - return blkg; + if (!blkio_blkg_waiting(stats)) + return; - return NULL; + now = sched_clock(); + if (time_after64(now, stats->start_group_wait_time)) + stats->group_wait_time += now - stats->start_group_wait_time; + blkio_clear_blkg_waiting(stats); } -/** - * blkg_lookup - lookup blkg for the specified blkcg - q pair - * @blkcg: blkcg of interest - * @q: request_queue of interest - * - * Lookup blkg for the @blkcg - @q pair. This function should be called - * under RCU read lock and is guaranteed to return %NULL if @q is bypassing - * - see blk_queue_bypass_start() for details. - */ -struct blkcg_gq *blkg_lookup(struct blkcg *blkcg, struct request_queue *q) +/* This should be called with the blkg->stats_lock held. */ +static void blkio_end_empty_time(struct blkio_group_stats *stats) { - WARN_ON_ONCE(!rcu_read_lock_held()); + unsigned long long now; + + if (!blkio_blkg_empty(stats)) + return; - if (unlikely(blk_queue_bypass(q))) - return NULL; - return __blkg_lookup(blkcg, q); + now = sched_clock(); + if (time_after64(now, stats->start_empty_time)) + stats->empty_time += now - stats->start_empty_time; + blkio_clear_blkg_empty(stats); } -EXPORT_SYMBOL_GPL(blkg_lookup); -static struct blkcg_gq *__blkg_lookup_create(struct blkcg *blkcg, - struct request_queue *q) - __releases(q->queue_lock) __acquires(q->queue_lock) +void blkiocg_update_set_idle_time_stats(struct blkio_group *blkg) { - struct blkcg_gq *blkg; - int ret; + unsigned long flags; - WARN_ON_ONCE(!rcu_read_lock_held()); - lockdep_assert_held(q->queue_lock); + spin_lock_irqsave(&blkg->stats_lock, flags); + BUG_ON(blkio_blkg_idling(&blkg->stats)); + blkg->stats.start_idle_time = sched_clock(); + blkio_mark_blkg_idling(&blkg->stats); + spin_unlock_irqrestore(&blkg->stats_lock, flags); +} +EXPORT_SYMBOL_GPL(blkiocg_update_set_idle_time_stats); - /* lookup and update hint on success, see __blkg_lookup() for details */ - blkg = __blkg_lookup(blkcg, q); - if (blkg) { - rcu_assign_pointer(blkcg->blkg_hint, blkg); - return blkg; +void blkiocg_update_idle_time_stats(struct blkio_group *blkg) +{ + unsigned long flags; + unsigned long long now; + struct blkio_group_stats *stats; + + spin_lock_irqsave(&blkg->stats_lock, flags); + stats = &blkg->stats; + if (blkio_blkg_idling(stats)) { + now = sched_clock(); + if (time_after64(now, stats->start_idle_time)) + stats->idle_time += now - stats->start_idle_time; + blkio_clear_blkg_idling(stats); } + spin_unlock_irqrestore(&blkg->stats_lock, flags); +} +EXPORT_SYMBOL_GPL(blkiocg_update_idle_time_stats); - /* blkg holds a reference to blkcg */ - if (!css_tryget(&blkcg->css)) - return ERR_PTR(-EINVAL); +void blkiocg_update_avg_queue_size_stats(struct blkio_group *blkg) +{ + unsigned long flags; + struct blkio_group_stats *stats; + + spin_lock_irqsave(&blkg->stats_lock, flags); + stats = &blkg->stats; + stats->avg_queue_size_sum += + stats->stat_arr[BLKIO_STAT_QUEUED][BLKIO_STAT_READ] + + stats->stat_arr[BLKIO_STAT_QUEUED][BLKIO_STAT_WRITE]; + stats->avg_queue_size_samples++; + blkio_update_group_wait_time(stats); + spin_unlock_irqrestore(&blkg->stats_lock, flags); +} +EXPORT_SYMBOL_GPL(blkiocg_update_avg_queue_size_stats); - /* allocate */ - ret = -ENOMEM; - blkg = blkg_alloc(blkcg, q); - if (unlikely(!blkg)) - goto err_put; +void blkiocg_set_start_empty_time(struct blkio_group *blkg) +{ + unsigned long flags; + struct blkio_group_stats *stats; - /* insert */ - ret = radix_tree_preload(GFP_ATOMIC); - if (ret) - goto err_free; + spin_lock_irqsave(&blkg->stats_lock, flags); + stats = &blkg->stats; - spin_lock(&blkcg->lock); - ret = radix_tree_insert(&blkcg->blkg_tree, q->id, blkg); - if (likely(!ret)) { - hlist_add_head_rcu(&blkg->blkcg_node, &blkcg->blkg_list); - list_add(&blkg->q_node, &q->blkg_list); + if (stats->stat_arr[BLKIO_STAT_QUEUED][BLKIO_STAT_READ] || + stats->stat_arr[BLKIO_STAT_QUEUED][BLKIO_STAT_WRITE]) { + spin_unlock_irqrestore(&blkg->stats_lock, flags); + return; } - spin_unlock(&blkcg->lock); - radix_tree_preload_end(); + /* + * group is already marked empty. This can happen if cfqq got new + * request in parent group and moved to this group while being added + * to service tree. Just ignore the event and move on. + */ + if(blkio_blkg_empty(stats)) { + spin_unlock_irqrestore(&blkg->stats_lock, flags); + return; + } - if (!ret) - return blkg; -err_free: - blkg_free(blkg); -err_put: - css_put(&blkcg->css); - return ERR_PTR(ret); + stats->start_empty_time = sched_clock(); + blkio_mark_blkg_empty(stats); + spin_unlock_irqrestore(&blkg->stats_lock, flags); } +EXPORT_SYMBOL_GPL(blkiocg_set_start_empty_time); -struct blkcg_gq *blkg_lookup_create(struct blkcg *blkcg, - struct request_queue *q) +void blkiocg_update_dequeue_stats(struct blkio_group *blkg, + unsigned long dequeue) { - /* - * This could be the first entry point of blkcg implementation and - * we shouldn't allow anything to go through for a bypassing queue. - */ - if (unlikely(blk_queue_bypass(q))) - return ERR_PTR(blk_queue_dead(q) ? -EINVAL : -EBUSY); - return __blkg_lookup_create(blkcg, q); + blkg->stats.dequeue += dequeue; +} +EXPORT_SYMBOL_GPL(blkiocg_update_dequeue_stats); +#else +static inline void blkio_set_start_group_wait_time(struct blkio_group *blkg, + struct blkio_group *curr_blkg) {} +static inline void blkio_end_empty_time(struct blkio_group_stats *stats) {} +#endif + +void blkiocg_update_io_add_stats(struct blkio_group *blkg, + struct blkio_group *curr_blkg, bool direction, + bool sync) +{ + unsigned long flags; + + spin_lock_irqsave(&blkg->stats_lock, flags); + blkio_add_stat(blkg->stats.stat_arr[BLKIO_STAT_QUEUED], 1, direction, + sync); + blkio_end_empty_time(&blkg->stats); + blkio_set_start_group_wait_time(blkg, curr_blkg); + spin_unlock_irqrestore(&blkg->stats_lock, flags); } -EXPORT_SYMBOL_GPL(blkg_lookup_create); +EXPORT_SYMBOL_GPL(blkiocg_update_io_add_stats); -static void blkg_destroy(struct blkcg_gq *blkg) +void blkiocg_update_io_remove_stats(struct blkio_group *blkg, + bool direction, bool sync) { - struct request_queue *q = blkg->q; - struct blkcg *blkcg = blkg->blkcg; + unsigned long flags; - lockdep_assert_held(q->queue_lock); - lockdep_assert_held(&blkcg->lock); + spin_lock_irqsave(&blkg->stats_lock, flags); + blkio_check_and_dec_stat(blkg->stats.stat_arr[BLKIO_STAT_QUEUED], + direction, sync); + spin_unlock_irqrestore(&blkg->stats_lock, flags); +} +EXPORT_SYMBOL_GPL(blkiocg_update_io_remove_stats); - /* Something wrong if we are trying to remove same group twice */ - WARN_ON_ONCE(list_empty(&blkg->q_node)); - WARN_ON_ONCE(hlist_unhashed(&blkg->blkcg_node)); +void blkiocg_update_timeslice_used(struct blkio_group *blkg, unsigned long time, + unsigned long unaccounted_time) +{ + unsigned long flags; + + spin_lock_irqsave(&blkg->stats_lock, flags); + blkg->stats.time += time; +#ifdef CONFIG_DEBUG_BLK_CGROUP + blkg->stats.unaccounted_time += unaccounted_time; +#endif + spin_unlock_irqrestore(&blkg->stats_lock, flags); +} +EXPORT_SYMBOL_GPL(blkiocg_update_timeslice_used); - radix_tree_delete(&blkcg->blkg_tree, blkg->q->id); - list_del_init(&blkg->q_node); - hlist_del_init_rcu(&blkg->blkcg_node); +/* + * should be called under rcu read lock or queue lock to make sure blkg pointer + * is valid. + */ +void blkiocg_update_dispatch_stats(struct blkio_group *blkg, + uint64_t bytes, bool direction, bool sync) +{ + struct blkio_group_stats_cpu *stats_cpu; + unsigned long flags; /* - * Both setting lookup hint to and clearing it from @blkg are done - * under queue_lock. If it's not pointing to @blkg now, it never - * will. Hint assignment itself can race safely. + * Disabling interrupts to provide mutual exclusion between two + * writes on same cpu. It probably is not needed for 64bit. Not + * optimizing that case yet. */ - if (rcu_dereference_raw(blkcg->blkg_hint) == blkg) - rcu_assign_pointer(blkcg->blkg_hint, NULL); + local_irq_save(flags); + + stats_cpu = this_cpu_ptr(blkg->stats_cpu); + + u64_stats_update_begin(&stats_cpu->syncp); + stats_cpu->sectors += bytes >> 9; + blkio_add_stat(stats_cpu->stat_arr_cpu[BLKIO_STAT_CPU_SERVICED], + 1, direction, sync); + blkio_add_stat(stats_cpu->stat_arr_cpu[BLKIO_STAT_CPU_SERVICE_BYTES], + bytes, direction, sync); + u64_stats_update_end(&stats_cpu->syncp); + local_irq_restore(flags); +} +EXPORT_SYMBOL_GPL(blkiocg_update_dispatch_stats); + +void blkiocg_update_completion_stats(struct blkio_group *blkg, + uint64_t start_time, uint64_t io_start_time, bool direction, bool sync) +{ + struct blkio_group_stats *stats; + unsigned long flags; + unsigned long long now = sched_clock(); + + spin_lock_irqsave(&blkg->stats_lock, flags); + stats = &blkg->stats; + if (time_after64(now, io_start_time)) + blkio_add_stat(stats->stat_arr[BLKIO_STAT_SERVICE_TIME], + now - io_start_time, direction, sync); + if (time_after64(io_start_time, start_time)) + blkio_add_stat(stats->stat_arr[BLKIO_STAT_WAIT_TIME], + io_start_time - start_time, direction, sync); + spin_unlock_irqrestore(&blkg->stats_lock, flags); +} +EXPORT_SYMBOL_GPL(blkiocg_update_completion_stats); + +/* Merged stats are per cpu. */ +void blkiocg_update_io_merged_stats(struct blkio_group *blkg, bool direction, + bool sync) +{ + struct blkio_group_stats_cpu *stats_cpu; + unsigned long flags; /* - * Put the reference taken at the time of creation so that when all - * queues are gone, group can be destroyed. + * Disabling interrupts to provide mutual exclusion between two + * writes on same cpu. It probably is not needed for 64bit. Not + * optimizing that case yet. */ - blkg_put(blkg); + local_irq_save(flags); + + stats_cpu = this_cpu_ptr(blkg->stats_cpu); + + u64_stats_update_begin(&stats_cpu->syncp); + blkio_add_stat(stats_cpu->stat_arr_cpu[BLKIO_STAT_CPU_MERGED], 1, + direction, sync); + u64_stats_update_end(&stats_cpu->syncp); + local_irq_restore(flags); } +EXPORT_SYMBOL_GPL(blkiocg_update_io_merged_stats); -/** - * blkg_destroy_all - destroy all blkgs associated with a request_queue - * @q: request_queue of interest - * - * Destroy all blkgs associated with @q. +/* + * This function allocates the per cpu stats for blkio_group. Should be called + * from sleepable context as alloc_per_cpu() requires that. */ -static void blkg_destroy_all(struct request_queue *q) +int blkio_alloc_blkg_stats(struct blkio_group *blkg) { - struct blkcg_gq *blkg, *n; + /* Allocate memory for per cpu stats */ + blkg->stats_cpu = alloc_percpu(struct blkio_group_stats_cpu); + if (!blkg->stats_cpu) + return -ENOMEM; + return 0; +} +EXPORT_SYMBOL_GPL(blkio_alloc_blkg_stats); - lockdep_assert_held(q->queue_lock); +void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg, + struct blkio_group *blkg, void *key, dev_t dev, + enum blkio_policy_id plid) +{ + unsigned long flags; + + spin_lock_irqsave(&blkcg->lock, flags); + spin_lock_init(&blkg->stats_lock); + rcu_assign_pointer(blkg->key, key); + blkg->blkcg_id = css_id(&blkcg->css); + hlist_add_head_rcu(&blkg->blkcg_node, &blkcg->blkg_list); + blkg->plid = plid; + spin_unlock_irqrestore(&blkcg->lock, flags); + /* Need to take css reference ? */ + cgroup_path(blkcg->css.cgroup, blkg->path, sizeof(blkg->path)); + blkg->dev = dev; +} +EXPORT_SYMBOL_GPL(blkiocg_add_blkio_group); - list_for_each_entry_safe(blkg, n, &q->blkg_list, q_node) { - struct blkcg *blkcg = blkg->blkcg; +static void __blkiocg_del_blkio_group(struct blkio_group *blkg) +{ + hlist_del_init_rcu(&blkg->blkcg_node); + blkg->blkcg_id = 0; +} - spin_lock(&blkcg->lock); - blkg_destroy(blkg); - spin_unlock(&blkcg->lock); +/* + * returns 0 if blkio_group was still on cgroup list. Otherwise returns 1 + * indicating that blk_group was unhashed by the time we got to it. + */ +int blkiocg_del_blkio_group(struct blkio_group *blkg) +{ + struct blkio_cgroup *blkcg; + unsigned long flags; + struct cgroup_subsys_state *css; + int ret = 1; + + rcu_read_lock(); + css = css_lookup(&blkio_subsys, blkg->blkcg_id); + if (css) { + blkcg = container_of(css, struct blkio_cgroup, css); + spin_lock_irqsave(&blkcg->lock, flags); + if (!hlist_unhashed(&blkg->blkcg_node)) { + __blkiocg_del_blkio_group(blkg); + ret = 0; + } + spin_unlock_irqrestore(&blkcg->lock, flags); } + + rcu_read_unlock(); + return ret; } +EXPORT_SYMBOL_GPL(blkiocg_del_blkio_group); -static void blkg_rcu_free(struct rcu_head *rcu_head) +/* called under rcu_read_lock(). */ +struct blkio_group *blkiocg_lookup_group(struct blkio_cgroup *blkcg, void *key) { - blkg_free(container_of(rcu_head, struct blkcg_gq, rcu_head)); + struct blkio_group *blkg; + struct hlist_node *n; + void *__key; + + hlist_for_each_entry_rcu(blkg, n, &blkcg->blkg_list, blkcg_node) { + __key = blkg->key; + if (__key == key) + return blkg; + } + + return NULL; } +EXPORT_SYMBOL_GPL(blkiocg_lookup_group); -void __blkg_release(struct blkcg_gq *blkg) +static void blkio_reset_stats_cpu(struct blkio_group *blkg) { - /* release the extra blkcg reference this blkg has been holding */ - css_put(&blkg->blkcg->css); - + struct blkio_group_stats_cpu *stats_cpu; + int i, j, k; /* - * A group is freed in rcu manner. But having an rcu lock does not - * mean that one can access all the fields of blkg and assume these - * are valid. For example, don't try to follow throtl_data and - * request queue links. + * Note: On 64 bit arch this should not be an issue. This has the + * possibility of returning some inconsistent value on 32bit arch + * as 64bit update on 32bit is non atomic. Taking care of this + * corner case makes code very complicated, like sending IPIs to + * cpus, taking care of stats of offline cpus etc. * - * Having a reference to blkg under an rcu allows acess to only - * values local to groups like group stats and group rate limits + * reset stats is anyway more of a debug feature and this sounds a + * corner case. So I am not complicating the code yet until and + * unless this becomes a real issue. */ - call_rcu(&blkg->rcu_head, blkg_rcu_free); + for_each_possible_cpu(i) { + stats_cpu = per_cpu_ptr(blkg->stats_cpu, i); + stats_cpu->sectors = 0; + for(j = 0; j < BLKIO_STAT_CPU_NR; j++) + for (k = 0; k < BLKIO_STAT_TOTAL; k++) + stats_cpu->stat_arr_cpu[j][k] = 0; + } } -EXPORT_SYMBOL_GPL(__blkg_release); -static int blkcg_reset_stats(struct cgroup *cgroup, struct cftype *cftype, - u64 val) +static int +blkiocg_reset_stats(struct cgroup *cgroup, struct cftype *cftype, u64 val) { - struct blkcg *blkcg = cgroup_to_blkcg(cgroup); - struct blkcg_gq *blkg; + struct blkio_cgroup *blkcg; + struct blkio_group *blkg; + struct blkio_group_stats *stats; struct hlist_node *n; + uint64_t queued[BLKIO_STAT_TOTAL]; int i; +#ifdef CONFIG_DEBUG_BLK_CGROUP + bool idling, waiting, empty; + unsigned long long now = sched_clock(); +#endif - mutex_lock(&blkcg_pol_mutex); + blkcg = cgroup_to_blkio_cgroup(cgroup); spin_lock_irq(&blkcg->lock); - - /* - * Note that stat reset is racy - it doesn't synchronize against - * stat updates. This is a debug feature which shouldn't exist - * anyway. If you get hit by a race, retry. - */ hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) { - for (i = 0; i < BLKCG_MAX_POLS; i++) { - struct blkcg_policy *pol = blkcg_policy[i]; - - if (blkcg_policy_enabled(blkg->q, pol) && - pol->pd_reset_stats_fn) - pol->pd_reset_stats_fn(blkg); + spin_lock(&blkg->stats_lock); + stats = &blkg->stats; +#ifdef CONFIG_DEBUG_BLK_CGROUP + idling = blkio_blkg_idling(stats); + waiting = blkio_blkg_waiting(stats); + empty = blkio_blkg_empty(stats); +#endif + for (i = 0; i < BLKIO_STAT_TOTAL; i++) + queued[i] = stats->stat_arr[BLKIO_STAT_QUEUED][i]; + memset(stats, 0, sizeof(struct blkio_group_stats)); + for (i = 0; i < BLKIO_STAT_TOTAL; i++) + stats->stat_arr[BLKIO_STAT_QUEUED][i] = queued[i]; +#ifdef CONFIG_DEBUG_BLK_CGROUP + if (idling) { + blkio_mark_blkg_idling(stats); + stats->start_idle_time = now; + } + if (waiting) { + blkio_mark_blkg_waiting(stats); + stats->start_group_wait_time = now; } + if (empty) { + blkio_mark_blkg_empty(stats); + stats->start_empty_time = now; + } +#endif + spin_unlock(&blkg->stats_lock); + + /* Reset Per cpu stats which don't take blkg->stats_lock */ + blkio_reset_stats_cpu(blkg); } spin_unlock_irq(&blkcg->lock); - mutex_unlock(&blkcg_pol_mutex); return 0; } -static const char *blkg_dev_name(struct blkcg_gq *blkg) +static void blkio_get_key_name(enum stat_sub_type type, dev_t dev, char *str, + int chars_left, bool diskname_only) { - /* some drivers (floppy) instantiate a queue w/o disk registered */ - if (blkg->q->backing_dev_info.dev) - return dev_name(blkg->q->backing_dev_info.dev); - return NULL; + snprintf(str, chars_left, "%d:%d", MAJOR(dev), MINOR(dev)); + chars_left -= strlen(str); + if (chars_left <= 0) { + printk(KERN_WARNING + "Possibly incorrect cgroup stat display format"); + return; + } + if (diskname_only) + return; + switch (type) { + case BLKIO_STAT_READ: + strlcat(str, " Read", chars_left); + break; + case BLKIO_STAT_WRITE: + strlcat(str, " Write", chars_left); + break; + case BLKIO_STAT_SYNC: + strlcat(str, " Sync", chars_left); + break; + case BLKIO_STAT_ASYNC: + strlcat(str, " Async", chars_left); + break; + case BLKIO_STAT_TOTAL: + strlcat(str, " Total", chars_left); + break; + default: + strlcat(str, " Invalid", chars_left); + } } -/** - * blkcg_print_blkgs - helper for printing per-blkg data - * @sf: seq_file to print to - * @blkcg: blkcg of interest - * @prfill: fill function to print out a blkg - * @pol: policy in question - * @data: data to be passed to @prfill - * @show_total: to print out sum of prfill return values or not - * - * This function invokes @prfill on each blkg of @blkcg if pd for the - * policy specified by @pol exists. @prfill is invoked with @sf, the - * policy data and @data. If @show_total is %true, the sum of the return - * values from @prfill is printed with "Total" label at the end. - * - * This is to be used to construct print functions for - * cftype->read_seq_string method. - */ -void blkcg_print_blkgs(struct seq_file *sf, struct blkcg *blkcg, - u64 (*prfill)(struct seq_file *, - struct blkg_policy_data *, int), - const struct blkcg_policy *pol, int data, - bool show_total) +static uint64_t blkio_fill_stat(char *str, int chars_left, uint64_t val, + struct cgroup_map_cb *cb, dev_t dev) { - struct blkcg_gq *blkg; - struct hlist_node *n; - u64 total = 0; - - spin_lock_irq(&blkcg->lock); - hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) - if (blkcg_policy_enabled(blkg->q, pol)) - total += prfill(sf, blkg->pd[pol->plid], data); - spin_unlock_irq(&blkcg->lock); - - if (show_total) - seq_printf(sf, "Total %llu\n", (unsigned long long)total); + blkio_get_key_name(0, dev, str, chars_left, true); + cb->fill(cb, str, val); + return val; } -EXPORT_SYMBOL_GPL(blkcg_print_blkgs); -/** - * __blkg_prfill_u64 - prfill helper for a single u64 value - * @sf: seq_file to print to - * @pd: policy private data of interest - * @v: value to print - * - * Print @v to @sf for the device assocaited with @pd. - */ -u64 __blkg_prfill_u64(struct seq_file *sf, struct blkg_policy_data *pd, u64 v) -{ - const char *dname = blkg_dev_name(pd->blkg); - if (!dname) - return 0; +static uint64_t blkio_read_stat_cpu(struct blkio_group *blkg, + enum stat_type_cpu type, enum stat_sub_type sub_type) +{ + int cpu; + struct blkio_group_stats_cpu *stats_cpu; + u64 val = 0, tval; + + for_each_possible_cpu(cpu) { + unsigned int start; + stats_cpu = per_cpu_ptr(blkg->stats_cpu, cpu); + + do { + start = u64_stats_fetch_begin(&stats_cpu->syncp); + if (type == BLKIO_STAT_CPU_SECTORS) + tval = stats_cpu->sectors; + else + tval = stats_cpu->stat_arr_cpu[type][sub_type]; + } while(u64_stats_fetch_retry(&stats_cpu->syncp, start)); + + val += tval; + } - seq_printf(sf, "%s %llu\n", dname, (unsigned long long)v); - return v; + return val; } -EXPORT_SYMBOL_GPL(__blkg_prfill_u64); -/** - * __blkg_prfill_rwstat - prfill helper for a blkg_rwstat - * @sf: seq_file to print to - * @pd: policy private data of interest - * @rwstat: rwstat to print - * - * Print @rwstat to @sf for the device assocaited with @pd. - */ -u64 __blkg_prfill_rwstat(struct seq_file *sf, struct blkg_policy_data *pd, - const struct blkg_rwstat *rwstat) -{ - static const char *rwstr[] = { - [BLKG_RWSTAT_READ] = "Read", - [BLKG_RWSTAT_WRITE] = "Write", - [BLKG_RWSTAT_SYNC] = "Sync", - [BLKG_RWSTAT_ASYNC] = "Async", - }; - const char *dname = blkg_dev_name(pd->blkg); - u64 v; - int i; +static uint64_t blkio_get_stat_cpu(struct blkio_group *blkg, + struct cgroup_map_cb *cb, dev_t dev, enum stat_type_cpu type) +{ + uint64_t disk_total, val; + char key_str[MAX_KEY_LEN]; + enum stat_sub_type sub_type; + + if (type == BLKIO_STAT_CPU_SECTORS) { + val = blkio_read_stat_cpu(blkg, type, 0); + return blkio_fill_stat(key_str, MAX_KEY_LEN - 1, val, cb, dev); + } - if (!dname) - return 0; + for (sub_type = BLKIO_STAT_READ; sub_type < BLKIO_STAT_TOTAL; + sub_type++) { + blkio_get_key_name(sub_type, dev, key_str, MAX_KEY_LEN, false); + val = blkio_read_stat_cpu(blkg, type, sub_type); + cb->fill(cb, key_str, val); + } - for (i = 0; i < BLKG_RWSTAT_NR; i++) - seq_printf(sf, "%s %s %llu\n", dname, rwstr[i], - (unsigned long long)rwstat->cnt[i]); + disk_total = blkio_read_stat_cpu(blkg, type, BLKIO_STAT_READ) + + blkio_read_stat_cpu(blkg, type, BLKIO_STAT_WRITE); - v = rwstat->cnt[BLKG_RWSTAT_READ] + rwstat->cnt[BLKG_RWSTAT_WRITE]; - seq_printf(sf, "%s Total %llu\n", dname, (unsigned long long)v); - return v; + blkio_get_key_name(BLKIO_STAT_TOTAL, dev, key_str, MAX_KEY_LEN, false); + cb->fill(cb, key_str, disk_total); + return disk_total; } -/** - * blkg_prfill_stat - prfill callback for blkg_stat - * @sf: seq_file to print to - * @pd: policy private data of interest - * @off: offset to the blkg_stat in @pd - * - * prfill callback for printing a blkg_stat. - */ -u64 blkg_prfill_stat(struct seq_file *sf, struct blkg_policy_data *pd, int off) +/* This should be called with blkg->stats_lock held */ +static uint64_t blkio_get_stat(struct blkio_group *blkg, + struct cgroup_map_cb *cb, dev_t dev, enum stat_type type) { - return __blkg_prfill_u64(sf, pd, blkg_stat_read((void *)pd + off)); + uint64_t disk_total; + char key_str[MAX_KEY_LEN]; + enum stat_sub_type sub_type; + + if (type == BLKIO_STAT_TIME) + return blkio_fill_stat(key_str, MAX_KEY_LEN - 1, + blkg->stats.time, cb, dev); +#ifdef CONFIG_DEBUG_BLK_CGROUP + if (type == BLKIO_STAT_UNACCOUNTED_TIME) + return blkio_fill_stat(key_str, MAX_KEY_LEN - 1, + blkg->stats.unaccounted_time, cb, dev); + if (type == BLKIO_STAT_AVG_QUEUE_SIZE) { + uint64_t sum = blkg->stats.avg_queue_size_sum; + uint64_t samples = blkg->stats.avg_queue_size_samples; + if (samples) + do_div(sum, samples); + else + sum = 0; + return blkio_fill_stat(key_str, MAX_KEY_LEN - 1, sum, cb, dev); + } + if (type == BLKIO_STAT_GROUP_WAIT_TIME) + return blkio_fill_stat(key_str, MAX_KEY_LEN - 1, + blkg->stats.group_wait_time, cb, dev); + if (type == BLKIO_STAT_IDLE_TIME) + return blkio_fill_stat(key_str, MAX_KEY_LEN - 1, + blkg->stats.idle_time, cb, dev); + if (type == BLKIO_STAT_EMPTY_TIME) + return blkio_fill_stat(key_str, MAX_KEY_LEN - 1, + blkg->stats.empty_time, cb, dev); + if (type == BLKIO_STAT_DEQUEUE) + return blkio_fill_stat(key_str, MAX_KEY_LEN - 1, + blkg->stats.dequeue, cb, dev); +#endif + + for (sub_type = BLKIO_STAT_READ; sub_type < BLKIO_STAT_TOTAL; + sub_type++) { + blkio_get_key_name(sub_type, dev, key_str, MAX_KEY_LEN, false); + cb->fill(cb, key_str, blkg->stats.stat_arr[type][sub_type]); + } + disk_total = blkg->stats.stat_arr[type][BLKIO_STAT_READ] + + blkg->stats.stat_arr[type][BLKIO_STAT_WRITE]; + blkio_get_key_name(BLKIO_STAT_TOTAL, dev, key_str, MAX_KEY_LEN, false); + cb->fill(cb, key_str, disk_total); + return disk_total; } -EXPORT_SYMBOL_GPL(blkg_prfill_stat); -/** - * blkg_prfill_rwstat - prfill callback for blkg_rwstat - * @sf: seq_file to print to - * @pd: policy private data of interest - * @off: offset to the blkg_rwstat in @pd - * - * prfill callback for printing a blkg_rwstat. - */ -u64 blkg_prfill_rwstat(struct seq_file *sf, struct blkg_policy_data *pd, - int off) +static int blkio_policy_parse_and_set(char *buf, + struct blkio_policy_node *newpn, enum blkio_policy_id plid, int fileid) { - struct blkg_rwstat rwstat = blkg_rwstat_read((void *)pd + off); + struct gendisk *disk = NULL; + char *s[4], *p, *major_s = NULL, *minor_s = NULL; + unsigned long major, minor; + int i = 0, ret = -EINVAL; + int part; + dev_t dev; + u64 temp; + + memset(s, 0, sizeof(s)); + + while ((p = strsep(&buf, " ")) != NULL) { + if (!*p) + continue; - return __blkg_prfill_rwstat(sf, pd, &rwstat); + s[i++] = p; + + /* Prevent from inputing too many things */ + if (i == 3) + break; + } + + if (i != 2) + goto out; + + p = strsep(&s[0], ":"); + if (p != NULL) + major_s = p; + else + goto out; + + minor_s = s[0]; + if (!minor_s) + goto out; + + if (strict_strtoul(major_s, 10, &major)) + goto out; + + if (strict_strtoul(minor_s, 10, &minor)) + goto out; + + dev = MKDEV(major, minor); + + if (strict_strtoull(s[1], 10, &temp)) + goto out; + + /* For rule removal, do not check for device presence. */ + if (temp) { + disk = get_gendisk(dev, &part); + if (!disk || part) { + ret = -ENODEV; + goto out; + } + } + + newpn->dev = dev; + + switch (plid) { + case BLKIO_POLICY_PROP: + if ((temp < BLKIO_WEIGHT_MIN && temp > 0) || + temp > BLKIO_WEIGHT_MAX) + goto out; + + newpn->plid = plid; + newpn->fileid = fileid; + newpn->val.weight = temp; + break; + case BLKIO_POLICY_THROTL: + switch(fileid) { + case BLKIO_THROTL_read_bps_device: + case BLKIO_THROTL_write_bps_device: + newpn->plid = plid; + newpn->fileid = fileid; + newpn->val.bps = temp; + break; + case BLKIO_THROTL_read_iops_device: + case BLKIO_THROTL_write_iops_device: + if (temp > THROTL_IOPS_MAX) + goto out; + + newpn->plid = plid; + newpn->fileid = fileid; + newpn->val.iops = (unsigned int)temp; + break; + } + break; + default: + BUG(); + } + ret = 0; +out: + put_disk(disk); + return ret; } -EXPORT_SYMBOL_GPL(blkg_prfill_rwstat); -/** - * blkg_conf_prep - parse and prepare for per-blkg config update - * @blkcg: target block cgroup - * @pol: target policy - * @input: input string - * @ctx: blkg_conf_ctx to be filled - * - * Parse per-blkg config update from @input and initialize @ctx with the - * result. @ctx->blkg points to the blkg to be updated and @ctx->v the new - * value. This function returns with RCU read lock and queue lock held and - * must be paired with blkg_conf_finish(). - */ -int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol, - const char *input, struct blkg_conf_ctx *ctx) - __acquires(rcu) __acquires(disk->queue->queue_lock) +unsigned int blkcg_get_weight(struct blkio_cgroup *blkcg, + dev_t dev) { - struct gendisk *disk; - struct blkcg_gq *blkg; - unsigned int major, minor; - unsigned long long v; - int part, ret; + struct blkio_policy_node *pn; + unsigned long flags; + unsigned int weight; - if (sscanf(input, "%u:%u %llu", &major, &minor, &v) != 3) - return -EINVAL; + spin_lock_irqsave(&blkcg->lock, flags); - disk = get_gendisk(MKDEV(major, minor), &part); - if (!disk || part) - return -EINVAL; + pn = blkio_policy_search_node(blkcg, dev, BLKIO_POLICY_PROP, + BLKIO_PROP_weight_device); + if (pn) + weight = pn->val.weight; + else + weight = blkcg->weight; - rcu_read_lock(); - spin_lock_irq(disk->queue->queue_lock); + spin_unlock_irqrestore(&blkcg->lock, flags); - if (blkcg_policy_enabled(disk->queue, pol)) - blkg = blkg_lookup_create(blkcg, disk->queue); - else - blkg = ERR_PTR(-EINVAL); + return weight; +} +EXPORT_SYMBOL_GPL(blkcg_get_weight); - if (IS_ERR(blkg)) { - ret = PTR_ERR(blkg); - rcu_read_unlock(); - spin_unlock_irq(disk->queue->queue_lock); - put_disk(disk); - /* - * If queue was bypassing, we should retry. Do so after a - * short msleep(). It isn't strictly necessary but queue - * can be bypassing for some time and it's always nice to - * avoid busy looping. - */ - if (ret == -EBUSY) { - msleep(10); - ret = restart_syscall(); +uint64_t blkcg_get_read_bps(struct blkio_cgroup *blkcg, dev_t dev) +{ + struct blkio_policy_node *pn; + unsigned long flags; + uint64_t bps = -1; + + spin_lock_irqsave(&blkcg->lock, flags); + pn = blkio_policy_search_node(blkcg, dev, BLKIO_POLICY_THROTL, + BLKIO_THROTL_read_bps_device); + if (pn) + bps = pn->val.bps; + spin_unlock_irqrestore(&blkcg->lock, flags); + + return bps; +} + +uint64_t blkcg_get_write_bps(struct blkio_cgroup *blkcg, dev_t dev) +{ + struct blkio_policy_node *pn; + unsigned long flags; + uint64_t bps = -1; + + spin_lock_irqsave(&blkcg->lock, flags); + pn = blkio_policy_search_node(blkcg, dev, BLKIO_POLICY_THROTL, + BLKIO_THROTL_write_bps_device); + if (pn) + bps = pn->val.bps; + spin_unlock_irqrestore(&blkcg->lock, flags); + + return bps; +} + +unsigned int blkcg_get_read_iops(struct blkio_cgroup *blkcg, dev_t dev) +{ + struct blkio_policy_node *pn; + unsigned long flags; + unsigned int iops = -1; + + spin_lock_irqsave(&blkcg->lock, flags); + pn = blkio_policy_search_node(blkcg, dev, BLKIO_POLICY_THROTL, + BLKIO_THROTL_read_iops_device); + if (pn) + iops = pn->val.iops; + spin_unlock_irqrestore(&blkcg->lock, flags); + + return iops; +} + +unsigned int blkcg_get_write_iops(struct blkio_cgroup *blkcg, dev_t dev) +{ + struct blkio_policy_node *pn; + unsigned long flags; + unsigned int iops = -1; + + spin_lock_irqsave(&blkcg->lock, flags); + pn = blkio_policy_search_node(blkcg, dev, BLKIO_POLICY_THROTL, + BLKIO_THROTL_write_iops_device); + if (pn) + iops = pn->val.iops; + spin_unlock_irqrestore(&blkcg->lock, flags); + + return iops; +} + +/* Checks whether user asked for deleting a policy rule */ +static bool blkio_delete_rule_command(struct blkio_policy_node *pn) +{ + switch(pn->plid) { + case BLKIO_POLICY_PROP: + if (pn->val.weight == 0) + return 1; + break; + case BLKIO_POLICY_THROTL: + switch(pn->fileid) { + case BLKIO_THROTL_read_bps_device: + case BLKIO_THROTL_write_bps_device: + if (pn->val.bps == 0) + return 1; + break; + case BLKIO_THROTL_read_iops_device: + case BLKIO_THROTL_write_iops_device: + if (pn->val.iops == 0) + return 1; } - return ret; + break; + default: + BUG(); } - ctx->disk = disk; - ctx->blkg = blkg; - ctx->v = v; return 0; } -EXPORT_SYMBOL_GPL(blkg_conf_prep); -/** - * blkg_conf_finish - finish up per-blkg config update - * @ctx: blkg_conf_ctx intiailized by blkg_conf_prep() - * - * Finish up after per-blkg config update. This function must be paired - * with blkg_conf_prep(). - */ -void blkg_conf_finish(struct blkg_conf_ctx *ctx) - __releases(ctx->disk->queue->queue_lock) __releases(rcu) +static void blkio_update_policy_rule(struct blkio_policy_node *oldpn, + struct blkio_policy_node *newpn) { - spin_unlock_irq(ctx->disk->queue->queue_lock); - rcu_read_unlock(); - put_disk(ctx->disk); + switch(oldpn->plid) { + case BLKIO_POLICY_PROP: + oldpn->val.weight = newpn->val.weight; + break; + case BLKIO_POLICY_THROTL: + switch(newpn->fileid) { + case BLKIO_THROTL_read_bps_device: + case BLKIO_THROTL_write_bps_device: + oldpn->val.bps = newpn->val.bps; + break; + case BLKIO_THROTL_read_iops_device: + case BLKIO_THROTL_write_iops_device: + oldpn->val.iops = newpn->val.iops; + } + break; + default: + BUG(); + } } -EXPORT_SYMBOL_GPL(blkg_conf_finish); -struct cftype blkcg_files[] = { - { - .name = "reset_stats", - .write_u64 = blkcg_reset_stats, - }, - { } /* terminate */ -}; +/* + * Some rules/values in blkg have changed. Propagate those to respective + * policies. + */ +static void blkio_update_blkg_policy(struct blkio_cgroup *blkcg, + struct blkio_group *blkg, struct blkio_policy_node *pn) +{ + unsigned int weight, iops; + u64 bps; + + switch(pn->plid) { + case BLKIO_POLICY_PROP: + weight = pn->val.weight ? pn->val.weight : + blkcg->weight; + blkio_update_group_weight(blkg, weight); + break; + case BLKIO_POLICY_THROTL: + switch(pn->fileid) { + case BLKIO_THROTL_read_bps_device: + case BLKIO_THROTL_write_bps_device: + bps = pn->val.bps ? pn->val.bps : (-1); + blkio_update_group_bps(blkg, bps, pn->fileid); + break; + case BLKIO_THROTL_read_iops_device: + case BLKIO_THROTL_write_iops_device: + iops = pn->val.iops ? pn->val.iops : (-1); + blkio_update_group_iops(blkg, iops, pn->fileid); + break; + } + break; + default: + BUG(); + } +} -/** - * blkcg_pre_destroy - cgroup pre_destroy callback - * @cgroup: cgroup of interest - * - * This function is called when @cgroup is about to go away and responsible - * for shooting down all blkgs associated with @cgroup. blkgs should be - * removed while holding both q and blkcg locks. As blkcg lock is nested - * inside q lock, this function performs reverse double lock dancing. - * - * This is the blkcg counterpart of ioc_release_fn(). +/* + * A policy node rule has been updated. Propagate this update to all the + * block groups which might be affected by this update. */ -static int blkcg_pre_destroy(struct cgroup *cgroup) +static void blkio_update_policy_node_blkg(struct blkio_cgroup *blkcg, + struct blkio_policy_node *pn) { - struct blkcg *blkcg = cgroup_to_blkcg(cgroup); + struct blkio_group *blkg; + struct hlist_node *n; + spin_lock(&blkio_list_lock); spin_lock_irq(&blkcg->lock); - while (!hlist_empty(&blkcg->blkg_list)) { - struct blkcg_gq *blkg = hlist_entry(blkcg->blkg_list.first, - struct blkcg_gq, blkcg_node); - struct request_queue *q = blkg->q; - - if (spin_trylock(q->queue_lock)) { - blkg_destroy(blkg); - spin_unlock(q->queue_lock); - } else { - spin_unlock_irq(&blkcg->lock); - cpu_relax(); - spin_lock_irq(&blkcg->lock); - } + hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) { + if (pn->dev != blkg->dev || pn->plid != blkg->plid) + continue; + blkio_update_blkg_policy(blkcg, blkg, pn); } spin_unlock_irq(&blkcg->lock); - return 0; + spin_unlock(&blkio_list_lock); } -static void blkcg_destroy(struct cgroup *cgroup) +static int blkiocg_file_write(struct cgroup *cgrp, struct cftype *cft, + const char *buffer) { - struct blkcg *blkcg = cgroup_to_blkcg(cgroup); + int ret = 0; + char *buf; + struct blkio_policy_node *newpn, *pn; + struct blkio_cgroup *blkcg; + int keep_newpn = 0; + enum blkio_policy_id plid = BLKIOFILE_POLICY(cft->private); + int fileid = BLKIOFILE_ATTR(cft->private); + + buf = kstrdup(buffer, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + newpn = kzalloc(sizeof(*newpn), GFP_KERNEL); + if (!newpn) { + ret = -ENOMEM; + goto free_buf; + } - if (blkcg != &blkcg_root) - kfree(blkcg); -} + ret = blkio_policy_parse_and_set(buf, newpn, plid, fileid); + if (ret) + goto free_newpn; -static struct cgroup_subsys_state *blkcg_create(struct cgroup *cgroup) -{ - static atomic64_t id_seq = ATOMIC64_INIT(0); - struct blkcg *blkcg; - struct cgroup *parent = cgroup->parent; + blkcg = cgroup_to_blkio_cgroup(cgrp); - if (!parent) { - blkcg = &blkcg_root; - goto done; + spin_lock_irq(&blkcg->lock); + + pn = blkio_policy_search_node(blkcg, newpn->dev, plid, fileid); + if (!pn) { + if (!blkio_delete_rule_command(newpn)) { + blkio_policy_insert_node(blkcg, newpn); + keep_newpn = 1; + } + spin_unlock_irq(&blkcg->lock); + goto update_io_group; } - blkcg = kzalloc(sizeof(*blkcg), GFP_KERNEL); - if (!blkcg) - return ERR_PTR(-ENOMEM); + if (blkio_delete_rule_command(newpn)) { + blkio_policy_delete_node(pn); + kfree(pn); + spin_unlock_irq(&blkcg->lock); + goto update_io_group; + } + spin_unlock_irq(&blkcg->lock); - blkcg->cfq_weight = CFQ_WEIGHT_DEFAULT; - blkcg->id = atomic64_inc_return(&id_seq); /* root is 0, start from 1 */ -done: - spin_lock_init(&blkcg->lock); - INIT_RADIX_TREE(&blkcg->blkg_tree, GFP_ATOMIC); - INIT_HLIST_HEAD(&blkcg->blkg_list); + blkio_update_policy_rule(pn, newpn); - return &blkcg->css; +update_io_group: + blkio_update_policy_node_blkg(blkcg, newpn); + +free_newpn: + if (!keep_newpn) + kfree(newpn); +free_buf: + kfree(buf); + return ret; } -/** - * blkcg_init_queue - initialize blkcg part of request queue - * @q: request_queue to initialize - * - * Called from blk_alloc_queue_node(). Responsible for initializing blkcg - * part of new request_queue @q. - * - * RETURNS: - * 0 on success, -errno on failure. - */ -int blkcg_init_queue(struct request_queue *q) +static void +blkio_print_policy_node(struct seq_file *m, struct blkio_policy_node *pn) { - might_sleep(); - - return blk_throtl_init(q); + switch(pn->plid) { + case BLKIO_POLICY_PROP: + if (pn->fileid == BLKIO_PROP_weight_device) + seq_printf(m, "%u:%u\t%u\n", MAJOR(pn->dev), + MINOR(pn->dev), pn->val.weight); + break; + case BLKIO_POLICY_THROTL: + switch(pn->fileid) { + case BLKIO_THROTL_read_bps_device: + case BLKIO_THROTL_write_bps_device: + seq_printf(m, "%u:%u\t%llu\n", MAJOR(pn->dev), + MINOR(pn->dev), pn->val.bps); + break; + case BLKIO_THROTL_read_iops_device: + case BLKIO_THROTL_write_iops_device: + seq_printf(m, "%u:%u\t%u\n", MAJOR(pn->dev), + MINOR(pn->dev), pn->val.iops); + break; + } + break; + default: + BUG(); + } } -/** - * blkcg_drain_queue - drain blkcg part of request_queue - * @q: request_queue to drain - * - * Called from blk_drain_queue(). Responsible for draining blkcg part. - */ -void blkcg_drain_queue(struct request_queue *q) +/* cgroup files which read their data from policy nodes end up here */ +static void blkio_read_policy_node_files(struct cftype *cft, + struct blkio_cgroup *blkcg, struct seq_file *m) { - lockdep_assert_held(q->queue_lock); - - blk_throtl_drain(q); + struct blkio_policy_node *pn; + + if (!list_empty(&blkcg->policy_list)) { + spin_lock_irq(&blkcg->lock); + list_for_each_entry(pn, &blkcg->policy_list, node) { + if (!pn_matches_cftype(cft, pn)) + continue; + blkio_print_policy_node(m, pn); + } + spin_unlock_irq(&blkcg->lock); + } } -/** - * blkcg_exit_queue - exit and release blkcg part of request_queue - * @q: request_queue being released - * - * Called from blk_release_queue(). Responsible for exiting blkcg part. - */ -void blkcg_exit_queue(struct request_queue *q) +static int blkiocg_file_read(struct cgroup *cgrp, struct cftype *cft, + struct seq_file *m) { - spin_lock_irq(q->queue_lock); - blkg_destroy_all(q); - spin_unlock_irq(q->queue_lock); + struct blkio_cgroup *blkcg; + enum blkio_policy_id plid = BLKIOFILE_POLICY(cft->private); + int name = BLKIOFILE_ATTR(cft->private); + + blkcg = cgroup_to_blkio_cgroup(cgrp); + + switch(plid) { + case BLKIO_POLICY_PROP: + switch(name) { + case BLKIO_PROP_weight_device: + blkio_read_policy_node_files(cft, blkcg, m); + return 0; + default: + BUG(); + } + break; + case BLKIO_POLICY_THROTL: + switch(name){ + case BLKIO_THROTL_read_bps_device: + case BLKIO_THROTL_write_bps_device: + case BLKIO_THROTL_read_iops_device: + case BLKIO_THROTL_write_iops_device: + blkio_read_policy_node_files(cft, blkcg, m); + return 0; + default: + BUG(); + } + break; + default: + BUG(); + } - blk_throtl_exit(q); + return 0; } -/* - * We cannot support shared io contexts, as we have no mean to support - * two tasks with the same ioc in two different groups without major rework - * of the main cic data structures. For now we allow a task to change - * its cgroup only if it's the only owner of its ioc. - */ -static int blkcg_can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) +static int blkio_read_blkg_stats(struct blkio_cgroup *blkcg, + struct cftype *cft, struct cgroup_map_cb *cb, + enum stat_type type, bool show_total, bool pcpu) { - struct task_struct *task; - struct io_context *ioc; - int ret = 0; + struct blkio_group *blkg; + struct hlist_node *n; + uint64_t cgroup_total = 0; - /* task_lock() is needed to avoid races with exit_io_context() */ - cgroup_taskset_for_each(task, cgrp, tset) { - task_lock(task); - ioc = task->io_context; - if (ioc && atomic_read(&ioc->nr_tasks) > 1) - ret = -EINVAL; - task_unlock(task); - if (ret) - break; + rcu_read_lock(); + hlist_for_each_entry_rcu(blkg, n, &blkcg->blkg_list, blkcg_node) { + if (blkg->dev) { + if (!cftype_blkg_same_policy(cft, blkg)) + continue; + if (pcpu) + cgroup_total += blkio_get_stat_cpu(blkg, cb, + blkg->dev, type); + else { + spin_lock_irq(&blkg->stats_lock); + cgroup_total += blkio_get_stat(blkg, cb, + blkg->dev, type); + spin_unlock_irq(&blkg->stats_lock); + } + } } - return ret; + if (show_total) + cb->fill(cb, "Total", cgroup_total); + rcu_read_unlock(); + return 0; } -struct cgroup_subsys blkio_subsys = { - .name = "blkio", - .create = blkcg_create, - .can_attach = blkcg_can_attach, - .pre_destroy = blkcg_pre_destroy, - .destroy = blkcg_destroy, - .subsys_id = blkio_subsys_id, - .base_cftypes = blkcg_files, - .module = THIS_MODULE, -}; -EXPORT_SYMBOL_GPL(blkio_subsys); - -/** - * blkcg_activate_policy - activate a blkcg policy on a request_queue - * @q: request_queue of interest - * @pol: blkcg policy to activate - * - * Activate @pol on @q. Requires %GFP_KERNEL context. @q goes through - * bypass mode to populate its blkgs with policy_data for @pol. - * - * Activation happens with @q bypassed, so nobody would be accessing blkgs - * from IO path. Update of each blkg is protected by both queue and blkcg - * locks so that holding either lock and testing blkcg_policy_enabled() is - * always enough for dereferencing policy data. - * - * The caller is responsible for synchronizing [de]activations and policy - * [un]registerations. Returns 0 on success, -errno on failure. - */ -int blkcg_activate_policy(struct request_queue *q, - const struct blkcg_policy *pol) +/* All map kind of cgroup file get serviced by this function */ +static int blkiocg_file_read_map(struct cgroup *cgrp, struct cftype *cft, + struct cgroup_map_cb *cb) { - LIST_HEAD(pds); - struct blkcg_gq *blkg; - struct blkg_policy_data *pd, *n; - int cnt = 0, ret; + struct blkio_cgroup *blkcg; + enum blkio_policy_id plid = BLKIOFILE_POLICY(cft->private); + int name = BLKIOFILE_ATTR(cft->private); + + blkcg = cgroup_to_blkio_cgroup(cgrp); + + switch(plid) { + case BLKIO_POLICY_PROP: + switch(name) { + case BLKIO_PROP_time: + return blkio_read_blkg_stats(blkcg, cft, cb, + BLKIO_STAT_TIME, 0, 0); + case BLKIO_PROP_sectors: + return blkio_read_blkg_stats(blkcg, cft, cb, + BLKIO_STAT_CPU_SECTORS, 0, 1); + case BLKIO_PROP_io_service_bytes: + return blkio_read_blkg_stats(blkcg, cft, cb, + BLKIO_STAT_CPU_SERVICE_BYTES, 1, 1); + case BLKIO_PROP_io_serviced: + return blkio_read_blkg_stats(blkcg, cft, cb, + BLKIO_STAT_CPU_SERVICED, 1, 1); + case BLKIO_PROP_io_service_time: + return blkio_read_blkg_stats(blkcg, cft, cb, + BLKIO_STAT_SERVICE_TIME, 1, 0); + case BLKIO_PROP_io_wait_time: + return blkio_read_blkg_stats(blkcg, cft, cb, + BLKIO_STAT_WAIT_TIME, 1, 0); + case BLKIO_PROP_io_merged: + return blkio_read_blkg_stats(blkcg, cft, cb, + BLKIO_STAT_CPU_MERGED, 1, 1); + case BLKIO_PROP_io_queued: + return blkio_read_blkg_stats(blkcg, cft, cb, + BLKIO_STAT_QUEUED, 1, 0); +#ifdef CONFIG_DEBUG_BLK_CGROUP + case BLKIO_PROP_unaccounted_time: + return blkio_read_blkg_stats(blkcg, cft, cb, + BLKIO_STAT_UNACCOUNTED_TIME, 0, 0); + case BLKIO_PROP_dequeue: + return blkio_read_blkg_stats(blkcg, cft, cb, + BLKIO_STAT_DEQUEUE, 0, 0); + case BLKIO_PROP_avg_queue_size: + return blkio_read_blkg_stats(blkcg, cft, cb, + BLKIO_STAT_AVG_QUEUE_SIZE, 0, 0); + case BLKIO_PROP_group_wait_time: + return blkio_read_blkg_stats(blkcg, cft, cb, + BLKIO_STAT_GROUP_WAIT_TIME, 0, 0); + case BLKIO_PROP_idle_time: + return blkio_read_blkg_stats(blkcg, cft, cb, + BLKIO_STAT_IDLE_TIME, 0, 0); + case BLKIO_PROP_empty_time: + return blkio_read_blkg_stats(blkcg, cft, cb, + BLKIO_STAT_EMPTY_TIME, 0, 0); +#endif + default: + BUG(); + } + break; + case BLKIO_POLICY_THROTL: + switch(name){ + case BLKIO_THROTL_io_service_bytes: + return blkio_read_blkg_stats(blkcg, cft, cb, + BLKIO_STAT_CPU_SERVICE_BYTES, 1, 1); + case BLKIO_THROTL_io_serviced: + return blkio_read_blkg_stats(blkcg, cft, cb, + BLKIO_STAT_CPU_SERVICED, 1, 1); + default: + BUG(); + } + break; + default: + BUG(); + } - if (blkcg_policy_enabled(q, pol)) - return 0; + return 0; +} - blk_queue_bypass_start(q); +static int blkio_weight_write(struct blkio_cgroup *blkcg, u64 val) +{ + struct blkio_group *blkg; + struct hlist_node *n; + struct blkio_policy_node *pn; - /* make sure the root blkg exists and count the existing blkgs */ - spin_lock_irq(q->queue_lock); + if (val < BLKIO_WEIGHT_MIN || val > BLKIO_WEIGHT_MAX) + return -EINVAL; - rcu_read_lock(); - blkg = __blkg_lookup_create(&blkcg_root, q); - rcu_read_unlock(); + spin_lock(&blkio_list_lock); + spin_lock_irq(&blkcg->lock); + blkcg->weight = (unsigned int)val; - if (IS_ERR(blkg)) { - ret = PTR_ERR(blkg); - goto out_unlock; + hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) { + pn = blkio_policy_search_node(blkcg, blkg->dev, + BLKIO_POLICY_PROP, BLKIO_PROP_weight_device); + if (pn) + continue; + + blkio_update_group_weight(blkg, blkcg->weight); } - q->root_blkg = blkg; + spin_unlock_irq(&blkcg->lock); + spin_unlock(&blkio_list_lock); + return 0; +} - list_for_each_entry(blkg, &q->blkg_list, q_node) - cnt++; +static u64 blkiocg_file_read_u64 (struct cgroup *cgrp, struct cftype *cft) { + struct blkio_cgroup *blkcg; + enum blkio_policy_id plid = BLKIOFILE_POLICY(cft->private); + int name = BLKIOFILE_ATTR(cft->private); - spin_unlock_irq(q->queue_lock); + blkcg = cgroup_to_blkio_cgroup(cgrp); - /* allocate policy_data for all existing blkgs */ - while (cnt--) { - pd = kzalloc_node(pol->pd_size, GFP_KERNEL, q->node); - if (!pd) { - ret = -ENOMEM; - goto out_free; + switch(plid) { + case BLKIO_POLICY_PROP: + switch(name) { + case BLKIO_PROP_weight: + return (u64)blkcg->weight; } - list_add_tail(&pd->alloc_node, &pds); + break; + default: + BUG(); } + return 0; +} - /* - * Install the allocated pds. With @q bypassing, no new blkg - * should have been created while the queue lock was dropped. - */ - spin_lock_irq(q->queue_lock); +static int +blkiocg_file_write_u64(struct cgroup *cgrp, struct cftype *cft, u64 val) +{ + struct blkio_cgroup *blkcg; + enum blkio_policy_id plid = BLKIOFILE_POLICY(cft->private); + int name = BLKIOFILE_ATTR(cft->private); + + blkcg = cgroup_to_blkio_cgroup(cgrp); - list_for_each_entry(blkg, &q->blkg_list, q_node) { - if (WARN_ON(list_empty(&pds))) { - /* umm... this shouldn't happen, just abort */ - ret = -ENOMEM; - goto out_unlock; + switch(plid) { + case BLKIO_POLICY_PROP: + switch(name) { + case BLKIO_PROP_weight: + return blkio_weight_write(blkcg, val); } - pd = list_first_entry(&pds, struct blkg_policy_data, alloc_node); - list_del_init(&pd->alloc_node); + break; + default: + BUG(); + } + + return 0; +} + +struct cftype blkio_files[] = { + { + .name = "weight_device", + .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP, + BLKIO_PROP_weight_device), + .read_seq_string = blkiocg_file_read, + .write_string = blkiocg_file_write, + .max_write_len = 256, + }, + { + .name = "weight", + .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP, + BLKIO_PROP_weight), + .read_u64 = blkiocg_file_read_u64, + .write_u64 = blkiocg_file_write_u64, + }, + { + .name = "time", + .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP, + BLKIO_PROP_time), + .read_map = blkiocg_file_read_map, + }, + { + .name = "sectors", + .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP, + BLKIO_PROP_sectors), + .read_map = blkiocg_file_read_map, + }, + { + .name = "io_service_bytes", + .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP, + BLKIO_PROP_io_service_bytes), + .read_map = blkiocg_file_read_map, + }, + { + .name = "io_serviced", + .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP, + BLKIO_PROP_io_serviced), + .read_map = blkiocg_file_read_map, + }, + { + .name = "io_service_time", + .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP, + BLKIO_PROP_io_service_time), + .read_map = blkiocg_file_read_map, + }, + { + .name = "io_wait_time", + .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP, + BLKIO_PROP_io_wait_time), + .read_map = blkiocg_file_read_map, + }, + { + .name = "io_merged", + .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP, + BLKIO_PROP_io_merged), + .read_map = blkiocg_file_read_map, + }, + { + .name = "io_queued", + .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP, + BLKIO_PROP_io_queued), + .read_map = blkiocg_file_read_map, + }, + { + .name = "reset_stats", + .write_u64 = blkiocg_reset_stats, + }, +#ifdef CONFIG_BLK_DEV_THROTTLING + { + .name = "throttle.read_bps_device", + .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_THROTL, + BLKIO_THROTL_read_bps_device), + .read_seq_string = blkiocg_file_read, + .write_string = blkiocg_file_write, + .max_write_len = 256, + }, - /* grab blkcg lock too while installing @pd on @blkg */ - spin_lock(&blkg->blkcg->lock); + { + .name = "throttle.write_bps_device", + .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_THROTL, + BLKIO_THROTL_write_bps_device), + .read_seq_string = blkiocg_file_read, + .write_string = blkiocg_file_write, + .max_write_len = 256, + }, - blkg->pd[pol->plid] = pd; - pd->blkg = blkg; - pol->pd_init_fn(blkg); + { + .name = "throttle.read_iops_device", + .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_THROTL, + BLKIO_THROTL_read_iops_device), + .read_seq_string = blkiocg_file_read, + .write_string = blkiocg_file_write, + .max_write_len = 256, + }, - spin_unlock(&blkg->blkcg->lock); - } + { + .name = "throttle.write_iops_device", + .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_THROTL, + BLKIO_THROTL_write_iops_device), + .read_seq_string = blkiocg_file_read, + .write_string = blkiocg_file_write, + .max_write_len = 256, + }, + { + .name = "throttle.io_service_bytes", + .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_THROTL, + BLKIO_THROTL_io_service_bytes), + .read_map = blkiocg_file_read_map, + }, + { + .name = "throttle.io_serviced", + .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_THROTL, + BLKIO_THROTL_io_serviced), + .read_map = blkiocg_file_read_map, + }, +#endif /* CONFIG_BLK_DEV_THROTTLING */ - __set_bit(pol->plid, q->blkcg_pols); - ret = 0; -out_unlock: - spin_unlock_irq(q->queue_lock); -out_free: - blk_queue_bypass_end(q); - list_for_each_entry_safe(pd, n, &pds, alloc_node) - kfree(pd); - return ret; -} -EXPORT_SYMBOL_GPL(blkcg_activate_policy); +#ifdef CONFIG_DEBUG_BLK_CGROUP + { + .name = "avg_queue_size", + .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP, + BLKIO_PROP_avg_queue_size), + .read_map = blkiocg_file_read_map, + }, + { + .name = "group_wait_time", + .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP, + BLKIO_PROP_group_wait_time), + .read_map = blkiocg_file_read_map, + }, + { + .name = "idle_time", + .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP, + BLKIO_PROP_idle_time), + .read_map = blkiocg_file_read_map, + }, + { + .name = "empty_time", + .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP, + BLKIO_PROP_empty_time), + .read_map = blkiocg_file_read_map, + }, + { + .name = "dequeue", + .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP, + BLKIO_PROP_dequeue), + .read_map = blkiocg_file_read_map, + }, + { + .name = "unaccounted_time", + .private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP, + BLKIO_PROP_unaccounted_time), + .read_map = blkiocg_file_read_map, + }, +#endif + { } /* terminate */ +}; -/** - * blkcg_deactivate_policy - deactivate a blkcg policy on a request_queue - * @q: request_queue of interest - * @pol: blkcg policy to deactivate - * - * Deactivate @pol on @q. Follows the same synchronization rules as - * blkcg_activate_policy(). - */ -void blkcg_deactivate_policy(struct request_queue *q, - const struct blkcg_policy *pol) +static void blkiocg_destroy(struct cgroup *cgroup) { - struct blkcg_gq *blkg; + struct blkio_cgroup *blkcg = cgroup_to_blkio_cgroup(cgroup); + unsigned long flags; + struct blkio_group *blkg; + void *key; + struct blkio_policy_type *blkiop; + struct blkio_policy_node *pn, *pntmp; - if (!blkcg_policy_enabled(q, pol)) - return; + rcu_read_lock(); + do { + spin_lock_irqsave(&blkcg->lock, flags); + + if (hlist_empty(&blkcg->blkg_list)) { + spin_unlock_irqrestore(&blkcg->lock, flags); + break; + } - blk_queue_bypass_start(q); - spin_lock_irq(q->queue_lock); + blkg = hlist_entry(blkcg->blkg_list.first, struct blkio_group, + blkcg_node); + key = rcu_dereference(blkg->key); + __blkiocg_del_blkio_group(blkg); - __clear_bit(pol->plid, q->blkcg_pols); + spin_unlock_irqrestore(&blkcg->lock, flags); - /* if no policy is left, no need for blkgs - shoot them down */ - if (bitmap_empty(q->blkcg_pols, BLKCG_MAX_POLS)) - blkg_destroy_all(q); + /* + * This blkio_group is being unlinked as associated cgroup is + * going away. Let all the IO controlling policies know about + * this event. + */ + spin_lock(&blkio_list_lock); + list_for_each_entry(blkiop, &blkio_list, list) { + if (blkiop->plid != blkg->plid) + continue; + blkiop->ops.blkio_unlink_group_fn(key, blkg); + } + spin_unlock(&blkio_list_lock); + } while (1); - list_for_each_entry(blkg, &q->blkg_list, q_node) { - /* grab blkcg lock too while removing @pd from @blkg */ - spin_lock(&blkg->blkcg->lock); + list_for_each_entry_safe(pn, pntmp, &blkcg->policy_list, node) { + blkio_policy_delete_node(pn); + kfree(pn); + } - if (pol->pd_exit_fn) - pol->pd_exit_fn(blkg); + free_css_id(&blkio_subsys, &blkcg->css); + rcu_read_unlock(); + if (blkcg != &blkio_root_cgroup) + kfree(blkcg); +} - kfree(blkg->pd[pol->plid]); - blkg->pd[pol->plid] = NULL; +static struct cgroup_subsys_state *blkiocg_create(struct cgroup *cgroup) +{ + struct blkio_cgroup *blkcg; + struct cgroup *parent = cgroup->parent; - spin_unlock(&blkg->blkcg->lock); + if (!parent) { + blkcg = &blkio_root_cgroup; + goto done; } - spin_unlock_irq(q->queue_lock); - blk_queue_bypass_end(q); + blkcg = kzalloc(sizeof(*blkcg), GFP_KERNEL); + if (!blkcg) + return ERR_PTR(-ENOMEM); + + blkcg->weight = BLKIO_WEIGHT_DEFAULT; +done: + spin_lock_init(&blkcg->lock); + INIT_HLIST_HEAD(&blkcg->blkg_list); + + INIT_LIST_HEAD(&blkcg->policy_list); + return &blkcg->css; } -EXPORT_SYMBOL_GPL(blkcg_deactivate_policy); -/** - * blkcg_policy_register - register a blkcg policy - * @pol: blkcg policy to register - * - * Register @pol with blkcg core. Might sleep and @pol may be modified on - * successful registration. Returns 0 on success and -errno on failure. +/* + * We cannot support shared io contexts, as we have no mean to support + * two tasks with the same ioc in two different groups without major rework + * of the main cic data structures. For now we allow a task to change + * its cgroup only if it's the only owner of its ioc. */ -int blkcg_policy_register(struct blkcg_policy *pol) +static int blkiocg_can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) { - int i, ret; - - if (WARN_ON(pol->pd_size < sizeof(struct blkg_policy_data))) - return -EINVAL; - - mutex_lock(&blkcg_pol_mutex); + struct task_struct *task; + struct io_context *ioc; + int ret = 0; - /* find an empty slot */ - ret = -ENOSPC; - for (i = 0; i < BLKCG_MAX_POLS; i++) - if (!blkcg_policy[i]) + /* task_lock() is needed to avoid races with exit_io_context() */ + cgroup_taskset_for_each(task, cgrp, tset) { + task_lock(task); + ioc = task->io_context; + if (ioc && atomic_read(&ioc->nr_tasks) > 1) + ret = -EINVAL; + task_unlock(task); + if (ret) break; - if (i >= BLKCG_MAX_POLS) - goto out_unlock; + } + return ret; +} - /* register and update blkgs */ - pol->plid = i; - blkcg_policy[i] = pol; +static void blkiocg_attach(struct cgroup *cgrp, struct cgroup_taskset *tset) +{ + struct task_struct *task; + struct io_context *ioc; - /* everything is in place, add intf files for the new policy */ - if (pol->cftypes) - WARN_ON(cgroup_add_cftypes(&blkio_subsys, pol->cftypes)); - ret = 0; -out_unlock: - mutex_unlock(&blkcg_pol_mutex); - return ret; + cgroup_taskset_for_each(task, cgrp, tset) { + /* we don't lose anything even if ioc allocation fails */ + ioc = get_task_io_context(task, GFP_ATOMIC, NUMA_NO_NODE); + if (ioc) { + ioc_cgroup_changed(ioc); + put_io_context(ioc); + } + } } -EXPORT_SYMBOL_GPL(blkcg_policy_register); -/** - * blkcg_policy_unregister - unregister a blkcg policy - * @pol: blkcg policy to unregister - * - * Undo blkcg_policy_register(@pol). Might sleep. - */ -void blkcg_policy_unregister(struct blkcg_policy *pol) +struct cgroup_subsys blkio_subsys = { + .name = "blkio", + .create = blkiocg_create, + .can_attach = blkiocg_can_attach, + .attach = blkiocg_attach, + .destroy = blkiocg_destroy, +#ifdef CONFIG_BLK_CGROUP + /* note: blkio_subsys_id is otherwise defined in blk-cgroup.h */ + .subsys_id = blkio_subsys_id, +#endif + .base_cftypes = blkio_files, + .use_id = 1, + .module = THIS_MODULE, +}; +EXPORT_SYMBOL_GPL(blkio_subsys); + +void blkio_policy_register(struct blkio_policy_type *blkiop) { - mutex_lock(&blkcg_pol_mutex); + spin_lock(&blkio_list_lock); + list_add_tail(&blkiop->list, &blkio_list); + spin_unlock(&blkio_list_lock); +} +EXPORT_SYMBOL_GPL(blkio_policy_register); - if (WARN_ON(blkcg_policy[pol->plid] != pol)) - goto out_unlock; +void blkio_policy_unregister(struct blkio_policy_type *blkiop) +{ + spin_lock(&blkio_list_lock); + list_del_init(&blkiop->list); + spin_unlock(&blkio_list_lock); +} +EXPORT_SYMBOL_GPL(blkio_policy_unregister); - /* kill the intf files first */ - if (pol->cftypes) - cgroup_rm_cftypes(&blkio_subsys, pol->cftypes); +static int __init init_cgroup_blkio(void) +{ + return cgroup_load_subsys(&blkio_subsys); +} - /* unregister and update blkgs */ - blkcg_policy[pol->plid] = NULL; -out_unlock: - mutex_unlock(&blkcg_pol_mutex); +static void __exit exit_cgroup_blkio(void) +{ + cgroup_unload_subsys(&blkio_subsys); } -EXPORT_SYMBOL_GPL(blkcg_policy_unregister); + +module_init(init_cgroup_blkio); +module_exit(exit_cgroup_blkio); +MODULE_LICENSE("GPL"); diff --git a/trunk/block/blk-cgroup.h b/trunk/block/blk-cgroup.h index 8ac457ce7783..6f3ace7e792f 100644 --- a/trunk/block/blk-cgroup.h +++ b/trunk/block/blk-cgroup.h @@ -15,371 +15,350 @@ #include #include -#include -#include + +enum blkio_policy_id { + BLKIO_POLICY_PROP = 0, /* Proportional Bandwidth division */ + BLKIO_POLICY_THROTL, /* Throttling */ +}; /* Max limits for throttle policy */ #define THROTL_IOPS_MAX UINT_MAX -/* CFQ specific, out here for blkcg->cfq_weight */ -#define CFQ_WEIGHT_MIN 10 -#define CFQ_WEIGHT_MAX 1000 -#define CFQ_WEIGHT_DEFAULT 500 - -#ifdef CONFIG_BLK_CGROUP - -enum blkg_rwstat_type { - BLKG_RWSTAT_READ, - BLKG_RWSTAT_WRITE, - BLKG_RWSTAT_SYNC, - BLKG_RWSTAT_ASYNC, - - BLKG_RWSTAT_NR, - BLKG_RWSTAT_TOTAL = BLKG_RWSTAT_NR, +#if defined(CONFIG_BLK_CGROUP) || defined(CONFIG_BLK_CGROUP_MODULE) + +#ifndef CONFIG_BLK_CGROUP +/* When blk-cgroup is a module, its subsys_id isn't a compile-time constant */ +extern struct cgroup_subsys blkio_subsys; +#define blkio_subsys_id blkio_subsys.subsys_id +#endif + +enum stat_type { + /* Total time spent (in ns) between request dispatch to the driver and + * request completion for IOs doen by this cgroup. This may not be + * accurate when NCQ is turned on. */ + BLKIO_STAT_SERVICE_TIME = 0, + /* Total time spent waiting in scheduler queue in ns */ + BLKIO_STAT_WAIT_TIME, + /* Number of IOs queued up */ + BLKIO_STAT_QUEUED, + /* All the single valued stats go below this */ + BLKIO_STAT_TIME, +#ifdef CONFIG_DEBUG_BLK_CGROUP + /* Time not charged to this cgroup */ + BLKIO_STAT_UNACCOUNTED_TIME, + BLKIO_STAT_AVG_QUEUE_SIZE, + BLKIO_STAT_IDLE_TIME, + BLKIO_STAT_EMPTY_TIME, + BLKIO_STAT_GROUP_WAIT_TIME, + BLKIO_STAT_DEQUEUE +#endif }; -struct blkcg_gq; - -struct blkcg { - struct cgroup_subsys_state css; - spinlock_t lock; - - struct radix_tree_root blkg_tree; - struct blkcg_gq *blkg_hint; - struct hlist_head blkg_list; - - /* for policies to test whether associated blkcg has changed */ - uint64_t id; - - /* TODO: per-policy storage in blkcg */ - unsigned int cfq_weight; /* belongs to cfq */ +/* Per cpu stats */ +enum stat_type_cpu { + BLKIO_STAT_CPU_SECTORS, + /* Total bytes transferred */ + BLKIO_STAT_CPU_SERVICE_BYTES, + /* Total IOs serviced, post merge */ + BLKIO_STAT_CPU_SERVICED, + /* Number of IOs merged */ + BLKIO_STAT_CPU_MERGED, + BLKIO_STAT_CPU_NR }; -struct blkg_stat { - struct u64_stats_sync syncp; - uint64_t cnt; +enum stat_sub_type { + BLKIO_STAT_READ = 0, + BLKIO_STAT_WRITE, + BLKIO_STAT_SYNC, + BLKIO_STAT_ASYNC, + BLKIO_STAT_TOTAL }; -struct blkg_rwstat { - struct u64_stats_sync syncp; - uint64_t cnt[BLKG_RWSTAT_NR]; +/* blkg state flags */ +enum blkg_state_flags { + BLKG_waiting = 0, + BLKG_idling, + BLKG_empty, }; -/* - * A blkcg_gq (blkg) is association between a block cgroup (blkcg) and a - * request_queue (q). This is used by blkcg policies which need to track - * information per blkcg - q pair. - * - * There can be multiple active blkcg policies and each has its private - * data on each blkg, the size of which is determined by - * blkcg_policy->pd_size. blkcg core allocates and frees such areas - * together with blkg and invokes pd_init/exit_fn() methods. - * - * Such private data must embed struct blkg_policy_data (pd) at the - * beginning and pd_size can't be smaller than pd. - */ -struct blkg_policy_data { - /* the blkg this per-policy data belongs to */ - struct blkcg_gq *blkg; - - /* used during policy activation */ - struct list_head alloc_node; +/* cgroup files owned by proportional weight policy */ +enum blkcg_file_name_prop { + BLKIO_PROP_weight = 1, + BLKIO_PROP_weight_device, + BLKIO_PROP_io_service_bytes, + BLKIO_PROP_io_serviced, + BLKIO_PROP_time, + BLKIO_PROP_sectors, + BLKIO_PROP_unaccounted_time, + BLKIO_PROP_io_service_time, + BLKIO_PROP_io_wait_time, + BLKIO_PROP_io_merged, + BLKIO_PROP_io_queued, + BLKIO_PROP_avg_queue_size, + BLKIO_PROP_group_wait_time, + BLKIO_PROP_idle_time, + BLKIO_PROP_empty_time, + BLKIO_PROP_dequeue, }; -/* association between a blk cgroup and a request queue */ -struct blkcg_gq { - /* Pointer to the associated request_queue */ - struct request_queue *q; - struct list_head q_node; - struct hlist_node blkcg_node; - struct blkcg *blkcg; - /* reference count */ - int refcnt; - - struct blkg_policy_data *pd[BLKCG_MAX_POLS]; - - struct rcu_head rcu_head; +/* cgroup files owned by throttle policy */ +enum blkcg_file_name_throtl { + BLKIO_THROTL_read_bps_device, + BLKIO_THROTL_write_bps_device, + BLKIO_THROTL_read_iops_device, + BLKIO_THROTL_write_iops_device, + BLKIO_THROTL_io_service_bytes, + BLKIO_THROTL_io_serviced, }; -typedef void (blkcg_pol_init_pd_fn)(struct blkcg_gq *blkg); -typedef void (blkcg_pol_exit_pd_fn)(struct blkcg_gq *blkg); -typedef void (blkcg_pol_reset_pd_stats_fn)(struct blkcg_gq *blkg); - -struct blkcg_policy { - int plid; - /* policy specific private data size */ - size_t pd_size; - /* cgroup files for the policy */ - struct cftype *cftypes; - - /* operations */ - blkcg_pol_init_pd_fn *pd_init_fn; - blkcg_pol_exit_pd_fn *pd_exit_fn; - blkcg_pol_reset_pd_stats_fn *pd_reset_stats_fn; +struct blkio_cgroup { + struct cgroup_subsys_state css; + unsigned int weight; + spinlock_t lock; + struct hlist_head blkg_list; + struct list_head policy_list; /* list of blkio_policy_node */ }; -extern struct blkcg blkcg_root; - -struct blkcg *cgroup_to_blkcg(struct cgroup *cgroup); -struct blkcg *bio_blkcg(struct bio *bio); -struct blkcg_gq *blkg_lookup(struct blkcg *blkcg, struct request_queue *q); -struct blkcg_gq *blkg_lookup_create(struct blkcg *blkcg, - struct request_queue *q); -int blkcg_init_queue(struct request_queue *q); -void blkcg_drain_queue(struct request_queue *q); -void blkcg_exit_queue(struct request_queue *q); - -/* Blkio controller policy registration */ -int blkcg_policy_register(struct blkcg_policy *pol); -void blkcg_policy_unregister(struct blkcg_policy *pol); -int blkcg_activate_policy(struct request_queue *q, - const struct blkcg_policy *pol); -void blkcg_deactivate_policy(struct request_queue *q, - const struct blkcg_policy *pol); - -void blkcg_print_blkgs(struct seq_file *sf, struct blkcg *blkcg, - u64 (*prfill)(struct seq_file *, - struct blkg_policy_data *, int), - const struct blkcg_policy *pol, int data, - bool show_total); -u64 __blkg_prfill_u64(struct seq_file *sf, struct blkg_policy_data *pd, u64 v); -u64 __blkg_prfill_rwstat(struct seq_file *sf, struct blkg_policy_data *pd, - const struct blkg_rwstat *rwstat); -u64 blkg_prfill_stat(struct seq_file *sf, struct blkg_policy_data *pd, int off); -u64 blkg_prfill_rwstat(struct seq_file *sf, struct blkg_policy_data *pd, - int off); - -struct blkg_conf_ctx { - struct gendisk *disk; - struct blkcg_gq *blkg; - u64 v; +struct blkio_group_stats { + /* total disk time and nr sectors dispatched by this group */ + uint64_t time; + uint64_t stat_arr[BLKIO_STAT_QUEUED + 1][BLKIO_STAT_TOTAL]; +#ifdef CONFIG_DEBUG_BLK_CGROUP + /* Time not charged to this cgroup */ + uint64_t unaccounted_time; + + /* Sum of number of IOs queued across all samples */ + uint64_t avg_queue_size_sum; + /* Count of samples taken for average */ + uint64_t avg_queue_size_samples; + /* How many times this group has been removed from service tree */ + unsigned long dequeue; + + /* Total time spent waiting for it to be assigned a timeslice. */ + uint64_t group_wait_time; + uint64_t start_group_wait_time; + + /* Time spent idling for this blkio_group */ + uint64_t idle_time; + uint64_t start_idle_time; + /* + * Total time when we have requests queued and do not contain the + * current active queue. + */ + uint64_t empty_time; + uint64_t start_empty_time; + uint16_t flags; +#endif }; -int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol, - const char *input, struct blkg_conf_ctx *ctx); -void blkg_conf_finish(struct blkg_conf_ctx *ctx); - - -/** - * blkg_to_pdata - get policy private data - * @blkg: blkg of interest - * @pol: policy of interest - * - * Return pointer to private data associated with the @blkg-@pol pair. - */ -static inline struct blkg_policy_data *blkg_to_pd(struct blkcg_gq *blkg, - struct blkcg_policy *pol) -{ - return blkg ? blkg->pd[pol->plid] : NULL; -} - -/** - * pdata_to_blkg - get blkg associated with policy private data - * @pd: policy private data of interest - * - * @pd is policy private data. Determine the blkg it's associated with. - */ -static inline struct blkcg_gq *pd_to_blkg(struct blkg_policy_data *pd) -{ - return pd ? pd->blkg : NULL; -} - -/** - * blkg_path - format cgroup path of blkg - * @blkg: blkg of interest - * @buf: target buffer - * @buflen: target buffer length - * - * Format the path of the cgroup of @blkg into @buf. - */ -static inline int blkg_path(struct blkcg_gq *blkg, char *buf, int buflen) -{ - int ret; - - rcu_read_lock(); - ret = cgroup_path(blkg->blkcg->css.cgroup, buf, buflen); - rcu_read_unlock(); - if (ret) - strncpy(buf, "", buflen); - return ret; -} - -/** - * blkg_get - get a blkg reference - * @blkg: blkg to get - * - * The caller should be holding queue_lock and an existing reference. - */ -static inline void blkg_get(struct blkcg_gq *blkg) -{ - lockdep_assert_held(blkg->q->queue_lock); - WARN_ON_ONCE(!blkg->refcnt); - blkg->refcnt++; -} - -void __blkg_release(struct blkcg_gq *blkg); - -/** - * blkg_put - put a blkg reference - * @blkg: blkg to put - * - * The caller should be holding queue_lock. - */ -static inline void blkg_put(struct blkcg_gq *blkg) -{ - lockdep_assert_held(blkg->q->queue_lock); - WARN_ON_ONCE(blkg->refcnt <= 0); - if (!--blkg->refcnt) - __blkg_release(blkg); -} - -/** - * blkg_stat_add - add a value to a blkg_stat - * @stat: target blkg_stat - * @val: value to add - * - * Add @val to @stat. The caller is responsible for synchronizing calls to - * this function. - */ -static inline void blkg_stat_add(struct blkg_stat *stat, uint64_t val) -{ - u64_stats_update_begin(&stat->syncp); - stat->cnt += val; - u64_stats_update_end(&stat->syncp); -} - -/** - * blkg_stat_read - read the current value of a blkg_stat - * @stat: blkg_stat to read - * - * Read the current value of @stat. This function can be called without - * synchroniztion and takes care of u64 atomicity. - */ -static inline uint64_t blkg_stat_read(struct blkg_stat *stat) -{ - unsigned int start; - uint64_t v; - - do { - start = u64_stats_fetch_begin(&stat->syncp); - v = stat->cnt; - } while (u64_stats_fetch_retry(&stat->syncp, start)); - - return v; -} - -/** - * blkg_stat_reset - reset a blkg_stat - * @stat: blkg_stat to reset - */ -static inline void blkg_stat_reset(struct blkg_stat *stat) -{ - stat->cnt = 0; -} - -/** - * blkg_rwstat_add - add a value to a blkg_rwstat - * @rwstat: target blkg_rwstat - * @rw: mask of REQ_{WRITE|SYNC} - * @val: value to add - * - * Add @val to @rwstat. The counters are chosen according to @rw. The - * caller is responsible for synchronizing calls to this function. - */ -static inline void blkg_rwstat_add(struct blkg_rwstat *rwstat, - int rw, uint64_t val) -{ - u64_stats_update_begin(&rwstat->syncp); - - if (rw & REQ_WRITE) - rwstat->cnt[BLKG_RWSTAT_WRITE] += val; - else - rwstat->cnt[BLKG_RWSTAT_READ] += val; - if (rw & REQ_SYNC) - rwstat->cnt[BLKG_RWSTAT_SYNC] += val; - else - rwstat->cnt[BLKG_RWSTAT_ASYNC] += val; - - u64_stats_update_end(&rwstat->syncp); -} +/* Per cpu blkio group stats */ +struct blkio_group_stats_cpu { + uint64_t sectors; + uint64_t stat_arr_cpu[BLKIO_STAT_CPU_NR][BLKIO_STAT_TOTAL]; + struct u64_stats_sync syncp; +}; -/** - * blkg_rwstat_read - read the current values of a blkg_rwstat - * @rwstat: blkg_rwstat to read - * - * Read the current snapshot of @rwstat and return it as the return value. - * This function can be called without synchronization and takes care of - * u64 atomicity. - */ -static inline struct blkg_rwstat blkg_rwstat_read(struct blkg_rwstat *rwstat) -{ - unsigned int start; - struct blkg_rwstat tmp; +struct blkio_group { + /* An rcu protected unique identifier for the group */ + void *key; + struct hlist_node blkcg_node; + unsigned short blkcg_id; + /* Store cgroup path */ + char path[128]; + /* The device MKDEV(major, minor), this group has been created for */ + dev_t dev; + /* policy which owns this blk group */ + enum blkio_policy_id plid; + + /* Need to serialize the stats in the case of reset/update */ + spinlock_t stats_lock; + struct blkio_group_stats stats; + /* Per cpu stats pointer */ + struct blkio_group_stats_cpu __percpu *stats_cpu; +}; - do { - start = u64_stats_fetch_begin(&rwstat->syncp); - tmp = *rwstat; - } while (u64_stats_fetch_retry(&rwstat->syncp, start)); +struct blkio_policy_node { + struct list_head node; + dev_t dev; + /* This node belongs to max bw policy or porportional weight policy */ + enum blkio_policy_id plid; + /* cgroup file to which this rule belongs to */ + int fileid; + + union { + unsigned int weight; + /* + * Rate read/write in terms of bytes per second + * Whether this rate represents read or write is determined + * by file type "fileid". + */ + u64 bps; + unsigned int iops; + } val; +}; - return tmp; -} +extern unsigned int blkcg_get_weight(struct blkio_cgroup *blkcg, + dev_t dev); +extern uint64_t blkcg_get_read_bps(struct blkio_cgroup *blkcg, + dev_t dev); +extern uint64_t blkcg_get_write_bps(struct blkio_cgroup *blkcg, + dev_t dev); +extern unsigned int blkcg_get_read_iops(struct blkio_cgroup *blkcg, + dev_t dev); +extern unsigned int blkcg_get_write_iops(struct blkio_cgroup *blkcg, + dev_t dev); + +typedef void (blkio_unlink_group_fn) (void *key, struct blkio_group *blkg); + +typedef void (blkio_update_group_weight_fn) (void *key, + struct blkio_group *blkg, unsigned int weight); +typedef void (blkio_update_group_read_bps_fn) (void * key, + struct blkio_group *blkg, u64 read_bps); +typedef void (blkio_update_group_write_bps_fn) (void *key, + struct blkio_group *blkg, u64 write_bps); +typedef void (blkio_update_group_read_iops_fn) (void *key, + struct blkio_group *blkg, unsigned int read_iops); +typedef void (blkio_update_group_write_iops_fn) (void *key, + struct blkio_group *blkg, unsigned int write_iops); + +struct blkio_policy_ops { + blkio_unlink_group_fn *blkio_unlink_group_fn; + blkio_update_group_weight_fn *blkio_update_group_weight_fn; + blkio_update_group_read_bps_fn *blkio_update_group_read_bps_fn; + blkio_update_group_write_bps_fn *blkio_update_group_write_bps_fn; + blkio_update_group_read_iops_fn *blkio_update_group_read_iops_fn; + blkio_update_group_write_iops_fn *blkio_update_group_write_iops_fn; +}; -/** - * blkg_rwstat_sum - read the total count of a blkg_rwstat - * @rwstat: blkg_rwstat to read - * - * Return the total count of @rwstat regardless of the IO direction. This - * function can be called without synchronization and takes care of u64 - * atomicity. - */ -static inline uint64_t blkg_rwstat_sum(struct blkg_rwstat *rwstat) -{ - struct blkg_rwstat tmp = blkg_rwstat_read(rwstat); +struct blkio_policy_type { + struct list_head list; + struct blkio_policy_ops ops; + enum blkio_policy_id plid; +}; - return tmp.cnt[BLKG_RWSTAT_READ] + tmp.cnt[BLKG_RWSTAT_WRITE]; -} +/* Blkio controller policy registration */ +extern void blkio_policy_register(struct blkio_policy_type *); +extern void blkio_policy_unregister(struct blkio_policy_type *); -/** - * blkg_rwstat_reset - reset a blkg_rwstat - * @rwstat: blkg_rwstat to reset - */ -static inline void blkg_rwstat_reset(struct blkg_rwstat *rwstat) +static inline char *blkg_path(struct blkio_group *blkg) { - memset(rwstat->cnt, 0, sizeof(rwstat->cnt)); + return blkg->path; } -#else /* CONFIG_BLK_CGROUP */ +#else -struct cgroup; - -struct blkg_policy_data { +struct blkio_group { }; -struct blkcg_gq { +struct blkio_policy_type { }; -struct blkcg_policy { -}; - -static inline struct blkcg *cgroup_to_blkcg(struct cgroup *cgroup) { return NULL; } -static inline struct blkcg *bio_blkcg(struct bio *bio) { return NULL; } -static inline struct blkcg_gq *blkg_lookup(struct blkcg *blkcg, void *key) { return NULL; } -static inline int blkcg_init_queue(struct request_queue *q) { return 0; } -static inline void blkcg_drain_queue(struct request_queue *q) { } -static inline void blkcg_exit_queue(struct request_queue *q) { } -static inline int blkcg_policy_register(struct blkcg_policy *pol) { return 0; } -static inline void blkcg_policy_unregister(struct blkcg_policy *pol) { } -static inline int blkcg_activate_policy(struct request_queue *q, - const struct blkcg_policy *pol) { return 0; } -static inline void blkcg_deactivate_policy(struct request_queue *q, - const struct blkcg_policy *pol) { } - -static inline struct blkg_policy_data *blkg_to_pd(struct blkcg_gq *blkg, - struct blkcg_policy *pol) { return NULL; } -static inline struct blkcg_gq *pd_to_blkg(struct blkg_policy_data *pd) { return NULL; } -static inline char *blkg_path(struct blkcg_gq *blkg) { return NULL; } -static inline void blkg_get(struct blkcg_gq *blkg) { } -static inline void blkg_put(struct blkcg_gq *blkg) { } - -#endif /* CONFIG_BLK_CGROUP */ -#endif /* _BLK_CGROUP_H */ +static inline void blkio_policy_register(struct blkio_policy_type *blkiop) { } +static inline void blkio_policy_unregister(struct blkio_policy_type *blkiop) { } + +static inline char *blkg_path(struct blkio_group *blkg) { return NULL; } + +#endif + +#define BLKIO_WEIGHT_MIN 10 +#define BLKIO_WEIGHT_MAX 1000 +#define BLKIO_WEIGHT_DEFAULT 500 + +#ifdef CONFIG_DEBUG_BLK_CGROUP +void blkiocg_update_avg_queue_size_stats(struct blkio_group *blkg); +void blkiocg_update_dequeue_stats(struct blkio_group *blkg, + unsigned long dequeue); +void blkiocg_update_set_idle_time_stats(struct blkio_group *blkg); +void blkiocg_update_idle_time_stats(struct blkio_group *blkg); +void blkiocg_set_start_empty_time(struct blkio_group *blkg); + +#define BLKG_FLAG_FNS(name) \ +static inline void blkio_mark_blkg_##name( \ + struct blkio_group_stats *stats) \ +{ \ + stats->flags |= (1 << BLKG_##name); \ +} \ +static inline void blkio_clear_blkg_##name( \ + struct blkio_group_stats *stats) \ +{ \ + stats->flags &= ~(1 << BLKG_##name); \ +} \ +static inline int blkio_blkg_##name(struct blkio_group_stats *stats) \ +{ \ + return (stats->flags & (1 << BLKG_##name)) != 0; \ +} \ + +BLKG_FLAG_FNS(waiting) +BLKG_FLAG_FNS(idling) +BLKG_FLAG_FNS(empty) +#undef BLKG_FLAG_FNS +#else +static inline void blkiocg_update_avg_queue_size_stats( + struct blkio_group *blkg) {} +static inline void blkiocg_update_dequeue_stats(struct blkio_group *blkg, + unsigned long dequeue) {} +static inline void blkiocg_update_set_idle_time_stats(struct blkio_group *blkg) +{} +static inline void blkiocg_update_idle_time_stats(struct blkio_group *blkg) {} +static inline void blkiocg_set_start_empty_time(struct blkio_group *blkg) {} +#endif + +#if defined(CONFIG_BLK_CGROUP) || defined(CONFIG_BLK_CGROUP_MODULE) +extern struct blkio_cgroup blkio_root_cgroup; +extern struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup); +extern struct blkio_cgroup *task_blkio_cgroup(struct task_struct *tsk); +extern void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg, + struct blkio_group *blkg, void *key, dev_t dev, + enum blkio_policy_id plid); +extern int blkio_alloc_blkg_stats(struct blkio_group *blkg); +extern int blkiocg_del_blkio_group(struct blkio_group *blkg); +extern struct blkio_group *blkiocg_lookup_group(struct blkio_cgroup *blkcg, + void *key); +void blkiocg_update_timeslice_used(struct blkio_group *blkg, + unsigned long time, + unsigned long unaccounted_time); +void blkiocg_update_dispatch_stats(struct blkio_group *blkg, uint64_t bytes, + bool direction, bool sync); +void blkiocg_update_completion_stats(struct blkio_group *blkg, + uint64_t start_time, uint64_t io_start_time, bool direction, bool sync); +void blkiocg_update_io_merged_stats(struct blkio_group *blkg, bool direction, + bool sync); +void blkiocg_update_io_add_stats(struct blkio_group *blkg, + struct blkio_group *curr_blkg, bool direction, bool sync); +void blkiocg_update_io_remove_stats(struct blkio_group *blkg, + bool direction, bool sync); +#else +struct cgroup; +static inline struct blkio_cgroup * +cgroup_to_blkio_cgroup(struct cgroup *cgroup) { return NULL; } +static inline struct blkio_cgroup * +task_blkio_cgroup(struct task_struct *tsk) { return NULL; } + +static inline void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg, + struct blkio_group *blkg, void *key, dev_t dev, + enum blkio_policy_id plid) {} + +static inline int blkio_alloc_blkg_stats(struct blkio_group *blkg) { return 0; } + +static inline int +blkiocg_del_blkio_group(struct blkio_group *blkg) { return 0; } + +static inline struct blkio_group * +blkiocg_lookup_group(struct blkio_cgroup *blkcg, void *key) { return NULL; } +static inline void blkiocg_update_timeslice_used(struct blkio_group *blkg, + unsigned long time, + unsigned long unaccounted_time) +{} +static inline void blkiocg_update_dispatch_stats(struct blkio_group *blkg, + uint64_t bytes, bool direction, bool sync) {} +static inline void blkiocg_update_completion_stats(struct blkio_group *blkg, + uint64_t start_time, uint64_t io_start_time, bool direction, + bool sync) {} +static inline void blkiocg_update_io_merged_stats(struct blkio_group *blkg, + bool direction, bool sync) {} +static inline void blkiocg_update_io_add_stats(struct blkio_group *blkg, + struct blkio_group *curr_blkg, bool direction, bool sync) {} +static inline void blkiocg_update_io_remove_stats(struct blkio_group *blkg, + bool direction, bool sync) {} +#endif +#endif /* _BLK_CGROUP_H */ diff --git a/trunk/block/blk-core.c b/trunk/block/blk-core.c index 3c923a7aeb56..1f61b74867e4 100644 --- a/trunk/block/blk-core.c +++ b/trunk/block/blk-core.c @@ -29,13 +29,11 @@ #include #include #include -#include #define CREATE_TRACE_POINTS #include #include "blk.h" -#include "blk-cgroup.h" EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_remap); EXPORT_TRACEPOINT_SYMBOL_GPL(block_rq_remap); @@ -282,7 +280,7 @@ EXPORT_SYMBOL(blk_stop_queue); * * This function does not cancel any asynchronous activity arising * out of elevator or throttling code. That would require elevaotor_exit() - * and blkcg_exit_queue() to be called with queue lock initialized. + * and blk_throtl_exit() to be called with queue lock initialized. * */ void blk_sync_queue(struct request_queue *q) @@ -367,23 +365,17 @@ void blk_drain_queue(struct request_queue *q, bool drain_all) spin_lock_irq(q->queue_lock); - /* - * The caller might be trying to drain @q before its - * elevator is initialized. - */ - if (q->elevator) - elv_drain_elevator(q); - - blkcg_drain_queue(q); + elv_drain_elevator(q); + if (drain_all) + blk_throtl_drain(q); /* * This function might be called on a queue which failed - * driver init after queue creation or is not yet fully - * active yet. Some drivers (e.g. fd and loop) get unhappy - * in such cases. Kick queue iff dispatch queue has - * something on it and @q has request_fn set. + * driver init after queue creation. Some drivers + * (e.g. fd) get unhappy in such cases. Kick queue iff + * dispatch queue has something on it. */ - if (!list_empty(&q->queue_head) && q->request_fn) + if (!list_empty(&q->queue_head)) __blk_run_queue(q); drain |= q->rq.elvpriv; @@ -410,49 +402,6 @@ void blk_drain_queue(struct request_queue *q, bool drain_all) } } -/** - * blk_queue_bypass_start - enter queue bypass mode - * @q: queue of interest - * - * In bypass mode, only the dispatch FIFO queue of @q is used. This - * function makes @q enter bypass mode and drains all requests which were - * throttled or issued before. On return, it's guaranteed that no request - * is being throttled or has ELVPRIV set and blk_queue_bypass() %true - * inside queue or RCU read lock. - */ -void blk_queue_bypass_start(struct request_queue *q) -{ - bool drain; - - spin_lock_irq(q->queue_lock); - drain = !q->bypass_depth++; - queue_flag_set(QUEUE_FLAG_BYPASS, q); - spin_unlock_irq(q->queue_lock); - - if (drain) { - blk_drain_queue(q, false); - /* ensure blk_queue_bypass() is %true inside RCU read lock */ - synchronize_rcu(); - } -} -EXPORT_SYMBOL_GPL(blk_queue_bypass_start); - -/** - * blk_queue_bypass_end - leave queue bypass mode - * @q: queue of interest - * - * Leave bypass mode and restore the normal queueing behavior. - */ -void blk_queue_bypass_end(struct request_queue *q) -{ - spin_lock_irq(q->queue_lock); - if (!--q->bypass_depth) - queue_flag_clear(QUEUE_FLAG_BYPASS, q); - WARN_ON_ONCE(q->bypass_depth < 0); - spin_unlock_irq(q->queue_lock); -} -EXPORT_SYMBOL_GPL(blk_queue_bypass_end); - /** * blk_cleanup_queue - shutdown a request queue * @q: request queue to shutdown @@ -469,19 +418,6 @@ void blk_cleanup_queue(struct request_queue *q) queue_flag_set_unlocked(QUEUE_FLAG_DEAD, q); spin_lock_irq(lock); - - /* - * Dead queue is permanently in bypass mode till released. Note - * that, unlike blk_queue_bypass_start(), we aren't performing - * synchronize_rcu() after entering bypass mode to avoid the delay - * as some drivers create and destroy a lot of queues while - * probing. This is still safe because blk_release_queue() will be - * called only after the queue refcnt drops to zero and nothing, - * RCU or not, would be traversing the queue by then. - */ - q->bypass_depth++; - queue_flag_set(QUEUE_FLAG_BYPASS, q); - queue_flag_set(QUEUE_FLAG_NOMERGES, q); queue_flag_set(QUEUE_FLAG_NOXMERGES, q); queue_flag_set(QUEUE_FLAG_DEAD, q); @@ -492,8 +428,13 @@ void blk_cleanup_queue(struct request_queue *q) spin_unlock_irq(lock); mutex_unlock(&q->sysfs_lock); - /* drain all requests queued before DEAD marking */ - blk_drain_queue(q, true); + /* + * Drain all requests queued before DEAD marking. The caller might + * be trying to tear down @q before its elevator is initialized, in + * which case we don't want to call into draining. + */ + if (q->elevator) + blk_drain_queue(q, true); /* @q won't process any more request, flush async actions */ del_timer_sync(&q->backing_dev_info.laptop_mode_wb_timer); @@ -557,15 +498,14 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) if (err) goto fail_id; + if (blk_throtl_init(q)) + goto fail_id; + setup_timer(&q->backing_dev_info.laptop_mode_wb_timer, laptop_mode_timer_fn, (unsigned long) q); setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q); - INIT_LIST_HEAD(&q->queue_head); INIT_LIST_HEAD(&q->timeout_list); INIT_LIST_HEAD(&q->icq_list); -#ifdef CONFIG_BLK_CGROUP - INIT_LIST_HEAD(&q->blkg_list); -#endif INIT_LIST_HEAD(&q->flush_queue[0]); INIT_LIST_HEAD(&q->flush_queue[1]); INIT_LIST_HEAD(&q->flush_data_in_flight); @@ -582,18 +522,6 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) */ q->queue_lock = &q->__queue_lock; - /* - * A queue starts its life with bypass turned on to avoid - * unnecessary bypass on/off overhead and nasty surprises during - * init. The initial bypass will be finished at the end of - * blk_init_allocated_queue(). - */ - q->bypass_depth = 1; - __set_bit(QUEUE_FLAG_BYPASS, &q->queue_flags); - - if (blkcg_init_queue(q)) - goto fail_id; - return q; fail_id: @@ -686,15 +614,15 @@ blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn, q->sg_reserved_size = INT_MAX; - /* init elevator */ - if (elevator_init(q, NULL)) - return NULL; - - blk_queue_congestion_threshold(q); + /* + * all done + */ + if (!elevator_init(q, NULL)) { + blk_queue_congestion_threshold(q); + return q; + } - /* all done, end the initial bypass */ - blk_queue_bypass_end(q); - return q; + return NULL; } EXPORT_SYMBOL(blk_init_allocated_queue); @@ -720,6 +648,33 @@ static inline void blk_free_request(struct request_queue *q, struct request *rq) mempool_free(rq, q->rq.rq_pool); } +static struct request * +blk_alloc_request(struct request_queue *q, struct io_cq *icq, + unsigned int flags, gfp_t gfp_mask) +{ + struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask); + + if (!rq) + return NULL; + + blk_rq_init(q, rq); + + rq->cmd_flags = flags | REQ_ALLOCED; + + if (flags & REQ_ELVPRIV) { + rq->elv.icq = icq; + if (unlikely(elv_set_request(q, rq, gfp_mask))) { + mempool_free(rq, q->rq.rq_pool); + return NULL; + } + /* @rq->elv.icq holds on to io_context until @rq is freed */ + if (icq) + get_io_context(icq->ioc); + } + + return rq; +} + /* * ioc_batching returns true if the ioc is a valid batching request and * should be given priority access to a request. @@ -807,22 +762,6 @@ static bool blk_rq_should_init_elevator(struct bio *bio) return true; } -/** - * rq_ioc - determine io_context for request allocation - * @bio: request being allocated is for this bio (can be %NULL) - * - * Determine io_context to use for request allocation for @bio. May return - * %NULL if %current->io_context doesn't exist. - */ -static struct io_context *rq_ioc(struct bio *bio) -{ -#ifdef CONFIG_BLK_CGROUP - if (bio && bio->bi_ioc) - return bio->bi_ioc; -#endif - return current->io_context; -} - /** * get_request - get a free request * @q: request_queue to allocate request from @@ -840,7 +779,7 @@ static struct io_context *rq_ioc(struct bio *bio) static struct request *get_request(struct request_queue *q, int rw_flags, struct bio *bio, gfp_t gfp_mask) { - struct request *rq; + struct request *rq = NULL; struct request_list *rl = &q->rq; struct elevator_type *et; struct io_context *ioc; @@ -850,7 +789,7 @@ static struct request *get_request(struct request_queue *q, int rw_flags, int may_queue; retry: et = q->elevator->type; - ioc = rq_ioc(bio); + ioc = current->io_context; if (unlikely(blk_queue_dead(q))) return NULL; @@ -869,7 +808,7 @@ static struct request *get_request(struct request_queue *q, int rw_flags, */ if (!ioc && !retried) { spin_unlock_irq(q->queue_lock); - create_io_context(gfp_mask, q->node); + create_io_context(current, gfp_mask, q->node); spin_lock_irq(q->queue_lock); retried = true; goto retry; @@ -892,7 +831,7 @@ static struct request *get_request(struct request_queue *q, int rw_flags, * process is not a "batcher", and not * exempted by the IO scheduler */ - return NULL; + goto out; } } } @@ -905,7 +844,7 @@ static struct request *get_request(struct request_queue *q, int rw_flags, * allocated with any setting of ->nr_requests */ if (rl->count[is_sync] >= (3 * q->nr_requests / 2)) - return NULL; + goto out; rl->count[is_sync]++; rl->starved[is_sync] = 0; @@ -920,7 +859,8 @@ static struct request *get_request(struct request_queue *q, int rw_flags, * Also, lookup icq while holding queue_lock. If it doesn't exist, * it will be created after releasing queue_lock. */ - if (blk_rq_should_init_elevator(bio) && !blk_queue_bypass(q)) { + if (blk_rq_should_init_elevator(bio) && + !test_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags)) { rw_flags |= REQ_ELVPRIV; rl->elvpriv++; if (et->icq_cache && ioc) @@ -931,36 +871,41 @@ static struct request *get_request(struct request_queue *q, int rw_flags, rw_flags |= REQ_IO_STAT; spin_unlock_irq(q->queue_lock); - /* allocate and init request */ - rq = mempool_alloc(q->rq.rq_pool, gfp_mask); - if (!rq) - goto fail_alloc; + /* create icq if missing */ + if ((rw_flags & REQ_ELVPRIV) && unlikely(et->icq_cache && !icq)) { + icq = ioc_create_icq(q, gfp_mask); + if (!icq) + goto fail_icq; + } - blk_rq_init(q, rq); - rq->cmd_flags = rw_flags | REQ_ALLOCED; - - /* init elvpriv */ - if (rw_flags & REQ_ELVPRIV) { - if (unlikely(et->icq_cache && !icq)) { - create_io_context(gfp_mask, q->node); - ioc = rq_ioc(bio); - if (!ioc) - goto fail_elvpriv; - - icq = ioc_create_icq(ioc, q, gfp_mask); - if (!icq) - goto fail_elvpriv; - } + rq = blk_alloc_request(q, icq, rw_flags, gfp_mask); - rq->elv.icq = icq; - if (unlikely(elv_set_request(q, rq, bio, gfp_mask))) - goto fail_elvpriv; +fail_icq: + if (unlikely(!rq)) { + /* + * Allocation failed presumably due to memory. Undo anything + * we might have messed up. + * + * Allocating task should really be put onto the front of the + * wait queue, but this is pretty rare. + */ + spin_lock_irq(q->queue_lock); + freed_request(q, rw_flags); - /* @rq->elv.icq holds io_context until @rq is freed */ - if (icq) - get_io_context(icq->ioc); + /* + * in the very unlikely event that allocation failed and no + * requests for this direction was pending, mark us starved + * so that freeing of a request in the other direction will + * notice us. another possible fix would be to split the + * rq mempool into READ and WRITE + */ +rq_starved: + if (unlikely(rl->count[is_sync] == 0)) + rl->starved[is_sync] = 1; + + goto out; } -out: + /* * ioc may be NULL here, and ioc_batching will be false. That's * OK, if the queue is under the request limit then requests need @@ -971,48 +916,8 @@ static struct request *get_request(struct request_queue *q, int rw_flags, ioc->nr_batch_requests--; trace_block_getrq(q, bio, rw_flags & 1); +out: return rq; - -fail_elvpriv: - /* - * elvpriv init failed. ioc, icq and elvpriv aren't mempool backed - * and may fail indefinitely under memory pressure and thus - * shouldn't stall IO. Treat this request as !elvpriv. This will - * disturb iosched and blkcg but weird is bettern than dead. - */ - printk_ratelimited(KERN_WARNING "%s: request aux data allocation failed, iosched may be disturbed\n", - dev_name(q->backing_dev_info.dev)); - - rq->cmd_flags &= ~REQ_ELVPRIV; - rq->elv.icq = NULL; - - spin_lock_irq(q->queue_lock); - rl->elvpriv--; - spin_unlock_irq(q->queue_lock); - goto out; - -fail_alloc: - /* - * Allocation failed presumably due to memory. Undo anything we - * might have messed up. - * - * Allocating task should really be put onto the front of the wait - * queue, but this is pretty rare. - */ - spin_lock_irq(q->queue_lock); - freed_request(q, rw_flags); - - /* - * in the very unlikely event that allocation failed and no - * requests for this direction was pending, mark us starved so that - * freeing of a request in the other direction will notice - * us. another possible fix would be to split the rq mempool into - * READ and WRITE - */ -rq_starved: - if (unlikely(rl->count[is_sync] == 0)) - rl->starved[is_sync] = 1; - return NULL; } /** @@ -1056,7 +961,7 @@ static struct request *get_request_wait(struct request_queue *q, int rw_flags, * up to a big batch of them for a small period time. * See ioc_batching, ioc_set_batching */ - create_io_context(GFP_NOIO, q->node); + create_io_context(current, GFP_NOIO, q->node); ioc_set_batching(q, current->io_context); spin_lock_irq(q->queue_lock); diff --git a/trunk/block/blk-ioc.c b/trunk/block/blk-ioc.c index 893b8007c657..fb95dd2f889a 100644 --- a/trunk/block/blk-ioc.c +++ b/trunk/block/blk-ioc.c @@ -155,20 +155,20 @@ void put_io_context(struct io_context *ioc) } EXPORT_SYMBOL(put_io_context); -/** - * put_io_context_active - put active reference on ioc - * @ioc: ioc of interest - * - * Undo get_io_context_active(). If active reference reaches zero after - * put, @ioc can never issue further IOs and ioscheds are notified. - */ -void put_io_context_active(struct io_context *ioc) +/* Called by the exiting task */ +void exit_io_context(struct task_struct *task) { + struct io_context *ioc; + struct io_cq *icq; struct hlist_node *n; unsigned long flags; - struct io_cq *icq; - if (!atomic_dec_and_test(&ioc->active_ref)) { + task_lock(task); + ioc = task->io_context; + task->io_context = NULL; + task_unlock(task); + + if (!atomic_dec_and_test(&ioc->nr_tasks)) { put_io_context(ioc); return; } @@ -197,20 +197,6 @@ void put_io_context_active(struct io_context *ioc) put_io_context(ioc); } -/* Called by the exiting task */ -void exit_io_context(struct task_struct *task) -{ - struct io_context *ioc; - - task_lock(task); - ioc = task->io_context; - task->io_context = NULL; - task_unlock(task); - - atomic_dec(&ioc->nr_tasks); - put_io_context_active(ioc); -} - /** * ioc_clear_queue - break any ioc association with the specified queue * @q: request_queue being cleared @@ -232,19 +218,19 @@ void ioc_clear_queue(struct request_queue *q) } } -int create_task_io_context(struct task_struct *task, gfp_t gfp_flags, int node) +void create_io_context_slowpath(struct task_struct *task, gfp_t gfp_flags, + int node) { struct io_context *ioc; - int ret; ioc = kmem_cache_alloc_node(iocontext_cachep, gfp_flags | __GFP_ZERO, node); if (unlikely(!ioc)) - return -ENOMEM; + return; /* initialize */ atomic_long_set(&ioc->refcount, 1); - atomic_set(&ioc->active_ref, 1); + atomic_set(&ioc->nr_tasks, 1); spin_lock_init(&ioc->lock); INIT_RADIX_TREE(&ioc->icq_tree, GFP_ATOMIC | __GFP_HIGH); INIT_HLIST_HEAD(&ioc->icq_list); @@ -263,12 +249,7 @@ int create_task_io_context(struct task_struct *task, gfp_t gfp_flags, int node) task->io_context = ioc; else kmem_cache_free(iocontext_cachep, ioc); - - ret = task->io_context ? 0 : -EBUSY; - task_unlock(task); - - return ret; } /** @@ -300,7 +281,7 @@ struct io_context *get_task_io_context(struct task_struct *task, return ioc; } task_unlock(task); - } while (!create_task_io_context(task, gfp_flags, node)); + } while (create_io_context(task, gfp_flags, node)); return NULL; } @@ -344,23 +325,26 @@ EXPORT_SYMBOL(ioc_lookup_icq); /** * ioc_create_icq - create and link io_cq - * @ioc: io_context of interest * @q: request_queue of interest * @gfp_mask: allocation mask * - * Make sure io_cq linking @ioc and @q exists. If icq doesn't exist, they - * will be created using @gfp_mask. + * Make sure io_cq linking %current->io_context and @q exists. If either + * io_context and/or icq don't exist, they will be created using @gfp_mask. * * The caller is responsible for ensuring @ioc won't go away and @q is * alive and will stay alive until this function returns. */ -struct io_cq *ioc_create_icq(struct io_context *ioc, struct request_queue *q, - gfp_t gfp_mask) +struct io_cq *ioc_create_icq(struct request_queue *q, gfp_t gfp_mask) { struct elevator_type *et = q->elevator->type; + struct io_context *ioc; struct io_cq *icq; /* allocate stuff */ + ioc = create_io_context(current, gfp_mask, q->node); + if (!ioc) + return NULL; + icq = kmem_cache_alloc_node(et->icq_cache, gfp_mask | __GFP_ZERO, q->node); if (!icq) @@ -398,6 +382,74 @@ struct io_cq *ioc_create_icq(struct io_context *ioc, struct request_queue *q, return icq; } +void ioc_set_icq_flags(struct io_context *ioc, unsigned int flags) +{ + struct io_cq *icq; + struct hlist_node *n; + + hlist_for_each_entry(icq, n, &ioc->icq_list, ioc_node) + icq->flags |= flags; +} + +/** + * ioc_ioprio_changed - notify ioprio change + * @ioc: io_context of interest + * @ioprio: new ioprio + * + * @ioc's ioprio has changed to @ioprio. Set %ICQ_IOPRIO_CHANGED for all + * icq's. iosched is responsible for checking the bit and applying it on + * request issue path. + */ +void ioc_ioprio_changed(struct io_context *ioc, int ioprio) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->lock, flags); + ioc->ioprio = ioprio; + ioc_set_icq_flags(ioc, ICQ_IOPRIO_CHANGED); + spin_unlock_irqrestore(&ioc->lock, flags); +} + +/** + * ioc_cgroup_changed - notify cgroup change + * @ioc: io_context of interest + * + * @ioc's cgroup has changed. Set %ICQ_CGROUP_CHANGED for all icq's. + * iosched is responsible for checking the bit and applying it on request + * issue path. + */ +void ioc_cgroup_changed(struct io_context *ioc) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->lock, flags); + ioc_set_icq_flags(ioc, ICQ_CGROUP_CHANGED); + spin_unlock_irqrestore(&ioc->lock, flags); +} +EXPORT_SYMBOL(ioc_cgroup_changed); + +/** + * icq_get_changed - fetch and clear icq changed mask + * @icq: icq of interest + * + * Fetch and clear ICQ_*_CHANGED bits from @icq. Grabs and releases + * @icq->ioc->lock. + */ +unsigned icq_get_changed(struct io_cq *icq) +{ + unsigned int changed = 0; + unsigned long flags; + + if (unlikely(icq->flags & ICQ_CHANGED_MASK)) { + spin_lock_irqsave(&icq->ioc->lock, flags); + changed = icq->flags & ICQ_CHANGED_MASK; + icq->flags &= ~ICQ_CHANGED_MASK; + spin_unlock_irqrestore(&icq->ioc->lock, flags); + } + return changed; +} +EXPORT_SYMBOL(icq_get_changed); + static int __init blk_ioc_init(void) { iocontext_cachep = kmem_cache_create("blkdev_ioc", diff --git a/trunk/block/blk-sysfs.c b/trunk/block/blk-sysfs.c index aa41b47c22d2..cf150011d808 100644 --- a/trunk/block/blk-sysfs.c +++ b/trunk/block/blk-sysfs.c @@ -9,7 +9,6 @@ #include #include "blk.h" -#include "blk-cgroup.h" struct queue_sysfs_entry { struct attribute attr; @@ -480,8 +479,6 @@ static void blk_release_queue(struct kobject *kobj) blk_sync_queue(q); - blkcg_exit_queue(q); - if (q->elevator) { spin_lock_irq(q->queue_lock); ioc_clear_queue(q); @@ -489,12 +486,15 @@ static void blk_release_queue(struct kobject *kobj) elevator_exit(q->elevator); } + blk_throtl_exit(q); + if (rl->rq_pool) mempool_destroy(rl->rq_pool); if (q->queue_tags) __blk_queue_free_tags(q); + blk_throtl_release(q); blk_trace_shutdown(q); bdi_destroy(&q->backing_dev_info); diff --git a/trunk/block/blk-throttle.c b/trunk/block/blk-throttle.c index 5b0659512047..f2ddb94626bd 100644 --- a/trunk/block/blk-throttle.c +++ b/trunk/block/blk-throttle.c @@ -21,8 +21,6 @@ static int throtl_quantum = 32; /* Throttling is performed over 100ms slice and after that slice is renewed */ static unsigned long throtl_slice = HZ/10; /* 100 ms */ -static struct blkcg_policy blkcg_policy_throtl; - /* A workqueue to queue throttle related work */ static struct workqueue_struct *kthrotld_workqueue; static void throtl_schedule_delayed_work(struct throtl_data *td, @@ -40,17 +38,9 @@ struct throtl_rb_root { #define rb_entry_tg(node) rb_entry((node), struct throtl_grp, rb_node) -/* Per-cpu group stats */ -struct tg_stats_cpu { - /* total bytes transferred */ - struct blkg_rwstat service_bytes; - /* total IOs serviced, post merge */ - struct blkg_rwstat serviced; -}; - struct throtl_grp { - /* must be the first member */ - struct blkg_policy_data pd; + /* List of throtl groups on the request queue*/ + struct hlist_node tg_node; /* active throtl group service_tree member */ struct rb_node rb_node; @@ -62,6 +52,8 @@ struct throtl_grp { */ unsigned long disptime; + struct blkio_group blkg; + atomic_t ref; unsigned int flags; /* Two lists for READ and WRITE */ @@ -88,18 +80,18 @@ struct throtl_grp { /* Some throttle limits got updated for the group */ int limits_changed; - /* Per cpu stats pointer */ - struct tg_stats_cpu __percpu *stats_cpu; - - /* List of tgs waiting for per cpu stats memory to be allocated */ - struct list_head stats_alloc_node; + struct rcu_head rcu_head; }; struct throtl_data { + /* List of throtl groups */ + struct hlist_head tg_list; + /* service tree for active throtl groups */ struct throtl_rb_root tg_service_tree; + struct throtl_grp *root_tg; struct request_queue *queue; /* Total Number of queued bios on READ and WRITE lists */ @@ -116,33 +108,6 @@ struct throtl_data int limits_changed; }; -/* list and work item to allocate percpu group stats */ -static DEFINE_SPINLOCK(tg_stats_alloc_lock); -static LIST_HEAD(tg_stats_alloc_list); - -static void tg_stats_alloc_fn(struct work_struct *); -static DECLARE_DELAYED_WORK(tg_stats_alloc_work, tg_stats_alloc_fn); - -static inline struct throtl_grp *pd_to_tg(struct blkg_policy_data *pd) -{ - return pd ? container_of(pd, struct throtl_grp, pd) : NULL; -} - -static inline struct throtl_grp *blkg_to_tg(struct blkcg_gq *blkg) -{ - return pd_to_tg(blkg_to_pd(blkg, &blkcg_policy_throtl)); -} - -static inline struct blkcg_gq *tg_to_blkg(struct throtl_grp *tg) -{ - return pd_to_blkg(&tg->pd); -} - -static inline struct throtl_grp *td_root_tg(struct throtl_data *td) -{ - return blkg_to_tg(td->queue->root_blkg); -} - enum tg_state_flags { THROTL_TG_FLAG_on_rr = 0, /* on round-robin busy list */ }; @@ -163,150 +128,244 @@ static inline int throtl_tg_##name(const struct throtl_grp *tg) \ THROTL_TG_FNS(on_rr); -#define throtl_log_tg(td, tg, fmt, args...) do { \ - char __pbuf[128]; \ - \ - blkg_path(tg_to_blkg(tg), __pbuf, sizeof(__pbuf)); \ - blk_add_trace_msg((td)->queue, "throtl %s " fmt, __pbuf, ##args); \ -} while (0) +#define throtl_log_tg(td, tg, fmt, args...) \ + blk_add_trace_msg((td)->queue, "throtl %s " fmt, \ + blkg_path(&(tg)->blkg), ##args); \ #define throtl_log(td, fmt, args...) \ blk_add_trace_msg((td)->queue, "throtl " fmt, ##args) +static inline struct throtl_grp *tg_of_blkg(struct blkio_group *blkg) +{ + if (blkg) + return container_of(blkg, struct throtl_grp, blkg); + + return NULL; +} + static inline unsigned int total_nr_queued(struct throtl_data *td) { return td->nr_queued[0] + td->nr_queued[1]; } -/* - * Worker for allocating per cpu stat for tgs. This is scheduled on the - * system_nrt_wq once there are some groups on the alloc_list waiting for - * allocation. - */ -static void tg_stats_alloc_fn(struct work_struct *work) +static inline struct throtl_grp *throtl_ref_get_tg(struct throtl_grp *tg) { - static struct tg_stats_cpu *stats_cpu; /* this fn is non-reentrant */ - struct delayed_work *dwork = to_delayed_work(work); - bool empty = false; - -alloc_stats: - if (!stats_cpu) { - stats_cpu = alloc_percpu(struct tg_stats_cpu); - if (!stats_cpu) { - /* allocation failed, try again after some time */ - queue_delayed_work(system_nrt_wq, dwork, - msecs_to_jiffies(10)); - return; - } - } - - spin_lock_irq(&tg_stats_alloc_lock); + atomic_inc(&tg->ref); + return tg; +} - if (!list_empty(&tg_stats_alloc_list)) { - struct throtl_grp *tg = list_first_entry(&tg_stats_alloc_list, - struct throtl_grp, - stats_alloc_node); - swap(tg->stats_cpu, stats_cpu); - list_del_init(&tg->stats_alloc_node); - } +static void throtl_free_tg(struct rcu_head *head) +{ + struct throtl_grp *tg; - empty = list_empty(&tg_stats_alloc_list); - spin_unlock_irq(&tg_stats_alloc_lock); - if (!empty) - goto alloc_stats; + tg = container_of(head, struct throtl_grp, rcu_head); + free_percpu(tg->blkg.stats_cpu); + kfree(tg); } -static void throtl_pd_init(struct blkcg_gq *blkg) +static void throtl_put_tg(struct throtl_grp *tg) { - struct throtl_grp *tg = blkg_to_tg(blkg); - unsigned long flags; + BUG_ON(atomic_read(&tg->ref) <= 0); + if (!atomic_dec_and_test(&tg->ref)) + return; + + /* + * A group is freed in rcu manner. But having an rcu lock does not + * mean that one can access all the fields of blkg and assume these + * are valid. For example, don't try to follow throtl_data and + * request queue links. + * + * Having a reference to blkg under an rcu allows acess to only + * values local to groups like group stats and group rate limits + */ + call_rcu(&tg->rcu_head, throtl_free_tg); +} +static void throtl_init_group(struct throtl_grp *tg) +{ + INIT_HLIST_NODE(&tg->tg_node); RB_CLEAR_NODE(&tg->rb_node); bio_list_init(&tg->bio_lists[0]); bio_list_init(&tg->bio_lists[1]); tg->limits_changed = false; - tg->bps[READ] = -1; - tg->bps[WRITE] = -1; - tg->iops[READ] = -1; - tg->iops[WRITE] = -1; + /* Practically unlimited BW */ + tg->bps[0] = tg->bps[1] = -1; + tg->iops[0] = tg->iops[1] = -1; /* - * Ugh... We need to perform per-cpu allocation for tg->stats_cpu - * but percpu allocator can't be called from IO path. Queue tg on - * tg_stats_alloc_list and allocate from work item. + * Take the initial reference that will be released on destroy + * This can be thought of a joint reference by cgroup and + * request queue which will be dropped by either request queue + * exit or cgroup deletion path depending on who is exiting first. */ - spin_lock_irqsave(&tg_stats_alloc_lock, flags); - list_add(&tg->stats_alloc_node, &tg_stats_alloc_list); - queue_delayed_work(system_nrt_wq, &tg_stats_alloc_work, 0); - spin_unlock_irqrestore(&tg_stats_alloc_lock, flags); + atomic_set(&tg->ref, 1); } -static void throtl_pd_exit(struct blkcg_gq *blkg) +/* Should be called with rcu read lock held (needed for blkcg) */ +static void +throtl_add_group_to_td_list(struct throtl_data *td, struct throtl_grp *tg) { - struct throtl_grp *tg = blkg_to_tg(blkg); - unsigned long flags; + hlist_add_head(&tg->tg_node, &td->tg_list); + td->nr_undestroyed_grps++; +} - spin_lock_irqsave(&tg_stats_alloc_lock, flags); - list_del_init(&tg->stats_alloc_node); - spin_unlock_irqrestore(&tg_stats_alloc_lock, flags); +static void +__throtl_tg_fill_dev_details(struct throtl_data *td, struct throtl_grp *tg) +{ + struct backing_dev_info *bdi = &td->queue->backing_dev_info; + unsigned int major, minor; - free_percpu(tg->stats_cpu); + if (!tg || tg->blkg.dev) + return; + + /* + * Fill in device details for a group which might not have been + * filled at group creation time as queue was being instantiated + * and driver had not attached a device yet + */ + if (bdi->dev && dev_name(bdi->dev)) { + sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor); + tg->blkg.dev = MKDEV(major, minor); + } } -static void throtl_pd_reset_stats(struct blkcg_gq *blkg) +/* + * Should be called with without queue lock held. Here queue lock will be + * taken rarely. It will be taken only once during life time of a group + * if need be + */ +static void +throtl_tg_fill_dev_details(struct throtl_data *td, struct throtl_grp *tg) { - struct throtl_grp *tg = blkg_to_tg(blkg); - int cpu; - - if (tg->stats_cpu == NULL) + if (!tg || tg->blkg.dev) return; - for_each_possible_cpu(cpu) { - struct tg_stats_cpu *sc = per_cpu_ptr(tg->stats_cpu, cpu); + spin_lock_irq(td->queue->queue_lock); + __throtl_tg_fill_dev_details(td, tg); + spin_unlock_irq(td->queue->queue_lock); +} + +static void throtl_init_add_tg_lists(struct throtl_data *td, + struct throtl_grp *tg, struct blkio_cgroup *blkcg) +{ + __throtl_tg_fill_dev_details(td, tg); + + /* Add group onto cgroup list */ + blkiocg_add_blkio_group(blkcg, &tg->blkg, (void *)td, + tg->blkg.dev, BLKIO_POLICY_THROTL); + + tg->bps[READ] = blkcg_get_read_bps(blkcg, tg->blkg.dev); + tg->bps[WRITE] = blkcg_get_write_bps(blkcg, tg->blkg.dev); + tg->iops[READ] = blkcg_get_read_iops(blkcg, tg->blkg.dev); + tg->iops[WRITE] = blkcg_get_write_iops(blkcg, tg->blkg.dev); + + throtl_add_group_to_td_list(td, tg); +} + +/* Should be called without queue lock and outside of rcu period */ +static struct throtl_grp *throtl_alloc_tg(struct throtl_data *td) +{ + struct throtl_grp *tg = NULL; + int ret; + + tg = kzalloc_node(sizeof(*tg), GFP_ATOMIC, td->queue->node); + if (!tg) + return NULL; + + ret = blkio_alloc_blkg_stats(&tg->blkg); - blkg_rwstat_reset(&sc->service_bytes); - blkg_rwstat_reset(&sc->serviced); + if (ret) { + kfree(tg); + return NULL; } + + throtl_init_group(tg); + return tg; } -static struct throtl_grp *throtl_lookup_tg(struct throtl_data *td, - struct blkcg *blkcg) +static struct +throtl_grp *throtl_find_tg(struct throtl_data *td, struct blkio_cgroup *blkcg) { + struct throtl_grp *tg = NULL; + void *key = td; + /* - * This is the common case when there are no blkcgs. Avoid lookup - * in this case - */ - if (blkcg == &blkcg_root) - return td_root_tg(td); + * This is the common case when there are no blkio cgroups. + * Avoid lookup in this case + */ + if (blkcg == &blkio_root_cgroup) + tg = td->root_tg; + else + tg = tg_of_blkg(blkiocg_lookup_group(blkcg, key)); - return blkg_to_tg(blkg_lookup(blkcg, td->queue)); + __throtl_tg_fill_dev_details(td, tg); + return tg; } -static struct throtl_grp *throtl_lookup_create_tg(struct throtl_data *td, - struct blkcg *blkcg) +static struct throtl_grp * throtl_get_tg(struct throtl_data *td) { + struct throtl_grp *tg = NULL, *__tg = NULL; + struct blkio_cgroup *blkcg; struct request_queue *q = td->queue; - struct throtl_grp *tg = NULL; + + /* no throttling for dead queue */ + if (unlikely(blk_queue_dead(q))) + return NULL; + + rcu_read_lock(); + blkcg = task_blkio_cgroup(current); + tg = throtl_find_tg(td, blkcg); + if (tg) { + rcu_read_unlock(); + return tg; + } + + /* + * Need to allocate a group. Allocation of group also needs allocation + * of per cpu stats which in-turn takes a mutex() and can block. Hence + * we need to drop rcu lock and queue_lock before we call alloc. + */ + rcu_read_unlock(); + spin_unlock_irq(q->queue_lock); + + tg = throtl_alloc_tg(td); + + /* Group allocated and queue is still alive. take the lock */ + spin_lock_irq(q->queue_lock); + + /* Make sure @q is still alive */ + if (unlikely(blk_queue_dead(q))) { + kfree(tg); + return NULL; + } /* - * This is the common case when there are no blkcgs. Avoid lookup - * in this case + * Initialize the new group. After sleeping, read the blkcg again. */ - if (blkcg == &blkcg_root) { - tg = td_root_tg(td); - } else { - struct blkcg_gq *blkg; - - blkg = blkg_lookup_create(blkcg, q); - - /* if %NULL and @q is alive, fall back to root_tg */ - if (!IS_ERR(blkg)) - tg = blkg_to_tg(blkg); - else if (!blk_queue_dead(q)) - tg = td_root_tg(td); + rcu_read_lock(); + blkcg = task_blkio_cgroup(current); + + /* + * If some other thread already allocated the group while we were + * not holding queue lock, free up the group + */ + __tg = throtl_find_tg(td, blkcg); + + if (__tg) { + kfree(tg); + rcu_read_unlock(); + return __tg; + } + + /* Group allocation failed. Account the IO to root group */ + if (!tg) { + tg = td->root_tg; + return tg; } + throtl_init_add_tg_lists(td, tg, blkcg); + rcu_read_unlock(); return tg; } @@ -675,41 +734,16 @@ static bool tg_may_dispatch(struct throtl_data *td, struct throtl_grp *tg, return 0; } -static void throtl_update_dispatch_stats(struct blkcg_gq *blkg, u64 bytes, - int rw) -{ - struct throtl_grp *tg = blkg_to_tg(blkg); - struct tg_stats_cpu *stats_cpu; - unsigned long flags; - - /* If per cpu stats are not allocated yet, don't do any accounting. */ - if (tg->stats_cpu == NULL) - return; - - /* - * Disabling interrupts to provide mutual exclusion between two - * writes on same cpu. It probably is not needed for 64bit. Not - * optimizing that case yet. - */ - local_irq_save(flags); - - stats_cpu = this_cpu_ptr(tg->stats_cpu); - - blkg_rwstat_add(&stats_cpu->serviced, rw, 1); - blkg_rwstat_add(&stats_cpu->service_bytes, rw, bytes); - - local_irq_restore(flags); -} - static void throtl_charge_bio(struct throtl_grp *tg, struct bio *bio) { bool rw = bio_data_dir(bio); + bool sync = rw_is_sync(bio->bi_rw); /* Charge the bio to the group */ tg->bytes_disp[rw] += bio->bi_size; tg->io_disp[rw]++; - throtl_update_dispatch_stats(tg_to_blkg(tg), bio->bi_size, bio->bi_rw); + blkiocg_update_dispatch_stats(&tg->blkg, bio->bi_size, rw, sync); } static void throtl_add_bio_tg(struct throtl_data *td, struct throtl_grp *tg, @@ -719,7 +753,7 @@ static void throtl_add_bio_tg(struct throtl_data *td, struct throtl_grp *tg, bio_list_add(&tg->bio_lists[rw], bio); /* Take a bio reference on tg */ - blkg_get(tg_to_blkg(tg)); + throtl_ref_get_tg(tg); tg->nr_queued[rw]++; td->nr_queued[rw]++; throtl_enqueue_tg(td, tg); @@ -752,8 +786,8 @@ static void tg_dispatch_one_bio(struct throtl_data *td, struct throtl_grp *tg, bio = bio_list_pop(&tg->bio_lists[rw]); tg->nr_queued[rw]--; - /* Drop bio reference on blkg */ - blkg_put(tg_to_blkg(tg)); + /* Drop bio reference on tg */ + throtl_put_tg(tg); BUG_ON(td->nr_queued[rw] <= 0); td->nr_queued[rw]--; @@ -831,8 +865,8 @@ static int throtl_select_dispatch(struct throtl_data *td, struct bio_list *bl) static void throtl_process_limit_change(struct throtl_data *td) { - struct request_queue *q = td->queue; - struct blkcg_gq *blkg, *n; + struct throtl_grp *tg; + struct hlist_node *pos, *n; if (!td->limits_changed) return; @@ -841,9 +875,7 @@ static void throtl_process_limit_change(struct throtl_data *td) throtl_log(td, "limits changed"); - list_for_each_entry_safe(blkg, n, &q->blkg_list, q_node) { - struct throtl_grp *tg = blkg_to_tg(blkg); - + hlist_for_each_entry_safe(tg, pos, n, &td->tg_list, tg_node) { if (!tg->limits_changed) continue; @@ -941,158 +973,119 @@ throtl_schedule_delayed_work(struct throtl_data *td, unsigned long delay) } } -static u64 tg_prfill_cpu_rwstat(struct seq_file *sf, - struct blkg_policy_data *pd, int off) +static void +throtl_destroy_tg(struct throtl_data *td, struct throtl_grp *tg) { - struct throtl_grp *tg = pd_to_tg(pd); - struct blkg_rwstat rwstat = { }, tmp; - int i, cpu; + /* Something wrong if we are trying to remove same group twice */ + BUG_ON(hlist_unhashed(&tg->tg_node)); - for_each_possible_cpu(cpu) { - struct tg_stats_cpu *sc = per_cpu_ptr(tg->stats_cpu, cpu); - - tmp = blkg_rwstat_read((void *)sc + off); - for (i = 0; i < BLKG_RWSTAT_NR; i++) - rwstat.cnt[i] += tmp.cnt[i]; - } + hlist_del_init(&tg->tg_node); - return __blkg_prfill_rwstat(sf, pd, &rwstat); + /* + * Put the reference taken at the time of creation so that when all + * queues are gone, group can be destroyed. + */ + throtl_put_tg(tg); + td->nr_undestroyed_grps--; } -static int tg_print_cpu_rwstat(struct cgroup *cgrp, struct cftype *cft, - struct seq_file *sf) +static void throtl_release_tgs(struct throtl_data *td) { - struct blkcg *blkcg = cgroup_to_blkcg(cgrp); + struct hlist_node *pos, *n; + struct throtl_grp *tg; - blkcg_print_blkgs(sf, blkcg, tg_prfill_cpu_rwstat, &blkcg_policy_throtl, - cft->private, true); - return 0; + hlist_for_each_entry_safe(tg, pos, n, &td->tg_list, tg_node) { + /* + * If cgroup removal path got to blk_group first and removed + * it from cgroup list, then it will take care of destroying + * cfqg also. + */ + if (!blkiocg_del_blkio_group(&tg->blkg)) + throtl_destroy_tg(td, tg); + } } -static u64 tg_prfill_conf_u64(struct seq_file *sf, struct blkg_policy_data *pd, - int off) +/* + * Blk cgroup controller notification saying that blkio_group object is being + * delinked as associated cgroup object is going away. That also means that + * no new IO will come in this group. So get rid of this group as soon as + * any pending IO in the group is finished. + * + * This function is called under rcu_read_lock(). key is the rcu protected + * pointer. That means "key" is a valid throtl_data pointer as long as we are + * rcu read lock. + * + * "key" was fetched from blkio_group under blkio_cgroup->lock. That means + * it should not be NULL as even if queue was going away, cgroup deltion + * path got to it first. + */ +void throtl_unlink_blkio_group(void *key, struct blkio_group *blkg) { - struct throtl_grp *tg = pd_to_tg(pd); - u64 v = *(u64 *)((void *)tg + off); + unsigned long flags; + struct throtl_data *td = key; - if (v == -1) - return 0; - return __blkg_prfill_u64(sf, pd, v); + spin_lock_irqsave(td->queue->queue_lock, flags); + throtl_destroy_tg(td, tg_of_blkg(blkg)); + spin_unlock_irqrestore(td->queue->queue_lock, flags); } -static u64 tg_prfill_conf_uint(struct seq_file *sf, struct blkg_policy_data *pd, - int off) +static void throtl_update_blkio_group_common(struct throtl_data *td, + struct throtl_grp *tg) { - struct throtl_grp *tg = pd_to_tg(pd); - unsigned int v = *(unsigned int *)((void *)tg + off); - - if (v == -1) - return 0; - return __blkg_prfill_u64(sf, pd, v); + xchg(&tg->limits_changed, true); + xchg(&td->limits_changed, true); + /* Schedule a work now to process the limit change */ + throtl_schedule_delayed_work(td, 0); } -static int tg_print_conf_u64(struct cgroup *cgrp, struct cftype *cft, - struct seq_file *sf) +/* + * For all update functions, key should be a valid pointer because these + * update functions are called under blkcg_lock, that means, blkg is + * valid and in turn key is valid. queue exit path can not race because + * of blkcg_lock + * + * Can not take queue lock in update functions as queue lock under blkcg_lock + * is not allowed. Under other paths we take blkcg_lock under queue_lock. + */ +static void throtl_update_blkio_group_read_bps(void *key, + struct blkio_group *blkg, u64 read_bps) { - blkcg_print_blkgs(sf, cgroup_to_blkcg(cgrp), tg_prfill_conf_u64, - &blkcg_policy_throtl, cft->private, false); - return 0; -} + struct throtl_data *td = key; + struct throtl_grp *tg = tg_of_blkg(blkg); -static int tg_print_conf_uint(struct cgroup *cgrp, struct cftype *cft, - struct seq_file *sf) -{ - blkcg_print_blkgs(sf, cgroup_to_blkcg(cgrp), tg_prfill_conf_uint, - &blkcg_policy_throtl, cft->private, false); - return 0; + tg->bps[READ] = read_bps; + throtl_update_blkio_group_common(td, tg); } -static int tg_set_conf(struct cgroup *cgrp, struct cftype *cft, const char *buf, - bool is_u64) +static void throtl_update_blkio_group_write_bps(void *key, + struct blkio_group *blkg, u64 write_bps) { - struct blkcg *blkcg = cgroup_to_blkcg(cgrp); - struct blkg_conf_ctx ctx; - struct throtl_grp *tg; - struct throtl_data *td; - int ret; - - ret = blkg_conf_prep(blkcg, &blkcg_policy_throtl, buf, &ctx); - if (ret) - return ret; - - tg = blkg_to_tg(ctx.blkg); - td = ctx.blkg->q->td; - - if (!ctx.v) - ctx.v = -1; - - if (is_u64) - *(u64 *)((void *)tg + cft->private) = ctx.v; - else - *(unsigned int *)((void *)tg + cft->private) = ctx.v; - - /* XXX: we don't need the following deferred processing */ - xchg(&tg->limits_changed, true); - xchg(&td->limits_changed, true); - throtl_schedule_delayed_work(td, 0); + struct throtl_data *td = key; + struct throtl_grp *tg = tg_of_blkg(blkg); - blkg_conf_finish(&ctx); - return 0; + tg->bps[WRITE] = write_bps; + throtl_update_blkio_group_common(td, tg); } -static int tg_set_conf_u64(struct cgroup *cgrp, struct cftype *cft, - const char *buf) +static void throtl_update_blkio_group_read_iops(void *key, + struct blkio_group *blkg, unsigned int read_iops) { - return tg_set_conf(cgrp, cft, buf, true); + struct throtl_data *td = key; + struct throtl_grp *tg = tg_of_blkg(blkg); + + tg->iops[READ] = read_iops; + throtl_update_blkio_group_common(td, tg); } -static int tg_set_conf_uint(struct cgroup *cgrp, struct cftype *cft, - const char *buf) +static void throtl_update_blkio_group_write_iops(void *key, + struct blkio_group *blkg, unsigned int write_iops) { - return tg_set_conf(cgrp, cft, buf, false); -} + struct throtl_data *td = key; + struct throtl_grp *tg = tg_of_blkg(blkg); -static struct cftype throtl_files[] = { - { - .name = "throttle.read_bps_device", - .private = offsetof(struct throtl_grp, bps[READ]), - .read_seq_string = tg_print_conf_u64, - .write_string = tg_set_conf_u64, - .max_write_len = 256, - }, - { - .name = "throttle.write_bps_device", - .private = offsetof(struct throtl_grp, bps[WRITE]), - .read_seq_string = tg_print_conf_u64, - .write_string = tg_set_conf_u64, - .max_write_len = 256, - }, - { - .name = "throttle.read_iops_device", - .private = offsetof(struct throtl_grp, iops[READ]), - .read_seq_string = tg_print_conf_uint, - .write_string = tg_set_conf_uint, - .max_write_len = 256, - }, - { - .name = "throttle.write_iops_device", - .private = offsetof(struct throtl_grp, iops[WRITE]), - .read_seq_string = tg_print_conf_uint, - .write_string = tg_set_conf_uint, - .max_write_len = 256, - }, - { - .name = "throttle.io_service_bytes", - .private = offsetof(struct tg_stats_cpu, service_bytes), - .read_seq_string = tg_print_cpu_rwstat, - }, - { - .name = "throttle.io_serviced", - .private = offsetof(struct tg_stats_cpu, serviced), - .read_seq_string = tg_print_cpu_rwstat, - }, - { } /* terminate */ -}; + tg->iops[WRITE] = write_iops; + throtl_update_blkio_group_common(td, tg); +} static void throtl_shutdown_wq(struct request_queue *q) { @@ -1101,13 +1094,19 @@ static void throtl_shutdown_wq(struct request_queue *q) cancel_delayed_work_sync(&td->throtl_work); } -static struct blkcg_policy blkcg_policy_throtl = { - .pd_size = sizeof(struct throtl_grp), - .cftypes = throtl_files, - - .pd_init_fn = throtl_pd_init, - .pd_exit_fn = throtl_pd_exit, - .pd_reset_stats_fn = throtl_pd_reset_stats, +static struct blkio_policy_type blkio_policy_throtl = { + .ops = { + .blkio_unlink_group_fn = throtl_unlink_blkio_group, + .blkio_update_group_read_bps_fn = + throtl_update_blkio_group_read_bps, + .blkio_update_group_write_bps_fn = + throtl_update_blkio_group_write_bps, + .blkio_update_group_read_iops_fn = + throtl_update_blkio_group_read_iops, + .blkio_update_group_write_iops_fn = + throtl_update_blkio_group_write_iops, + }, + .plid = BLKIO_POLICY_THROTL, }; bool blk_throtl_bio(struct request_queue *q, struct bio *bio) @@ -1115,7 +1114,7 @@ bool blk_throtl_bio(struct request_queue *q, struct bio *bio) struct throtl_data *td = q->td; struct throtl_grp *tg; bool rw = bio_data_dir(bio), update_disptime = true; - struct blkcg *blkcg; + struct blkio_cgroup *blkcg; bool throttled = false; if (bio->bi_rw & REQ_THROTTLED) { @@ -1123,31 +1122,33 @@ bool blk_throtl_bio(struct request_queue *q, struct bio *bio) goto out; } - /* bio_associate_current() needs ioc, try creating */ - create_io_context(GFP_ATOMIC, q->node); - /* * A throtl_grp pointer retrieved under rcu can be used to access * basic fields like stats and io rates. If a group has no rules, * just update the dispatch stats in lockless manner and return. */ + rcu_read_lock(); - blkcg = bio_blkcg(bio); - tg = throtl_lookup_tg(td, blkcg); + blkcg = task_blkio_cgroup(current); + tg = throtl_find_tg(td, blkcg); if (tg) { + throtl_tg_fill_dev_details(td, tg); + if (tg_no_rule_group(tg, rw)) { - throtl_update_dispatch_stats(tg_to_blkg(tg), - bio->bi_size, bio->bi_rw); - goto out_unlock_rcu; + blkiocg_update_dispatch_stats(&tg->blkg, bio->bi_size, + rw, rw_is_sync(bio->bi_rw)); + rcu_read_unlock(); + goto out; } } + rcu_read_unlock(); /* * Either group has not been allocated yet or it is not an unlimited * IO group */ spin_lock_irq(q->queue_lock); - tg = throtl_lookup_create_tg(td, blkcg); + tg = throtl_get_tg(td); if (unlikely(!tg)) goto out_unlock; @@ -1188,7 +1189,6 @@ bool blk_throtl_bio(struct request_queue *q, struct bio *bio) tg->io_disp[rw], tg->iops[rw], tg->nr_queued[READ], tg->nr_queued[WRITE]); - bio_associate_current(bio); throtl_add_bio_tg(q->td, tg, bio); throttled = true; @@ -1199,8 +1199,6 @@ bool blk_throtl_bio(struct request_queue *q, struct bio *bio) out_unlock: spin_unlock_irq(q->queue_lock); -out_unlock_rcu: - rcu_read_unlock(); out: return throttled; } @@ -1243,31 +1241,79 @@ void blk_throtl_drain(struct request_queue *q) int blk_throtl_init(struct request_queue *q) { struct throtl_data *td; - int ret; + struct throtl_grp *tg; td = kzalloc_node(sizeof(*td), GFP_KERNEL, q->node); if (!td) return -ENOMEM; + INIT_HLIST_HEAD(&td->tg_list); td->tg_service_tree = THROTL_RB_ROOT; td->limits_changed = false; INIT_DELAYED_WORK(&td->throtl_work, blk_throtl_work); - q->td = td; + /* alloc and Init root group. */ td->queue = q; + tg = throtl_alloc_tg(td); - /* activate policy */ - ret = blkcg_activate_policy(q, &blkcg_policy_throtl); - if (ret) + if (!tg) { kfree(td); - return ret; + return -ENOMEM; + } + + td->root_tg = tg; + + rcu_read_lock(); + throtl_init_add_tg_lists(td, tg, &blkio_root_cgroup); + rcu_read_unlock(); + + /* Attach throtl data to request queue */ + q->td = td; + return 0; } void blk_throtl_exit(struct request_queue *q) { - BUG_ON(!q->td); + struct throtl_data *td = q->td; + bool wait = false; + + BUG_ON(!td); + + throtl_shutdown_wq(q); + + spin_lock_irq(q->queue_lock); + throtl_release_tgs(td); + + /* If there are other groups */ + if (td->nr_undestroyed_grps > 0) + wait = true; + + spin_unlock_irq(q->queue_lock); + + /* + * Wait for tg->blkg->key accessors to exit their grace periods. + * Do this wait only if there are other undestroyed groups out + * there (other than root group). This can happen if cgroup deletion + * path claimed the responsibility of cleaning up a group before + * queue cleanup code get to the group. + * + * Do not call synchronize_rcu() unconditionally as there are drivers + * which create/delete request queue hundreds of times during scan/boot + * and synchronize_rcu() can take significant time and slow down boot. + */ + if (wait) + synchronize_rcu(); + + /* + * Just being safe to make sure after previous flush if some body did + * update limits through cgroup and another work got queued, cancel + * it. + */ throtl_shutdown_wq(q); - blkcg_deactivate_policy(q, &blkcg_policy_throtl); +} + +void blk_throtl_release(struct request_queue *q) +{ kfree(q->td); } @@ -1277,7 +1323,8 @@ static int __init throtl_init(void) if (!kthrotld_workqueue) panic("Failed to create kthrotld\n"); - return blkcg_policy_register(&blkcg_policy_throtl); + blkio_policy_register(&blkio_policy_throtl); + return 0; } module_init(throtl_init); diff --git a/trunk/block/blk.h b/trunk/block/blk.h index 85f6ae42f7d3..d45be871329e 100644 --- a/trunk/block/blk.h +++ b/trunk/block/blk.h @@ -23,8 +23,7 @@ void blk_rq_bio_prep(struct request_queue *q, struct request *rq, struct bio *bio); int blk_rq_append_bio(struct request_queue *q, struct request *rq, struct bio *bio); -void blk_queue_bypass_start(struct request_queue *q); -void blk_queue_bypass_end(struct request_queue *q); +void blk_drain_queue(struct request_queue *q, bool drain_all); void blk_dequeue_request(struct request *rq); void __blk_queue_free_tags(struct request_queue *q); bool __blk_end_bidi_request(struct request *rq, int error, @@ -145,6 +144,9 @@ void blk_queue_congestion_threshold(struct request_queue *q); int blk_dev_init(void); +void elv_quiesce_start(struct request_queue *q); +void elv_quiesce_end(struct request_queue *q); + /* * Return the threshold (number of used requests) at which the queue is @@ -184,30 +186,32 @@ static inline int blk_do_io_stat(struct request *rq) */ void get_io_context(struct io_context *ioc); struct io_cq *ioc_lookup_icq(struct io_context *ioc, struct request_queue *q); -struct io_cq *ioc_create_icq(struct io_context *ioc, struct request_queue *q, - gfp_t gfp_mask); +struct io_cq *ioc_create_icq(struct request_queue *q, gfp_t gfp_mask); void ioc_clear_queue(struct request_queue *q); -int create_task_io_context(struct task_struct *task, gfp_t gfp_mask, int node); +void create_io_context_slowpath(struct task_struct *task, gfp_t gfp_mask, + int node); /** * create_io_context - try to create task->io_context + * @task: target task * @gfp_mask: allocation mask * @node: allocation node * - * If %current->io_context is %NULL, allocate a new io_context and install - * it. Returns the current %current->io_context which may be %NULL if - * allocation failed. + * If @task->io_context is %NULL, allocate a new io_context and install it. + * Returns the current @task->io_context which may be %NULL if allocation + * failed. * * Note that this function can't be called with IRQ disabled because - * task_lock which protects %current->io_context is IRQ-unsafe. + * task_lock which protects @task->io_context is IRQ-unsafe. */ -static inline struct io_context *create_io_context(gfp_t gfp_mask, int node) +static inline struct io_context *create_io_context(struct task_struct *task, + gfp_t gfp_mask, int node) { WARN_ON_ONCE(irqs_disabled()); - if (unlikely(!current->io_context)) - create_task_io_context(current, gfp_mask, node); - return current->io_context; + if (unlikely(!task->io_context)) + create_io_context_slowpath(task, gfp_mask, node); + return task->io_context; } /* @@ -218,6 +222,7 @@ extern bool blk_throtl_bio(struct request_queue *q, struct bio *bio); extern void blk_throtl_drain(struct request_queue *q); extern int blk_throtl_init(struct request_queue *q); extern void blk_throtl_exit(struct request_queue *q); +extern void blk_throtl_release(struct request_queue *q); #else /* CONFIG_BLK_DEV_THROTTLING */ static inline bool blk_throtl_bio(struct request_queue *q, struct bio *bio) { @@ -226,6 +231,7 @@ static inline bool blk_throtl_bio(struct request_queue *q, struct bio *bio) static inline void blk_throtl_drain(struct request_queue *q) { } static inline int blk_throtl_init(struct request_queue *q) { return 0; } static inline void blk_throtl_exit(struct request_queue *q) { } +static inline void blk_throtl_release(struct request_queue *q) { } #endif /* CONFIG_BLK_DEV_THROTTLING */ #endif /* BLK_INTERNAL_H */ diff --git a/trunk/block/cfq-iosched.c b/trunk/block/cfq-iosched.c index 673c977cc2bf..3c38536bd52c 100644 --- a/trunk/block/cfq-iosched.c +++ b/trunk/block/cfq-iosched.c @@ -15,9 +15,7 @@ #include #include #include "blk.h" -#include "blk-cgroup.h" - -static struct blkcg_policy blkcg_policy_cfq __maybe_unused; +#include "cfq.h" /* * tunables @@ -173,53 +171,8 @@ enum wl_type_t { SYNC_WORKLOAD = 2 }; -struct cfqg_stats { -#ifdef CONFIG_CFQ_GROUP_IOSCHED - /* total bytes transferred */ - struct blkg_rwstat service_bytes; - /* total IOs serviced, post merge */ - struct blkg_rwstat serviced; - /* number of ios merged */ - struct blkg_rwstat merged; - /* total time spent on device in ns, may not be accurate w/ queueing */ - struct blkg_rwstat service_time; - /* total time spent waiting in scheduler queue in ns */ - struct blkg_rwstat wait_time; - /* number of IOs queued up */ - struct blkg_rwstat queued; - /* total sectors transferred */ - struct blkg_stat sectors; - /* total disk time and nr sectors dispatched by this group */ - struct blkg_stat time; -#ifdef CONFIG_DEBUG_BLK_CGROUP - /* time not charged to this cgroup */ - struct blkg_stat unaccounted_time; - /* sum of number of ios queued across all samples */ - struct blkg_stat avg_queue_size_sum; - /* count of samples taken for average */ - struct blkg_stat avg_queue_size_samples; - /* how many times this group has been removed from service tree */ - struct blkg_stat dequeue; - /* total time spent waiting for it to be assigned a timeslice. */ - struct blkg_stat group_wait_time; - /* time spent idling for this blkcg_gq */ - struct blkg_stat idle_time; - /* total time with empty current active q with other requests queued */ - struct blkg_stat empty_time; - /* fields after this shouldn't be cleared on stat reset */ - uint64_t start_group_wait_time; - uint64_t start_idle_time; - uint64_t start_empty_time; - uint16_t flags; -#endif /* CONFIG_DEBUG_BLK_CGROUP */ -#endif /* CONFIG_CFQ_GROUP_IOSCHED */ -}; - /* This is per cgroup per device grouping structure */ struct cfq_group { - /* must be the first member */ - struct blkg_policy_data pd; - /* group service_tree member */ struct rb_node rb_node; @@ -227,7 +180,7 @@ struct cfq_group { u64 vdisktime; unsigned int weight; unsigned int new_weight; - unsigned int dev_weight; + bool needs_update; /* number of cfqq currently on this group */ int nr_cfqq; @@ -253,21 +206,20 @@ struct cfq_group { unsigned long saved_workload_slice; enum wl_type_t saved_workload; enum wl_prio_t saved_serving_prio; - + struct blkio_group blkg; +#ifdef CONFIG_CFQ_GROUP_IOSCHED + struct hlist_node cfqd_node; + int ref; +#endif /* number of requests that are on the dispatch list or inside driver */ int dispatched; struct cfq_ttime ttime; - struct cfqg_stats stats; }; struct cfq_io_cq { struct io_cq icq; /* must be the first member */ struct cfq_queue *cfqq[2]; struct cfq_ttime ttime; - int ioprio; /* the current ioprio */ -#ifdef CONFIG_CFQ_GROUP_IOSCHED - uint64_t blkcg_id; /* the current blkcg ID */ -#endif }; /* @@ -277,7 +229,7 @@ struct cfq_data { struct request_queue *queue; /* Root service tree for cfq_groups */ struct cfq_rb_root grp_service_tree; - struct cfq_group *root_group; + struct cfq_group root_group; /* * The priority currently being served @@ -351,6 +303,12 @@ struct cfq_data { struct cfq_queue oom_cfqq; unsigned long last_delayed_sync; + + /* List of cfq groups being managed on this device*/ + struct hlist_head cfqg_list; + + /* Number of groups which are on blkcg->blkg_list */ + unsigned int nr_blkcg_linked_grps; }; static struct cfq_group *cfq_get_next_cfqg(struct cfq_data *cfqd); @@ -413,284 +371,21 @@ CFQ_CFQQ_FNS(deep); CFQ_CFQQ_FNS(wait_busy); #undef CFQ_CFQQ_FNS -static inline struct cfq_group *pd_to_cfqg(struct blkg_policy_data *pd) -{ - return pd ? container_of(pd, struct cfq_group, pd) : NULL; -} - -static inline struct cfq_group *blkg_to_cfqg(struct blkcg_gq *blkg) -{ - return pd_to_cfqg(blkg_to_pd(blkg, &blkcg_policy_cfq)); -} - -static inline struct blkcg_gq *cfqg_to_blkg(struct cfq_group *cfqg) -{ - return pd_to_blkg(&cfqg->pd); -} - -#if defined(CONFIG_CFQ_GROUP_IOSCHED) && defined(CONFIG_DEBUG_BLK_CGROUP) - -/* cfqg stats flags */ -enum cfqg_stats_flags { - CFQG_stats_waiting = 0, - CFQG_stats_idling, - CFQG_stats_empty, -}; - -#define CFQG_FLAG_FNS(name) \ -static inline void cfqg_stats_mark_##name(struct cfqg_stats *stats) \ -{ \ - stats->flags |= (1 << CFQG_stats_##name); \ -} \ -static inline void cfqg_stats_clear_##name(struct cfqg_stats *stats) \ -{ \ - stats->flags &= ~(1 << CFQG_stats_##name); \ -} \ -static inline int cfqg_stats_##name(struct cfqg_stats *stats) \ -{ \ - return (stats->flags & (1 << CFQG_stats_##name)) != 0; \ -} \ - -CFQG_FLAG_FNS(waiting) -CFQG_FLAG_FNS(idling) -CFQG_FLAG_FNS(empty) -#undef CFQG_FLAG_FNS - -/* This should be called with the queue_lock held. */ -static void cfqg_stats_update_group_wait_time(struct cfqg_stats *stats) -{ - unsigned long long now; - - if (!cfqg_stats_waiting(stats)) - return; - - now = sched_clock(); - if (time_after64(now, stats->start_group_wait_time)) - blkg_stat_add(&stats->group_wait_time, - now - stats->start_group_wait_time); - cfqg_stats_clear_waiting(stats); -} - -/* This should be called with the queue_lock held. */ -static void cfqg_stats_set_start_group_wait_time(struct cfq_group *cfqg, - struct cfq_group *curr_cfqg) -{ - struct cfqg_stats *stats = &cfqg->stats; - - if (cfqg_stats_waiting(stats)) - return; - if (cfqg == curr_cfqg) - return; - stats->start_group_wait_time = sched_clock(); - cfqg_stats_mark_waiting(stats); -} - -/* This should be called with the queue_lock held. */ -static void cfqg_stats_end_empty_time(struct cfqg_stats *stats) -{ - unsigned long long now; - - if (!cfqg_stats_empty(stats)) - return; - - now = sched_clock(); - if (time_after64(now, stats->start_empty_time)) - blkg_stat_add(&stats->empty_time, - now - stats->start_empty_time); - cfqg_stats_clear_empty(stats); -} - -static void cfqg_stats_update_dequeue(struct cfq_group *cfqg) -{ - blkg_stat_add(&cfqg->stats.dequeue, 1); -} - -static void cfqg_stats_set_start_empty_time(struct cfq_group *cfqg) -{ - struct cfqg_stats *stats = &cfqg->stats; - - if (blkg_rwstat_sum(&stats->queued)) - return; - - /* - * group is already marked empty. This can happen if cfqq got new - * request in parent group and moved to this group while being added - * to service tree. Just ignore the event and move on. - */ - if (cfqg_stats_empty(stats)) - return; - - stats->start_empty_time = sched_clock(); - cfqg_stats_mark_empty(stats); -} - -static void cfqg_stats_update_idle_time(struct cfq_group *cfqg) -{ - struct cfqg_stats *stats = &cfqg->stats; - - if (cfqg_stats_idling(stats)) { - unsigned long long now = sched_clock(); - - if (time_after64(now, stats->start_idle_time)) - blkg_stat_add(&stats->idle_time, - now - stats->start_idle_time); - cfqg_stats_clear_idling(stats); - } -} - -static void cfqg_stats_set_start_idle_time(struct cfq_group *cfqg) -{ - struct cfqg_stats *stats = &cfqg->stats; - - BUG_ON(cfqg_stats_idling(stats)); - - stats->start_idle_time = sched_clock(); - cfqg_stats_mark_idling(stats); -} - -static void cfqg_stats_update_avg_queue_size(struct cfq_group *cfqg) -{ - struct cfqg_stats *stats = &cfqg->stats; - - blkg_stat_add(&stats->avg_queue_size_sum, - blkg_rwstat_sum(&stats->queued)); - blkg_stat_add(&stats->avg_queue_size_samples, 1); - cfqg_stats_update_group_wait_time(stats); -} - -#else /* CONFIG_CFQ_GROUP_IOSCHED && CONFIG_DEBUG_BLK_CGROUP */ - -static inline void cfqg_stats_set_start_group_wait_time(struct cfq_group *cfqg, struct cfq_group *curr_cfqg) { } -static inline void cfqg_stats_end_empty_time(struct cfqg_stats *stats) { } -static inline void cfqg_stats_update_dequeue(struct cfq_group *cfqg) { } -static inline void cfqg_stats_set_start_empty_time(struct cfq_group *cfqg) { } -static inline void cfqg_stats_update_idle_time(struct cfq_group *cfqg) { } -static inline void cfqg_stats_set_start_idle_time(struct cfq_group *cfqg) { } -static inline void cfqg_stats_update_avg_queue_size(struct cfq_group *cfqg) { } - -#endif /* CONFIG_CFQ_GROUP_IOSCHED && CONFIG_DEBUG_BLK_CGROUP */ - #ifdef CONFIG_CFQ_GROUP_IOSCHED - -static inline void cfqg_get(struct cfq_group *cfqg) -{ - return blkg_get(cfqg_to_blkg(cfqg)); -} - -static inline void cfqg_put(struct cfq_group *cfqg) -{ - return blkg_put(cfqg_to_blkg(cfqg)); -} - -#define cfq_log_cfqq(cfqd, cfqq, fmt, args...) do { \ - char __pbuf[128]; \ - \ - blkg_path(cfqg_to_blkg((cfqq)->cfqg), __pbuf, sizeof(__pbuf)); \ +#define cfq_log_cfqq(cfqd, cfqq, fmt, args...) \ blk_add_trace_msg((cfqd)->queue, "cfq%d%c %s " fmt, (cfqq)->pid, \ - cfq_cfqq_sync((cfqq)) ? 'S' : 'A', \ - __pbuf, ##args); \ -} while (0) + cfq_cfqq_sync((cfqq)) ? 'S' : 'A', \ + blkg_path(&(cfqq)->cfqg->blkg), ##args) -#define cfq_log_cfqg(cfqd, cfqg, fmt, args...) do { \ - char __pbuf[128]; \ - \ - blkg_path(cfqg_to_blkg(cfqg), __pbuf, sizeof(__pbuf)); \ - blk_add_trace_msg((cfqd)->queue, "%s " fmt, __pbuf, ##args); \ -} while (0) - -static inline void cfqg_stats_update_io_add(struct cfq_group *cfqg, - struct cfq_group *curr_cfqg, int rw) -{ - blkg_rwstat_add(&cfqg->stats.queued, rw, 1); - cfqg_stats_end_empty_time(&cfqg->stats); - cfqg_stats_set_start_group_wait_time(cfqg, curr_cfqg); -} - -static inline void cfqg_stats_update_timeslice_used(struct cfq_group *cfqg, - unsigned long time, unsigned long unaccounted_time) -{ - blkg_stat_add(&cfqg->stats.time, time); -#ifdef CONFIG_DEBUG_BLK_CGROUP - blkg_stat_add(&cfqg->stats.unaccounted_time, unaccounted_time); -#endif -} - -static inline void cfqg_stats_update_io_remove(struct cfq_group *cfqg, int rw) -{ - blkg_rwstat_add(&cfqg->stats.queued, rw, -1); -} - -static inline void cfqg_stats_update_io_merged(struct cfq_group *cfqg, int rw) -{ - blkg_rwstat_add(&cfqg->stats.merged, rw, 1); -} - -static inline void cfqg_stats_update_dispatch(struct cfq_group *cfqg, - uint64_t bytes, int rw) -{ - blkg_stat_add(&cfqg->stats.sectors, bytes >> 9); - blkg_rwstat_add(&cfqg->stats.serviced, rw, 1); - blkg_rwstat_add(&cfqg->stats.service_bytes, rw, bytes); -} - -static inline void cfqg_stats_update_completion(struct cfq_group *cfqg, - uint64_t start_time, uint64_t io_start_time, int rw) -{ - struct cfqg_stats *stats = &cfqg->stats; - unsigned long long now = sched_clock(); - - if (time_after64(now, io_start_time)) - blkg_rwstat_add(&stats->service_time, rw, now - io_start_time); - if (time_after64(io_start_time, start_time)) - blkg_rwstat_add(&stats->wait_time, rw, - io_start_time - start_time); -} - -static void cfq_pd_reset_stats(struct blkcg_gq *blkg) -{ - struct cfq_group *cfqg = blkg_to_cfqg(blkg); - struct cfqg_stats *stats = &cfqg->stats; - - /* queued stats shouldn't be cleared */ - blkg_rwstat_reset(&stats->service_bytes); - blkg_rwstat_reset(&stats->serviced); - blkg_rwstat_reset(&stats->merged); - blkg_rwstat_reset(&stats->service_time); - blkg_rwstat_reset(&stats->wait_time); - blkg_stat_reset(&stats->time); -#ifdef CONFIG_DEBUG_BLK_CGROUP - blkg_stat_reset(&stats->unaccounted_time); - blkg_stat_reset(&stats->avg_queue_size_sum); - blkg_stat_reset(&stats->avg_queue_size_samples); - blkg_stat_reset(&stats->dequeue); - blkg_stat_reset(&stats->group_wait_time); - blkg_stat_reset(&stats->idle_time); - blkg_stat_reset(&stats->empty_time); -#endif -} - -#else /* CONFIG_CFQ_GROUP_IOSCHED */ - -static inline void cfqg_get(struct cfq_group *cfqg) { } -static inline void cfqg_put(struct cfq_group *cfqg) { } +#define cfq_log_cfqg(cfqd, cfqg, fmt, args...) \ + blk_add_trace_msg((cfqd)->queue, "%s " fmt, \ + blkg_path(&(cfqg)->blkg), ##args) \ +#else #define cfq_log_cfqq(cfqd, cfqq, fmt, args...) \ blk_add_trace_msg((cfqd)->queue, "cfq%d " fmt, (cfqq)->pid, ##args) #define cfq_log_cfqg(cfqd, cfqg, fmt, args...) do {} while (0) - -static inline void cfqg_stats_update_io_add(struct cfq_group *cfqg, - struct cfq_group *curr_cfqg, int rw) { } -static inline void cfqg_stats_update_timeslice_used(struct cfq_group *cfqg, - unsigned long time, unsigned long unaccounted_time) { } -static inline void cfqg_stats_update_io_remove(struct cfq_group *cfqg, int rw) { } -static inline void cfqg_stats_update_io_merged(struct cfq_group *cfqg, int rw) { } -static inline void cfqg_stats_update_dispatch(struct cfq_group *cfqg, - uint64_t bytes, int rw) { } -static inline void cfqg_stats_update_completion(struct cfq_group *cfqg, - uint64_t start_time, uint64_t io_start_time, int rw) { } - -#endif /* CONFIG_CFQ_GROUP_IOSCHED */ - +#endif #define cfq_log(cfqd, fmt, args...) \ blk_add_trace_msg((cfqd)->queue, "cfq " fmt, ##args) @@ -771,9 +466,8 @@ static inline int cfqg_busy_async_queues(struct cfq_data *cfqd, } static void cfq_dispatch_insert(struct request_queue *, struct request *); -static struct cfq_queue *cfq_get_queue(struct cfq_data *cfqd, bool is_sync, - struct cfq_io_cq *cic, struct bio *bio, - gfp_t gfp_mask); +static struct cfq_queue *cfq_get_queue(struct cfq_data *, bool, + struct io_context *, gfp_t); static inline struct cfq_io_cq *icq_to_cic(struct io_cq *icq) { @@ -851,7 +545,7 @@ static inline u64 cfq_scale_slice(unsigned long delta, struct cfq_group *cfqg) { u64 d = delta << CFQ_SERVICE_SHIFT; - d = d * CFQ_WEIGHT_DEFAULT; + d = d * BLKIO_WEIGHT_DEFAULT; do_div(d, cfqg->weight); return d; } @@ -1178,9 +872,9 @@ static void cfq_update_group_weight(struct cfq_group *cfqg) { BUG_ON(!RB_EMPTY_NODE(&cfqg->rb_node)); - if (cfqg->new_weight) { + if (cfqg->needs_update) { cfqg->weight = cfqg->new_weight; - cfqg->new_weight = 0; + cfqg->needs_update = false; } } @@ -1242,7 +936,7 @@ cfq_group_notify_queue_del(struct cfq_data *cfqd, struct cfq_group *cfqg) cfq_log_cfqg(cfqd, cfqg, "del_from_rr group"); cfq_group_service_tree_del(st, cfqg); cfqg->saved_workload_slice = 0; - cfqg_stats_update_dequeue(cfqg); + cfq_blkiocg_update_dequeue_stats(&cfqg->blkg, 1); } static inline unsigned int cfq_cfqq_slice_usage(struct cfq_queue *cfqq, @@ -1314,59 +1008,178 @@ static void cfq_group_served(struct cfq_data *cfqd, struct cfq_group *cfqg, "sl_used=%u disp=%u charge=%u iops=%u sect=%lu", used_sl, cfqq->slice_dispatch, charge, iops_mode(cfqd), cfqq->nr_sectors); - cfqg_stats_update_timeslice_used(cfqg, used_sl, unaccounted_sl); - cfqg_stats_set_start_empty_time(cfqg); + cfq_blkiocg_update_timeslice_used(&cfqg->blkg, used_sl, + unaccounted_sl); + cfq_blkiocg_set_start_empty_time(&cfqg->blkg); } -/** - * cfq_init_cfqg_base - initialize base part of a cfq_group - * @cfqg: cfq_group to initialize - * - * Initialize the base part which is used whether %CONFIG_CFQ_GROUP_IOSCHED - * is enabled or not. +#ifdef CONFIG_CFQ_GROUP_IOSCHED +static inline struct cfq_group *cfqg_of_blkg(struct blkio_group *blkg) +{ + if (blkg) + return container_of(blkg, struct cfq_group, blkg); + return NULL; +} + +static void cfq_update_blkio_group_weight(void *key, struct blkio_group *blkg, + unsigned int weight) +{ + struct cfq_group *cfqg = cfqg_of_blkg(blkg); + cfqg->new_weight = weight; + cfqg->needs_update = true; +} + +static void cfq_init_add_cfqg_lists(struct cfq_data *cfqd, + struct cfq_group *cfqg, struct blkio_cgroup *blkcg) +{ + struct backing_dev_info *bdi = &cfqd->queue->backing_dev_info; + unsigned int major, minor; + + /* + * Add group onto cgroup list. It might happen that bdi->dev is + * not initialized yet. Initialize this new group without major + * and minor info and this info will be filled in once a new thread + * comes for IO. + */ + if (bdi->dev) { + sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor); + cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg, + (void *)cfqd, MKDEV(major, minor)); + } else + cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg, + (void *)cfqd, 0); + + cfqd->nr_blkcg_linked_grps++; + cfqg->weight = blkcg_get_weight(blkcg, cfqg->blkg.dev); + + /* Add group on cfqd list */ + hlist_add_head(&cfqg->cfqd_node, &cfqd->cfqg_list); +} + +/* + * Should be called from sleepable context. No request queue lock as per + * cpu stats are allocated dynamically and alloc_percpu needs to be called + * from sleepable context. */ -static void cfq_init_cfqg_base(struct cfq_group *cfqg) +static struct cfq_group * cfq_alloc_cfqg(struct cfq_data *cfqd) { + struct cfq_group *cfqg = NULL; + int i, j, ret; struct cfq_rb_root *st; - int i, j; + + cfqg = kzalloc_node(sizeof(*cfqg), GFP_ATOMIC, cfqd->queue->node); + if (!cfqg) + return NULL; for_each_cfqg_st(cfqg, i, j, st) *st = CFQ_RB_ROOT; RB_CLEAR_NODE(&cfqg->rb_node); cfqg->ttime.last_end_request = jiffies; + + /* + * Take the initial reference that will be released on destroy + * This can be thought of a joint reference by cgroup and + * elevator which will be dropped by either elevator exit + * or cgroup deletion path depending on who is exiting first. + */ + cfqg->ref = 1; + + ret = blkio_alloc_blkg_stats(&cfqg->blkg); + if (ret) { + kfree(cfqg); + return NULL; + } + + return cfqg; } -#ifdef CONFIG_CFQ_GROUP_IOSCHED -static void cfq_pd_init(struct blkcg_gq *blkg) +static struct cfq_group * +cfq_find_cfqg(struct cfq_data *cfqd, struct blkio_cgroup *blkcg) { - struct cfq_group *cfqg = blkg_to_cfqg(blkg); + struct cfq_group *cfqg = NULL; + void *key = cfqd; + struct backing_dev_info *bdi = &cfqd->queue->backing_dev_info; + unsigned int major, minor; + + /* + * This is the common case when there are no blkio cgroups. + * Avoid lookup in this case + */ + if (blkcg == &blkio_root_cgroup) + cfqg = &cfqd->root_group; + else + cfqg = cfqg_of_blkg(blkiocg_lookup_group(blkcg, key)); + + if (cfqg && !cfqg->blkg.dev && bdi->dev && dev_name(bdi->dev)) { + sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor); + cfqg->blkg.dev = MKDEV(major, minor); + } - cfq_init_cfqg_base(cfqg); - cfqg->weight = blkg->blkcg->cfq_weight; + return cfqg; } /* * Search for the cfq group current task belongs to. request_queue lock must * be held. */ -static struct cfq_group *cfq_lookup_create_cfqg(struct cfq_data *cfqd, - struct blkcg *blkcg) +static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd) { + struct blkio_cgroup *blkcg; + struct cfq_group *cfqg = NULL, *__cfqg = NULL; struct request_queue *q = cfqd->queue; - struct cfq_group *cfqg = NULL; - /* avoid lookup for the common case where there's no blkcg */ - if (blkcg == &blkcg_root) { - cfqg = cfqd->root_group; - } else { - struct blkcg_gq *blkg; + rcu_read_lock(); + blkcg = task_blkio_cgroup(current); + cfqg = cfq_find_cfqg(cfqd, blkcg); + if (cfqg) { + rcu_read_unlock(); + return cfqg; + } + + /* + * Need to allocate a group. Allocation of group also needs allocation + * of per cpu stats which in-turn takes a mutex() and can block. Hence + * we need to drop rcu lock and queue_lock before we call alloc. + * + * Not taking any queue reference here and assuming that queue is + * around by the time we return. CFQ queue allocation code does + * the same. It might be racy though. + */ + + rcu_read_unlock(); + spin_unlock_irq(q->queue_lock); - blkg = blkg_lookup_create(blkcg, q); - if (!IS_ERR(blkg)) - cfqg = blkg_to_cfqg(blkg); + cfqg = cfq_alloc_cfqg(cfqd); + + spin_lock_irq(q->queue_lock); + + rcu_read_lock(); + blkcg = task_blkio_cgroup(current); + + /* + * If some other thread already allocated the group while we were + * not holding queue lock, free up the group + */ + __cfqg = cfq_find_cfqg(cfqd, blkcg); + + if (__cfqg) { + kfree(cfqg); + rcu_read_unlock(); + return __cfqg; } + if (!cfqg) + cfqg = &cfqd->root_group; + + cfq_init_add_cfqg_lists(cfqd, cfqg, blkcg); + rcu_read_unlock(); + return cfqg; +} + +static inline struct cfq_group *cfq_ref_get_cfqg(struct cfq_group *cfqg) +{ + cfqg->ref++; return cfqg; } @@ -1374,224 +1187,94 @@ static void cfq_link_cfqq_cfqg(struct cfq_queue *cfqq, struct cfq_group *cfqg) { /* Currently, all async queues are mapped to root group */ if (!cfq_cfqq_sync(cfqq)) - cfqg = cfqq->cfqd->root_group; + cfqg = &cfqq->cfqd->root_group; cfqq->cfqg = cfqg; /* cfqq reference on cfqg */ - cfqg_get(cfqg); + cfqq->cfqg->ref++; } -static u64 cfqg_prfill_weight_device(struct seq_file *sf, - struct blkg_policy_data *pd, int off) +static void cfq_put_cfqg(struct cfq_group *cfqg) { - struct cfq_group *cfqg = pd_to_cfqg(pd); - - if (!cfqg->dev_weight) - return 0; - return __blkg_prfill_u64(sf, pd, cfqg->dev_weight); -} + struct cfq_rb_root *st; + int i, j; -static int cfqg_print_weight_device(struct cgroup *cgrp, struct cftype *cft, - struct seq_file *sf) -{ - blkcg_print_blkgs(sf, cgroup_to_blkcg(cgrp), - cfqg_prfill_weight_device, &blkcg_policy_cfq, 0, - false); - return 0; + BUG_ON(cfqg->ref <= 0); + cfqg->ref--; + if (cfqg->ref) + return; + for_each_cfqg_st(cfqg, i, j, st) + BUG_ON(!RB_EMPTY_ROOT(&st->rb)); + free_percpu(cfqg->blkg.stats_cpu); + kfree(cfqg); } -static int cfq_print_weight(struct cgroup *cgrp, struct cftype *cft, - struct seq_file *sf) +static void cfq_destroy_cfqg(struct cfq_data *cfqd, struct cfq_group *cfqg) { - seq_printf(sf, "%u\n", cgroup_to_blkcg(cgrp)->cfq_weight); - return 0; -} + /* Something wrong if we are trying to remove same group twice */ + BUG_ON(hlist_unhashed(&cfqg->cfqd_node)); -static int cfqg_set_weight_device(struct cgroup *cgrp, struct cftype *cft, - const char *buf) -{ - struct blkcg *blkcg = cgroup_to_blkcg(cgrp); - struct blkg_conf_ctx ctx; - struct cfq_group *cfqg; - int ret; + hlist_del_init(&cfqg->cfqd_node); - ret = blkg_conf_prep(blkcg, &blkcg_policy_cfq, buf, &ctx); - if (ret) - return ret; + BUG_ON(cfqd->nr_blkcg_linked_grps <= 0); + cfqd->nr_blkcg_linked_grps--; - ret = -EINVAL; - cfqg = blkg_to_cfqg(ctx.blkg); - if (!ctx.v || (ctx.v >= CFQ_WEIGHT_MIN && ctx.v <= CFQ_WEIGHT_MAX)) { - cfqg->dev_weight = ctx.v; - cfqg->new_weight = cfqg->dev_weight ?: blkcg->cfq_weight; - ret = 0; - } - - blkg_conf_finish(&ctx); - return ret; + /* + * Put the reference taken at the time of creation so that when all + * queues are gone, group can be destroyed. + */ + cfq_put_cfqg(cfqg); } -static int cfq_set_weight(struct cgroup *cgrp, struct cftype *cft, u64 val) +static void cfq_release_cfq_groups(struct cfq_data *cfqd) { - struct blkcg *blkcg = cgroup_to_blkcg(cgrp); - struct blkcg_gq *blkg; - struct hlist_node *n; - - if (val < CFQ_WEIGHT_MIN || val > CFQ_WEIGHT_MAX) - return -EINVAL; - - spin_lock_irq(&blkcg->lock); - blkcg->cfq_weight = (unsigned int)val; - - hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) { - struct cfq_group *cfqg = blkg_to_cfqg(blkg); + struct hlist_node *pos, *n; + struct cfq_group *cfqg; - if (cfqg && !cfqg->dev_weight) - cfqg->new_weight = blkcg->cfq_weight; + hlist_for_each_entry_safe(cfqg, pos, n, &cfqd->cfqg_list, cfqd_node) { + /* + * If cgroup removal path got to blk_group first and removed + * it from cgroup list, then it will take care of destroying + * cfqg also. + */ + if (!cfq_blkiocg_del_blkio_group(&cfqg->blkg)) + cfq_destroy_cfqg(cfqd, cfqg); } - - spin_unlock_irq(&blkcg->lock); - return 0; -} - -static int cfqg_print_stat(struct cgroup *cgrp, struct cftype *cft, - struct seq_file *sf) -{ - struct blkcg *blkcg = cgroup_to_blkcg(cgrp); - - blkcg_print_blkgs(sf, blkcg, blkg_prfill_stat, &blkcg_policy_cfq, - cft->private, false); - return 0; } -static int cfqg_print_rwstat(struct cgroup *cgrp, struct cftype *cft, - struct seq_file *sf) +/* + * Blk cgroup controller notification saying that blkio_group object is being + * delinked as associated cgroup object is going away. That also means that + * no new IO will come in this group. So get rid of this group as soon as + * any pending IO in the group is finished. + * + * This function is called under rcu_read_lock(). key is the rcu protected + * pointer. That means "key" is a valid cfq_data pointer as long as we are rcu + * read lock. + * + * "key" was fetched from blkio_group under blkio_cgroup->lock. That means + * it should not be NULL as even if elevator was exiting, cgroup deltion + * path got to it first. + */ +static void cfq_unlink_blkio_group(void *key, struct blkio_group *blkg) { - struct blkcg *blkcg = cgroup_to_blkcg(cgrp); + unsigned long flags; + struct cfq_data *cfqd = key; - blkcg_print_blkgs(sf, blkcg, blkg_prfill_rwstat, &blkcg_policy_cfq, - cft->private, true); - return 0; + spin_lock_irqsave(cfqd->queue->queue_lock, flags); + cfq_destroy_cfqg(cfqd, cfqg_of_blkg(blkg)); + spin_unlock_irqrestore(cfqd->queue->queue_lock, flags); } -#ifdef CONFIG_DEBUG_BLK_CGROUP -static u64 cfqg_prfill_avg_queue_size(struct seq_file *sf, - struct blkg_policy_data *pd, int off) +#else /* GROUP_IOSCHED */ +static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd) { - struct cfq_group *cfqg = pd_to_cfqg(pd); - u64 samples = blkg_stat_read(&cfqg->stats.avg_queue_size_samples); - u64 v = 0; - - if (samples) { - v = blkg_stat_read(&cfqg->stats.avg_queue_size_sum); - do_div(v, samples); - } - __blkg_prfill_u64(sf, pd, v); - return 0; + return &cfqd->root_group; } -/* print avg_queue_size */ -static int cfqg_print_avg_queue_size(struct cgroup *cgrp, struct cftype *cft, - struct seq_file *sf) +static inline struct cfq_group *cfq_ref_get_cfqg(struct cfq_group *cfqg) { - struct blkcg *blkcg = cgroup_to_blkcg(cgrp); - - blkcg_print_blkgs(sf, blkcg, cfqg_prfill_avg_queue_size, - &blkcg_policy_cfq, 0, false); - return 0; -} -#endif /* CONFIG_DEBUG_BLK_CGROUP */ - -static struct cftype cfq_blkcg_files[] = { - { - .name = "weight_device", - .read_seq_string = cfqg_print_weight_device, - .write_string = cfqg_set_weight_device, - .max_write_len = 256, - }, - { - .name = "weight", - .read_seq_string = cfq_print_weight, - .write_u64 = cfq_set_weight, - }, - { - .name = "time", - .private = offsetof(struct cfq_group, stats.time), - .read_seq_string = cfqg_print_stat, - }, - { - .name = "sectors", - .private = offsetof(struct cfq_group, stats.sectors), - .read_seq_string = cfqg_print_stat, - }, - { - .name = "io_service_bytes", - .private = offsetof(struct cfq_group, stats.service_bytes), - .read_seq_string = cfqg_print_rwstat, - }, - { - .name = "io_serviced", - .private = offsetof(struct cfq_group, stats.serviced), - .read_seq_string = cfqg_print_rwstat, - }, - { - .name = "io_service_time", - .private = offsetof(struct cfq_group, stats.service_time), - .read_seq_string = cfqg_print_rwstat, - }, - { - .name = "io_wait_time", - .private = offsetof(struct cfq_group, stats.wait_time), - .read_seq_string = cfqg_print_rwstat, - }, - { - .name = "io_merged", - .private = offsetof(struct cfq_group, stats.merged), - .read_seq_string = cfqg_print_rwstat, - }, - { - .name = "io_queued", - .private = offsetof(struct cfq_group, stats.queued), - .read_seq_string = cfqg_print_rwstat, - }, -#ifdef CONFIG_DEBUG_BLK_CGROUP - { - .name = "avg_queue_size", - .read_seq_string = cfqg_print_avg_queue_size, - }, - { - .name = "group_wait_time", - .private = offsetof(struct cfq_group, stats.group_wait_time), - .read_seq_string = cfqg_print_stat, - }, - { - .name = "idle_time", - .private = offsetof(struct cfq_group, stats.idle_time), - .read_seq_string = cfqg_print_stat, - }, - { - .name = "empty_time", - .private = offsetof(struct cfq_group, stats.empty_time), - .read_seq_string = cfqg_print_stat, - }, - { - .name = "dequeue", - .private = offsetof(struct cfq_group, stats.dequeue), - .read_seq_string = cfqg_print_stat, - }, - { - .name = "unaccounted_time", - .private = offsetof(struct cfq_group, stats.unaccounted_time), - .read_seq_string = cfqg_print_stat, - }, -#endif /* CONFIG_DEBUG_BLK_CGROUP */ - { } /* terminate */ -}; -#else /* GROUP_IOSCHED */ -static struct cfq_group *cfq_lookup_create_cfqg(struct cfq_data *cfqd, - struct blkcg *blkcg) -{ - return cfqd->root_group; + return cfqg; } static inline void @@ -1599,6 +1282,9 @@ cfq_link_cfqq_cfqg(struct cfq_queue *cfqq, struct cfq_group *cfqg) { cfqq->cfqg = cfqg; } +static void cfq_release_cfq_groups(struct cfq_data *cfqd) {} +static inline void cfq_put_cfqg(struct cfq_group *cfqg) {} + #endif /* GROUP_IOSCHED */ /* @@ -1865,10 +1551,12 @@ static void cfq_reposition_rq_rb(struct cfq_queue *cfqq, struct request *rq) { elv_rb_del(&cfqq->sort_list, rq); cfqq->queued[rq_is_sync(rq)]--; - cfqg_stats_update_io_remove(RQ_CFQG(rq), rq->cmd_flags); + cfq_blkiocg_update_io_remove_stats(&(RQ_CFQG(rq))->blkg, + rq_data_dir(rq), rq_is_sync(rq)); cfq_add_rq_rb(rq); - cfqg_stats_update_io_add(RQ_CFQG(rq), cfqq->cfqd->serving_group, - rq->cmd_flags); + cfq_blkiocg_update_io_add_stats(&(RQ_CFQG(rq))->blkg, + &cfqq->cfqd->serving_group->blkg, rq_data_dir(rq), + rq_is_sync(rq)); } static struct request * @@ -1924,7 +1612,8 @@ static void cfq_remove_request(struct request *rq) cfq_del_rq_rb(rq); cfqq->cfqd->rq_queued--; - cfqg_stats_update_io_remove(RQ_CFQG(rq), rq->cmd_flags); + cfq_blkiocg_update_io_remove_stats(&(RQ_CFQG(rq))->blkg, + rq_data_dir(rq), rq_is_sync(rq)); if (rq->cmd_flags & REQ_PRIO) { WARN_ON(!cfqq->prio_pending); cfqq->prio_pending--; @@ -1959,7 +1648,8 @@ static void cfq_merged_request(struct request_queue *q, struct request *req, static void cfq_bio_merged(struct request_queue *q, struct request *req, struct bio *bio) { - cfqg_stats_update_io_merged(RQ_CFQG(req), bio->bi_rw); + cfq_blkiocg_update_io_merged_stats(&(RQ_CFQG(req))->blkg, + bio_data_dir(bio), cfq_bio_sync(bio)); } static void @@ -1981,7 +1671,8 @@ cfq_merged_requests(struct request_queue *q, struct request *rq, if (cfqq->next_rq == next) cfqq->next_rq = rq; cfq_remove_request(next); - cfqg_stats_update_io_merged(RQ_CFQG(rq), next->cmd_flags); + cfq_blkiocg_update_io_merged_stats(&(RQ_CFQG(rq))->blkg, + rq_data_dir(next), rq_is_sync(next)); cfqq = RQ_CFQQ(next); /* @@ -2022,7 +1713,7 @@ static int cfq_allow_merge(struct request_queue *q, struct request *rq, static inline void cfq_del_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq) { del_timer(&cfqd->idle_slice_timer); - cfqg_stats_update_idle_time(cfqq->cfqg); + cfq_blkiocg_update_idle_time_stats(&cfqq->cfqg->blkg); } static void __cfq_set_active_queue(struct cfq_data *cfqd, @@ -2031,7 +1722,7 @@ static void __cfq_set_active_queue(struct cfq_data *cfqd, if (cfqq) { cfq_log_cfqq(cfqd, cfqq, "set_active wl_prio:%d wl_type:%d", cfqd->serving_prio, cfqd->serving_type); - cfqg_stats_update_avg_queue_size(cfqq->cfqg); + cfq_blkiocg_update_avg_queue_size_stats(&cfqq->cfqg->blkg); cfqq->slice_start = 0; cfqq->dispatch_start = jiffies; cfqq->allocated_slice = 0; @@ -2352,7 +2043,7 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd) * task has exited, don't wait */ cic = cfqd->active_cic; - if (!cic || !atomic_read(&cic->icq.ioc->active_ref)) + if (!cic || !atomic_read(&cic->icq.ioc->nr_tasks)) return; /* @@ -2379,7 +2070,7 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd) sl = cfqd->cfq_slice_idle; mod_timer(&cfqd->idle_slice_timer, jiffies + sl); - cfqg_stats_set_start_idle_time(cfqq->cfqg); + cfq_blkiocg_update_set_idle_time_stats(&cfqq->cfqg->blkg); cfq_log_cfqq(cfqd, cfqq, "arm_idle: %lu group_idle: %d", sl, group_idle ? 1 : 0); } @@ -2402,7 +2093,8 @@ static void cfq_dispatch_insert(struct request_queue *q, struct request *rq) cfqd->rq_in_flight[cfq_cfqq_sync(cfqq)]++; cfqq->nr_sectors += blk_rq_sectors(rq); - cfqg_stats_update_dispatch(cfqq->cfqg, blk_rq_bytes(rq), rq->cmd_flags); + cfq_blkiocg_update_dispatch_stats(&cfqq->cfqg->blkg, blk_rq_bytes(rq), + rq_data_dir(rq), rq_is_sync(rq)); } /* @@ -2985,7 +2677,7 @@ static void cfq_put_queue(struct cfq_queue *cfqq) BUG_ON(cfq_cfqq_on_rr(cfqq)); kmem_cache_free(cfq_pool, cfqq); - cfqg_put(cfqg); + cfq_put_cfqg(cfqg); } static void cfq_put_cooperator(struct cfq_queue *cfqq) @@ -3044,7 +2736,7 @@ static void cfq_exit_icq(struct io_cq *icq) } } -static void cfq_init_prio_data(struct cfq_queue *cfqq, struct cfq_io_cq *cic) +static void cfq_init_prio_data(struct cfq_queue *cfqq, struct io_context *ioc) { struct task_struct *tsk = current; int ioprio_class; @@ -3052,7 +2744,7 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq, struct cfq_io_cq *cic) if (!cfq_cfqq_prio_changed(cfqq)) return; - ioprio_class = IOPRIO_PRIO_CLASS(cic->ioprio); + ioprio_class = IOPRIO_PRIO_CLASS(ioc->ioprio); switch (ioprio_class) { default: printk(KERN_ERR "cfq: bad prio %x\n", ioprio_class); @@ -3064,11 +2756,11 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq, struct cfq_io_cq *cic) cfqq->ioprio_class = task_nice_ioclass(tsk); break; case IOPRIO_CLASS_RT: - cfqq->ioprio = IOPRIO_PRIO_DATA(cic->ioprio); + cfqq->ioprio = task_ioprio(ioc); cfqq->ioprio_class = IOPRIO_CLASS_RT; break; case IOPRIO_CLASS_BE: - cfqq->ioprio = IOPRIO_PRIO_DATA(cic->ioprio); + cfqq->ioprio = task_ioprio(ioc); cfqq->ioprio_class = IOPRIO_CLASS_BE; break; case IOPRIO_CLASS_IDLE: @@ -3086,24 +2778,19 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq, struct cfq_io_cq *cic) cfq_clear_cfqq_prio_changed(cfqq); } -static void check_ioprio_changed(struct cfq_io_cq *cic, struct bio *bio) +static void changed_ioprio(struct cfq_io_cq *cic) { - int ioprio = cic->icq.ioc->ioprio; struct cfq_data *cfqd = cic_to_cfqd(cic); struct cfq_queue *cfqq; - /* - * Check whether ioprio has changed. The condition may trigger - * spuriously on a newly created cic but there's no harm. - */ - if (unlikely(!cfqd) || likely(cic->ioprio == ioprio)) + if (unlikely(!cfqd)) return; cfqq = cic->cfqq[BLK_RW_ASYNC]; if (cfqq) { struct cfq_queue *new_cfqq; - new_cfqq = cfq_get_queue(cfqd, BLK_RW_ASYNC, cic, bio, - GFP_ATOMIC); + new_cfqq = cfq_get_queue(cfqd, BLK_RW_ASYNC, cic->icq.ioc, + GFP_ATOMIC); if (new_cfqq) { cic->cfqq[BLK_RW_ASYNC] = new_cfqq; cfq_put_queue(cfqq); @@ -3113,8 +2800,6 @@ static void check_ioprio_changed(struct cfq_io_cq *cic, struct bio *bio) cfqq = cic->cfqq[BLK_RW_SYNC]; if (cfqq) cfq_mark_cfqq_prio_changed(cfqq); - - cic->ioprio = ioprio; } static void cfq_init_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq, @@ -3138,24 +2823,17 @@ static void cfq_init_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq, } #ifdef CONFIG_CFQ_GROUP_IOSCHED -static void check_blkcg_changed(struct cfq_io_cq *cic, struct bio *bio) +static void changed_cgroup(struct cfq_io_cq *cic) { + struct cfq_queue *sync_cfqq = cic_to_cfqq(cic, 1); struct cfq_data *cfqd = cic_to_cfqd(cic); - struct cfq_queue *sync_cfqq; - uint64_t id; + struct request_queue *q; - rcu_read_lock(); - id = bio_blkcg(bio)->id; - rcu_read_unlock(); - - /* - * Check whether blkcg has changed. The condition may trigger - * spuriously on a newly created cic but there's no harm. - */ - if (unlikely(!cfqd) || likely(cic->blkcg_id == id)) + if (unlikely(!cfqd)) return; - sync_cfqq = cic_to_cfqq(cic, 1); + q = cfqd->queue; + if (sync_cfqq) { /* * Drop reference to sync queue. A new sync queue will be @@ -3165,26 +2843,21 @@ static void check_blkcg_changed(struct cfq_io_cq *cic, struct bio *bio) cic_set_cfqq(cic, NULL, 1); cfq_put_queue(sync_cfqq); } - - cic->blkcg_id = id; } -#else -static inline void check_blkcg_changed(struct cfq_io_cq *cic, struct bio *bio) { } #endif /* CONFIG_CFQ_GROUP_IOSCHED */ static struct cfq_queue * -cfq_find_alloc_queue(struct cfq_data *cfqd, bool is_sync, struct cfq_io_cq *cic, - struct bio *bio, gfp_t gfp_mask) +cfq_find_alloc_queue(struct cfq_data *cfqd, bool is_sync, + struct io_context *ioc, gfp_t gfp_mask) { - struct blkcg *blkcg; struct cfq_queue *cfqq, *new_cfqq = NULL; + struct cfq_io_cq *cic; struct cfq_group *cfqg; retry: - rcu_read_lock(); - - blkcg = bio_blkcg(bio); - cfqg = cfq_lookup_create_cfqg(cfqd, blkcg); + cfqg = cfq_get_cfqg(cfqd); + cic = cfq_cic_lookup(cfqd, ioc); + /* cic always exists here */ cfqq = cic_to_cfqq(cic, is_sync); /* @@ -3197,7 +2870,6 @@ cfq_find_alloc_queue(struct cfq_data *cfqd, bool is_sync, struct cfq_io_cq *cic, cfqq = new_cfqq; new_cfqq = NULL; } else if (gfp_mask & __GFP_WAIT) { - rcu_read_unlock(); spin_unlock_irq(cfqd->queue->queue_lock); new_cfqq = kmem_cache_alloc_node(cfq_pool, gfp_mask | __GFP_ZERO, @@ -3213,7 +2885,7 @@ cfq_find_alloc_queue(struct cfq_data *cfqd, bool is_sync, struct cfq_io_cq *cic, if (cfqq) { cfq_init_cfqq(cfqd, cfqq, current->pid, is_sync); - cfq_init_prio_data(cfqq, cic); + cfq_init_prio_data(cfqq, ioc); cfq_link_cfqq_cfqg(cfqq, cfqg); cfq_log_cfqq(cfqd, cfqq, "alloced"); } else @@ -3223,7 +2895,6 @@ cfq_find_alloc_queue(struct cfq_data *cfqd, bool is_sync, struct cfq_io_cq *cic, if (new_cfqq) kmem_cache_free(cfq_pool, new_cfqq); - rcu_read_unlock(); return cfqq; } @@ -3233,9 +2904,6 @@ cfq_async_queue_prio(struct cfq_data *cfqd, int ioprio_class, int ioprio) switch (ioprio_class) { case IOPRIO_CLASS_RT: return &cfqd->async_cfqq[0][ioprio]; - case IOPRIO_CLASS_NONE: - ioprio = IOPRIO_NORM; - /* fall through */ case IOPRIO_CLASS_BE: return &cfqd->async_cfqq[1][ioprio]; case IOPRIO_CLASS_IDLE: @@ -3246,11 +2914,11 @@ cfq_async_queue_prio(struct cfq_data *cfqd, int ioprio_class, int ioprio) } static struct cfq_queue * -cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct cfq_io_cq *cic, - struct bio *bio, gfp_t gfp_mask) +cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct io_context *ioc, + gfp_t gfp_mask) { - const int ioprio_class = IOPRIO_PRIO_CLASS(cic->ioprio); - const int ioprio = IOPRIO_PRIO_DATA(cic->ioprio); + const int ioprio = task_ioprio(ioc); + const int ioprio_class = task_ioprio_class(ioc); struct cfq_queue **async_cfqq = NULL; struct cfq_queue *cfqq = NULL; @@ -3260,7 +2928,7 @@ cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct cfq_io_cq *cic, } if (!cfqq) - cfqq = cfq_find_alloc_queue(cfqd, is_sync, cic, bio, gfp_mask); + cfqq = cfq_find_alloc_queue(cfqd, is_sync, ioc, gfp_mask); /* * pin the queue now that it's allocated, scheduler exit will prune it @@ -3342,7 +3010,7 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq, if (cfqq->next_rq && (cfqq->next_rq->cmd_flags & REQ_NOIDLE)) enable_idle = 0; - else if (!atomic_read(&cic->icq.ioc->active_ref) || + else if (!atomic_read(&cic->icq.ioc->nr_tasks) || !cfqd->cfq_slice_idle || (!cfq_cfqq_deep(cfqq) && CFQQ_SEEKY(cfqq))) enable_idle = 0; @@ -3506,7 +3174,8 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, cfq_clear_cfqq_wait_request(cfqq); __blk_run_queue(cfqd->queue); } else { - cfqg_stats_update_idle_time(cfqq->cfqg); + cfq_blkiocg_update_idle_time_stats( + &cfqq->cfqg->blkg); cfq_mark_cfqq_must_dispatch(cfqq); } } @@ -3528,13 +3197,14 @@ static void cfq_insert_request(struct request_queue *q, struct request *rq) struct cfq_queue *cfqq = RQ_CFQQ(rq); cfq_log_cfqq(cfqd, cfqq, "insert_request"); - cfq_init_prio_data(cfqq, RQ_CIC(rq)); + cfq_init_prio_data(cfqq, RQ_CIC(rq)->icq.ioc); rq_set_fifo_time(rq, jiffies + cfqd->cfq_fifo_expire[rq_is_sync(rq)]); list_add_tail(&rq->queuelist, &cfqq->fifo); cfq_add_rq_rb(rq); - cfqg_stats_update_io_add(RQ_CFQG(rq), cfqd->serving_group, - rq->cmd_flags); + cfq_blkiocg_update_io_add_stats(&(RQ_CFQG(rq))->blkg, + &cfqd->serving_group->blkg, rq_data_dir(rq), + rq_is_sync(rq)); cfq_rq_enqueued(cfqd, cfqq, rq); } @@ -3630,8 +3300,9 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq) cfqd->rq_in_driver--; cfqq->dispatched--; (RQ_CFQG(rq))->dispatched--; - cfqg_stats_update_completion(cfqq->cfqg, rq_start_time_ns(rq), - rq_io_start_time_ns(rq), rq->cmd_flags); + cfq_blkiocg_update_completion_stats(&cfqq->cfqg->blkg, + rq_start_time_ns(rq), rq_io_start_time_ns(rq), + rq_data_dir(rq), rq_is_sync(rq)); cfqd->rq_in_flight[cfq_cfqq_sync(cfqq)]--; @@ -3728,7 +3399,7 @@ static int cfq_may_queue(struct request_queue *q, int rw) cfqq = cic_to_cfqq(cic, rw_is_sync(rw)); if (cfqq) { - cfq_init_prio_data(cfqq, cic); + cfq_init_prio_data(cfqq, cic->icq.ioc); return __cfq_may_queue(cfqq); } @@ -3750,7 +3421,7 @@ static void cfq_put_request(struct request *rq) cfqq->allocated[rw]--; /* Put down rq reference on cfqg */ - cfqg_put(RQ_CFQG(rq)); + cfq_put_cfqg(RQ_CFQG(rq)); rq->elv.priv[0] = NULL; rq->elv.priv[1] = NULL; @@ -3794,25 +3465,32 @@ split_cfqq(struct cfq_io_cq *cic, struct cfq_queue *cfqq) * Allocate cfq data structures associated with this request. */ static int -cfq_set_request(struct request_queue *q, struct request *rq, struct bio *bio, - gfp_t gfp_mask) +cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask) { struct cfq_data *cfqd = q->elevator->elevator_data; struct cfq_io_cq *cic = icq_to_cic(rq->elv.icq); const int rw = rq_data_dir(rq); const bool is_sync = rq_is_sync(rq); struct cfq_queue *cfqq; + unsigned int changed; might_sleep_if(gfp_mask & __GFP_WAIT); spin_lock_irq(q->queue_lock); - check_ioprio_changed(cic, bio); - check_blkcg_changed(cic, bio); + /* handle changed notifications */ + changed = icq_get_changed(&cic->icq); + if (unlikely(changed & ICQ_IOPRIO_CHANGED)) + changed_ioprio(cic); +#ifdef CONFIG_CFQ_GROUP_IOSCHED + if (unlikely(changed & ICQ_CGROUP_CHANGED)) + changed_cgroup(cic); +#endif + new_queue: cfqq = cic_to_cfqq(cic, is_sync); if (!cfqq || cfqq == &cfqd->oom_cfqq) { - cfqq = cfq_get_queue(cfqd, is_sync, cic, bio, gfp_mask); + cfqq = cfq_get_queue(cfqd, is_sync, cic->icq.ioc, gfp_mask); cic_set_cfqq(cic, cfqq, is_sync); } else { /* @@ -3838,9 +3516,8 @@ cfq_set_request(struct request_queue *q, struct request *rq, struct bio *bio, cfqq->allocated[rw]++; cfqq->ref++; - cfqg_get(cfqq->cfqg); rq->elv.priv[0] = cfqq; - rq->elv.priv[1] = cfqq->cfqg; + rq->elv.priv[1] = cfq_ref_get_cfqg(cfqq->cfqg); spin_unlock_irq(q->queue_lock); return 0; } @@ -3937,6 +3614,7 @@ static void cfq_exit_queue(struct elevator_queue *e) { struct cfq_data *cfqd = e->elevator_data; struct request_queue *q = cfqd->queue; + bool wait = false; cfq_shutdown_timer_wq(cfqd); @@ -3946,52 +3624,89 @@ static void cfq_exit_queue(struct elevator_queue *e) __cfq_slice_expired(cfqd, cfqd->active_queue, 0); cfq_put_async_queues(cfqd); + cfq_release_cfq_groups(cfqd); + + /* + * If there are groups which we could not unlink from blkcg list, + * wait for a rcu period for them to be freed. + */ + if (cfqd->nr_blkcg_linked_grps) + wait = true; spin_unlock_irq(q->queue_lock); cfq_shutdown_timer_wq(cfqd); -#ifndef CONFIG_CFQ_GROUP_IOSCHED - kfree(cfqd->root_group); + /* + * Wait for cfqg->blkg->key accessors to exit their grace periods. + * Do this wait only if there are other unlinked groups out + * there. This can happen if cgroup deletion path claimed the + * responsibility of cleaning up a group before queue cleanup code + * get to the group. + * + * Do not call synchronize_rcu() unconditionally as there are drivers + * which create/delete request queue hundreds of times during scan/boot + * and synchronize_rcu() can take significant time and slow down boot. + */ + if (wait) + synchronize_rcu(); + +#ifdef CONFIG_CFQ_GROUP_IOSCHED + /* Free up per cpu stats for root group */ + free_percpu(cfqd->root_group.blkg.stats_cpu); #endif - blkcg_deactivate_policy(q, &blkcg_policy_cfq); kfree(cfqd); } -static int cfq_init_queue(struct request_queue *q) +static void *cfq_init_queue(struct request_queue *q) { struct cfq_data *cfqd; - struct blkcg_gq *blkg __maybe_unused; - int i, ret; + int i, j; + struct cfq_group *cfqg; + struct cfq_rb_root *st; cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL | __GFP_ZERO, q->node); if (!cfqd) - return -ENOMEM; - - cfqd->queue = q; - q->elevator->elevator_data = cfqd; + return NULL; /* Init root service tree */ cfqd->grp_service_tree = CFQ_RB_ROOT; - /* Init root group and prefer root group over other groups by default */ + /* Init root group */ + cfqg = &cfqd->root_group; + for_each_cfqg_st(cfqg, i, j, st) + *st = CFQ_RB_ROOT; + RB_CLEAR_NODE(&cfqg->rb_node); + + /* Give preference to root group over other groups */ + cfqg->weight = 2*BLKIO_WEIGHT_DEFAULT; + #ifdef CONFIG_CFQ_GROUP_IOSCHED - ret = blkcg_activate_policy(q, &blkcg_policy_cfq); - if (ret) - goto out_free; + /* + * Set root group reference to 2. One reference will be dropped when + * all groups on cfqd->cfqg_list are being deleted during queue exit. + * Other reference will remain there as we don't want to delete this + * group as it is statically allocated and gets destroyed when + * throtl_data goes away. + */ + cfqg->ref = 2; - cfqd->root_group = blkg_to_cfqg(q->root_blkg); -#else - ret = -ENOMEM; - cfqd->root_group = kzalloc_node(sizeof(*cfqd->root_group), - GFP_KERNEL, cfqd->queue->node); - if (!cfqd->root_group) - goto out_free; + if (blkio_alloc_blkg_stats(&cfqg->blkg)) { + kfree(cfqg); + kfree(cfqd); + return NULL; + } - cfq_init_cfqg_base(cfqd->root_group); -#endif - cfqd->root_group->weight = 2 * CFQ_WEIGHT_DEFAULT; + rcu_read_lock(); + + cfq_blkiocg_add_blkio_group(&blkio_root_cgroup, &cfqg->blkg, + (void *)cfqd, 0); + rcu_read_unlock(); + cfqd->nr_blkcg_linked_grps++; + /* Add group on cfqd->cfqg_list */ + hlist_add_head(&cfqg->cfqd_node, &cfqd->cfqg_list); +#endif /* * Not strictly needed (since RB_ROOT just clears the node and we * zeroed cfqd on alloc), but better be safe in case someone decides @@ -4003,17 +3718,13 @@ static int cfq_init_queue(struct request_queue *q) /* * Our fallback cfqq if cfq_find_alloc_queue() runs into OOM issues. * Grab a permanent reference to it, so that the normal code flow - * will not attempt to free it. oom_cfqq is linked to root_group - * but shouldn't hold a reference as it'll never be unlinked. Lose - * the reference from linking right away. + * will not attempt to free it. */ cfq_init_cfqq(cfqd, &cfqd->oom_cfqq, 1, 0); cfqd->oom_cfqq.ref++; + cfq_link_cfqq_cfqg(&cfqd->oom_cfqq, &cfqd->root_group); - spin_lock_irq(q->queue_lock); - cfq_link_cfqq_cfqg(&cfqd->oom_cfqq, cfqd->root_group); - cfqg_put(cfqd->root_group); - spin_unlock_irq(q->queue_lock); + cfqd->queue = q; init_timer(&cfqd->idle_slice_timer); cfqd->idle_slice_timer.function = cfq_idle_slice_timer; @@ -4039,11 +3750,7 @@ static int cfq_init_queue(struct request_queue *q) * second, in order to have larger depth for async operations. */ cfqd->last_delayed_sync = jiffies - HZ; - return 0; - -out_free: - kfree(cfqd); - return ret; + return cfqd; } /* @@ -4170,13 +3877,15 @@ static struct elevator_type iosched_cfq = { }; #ifdef CONFIG_CFQ_GROUP_IOSCHED -static struct blkcg_policy blkcg_policy_cfq = { - .pd_size = sizeof(struct cfq_group), - .cftypes = cfq_blkcg_files, - - .pd_init_fn = cfq_pd_init, - .pd_reset_stats_fn = cfq_pd_reset_stats, +static struct blkio_policy_type blkio_policy_cfq = { + .ops = { + .blkio_unlink_group_fn = cfq_unlink_blkio_group, + .blkio_update_group_weight_fn = cfq_update_blkio_group_weight, + }, + .plid = BLKIO_POLICY_PROP, }; +#else +static struct blkio_policy_type blkio_policy_cfq; #endif static int __init cfq_init(void) @@ -4197,31 +3906,24 @@ static int __init cfq_init(void) #else cfq_group_idle = 0; #endif - - ret = blkcg_policy_register(&blkcg_policy_cfq); - if (ret) - return ret; - cfq_pool = KMEM_CACHE(cfq_queue, 0); if (!cfq_pool) - goto err_pol_unreg; + return -ENOMEM; ret = elv_register(&iosched_cfq); - if (ret) - goto err_free_pool; + if (ret) { + kmem_cache_destroy(cfq_pool); + return ret; + } - return 0; + blkio_policy_register(&blkio_policy_cfq); -err_free_pool: - kmem_cache_destroy(cfq_pool); -err_pol_unreg: - blkcg_policy_unregister(&blkcg_policy_cfq); - return ret; + return 0; } static void __exit cfq_exit(void) { - blkcg_policy_unregister(&blkcg_policy_cfq); + blkio_policy_unregister(&blkio_policy_cfq); elv_unregister(&iosched_cfq); kmem_cache_destroy(cfq_pool); } diff --git a/trunk/block/cfq.h b/trunk/block/cfq.h new file mode 100644 index 000000000000..2a155927e37c --- /dev/null +++ b/trunk/block/cfq.h @@ -0,0 +1,115 @@ +#ifndef _CFQ_H +#define _CFQ_H +#include "blk-cgroup.h" + +#ifdef CONFIG_CFQ_GROUP_IOSCHED +static inline void cfq_blkiocg_update_io_add_stats(struct blkio_group *blkg, + struct blkio_group *curr_blkg, bool direction, bool sync) +{ + blkiocg_update_io_add_stats(blkg, curr_blkg, direction, sync); +} + +static inline void cfq_blkiocg_update_dequeue_stats(struct blkio_group *blkg, + unsigned long dequeue) +{ + blkiocg_update_dequeue_stats(blkg, dequeue); +} + +static inline void cfq_blkiocg_update_timeslice_used(struct blkio_group *blkg, + unsigned long time, unsigned long unaccounted_time) +{ + blkiocg_update_timeslice_used(blkg, time, unaccounted_time); +} + +static inline void cfq_blkiocg_set_start_empty_time(struct blkio_group *blkg) +{ + blkiocg_set_start_empty_time(blkg); +} + +static inline void cfq_blkiocg_update_io_remove_stats(struct blkio_group *blkg, + bool direction, bool sync) +{ + blkiocg_update_io_remove_stats(blkg, direction, sync); +} + +static inline void cfq_blkiocg_update_io_merged_stats(struct blkio_group *blkg, + bool direction, bool sync) +{ + blkiocg_update_io_merged_stats(blkg, direction, sync); +} + +static inline void cfq_blkiocg_update_idle_time_stats(struct blkio_group *blkg) +{ + blkiocg_update_idle_time_stats(blkg); +} + +static inline void +cfq_blkiocg_update_avg_queue_size_stats(struct blkio_group *blkg) +{ + blkiocg_update_avg_queue_size_stats(blkg); +} + +static inline void +cfq_blkiocg_update_set_idle_time_stats(struct blkio_group *blkg) +{ + blkiocg_update_set_idle_time_stats(blkg); +} + +static inline void cfq_blkiocg_update_dispatch_stats(struct blkio_group *blkg, + uint64_t bytes, bool direction, bool sync) +{ + blkiocg_update_dispatch_stats(blkg, bytes, direction, sync); +} + +static inline void cfq_blkiocg_update_completion_stats(struct blkio_group *blkg, uint64_t start_time, uint64_t io_start_time, bool direction, bool sync) +{ + blkiocg_update_completion_stats(blkg, start_time, io_start_time, + direction, sync); +} + +static inline void cfq_blkiocg_add_blkio_group(struct blkio_cgroup *blkcg, + struct blkio_group *blkg, void *key, dev_t dev) { + blkiocg_add_blkio_group(blkcg, blkg, key, dev, BLKIO_POLICY_PROP); +} + +static inline int cfq_blkiocg_del_blkio_group(struct blkio_group *blkg) +{ + return blkiocg_del_blkio_group(blkg); +} + +#else /* CFQ_GROUP_IOSCHED */ +static inline void cfq_blkiocg_update_io_add_stats(struct blkio_group *blkg, + struct blkio_group *curr_blkg, bool direction, bool sync) {} + +static inline void cfq_blkiocg_update_dequeue_stats(struct blkio_group *blkg, + unsigned long dequeue) {} + +static inline void cfq_blkiocg_update_timeslice_used(struct blkio_group *blkg, + unsigned long time, unsigned long unaccounted_time) {} +static inline void cfq_blkiocg_set_start_empty_time(struct blkio_group *blkg) {} +static inline void cfq_blkiocg_update_io_remove_stats(struct blkio_group *blkg, + bool direction, bool sync) {} +static inline void cfq_blkiocg_update_io_merged_stats(struct blkio_group *blkg, + bool direction, bool sync) {} +static inline void cfq_blkiocg_update_idle_time_stats(struct blkio_group *blkg) +{ +} +static inline void +cfq_blkiocg_update_avg_queue_size_stats(struct blkio_group *blkg) {} + +static inline void +cfq_blkiocg_update_set_idle_time_stats(struct blkio_group *blkg) {} + +static inline void cfq_blkiocg_update_dispatch_stats(struct blkio_group *blkg, + uint64_t bytes, bool direction, bool sync) {} +static inline void cfq_blkiocg_update_completion_stats(struct blkio_group *blkg, uint64_t start_time, uint64_t io_start_time, bool direction, bool sync) {} + +static inline void cfq_blkiocg_add_blkio_group(struct blkio_cgroup *blkcg, + struct blkio_group *blkg, void *key, dev_t dev) {} +static inline int cfq_blkiocg_del_blkio_group(struct blkio_group *blkg) +{ + return 0; +} + +#endif /* CFQ_GROUP_IOSCHED */ +#endif diff --git a/trunk/block/deadline-iosched.c b/trunk/block/deadline-iosched.c index 599b12e5380f..7bf12d793fcd 100644 --- a/trunk/block/deadline-iosched.c +++ b/trunk/block/deadline-iosched.c @@ -337,13 +337,13 @@ static void deadline_exit_queue(struct elevator_queue *e) /* * initialize elevator private data (deadline_data). */ -static int deadline_init_queue(struct request_queue *q) +static void *deadline_init_queue(struct request_queue *q) { struct deadline_data *dd; dd = kmalloc_node(sizeof(*dd), GFP_KERNEL | __GFP_ZERO, q->node); if (!dd) - return -ENOMEM; + return NULL; INIT_LIST_HEAD(&dd->fifo_list[READ]); INIT_LIST_HEAD(&dd->fifo_list[WRITE]); @@ -354,9 +354,7 @@ static int deadline_init_queue(struct request_queue *q) dd->writes_starved = writes_starved; dd->front_merges = 1; dd->fifo_batch = fifo_batch; - - q->elevator->elevator_data = dd; - return 0; + return dd; } /* diff --git a/trunk/block/elevator.c b/trunk/block/elevator.c index 6a55d418896f..f016855a46b0 100644 --- a/trunk/block/elevator.c +++ b/trunk/block/elevator.c @@ -38,7 +38,6 @@ #include #include "blk.h" -#include "blk-cgroup.h" static DEFINE_SPINLOCK(elv_list_lock); static LIST_HEAD(elv_list); @@ -122,6 +121,15 @@ static struct elevator_type *elevator_get(const char *name) return e; } +static int elevator_init_queue(struct request_queue *q, + struct elevator_queue *eq) +{ + eq->elevator_data = eq->type->ops.elevator_init_fn(q); + if (eq->elevator_data) + return 0; + return -ENOMEM; +} + static char chosen_elevator[ELV_NAME_MAX]; static int __init elevator_setup(char *str) @@ -180,6 +188,7 @@ static void elevator_release(struct kobject *kobj) int elevator_init(struct request_queue *q, char *name) { struct elevator_type *e = NULL; + struct elevator_queue *eq; int err; if (unlikely(q->elevator)) @@ -213,16 +222,17 @@ int elevator_init(struct request_queue *q, char *name) } } - q->elevator = elevator_alloc(q, e); - if (!q->elevator) + eq = elevator_alloc(q, e); + if (!eq) return -ENOMEM; - err = e->ops.elevator_init_fn(q); + err = elevator_init_queue(q, eq); if (err) { - kobject_put(&q->elevator->kobj); + kobject_put(&eq->kobj); return err; } + q->elevator = eq; return 0; } EXPORT_SYMBOL(elevator_init); @@ -554,6 +564,25 @@ void elv_drain_elevator(struct request_queue *q) } } +void elv_quiesce_start(struct request_queue *q) +{ + if (!q->elevator) + return; + + spin_lock_irq(q->queue_lock); + queue_flag_set(QUEUE_FLAG_ELVSWITCH, q); + spin_unlock_irq(q->queue_lock); + + blk_drain_queue(q, false); +} + +void elv_quiesce_end(struct request_queue *q) +{ + spin_lock_irq(q->queue_lock); + queue_flag_clear(QUEUE_FLAG_ELVSWITCH, q); + spin_unlock_irq(q->queue_lock); +} + void __elv_add_request(struct request_queue *q, struct request *rq, int where) { trace_block_rq_insert(q, rq); @@ -663,13 +692,12 @@ struct request *elv_former_request(struct request_queue *q, struct request *rq) return NULL; } -int elv_set_request(struct request_queue *q, struct request *rq, - struct bio *bio, gfp_t gfp_mask) +int elv_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask) { struct elevator_queue *e = q->elevator; if (e->type->ops.elevator_set_req_fn) - return e->type->ops.elevator_set_req_fn(q, rq, bio, gfp_mask); + return e->type->ops.elevator_set_req_fn(q, rq, gfp_mask); return 0; } @@ -773,9 +801,8 @@ static struct kobj_type elv_ktype = { .release = elevator_release, }; -int elv_register_queue(struct request_queue *q) +int __elv_register_queue(struct request_queue *q, struct elevator_queue *e) { - struct elevator_queue *e = q->elevator; int error; error = kobject_add(&e->kobj, &q->kobj, "%s", "iosched"); @@ -793,6 +820,11 @@ int elv_register_queue(struct request_queue *q) } return error; } + +int elv_register_queue(struct request_queue *q) +{ + return __elv_register_queue(q, q->elevator); +} EXPORT_SYMBOL(elv_register_queue); void elv_unregister_queue(struct request_queue *q) @@ -875,60 +907,53 @@ EXPORT_SYMBOL_GPL(elv_unregister); */ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e) { - struct elevator_queue *old = q->elevator; - bool registered = old->registered; + struct elevator_queue *old_elevator, *e; int err; - /* - * Turn on BYPASS and drain all requests w/ elevator private data. - * Block layer doesn't call into a quiesced elevator - all requests - * are directly put on the dispatch list without elevator data - * using INSERT_BACK. All requests have SOFTBARRIER set and no - * merge happens either. - */ - blk_queue_bypass_start(q); - - /* unregister and clear all auxiliary data of the old elevator */ - if (registered) - elv_unregister_queue(q); - - spin_lock_irq(q->queue_lock); - ioc_clear_queue(q); - spin_unlock_irq(q->queue_lock); - - /* allocate, init and register new elevator */ - err = -ENOMEM; - q->elevator = elevator_alloc(q, new_e); - if (!q->elevator) - goto fail_init; + /* allocate new elevator */ + e = elevator_alloc(q, new_e); + if (!e) + return -ENOMEM; - err = new_e->ops.elevator_init_fn(q); + err = elevator_init_queue(q, e); if (err) { - kobject_put(&q->elevator->kobj); - goto fail_init; + kobject_put(&e->kobj); + return err; } - if (registered) { - err = elv_register_queue(q); + /* turn on BYPASS and drain all requests w/ elevator private data */ + elv_quiesce_start(q); + + /* unregister old queue, register new one and kill old elevator */ + if (q->elevator->registered) { + elv_unregister_queue(q); + err = __elv_register_queue(q, e); if (err) goto fail_register; } - /* done, kill the old one and finish */ - elevator_exit(old); - blk_queue_bypass_end(q); + /* done, clear io_cq's, switch elevators and turn off BYPASS */ + spin_lock_irq(q->queue_lock); + ioc_clear_queue(q); + old_elevator = q->elevator; + q->elevator = e; + spin_unlock_irq(q->queue_lock); + + elevator_exit(old_elevator); + elv_quiesce_end(q); - blk_add_trace_msg(q, "elv switch: %s", new_e->elevator_name); + blk_add_trace_msg(q, "elv switch: %s", e->type->elevator_name); return 0; fail_register: - elevator_exit(q->elevator); -fail_init: - /* switch failed, restore and re-register old elevator */ - q->elevator = old; + /* + * switch failed, exit the new io scheduler and reattach the old + * one again (along with re-adding the sysfs dir) + */ + elevator_exit(e); elv_register_queue(q); - blk_queue_bypass_end(q); + elv_quiesce_end(q); return err; } diff --git a/trunk/block/noop-iosched.c b/trunk/block/noop-iosched.c index 5d1bf70e33d5..413a0b1d788c 100644 --- a/trunk/block/noop-iosched.c +++ b/trunk/block/noop-iosched.c @@ -59,17 +59,15 @@ noop_latter_request(struct request_queue *q, struct request *rq) return list_entry(rq->queuelist.next, struct request, queuelist); } -static int noop_init_queue(struct request_queue *q) +static void *noop_init_queue(struct request_queue *q) { struct noop_data *nd; nd = kmalloc_node(sizeof(*nd), GFP_KERNEL, q->node); if (!nd) - return -ENOMEM; - + return NULL; INIT_LIST_HEAD(&nd->queue); - q->elevator->elevator_data = nd; - return 0; + return nd; } static void noop_exit_queue(struct elevator_queue *e) diff --git a/trunk/drivers/acpi/bgrt.c b/trunk/drivers/acpi/bgrt.c index 6680df36b963..8cf6c46e99fb 100644 --- a/trunk/drivers/acpi/bgrt.c +++ b/trunk/drivers/acpi/bgrt.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/acpi/sleep.c b/trunk/drivers/acpi/sleep.c index 74ee4ab577b6..06527c526618 100644 --- a/trunk/drivers/acpi/sleep.c +++ b/trunk/drivers/acpi/sleep.c @@ -93,9 +93,11 @@ static int acpi_sleep_prepare(u32 acpi_state) #ifdef CONFIG_ACPI_SLEEP /* do we have a wakeup address for S2 and S3? */ if (acpi_state == ACPI_STATE_S3) { - if (!acpi_wakeup_address) + if (!acpi_wakeup_address) { return -EFAULT; - acpi_set_firmware_waking_vector(acpi_wakeup_address); + } + acpi_set_firmware_waking_vector( + (acpi_physical_address)acpi_wakeup_address); } ACPI_FLUSH_CPU_CACHE(); diff --git a/trunk/drivers/atm/solos-pci.c b/trunk/drivers/atm/solos-pci.c index 98510931c815..e8cd652d2017 100644 --- a/trunk/drivers/atm/solos-pci.c +++ b/trunk/drivers/atm/solos-pci.c @@ -984,7 +984,6 @@ static uint32_t fpga_tx(struct solos_card *card) } else if (skb && card->using_dma) { SKB_CB(skb)->dma_addr = pci_map_single(card->dev, skb->data, skb->len, PCI_DMA_TODEVICE); - card->tx_skb[port] = skb; iowrite32(SKB_CB(skb)->dma_addr, card->config_regs + TX_DMA_ADDR(port)); } @@ -1153,8 +1152,7 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) db_fpga_upgrade = db_firmware_upgrade = 0; } - if (card->fpga_version >= DMA_SUPPORTED) { - pci_set_master(dev); + if (card->fpga_version >= DMA_SUPPORTED){ card->using_dma = 1; } else { card->using_dma = 0; diff --git a/trunk/drivers/base/regmap/regmap-i2c.c b/trunk/drivers/base/regmap/regmap-i2c.c index fa6bf5279d28..5f6b2478bf17 100644 --- a/trunk/drivers/base/regmap/regmap-i2c.c +++ b/trunk/drivers/base/regmap/regmap-i2c.c @@ -42,7 +42,7 @@ static int regmap_i2c_gather_write(void *context, /* If the I2C controller can't do a gather tell the core, it * will substitute in a linear write for us. */ - if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_NOSTART)) + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_PROTOCOL_MANGLING)) return -ENOTSUPP; xfer[0].addr = i2c->addr; diff --git a/trunk/drivers/base/soc.c b/trunk/drivers/base/soc.c index 72b5e7280d14..ba29b2e73d48 100644 --- a/trunk/drivers/base/soc.c +++ b/trunk/drivers/base/soc.c @@ -42,7 +42,7 @@ struct device *soc_device_to_device(struct soc_device *soc_dev) return &soc_dev->dev; } -static umode_t soc_attribute_mode(struct kobject *kobj, +static mode_t soc_attribute_mode(struct kobject *kobj, struct attribute *attr, int index) { diff --git a/trunk/drivers/block/drbd/drbd_actlog.c b/trunk/drivers/block/drbd/drbd_actlog.c index e54e31b02b88..cf0e63dd97da 100644 --- a/trunk/drivers/block/drbd/drbd_actlog.c +++ b/trunk/drivers/block/drbd/drbd_actlog.c @@ -65,80 +65,39 @@ struct drbd_atodb_wait { int w_al_write_transaction(struct drbd_conf *, struct drbd_work *, int); -void *drbd_md_get_buffer(struct drbd_conf *mdev) -{ - int r; - - wait_event(mdev->misc_wait, - (r = atomic_cmpxchg(&mdev->md_io_in_use, 0, 1)) == 0 || - mdev->state.disk <= D_FAILED); - - return r ? NULL : page_address(mdev->md_io_page); -} - -void drbd_md_put_buffer(struct drbd_conf *mdev) -{ - if (atomic_dec_and_test(&mdev->md_io_in_use)) - wake_up(&mdev->misc_wait); -} - -static bool md_io_allowed(struct drbd_conf *mdev) -{ - enum drbd_disk_state ds = mdev->state.disk; - return ds >= D_NEGOTIATING || ds == D_ATTACHING; -} - -void wait_until_done_or_disk_failure(struct drbd_conf *mdev, struct drbd_backing_dev *bdev, - unsigned int *done) -{ - long dt = bdev->dc.disk_timeout * HZ / 10; - if (dt == 0) - dt = MAX_SCHEDULE_TIMEOUT; - - dt = wait_event_timeout(mdev->misc_wait, *done || !md_io_allowed(mdev), dt); - if (dt == 0) - dev_err(DEV, "meta-data IO operation timed out\n"); -} - static int _drbd_md_sync_page_io(struct drbd_conf *mdev, struct drbd_backing_dev *bdev, struct page *page, sector_t sector, int rw, int size) { struct bio *bio; + struct drbd_md_io md_io; int ok; - mdev->md_io.done = 0; - mdev->md_io.error = -ENODEV; + md_io.mdev = mdev; + init_completion(&md_io.event); + md_io.error = 0; if ((rw & WRITE) && !test_bit(MD_NO_FUA, &mdev->flags)) rw |= REQ_FUA | REQ_FLUSH; rw |= REQ_SYNC; - bio = bio_alloc_drbd(GFP_NOIO); + bio = bio_alloc(GFP_NOIO, 1); bio->bi_bdev = bdev->md_bdev; bio->bi_sector = sector; ok = (bio_add_page(bio, page, size, 0) == size); if (!ok) goto out; - bio->bi_private = &mdev->md_io; + bio->bi_private = &md_io; bio->bi_end_io = drbd_md_io_complete; bio->bi_rw = rw; - if (!get_ldev_if_state(mdev, D_ATTACHING)) { /* Corresponding put_ldev in drbd_md_io_complete() */ - dev_err(DEV, "ASSERT FAILED: get_ldev_if_state() == 1 in _drbd_md_sync_page_io()\n"); - ok = 0; - goto out; - } - - bio_get(bio); /* one bio_put() is in the completion handler */ - atomic_inc(&mdev->md_io_in_use); /* drbd_md_put_buffer() is in the completion handler */ if (drbd_insert_fault(mdev, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) bio_endio(bio, -EIO); else submit_bio(rw, bio); - wait_until_done_or_disk_failure(mdev, bdev, &mdev->md_io.done); - ok = bio_flagged(bio, BIO_UPTODATE) && mdev->md_io.error == 0; + wait_for_completion(&md_io.event); + ok = bio_flagged(bio, BIO_UPTODATE) && md_io.error == 0; out: bio_put(bio); @@ -152,7 +111,7 @@ int drbd_md_sync_page_io(struct drbd_conf *mdev, struct drbd_backing_dev *bdev, int offset = 0; struct page *iop = mdev->md_io_page; - D_ASSERT(atomic_read(&mdev->md_io_in_use) == 1); + D_ASSERT(mutex_is_locked(&mdev->md_io_mutex)); BUG_ON(!bdev->md_bdev); @@ -369,13 +328,8 @@ w_al_write_transaction(struct drbd_conf *mdev, struct drbd_work *w, int unused) return 1; } - buffer = drbd_md_get_buffer(mdev); /* protects md_io_buffer, al_tr_cycle, ... */ - if (!buffer) { - dev_err(DEV, "disk failed while waiting for md_io buffer\n"); - complete(&((struct update_al_work *)w)->event); - put_ldev(mdev); - return 1; - } + mutex_lock(&mdev->md_io_mutex); /* protects md_io_buffer, al_tr_cycle, ... */ + buffer = (struct al_transaction *)page_address(mdev->md_io_page); buffer->magic = __constant_cpu_to_be32(DRBD_MAGIC); buffer->tr_number = cpu_to_be32(mdev->al_tr_number); @@ -420,7 +374,7 @@ w_al_write_transaction(struct drbd_conf *mdev, struct drbd_work *w, int unused) D_ASSERT(mdev->al_tr_pos < MD_AL_MAX_SIZE); mdev->al_tr_number++; - drbd_md_put_buffer(mdev); + mutex_unlock(&mdev->md_io_mutex); complete(&((struct update_al_work *)w)->event); put_ldev(mdev); @@ -489,9 +443,8 @@ int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) /* lock out all other meta data io for now, * and make sure the page is mapped. */ - buffer = drbd_md_get_buffer(mdev); - if (!buffer) - return 0; + mutex_lock(&mdev->md_io_mutex); + buffer = page_address(mdev->md_io_page); /* Find the valid transaction in the log */ for (i = 0; i <= mx; i++) { @@ -499,7 +452,7 @@ int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) if (rv == 0) continue; if (rv == -1) { - drbd_md_put_buffer(mdev); + mutex_unlock(&mdev->md_io_mutex); return 0; } cnr = be32_to_cpu(buffer->tr_number); @@ -525,7 +478,7 @@ int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) if (!found_valid) { dev_warn(DEV, "No usable activity log found.\n"); - drbd_md_put_buffer(mdev); + mutex_unlock(&mdev->md_io_mutex); return 1; } @@ -540,7 +493,7 @@ int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) rv = drbd_al_read_tr(mdev, bdev, buffer, i); ERR_IF(rv == 0) goto cancel; if (rv == -1) { - drbd_md_put_buffer(mdev); + mutex_unlock(&mdev->md_io_mutex); return 0; } @@ -581,7 +534,7 @@ int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) mdev->al_tr_pos = 0; /* ok, we are done with it */ - drbd_md_put_buffer(mdev); + mutex_unlock(&mdev->md_io_mutex); dev_info(DEV, "Found %d transactions (%d active extents) in activity log.\n", transactions, active_extents); @@ -718,20 +671,16 @@ static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector, else ext->rs_failed += count; if (ext->rs_left < ext->rs_failed) { - dev_warn(DEV, "BAD! sector=%llus enr=%u rs_left=%d " - "rs_failed=%d count=%d cstate=%s\n", + dev_err(DEV, "BAD! sector=%llus enr=%u rs_left=%d " + "rs_failed=%d count=%d\n", (unsigned long long)sector, ext->lce.lc_number, ext->rs_left, - ext->rs_failed, count, - drbd_conn_str(mdev->state.conn)); - - /* We don't expect to be able to clear more bits - * than have been set when we originally counted - * the set bits to cache that value in ext->rs_left. - * Whatever the reason (disconnect during resync, - * delayed local completion of an application write), - * try to fix it up by recounting here. */ - ext->rs_left = drbd_bm_e_weight(mdev, enr); + ext->rs_failed, count); + dump_stack(); + + lc_put(mdev->resync, &ext->lce); + drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); + return; } } else { /* Normally this element should be in the cache, @@ -1243,7 +1192,6 @@ int drbd_rs_del_all(struct drbd_conf *mdev) put_ldev(mdev); } spin_unlock_irq(&mdev->al_lock); - wake_up(&mdev->al_wait); return 0; } diff --git a/trunk/drivers/block/drbd/drbd_bitmap.c b/trunk/drivers/block/drbd/drbd_bitmap.c index b5c5ff53cb57..3030201c69d8 100644 --- a/trunk/drivers/block/drbd/drbd_bitmap.c +++ b/trunk/drivers/block/drbd/drbd_bitmap.c @@ -205,7 +205,7 @@ void drbd_bm_unlock(struct drbd_conf *mdev) static void bm_store_page_idx(struct page *page, unsigned long idx) { BUG_ON(0 != (idx & ~BM_PAGE_IDX_MASK)); - set_page_private(page, idx); + page_private(page) |= idx; } static unsigned long bm_page_to_idx(struct page *page) @@ -886,21 +886,12 @@ void drbd_bm_clear_all(struct drbd_conf *mdev) struct bm_aio_ctx { struct drbd_conf *mdev; atomic_t in_flight; - unsigned int done; + struct completion done; unsigned flags; #define BM_AIO_COPY_PAGES 1 int error; - struct kref kref; }; -static void bm_aio_ctx_destroy(struct kref *kref) -{ - struct bm_aio_ctx *ctx = container_of(kref, struct bm_aio_ctx, kref); - - put_ldev(ctx->mdev); - kfree(ctx); -} - /* bv_page may be a copy, or may be the original */ static void bm_async_io_complete(struct bio *bio, int error) { @@ -939,21 +930,20 @@ static void bm_async_io_complete(struct bio *bio, int error) bm_page_unlock_io(mdev, idx); + /* FIXME give back to page pool */ if (ctx->flags & BM_AIO_COPY_PAGES) - mempool_free(bio->bi_io_vec[0].bv_page, drbd_md_io_page_pool); + put_page(bio->bi_io_vec[0].bv_page); bio_put(bio); - if (atomic_dec_and_test(&ctx->in_flight)) { - ctx->done = 1; - wake_up(&mdev->misc_wait); - kref_put(&ctx->kref, &bm_aio_ctx_destroy); - } + if (atomic_dec_and_test(&ctx->in_flight)) + complete(&ctx->done); } static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must_hold(local) { - struct bio *bio = bio_alloc_drbd(GFP_NOIO); + /* we are process context. we always get a bio */ + struct bio *bio = bio_alloc(GFP_KERNEL, 1); struct drbd_conf *mdev = ctx->mdev; struct drbd_bitmap *b = mdev->bitmap; struct page *page; @@ -976,8 +966,10 @@ static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must bm_set_page_unchanged(b->bm_pages[page_nr]); if (ctx->flags & BM_AIO_COPY_PAGES) { + /* FIXME alloc_page is good enough for now, but actually needs + * to use pre-allocated page pool */ void *src, *dest; - page = mempool_alloc(drbd_md_io_page_pool, __GFP_HIGHMEM|__GFP_WAIT); + page = alloc_page(__GFP_HIGHMEM|__GFP_WAIT); dest = kmap_atomic(page); src = kmap_atomic(b->bm_pages[page_nr]); memcpy(dest, src, PAGE_SIZE); @@ -989,8 +981,6 @@ static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must bio->bi_bdev = mdev->ldev->md_bdev; bio->bi_sector = on_disk_sector; - /* bio_add_page of a single page to an empty bio will always succeed, - * according to api. Do we want to assert that? */ bio_add_page(bio, page, len, 0); bio->bi_private = ctx; bio->bi_end_io = bm_async_io_complete; @@ -1009,9 +999,14 @@ static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must /* * bm_rw: read/write the whole bitmap from/to its on disk location. */ -static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_writeout_upper_idx) __must_hold(local) +static int bm_rw(struct drbd_conf *mdev, int rw, unsigned lazy_writeout_upper_idx) __must_hold(local) { - struct bm_aio_ctx *ctx; + struct bm_aio_ctx ctx = { + .mdev = mdev, + .in_flight = ATOMIC_INIT(1), + .done = COMPLETION_INITIALIZER_ONSTACK(ctx.done), + .flags = lazy_writeout_upper_idx ? BM_AIO_COPY_PAGES : 0, + }; struct drbd_bitmap *b = mdev->bitmap; int num_pages, i, count = 0; unsigned long now; @@ -1026,27 +1021,7 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w * For lazy writeout, we don't care for ongoing changes to the bitmap, * as we submit copies of pages anyways. */ - - ctx = kmalloc(sizeof(struct bm_aio_ctx), GFP_NOIO); - if (!ctx) - return -ENOMEM; - - *ctx = (struct bm_aio_ctx) { - .mdev = mdev, - .in_flight = ATOMIC_INIT(1), - .done = 0, - .flags = flags, - .error = 0, - .kref = { ATOMIC_INIT(2) }, - }; - - if (!get_ldev_if_state(mdev, D_ATTACHING)) { /* put is in bm_aio_ctx_destroy() */ - dev_err(DEV, "ASSERT FAILED: get_ldev_if_state() == 1 in bm_rw()\n"); - kfree(ctx); - return -ENODEV; - } - - if (!ctx->flags) + if (!ctx.flags) WARN_ON(!(BM_LOCKED_MASK & b->bm_flags)); num_pages = b->bm_number_of_pages; @@ -1071,38 +1046,29 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w continue; } } - atomic_inc(&ctx->in_flight); - bm_page_io_async(ctx, i, rw); + atomic_inc(&ctx.in_flight); + bm_page_io_async(&ctx, i, rw); ++count; cond_resched(); } /* - * We initialize ctx->in_flight to one to make sure bm_async_io_complete - * will not set ctx->done early, and decrement / test it here. If there + * We initialize ctx.in_flight to one to make sure bm_async_io_complete + * will not complete() early, and decrement / test it here. If there * are still some bios in flight, we need to wait for them here. - * If all IO is done already (or nothing had been submitted), there is - * no need to wait. Still, we need to put the kref associated with the - * "in_flight reached zero, all done" event. */ - if (!atomic_dec_and_test(&ctx->in_flight)) - wait_until_done_or_disk_failure(mdev, mdev->ldev, &ctx->done); - else - kref_put(&ctx->kref, &bm_aio_ctx_destroy); - + if (!atomic_dec_and_test(&ctx.in_flight)) + wait_for_completion(&ctx.done); dev_info(DEV, "bitmap %s of %u pages took %lu jiffies\n", rw == WRITE ? "WRITE" : "READ", count, jiffies - now); - if (ctx->error) { + if (ctx.error) { dev_alert(DEV, "we had at least one MD IO ERROR during bitmap IO\n"); drbd_chk_io_error(mdev, 1, true); - err = -EIO; /* ctx->error ? */ + err = -EIO; /* ctx.error ? */ } - if (atomic_read(&ctx->in_flight)) - err = -EIO; /* Disk failed during IO... */ - now = jiffies; if (rw == WRITE) { drbd_md_flush(mdev); @@ -1116,7 +1082,6 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w dev_info(DEV, "%s (%lu bits) marked out-of-sync by on disk bit-map.\n", ppsize(ppb, now << (BM_BLOCK_SHIFT-10)), now); - kref_put(&ctx->kref, &bm_aio_ctx_destroy); return err; } @@ -1126,7 +1091,7 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w */ int drbd_bm_read(struct drbd_conf *mdev) __must_hold(local) { - return bm_rw(mdev, READ, 0, 0); + return bm_rw(mdev, READ, 0); } /** @@ -1137,7 +1102,7 @@ int drbd_bm_read(struct drbd_conf *mdev) __must_hold(local) */ int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local) { - return bm_rw(mdev, WRITE, 0, 0); + return bm_rw(mdev, WRITE, 0); } /** @@ -1147,23 +1112,7 @@ int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local) */ int drbd_bm_write_lazy(struct drbd_conf *mdev, unsigned upper_idx) __must_hold(local) { - return bm_rw(mdev, WRITE, BM_AIO_COPY_PAGES, upper_idx); -} - -/** - * drbd_bm_write_copy_pages() - Write the whole bitmap to its on disk location. - * @mdev: DRBD device. - * - * Will only write pages that have changed since last IO. - * In contrast to drbd_bm_write(), this will copy the bitmap pages - * to temporary writeout pages. It is intended to trigger a full write-out - * while still allowing the bitmap to change, for example if a resync or online - * verify is aborted due to a failed peer disk, while local IO continues, or - * pending resync acks are still being processed. - */ -int drbd_bm_write_copy_pages(struct drbd_conf *mdev) __must_hold(local) -{ - return bm_rw(mdev, WRITE, BM_AIO_COPY_PAGES, 0); + return bm_rw(mdev, WRITE, upper_idx); } @@ -1181,45 +1130,28 @@ int drbd_bm_write_copy_pages(struct drbd_conf *mdev) __must_hold(local) */ int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(local) { - struct bm_aio_ctx *ctx; - int err; - - if (bm_test_page_unchanged(mdev->bitmap->bm_pages[idx])) { - dynamic_dev_dbg(DEV, "skipped bm page write for idx %u\n", idx); - return 0; - } - - ctx = kmalloc(sizeof(struct bm_aio_ctx), GFP_NOIO); - if (!ctx) - return -ENOMEM; - - *ctx = (struct bm_aio_ctx) { + struct bm_aio_ctx ctx = { .mdev = mdev, .in_flight = ATOMIC_INIT(1), - .done = 0, + .done = COMPLETION_INITIALIZER_ONSTACK(ctx.done), .flags = BM_AIO_COPY_PAGES, - .error = 0, - .kref = { ATOMIC_INIT(2) }, }; - if (!get_ldev_if_state(mdev, D_ATTACHING)) { /* put is in bm_aio_ctx_destroy() */ - dev_err(DEV, "ASSERT FAILED: get_ldev_if_state() == 1 in drbd_bm_write_page()\n"); - kfree(ctx); - return -ENODEV; + if (bm_test_page_unchanged(mdev->bitmap->bm_pages[idx])) { + dynamic_dev_dbg(DEV, "skipped bm page write for idx %u\n", idx); + return 0; } - bm_page_io_async(ctx, idx, WRITE_SYNC); - wait_until_done_or_disk_failure(mdev, mdev->ldev, &ctx->done); + bm_page_io_async(&ctx, idx, WRITE_SYNC); + wait_for_completion(&ctx.done); - if (ctx->error) + if (ctx.error) drbd_chk_io_error(mdev, 1, true); /* that should force detach, so the in memory bitmap will be * gone in a moment as well. */ mdev->bm_writ_cnt++; - err = atomic_read(&ctx->in_flight) ? -EIO : ctx->error; - kref_put(&ctx->kref, &bm_aio_ctx_destroy); - return err; + return ctx.error; } /* NOTE diff --git a/trunk/drivers/block/drbd/drbd_int.h b/trunk/drivers/block/drbd/drbd_int.h index 02f013a073a7..8d680562ba73 100644 --- a/trunk/drivers/block/drbd/drbd_int.h +++ b/trunk/drivers/block/drbd/drbd_int.h @@ -712,6 +712,7 @@ struct drbd_request { struct list_head tl_requests; /* ring list in the transfer log */ struct bio *master_bio; /* master bio pointer */ unsigned long rq_state; /* see comments above _req_mod() */ + int seq_num; unsigned long start_time; }; @@ -850,7 +851,6 @@ enum { NEW_CUR_UUID, /* Create new current UUID when thawing IO */ AL_SUSPENDED, /* Activity logging is currently suspended. */ AHEAD_TO_SYNC_SOURCE, /* Ahead -> SyncSource queued */ - STATE_SENT, /* Do not change state/UUIDs while this is set */ }; struct drbd_bitmap; /* opaque for drbd_conf */ @@ -862,30 +862,31 @@ enum bm_flag { BM_P_VMALLOCED = 0x10000, /* internal use only, will be masked out */ /* currently locked for bulk operation */ - BM_LOCKED_MASK = 0xf, + BM_LOCKED_MASK = 0x7, /* in detail, that is: */ BM_DONT_CLEAR = 0x1, BM_DONT_SET = 0x2, BM_DONT_TEST = 0x4, - /* so we can mark it locked for bulk operation, - * and still allow all non-bulk operations */ - BM_IS_LOCKED = 0x8, - /* (test bit, count bit) allowed (common case) */ - BM_LOCKED_TEST_ALLOWED = BM_DONT_CLEAR | BM_DONT_SET | BM_IS_LOCKED, + BM_LOCKED_TEST_ALLOWED = 0x3, /* testing bits, as well as setting new bits allowed, but clearing bits * would be unexpected. Used during bitmap receive. Setting new bits * requires sending of "out-of-sync" information, though. */ - BM_LOCKED_SET_ALLOWED = BM_DONT_CLEAR | BM_IS_LOCKED, + BM_LOCKED_SET_ALLOWED = 0x1, - /* for drbd_bm_write_copy_pages, everything is allowed, - * only concurrent bulk operations are locked out. */ - BM_LOCKED_CHANGE_ALLOWED = BM_IS_LOCKED, + /* clear is not expected while bitmap is locked for bulk operation */ }; + +/* TODO sort members for performance + * MAYBE group them further */ + +/* THINK maybe we actually want to use the default "event/%s" worker threads + * or similar in linux 2.6, which uses per cpu data and threads. + */ struct drbd_work_queue { struct list_head q; struct semaphore s; /* producers up it, worker down()s it */ @@ -937,7 +938,8 @@ struct drbd_backing_dev { }; struct drbd_md_io { - unsigned int done; + struct drbd_conf *mdev; + struct completion event; int error; }; @@ -1020,7 +1022,6 @@ struct drbd_conf { struct drbd_tl_epoch *newest_tle; struct drbd_tl_epoch *oldest_tle; struct list_head out_of_sequence_requests; - struct list_head barrier_acked_requests; struct hlist_head *tl_hash; unsigned int tl_hash_s; @@ -1055,8 +1056,6 @@ struct drbd_conf { struct crypto_hash *csums_tfm; struct crypto_hash *verify_tfm; - unsigned long last_reattach_jif; - unsigned long last_reconnect_jif; struct drbd_thread receiver; struct drbd_thread worker; struct drbd_thread asender; @@ -1095,8 +1094,7 @@ struct drbd_conf { wait_queue_head_t ee_wait; struct page *md_io_page; /* one page buffer for md_io */ struct page *md_io_tmpp; /* for logical_block_size != 512 */ - struct drbd_md_io md_io; - atomic_t md_io_in_use; /* protects the md_io, md_io_page and md_io_tmpp */ + struct mutex md_io_mutex; /* protects the md_io_buffer */ spinlock_t al_lock; wait_queue_head_t al_wait; struct lru_cache *act_log; /* activity log */ @@ -1230,8 +1228,8 @@ extern int drbd_send_uuids(struct drbd_conf *mdev); extern int drbd_send_uuids_skip_initial_sync(struct drbd_conf *mdev); extern int drbd_gen_and_send_sync_uuid(struct drbd_conf *mdev); extern int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags flags); -extern int drbd_send_state(struct drbd_conf *mdev, union drbd_state s); -extern int drbd_send_current_state(struct drbd_conf *mdev); +extern int _drbd_send_state(struct drbd_conf *mdev); +extern int drbd_send_state(struct drbd_conf *mdev); extern int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, enum drbd_packets cmd, struct p_header80 *h, size_t size, unsigned msg_flags); @@ -1463,7 +1461,6 @@ extern int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr); extern int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(local); extern int drbd_bm_read(struct drbd_conf *mdev) __must_hold(local); extern int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local); -extern int drbd_bm_write_copy_pages(struct drbd_conf *mdev) __must_hold(local); extern unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev, unsigned long al_enr); extern size_t drbd_bm_words(struct drbd_conf *mdev); @@ -1496,38 +1493,11 @@ extern struct kmem_cache *drbd_al_ext_cache; /* activity log extents */ extern mempool_t *drbd_request_mempool; extern mempool_t *drbd_ee_mempool; -/* drbd's page pool, used to buffer data received from the peer, - * or data requested by the peer. - * - * This does not have an emergency reserve. - * - * When allocating from this pool, it first takes pages from the pool. - * Only if the pool is depleted will try to allocate from the system. - * - * The assumption is that pages taken from this pool will be processed, - * and given back, "quickly", and then can be recycled, so we can avoid - * frequent calls to alloc_page(), and still will be able to make progress even - * under memory pressure. - */ -extern struct page *drbd_pp_pool; +extern struct page *drbd_pp_pool; /* drbd's page pool */ extern spinlock_t drbd_pp_lock; extern int drbd_pp_vacant; extern wait_queue_head_t drbd_pp_wait; -/* We also need a standard (emergency-reserve backed) page pool - * for meta data IO (activity log, bitmap). - * We can keep it global, as long as it is used as "N pages at a time". - * 128 should be plenty, currently we probably can get away with as few as 1. - */ -#define DRBD_MIN_POOL_PAGES 128 -extern mempool_t *drbd_md_io_page_pool; - -/* We also need to make sure we get a bio - * when we need it for housekeeping purposes */ -extern struct bio_set *drbd_md_io_bio_set; -/* to allocate from that set */ -extern struct bio *bio_alloc_drbd(gfp_t gfp_mask); - extern rwlock_t global_state_lock; extern struct drbd_conf *drbd_new_device(unsigned int minor); @@ -1566,12 +1536,8 @@ extern void resume_next_sg(struct drbd_conf *mdev); extern void suspend_other_sg(struct drbd_conf *mdev); extern int drbd_resync_finished(struct drbd_conf *mdev); /* maybe rather drbd_main.c ? */ -extern void *drbd_md_get_buffer(struct drbd_conf *mdev); -extern void drbd_md_put_buffer(struct drbd_conf *mdev); extern int drbd_md_sync_page_io(struct drbd_conf *mdev, - struct drbd_backing_dev *bdev, sector_t sector, int rw); -extern void wait_until_done_or_disk_failure(struct drbd_conf *mdev, struct drbd_backing_dev *bdev, - unsigned int *done); + struct drbd_backing_dev *bdev, sector_t sector, int rw); extern void drbd_ov_oos_found(struct drbd_conf*, sector_t, int); extern void drbd_rs_controller_reset(struct drbd_conf *mdev); @@ -1788,6 +1754,19 @@ static inline struct page *page_chain_next(struct page *page) #define page_chain_for_each_safe(page, n) \ for (; page && ({ n = page_chain_next(page); 1; }); page = n) +static inline int drbd_bio_has_active_page(struct bio *bio) +{ + struct bio_vec *bvec; + int i; + + __bio_for_each_segment(bvec, bio, i, 0) { + if (page_count(bvec->bv_page) > 1) + return 1; + } + + return 0; +} + static inline int drbd_ee_has_active_page(struct drbd_epoch_entry *e) { struct page *page = e->pages; @@ -1798,6 +1777,7 @@ static inline int drbd_ee_has_active_page(struct drbd_epoch_entry *e) return 0; } + static inline void drbd_state_lock(struct drbd_conf *mdev) { wait_event(mdev->misc_wait, @@ -2250,7 +2230,7 @@ static inline void drbd_get_syncer_progress(struct drbd_conf *mdev, * Note: currently we don't support such large bitmaps on 32bit * arch anyways, but no harm done to be prepared for it here. */ - unsigned int shift = mdev->rs_total > UINT_MAX ? 16 : 10; + unsigned int shift = mdev->rs_total >= (1ULL << 32) ? 16 : 10; unsigned long left = *bits_left >> shift; unsigned long total = 1UL + (mdev->rs_total >> shift); unsigned long tmp = 1000UL - left * 1000UL/total; @@ -2326,12 +2306,12 @@ static inline int drbd_state_is_stable(struct drbd_conf *mdev) case D_OUTDATED: case D_CONSISTENT: case D_UP_TO_DATE: - case D_FAILED: /* disk state is stable as well. */ break; /* no new io accepted during tansitional states */ case D_ATTACHING: + case D_FAILED: case D_NEGOTIATING: case D_UNKNOWN: case D_MASK: diff --git a/trunk/drivers/block/drbd/drbd_main.c b/trunk/drivers/block/drbd/drbd_main.c index 920ede2829d6..211fc44f84be 100644 --- a/trunk/drivers/block/drbd/drbd_main.c +++ b/trunk/drivers/block/drbd/drbd_main.c @@ -139,8 +139,6 @@ struct kmem_cache *drbd_bm_ext_cache; /* bitmap extents */ struct kmem_cache *drbd_al_ext_cache; /* activity log extents */ mempool_t *drbd_request_mempool; mempool_t *drbd_ee_mempool; -mempool_t *drbd_md_io_page_pool; -struct bio_set *drbd_md_io_bio_set; /* I do not use a standard mempool, because: 1) I want to hand out the pre-allocated objects first. @@ -161,24 +159,7 @@ static const struct block_device_operations drbd_ops = { .release = drbd_release, }; -static void bio_destructor_drbd(struct bio *bio) -{ - bio_free(bio, drbd_md_io_bio_set); -} - -struct bio *bio_alloc_drbd(gfp_t gfp_mask) -{ - struct bio *bio; - - if (!drbd_md_io_bio_set) - return bio_alloc(gfp_mask, 1); - - bio = bio_alloc_bioset(gfp_mask, 1, drbd_md_io_bio_set); - if (!bio) - return NULL; - bio->bi_destructor = bio_destructor_drbd; - return bio; -} +#define ARRY_SIZE(A) (sizeof(A)/sizeof(A[0])) #ifdef __CHECKER__ /* When checking with sparse, and this is an inline function, sparse will @@ -227,7 +208,6 @@ static int tl_init(struct drbd_conf *mdev) mdev->oldest_tle = b; mdev->newest_tle = b; INIT_LIST_HEAD(&mdev->out_of_sequence_requests); - INIT_LIST_HEAD(&mdev->barrier_acked_requests); mdev->tl_hash = NULL; mdev->tl_hash_s = 0; @@ -266,7 +246,9 @@ void _tl_add_barrier(struct drbd_conf *mdev, struct drbd_tl_epoch *new) new->n_writes = 0; newest_before = mdev->newest_tle; - new->br_number = newest_before->br_number+1; + /* never send a barrier number == 0, because that is special-cased + * when using TCQ for our write ordering code */ + new->br_number = (newest_before->br_number+1) ?: 1; if (mdev->newest_tle != new) { mdev->newest_tle->next = new; mdev->newest_tle = new; @@ -329,7 +311,7 @@ void tl_release(struct drbd_conf *mdev, unsigned int barrier_nr, These have been list_move'd to the out_of_sequence_requests list in _req_mod(, barrier_acked) above. */ - list_splice_init(&b->requests, &mdev->barrier_acked_requests); + list_del_init(&b->requests); nob = b->next; if (test_and_clear_bit(CREATE_BARRIER, &mdev->flags)) { @@ -429,23 +411,6 @@ static void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) b = tmp; list_splice(&carry_reads, &b->requests); } - - /* Actions operating on the disk state, also want to work on - requests that got barrier acked. */ - switch (what) { - case fail_frozen_disk_io: - case restart_frozen_disk_io: - list_for_each_safe(le, tle, &mdev->barrier_acked_requests) { - req = list_entry(le, struct drbd_request, tl_requests); - _req_mod(req, what); - } - - case connection_lost_while_pending: - case resend: - break; - default: - dev_err(DEV, "what = %d in _tl_restart()\n", what); - } } @@ -492,38 +457,6 @@ void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) spin_unlock_irq(&mdev->req_lock); } -/** - * tl_abort_disk_io() - Abort disk I/O for all requests for a certain mdev in the TL - * @mdev: DRBD device. - */ -void tl_abort_disk_io(struct drbd_conf *mdev) -{ - struct drbd_tl_epoch *b; - struct list_head *le, *tle; - struct drbd_request *req; - - spin_lock_irq(&mdev->req_lock); - b = mdev->oldest_tle; - while (b) { - list_for_each_safe(le, tle, &b->requests) { - req = list_entry(le, struct drbd_request, tl_requests); - if (!(req->rq_state & RQ_LOCAL_PENDING)) - continue; - _req_mod(req, abort_disk_io); - } - b = b->next; - } - - list_for_each_safe(le, tle, &mdev->barrier_acked_requests) { - req = list_entry(le, struct drbd_request, tl_requests); - if (!(req->rq_state & RQ_LOCAL_PENDING)) - continue; - _req_mod(req, abort_disk_io); - } - - spin_unlock_irq(&mdev->req_lock); -} - /** * cl_wide_st_chg() - true if the state change is a cluster wide one * @mdev: DRBD device. @@ -537,7 +470,7 @@ static int cl_wide_st_chg(struct drbd_conf *mdev, ((os.role != R_PRIMARY && ns.role == R_PRIMARY) || (os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) || (os.conn != C_STARTING_SYNC_S && ns.conn == C_STARTING_SYNC_S) || - (os.disk != D_FAILED && ns.disk == D_FAILED))) || + (os.disk != D_DISKLESS && ns.disk == D_DISKLESS))) || (os.conn >= C_CONNECTED && ns.conn == C_DISCONNECTING) || (os.conn == C_CONNECTED && ns.conn == C_VERIFY_S); } @@ -576,16 +509,8 @@ static enum drbd_state_rv is_valid_state(struct drbd_conf *, union drbd_state); static enum drbd_state_rv is_valid_state_transition(struct drbd_conf *, union drbd_state, union drbd_state); -enum sanitize_state_warnings { - NO_WARNING, - ABORTED_ONLINE_VERIFY, - ABORTED_RESYNC, - CONNECTION_LOST_NEGOTIATING, - IMPLICITLY_UPGRADED_DISK, - IMPLICITLY_UPGRADED_PDSK, -}; static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os, - union drbd_state ns, enum sanitize_state_warnings *warn); + union drbd_state ns, const char **warn_sync_abort); int drbd_send_state_req(struct drbd_conf *, union drbd_state, union drbd_state); @@ -860,13 +785,6 @@ is_valid_state_transition(struct drbd_conf *mdev, union drbd_state ns, if (ns.conn == os.conn && ns.conn == C_WF_REPORT_PARAMS) rv = SS_IN_TRANSIENT_STATE; - /* While establishing a connection only allow cstate to change. - Delay/refuse role changes, detach attach etc... */ - if (test_bit(STATE_SENT, &mdev->flags) && - !(os.conn == C_WF_REPORT_PARAMS || - (ns.conn == C_WF_REPORT_PARAMS && os.conn == C_WF_CONNECTION))) - rv = SS_IN_TRANSIENT_STATE; - if ((ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T) && os.conn < C_CONNECTED) rv = SS_NEED_CONNECTION; @@ -885,21 +803,6 @@ is_valid_state_transition(struct drbd_conf *mdev, union drbd_state ns, return rv; } -static void print_sanitize_warnings(struct drbd_conf *mdev, enum sanitize_state_warnings warn) -{ - static const char *msg_table[] = { - [NO_WARNING] = "", - [ABORTED_ONLINE_VERIFY] = "Online-verify aborted.", - [ABORTED_RESYNC] = "Resync aborted.", - [CONNECTION_LOST_NEGOTIATING] = "Connection lost while negotiating, no data!", - [IMPLICITLY_UPGRADED_DISK] = "Implicitly upgraded disk", - [IMPLICITLY_UPGRADED_PDSK] = "Implicitly upgraded pdsk", - }; - - if (warn != NO_WARNING) - dev_warn(DEV, "%s\n", msg_table[warn]); -} - /** * sanitize_state() - Resolves implicitly necessary additional changes to a state transition * @mdev: DRBD device. @@ -911,14 +814,11 @@ static void print_sanitize_warnings(struct drbd_conf *mdev, enum sanitize_state_ * to D_UNKNOWN. This rule and many more along those lines are in this function. */ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os, - union drbd_state ns, enum sanitize_state_warnings *warn) + union drbd_state ns, const char **warn_sync_abort) { enum drbd_fencing_p fp; enum drbd_disk_state disk_min, disk_max, pdsk_min, pdsk_max; - if (warn) - *warn = NO_WARNING; - fp = FP_DONT_CARE; if (get_ldev(mdev)) { fp = mdev->ldev->dc.fencing; @@ -933,13 +833,18 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state /* After a network error (+C_TEAR_DOWN) only C_UNCONNECTED or C_DISCONNECTING can follow. * If you try to go into some Sync* state, that shall fail (elsewhere). */ if (os.conn >= C_TIMEOUT && os.conn <= C_TEAR_DOWN && - ns.conn != C_UNCONNECTED && ns.conn != C_DISCONNECTING && ns.conn <= C_CONNECTED) + ns.conn != C_UNCONNECTED && ns.conn != C_DISCONNECTING && ns.conn <= C_TEAR_DOWN) ns.conn = os.conn; /* we cannot fail (again) if we already detached */ if (ns.disk == D_FAILED && os.disk == D_DISKLESS) ns.disk = D_DISKLESS; + /* if we are only D_ATTACHING yet, + * we can (and should) go directly to D_DISKLESS. */ + if (ns.disk == D_FAILED && os.disk == D_ATTACHING) + ns.disk = D_DISKLESS; + /* After C_DISCONNECTING only C_STANDALONE may follow */ if (os.conn == C_DISCONNECTING && ns.conn != C_STANDALONE) ns.conn = os.conn; @@ -958,9 +863,10 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state /* Abort resync if a disk fails/detaches */ if (os.conn > C_CONNECTED && ns.conn > C_CONNECTED && (ns.disk <= D_FAILED || ns.pdsk <= D_FAILED)) { - if (warn) - *warn = os.conn == C_VERIFY_S || os.conn == C_VERIFY_T ? - ABORTED_ONLINE_VERIFY : ABORTED_RESYNC; + if (warn_sync_abort) + *warn_sync_abort = + os.conn == C_VERIFY_S || os.conn == C_VERIFY_T ? + "Online-verify" : "Resync"; ns.conn = C_CONNECTED; } @@ -971,8 +877,7 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state ns.disk = mdev->new_state_tmp.disk; ns.pdsk = mdev->new_state_tmp.pdsk; } else { - if (warn) - *warn = CONNECTION_LOST_NEGOTIATING; + dev_alert(DEV, "Connection lost while negotiating, no data!\n"); ns.disk = D_DISKLESS; ns.pdsk = D_UNKNOWN; } @@ -1054,16 +959,16 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state ns.disk = disk_max; if (ns.disk < disk_min) { - if (warn) - *warn = IMPLICITLY_UPGRADED_DISK; + dev_warn(DEV, "Implicitly set disk from %s to %s\n", + drbd_disk_str(ns.disk), drbd_disk_str(disk_min)); ns.disk = disk_min; } if (ns.pdsk > pdsk_max) ns.pdsk = pdsk_max; if (ns.pdsk < pdsk_min) { - if (warn) - *warn = IMPLICITLY_UPGRADED_PDSK; + dev_warn(DEV, "Implicitly set pdsk from %s to %s\n", + drbd_disk_str(ns.pdsk), drbd_disk_str(pdsk_min)); ns.pdsk = pdsk_min; } @@ -1140,12 +1045,12 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, { union drbd_state os; enum drbd_state_rv rv = SS_SUCCESS; - enum sanitize_state_warnings ssw; + const char *warn_sync_abort = NULL; struct after_state_chg_work *ascw; os = mdev->state; - ns = sanitize_state(mdev, os, ns, &ssw); + ns = sanitize_state(mdev, os, ns, &warn_sync_abort); if (ns.i == os.i) return SS_NOTHING_TO_DO; @@ -1171,7 +1076,8 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, return rv; } - print_sanitize_warnings(mdev, ssw); + if (warn_sync_abort) + dev_warn(DEV, "%s aborted.\n", warn_sync_abort); { char *pbp, pb[300]; @@ -1337,7 +1243,7 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, drbd_thread_stop_nowait(&mdev->receiver); /* Upon network failure, we need to restart the receiver. */ - if (os.conn > C_WF_CONNECTION && + if (os.conn > C_TEAR_DOWN && ns.conn <= C_TEAR_DOWN && ns.conn >= C_TIMEOUT) drbd_thread_restart_nowait(&mdev->receiver); @@ -1345,15 +1251,6 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) drbd_resume_al(mdev); - /* remember last connect and attach times so request_timer_fn() won't - * kill newly established sessions while we are still trying to thaw - * previously frozen IO */ - if (os.conn != C_WF_REPORT_PARAMS && ns.conn == C_WF_REPORT_PARAMS) - mdev->last_reconnect_jif = jiffies; - if ((os.disk == D_ATTACHING || os.disk == D_NEGOTIATING) && - ns.disk > D_NEGOTIATING) - mdev->last_reattach_jif = jiffies; - ascw = kmalloc(sizeof(*ascw), GFP_ATOMIC); if (ascw) { ascw->os = os; @@ -1457,16 +1354,12 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, /* Here we have the actions that are performed after a state change. This function might sleep */ - if (os.disk <= D_NEGOTIATING && ns.disk > D_NEGOTIATING) - mod_timer(&mdev->request_timer, jiffies + HZ); - nsm.i = -1; if (ns.susp_nod) { if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) what = resend; - if ((os.disk == D_ATTACHING || os.disk == D_NEGOTIATING) && - ns.disk > D_NEGOTIATING) + if (os.disk == D_ATTACHING && ns.disk > D_ATTACHING) what = restart_frozen_disk_io; if (what != nothing) @@ -1515,7 +1408,7 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, /* Do not change the order of the if above and the two below... */ if (os.pdsk == D_DISKLESS && ns.pdsk > D_DISKLESS) { /* attach on the peer */ drbd_send_uuids(mdev); - drbd_send_state(mdev, ns); + drbd_send_state(mdev); } /* No point in queuing send_bitmap if we don't have a connection * anymore, so check also the _current_ state, not only the new state @@ -1548,11 +1441,11 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, } if (ns.pdsk < D_INCONSISTENT && get_ldev(mdev)) { - if (os.peer == R_SECONDARY && ns.peer == R_PRIMARY && - mdev->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) { + if (ns.peer == R_PRIMARY && mdev->ldev->md.uuid[UI_BITMAP] == 0) { drbd_uuid_new_current(mdev); drbd_send_uuids(mdev); } + /* D_DISKLESS Peer becomes secondary */ if (os.peer == R_PRIMARY && ns.peer == R_SECONDARY) /* We may still be Primary ourselves. @@ -1580,14 +1473,14 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, os.disk == D_ATTACHING && ns.disk == D_NEGOTIATING) { drbd_send_sizes(mdev, 0, 0); /* to start sync... */ drbd_send_uuids(mdev); - drbd_send_state(mdev, ns); + drbd_send_state(mdev); } /* We want to pause/continue resync, tell peer. */ if (ns.conn >= C_CONNECTED && ((os.aftr_isp != ns.aftr_isp) || (os.user_isp != ns.user_isp))) - drbd_send_state(mdev, ns); + drbd_send_state(mdev); /* In case one of the isp bits got set, suspend other devices. */ if ((!os.aftr_isp && !os.peer_isp && !os.user_isp) && @@ -1597,10 +1490,10 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, /* Make sure the peer gets informed about eventual state changes (ISP bits) while we were in WFReportParams. */ if (os.conn == C_WF_REPORT_PARAMS && ns.conn >= C_CONNECTED) - drbd_send_state(mdev, ns); + drbd_send_state(mdev); if (os.conn != C_AHEAD && ns.conn == C_AHEAD) - drbd_send_state(mdev, ns); + drbd_send_state(mdev); /* We are in the progress to start a full sync... */ if ((os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) || @@ -1620,38 +1513,33 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, /* first half of local IO error, failure to attach, * or administrative detach */ if (os.disk != D_FAILED && ns.disk == D_FAILED) { - enum drbd_io_error_p eh = EP_PASS_ON; - int was_io_error = 0; + enum drbd_io_error_p eh; + int was_io_error; /* corresponding get_ldev was in __drbd_set_state, to serialize - * our cleanup here with the transition to D_DISKLESS. - * But is is still not save to dreference ldev here, since - * we might come from an failed Attach before ldev was set. */ - if (mdev->ldev) { - eh = mdev->ldev->dc.on_io_error; - was_io_error = test_and_clear_bit(WAS_IO_ERROR, &mdev->flags); - - /* Immediately allow completion of all application IO, that waits - for completion from the local disk. */ - tl_abort_disk_io(mdev); - - /* current state still has to be D_FAILED, - * there is only one way out: to D_DISKLESS, - * and that may only happen after our put_ldev below. */ - if (mdev->state.disk != D_FAILED) - dev_err(DEV, - "ASSERT FAILED: disk is %s during detach\n", - drbd_disk_str(mdev->state.disk)); - - if (ns.conn >= C_CONNECTED) - drbd_send_state(mdev, ns); - - drbd_rs_cancel_all(mdev); - - /* In case we want to get something to stable storage still, - * this may be the last chance. - * Following put_ldev may transition to D_DISKLESS. */ - drbd_md_sync(mdev); - } + * our cleanup here with the transition to D_DISKLESS, + * so it is safe to dreference ldev here. */ + eh = mdev->ldev->dc.on_io_error; + was_io_error = test_and_clear_bit(WAS_IO_ERROR, &mdev->flags); + + /* current state still has to be D_FAILED, + * there is only one way out: to D_DISKLESS, + * and that may only happen after our put_ldev below. */ + if (mdev->state.disk != D_FAILED) + dev_err(DEV, + "ASSERT FAILED: disk is %s during detach\n", + drbd_disk_str(mdev->state.disk)); + + if (drbd_send_state(mdev)) + dev_warn(DEV, "Notified peer that I am detaching my disk\n"); + else + dev_err(DEV, "Sending state for detaching disk failed\n"); + + drbd_rs_cancel_all(mdev); + + /* In case we want to get something to stable storage still, + * this may be the last chance. + * Following put_ldev may transition to D_DISKLESS. */ + drbd_md_sync(mdev); put_ldev(mdev); if (was_io_error && eh == EP_CALL_HELPER) @@ -1673,17 +1561,16 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, mdev->rs_failed = 0; atomic_set(&mdev->rs_pending_cnt, 0); - if (ns.conn >= C_CONNECTED) - drbd_send_state(mdev, ns); - + if (drbd_send_state(mdev)) + dev_warn(DEV, "Notified peer that I'm now diskless.\n"); /* corresponding get_ldev in __drbd_set_state * this may finally trigger drbd_ldev_destroy. */ put_ldev(mdev); } /* Notify peer that I had a local IO error, and did not detached.. */ - if (os.disk == D_UP_TO_DATE && ns.disk == D_INCONSISTENT && ns.conn >= C_CONNECTED) - drbd_send_state(mdev, ns); + if (os.disk == D_UP_TO_DATE && ns.disk == D_INCONSISTENT) + drbd_send_state(mdev); /* Disks got bigger while they were detached */ if (ns.disk > D_NEGOTIATING && ns.pdsk > D_NEGOTIATING && @@ -1701,13 +1588,7 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, /* sync target done with resync. Explicitly notify peer, even though * it should (at least for non-empty resyncs) already know itself. */ if (os.disk < D_UP_TO_DATE && os.conn >= C_SYNC_SOURCE && ns.conn == C_CONNECTED) - drbd_send_state(mdev, ns); - - /* Wake up role changes, that were delayed because of connection establishing */ - if (os.conn == C_WF_REPORT_PARAMS && ns.conn != C_WF_REPORT_PARAMS) { - clear_bit(STATE_SENT, &mdev->flags); - wake_up(&mdev->state_wait); - } + drbd_send_state(mdev); /* This triggers bitmap writeout of potentially still unwritten pages * if the resync finished cleanly, or aborted because of peer disk @@ -1717,8 +1598,8 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, * No harm done if some bits change during this phase. */ if (os.conn > C_CONNECTED && ns.conn <= C_CONNECTED && get_ldev(mdev)) { - drbd_queue_bitmap_io(mdev, &drbd_bm_write_copy_pages, NULL, - "write from resync_finished", BM_LOCKED_CHANGE_ALLOWED); + drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL, + "write from resync_finished", BM_LOCKED_SET_ALLOWED); put_ldev(mdev); } @@ -2176,11 +2057,7 @@ int drbd_gen_and_send_sync_uuid(struct drbd_conf *mdev) D_ASSERT(mdev->state.disk == D_UP_TO_DATE); - uuid = mdev->ldev->md.uuid[UI_BITMAP]; - if (uuid && uuid != UUID_JUST_CREATED) - uuid = uuid + UUID_NEW_BM_OFFSET; - else - get_random_bytes(&uuid, sizeof(u64)); + uuid = mdev->ldev->md.uuid[UI_BITMAP] + UUID_NEW_BM_OFFSET; drbd_uuid_set(mdev, UI_BITMAP, uuid); drbd_print_uuids(mdev, "updated sync UUID"); drbd_md_sync(mdev); @@ -2212,10 +2089,6 @@ int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags fl max_bio_size = DRBD_MAX_BIO_SIZE; /* ... multiple BIOs per peer_request */ } - /* Never allow old drbd (up to 8.3.7) to see more than 32KiB */ - if (mdev->agreed_pro_version <= 94) - max_bio_size = min_t(int, max_bio_size, DRBD_MAX_SIZE_H80_PACKET); - p.d_size = cpu_to_be64(d_size); p.u_size = cpu_to_be64(u_size); p.c_size = cpu_to_be64(trigger_reply ? 0 : drbd_get_capacity(mdev->this_bdev)); @@ -2229,10 +2102,10 @@ int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags fl } /** - * drbd_send_current_state() - Sends the drbd state to the peer + * drbd_send_state() - Sends the drbd state to the peer * @mdev: DRBD device. */ -int drbd_send_current_state(struct drbd_conf *mdev) +int drbd_send_state(struct drbd_conf *mdev) { struct socket *sock; struct p_state p; @@ -2258,37 +2131,6 @@ int drbd_send_current_state(struct drbd_conf *mdev) return ok; } -/** - * drbd_send_state() - After a state change, sends the new state to the peer - * @mdev: DRBD device. - * @state: the state to send, not necessarily the current state. - * - * Each state change queues an "after_state_ch" work, which will eventually - * send the resulting new state to the peer. If more state changes happen - * between queuing and processing of the after_state_ch work, we still - * want to send each intermediary state in the order it occurred. - */ -int drbd_send_state(struct drbd_conf *mdev, union drbd_state state) -{ - struct socket *sock; - struct p_state p; - int ok = 0; - - mutex_lock(&mdev->data.mutex); - - p.state = cpu_to_be32(state.i); - sock = mdev->data.socket; - - if (likely(sock != NULL)) { - ok = _drbd_send_cmd(mdev, sock, P_STATE, - (struct p_header80 *)&p, sizeof(p), 0); - } - - mutex_unlock(&mdev->data.mutex); - - return ok; -} - int drbd_send_state_req(struct drbd_conf *mdev, union drbd_state mask, union drbd_state val) { @@ -2773,7 +2615,7 @@ static int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio) struct bio_vec *bvec; int i; /* hint all but last page with MSG_MORE */ - bio_for_each_segment(bvec, bio, i) { + __bio_for_each_segment(bvec, bio, i, 0) { if (!_drbd_no_send_page(mdev, bvec->bv_page, bvec->bv_offset, bvec->bv_len, i == bio->bi_vcnt -1 ? 0 : MSG_MORE)) @@ -2787,7 +2629,7 @@ static int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio) struct bio_vec *bvec; int i; /* hint all but last page with MSG_MORE */ - bio_for_each_segment(bvec, bio, i) { + __bio_for_each_segment(bvec, bio, i, 0) { if (!_drbd_send_page(mdev, bvec->bv_page, bvec->bv_offset, bvec->bv_len, i == bio->bi_vcnt -1 ? 0 : MSG_MORE)) @@ -2853,7 +2695,8 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) p.sector = cpu_to_be64(req->sector); p.block_id = (unsigned long)req; - p.seq_num = cpu_to_be32(atomic_add_return(1, &mdev->packet_seq)); + p.seq_num = cpu_to_be32(req->seq_num = + atomic_add_return(1, &mdev->packet_seq)); dp_flags = bio_flags_to_wire(mdev, req->master_bio->bi_rw); @@ -3144,8 +2987,8 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) atomic_set(&mdev->rs_sect_in, 0); atomic_set(&mdev->rs_sect_ev, 0); atomic_set(&mdev->ap_in_flight, 0); - atomic_set(&mdev->md_io_in_use, 0); + mutex_init(&mdev->md_io_mutex); mutex_init(&mdev->data.mutex); mutex_init(&mdev->meta.mutex); sema_init(&mdev->data.work.s, 0); @@ -3283,10 +3126,6 @@ static void drbd_destroy_mempools(void) /* D_ASSERT(atomic_read(&drbd_pp_vacant)==0); */ - if (drbd_md_io_bio_set) - bioset_free(drbd_md_io_bio_set); - if (drbd_md_io_page_pool) - mempool_destroy(drbd_md_io_page_pool); if (drbd_ee_mempool) mempool_destroy(drbd_ee_mempool); if (drbd_request_mempool) @@ -3300,8 +3139,6 @@ static void drbd_destroy_mempools(void) if (drbd_al_ext_cache) kmem_cache_destroy(drbd_al_ext_cache); - drbd_md_io_bio_set = NULL; - drbd_md_io_page_pool = NULL; drbd_ee_mempool = NULL; drbd_request_mempool = NULL; drbd_ee_cache = NULL; @@ -3325,8 +3162,6 @@ static int drbd_create_mempools(void) drbd_bm_ext_cache = NULL; drbd_al_ext_cache = NULL; drbd_pp_pool = NULL; - drbd_md_io_page_pool = NULL; - drbd_md_io_bio_set = NULL; /* caches */ drbd_request_cache = kmem_cache_create( @@ -3350,16 +3185,6 @@ static int drbd_create_mempools(void) goto Enomem; /* mempools */ -#ifdef COMPAT_HAVE_BIOSET_CREATE - drbd_md_io_bio_set = bioset_create(DRBD_MIN_POOL_PAGES, 0); - if (drbd_md_io_bio_set == NULL) - goto Enomem; -#endif - - drbd_md_io_page_pool = mempool_create_page_pool(DRBD_MIN_POOL_PAGES, 0); - if (drbd_md_io_page_pool == NULL) - goto Enomem; - drbd_request_mempool = mempool_create(number, mempool_alloc_slab, mempool_free_slab, drbd_request_cache); if (drbd_request_mempool == NULL) @@ -3437,8 +3262,6 @@ static void drbd_delete_device(unsigned int minor) if (!mdev) return; - del_timer_sync(&mdev->request_timer); - /* paranoia asserts */ if (mdev->open_cnt != 0) dev_err(DEV, "open_cnt = %d in %s:%u", mdev->open_cnt, @@ -3843,10 +3666,8 @@ void drbd_md_sync(struct drbd_conf *mdev) if (!get_ldev_if_state(mdev, D_FAILED)) return; - buffer = drbd_md_get_buffer(mdev); - if (!buffer) - goto out; - + mutex_lock(&mdev->md_io_mutex); + buffer = (struct meta_data_on_disk *)page_address(mdev->md_io_page); memset(buffer, 0, 512); buffer->la_size = cpu_to_be64(drbd_get_capacity(mdev->this_bdev)); @@ -3877,8 +3698,7 @@ void drbd_md_sync(struct drbd_conf *mdev) * since we updated it on metadata. */ mdev->ldev->md.la_size_sect = drbd_get_capacity(mdev->this_bdev); - drbd_md_put_buffer(mdev); -out: + mutex_unlock(&mdev->md_io_mutex); put_ldev(mdev); } @@ -3898,9 +3718,8 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) if (!get_ldev_if_state(mdev, D_ATTACHING)) return ERR_IO_MD_DISK; - buffer = drbd_md_get_buffer(mdev); - if (!buffer) - goto out; + mutex_lock(&mdev->md_io_mutex); + buffer = (struct meta_data_on_disk *)page_address(mdev->md_io_page); if (!drbd_md_sync_page_io(mdev, bdev, bdev->md.md_offset, READ)) { /* NOTE: can't do normal error processing here as this is @@ -3961,8 +3780,7 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) mdev->sync_conf.al_extents = 127; err: - drbd_md_put_buffer(mdev); - out: + mutex_unlock(&mdev->md_io_mutex); put_ldev(mdev); return rv; @@ -4365,11 +4183,12 @@ const char *drbd_buildtag(void) static char buildtag[38] = "\0uilt-in"; if (buildtag[0] == 0) { -#ifdef MODULE - sprintf(buildtag, "srcversion: %-24s", THIS_MODULE->srcversion); -#else - buildtag[0] = 'b'; +#ifdef CONFIG_MODULES + if (THIS_MODULE != NULL) + sprintf(buildtag, "srcversion: %-24s", THIS_MODULE->srcversion); + else #endif + buildtag[0] = 'b'; } return buildtag; diff --git a/trunk/drivers/block/drbd/drbd_nl.c b/trunk/drivers/block/drbd/drbd_nl.c index 6d4de6a72e80..946166e13953 100644 --- a/trunk/drivers/block/drbd/drbd_nl.c +++ b/trunk/drivers/block/drbd/drbd_nl.c @@ -289,7 +289,7 @@ static int _try_outdate_peer_async(void *data) */ spin_lock_irq(&mdev->req_lock); ns = mdev->state; - if (ns.conn < C_WF_REPORT_PARAMS && !test_bit(STATE_SENT, &mdev->flags)) { + if (ns.conn < C_WF_REPORT_PARAMS) { ns.pdsk = nps; _drbd_set_state(mdev, ns, CS_VERBOSE, NULL); } @@ -432,7 +432,7 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) /* if this was forced, we should consider sync */ if (forced) drbd_send_uuids(mdev); - drbd_send_current_state(mdev); + drbd_send_state(mdev); } drbd_md_sync(mdev); @@ -845,10 +845,9 @@ void drbd_reconsider_max_bio_size(struct drbd_conf *mdev) Because new from 8.3.8 onwards the peer can use multiple BIOs for a single peer_request */ if (mdev->state.conn >= C_CONNECTED) { - if (mdev->agreed_pro_version < 94) { - peer = min_t(int, mdev->peer_max_bio_size, DRBD_MAX_SIZE_H80_PACKET); - /* Correct old drbd (up to 8.3.7) if it believes it can do more than 32KiB */ - } else if (mdev->agreed_pro_version == 94) + if (mdev->agreed_pro_version < 94) + peer = mdev->peer_max_bio_size; + else if (mdev->agreed_pro_version == 94) peer = DRBD_MAX_SIZE_H80_PACKET; else /* drbd 8.3.8 onwards */ peer = DRBD_MAX_BIO_SIZE; @@ -1033,7 +1032,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp dev_err(DEV, "max capacity %llu smaller than disk size %llu\n", (unsigned long long) drbd_get_max_capacity(nbc), (unsigned long long) nbc->dc.disk_size); - retcode = ERR_DISK_TOO_SMALL; + retcode = ERR_DISK_TO_SMALL; goto fail; } @@ -1047,7 +1046,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp } if (drbd_get_capacity(nbc->md_bdev) < min_md_device_sectors) { - retcode = ERR_MD_DISK_TOO_SMALL; + retcode = ERR_MD_DISK_TO_SMALL; dev_warn(DEV, "refusing attach: md-device too small, " "at least %llu sectors needed for this meta-disk type\n", (unsigned long long) min_md_device_sectors); @@ -1058,7 +1057,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp * (we may currently be R_PRIMARY with no local disk...) */ if (drbd_get_max_capacity(nbc) < drbd_get_capacity(mdev->this_bdev)) { - retcode = ERR_DISK_TOO_SMALL; + retcode = ERR_DISK_TO_SMALL; goto fail; } @@ -1139,7 +1138,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp if (drbd_md_test_flag(nbc, MDF_CONSISTENT) && drbd_new_dev_size(mdev, nbc, 0) < nbc->md.la_size_sect) { dev_warn(DEV, "refusing to truncate a consistent device\n"); - retcode = ERR_DISK_TOO_SMALL; + retcode = ERR_DISK_TO_SMALL; goto force_diskless_dec; } @@ -1337,34 +1336,17 @@ static int drbd_nl_detach(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, { enum drbd_ret_code retcode; int ret; - struct detach dt = {}; - - if (!detach_from_tags(mdev, nlp->tag_list, &dt)) { - reply->ret_code = ERR_MANDATORY_TAG; - goto out; - } - - if (dt.detach_force) { - drbd_force_state(mdev, NS(disk, D_FAILED)); - reply->ret_code = SS_SUCCESS; - goto out; - } - drbd_suspend_io(mdev); /* so no-one is stuck in drbd_al_begin_io */ - drbd_md_get_buffer(mdev); /* make sure there is no in-flight meta-data IO */ retcode = drbd_request_state(mdev, NS(disk, D_FAILED)); - drbd_md_put_buffer(mdev); /* D_FAILED will transition to DISKLESS. */ ret = wait_event_interruptible(mdev->misc_wait, mdev->state.disk != D_FAILED); drbd_resume_io(mdev); - if ((int)retcode == (int)SS_IS_DISKLESS) retcode = SS_NOTHING_TO_DO; if (ret) retcode = ERR_INTR; reply->ret_code = retcode; -out: return 0; } @@ -1729,7 +1711,7 @@ static int drbd_nl_resize(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, if (rs.no_resync && mdev->agreed_pro_version < 93) { retcode = ERR_NEED_APV_93; - goto fail_ldev; + goto fail; } if (mdev->ldev->known_size != drbd_get_capacity(mdev->ldev->backing_bdev)) @@ -1756,10 +1738,6 @@ static int drbd_nl_resize(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, fail: reply->ret_code = retcode; return 0; - - fail_ldev: - put_ldev(mdev); - goto fail; } static int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, @@ -1963,7 +1941,6 @@ static int drbd_nl_invalidate(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl /* If there is still bitmap IO pending, probably because of a previous * resync just being finished, wait for it before requesting a new resync. */ - drbd_suspend_io(mdev); wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags)); retcode = _drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_T), CS_ORDERED); @@ -1982,7 +1959,6 @@ static int drbd_nl_invalidate(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl retcode = drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_T)); } - drbd_resume_io(mdev); reply->ret_code = retcode; return 0; @@ -2004,7 +1980,6 @@ static int drbd_nl_invalidate_peer(struct drbd_conf *mdev, struct drbd_nl_cfg_re /* If there is still bitmap IO pending, probably because of a previous * resync just being finished, wait for it before requesting a new resync. */ - drbd_suspend_io(mdev); wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags)); retcode = _drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_S), CS_ORDERED); @@ -2023,7 +1998,6 @@ static int drbd_nl_invalidate_peer(struct drbd_conf *mdev, struct drbd_nl_cfg_re } else retcode = drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_S)); } - drbd_resume_io(mdev); reply->ret_code = retcode; return 0; @@ -2196,13 +2170,11 @@ static int drbd_nl_start_ov(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, /* If there is still bitmap IO pending, e.g. previous resync or verify * just being finished, wait for it before requesting a new resync. */ - drbd_suspend_io(mdev); wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags)); /* w_make_ov_request expects position to be aligned */ mdev->ov_start_sector = args.start_sector & ~BM_SECT_PER_BIT; reply->ret_code = drbd_request_state(mdev,NS(conn,C_VERIFY_S)); - drbd_resume_io(mdev); return 0; } diff --git a/trunk/drivers/block/drbd/drbd_proc.c b/trunk/drivers/block/drbd/drbd_proc.c index 869bada2ed06..2959cdfb77f5 100644 --- a/trunk/drivers/block/drbd/drbd_proc.c +++ b/trunk/drivers/block/drbd/drbd_proc.c @@ -52,7 +52,7 @@ void seq_printf_with_thousands_grouping(struct seq_file *seq, long v) if (unlikely(v >= 1000000)) { /* cool: > GiByte/s */ seq_printf(seq, "%ld,", v / 1000000); - v %= 1000000; + v /= 1000000; seq_printf(seq, "%03ld,%03ld", v/1000, v % 1000); } else if (likely(v >= 1000)) seq_printf(seq, "%ld,%03ld", v/1000, v % 1000); diff --git a/trunk/drivers/block/drbd/drbd_receiver.c b/trunk/drivers/block/drbd/drbd_receiver.c index ea4836e0ae98..436f519bed1c 100644 --- a/trunk/drivers/block/drbd/drbd_receiver.c +++ b/trunk/drivers/block/drbd/drbd_receiver.c @@ -466,7 +466,6 @@ static int drbd_accept(struct drbd_conf *mdev, const char **what, goto out; } (*newsock)->ops = sock->ops; - __module_get((*newsock)->ops->owner); out: return err; @@ -751,7 +750,6 @@ static int drbd_connect(struct drbd_conf *mdev) { struct socket *s, *sock, *msock; int try, h, ok; - enum drbd_state_rv rv; D_ASSERT(!mdev->data.socket); @@ -890,32 +888,25 @@ static int drbd_connect(struct drbd_conf *mdev) } } + if (drbd_request_state(mdev, NS(conn, C_WF_REPORT_PARAMS)) < SS_SUCCESS) + return 0; + sock->sk->sk_sndtimeo = mdev->net_conf->timeout*HZ/10; sock->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; atomic_set(&mdev->packet_seq, 0); mdev->peer_seq = 0; + drbd_thread_start(&mdev->asender); + if (drbd_send_protocol(mdev) == -1) return -1; - set_bit(STATE_SENT, &mdev->flags); drbd_send_sync_param(mdev, &mdev->sync_conf); drbd_send_sizes(mdev, 0, 0); drbd_send_uuids(mdev); - drbd_send_current_state(mdev); + drbd_send_state(mdev); clear_bit(USE_DEGR_WFC_T, &mdev->flags); clear_bit(RESIZE_PENDING, &mdev->flags); - - spin_lock_irq(&mdev->req_lock); - rv = _drbd_set_state(_NS(mdev, conn, C_WF_REPORT_PARAMS), CS_VERBOSE, NULL); - if (mdev->state.conn != C_WF_REPORT_PARAMS) - clear_bit(STATE_SENT, &mdev->flags); - spin_unlock_irq(&mdev->req_lock); - - if (rv < SS_SUCCESS) - return 0; - - drbd_thread_start(&mdev->asender); mod_timer(&mdev->request_timer, jiffies + HZ); /* just start it here. */ return 1; @@ -966,7 +957,7 @@ static void drbd_flush(struct drbd_conf *mdev) rv = blkdev_issue_flush(mdev->ldev->backing_bdev, GFP_KERNEL, NULL); if (rv) { - dev_info(DEV, "local disk flush failed with status %d\n", rv); + dev_err(DEV, "local disk flush failed with status %d\n", rv); /* would rather check on EOPNOTSUPP, but that is not reliable. * don't try again for ANY return value != 0 * if (rv == -EOPNOTSUPP) */ @@ -1010,14 +1001,13 @@ static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *mdev, if (epoch_size != 0 && atomic_read(&epoch->active) == 0 && - (test_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags) || ev & EV_CLEANUP)) { + test_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags)) { if (!(ev & EV_CLEANUP)) { spin_unlock(&mdev->epoch_lock); drbd_send_b_ack(mdev, epoch->barrier_nr, epoch_size); spin_lock(&mdev->epoch_lock); } - if (test_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags)) - dec_unacked(mdev); + dec_unacked(mdev); if (mdev->current_epoch != epoch) { next_epoch = list_entry(epoch->list.next, struct drbd_epoch, list); @@ -1106,11 +1096,7 @@ int drbd_submit_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, /* In most cases, we will only need one bio. But in case the lower * level restrictions happen to be different at this offset on this * side than those of the sending peer, we may need to submit the - * request in more than one bio. - * - * Plain bio_alloc is good enough here, this is no DRBD internally - * generated bio, but a bio allocated on behalf of the peer. - */ + * request in more than one bio. */ next_bio: bio = bio_alloc(GFP_NOIO, nr_pages); if (!bio) { @@ -1597,24 +1583,6 @@ static int e_send_discard_ack(struct drbd_conf *mdev, struct drbd_work *w, int u return ok; } -static bool overlapping_resync_write(struct drbd_conf *mdev, struct drbd_epoch_entry *data_e) -{ - - struct drbd_epoch_entry *rs_e; - bool rv = 0; - - spin_lock_irq(&mdev->req_lock); - list_for_each_entry(rs_e, &mdev->sync_ee, w.list) { - if (overlaps(data_e->sector, data_e->size, rs_e->sector, rs_e->size)) { - rv = 1; - break; - } - } - spin_unlock_irq(&mdev->req_lock); - - return rv; -} - /* Called from receive_Data. * Synchronize packets on sock with packets on msock. * @@ -1858,9 +1826,6 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned list_add(&e->w.list, &mdev->active_ee); spin_unlock_irq(&mdev->req_lock); - if (mdev->state.conn == C_SYNC_TARGET) - wait_event(mdev->ee_wait, !overlapping_resync_write(mdev, e)); - switch (mdev->net_conf->wire_protocol) { case DRBD_PROT_C: inc_unacked(mdev); @@ -2455,7 +2420,7 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l mdev->p_uuid[UI_BITMAP] = mdev->p_uuid[UI_HISTORY_START]; mdev->p_uuid[UI_HISTORY_START] = mdev->p_uuid[UI_HISTORY_START + 1]; - dev_info(DEV, "Lost last syncUUID packet, corrected:\n"); + dev_info(DEV, "Did not got last syncUUID packet, corrected:\n"); drbd_uuid_dump(mdev, "peer", mdev->p_uuid, mdev->p_uuid[UI_SIZE], mdev->p_uuid[UI_FLAGS]); return -1; @@ -2841,10 +2806,10 @@ static int receive_SyncParam(struct drbd_conf *mdev, enum drbd_packets cmd, unsi if (apv >= 88) { if (apv == 88) { - if (data_size > SHARED_SECRET_MAX || data_size == 0) { - dev_err(DEV, "verify-alg of wrong size, " - "peer wants %u, accepting only up to %u byte\n", - data_size, SHARED_SECRET_MAX); + if (data_size > SHARED_SECRET_MAX) { + dev_err(DEV, "verify-alg too long, " + "peer wants %u, accepting only %u byte\n", + data_size, SHARED_SECRET_MAX); return false; } @@ -3203,20 +3168,9 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned os = ns = mdev->state; spin_unlock_irq(&mdev->req_lock); - /* If some other part of the code (asender thread, timeout) - * already decided to close the connection again, - * we must not "re-establish" it here. */ - if (os.conn <= C_TEAR_DOWN) - return false; - - /* If this is the "end of sync" confirmation, usually the peer disk - * transitions from D_INCONSISTENT to D_UP_TO_DATE. For empty (0 bits - * set) resync started in PausedSyncT, or if the timing of pause-/ - * unpause-sync events has been "just right", the peer disk may - * transition from D_CONSISTENT to D_UP_TO_DATE as well. - */ - if ((os.pdsk == D_INCONSISTENT || os.pdsk == D_CONSISTENT) && - real_peer_disk == D_UP_TO_DATE && + /* peer says his disk is uptodate, while we think it is inconsistent, + * and this happens while we think we have a sync going on. */ + if (os.pdsk == D_INCONSISTENT && real_peer_disk == D_UP_TO_DATE && os.conn > C_CONNECTED && os.disk == D_UP_TO_DATE) { /* If we are (becoming) SyncSource, but peer is still in sync * preparation, ignore its uptodate-ness to avoid flapping, it @@ -3334,7 +3288,7 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned /* Nowadays only used when forcing a node into primary role and setting its disk to UpToDate with that */ drbd_send_uuids(mdev); - drbd_send_current_state(mdev); + drbd_send_state(mdev); } } @@ -3822,13 +3776,6 @@ static void drbd_disconnect(struct drbd_conf *mdev) if (mdev->state.conn == C_STANDALONE) return; - /* We are about to start the cleanup after connection loss. - * Make sure drbd_make_request knows about that. - * Usually we should be in some network failure state already, - * but just in case we are not, we fix it up here. - */ - drbd_force_state(mdev, NS(conn, C_NETWORK_FAILURE)); - /* asender does not clean up anything. it must not interfere, either */ drbd_thread_stop(&mdev->asender); drbd_free_sock(mdev); @@ -3856,6 +3803,8 @@ static void drbd_disconnect(struct drbd_conf *mdev) atomic_set(&mdev->rs_pending_cnt, 0); wake_up(&mdev->misc_wait); + del_timer(&mdev->request_timer); + /* make sure syncer is stopped and w_resume_next_sg queued */ del_timer_sync(&mdev->resync_timer); resync_timer_fn((unsigned long)mdev); @@ -4484,7 +4433,7 @@ static int got_BarrierAck(struct drbd_conf *mdev, struct p_header80 *h) if (mdev->state.conn == C_AHEAD && atomic_read(&mdev->ap_in_flight) == 0 && - !test_and_set_bit(AHEAD_TO_SYNC_SOURCE, &mdev->flags)) { + !test_and_set_bit(AHEAD_TO_SYNC_SOURCE, &mdev->current_epoch->flags)) { mdev->start_resync_timer.expires = jiffies + HZ; add_timer(&mdev->start_resync_timer); } diff --git a/trunk/drivers/block/drbd/drbd_req.c b/trunk/drivers/block/drbd/drbd_req.c index 9c5c84946b05..4a0f314086e5 100644 --- a/trunk/drivers/block/drbd/drbd_req.c +++ b/trunk/drivers/block/drbd/drbd_req.c @@ -37,7 +37,6 @@ static void _drbd_start_io_acct(struct drbd_conf *mdev, struct drbd_request *req const int rw = bio_data_dir(bio); int cpu; cpu = part_stat_lock(); - part_round_stats(cpu, &mdev->vdisk->part0); part_stat_inc(cpu, &mdev->vdisk->part0, ios[rw]); part_stat_add(cpu, &mdev->vdisk->part0, sectors[rw], bio_sectors(bio)); part_inc_in_flight(&mdev->vdisk->part0, rw); @@ -215,7 +214,8 @@ void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m) { const unsigned long s = req->rq_state; struct drbd_conf *mdev = req->mdev; - int rw = req->rq_state & RQ_WRITE ? WRITE : READ; + /* only WRITES may end up here without a master bio (on barrier ack) */ + int rw = req->master_bio ? bio_data_dir(req->master_bio) : WRITE; /* we must not complete the master bio, while it is * still being processed by _drbd_send_zc_bio (drbd_send_dblock) @@ -230,7 +230,7 @@ void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m) return; if (s & RQ_NET_PENDING) return; - if (s & RQ_LOCAL_PENDING && !(s & RQ_LOCAL_ABORTED)) + if (s & RQ_LOCAL_PENDING) return; if (req->master_bio) { @@ -277,9 +277,6 @@ void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m) req->master_bio = NULL; } - if (s & RQ_LOCAL_PENDING) - return; - if ((s & RQ_NET_MASK) == 0 || (s & RQ_NET_DONE)) { /* this is disconnected (local only) operation, * or protocol C P_WRITE_ACK, @@ -432,7 +429,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, break; case completed_ok: - if (req->rq_state & RQ_WRITE) + if (bio_data_dir(req->master_bio) == WRITE) mdev->writ_cnt += req->size>>9; else mdev->read_cnt += req->size>>9; @@ -441,14 +438,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, req->rq_state &= ~RQ_LOCAL_PENDING; _req_may_be_done_not_susp(req, m); - break; - - case abort_disk_io: - req->rq_state |= RQ_LOCAL_ABORTED; - if (req->rq_state & RQ_WRITE) - _req_may_be_done_not_susp(req, m); - else - goto goto_queue_for_net_read; + put_ldev(mdev); break; case write_completed_with_error: @@ -457,6 +447,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, __drbd_chk_io_error(mdev, false); _req_may_be_done_not_susp(req, m); + put_ldev(mdev); break; case read_ahead_completed_with_error: @@ -464,6 +455,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, req->rq_state |= RQ_LOCAL_COMPLETED; req->rq_state &= ~RQ_LOCAL_PENDING; _req_may_be_done_not_susp(req, m); + put_ldev(mdev); break; case read_completed_with_error: @@ -475,8 +467,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, D_ASSERT(!(req->rq_state & RQ_NET_MASK)); __drbd_chk_io_error(mdev, false); - - goto_queue_for_net_read: + put_ldev(mdev); /* no point in retrying if there is no good remote data, * or we have no connection. */ @@ -565,8 +556,10 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, drbd_queue_work(&mdev->data.work, &req->w); break; - case read_retry_remote_canceled: + case oos_handed_to_network: + /* actually the same */ case send_canceled: + /* treat it the same */ case send_failed: /* real cleanup will be done from tl_clear. just update flags * so it is no longer marked as on the worker queue */ @@ -596,17 +589,17 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, } req->rq_state &= ~RQ_NET_QUEUED; req->rq_state |= RQ_NET_SENT; + /* because _drbd_send_zc_bio could sleep, and may want to + * dereference the bio even after the "write_acked_by_peer" and + * "completed_ok" events came in, once we return from + * _drbd_send_zc_bio (drbd_send_dblock), we have to check + * whether it is done already, and end it. */ _req_may_be_done_not_susp(req, m); break; - case oos_handed_to_network: - /* Was not set PENDING, no longer QUEUED, so is now DONE - * as far as this connection is concerned. */ + case read_retry_remote_canceled: req->rq_state &= ~RQ_NET_QUEUED; - req->rq_state |= RQ_NET_DONE; - _req_may_be_done_not_susp(req, m); - break; - + /* fall through, in case we raced with drbd_disconnect */ case connection_lost_while_pending: /* transfer log cleanup after connection loss */ /* assert something? */ @@ -623,6 +616,8 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, _req_may_be_done(req, m); /* Allowed while state.susp */ break; + case write_acked_by_peer_and_sis: + req->rq_state |= RQ_NET_SIS; case conflict_discarded_by_peer: /* for discarded conflicting writes of multiple primaries, * there is no need to keep anything in the tl, potential @@ -633,15 +628,18 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, (unsigned long long)req->sector, req->size); req->rq_state |= RQ_NET_DONE; /* fall through */ - case write_acked_by_peer_and_sis: case write_acked_by_peer: - if (what == write_acked_by_peer_and_sis) - req->rq_state |= RQ_NET_SIS; /* protocol C; successfully written on peer. - * Nothing more to do here. + * Nothing to do here. * We want to keep the tl in place for all protocols, to cater - * for volatile write-back caches on lower level devices. */ + * for volatile write-back caches on lower level devices. + * + * A barrier request is expected to have forced all prior + * requests onto stable storage, so completion of a barrier + * request could set NET_DONE right here, and not wait for the + * P_BARRIER_ACK, but that is an unnecessary optimization. */ + /* this makes it effectively the same as for: */ case recv_acked_by_peer: /* protocol B; pretends to be successfully written on peer. * see also notes above in handed_over_to_network about @@ -775,7 +773,6 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, uns int local, remote, send_oos = 0; int err = -EIO; int ret = 0; - union drbd_state s; /* allocate outside of all locks; */ req = drbd_req_new(mdev, bio); @@ -837,9 +834,8 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, uns drbd_al_begin_io(mdev, sector); } - s = mdev->state; - remote = remote && drbd_should_do_remote(s); - send_oos = rw == WRITE && drbd_should_send_oos(s); + remote = remote && drbd_should_do_remote(mdev->state); + send_oos = rw == WRITE && drbd_should_send_oos(mdev->state); D_ASSERT(!(remote && send_oos)); if (!(local || remote) && !is_susp(mdev->state)) { @@ -871,7 +867,7 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, uns if (is_susp(mdev->state)) { /* If we got suspended, use the retry mechanism of - drbd_make_request() to restart processing of this + generic_make_request() to restart processing of this bio. In the next call to drbd_make_request we sleep in inc_ap_bio() */ ret = 1; @@ -1095,6 +1091,7 @@ void drbd_make_request(struct request_queue *q, struct bio *bio) */ D_ASSERT(bio->bi_size > 0); D_ASSERT((bio->bi_size & 0x1ff) == 0); + D_ASSERT(bio->bi_idx == 0); /* to make some things easier, force alignment of requests within the * granularity of our hash tables */ @@ -1102,9 +1099,8 @@ void drbd_make_request(struct request_queue *q, struct bio *bio) e_enr = (bio->bi_sector+(bio->bi_size>>9)-1) >> HT_SHIFT; if (likely(s_enr == e_enr)) { - do { - inc_ap_bio(mdev, 1); - } while (drbd_make_request_common(mdev, bio, start_time)); + inc_ap_bio(mdev, 1); + drbd_make_request_common(mdev, bio, start_time); return; } @@ -1200,66 +1196,36 @@ void request_timer_fn(unsigned long data) struct drbd_conf *mdev = (struct drbd_conf *) data; struct drbd_request *req; /* oldest request */ struct list_head *le; - unsigned long ent = 0, dt = 0, et, nt; /* effective timeout = ko_count * timeout */ - unsigned long now; + unsigned long et = 0; /* effective timeout = ko_count * timeout */ if (get_net_conf(mdev)) { - if (mdev->state.conn >= C_WF_REPORT_PARAMS) - ent = mdev->net_conf->timeout*HZ/10 - * mdev->net_conf->ko_count; + et = mdev->net_conf->timeout*HZ/10 * mdev->net_conf->ko_count; put_net_conf(mdev); } - if (get_ldev(mdev)) { /* implicit state.disk >= D_INCONSISTENT */ - dt = mdev->ldev->dc.disk_timeout * HZ / 10; - put_ldev(mdev); - } - et = min_not_zero(dt, ent); - - if (!et) + if (!et || mdev->state.conn < C_WF_REPORT_PARAMS) return; /* Recurring timer stopped */ - now = jiffies; - spin_lock_irq(&mdev->req_lock); le = &mdev->oldest_tle->requests; if (list_empty(le)) { spin_unlock_irq(&mdev->req_lock); - mod_timer(&mdev->request_timer, now + et); + mod_timer(&mdev->request_timer, jiffies + et); return; } le = le->prev; req = list_entry(le, struct drbd_request, tl_requests); - - /* The request is considered timed out, if - * - we have some effective timeout from the configuration, - * with above state restrictions applied, - * - the oldest request is waiting for a response from the network - * resp. the local disk, - * - the oldest request is in fact older than the effective timeout, - * - the connection was established (resp. disk was attached) - * for longer than the timeout already. - * Note that for 32bit jiffies and very stable connections/disks, - * we may have a wrap around, which is catched by - * !time_in_range(now, last_..._jif, last_..._jif + timeout). - * - * Side effect: once per 32bit wrap-around interval, which means every - * ~198 days with 250 HZ, we have a window where the timeout would need - * to expire twice (worst case) to become effective. Good enough. - */ - if (ent && req->rq_state & RQ_NET_PENDING && - time_after(now, req->start_time + ent) && - !time_in_range(now, mdev->last_reconnect_jif, mdev->last_reconnect_jif + ent)) { - dev_warn(DEV, "Remote failed to finish a request within ko-count * timeout\n"); - _drbd_set_state(_NS(mdev, conn, C_TIMEOUT), CS_VERBOSE | CS_HARD, NULL); - } - if (dt && req->rq_state & RQ_LOCAL_PENDING && - time_after(now, req->start_time + dt) && - !time_in_range(now, mdev->last_reattach_jif, mdev->last_reattach_jif + dt)) { - dev_warn(DEV, "Local backing device failed to meet the disk-timeout\n"); - __drbd_chk_io_error(mdev, 1); + if (time_is_before_eq_jiffies(req->start_time + et)) { + if (req->rq_state & RQ_NET_PENDING) { + dev_warn(DEV, "Remote failed to finish a request within ko-count * timeout\n"); + _drbd_set_state(_NS(mdev, conn, C_TIMEOUT), CS_VERBOSE, NULL); + } else { + dev_warn(DEV, "Local backing block device frozen?\n"); + mod_timer(&mdev->request_timer, jiffies + et); + } + } else { + mod_timer(&mdev->request_timer, req->start_time + et); } - nt = (time_after(now, req->start_time + et) ? now : req->start_time) + et; + spin_unlock_irq(&mdev->req_lock); - mod_timer(&mdev->request_timer, nt); } diff --git a/trunk/drivers/block/drbd/drbd_req.h b/trunk/drivers/block/drbd/drbd_req.h index 3d2111919486..68a234a5fdc5 100644 --- a/trunk/drivers/block/drbd/drbd_req.h +++ b/trunk/drivers/block/drbd/drbd_req.h @@ -105,7 +105,6 @@ enum drbd_req_event { read_completed_with_error, read_ahead_completed_with_error, write_completed_with_error, - abort_disk_io, completed_ok, resend, fail_frozen_disk_io, @@ -119,21 +118,18 @@ enum drbd_req_event { * same time, so we should hold the request lock anyways. */ enum drbd_req_state_bits { - /* 3210 - * 0000: no local possible - * 0001: to be submitted + /* 210 + * 000: no local possible + * 001: to be submitted * UNUSED, we could map: 011: submitted, completion still pending - * 0110: completed ok - * 0010: completed with error - * 1001: Aborted (before completion) - * 1x10: Aborted and completed -> free + * 110: completed ok + * 010: completed with error */ __RQ_LOCAL_PENDING, __RQ_LOCAL_COMPLETED, __RQ_LOCAL_OK, - __RQ_LOCAL_ABORTED, - /* 87654 + /* 76543 * 00000: no network possible * 00001: to be send * 00011: to be send, on worker queue @@ -203,9 +199,8 @@ enum drbd_req_state_bits { #define RQ_LOCAL_PENDING (1UL << __RQ_LOCAL_PENDING) #define RQ_LOCAL_COMPLETED (1UL << __RQ_LOCAL_COMPLETED) #define RQ_LOCAL_OK (1UL << __RQ_LOCAL_OK) -#define RQ_LOCAL_ABORTED (1UL << __RQ_LOCAL_ABORTED) -#define RQ_LOCAL_MASK ((RQ_LOCAL_ABORTED << 1)-1) +#define RQ_LOCAL_MASK ((RQ_LOCAL_OK << 1)-1) /* 0x07 */ #define RQ_NET_PENDING (1UL << __RQ_NET_PENDING) #define RQ_NET_QUEUED (1UL << __RQ_NET_QUEUED) diff --git a/trunk/drivers/block/drbd/drbd_worker.c b/trunk/drivers/block/drbd/drbd_worker.c index 620c70ff2231..4d3e6f6213ba 100644 --- a/trunk/drivers/block/drbd/drbd_worker.c +++ b/trunk/drivers/block/drbd/drbd_worker.c @@ -70,29 +70,11 @@ rwlock_t global_state_lock; void drbd_md_io_complete(struct bio *bio, int error) { struct drbd_md_io *md_io; - struct drbd_conf *mdev; md_io = (struct drbd_md_io *)bio->bi_private; - mdev = container_of(md_io, struct drbd_conf, md_io); - md_io->error = error; - /* We grabbed an extra reference in _drbd_md_sync_page_io() to be able - * to timeout on the lower level device, and eventually detach from it. - * If this io completion runs after that timeout expired, this - * drbd_md_put_buffer() may allow us to finally try and re-attach. - * During normal operation, this only puts that extra reference - * down to 1 again. - * Make sure we first drop the reference, and only then signal - * completion, or we may (in drbd_al_read_log()) cycle so fast into the - * next drbd_md_sync_page_io(), that we trigger the - * ASSERT(atomic_read(&mdev->md_io_in_use) == 1) there. - */ - drbd_md_put_buffer(mdev); - md_io->done = 1; - wake_up(&mdev->misc_wait); - bio_put(bio); - put_ldev(mdev); + complete(&md_io->event); } /* reads on behalf of the partner, @@ -244,7 +226,6 @@ void drbd_endio_pri(struct bio *bio, int error) spin_lock_irqsave(&mdev->req_lock, flags); __req_mod(req, what, &m); spin_unlock_irqrestore(&mdev->req_lock, flags); - put_ldev(mdev); if (m.bio) complete_master_bio(mdev, &m); @@ -309,7 +290,7 @@ void drbd_csum_bio(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio * sg_init_table(&sg, 1); crypto_hash_init(&desc); - bio_for_each_segment(bvec, bio, i) { + __bio_for_each_segment(bvec, bio, i, 0) { sg_set_page(&sg, bvec->bv_page, bvec->bv_len, bvec->bv_offset); crypto_hash_update(&desc, &sg, sg.length); } @@ -747,7 +728,7 @@ int w_start_resync(struct drbd_conf *mdev, struct drbd_work *w, int cancel) } drbd_start_resync(mdev, C_SYNC_SOURCE); - clear_bit(AHEAD_TO_SYNC_SOURCE, &mdev->flags); + clear_bit(AHEAD_TO_SYNC_SOURCE, &mdev->current_epoch->flags); return 1; } @@ -1538,14 +1519,14 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) } drbd_state_lock(mdev); - write_lock_irq(&global_state_lock); + if (!get_ldev_if_state(mdev, D_NEGOTIATING)) { - write_unlock_irq(&global_state_lock); drbd_state_unlock(mdev); return; } - ns.i = mdev->state.i; + write_lock_irq(&global_state_lock); + ns = mdev->state; ns.aftr_isp = !_drbd_may_sync_now(mdev); diff --git a/trunk/drivers/block/floppy.c b/trunk/drivers/block/floppy.c index cce7df367b79..b0b00d70c166 100644 --- a/trunk/drivers/block/floppy.c +++ b/trunk/drivers/block/floppy.c @@ -551,7 +551,7 @@ static void floppy_ready(void); static void floppy_start(void); static void process_fd_request(void); static void recalibrate_floppy(void); -static void floppy_shutdown(struct work_struct *); +static void floppy_shutdown(unsigned long); static int floppy_request_regions(int); static void floppy_release_regions(int); @@ -588,8 +588,6 @@ static int buffer_max = -1; static struct floppy_fdc_state fdc_state[N_FDC]; static int fdc; /* current fdc */ -static struct workqueue_struct *floppy_wq; - static struct floppy_struct *_floppy = floppy_type; static unsigned char current_drive; static long current_count_sectors; @@ -631,15 +629,16 @@ static inline void set_debugt(void) { } static inline void debugt(const char *func, const char *msg) { } #endif /* DEBUGT */ +typedef void (*timeout_fn)(unsigned long); +static DEFINE_TIMER(fd_timeout, floppy_shutdown, 0, 0); -static DECLARE_DELAYED_WORK(fd_timeout, floppy_shutdown); static const char *timeout_message; static void is_alive(const char *func, const char *message) { /* this routine checks whether the floppy driver is "alive" */ if (test_bit(0, &fdc_busy) && command_status < 2 && - !delayed_work_pending(&fd_timeout)) { + !timer_pending(&fd_timeout)) { DPRINT("%s: timeout handler died. %s\n", func, message); } } @@ -667,18 +666,15 @@ static int output_log_pos; static void __reschedule_timeout(int drive, const char *message) { - unsigned long delay; - if (drive == current_reqD) drive = current_drive; - + del_timer(&fd_timeout); if (drive < 0 || drive >= N_DRIVE) { - delay = 20UL * HZ; + fd_timeout.expires = jiffies + 20UL * HZ; drive = 0; } else - delay = UDP->timeout; - - queue_delayed_work(floppy_wq, &fd_timeout, delay); + fd_timeout.expires = jiffies + UDP->timeout; + add_timer(&fd_timeout); if (UDP->flags & FD_DEBUG) DPRINT("reschedule timeout %s\n", message); timeout_message = message; @@ -876,7 +872,7 @@ static int lock_fdc(int drive, bool interruptible) command_status = FD_COMMAND_NONE; - reschedule_timeout(drive, "lock fdc"); + __reschedule_timeout(drive, "lock fdc"); set_fdc(drive); return 0; } @@ -884,15 +880,23 @@ static int lock_fdc(int drive, bool interruptible) /* unlocks the driver */ static void unlock_fdc(void) { + unsigned long flags; + + raw_cmd = NULL; if (!test_bit(0, &fdc_busy)) DPRINT("FDC access conflict!\n"); - raw_cmd = NULL; + if (do_floppy) + DPRINT("device interrupt still active at FDC release: %pf!\n", + do_floppy); command_status = FD_COMMAND_NONE; - __cancel_delayed_work(&fd_timeout); - do_floppy = NULL; + spin_lock_irqsave(&floppy_lock, flags); + del_timer(&fd_timeout); cont = NULL; clear_bit(0, &fdc_busy); + if (current_req || set_next_request()) + do_fd_request(current_req->q); + spin_unlock_irqrestore(&floppy_lock, flags); wake_up(&fdc_wait); } @@ -964,24 +968,26 @@ static DECLARE_WORK(floppy_work, NULL); static void schedule_bh(void (*handler)(void)) { - WARN_ON(work_pending(&floppy_work)); - PREPARE_WORK(&floppy_work, (work_func_t)handler); - queue_work(floppy_wq, &floppy_work); + schedule_work(&floppy_work); } -static DECLARE_DELAYED_WORK(fd_timer, NULL); +static DEFINE_TIMER(fd_timer, NULL, 0, 0); static void cancel_activity(void) { + unsigned long flags; + + spin_lock_irqsave(&floppy_lock, flags); do_floppy = NULL; - cancel_delayed_work_sync(&fd_timer); - cancel_work_sync(&floppy_work); + PREPARE_WORK(&floppy_work, (work_func_t)empty); + del_timer(&fd_timer); + spin_unlock_irqrestore(&floppy_lock, flags); } /* this function makes sure that the disk stays in the drive during the * transfer */ -static void fd_watchdog(struct work_struct *arg) +static void fd_watchdog(void) { debug_dcl(DP->flags, "calling disk change from watchdog\n"); @@ -991,20 +997,21 @@ static void fd_watchdog(struct work_struct *arg) cont->done(0); reset_fdc(); } else { - cancel_delayed_work(&fd_timer); - PREPARE_DELAYED_WORK(&fd_timer, fd_watchdog); - queue_delayed_work(floppy_wq, &fd_timer, HZ / 10); + del_timer(&fd_timer); + fd_timer.function = (timeout_fn)fd_watchdog; + fd_timer.expires = jiffies + HZ / 10; + add_timer(&fd_timer); } } static void main_command_interrupt(void) { - cancel_delayed_work(&fd_timer); + del_timer(&fd_timer); cont->interrupt(); } /* waits for a delay (spinup or select) to pass */ -static int fd_wait_for_completion(unsigned long expires, work_func_t function) +static int fd_wait_for_completion(unsigned long delay, timeout_fn function) { if (FDCS->reset) { reset_fdc(); /* do the reset during sleep to win time @@ -1013,10 +1020,11 @@ static int fd_wait_for_completion(unsigned long expires, work_func_t function) return 1; } - if (time_before(jiffies, expires)) { - cancel_delayed_work(&fd_timer); - PREPARE_DELAYED_WORK(&fd_timer, function); - queue_delayed_work(floppy_wq, &fd_timer, expires - jiffies); + if (time_before(jiffies, delay)) { + del_timer(&fd_timer); + fd_timer.function = function; + fd_timer.expires = delay; + add_timer(&fd_timer); return 1; } return 0; @@ -1334,7 +1342,7 @@ static int fdc_dtr(void) */ FDCS->dtr = raw_cmd->rate & 3; return fd_wait_for_completion(jiffies + 2UL * HZ / 100, - (work_func_t)floppy_ready); + (timeout_fn)floppy_ready); } /* fdc_dtr */ static void tell_sector(void) @@ -1439,7 +1447,7 @@ static void setup_rw_floppy(void) int flags; int dflags; unsigned long ready_date; - work_func_t function; + timeout_fn function; flags = raw_cmd->flags; if (flags & (FD_RAW_READ | FD_RAW_WRITE)) @@ -1453,9 +1461,9 @@ static void setup_rw_floppy(void) */ if (time_after(ready_date, jiffies + DP->select_delay)) { ready_date -= DP->select_delay; - function = (work_func_t)floppy_start; + function = (timeout_fn)floppy_start; } else - function = (work_func_t)setup_rw_floppy; + function = (timeout_fn)setup_rw_floppy; /* wait until the floppy is spinning fast enough */ if (fd_wait_for_completion(ready_date, function)) @@ -1485,7 +1493,7 @@ static void setup_rw_floppy(void) inr = result(); cont->interrupt(); } else if (flags & FD_RAW_NEED_DISK) - fd_watchdog(NULL); + fd_watchdog(); } static int blind_seek; @@ -1794,22 +1802,20 @@ static void show_floppy(void) pr_info("do_floppy=%pf\n", do_floppy); if (work_pending(&floppy_work)) pr_info("floppy_work.func=%pf\n", floppy_work.func); - if (delayed_work_pending(&fd_timer)) - pr_info("delayed work.function=%p expires=%ld\n", - fd_timer.work.func, - fd_timer.timer.expires - jiffies); - if (delayed_work_pending(&fd_timeout)) - pr_info("timer_function=%p expires=%ld\n", - fd_timeout.work.func, - fd_timeout.timer.expires - jiffies); - + if (timer_pending(&fd_timer)) + pr_info("fd_timer.function=%pf\n", fd_timer.function); + if (timer_pending(&fd_timeout)) { + pr_info("timer_function=%pf\n", fd_timeout.function); + pr_info("expires=%lu\n", fd_timeout.expires - jiffies); + pr_info("now=%lu\n", jiffies); + } pr_info("cont=%p\n", cont); pr_info("current_req=%p\n", current_req); pr_info("command_status=%d\n", command_status); pr_info("\n"); } -static void floppy_shutdown(struct work_struct *arg) +static void floppy_shutdown(unsigned long data) { unsigned long flags; @@ -1862,7 +1868,7 @@ static int start_motor(void (*function)(void)) /* wait_for_completion also schedules reset if needed. */ return fd_wait_for_completion(DRS->select_date + DP->select_delay, - (work_func_t)function); + (timeout_fn)function); } static void floppy_ready(void) @@ -2815,6 +2821,7 @@ static void redo_fd_request(void) spin_lock_irq(&floppy_lock); pending = set_next_request(); spin_unlock_irq(&floppy_lock); + if (!pending) { do_floppy = NULL; unlock_fdc(); @@ -2891,15 +2898,13 @@ static void do_fd_request(struct request_queue *q) current_req->cmd_flags)) return; - if (test_and_set_bit(0, &fdc_busy)) { + if (test_bit(0, &fdc_busy)) { /* fdc busy, this new request will be treated when the current one is done */ is_alive(__func__, "old request running"); return; } - command_status = FD_COMMAND_NONE; - __reschedule_timeout(MAXTIMEOUT, "fd_request"); - set_fdc(0); + lock_fdc(MAXTIMEOUT, false); process_fd_request(); is_alive(__func__, ""); } @@ -3607,7 +3612,9 @@ static int floppy_release(struct gendisk *disk, fmode_t mode) mutex_lock(&floppy_mutex); mutex_lock(&open_lock); - if (!UDRS->fd_ref--) { + if (UDRS->fd_ref < 0) + UDRS->fd_ref = 0; + else if (!UDRS->fd_ref--) { DPRINT("floppy_release with fd_ref == 0"); UDRS->fd_ref = 0; } @@ -3643,7 +3650,13 @@ static int floppy_open(struct block_device *bdev, fmode_t mode) set_bit(FD_VERIFY_BIT, &UDRS->flags); } - UDRS->fd_ref++; + if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL))) + goto out2; + + if (mode & FMODE_EXCL) + UDRS->fd_ref = -1; + else + UDRS->fd_ref++; opened_bdev[drive] = bdev; @@ -3706,8 +3719,10 @@ static int floppy_open(struct block_device *bdev, fmode_t mode) mutex_unlock(&floppy_mutex); return 0; out: - UDRS->fd_ref--; - + if (UDRS->fd_ref < 0) + UDRS->fd_ref = 0; + else + UDRS->fd_ref--; if (!UDRS->fd_ref) opened_bdev[drive] = NULL; out2: @@ -4144,16 +4159,10 @@ static int __init floppy_init(void) goto out_put_disk; } - floppy_wq = alloc_ordered_workqueue("floppy", 0); - if (!floppy_wq) { - err = -ENOMEM; - goto out_put_disk; - } - disks[dr]->queue = blk_init_queue(do_fd_request, &floppy_lock); if (!disks[dr]->queue) { err = -ENOMEM; - goto out_destroy_workq; + goto out_put_disk; } blk_queue_max_hw_sectors(disks[dr]->queue, 64); @@ -4204,7 +4213,7 @@ static int __init floppy_init(void) use_virtual_dma = can_use_virtual_dma & 1; fdc_state[0].address = FDC1; if (fdc_state[0].address == -1) { - cancel_delayed_work(&fd_timeout); + del_timer_sync(&fd_timeout); err = -ENODEV; goto out_unreg_region; } @@ -4215,7 +4224,7 @@ static int __init floppy_init(void) fdc = 0; /* reset fdc in case of unexpected interrupt */ err = floppy_grab_irq_and_dma(); if (err) { - cancel_delayed_work(&fd_timeout); + del_timer_sync(&fd_timeout); err = -EBUSY; goto out_unreg_region; } @@ -4272,13 +4281,13 @@ static int __init floppy_init(void) user_reset_fdc(-1, FD_RESET_ALWAYS, false); } fdc = 0; - cancel_delayed_work(&fd_timeout); + del_timer_sync(&fd_timeout); current_drive = 0; initialized = true; if (have_no_fdc) { DPRINT("no floppy controllers found\n"); err = have_no_fdc; - goto out_release_dma; + goto out_flush_work; } for (drive = 0; drive < N_DRIVE; drive++) { @@ -4293,7 +4302,7 @@ static int __init floppy_init(void) err = platform_device_register(&floppy_device[drive]); if (err) - goto out_release_dma; + goto out_flush_work; err = device_create_file(&floppy_device[drive].dev, &dev_attr_cmos); @@ -4311,14 +4320,13 @@ static int __init floppy_init(void) out_unreg_platform_dev: platform_device_unregister(&floppy_device[drive]); -out_release_dma: +out_flush_work: + flush_work_sync(&floppy_work); if (atomic_read(&usage_count)) floppy_release_irq_and_dma(); out_unreg_region: blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256); platform_driver_unregister(&floppy_driver); -out_destroy_workq: - destroy_workqueue(floppy_wq); out_unreg_blkdev: unregister_blkdev(FLOPPY_MAJOR, "fd"); out_put_disk: @@ -4389,7 +4397,7 @@ static int floppy_grab_irq_and_dma(void) * We might have scheduled a free_irq(), wait it to * drain first: */ - flush_workqueue(floppy_wq); + flush_work_sync(&floppy_work); if (fd_request_irq()) { DPRINT("Unable to grab IRQ%d for the floppy driver\n", @@ -4480,9 +4488,9 @@ static void floppy_release_irq_and_dma(void) pr_info("motor off timer %d still active\n", drive); #endif - if (delayed_work_pending(&fd_timeout)) + if (timer_pending(&fd_timeout)) pr_info("floppy timer still active:%s\n", timeout_message); - if (delayed_work_pending(&fd_timer)) + if (timer_pending(&fd_timer)) pr_info("auxiliary floppy timer still active\n"); if (work_pending(&floppy_work)) pr_info("work still pending\n"); @@ -4552,9 +4560,8 @@ static void __exit floppy_module_exit(void) put_disk(disks[drive]); } - cancel_delayed_work_sync(&fd_timeout); - cancel_delayed_work_sync(&fd_timer); - destroy_workqueue(floppy_wq); + del_timer_sync(&fd_timeout); + del_timer_sync(&fd_timer); if (atomic_read(&usage_count)) floppy_release_irq_and_dma(); diff --git a/trunk/drivers/block/mtip32xx/mtip32xx.c b/trunk/drivers/block/mtip32xx/mtip32xx.c index 264bc77dcb91..304000c3d433 100644 --- a/trunk/drivers/block/mtip32xx/mtip32xx.c +++ b/trunk/drivers/block/mtip32xx/mtip32xx.c @@ -294,16 +294,18 @@ static int hba_reset_nosleep(struct driver_data *dd) */ static inline void mtip_issue_ncq_command(struct mtip_port *port, int tag) { + unsigned long flags = 0; + atomic_set(&port->commands[tag].active, 1); - spin_lock(&port->cmd_issue_lock); + spin_lock_irqsave(&port->cmd_issue_lock, flags); writel((1 << MTIP_TAG_BIT(tag)), port->s_active[MTIP_TAG_INDEX(tag)]); writel((1 << MTIP_TAG_BIT(tag)), port->cmd_issue[MTIP_TAG_INDEX(tag)]); - spin_unlock(&port->cmd_issue_lock); + spin_unlock_irqrestore(&port->cmd_issue_lock, flags); /* Set the command's timeout value.*/ port->commands[tag].comp_time = jiffies + msecs_to_jiffies( @@ -434,7 +436,8 @@ static void mtip_init_port(struct mtip_port *port) writel(0xFFFFFFFF, port->completed[i]); /* Clear any pending interrupts for this port */ - writel(readl(port->mmio + PORT_IRQ_STAT), port->mmio + PORT_IRQ_STAT); + writel(readl(port->dd->mmio + PORT_IRQ_STAT), + port->dd->mmio + PORT_IRQ_STAT); /* Clear any pending interrupts on the HBA. */ writel(readl(port->dd->mmio + HOST_IRQ_STAT), @@ -779,24 +782,13 @@ static void mtip_handle_tfe(struct driver_data *dd) /* Stop the timer to prevent command timeouts. */ del_timer(&port->cmd_timer); - set_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); - - if (test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags) && - test_bit(MTIP_TAG_INTERNAL, port->allocated)) { - cmd = &port->commands[MTIP_TAG_INTERNAL]; - dbg_printk(MTIP_DRV_NAME " TFE for the internal command\n"); - - atomic_inc(&cmd->active); /* active > 1 indicates error */ - if (cmd->comp_data && cmd->comp_func) { - cmd->comp_func(port, MTIP_TAG_INTERNAL, - cmd->comp_data, PORT_IRQ_TF_ERR); - } - goto handle_tfe_exit; - } /* clear the tag accumulator */ memset(tagaccum, 0, SLOTBITS_IN_LONGS * sizeof(long)); + /* Set eh_active */ + set_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); + /* Loop through all the groups */ for (group = 0; group < dd->slot_groups; group++) { completed = readl(port->completed[group]); @@ -948,7 +940,6 @@ static void mtip_handle_tfe(struct driver_data *dd) } print_tags(dd, "reissued (TFE)", tagaccum, cmd_cnt); -handle_tfe_exit: /* clear eh_active */ clear_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); wake_up_interruptible(&port->svc_wait); @@ -970,8 +961,6 @@ static inline void mtip_process_sdbf(struct driver_data *dd) /* walk all bits in all slot groups */ for (group = 0; group < dd->slot_groups; group++) { completed = readl(port->completed[group]); - if (!completed) - continue; /* clear completed status register in the hardware.*/ writel(completed, port->completed[group]); @@ -1340,6 +1329,22 @@ static int mtip_exec_internal_command(struct mtip_port *port, } rv = -EAGAIN; } + + if (readl(port->cmd_issue[MTIP_TAG_INTERNAL]) + & (1 << MTIP_TAG_INTERNAL)) { + dev_warn(&port->dd->pdev->dev, + "Retiring internal command but CI is 1.\n"); + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, + &port->dd->dd_flag)) { + hba_reset_nosleep(port->dd); + rv = -ENXIO; + } else { + mtip_restart_port(port); + rv = -EAGAIN; + } + goto exec_ic_exit; + } + } else { /* Spin for checking if command still outstanding */ timeout = jiffies + msecs_to_jiffies(timeout); @@ -1356,25 +1361,21 @@ static int mtip_exec_internal_command(struct mtip_port *port, rv = -ENXIO; goto exec_ic_exit; } - if (readl(port->mmio + PORT_IRQ_STAT) & PORT_IRQ_ERR) { - atomic_inc(&int_cmd->active); /* error */ - break; - } } - } - if (atomic_read(&int_cmd->active) > 1) { - dev_err(&port->dd->pdev->dev, - "Internal command [%02X] failed\n", fis->command); - rv = -EIO; - } - if (readl(port->cmd_issue[MTIP_TAG_INTERNAL]) + if (readl(port->cmd_issue[MTIP_TAG_INTERNAL]) & (1 << MTIP_TAG_INTERNAL)) { - rv = -ENXIO; - if (!test_bit(MTIP_DDF_REMOVE_PENDING_BIT, - &port->dd->dd_flag)) { - mtip_restart_port(port); + dev_err(&port->dd->pdev->dev, + "Internal command did not complete [atomic]\n"); rv = -EAGAIN; + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, + &port->dd->dd_flag)) { + hba_reset_nosleep(port->dd); + rv = -ENXIO; + } else { + mtip_restart_port(port); + rv = -EAGAIN; + } } } exec_ic_exit: @@ -1892,33 +1893,13 @@ static int exec_drive_command(struct mtip_port *port, u8 *command, void __user *user_buffer) { struct host_to_dev_fis fis; - struct host_to_dev_fis *reply; - u8 *buf = NULL; - dma_addr_t dma_addr = 0; - int rv = 0, xfer_sz = command[3]; - - if (xfer_sz) { - if (user_buffer) - return -EFAULT; - - buf = dmam_alloc_coherent(&port->dd->pdev->dev, - ATA_SECT_SIZE * xfer_sz, - &dma_addr, - GFP_KERNEL); - if (!buf) { - dev_err(&port->dd->pdev->dev, - "Memory allocation failed (%d bytes)\n", - ATA_SECT_SIZE * xfer_sz); - return -ENOMEM; - } - memset(buf, 0, ATA_SECT_SIZE * xfer_sz); - } + struct host_to_dev_fis *reply = (port->rxfis + RX_FIS_D2H_REG); /* Build the FIS. */ memset(&fis, 0, sizeof(struct host_to_dev_fis)); - fis.type = 0x27; - fis.opts = 1 << 7; - fis.command = command[0]; + fis.type = 0x27; + fis.opts = 1 << 7; + fis.command = command[0]; fis.features = command[2]; fis.sect_count = command[3]; if (fis.command == ATA_CMD_SMART) { @@ -1927,11 +1908,6 @@ static int exec_drive_command(struct mtip_port *port, u8 *command, fis.cyl_hi = 0xC2; } - if (xfer_sz) - reply = (port->rxfis + RX_FIS_PIO_SETUP); - else - reply = (port->rxfis + RX_FIS_D2H_REG); - dbg_printk(MTIP_DRV_NAME " %s: User Command: cmd %x, sect %x, " "feat %x, sectcnt %x\n", @@ -1941,46 +1917,43 @@ static int exec_drive_command(struct mtip_port *port, u8 *command, command[2], command[3]); + memset(port->sector_buffer, 0x00, ATA_SECT_SIZE); + /* Execute the command. */ if (mtip_exec_internal_command(port, &fis, 5, - (xfer_sz ? dma_addr : 0), - (xfer_sz ? ATA_SECT_SIZE * xfer_sz : 0), + port->sector_buffer_dma, + (command[3] != 0) ? ATA_SECT_SIZE : 0, 0, GFP_KERNEL, MTIP_IOCTL_COMMAND_TIMEOUT_MS) < 0) { - rv = -EFAULT; - goto exit_drive_command; + return -1; } /* Collect the completion status. */ command[0] = reply->command; /* Status*/ command[1] = reply->features; /* Error*/ - command[2] = reply->sect_count; + command[2] = command[3]; dbg_printk(MTIP_DRV_NAME " %s: Completion Status: stat %x, " - "err %x, nsect %x\n", + "err %x, cmd %x\n", __func__, command[0], command[1], command[2]); - if (xfer_sz) { + if (user_buffer && command[3]) { if (copy_to_user(user_buffer, - buf, + port->sector_buffer, ATA_SECT_SIZE * command[3])) { - rv = -EFAULT; - goto exit_drive_command; + return -EFAULT; } } -exit_drive_command: - if (buf) - dmam_free_coherent(&port->dd->pdev->dev, - ATA_SECT_SIZE * xfer_sz, buf, dma_addr); - return rv; + + return 0; } /* @@ -2030,32 +2003,6 @@ static unsigned int implicit_sector(unsigned char command, return rv; } -static void mtip_set_timeout(struct host_to_dev_fis *fis, unsigned int *timeout) -{ - switch (fis->command) { - case ATA_CMD_DOWNLOAD_MICRO: - *timeout = 120000; /* 2 minutes */ - break; - case ATA_CMD_SEC_ERASE_UNIT: - case 0xFC: - *timeout = 240000; /* 4 minutes */ - break; - case ATA_CMD_STANDBYNOW1: - *timeout = 10000; /* 10 seconds */ - break; - case 0xF7: - case 0xFA: - *timeout = 60000; /* 60 seconds */ - break; - case ATA_CMD_SMART: - *timeout = 15000; /* 15 seconds */ - break; - default: - *timeout = MTIP_IOCTL_COMMAND_TIMEOUT_MS; - break; - } -} - /* * Executes a taskfile * See ide_taskfile_ioctl() for derivation @@ -2076,7 +2023,7 @@ static int exec_drive_taskfile(struct driver_data *dd, unsigned int taskin = 0; unsigned int taskout = 0; u8 nsect = 0; - unsigned int timeout; + unsigned int timeout = MTIP_IOCTL_COMMAND_TIMEOUT_MS; unsigned int force_single_sector; unsigned int transfer_size; unsigned long task_file_data; @@ -2206,7 +2153,32 @@ static int exec_drive_taskfile(struct driver_data *dd, fis.lba_hi, fis.device); - mtip_set_timeout(&fis, &timeout); + switch (fis.command) { + case ATA_CMD_DOWNLOAD_MICRO: + /* Change timeout for Download Microcode to 2 minutes */ + timeout = 120000; + break; + case ATA_CMD_SEC_ERASE_UNIT: + /* Change timeout for Security Erase Unit to 4 minutes.*/ + timeout = 240000; + break; + case ATA_CMD_STANDBYNOW1: + /* Change timeout for standby immediate to 10 seconds.*/ + timeout = 10000; + break; + case 0xF7: + case 0xFA: + /* Change timeout for vendor unique command to 10 secs */ + timeout = 10000; + break; + case ATA_CMD_SMART: + /* Change timeout for vendor unique command to 15 secs */ + timeout = 15000; + break; + default: + timeout = MTIP_IOCTL_COMMAND_TIMEOUT_MS; + break; + } /* Determine the correct transfer size.*/ if (force_single_sector) @@ -2323,12 +2295,13 @@ static int mtip_hw_ioctl(struct driver_data *dd, unsigned int cmd, { switch (cmd) { case HDIO_GET_IDENTITY: - { - if (copy_to_user((void __user *)arg, dd->port->identify, - sizeof(u16) * ATA_ID_WORDS)) - return -EFAULT; + if (mtip_get_identify(dd->port, (void __user *) arg) < 0) { + dev_warn(&dd->pdev->dev, + "Unable to read identity\n"); + return -EIO; + } + break; - } case HDIO_DRIVE_CMD: { u8 drive_command[4]; @@ -2564,58 +2537,40 @@ static ssize_t mtip_hw_show_registers(struct device *dev, int size = 0; int n; - size += sprintf(&buf[size], "Hardware\n--------\n"); - size += sprintf(&buf[size], "S ACTive : [ 0x"); + size += sprintf(&buf[size], "S ACTive:\n"); - for (n = dd->slot_groups-1; n >= 0; n--) - size += sprintf(&buf[size], "%08X ", + for (n = 0; n < dd->slot_groups; n++) + size += sprintf(&buf[size], "0x%08x\n", readl(dd->port->s_active[n])); - size += sprintf(&buf[size], "]\n"); - size += sprintf(&buf[size], "Command Issue : [ 0x"); + size += sprintf(&buf[size], "Command Issue:\n"); - for (n = dd->slot_groups-1; n >= 0; n--) - size += sprintf(&buf[size], "%08X ", + for (n = 0; n < dd->slot_groups; n++) + size += sprintf(&buf[size], "0x%08x\n", readl(dd->port->cmd_issue[n])); - size += sprintf(&buf[size], "]\n"); - size += sprintf(&buf[size], "Completed : [ 0x"); - - for (n = dd->slot_groups-1; n >= 0; n--) - size += sprintf(&buf[size], "%08X ", - readl(dd->port->completed[n])); - - size += sprintf(&buf[size], "]\n"); - size += sprintf(&buf[size], "PORT IRQ STAT : [ 0x%08X ]\n", - readl(dd->port->mmio + PORT_IRQ_STAT)); - size += sprintf(&buf[size], "HOST IRQ STAT : [ 0x%08X ]\n", - readl(dd->mmio + HOST_IRQ_STAT)); - size += sprintf(&buf[size], "\n"); + size += sprintf(&buf[size], "Allocated:\n"); - size += sprintf(&buf[size], "Local\n-----\n"); - size += sprintf(&buf[size], "Allocated : [ 0x"); - - for (n = dd->slot_groups-1; n >= 0; n--) { + for (n = 0; n < dd->slot_groups; n++) { if (sizeof(long) > sizeof(u32)) group_allocated = dd->port->allocated[n/2] >> (32*(n&1)); else group_allocated = dd->port->allocated[n]; - size += sprintf(&buf[size], "%08X ", group_allocated); + size += sprintf(&buf[size], "0x%08x\n", + group_allocated); } - size += sprintf(&buf[size], "]\n"); - size += sprintf(&buf[size], "Commands in Q: [ 0x"); + size += sprintf(&buf[size], "Completed:\n"); - for (n = dd->slot_groups-1; n >= 0; n--) { - if (sizeof(long) > sizeof(u32)) - group_allocated = - dd->port->cmds_to_issue[n/2] >> (32*(n&1)); - else - group_allocated = dd->port->cmds_to_issue[n]; - size += sprintf(&buf[size], "%08X ", group_allocated); - } - size += sprintf(&buf[size], "]\n"); + for (n = 0; n < dd->slot_groups; n++) + size += sprintf(&buf[size], "0x%08x\n", + readl(dd->port->completed[n])); + + size += sprintf(&buf[size], "PORT IRQ STAT : 0x%08x\n", + readl(dd->port->mmio + PORT_IRQ_STAT)); + size += sprintf(&buf[size], "HOST IRQ STAT : 0x%08x\n", + readl(dd->mmio + HOST_IRQ_STAT)); return size; } @@ -2637,24 +2592,8 @@ static ssize_t mtip_hw_show_status(struct device *dev, return size; } -static ssize_t mtip_hw_show_flags(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct driver_data *dd = dev_to_disk(dev)->private_data; - int size = 0; - - size += sprintf(&buf[size], "Flag in port struct : [ %08lX ]\n", - dd->port->flags); - size += sprintf(&buf[size], "Flag in dd struct : [ %08lX ]\n", - dd->dd_flag); - - return size; -} - static DEVICE_ATTR(registers, S_IRUGO, mtip_hw_show_registers, NULL); static DEVICE_ATTR(status, S_IRUGO, mtip_hw_show_status, NULL); -static DEVICE_ATTR(flags, S_IRUGO, mtip_hw_show_flags, NULL); /* * Create the sysfs related attributes. @@ -2677,9 +2616,6 @@ static int mtip_hw_sysfs_init(struct driver_data *dd, struct kobject *kobj) if (sysfs_create_file(kobj, &dev_attr_status.attr)) dev_warn(&dd->pdev->dev, "Error creating 'status' sysfs entry\n"); - if (sysfs_create_file(kobj, &dev_attr_flags.attr)) - dev_warn(&dd->pdev->dev, - "Error creating 'flags' sysfs entry\n"); return 0; } @@ -2700,7 +2636,6 @@ static int mtip_hw_sysfs_exit(struct driver_data *dd, struct kobject *kobj) sysfs_remove_file(kobj, &dev_attr_registers.attr); sysfs_remove_file(kobj, &dev_attr_status.attr); - sysfs_remove_file(kobj, &dev_attr_flags.attr); return 0; } @@ -3699,10 +3634,7 @@ static int mtip_block_initialize(struct driver_data *dd) set_bit(QUEUE_FLAG_NONROT, &dd->queue->queue_flags); blk_queue_max_segments(dd->queue, MTIP_MAX_SG); blk_queue_physical_block_size(dd->queue, 4096); - blk_queue_max_hw_sectors(dd->queue, 0xffff); - blk_queue_max_segment_size(dd->queue, 0x400000); blk_queue_io_min(dd->queue, 4096); - /* * write back cache is not supported in the device. FUA depends on * write back cache support, hence setting flush support to zero. diff --git a/trunk/drivers/block/mtip32xx/mtip32xx.h b/trunk/drivers/block/mtip32xx/mtip32xx.h index b2c88da26b2a..4ef58336310a 100644 --- a/trunk/drivers/block/mtip32xx/mtip32xx.h +++ b/trunk/drivers/block/mtip32xx/mtip32xx.h @@ -113,35 +113,33 @@ #define __force_bit2int (unsigned int __force) -enum { - /* below are bit numbers in 'flags' defined in mtip_port */ - MTIP_PF_IC_ACTIVE_BIT = 0, /* pio/ioctl */ - MTIP_PF_EH_ACTIVE_BIT = 1, /* error handling */ - MTIP_PF_SE_ACTIVE_BIT = 2, /* secure erase */ - MTIP_PF_DM_ACTIVE_BIT = 3, /* download microcde */ - MTIP_PF_PAUSE_IO = ((1 << MTIP_PF_IC_ACTIVE_BIT) | \ +/* below are bit numbers in 'flags' defined in mtip_port */ +#define MTIP_PF_IC_ACTIVE_BIT 0 /* pio/ioctl */ +#define MTIP_PF_EH_ACTIVE_BIT 1 /* error handling */ +#define MTIP_PF_SE_ACTIVE_BIT 2 /* secure erase */ +#define MTIP_PF_DM_ACTIVE_BIT 3 /* download microcde */ +#define MTIP_PF_PAUSE_IO ((1 << MTIP_PF_IC_ACTIVE_BIT) | \ (1 << MTIP_PF_EH_ACTIVE_BIT) | \ (1 << MTIP_PF_SE_ACTIVE_BIT) | \ - (1 << MTIP_PF_DM_ACTIVE_BIT)), - - MTIP_PF_SVC_THD_ACTIVE_BIT = 4, - MTIP_PF_ISSUE_CMDS_BIT = 5, - MTIP_PF_REBUILD_BIT = 6, - MTIP_PF_SVC_THD_STOP_BIT = 8, - - /* below are bit numbers in 'dd_flag' defined in driver_data */ - MTIP_DDF_REMOVE_PENDING_BIT = 1, - MTIP_DDF_OVER_TEMP_BIT = 2, - MTIP_DDF_WRITE_PROTECT_BIT = 3, - MTIP_DDF_STOP_IO = ((1 << MTIP_DDF_REMOVE_PENDING_BIT) | \ + (1 << MTIP_PF_DM_ACTIVE_BIT)) + +#define MTIP_PF_SVC_THD_ACTIVE_BIT 4 +#define MTIP_PF_ISSUE_CMDS_BIT 5 +#define MTIP_PF_REBUILD_BIT 6 +#define MTIP_PF_SVC_THD_STOP_BIT 8 + +/* below are bit numbers in 'dd_flag' defined in driver_data */ +#define MTIP_DDF_REMOVE_PENDING_BIT 1 +#define MTIP_DDF_OVER_TEMP_BIT 2 +#define MTIP_DDF_WRITE_PROTECT_BIT 3 +#define MTIP_DDF_STOP_IO ((1 << MTIP_DDF_REMOVE_PENDING_BIT) | \ (1 << MTIP_DDF_OVER_TEMP_BIT) | \ - (1 << MTIP_DDF_WRITE_PROTECT_BIT)), + (1 << MTIP_DDF_WRITE_PROTECT_BIT)) - MTIP_DDF_CLEANUP_BIT = 5, - MTIP_DDF_RESUME_BIT = 6, - MTIP_DDF_INIT_DONE_BIT = 7, - MTIP_DDF_REBUILD_FAILED_BIT = 8, -}; +#define MTIP_DDF_CLEANUP_BIT 5 +#define MTIP_DDF_RESUME_BIT 6 +#define MTIP_DDF_INIT_DONE_BIT 7 +#define MTIP_DDF_REBUILD_FAILED_BIT 8 __packed struct smart_attr{ u8 attr_id; diff --git a/trunk/drivers/block/rbd.c b/trunk/drivers/block/rbd.c index 65665c9c42c6..013c7a549fb6 100644 --- a/trunk/drivers/block/rbd.c +++ b/trunk/drivers/block/rbd.c @@ -141,7 +141,7 @@ struct rbd_request { struct rbd_snap { struct device dev; const char *name; - u64 size; + size_t size; struct list_head node; u64 id; }; @@ -175,7 +175,8 @@ struct rbd_device { /* protects updating the header */ struct rw_semaphore header_rwsem; char snap_name[RBD_MAX_SNAP_NAME_LEN]; - u64 snap_id; /* current snapshot id */ + u32 cur_snap; /* index+1 of current snapshot within snap context + 0 - for the head */ int read_only; struct list_head node; @@ -240,7 +241,7 @@ static void rbd_put_dev(struct rbd_device *rbd_dev) put_device(&rbd_dev->dev); } -static int __rbd_refresh_header(struct rbd_device *rbd_dev); +static int __rbd_update_snaps(struct rbd_device *rbd_dev); static int rbd_open(struct block_device *bdev, fmode_t mode) { @@ -449,9 +450,7 @@ static void rbd_client_release(struct kref *kref) struct rbd_client *rbdc = container_of(kref, struct rbd_client, kref); dout("rbd_release_client %p\n", rbdc); - spin_lock(&rbd_client_list_lock); list_del(&rbdc->node); - spin_unlock(&rbd_client_list_lock); ceph_destroy_client(rbdc->client); kfree(rbdc->rbd_opts); @@ -464,7 +463,9 @@ static void rbd_client_release(struct kref *kref) */ static void rbd_put_client(struct rbd_device *rbd_dev) { + spin_lock(&rbd_client_list_lock); kref_put(&rbd_dev->rbd_client->kref, rbd_client_release); + spin_unlock(&rbd_client_list_lock); rbd_dev->rbd_client = NULL; } @@ -486,18 +487,16 @@ static void rbd_coll_release(struct kref *kref) */ static int rbd_header_from_disk(struct rbd_image_header *header, struct rbd_image_header_ondisk *ondisk, - u32 allocated_snaps, + int allocated_snaps, gfp_t gfp_flags) { - u32 i, snap_count; + int i; + u32 snap_count; if (memcmp(ondisk, RBD_HEADER_TEXT, sizeof(RBD_HEADER_TEXT))) return -ENXIO; snap_count = le32_to_cpu(ondisk->snap_count); - if (snap_count > (UINT_MAX - sizeof(struct ceph_snap_context)) - / sizeof (*ondisk)) - return -EINVAL; header->snapc = kmalloc(sizeof(struct ceph_snap_context) + snap_count * sizeof (*ondisk), gfp_flags); @@ -507,11 +506,11 @@ static int rbd_header_from_disk(struct rbd_image_header *header, header->snap_names_len = le64_to_cpu(ondisk->snap_names_len); if (snap_count) { header->snap_names = kmalloc(header->snap_names_len, - gfp_flags); + GFP_KERNEL); if (!header->snap_names) goto err_snapc; header->snap_sizes = kmalloc(snap_count * sizeof(u64), - gfp_flags); + GFP_KERNEL); if (!header->snap_sizes) goto err_names; } else { @@ -553,6 +552,21 @@ static int rbd_header_from_disk(struct rbd_image_header *header, return -ENOMEM; } +static int snap_index(struct rbd_image_header *header, int snap_num) +{ + return header->total_snaps - snap_num; +} + +static u64 cur_snap_id(struct rbd_device *rbd_dev) +{ + struct rbd_image_header *header = &rbd_dev->header; + + if (!rbd_dev->cur_snap) + return 0; + + return header->snapc->snaps[snap_index(header, rbd_dev->cur_snap)]; +} + static int snap_by_name(struct rbd_image_header *header, const char *snap_name, u64 *seq, u64 *size) { @@ -591,7 +605,7 @@ static int rbd_header_set_snap(struct rbd_device *dev, u64 *size) snapc->seq = header->snap_seq; else snapc->seq = 0; - dev->snap_id = CEPH_NOSNAP; + dev->cur_snap = 0; dev->read_only = 0; if (size) *size = header->image_size; @@ -599,7 +613,8 @@ static int rbd_header_set_snap(struct rbd_device *dev, u64 *size) ret = snap_by_name(header, dev->snap_name, &snapc->seq, size); if (ret < 0) goto done; - dev->snap_id = snapc->seq; + + dev->cur_snap = header->total_snaps - ret; dev->read_only = 1; } @@ -920,6 +935,7 @@ static int rbd_do_request(struct request *rq, layout->fl_stripe_unit = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER); layout->fl_stripe_count = cpu_to_le32(1); layout->fl_object_size = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER); + layout->fl_pg_preferred = cpu_to_le32(-1); layout->fl_pg_pool = cpu_to_le32(dev->poolid); ceph_calc_raw_layout(osdc, layout, snapid, ofs, &len, &bno, req, ops); @@ -1152,7 +1168,7 @@ static int rbd_req_read(struct request *rq, int coll_index) { return rbd_do_op(rq, rbd_dev, NULL, - snapid, + (snapid ? snapid : CEPH_NOSNAP), CEPH_OSD_OP_READ, CEPH_OSD_FLAG_READ, 2, @@ -1171,7 +1187,7 @@ static int rbd_req_sync_read(struct rbd_device *dev, u64 *ver) { return rbd_req_sync_op(dev, NULL, - snapid, + (snapid ? snapid : CEPH_NOSNAP), CEPH_OSD_OP_READ, CEPH_OSD_FLAG_READ, NULL, @@ -1222,7 +1238,7 @@ static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data) dout("rbd_watch_cb %s notify_id=%lld opcode=%d\n", dev->obj_md_name, notify_id, (int)opcode); mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); - rc = __rbd_refresh_header(dev); + rc = __rbd_update_snaps(dev); mutex_unlock(&ctl_mutex); if (rc) pr_warning(RBD_DRV_NAME "%d got notification but failed to " @@ -1505,7 +1521,7 @@ static void rbd_rq_fn(struct request_queue *q) coll, cur_seg); else rbd_req_read(rq, rbd_dev, - rbd_dev->snap_id, + cur_snap_id(rbd_dev), ofs, op_size, bio, coll, cur_seg); @@ -1576,7 +1592,7 @@ static int rbd_read_header(struct rbd_device *rbd_dev, { ssize_t rc; struct rbd_image_header_ondisk *dh; - u32 snap_count = 0; + int snap_count = 0; u64 ver; size_t len; @@ -1640,7 +1656,7 @@ static int rbd_header_add_snap(struct rbd_device *dev, struct ceph_mon_client *monc; /* we should create a snapshot only if we're pointing at the head */ - if (dev->snap_id != CEPH_NOSNAP) + if (dev->cur_snap) return -EINVAL; monc = &dev->rbd_client->client->monc; @@ -1667,9 +1683,7 @@ static int rbd_header_add_snap(struct rbd_device *dev, if (ret < 0) return ret; - down_write(&dev->header_rwsem); - dev->header.snapc->seq = new_snapid; - up_write(&dev->header_rwsem); + dev->header.snapc->seq = new_snapid; return 0; bad: @@ -1689,7 +1703,7 @@ static void __rbd_remove_all_snaps(struct rbd_device *rbd_dev) /* * only read the first part of the ondisk header, without the snaps info */ -static int __rbd_refresh_header(struct rbd_device *rbd_dev) +static int __rbd_update_snaps(struct rbd_device *rbd_dev) { int ret; struct rbd_image_header h; @@ -1876,7 +1890,7 @@ static ssize_t rbd_image_refresh(struct device *dev, mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); - rc = __rbd_refresh_header(rbd_dev); + rc = __rbd_update_snaps(rbd_dev); if (rc < 0) ret = rc; @@ -1935,7 +1949,7 @@ static ssize_t rbd_snap_size_show(struct device *dev, { struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev); - return sprintf(buf, "%llu\n", (unsigned long long)snap->size); + return sprintf(buf, "%zd\n", snap->size); } static ssize_t rbd_snap_id_show(struct device *dev, @@ -1944,7 +1958,7 @@ static ssize_t rbd_snap_id_show(struct device *dev, { struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev); - return sprintf(buf, "%llu\n", (unsigned long long)snap->id); + return sprintf(buf, "%llu\n", (unsigned long long) snap->id); } static DEVICE_ATTR(snap_size, S_IRUGO, rbd_snap_size_show, NULL); @@ -2159,7 +2173,7 @@ static int rbd_init_watch_dev(struct rbd_device *rbd_dev) rbd_dev->header.obj_version); if (ret == -ERANGE) { mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); - rc = __rbd_refresh_header(rbd_dev); + rc = __rbd_update_snaps(rbd_dev); mutex_unlock(&ctl_mutex); if (rc < 0) return rc; @@ -2544,7 +2558,7 @@ static ssize_t rbd_snap_add(struct device *dev, if (ret < 0) goto err_unlock; - ret = __rbd_refresh_header(rbd_dev); + ret = __rbd_update_snaps(rbd_dev); if (ret < 0) goto err_unlock; diff --git a/trunk/drivers/block/xen-blkfront.c b/trunk/drivers/block/xen-blkfront.c index 60eed4bdd2e4..4e86393a09cf 100644 --- a/trunk/drivers/block/xen-blkfront.c +++ b/trunk/drivers/block/xen-blkfront.c @@ -526,14 +526,6 @@ static int xen_translate_vdev(int vdevice, int *minor, unsigned int *offset) return 0; } -static char *encode_disk_name(char *ptr, unsigned int n) -{ - if (n >= 26) - ptr = encode_disk_name(ptr, n / 26 - 1); - *ptr = 'a' + n % 26; - return ptr + 1; -} - static int xlvbd_alloc_gendisk(blkif_sector_t capacity, struct blkfront_info *info, u16 vdisk_info, u16 sector_size) @@ -544,7 +536,6 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity, unsigned int offset; int minor; int nr_parts; - char *ptr; BUG_ON(info->gd != NULL); BUG_ON(info->rq != NULL); @@ -569,11 +560,7 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity, "emulated IDE disks,\n\t choose an xvd device name" "from xvde on\n", info->vdevice); } - if (minor >> MINORBITS) { - pr_warn("blkfront: %#x's minor (%#x) out of range; ignoring\n", - info->vdevice, minor); - return -ENODEV; - } + err = -ENODEV; if ((minor % nr_parts) == 0) nr_minors = nr_parts; @@ -587,14 +574,23 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity, if (gd == NULL) goto release; - strcpy(gd->disk_name, DEV_NAME); - ptr = encode_disk_name(gd->disk_name + sizeof(DEV_NAME) - 1, offset); - BUG_ON(ptr >= gd->disk_name + DISK_NAME_LEN); - if (nr_minors > 1) - *ptr = 0; - else - snprintf(ptr, gd->disk_name + DISK_NAME_LEN - ptr, - "%d", minor & (nr_parts - 1)); + if (nr_minors > 1) { + if (offset < 26) + sprintf(gd->disk_name, "%s%c", DEV_NAME, 'a' + offset); + else + sprintf(gd->disk_name, "%s%c%c", DEV_NAME, + 'a' + ((offset / 26)-1), 'a' + (offset % 26)); + } else { + if (offset < 26) + sprintf(gd->disk_name, "%s%c%d", DEV_NAME, + 'a' + offset, + minor & (nr_parts - 1)); + else + sprintf(gd->disk_name, "%s%c%c%d", DEV_NAME, + 'a' + ((offset / 26) - 1), + 'a' + (offset % 26), + minor & (nr_parts - 1)); + } gd->major = XENVBD_MAJOR; gd->first_minor = minor; @@ -1500,9 +1496,7 @@ module_init(xlblk_init); static void __exit xlblk_exit(void) { - xenbus_unregister_driver(&blkfront_driver); - unregister_blkdev(XENVBD_MAJOR, DEV_NAME); - kfree(minors); + return xenbus_unregister_driver(&blkfront_driver); } module_exit(xlblk_exit); diff --git a/trunk/drivers/edac/amd64_edac.c b/trunk/drivers/edac/amd64_edac.c index 7be9b7288e90..7ef73c919c5d 100644 --- a/trunk/drivers/edac/amd64_edac.c +++ b/trunk/drivers/edac/amd64_edac.c @@ -715,6 +715,25 @@ static inline u64 input_addr_to_sys_addr(struct mem_ctl_info *mci, input_addr_to_dram_addr(mci, input_addr)); } +/* + * Find the minimum and maximum InputAddr values that map to the given @csrow. + * Pass back these values in *input_addr_min and *input_addr_max. + */ +static void find_csrow_limits(struct mem_ctl_info *mci, int csrow, + u64 *input_addr_min, u64 *input_addr_max) +{ + struct amd64_pvt *pvt; + u64 base, mask; + + pvt = mci->pvt_info; + BUG_ON((csrow < 0) || (csrow >= pvt->csels[0].b_cnt)); + + get_cs_base_and_mask(pvt, csrow, 0, &base, &mask); + + *input_addr_min = base & ~mask; + *input_addr_max = base | mask; +} + /* Map the Error address to a PAGE and PAGE OFFSET. */ static inline void error_address_to_page_and_offset(u64 error_address, u32 *page, u32 *offset) @@ -1039,37 +1058,6 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr, int channel, csrow; u32 page, offset; - error_address_to_page_and_offset(sys_addr, &page, &offset); - - /* - * Find out which node the error address belongs to. This may be - * different from the node that detected the error. - */ - src_mci = find_mc_by_sys_addr(mci, sys_addr); - if (!src_mci) { - amd64_mc_err(mci, "failed to map error addr 0x%lx to a node\n", - (unsigned long)sys_addr); - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - page, offset, syndrome, - -1, -1, -1, - EDAC_MOD_STR, - "failed to map error addr to a node", - NULL); - return; - } - - /* Now map the sys_addr to a CSROW */ - csrow = sys_addr_to_csrow(src_mci, sys_addr); - if (csrow < 0) { - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - page, offset, syndrome, - -1, -1, -1, - EDAC_MOD_STR, - "failed to map error addr to a csrow", - NULL); - return; - } - /* CHIPKILL enabled */ if (pvt->nbcfg & NBCFG_CHIPKILL) { channel = get_channel_from_ecc_syndrome(mci, syndrome); @@ -1079,15 +1067,9 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr, * 2 DIMMs is in error. So we need to ID 'both' of them * as suspect. */ - amd64_mc_warn(src_mci, "unknown syndrome 0x%04x - " - "possible error reporting race\n", - syndrome); - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - page, offset, syndrome, - csrow, -1, -1, - EDAC_MOD_STR, - "unknown syndrome - possible error reporting race", - NULL); + amd64_mc_warn(mci, "unknown syndrome 0x%04x - possible " + "error reporting race\n", syndrome); + edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR); return; } } else { @@ -1102,10 +1084,28 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr, channel = ((sys_addr & BIT(3)) != 0); } - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, src_mci, - page, offset, syndrome, - csrow, channel, -1, - EDAC_MOD_STR, "", NULL); + /* + * Find out which node the error address belongs to. This may be + * different from the node that detected the error. + */ + src_mci = find_mc_by_sys_addr(mci, sys_addr); + if (!src_mci) { + amd64_mc_err(mci, "failed to map error addr 0x%lx to a node\n", + (unsigned long)sys_addr); + edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR); + return; + } + + /* Now map the sys_addr to a CSROW */ + csrow = sys_addr_to_csrow(src_mci, sys_addr); + if (csrow < 0) { + edac_mc_handle_ce_no_info(src_mci, EDAC_MOD_STR); + } else { + error_address_to_page_and_offset(sys_addr, &page, &offset); + + edac_mc_handle_ce(src_mci, page, offset, syndrome, csrow, + channel, EDAC_MOD_STR); + } } static int ddr2_cs_size(unsigned i, bool dct_width) @@ -1611,20 +1611,15 @@ static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr, u32 page, offset; int nid, csrow, chan = 0; - error_address_to_page_and_offset(sys_addr, &page, &offset); - csrow = f1x_translate_sysaddr_to_cs(pvt, sys_addr, &nid, &chan); if (csrow < 0) { - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - page, offset, syndrome, - -1, -1, -1, - EDAC_MOD_STR, - "failed to map error addr to a csrow", - NULL); + edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR); return; } + error_address_to_page_and_offset(sys_addr, &page, &offset); + /* * We need the syndromes for channel detection only when we're * ganged. Otherwise @chan should already contain the channel at @@ -1633,10 +1628,16 @@ static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr, if (dct_ganging_enabled(pvt)) chan = get_channel_from_ecc_syndrome(mci, syndrome); - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - page, offset, syndrome, - csrow, chan, -1, - EDAC_MOD_STR, "", NULL); + if (chan >= 0) + edac_mc_handle_ce(mci, page, offset, syndrome, csrow, chan, + EDAC_MOD_STR); + else + /* + * Channel unknown, report all channels on this CSROW as failed. + */ + for (chan = 0; chan < mci->csrows[csrow].nr_channels; chan++) + edac_mc_handle_ce(mci, page, offset, syndrome, + csrow, chan, EDAC_MOD_STR); } /* @@ -1917,12 +1918,7 @@ static void amd64_handle_ce(struct mem_ctl_info *mci, struct mce *m) /* Ensure that the Error Address is VALID */ if (!(m->status & MCI_STATUS_ADDRV)) { amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n"); - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - 0, 0, 0, - -1, -1, -1, - EDAC_MOD_STR, - "HW has no ERROR_ADDRESS available", - NULL); + edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR); return; } @@ -1946,17 +1942,11 @@ static void amd64_handle_ue(struct mem_ctl_info *mci, struct mce *m) if (!(m->status & MCI_STATUS_ADDRV)) { amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n"); - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - 0, 0, 0, - -1, -1, -1, - EDAC_MOD_STR, - "HW has no ERROR_ADDRESS available", - NULL); + edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR); return; } sys_addr = get_error_address(m); - error_address_to_page_and_offset(sys_addr, &page, &offset); /* * Find out which node the error address belongs to. This may be @@ -1966,11 +1956,7 @@ static void amd64_handle_ue(struct mem_ctl_info *mci, struct mce *m) if (!src_mci) { amd64_mc_err(mci, "ERROR ADDRESS (0x%lx) NOT mapped to a MC\n", (unsigned long)sys_addr); - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - page, offset, 0, - -1, -1, -1, - EDAC_MOD_STR, - "ERROR ADDRESS NOT mapped to a MC", NULL); + edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR); return; } @@ -1980,17 +1966,10 @@ static void amd64_handle_ue(struct mem_ctl_info *mci, struct mce *m) if (csrow < 0) { amd64_mc_err(mci, "ERROR_ADDRESS (0x%lx) NOT mapped to CS\n", (unsigned long)sys_addr); - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - page, offset, 0, - -1, -1, -1, - EDAC_MOD_STR, - "ERROR ADDRESS NOT mapped to CS", - NULL); + edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR); } else { - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - page, offset, 0, - csrow, -1, -1, - EDAC_MOD_STR, "", NULL); + error_address_to_page_and_offset(sys_addr, &page, &offset); + edac_mc_handle_ue(log_mci, page, offset, csrow, EDAC_MOD_STR); } } @@ -2192,7 +2171,7 @@ static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr) nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode) << (20 - PAGE_SHIFT); debugf0(" (csrow=%d) DBAM map index= %d\n", csrow_nr, cs_mode); - debugf0(" nr_pages/channel= %u channel-count = %d\n", + debugf0(" nr_pages= %u channel-count = %d\n", nr_pages, pvt->channel_count); return nr_pages; @@ -2206,12 +2185,9 @@ static int init_csrows(struct mem_ctl_info *mci) { struct csrow_info *csrow; struct amd64_pvt *pvt = mci->pvt_info; - u64 base, mask; + u64 input_addr_min, input_addr_max, sys_addr, base, mask; u32 val; - int i, j, empty = 1; - enum mem_type mtype; - enum edac_type edac_mode; - int nr_pages = 0; + int i, empty = 1; amd64_read_pci_cfg(pvt->F3, NBCFG, &val); @@ -2235,32 +2211,41 @@ static int init_csrows(struct mem_ctl_info *mci) empty = 0; if (csrow_enabled(i, 0, pvt)) - nr_pages = amd64_csrow_nr_pages(pvt, 0, i); + csrow->nr_pages = amd64_csrow_nr_pages(pvt, 0, i); if (csrow_enabled(i, 1, pvt)) - nr_pages += amd64_csrow_nr_pages(pvt, 1, i); + csrow->nr_pages += amd64_csrow_nr_pages(pvt, 1, i); + find_csrow_limits(mci, i, &input_addr_min, &input_addr_max); + sys_addr = input_addr_to_sys_addr(mci, input_addr_min); + csrow->first_page = (u32) (sys_addr >> PAGE_SHIFT); + sys_addr = input_addr_to_sys_addr(mci, input_addr_max); + csrow->last_page = (u32) (sys_addr >> PAGE_SHIFT); get_cs_base_and_mask(pvt, i, 0, &base, &mask); + csrow->page_mask = ~mask; /* 8 bytes of resolution */ - mtype = amd64_determine_memory_type(pvt, i); + csrow->mtype = amd64_determine_memory_type(pvt, i); debugf1(" for MC node %d csrow %d:\n", pvt->mc_node_id, i); - debugf1(" nr_pages: %u\n", nr_pages * pvt->channel_count); + debugf1(" input_addr_min: 0x%lx input_addr_max: 0x%lx\n", + (unsigned long)input_addr_min, + (unsigned long)input_addr_max); + debugf1(" sys_addr: 0x%lx page_mask: 0x%lx\n", + (unsigned long)sys_addr, csrow->page_mask); + debugf1(" nr_pages: %u first_page: 0x%lx " + "last_page: 0x%lx\n", + (unsigned)csrow->nr_pages, + csrow->first_page, csrow->last_page); /* * determine whether CHIPKILL or JUST ECC or NO ECC is operating */ if (pvt->nbcfg & NBCFG_ECC_ENABLE) - edac_mode = (pvt->nbcfg & NBCFG_CHIPKILL) ? - EDAC_S4ECD4ED : EDAC_SECDED; + csrow->edac_mode = + (pvt->nbcfg & NBCFG_CHIPKILL) ? + EDAC_S4ECD4ED : EDAC_SECDED; else - edac_mode = EDAC_NONE; - - for (j = 0; j < pvt->channel_count; j++) { - csrow->channels[j].dimm->mtype = mtype; - csrow->channels[j].dimm->edac_mode = edac_mode; - csrow->channels[j].dimm->nr_pages = nr_pages; - } + csrow->edac_mode = EDAC_NONE; } return empty; @@ -2555,7 +2540,6 @@ static int amd64_init_one_instance(struct pci_dev *F2) struct amd64_pvt *pvt = NULL; struct amd64_family_type *fam_type = NULL; struct mem_ctl_info *mci = NULL; - struct edac_mc_layer layers[2]; int err = 0, ret; u8 nid = get_node_id(F2); @@ -2590,13 +2574,7 @@ static int amd64_init_one_instance(struct pci_dev *F2) goto err_siblings; ret = -ENOMEM; - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = pvt->csels[0].b_cnt; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = pvt->channel_count; - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(nid, ARRAY_SIZE(layers), layers, 0); + mci = edac_mc_alloc(0, pvt->csels[0].b_cnt, pvt->channel_count, nid); if (!mci) goto err_siblings; diff --git a/trunk/drivers/edac/amd76x_edac.c b/trunk/drivers/edac/amd76x_edac.c index 9774d443fa57..f8fd3c807bde 100644 --- a/trunk/drivers/edac/amd76x_edac.c +++ b/trunk/drivers/edac/amd76x_edac.c @@ -29,6 +29,7 @@ edac_mc_chipset_printk(mci, level, "amd76x", fmt, ##arg) #define AMD76X_NR_CSROWS 8 +#define AMD76X_NR_CHANS 1 #define AMD76X_NR_DIMMS 4 /* AMD 76x register addresses - device 0 function 0 - PCI bridge */ @@ -145,10 +146,8 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci, if (handle_errors) { row = (info->ecc_mode_status >> 4) & 0xf; - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - mci->csrows[row].first_page, 0, 0, - row, 0, -1, - mci->ctl_name, "", NULL); + edac_mc_handle_ue(mci, mci->csrows[row].first_page, 0, + row, mci->ctl_name); } } @@ -160,10 +159,8 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci, if (handle_errors) { row = info->ecc_mode_status & 0xf; - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - mci->csrows[row].first_page, 0, 0, - row, 0, -1, - mci->ctl_name, "", NULL); + edac_mc_handle_ce(mci, mci->csrows[row].first_page, 0, + 0, row, 0, mci->ctl_name); } } @@ -189,13 +186,11 @@ static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, enum edac_type edac_mode) { struct csrow_info *csrow; - struct dimm_info *dimm; u32 mba, mba_base, mba_mask, dms; int index; for (index = 0; index < mci->nr_csrows; index++) { csrow = &mci->csrows[index]; - dimm = csrow->channels[0].dimm; /* find the DRAM Chip Select Base address and mask */ pci_read_config_dword(pdev, @@ -208,13 +203,13 @@ static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, mba_mask = ((mba & 0xff80) << 16) | 0x7fffffUL; pci_read_config_dword(pdev, AMD76X_DRAM_MODE_STATUS, &dms); csrow->first_page = mba_base >> PAGE_SHIFT; - dimm->nr_pages = (mba_mask + 1) >> PAGE_SHIFT; - csrow->last_page = csrow->first_page + dimm->nr_pages - 1; + csrow->nr_pages = (mba_mask + 1) >> PAGE_SHIFT; + csrow->last_page = csrow->first_page + csrow->nr_pages - 1; csrow->page_mask = mba_mask >> PAGE_SHIFT; - dimm->grain = dimm->nr_pages << PAGE_SHIFT; - dimm->mtype = MEM_RDDR; - dimm->dtype = ((dms >> index) & 0x1) ? DEV_X4 : DEV_UNKNOWN; - dimm->edac_mode = edac_mode; + csrow->grain = csrow->nr_pages << PAGE_SHIFT; + csrow->mtype = MEM_RDDR; + csrow->dtype = ((dms >> index) & 0x1) ? DEV_X4 : DEV_UNKNOWN; + csrow->edac_mode = edac_mode; } } @@ -235,8 +230,7 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx) EDAC_SECDED, EDAC_SECDED }; - struct mem_ctl_info *mci; - struct edac_mc_layer layers[2]; + struct mem_ctl_info *mci = NULL; u32 ems; u32 ems_mode; struct amd76x_error_info discard; @@ -244,17 +238,11 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx) debugf0("%s()\n", __func__); pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS, &ems); ems_mode = (ems >> 10) & 0x3; + mci = edac_mc_alloc(0, AMD76X_NR_CSROWS, AMD76X_NR_CHANS, 0); - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = AMD76X_NR_CSROWS; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = 1; - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0); - - if (mci == NULL) + if (mci == NULL) { return -ENOMEM; + } debugf0("%s(): mci = %p\n", __func__, mci); mci->dev = &pdev->dev; diff --git a/trunk/drivers/edac/cell_edac.c b/trunk/drivers/edac/cell_edac.c index 69ee6aab5c71..9a6a274e6925 100644 --- a/trunk/drivers/edac/cell_edac.c +++ b/trunk/drivers/edac/cell_edac.c @@ -48,9 +48,8 @@ static void cell_edac_count_ce(struct mem_ctl_info *mci, int chan, u64 ar) syndrome = (ar & 0x000000001fe00000ul) >> 21; /* TODO: Decoding of the error address */ - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - csrow->first_page + pfn, offset, syndrome, - 0, chan, -1, "", "", NULL); + edac_mc_handle_ce(mci, csrow->first_page + pfn, offset, + syndrome, 0, chan, ""); } static void cell_edac_count_ue(struct mem_ctl_info *mci, int chan, u64 ar) @@ -70,9 +69,7 @@ static void cell_edac_count_ue(struct mem_ctl_info *mci, int chan, u64 ar) offset = address & ~PAGE_MASK; /* TODO: Decoding of the error address */ - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - csrow->first_page + pfn, offset, 0, - 0, chan, -1, "", "", NULL); + edac_mc_handle_ue(mci, csrow->first_page + pfn, offset, 0, ""); } static void cell_edac_check(struct mem_ctl_info *mci) @@ -127,11 +124,8 @@ static void cell_edac_check(struct mem_ctl_info *mci) static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci) { struct csrow_info *csrow = &mci->csrows[0]; - struct dimm_info *dimm; struct cell_edac_priv *priv = mci->pvt_info; struct device_node *np; - int j; - u32 nr_pages; for (np = NULL; (np = of_find_node_by_name(np, "memory")) != NULL;) { @@ -146,20 +140,15 @@ static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci) if (of_node_to_nid(np) != priv->node) continue; csrow->first_page = r.start >> PAGE_SHIFT; - nr_pages = resource_size(&r) >> PAGE_SHIFT; - csrow->last_page = csrow->first_page + nr_pages - 1; - - for (j = 0; j < csrow->nr_channels; j++) { - dimm = csrow->channels[j].dimm; - dimm->mtype = MEM_XDR; - dimm->edac_mode = EDAC_SECDED; - dimm->nr_pages = nr_pages / csrow->nr_channels; - } + csrow->nr_pages = resource_size(&r) >> PAGE_SHIFT; + csrow->last_page = csrow->first_page + csrow->nr_pages - 1; + csrow->mtype = MEM_XDR; + csrow->edac_mode = EDAC_SECDED; dev_dbg(mci->dev, "Initialized on node %d, chanmask=0x%x," " first_page=0x%lx, nr_pages=0x%x\n", priv->node, priv->chanmask, - csrow->first_page, nr_pages); + csrow->first_page, csrow->nr_pages); break; } } @@ -168,10 +157,9 @@ static int __devinit cell_edac_probe(struct platform_device *pdev) { struct cbe_mic_tm_regs __iomem *regs; struct mem_ctl_info *mci; - struct edac_mc_layer layers[2]; struct cell_edac_priv *priv; u64 reg; - int rc, chanmask, num_chans; + int rc, chanmask; regs = cbe_get_cpu_mic_tm_regs(cbe_node_to_cpu(pdev->id)); if (regs == NULL) @@ -196,16 +184,8 @@ static int __devinit cell_edac_probe(struct platform_device *pdev) in_be64(®s->mic_fir)); /* Allocate & init EDAC MC data structure */ - num_chans = chanmask == 3 ? 2 : 1; - - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = 1; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = num_chans; - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(pdev->id, ARRAY_SIZE(layers), layers, - sizeof(struct cell_edac_priv)); + mci = edac_mc_alloc(sizeof(struct cell_edac_priv), 1, + chanmask == 3 ? 2 : 1, pdev->id); if (mci == NULL) return -ENOMEM; priv = mci->pvt_info; diff --git a/trunk/drivers/edac/cpc925_edac.c b/trunk/drivers/edac/cpc925_edac.c index e22030a9de66..a774c0ddaf5b 100644 --- a/trunk/drivers/edac/cpc925_edac.c +++ b/trunk/drivers/edac/cpc925_edac.c @@ -329,10 +329,9 @@ static void cpc925_init_csrows(struct mem_ctl_info *mci) { struct cpc925_mc_pdata *pdata = mci->pvt_info; struct csrow_info *csrow; - struct dimm_info *dimm; - int index, j; + int index; u32 mbmr, mbbar, bba; - unsigned long row_size, nr_pages, last_nr_pages = 0; + unsigned long row_size, last_nr_pages = 0; get_total_mem(pdata); @@ -351,41 +350,36 @@ static void cpc925_init_csrows(struct mem_ctl_info *mci) row_size = bba * (1UL << 28); /* 256M */ csrow->first_page = last_nr_pages; - nr_pages = row_size >> PAGE_SHIFT; - csrow->last_page = csrow->first_page + nr_pages - 1; + csrow->nr_pages = row_size >> PAGE_SHIFT; + csrow->last_page = csrow->first_page + csrow->nr_pages - 1; last_nr_pages = csrow->last_page + 1; - for (j = 0; j < csrow->nr_channels; j++) { - dimm = csrow->channels[j].dimm; - - dimm->nr_pages = nr_pages / csrow->nr_channels; - dimm->mtype = MEM_RDDR; - dimm->edac_mode = EDAC_SECDED; - - switch (csrow->nr_channels) { - case 1: /* Single channel */ - dimm->grain = 32; /* four-beat burst of 32 bytes */ - break; - case 2: /* Dual channel */ - default: - dimm->grain = 64; /* four-beat burst of 64 bytes */ - break; - } - - switch ((mbmr & MBMR_MODE_MASK) >> MBMR_MODE_SHIFT) { - case 6: /* 0110, no way to differentiate X8 VS X16 */ - case 5: /* 0101 */ - case 8: /* 1000 */ - dimm->dtype = DEV_X16; - break; - case 7: /* 0111 */ - case 9: /* 1001 */ - dimm->dtype = DEV_X8; - break; - default: - dimm->dtype = DEV_UNKNOWN; - break; - } + csrow->mtype = MEM_RDDR; + csrow->edac_mode = EDAC_SECDED; + + switch (csrow->nr_channels) { + case 1: /* Single channel */ + csrow->grain = 32; /* four-beat burst of 32 bytes */ + break; + case 2: /* Dual channel */ + default: + csrow->grain = 64; /* four-beat burst of 64 bytes */ + break; + } + + switch ((mbmr & MBMR_MODE_MASK) >> MBMR_MODE_SHIFT) { + case 6: /* 0110, no way to differentiate X8 VS X16 */ + case 5: /* 0101 */ + case 8: /* 1000 */ + csrow->dtype = DEV_X16; + break; + case 7: /* 0111 */ + case 9: /* 1001 */ + csrow->dtype = DEV_X8; + break; + default: + csrow->dtype = DEV_UNKNOWN; + break; } } } @@ -555,18 +549,13 @@ static void cpc925_mc_check(struct mem_ctl_info *mci) if (apiexcp & CECC_EXCP_DETECTED) { cpc925_mc_printk(mci, KERN_INFO, "DRAM CECC Fault\n"); channel = cpc925_mc_find_channel(mci, syndrome); - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - pfn, offset, syndrome, - csrow, channel, -1, - mci->ctl_name, "", NULL); + edac_mc_handle_ce(mci, pfn, offset, syndrome, + csrow, channel, mci->ctl_name); } if (apiexcp & UECC_EXCP_DETECTED) { cpc925_mc_printk(mci, KERN_INFO, "DRAM UECC Fault\n"); - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - pfn, offset, 0, - csrow, -1, -1, - mci->ctl_name, "", NULL); + edac_mc_handle_ue(mci, pfn, offset, csrow, mci->ctl_name); } cpc925_mc_printk(mci, KERN_INFO, "Dump registers:\n"); @@ -938,7 +927,6 @@ static int __devinit cpc925_probe(struct platform_device *pdev) { static int edac_mc_idx; struct mem_ctl_info *mci; - struct edac_mc_layer layers[2]; void __iomem *vbase; struct cpc925_mc_pdata *pdata; struct resource *r; @@ -974,16 +962,9 @@ static int __devinit cpc925_probe(struct platform_device *pdev) goto err2; } - nr_channels = cpc925_mc_get_channels(vbase) + 1; - - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = CPC925_NR_CSROWS; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = nr_channels; - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), layers, - sizeof(struct cpc925_mc_pdata)); + nr_channels = cpc925_mc_get_channels(vbase); + mci = edac_mc_alloc(sizeof(struct cpc925_mc_pdata), + CPC925_NR_CSROWS, nr_channels + 1, edac_mc_idx); if (!mci) { cpc925_printk(KERN_ERR, "No memory for mem_ctl_info\n"); res = -ENOMEM; diff --git a/trunk/drivers/edac/e752x_edac.c b/trunk/drivers/edac/e752x_edac.c index 3186512c9739..41223261ede9 100644 --- a/trunk/drivers/edac/e752x_edac.c +++ b/trunk/drivers/edac/e752x_edac.c @@ -4,11 +4,7 @@ * This file may be distributed under the terms of the * GNU General Public License. * - * Implement support for the e7520, E7525, e7320 and i3100 memory controllers. - * - * Datasheets: - * http://www.intel.in/content/www/in/en/chipsets/e7525-memory-controller-hub-datasheet.html - * ftp://download.intel.com/design/intarch/datashts/31345803.pdf + * See "enum e752x_chips" below for supported chipsets * * Written by Tom Zimmerman * @@ -17,6 +13,8 @@ * Wang Zhenyu at intel.com * Dave Jiang at mvista.com * + * $Id: edac_e752x.c,v 1.5.2.11 2005/10/05 00:43:44 dsp_llnl Exp $ + * */ #include @@ -189,25 +187,6 @@ enum e752x_chips { I3100 = 3 }; -/* - * Those chips Support single-rank and dual-rank memories only. - * - * On e752x chips, the odd rows are present only on dual-rank memories. - * Dividing the rank by two will provide the dimm# - * - * i3100 MC has a different mapping: it supports only 4 ranks. - * - * The mapping is (from 1 to n): - * slot single-ranked double-ranked - * dimm #1 -> rank #4 NA - * dimm #2 -> rank #3 NA - * dimm #3 -> rank #2 Ranks 2 and 3 - * dimm #4 -> rank $1 Ranks 1 and 4 - * - * FIXME: The current mapping for i3100 considers that it supports up to 8 - * ranks/chanel, but datasheet says that the MC supports only 4 ranks. - */ - struct e752x_pvt { struct pci_dev *bridge_ck; struct pci_dev *dev_d0f0; @@ -371,10 +350,8 @@ static void do_process_ce(struct mem_ctl_info *mci, u16 error_one, channel = !(error_one & 1); /* e752x mc reads 34:6 of the DRAM linear address */ - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - page, offset_in_page(sec1_add << 4), sec1_syndrome, - row, channel, -1, - "e752x CE", "", NULL); + edac_mc_handle_ce(mci, page, offset_in_page(sec1_add << 4), + sec1_syndrome, row, channel, "e752x CE"); } static inline void process_ce(struct mem_ctl_info *mci, u16 error_one, @@ -408,12 +385,9 @@ static void do_process_ue(struct mem_ctl_info *mci, u16 error_one, edac_mc_find_csrow_by_page(mci, block_page); /* e752x mc reads 34:6 of the DRAM linear address */ - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - block_page, - offset_in_page(error_2b << 4), 0, - row, -1, -1, - "e752x UE from Read", "", NULL); - + edac_mc_handle_ue(mci, block_page, + offset_in_page(error_2b << 4), + row, "e752x UE from Read"); } if (error_one & 0x0404) { error_2b = scrb_add; @@ -427,11 +401,9 @@ static void do_process_ue(struct mem_ctl_info *mci, u16 error_one, edac_mc_find_csrow_by_page(mci, block_page); /* e752x mc reads 34:6 of the DRAM linear address */ - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - block_page, - offset_in_page(error_2b << 4), 0, - row, -1, -1, - "e752x UE from Scruber", "", NULL); + edac_mc_handle_ue(mci, block_page, + offset_in_page(error_2b << 4), + row, "e752x UE from Scruber"); } } @@ -454,9 +426,7 @@ static inline void process_ue_no_info_wr(struct mem_ctl_info *mci, return; debugf3("%s()\n", __func__); - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0, - -1, -1, -1, - "e752x UE log memory write", "", NULL); + edac_mc_handle_ue_no_info(mci, "e752x UE log memory write"); } static void do_process_ded_retry(struct mem_ctl_info *mci, u16 error, @@ -1074,7 +1044,7 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, int drc_drbg; /* DRB granularity 0=64mb, 1=128mb */ int drc_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */ u8 value; - u32 dra, drc, cumul_size, i, nr_pages; + u32 dra, drc, cumul_size; dra = 0; for (index = 0; index < 4; index++) { @@ -1083,7 +1053,7 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, dra |= dra_reg << (index * 8); } pci_read_config_dword(pdev, E752X_DRC, &drc); - drc_chan = dual_channel_active(ddrcsr) ? 1 : 0; + drc_chan = dual_channel_active(ddrcsr); drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */ drc_ddim = (drc >> 20) & 0x3; @@ -1108,33 +1078,26 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, csrow->first_page = last_cumul_size; csrow->last_page = cumul_size - 1; - nr_pages = cumul_size - last_cumul_size; + csrow->nr_pages = cumul_size - last_cumul_size; last_cumul_size = cumul_size; - - for (i = 0; i < csrow->nr_channels; i++) { - struct dimm_info *dimm = csrow->channels[i].dimm; - - debugf3("Initializing rank at (%i,%i)\n", index, i); - dimm->nr_pages = nr_pages / csrow->nr_channels; - dimm->grain = 1 << 12; /* 4KiB - resolution of CELOG */ - dimm->mtype = MEM_RDDR; /* only one type supported */ - dimm->dtype = mem_dev ? DEV_X4 : DEV_X8; - - /* - * if single channel or x8 devices then SECDED - * if dual channel and x4 then S4ECD4ED - */ - if (drc_ddim) { - if (drc_chan && mem_dev) { - dimm->edac_mode = EDAC_S4ECD4ED; - mci->edac_cap |= EDAC_FLAG_S4ECD4ED; - } else { - dimm->edac_mode = EDAC_SECDED; - mci->edac_cap |= EDAC_FLAG_SECDED; - } - } else - dimm->edac_mode = EDAC_NONE; - } + csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */ + csrow->mtype = MEM_RDDR; /* only one type supported */ + csrow->dtype = mem_dev ? DEV_X4 : DEV_X8; + + /* + * if single channel or x8 devices then SECDED + * if dual channel and x4 then S4ECD4ED + */ + if (drc_ddim) { + if (drc_chan && mem_dev) { + csrow->edac_mode = EDAC_S4ECD4ED; + mci->edac_cap |= EDAC_FLAG_S4ECD4ED; + } else { + csrow->edac_mode = EDAC_SECDED; + mci->edac_cap |= EDAC_FLAG_SECDED; + } + } else + csrow->edac_mode = EDAC_NONE; } } @@ -1263,7 +1226,6 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) u16 pci_data; u8 stat8; struct mem_ctl_info *mci; - struct edac_mc_layer layers[2]; struct e752x_pvt *pvt; u16 ddrcsr; int drc_chan; /* Number of channels 0=1chan,1=2chan */ @@ -1290,15 +1252,11 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) /* Dual channel = 1, Single channel = 0 */ drc_chan = dual_channel_active(ddrcsr); - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = E752X_NR_CSROWS; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = drc_chan + 1; - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt)); - if (mci == NULL) + mci = edac_mc_alloc(sizeof(*pvt), E752X_NR_CSROWS, drc_chan + 1, 0); + + if (mci == NULL) { return -ENOMEM; + } debugf3("%s(): init mci\n", __func__); mci->mtype_cap = MEM_FLAG_RDDR; diff --git a/trunk/drivers/edac/e7xxx_edac.c b/trunk/drivers/edac/e7xxx_edac.c index 9a9c1a546797..68dea87b72e6 100644 --- a/trunk/drivers/edac/e7xxx_edac.c +++ b/trunk/drivers/edac/e7xxx_edac.c @@ -10,9 +10,6 @@ * Based on work by Dan Hollis and others. * http://www.anime.net/~goemon/linux-ecc/ * - * Datasheet: - * http://www.intel.com/content/www/us/en/chipsets/e7501-chipset-memory-controller-hub-datasheet.html - * * Contributors: * Eric Biederman (Linux Networx) * Tom Zimmerman (Linux Networx) @@ -74,7 +71,7 @@ #endif /* PCI_DEVICE_ID_INTEL_7505_1_ERR */ #define E7XXX_NR_CSROWS 8 /* number of csrows */ -#define E7XXX_NR_DIMMS 8 /* 2 channels, 4 dimms/channel */ +#define E7XXX_NR_DIMMS 8 /* FIXME - is this correct? */ /* E7XXX register addresses - device 0 function 0 */ #define E7XXX_DRB 0x60 /* DRAM row boundary register (8b) */ @@ -219,15 +216,13 @@ static void process_ce(struct mem_ctl_info *mci, struct e7xxx_error_info *info) row = edac_mc_find_csrow_by_page(mci, page); /* convert syndrome to channel */ channel = e7xxx_find_channel(syndrome); - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, page, 0, syndrome, - row, channel, -1, "e7xxx CE", "", NULL); + edac_mc_handle_ce(mci, page, 0, syndrome, row, channel, "e7xxx CE"); } static void process_ce_no_info(struct mem_ctl_info *mci) { debugf3("%s()\n", __func__); - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0, -1, -1, -1, - "e7xxx CE log register overflow", "", NULL); + edac_mc_handle_ce_no_info(mci, "e7xxx CE log register overflow"); } static void process_ue(struct mem_ctl_info *mci, struct e7xxx_error_info *info) @@ -241,17 +236,13 @@ static void process_ue(struct mem_ctl_info *mci, struct e7xxx_error_info *info) /* FIXME - should use PAGE_SHIFT */ block_page = error_2b >> 6; /* convert to 4k address */ row = edac_mc_find_csrow_by_page(mci, block_page); - - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, block_page, 0, 0, - row, -1, -1, "e7xxx UE", "", NULL); + edac_mc_handle_ue(mci, block_page, 0, row, "e7xxx UE"); } static void process_ue_no_info(struct mem_ctl_info *mci) { debugf3("%s()\n", __func__); - - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0, -1, -1, -1, - "e7xxx UE log register overflow", "", NULL); + edac_mc_handle_ue_no_info(mci, "e7xxx UE log register overflow"); } static void e7xxx_get_error_info(struct mem_ctl_info *mci, @@ -356,12 +347,11 @@ static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, int dev_idx, u32 drc) { unsigned long last_cumul_size; - int index, j; + int index; u8 value; - u32 dra, cumul_size, nr_pages; + u32 dra, cumul_size; int drc_chan, drc_drbg, drc_ddim, mem_dev; struct csrow_info *csrow; - struct dimm_info *dimm; pci_read_config_dword(pdev, E7XXX_DRA, &dra); drc_chan = dual_channel_active(drc, dev_idx); @@ -389,32 +379,26 @@ static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, csrow->first_page = last_cumul_size; csrow->last_page = cumul_size - 1; - nr_pages = cumul_size - last_cumul_size; + csrow->nr_pages = cumul_size - last_cumul_size; last_cumul_size = cumul_size; - - for (j = 0; j < drc_chan + 1; j++) { - dimm = csrow->channels[j].dimm; - - dimm->nr_pages = nr_pages / (drc_chan + 1); - dimm->grain = 1 << 12; /* 4KiB - resolution of CELOG */ - dimm->mtype = MEM_RDDR; /* only one type supported */ - dimm->dtype = mem_dev ? DEV_X4 : DEV_X8; - - /* - * if single channel or x8 devices then SECDED - * if dual channel and x4 then S4ECD4ED - */ - if (drc_ddim) { - if (drc_chan && mem_dev) { - dimm->edac_mode = EDAC_S4ECD4ED; - mci->edac_cap |= EDAC_FLAG_S4ECD4ED; - } else { - dimm->edac_mode = EDAC_SECDED; - mci->edac_cap |= EDAC_FLAG_SECDED; - } - } else - dimm->edac_mode = EDAC_NONE; - } + csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */ + csrow->mtype = MEM_RDDR; /* only one type supported */ + csrow->dtype = mem_dev ? DEV_X4 : DEV_X8; + + /* + * if single channel or x8 devices then SECDED + * if dual channel and x4 then S4ECD4ED + */ + if (drc_ddim) { + if (drc_chan && mem_dev) { + csrow->edac_mode = EDAC_S4ECD4ED; + mci->edac_cap |= EDAC_FLAG_S4ECD4ED; + } else { + csrow->edac_mode = EDAC_SECDED; + mci->edac_cap |= EDAC_FLAG_SECDED; + } + } else + csrow->edac_mode = EDAC_NONE; } } @@ -422,7 +406,6 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) { u16 pci_data; struct mem_ctl_info *mci = NULL; - struct edac_mc_layer layers[2]; struct e7xxx_pvt *pvt = NULL; u32 drc; int drc_chan; @@ -433,21 +416,8 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) pci_read_config_dword(pdev, E7XXX_DRC, &drc); drc_chan = dual_channel_active(drc, dev_idx); - /* - * According with the datasheet, this device has a maximum of - * 4 DIMMS per channel, either single-rank or dual-rank. So, the - * total amount of dimms is 8 (E7XXX_NR_DIMMS). - * That means that the DIMM is mapped as CSROWs, and the channel - * will map the rank. So, an error to either channel should be - * attributed to the same dimm. - */ - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = E7XXX_NR_CSROWS; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = drc_chan + 1; - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt)); + mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1, 0); + if (mci == NULL) return -ENOMEM; diff --git a/trunk/drivers/edac/edac_core.h b/trunk/drivers/edac/edac_core.h index 117490d4f835..5b739411d62f 100644 --- a/trunk/drivers/edac/edac_core.h +++ b/trunk/drivers/edac/edac_core.h @@ -447,10 +447,8 @@ static inline void pci_write_bits32(struct pci_dev *pdev, int offset, #endif /* CONFIG_PCI */ -struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, - unsigned n_layers, - struct edac_mc_layer *layers, - unsigned sz_pvt); +extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, + unsigned nr_chans, int edac_index); extern int edac_mc_add_mc(struct mem_ctl_info *mci); extern void edac_mc_free(struct mem_ctl_info *mci); extern struct mem_ctl_info *edac_mc_find(int idx); @@ -458,17 +456,35 @@ extern struct mem_ctl_info *find_mci_by_dev(struct device *dev); extern struct mem_ctl_info *edac_mc_del_mc(struct device *dev); extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page); -void edac_mc_handle_error(const enum hw_event_mc_err_type type, - struct mem_ctl_info *mci, - const unsigned long page_frame_number, - const unsigned long offset_in_page, - const unsigned long syndrome, - const int layer0, - const int layer1, - const int layer2, - const char *msg, - const char *other_detail, - const void *mcelog); + +/* + * The no info errors are used when error overflows are reported. + * There are a limited number of error logging registers that can + * be exausted. When all registers are exhausted and an additional + * error occurs then an error overflow register records that an + * error occurred and the type of error, but doesn't have any + * further information. The ce/ue versions make for cleaner + * reporting logic and function interface - reduces conditional + * statement clutter and extra function arguments. + */ +extern void edac_mc_handle_ce(struct mem_ctl_info *mci, + unsigned long page_frame_number, + unsigned long offset_in_page, + unsigned long syndrome, int row, int channel, + const char *msg); +extern void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, + const char *msg); +extern void edac_mc_handle_ue(struct mem_ctl_info *mci, + unsigned long page_frame_number, + unsigned long offset_in_page, int row, + const char *msg); +extern void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, + const char *msg); +extern void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci, unsigned int csrow, + unsigned int channel0, unsigned int channel1, + char *msg); +extern void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, unsigned int csrow, + unsigned int channel, char *msg); /* * edac_device APIs @@ -480,7 +496,6 @@ extern void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev, extern void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev, int inst_nr, int block_nr, const char *msg); extern int edac_device_alloc_index(void); -extern const char *edac_layer_name[]; /* * edac_pci APIs diff --git a/trunk/drivers/edac/edac_device.c b/trunk/drivers/edac/edac_device.c index ee3f1f810c1e..45b8f4bdd773 100644 --- a/trunk/drivers/edac/edac_device.c +++ b/trunk/drivers/edac/edac_device.c @@ -79,7 +79,7 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info( unsigned total_size; unsigned count; unsigned instance, block, attr; - void *pvt, *p; + void *pvt; int err; debugf4("%s() instances=%d blocks=%d\n", @@ -92,30 +92,35 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info( * to be at least as stringent as what the compiler would * provide if we could simply hardcode everything into a single struct. */ - p = NULL; - dev_ctl = edac_align_ptr(&p, sizeof(*dev_ctl), 1); + dev_ctl = (struct edac_device_ctl_info *)NULL; /* Calc the 'end' offset past end of ONE ctl_info structure * which will become the start of the 'instance' array */ - dev_inst = edac_align_ptr(&p, sizeof(*dev_inst), nr_instances); + dev_inst = edac_align_ptr(&dev_ctl[1], sizeof(*dev_inst)); /* Calc the 'end' offset past the instance array within the ctl_info * which will become the start of the block array */ - count = nr_instances * nr_blocks; - dev_blk = edac_align_ptr(&p, sizeof(*dev_blk), count); + dev_blk = edac_align_ptr(&dev_inst[nr_instances], sizeof(*dev_blk)); /* Calc the 'end' offset past the dev_blk array * which will become the start of the attrib array, if any. */ - /* calc how many nr_attrib we need */ - if (nr_attrib > 0) + count = nr_instances * nr_blocks; + dev_attrib = edac_align_ptr(&dev_blk[count], sizeof(*dev_attrib)); + + /* Check for case of when an attribute array is specified */ + if (nr_attrib > 0) { + /* calc how many nr_attrib we need */ count *= nr_attrib; - dev_attrib = edac_align_ptr(&p, sizeof(*dev_attrib), count); - /* Calc the 'end' offset past the attributes array */ - pvt = edac_align_ptr(&p, sz_private, 1); + /* Calc the 'end' offset past the attributes array */ + pvt = edac_align_ptr(&dev_attrib[count], sz_private); + } else { + /* no attribute array specified */ + pvt = edac_align_ptr(dev_attrib, sz_private); + } /* 'pvt' now points to where the private data area is. * At this point 'pvt' (like dev_inst,dev_blk and dev_attrib) diff --git a/trunk/drivers/edac/edac_mc.c b/trunk/drivers/edac/edac_mc.c index 10f375032e96..feef7733fae7 100644 --- a/trunk/drivers/edac/edac_mc.c +++ b/trunk/drivers/edac/edac_mc.c @@ -43,26 +43,9 @@ static void edac_mc_dump_channel(struct rank_info *chan) { debugf4("\tchannel = %p\n", chan); debugf4("\tchannel->chan_idx = %d\n", chan->chan_idx); + debugf4("\tchannel->ce_count = %d\n", chan->ce_count); + debugf4("\tchannel->label = '%s'\n", chan->label); debugf4("\tchannel->csrow = %p\n\n", chan->csrow); - debugf4("\tchannel->dimm = %p\n", chan->dimm); -} - -static void edac_mc_dump_dimm(struct dimm_info *dimm) -{ - int i; - - debugf4("\tdimm = %p\n", dimm); - debugf4("\tdimm->label = '%s'\n", dimm->label); - debugf4("\tdimm->nr_pages = 0x%x\n", dimm->nr_pages); - debugf4("\tdimm location "); - for (i = 0; i < dimm->mci->n_layers; i++) { - printk(KERN_CONT "%d", dimm->location[i]); - if (i < dimm->mci->n_layers - 1) - printk(KERN_CONT "."); - } - printk(KERN_CONT "\n"); - debugf4("\tdimm->grain = %d\n", dimm->grain); - debugf4("\tdimm->nr_pages = 0x%x\n", dimm->nr_pages); } static void edac_mc_dump_csrow(struct csrow_info *csrow) @@ -72,6 +55,7 @@ static void edac_mc_dump_csrow(struct csrow_info *csrow) debugf4("\tcsrow->first_page = 0x%lx\n", csrow->first_page); debugf4("\tcsrow->last_page = 0x%lx\n", csrow->last_page); debugf4("\tcsrow->page_mask = 0x%lx\n", csrow->page_mask); + debugf4("\tcsrow->nr_pages = 0x%x\n", csrow->nr_pages); debugf4("\tcsrow->nr_channels = %d\n", csrow->nr_channels); debugf4("\tcsrow->channels = %p\n", csrow->channels); debugf4("\tcsrow->mci = %p\n\n", csrow->mci); @@ -86,8 +70,6 @@ static void edac_mc_dump_mci(struct mem_ctl_info *mci) debugf4("\tmci->edac_check = %p\n", mci->edac_check); debugf3("\tmci->nr_csrows = %d, csrows = %p\n", mci->nr_csrows, mci->csrows); - debugf3("\tmci->nr_dimms = %d, dimms = %p\n", - mci->tot_dimms, mci->dimms); debugf3("\tdev = %p\n", mci->dev); debugf3("\tmod_name:ctl_name = %s:%s\n", mci->mod_name, mci->ctl_name); debugf3("\tpvt_info = %p\n\n", mci->pvt_info); @@ -119,37 +101,18 @@ const char *edac_mem_types[] = { }; EXPORT_SYMBOL_GPL(edac_mem_types); -/** - * edac_align_ptr - Prepares the pointer offsets for a single-shot allocation - * @p: pointer to a pointer with the memory offset to be used. At - * return, this will be incremented to point to the next offset - * @size: Size of the data structure to be reserved - * @n_elems: Number of elements that should be reserved +/* 'ptr' points to a possibly unaligned item X such that sizeof(X) is 'size'. + * Adjust 'ptr' so that its alignment is at least as stringent as what the + * compiler would provide for X and return the aligned result. * * If 'size' is a constant, the compiler will optimize this whole function - * down to either a no-op or the addition of a constant to the value of '*p'. - * - * The 'p' pointer is absolutely needed to keep the proper advancing - * further in memory to the proper offsets when allocating the struct along - * with its embedded structs, as edac_device_alloc_ctl_info() does it - * above, for example. - * - * At return, the pointer 'p' will be incremented to be used on a next call - * to this function. + * down to either a no-op or the addition of a constant to the value of 'ptr'. */ -void *edac_align_ptr(void **p, unsigned size, int n_elems) +void *edac_align_ptr(void *ptr, unsigned size) { unsigned align, r; - void *ptr = *p; - - *p += size * n_elems; - /* - * 'p' can possibly be an unaligned item X such that sizeof(X) is - * 'size'. Adjust 'p' so that its alignment is at least as - * stringent as what the compiler would provide for X and return - * the aligned result. - * Here we assume that the alignment of a "long long" is the most + /* Here we assume that the alignment of a "long long" is the most * stringent alignment that the compiler will ever provide by default. * As far as I know, this is a reasonable assumption. */ @@ -169,18 +132,14 @@ void *edac_align_ptr(void **p, unsigned size, int n_elems) if (r == 0) return (char *)ptr; - *p += align - r; - return (void *)(((unsigned long)ptr) + align - r); } /** - * edac_mc_alloc: Allocate and partially fill a struct mem_ctl_info structure - * @mc_num: Memory controller number - * @n_layers: Number of MC hierarchy layers - * layers: Describes each layer as seen by the Memory Controller - * @size_pvt: size of private storage needed - * + * edac_mc_alloc: Allocate a struct mem_ctl_info structure + * @size_pvt: size of private storage needed + * @nr_csrows: Number of CWROWS needed for this MC + * @nr_chans: Number of channels for the MC * * Everything is kmalloc'ed as one big chunk - more efficient. * Only can be used if all structures have the same lifetime - otherwise @@ -188,77 +147,32 @@ void *edac_align_ptr(void **p, unsigned size, int n_elems) * * Use edac_mc_free() to free mc structures allocated by this function. * - * NOTE: drivers handle multi-rank memories in different ways: in some - * drivers, one multi-rank memory stick is mapped as one entry, while, in - * others, a single multi-rank memory stick would be mapped into several - * entries. Currently, this function will allocate multiple struct dimm_info - * on such scenarios, as grouping the multiple ranks require drivers change. - * * Returns: - * On failure: NULL - * On success: struct mem_ctl_info pointer + * NULL allocation failed + * struct mem_ctl_info pointer */ -struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, - unsigned n_layers, - struct edac_mc_layer *layers, - unsigned sz_pvt) +struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, + unsigned nr_chans, int edac_index) { struct mem_ctl_info *mci; - struct edac_mc_layer *layer; - struct csrow_info *csi, *csr; + struct csrow_info *csi, *csrow; struct rank_info *chi, *chp, *chan; - struct dimm_info *dimm; - u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS]; - unsigned pos[EDAC_MAX_LAYERS]; - unsigned size, tot_dimms = 1, count = 1; - unsigned tot_csrows = 1, tot_channels = 1, tot_errcount = 0; - void *pvt, *p, *ptr = NULL; - int i, j, err, row, chn, n, len; - bool per_rank = false; - - BUG_ON(n_layers > EDAC_MAX_LAYERS || n_layers == 0); - /* - * Calculate the total amount of dimms and csrows/cschannels while - * in the old API emulation mode - */ - for (i = 0; i < n_layers; i++) { - tot_dimms *= layers[i].size; - if (layers[i].is_virt_csrow) - tot_csrows *= layers[i].size; - else - tot_channels *= layers[i].size; - - if (layers[i].type == EDAC_MC_LAYER_CHIP_SELECT) - per_rank = true; - } + void *pvt; + unsigned size; + int row, chn; + int err; /* Figure out the offsets of the various items from the start of an mc * structure. We want the alignment of each item to be at least as * stringent as what the compiler would provide if we could simply * hardcode everything into a single struct. */ - mci = edac_align_ptr(&ptr, sizeof(*mci), 1); - layer = edac_align_ptr(&ptr, sizeof(*layer), n_layers); - csi = edac_align_ptr(&ptr, sizeof(*csi), tot_csrows); - chi = edac_align_ptr(&ptr, sizeof(*chi), tot_csrows * tot_channels); - dimm = edac_align_ptr(&ptr, sizeof(*dimm), tot_dimms); - for (i = 0; i < n_layers; i++) { - count *= layers[i].size; - debugf4("%s: errcount layer %d size %d\n", __func__, i, count); - ce_per_layer[i] = edac_align_ptr(&ptr, sizeof(u32), count); - ue_per_layer[i] = edac_align_ptr(&ptr, sizeof(u32), count); - tot_errcount += 2 * count; - } - - debugf4("%s: allocating %d error counters\n", __func__, tot_errcount); - pvt = edac_align_ptr(&ptr, sz_pvt, 1); + mci = (struct mem_ctl_info *)0; + csi = edac_align_ptr(&mci[1], sizeof(*csi)); + chi = edac_align_ptr(&csi[nr_csrows], sizeof(*chi)); + pvt = edac_align_ptr(&chi[nr_chans * nr_csrows], sz_pvt); size = ((unsigned long)pvt) + sz_pvt; - debugf1("%s(): allocating %u bytes for mci data (%d %s, %d csrows/channels)\n", - __func__, size, - tot_dimms, - per_rank ? "ranks" : "dimms", - tot_csrows * tot_channels); mci = kzalloc(size, GFP_KERNEL); if (mci == NULL) return NULL; @@ -266,103 +180,28 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, /* Adjust pointers so they point within the memory we just allocated * rather than an imaginary chunk of memory located at address 0. */ - layer = (struct edac_mc_layer *)(((char *)mci) + ((unsigned long)layer)); csi = (struct csrow_info *)(((char *)mci) + ((unsigned long)csi)); chi = (struct rank_info *)(((char *)mci) + ((unsigned long)chi)); - dimm = (struct dimm_info *)(((char *)mci) + ((unsigned long)dimm)); - for (i = 0; i < n_layers; i++) { - mci->ce_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ce_per_layer[i])); - mci->ue_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ue_per_layer[i])); - } pvt = sz_pvt ? (((char *)mci) + ((unsigned long)pvt)) : NULL; /* setup index and various internal pointers */ - mci->mc_idx = mc_num; + mci->mc_idx = edac_index; mci->csrows = csi; - mci->dimms = dimm; - mci->tot_dimms = tot_dimms; mci->pvt_info = pvt; - mci->n_layers = n_layers; - mci->layers = layer; - memcpy(mci->layers, layers, sizeof(*layer) * n_layers); - mci->nr_csrows = tot_csrows; - mci->num_cschannel = tot_channels; - mci->mem_is_per_rank = per_rank; + mci->nr_csrows = nr_csrows; - /* - * Fill the csrow struct - */ - for (row = 0; row < tot_csrows; row++) { - csr = &csi[row]; - csr->csrow_idx = row; - csr->mci = mci; - csr->nr_channels = tot_channels; - chp = &chi[row * tot_channels]; - csr->channels = chp; - - for (chn = 0; chn < tot_channels; chn++) { + for (row = 0; row < nr_csrows; row++) { + csrow = &csi[row]; + csrow->csrow_idx = row; + csrow->mci = mci; + csrow->nr_channels = nr_chans; + chp = &chi[row * nr_chans]; + csrow->channels = chp; + + for (chn = 0; chn < nr_chans; chn++) { chan = &chp[chn]; chan->chan_idx = chn; - chan->csrow = csr; - } - } - - /* - * Fill the dimm struct - */ - memset(&pos, 0, sizeof(pos)); - row = 0; - chn = 0; - debugf4("%s: initializing %d %s\n", __func__, tot_dimms, - per_rank ? "ranks" : "dimms"); - for (i = 0; i < tot_dimms; i++) { - chan = &csi[row].channels[chn]; - dimm = EDAC_DIMM_PTR(layer, mci->dimms, n_layers, - pos[0], pos[1], pos[2]); - dimm->mci = mci; - - debugf2("%s: %d: %s%zd (%d:%d:%d): row %d, chan %d\n", __func__, - i, per_rank ? "rank" : "dimm", (dimm - mci->dimms), - pos[0], pos[1], pos[2], row, chn); - - /* - * Copy DIMM location and initialize it. - */ - len = sizeof(dimm->label); - p = dimm->label; - n = snprintf(p, len, "mc#%u", mc_num); - p += n; - len -= n; - for (j = 0; j < n_layers; j++) { - n = snprintf(p, len, "%s#%u", - edac_layer_name[layers[j].type], - pos[j]); - p += n; - len -= n; - dimm->location[j] = pos[j]; - - if (len <= 0) - break; - } - - /* Link it to the csrows old API data */ - chan->dimm = dimm; - dimm->csrow = row; - dimm->cschannel = chn; - - /* Increment csrow location */ - row++; - if (row == tot_csrows) { - row = 0; - chn++; - } - - /* Increment dimm location */ - for (j = n_layers - 1; j >= 0; j--) { - pos[j]++; - if (pos[j] < layers[j].size) - break; - pos[j] = 0; + chan->csrow = csrow; } } @@ -651,6 +490,7 @@ EXPORT_SYMBOL(edac_mc_find); * edac_mc_add_mc: Insert the 'mci' structure into the mci global list and * create sysfs entries associated with mci structure * @mci: pointer to the mci structure to be added to the list + * @mc_idx: A unique numeric identifier to be assigned to the 'mci' structure. * * Return: * 0 Success @@ -677,8 +517,6 @@ int edac_mc_add_mc(struct mem_ctl_info *mci) edac_mc_dump_channel(&mci->csrows[i]. channels[j]); } - for (i = 0; i < mci->tot_dimms; i++) - edac_mc_dump_dimm(&mci->dimms[i]); } #endif mutex_lock(&mem_ctls_mutex); @@ -798,19 +636,15 @@ static void edac_mc_scrub_block(unsigned long page, unsigned long offset, int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page) { struct csrow_info *csrows = mci->csrows; - int row, i, j, n; + int row, i; debugf1("MC%d: %s(): 0x%lx\n", mci->mc_idx, __func__, page); row = -1; for (i = 0; i < mci->nr_csrows; i++) { struct csrow_info *csrow = &csrows[i]; - n = 0; - for (j = 0; j < csrow->nr_channels; j++) { - struct dimm_info *dimm = csrow->channels[j].dimm; - n += dimm->nr_pages; - } - if (n == 0) + + if (csrow->nr_pages == 0) continue; debugf3("MC%d: %s(): first(0x%lx) page(0x%lx) last(0x%lx) " @@ -836,307 +670,249 @@ int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page) } EXPORT_SYMBOL_GPL(edac_mc_find_csrow_by_page); -const char *edac_layer_name[] = { - [EDAC_MC_LAYER_BRANCH] = "branch", - [EDAC_MC_LAYER_CHANNEL] = "channel", - [EDAC_MC_LAYER_SLOT] = "slot", - [EDAC_MC_LAYER_CHIP_SELECT] = "csrow", -}; -EXPORT_SYMBOL_GPL(edac_layer_name); - -static void edac_inc_ce_error(struct mem_ctl_info *mci, - bool enable_per_layer_report, - const int pos[EDAC_MAX_LAYERS]) +/* FIXME - setable log (warning/emerg) levels */ +/* FIXME - integrate with evlog: http://evlog.sourceforge.net/ */ +void edac_mc_handle_ce(struct mem_ctl_info *mci, + unsigned long page_frame_number, + unsigned long offset_in_page, unsigned long syndrome, + int row, int channel, const char *msg) { - int i, index = 0; + unsigned long remapped_page; - mci->ce_mc++; + debugf3("MC%d: %s()\n", mci->mc_idx, __func__); - if (!enable_per_layer_report) { - mci->ce_noinfo_count++; + /* FIXME - maybe make panic on INTERNAL ERROR an option */ + if (row >= mci->nr_csrows || row < 0) { + /* something is wrong */ + edac_mc_printk(mci, KERN_ERR, + "INTERNAL ERROR: row out of range " + "(%d >= %d)\n", row, mci->nr_csrows); + edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR"); return; } - for (i = 0; i < mci->n_layers; i++) { - if (pos[i] < 0) - break; - index += pos[i]; - mci->ce_per_layer[i][index]++; - - if (i < mci->n_layers - 1) - index *= mci->layers[i + 1].size; - } -} - -static void edac_inc_ue_error(struct mem_ctl_info *mci, - bool enable_per_layer_report, - const int pos[EDAC_MAX_LAYERS]) -{ - int i, index = 0; - - mci->ue_mc++; - - if (!enable_per_layer_report) { - mci->ce_noinfo_count++; + if (channel >= mci->csrows[row].nr_channels || channel < 0) { + /* something is wrong */ + edac_mc_printk(mci, KERN_ERR, + "INTERNAL ERROR: channel out of range " + "(%d >= %d)\n", channel, + mci->csrows[row].nr_channels); + edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR"); return; } - for (i = 0; i < mci->n_layers; i++) { - if (pos[i] < 0) - break; - index += pos[i]; - mci->ue_per_layer[i][index]++; - - if (i < mci->n_layers - 1) - index *= mci->layers[i + 1].size; - } -} + if (edac_mc_get_log_ce()) + /* FIXME - put in DIMM location */ + edac_mc_printk(mci, KERN_WARNING, + "CE page 0x%lx, offset 0x%lx, grain %d, syndrome " + "0x%lx, row %d, channel %d, label \"%s\": %s\n", + page_frame_number, offset_in_page, + mci->csrows[row].grain, syndrome, row, channel, + mci->csrows[row].channels[channel].label, msg); -static void edac_ce_error(struct mem_ctl_info *mci, - const int pos[EDAC_MAX_LAYERS], - const char *msg, - const char *location, - const char *label, - const char *detail, - const char *other_detail, - const bool enable_per_layer_report, - const unsigned long page_frame_number, - const unsigned long offset_in_page, - u32 grain) -{ - unsigned long remapped_page; - - if (edac_mc_get_log_ce()) { - if (other_detail && *other_detail) - edac_mc_printk(mci, KERN_WARNING, - "CE %s on %s (%s%s - %s)\n", - msg, label, location, - detail, other_detail); - else - edac_mc_printk(mci, KERN_WARNING, - "CE %s on %s (%s%s)\n", - msg, label, location, - detail); - } - edac_inc_ce_error(mci, enable_per_layer_report, pos); + mci->ce_count++; + mci->csrows[row].ce_count++; + mci->csrows[row].channels[channel].ce_count++; if (mci->scrub_mode & SCRUB_SW_SRC) { /* - * Some memory controllers (called MCs below) can remap - * memory so that it is still available at a different - * address when PCI devices map into memory. - * MC's that can't do this, lose the memory where PCI - * devices are mapped. This mapping is MC-dependent - * and so we call back into the MC driver for it to - * map the MC page to a physical (CPU) page which can - * then be mapped to a virtual page - which can then - * be scrubbed. - */ + * Some MC's can remap memory so that it is still available + * at a different address when PCI devices map into memory. + * MC's that can't do this lose the memory where PCI devices + * are mapped. This mapping is MC dependent and so we call + * back into the MC driver for it to map the MC page to + * a physical (CPU) page which can then be mapped to a virtual + * page - which can then be scrubbed. + */ remapped_page = mci->ctl_page_to_phys ? mci->ctl_page_to_phys(mci, page_frame_number) : page_frame_number; - edac_mc_scrub_block(remapped_page, - offset_in_page, grain); + edac_mc_scrub_block(remapped_page, offset_in_page, + mci->csrows[row].grain); } } +EXPORT_SYMBOL_GPL(edac_mc_handle_ce); -static void edac_ue_error(struct mem_ctl_info *mci, - const int pos[EDAC_MAX_LAYERS], - const char *msg, - const char *location, - const char *label, - const char *detail, - const char *other_detail, - const bool enable_per_layer_report) +void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg) { - if (edac_mc_get_log_ue()) { - if (other_detail && *other_detail) - edac_mc_printk(mci, KERN_WARNING, - "UE %s on %s (%s%s - %s)\n", - msg, label, location, detail, - other_detail); - else - edac_mc_printk(mci, KERN_WARNING, - "UE %s on %s (%s%s)\n", - msg, label, location, detail); - } - - if (edac_mc_get_panic_on_ue()) { - if (other_detail && *other_detail) - panic("UE %s on %s (%s%s - %s)\n", - msg, label, location, detail, other_detail); - else - panic("UE %s on %s (%s%s)\n", - msg, label, location, detail); - } + if (edac_mc_get_log_ce()) + edac_mc_printk(mci, KERN_WARNING, + "CE - no information available: %s\n", msg); - edac_inc_ue_error(mci, enable_per_layer_report, pos); + mci->ce_noinfo_count++; + mci->ce_count++; } +EXPORT_SYMBOL_GPL(edac_mc_handle_ce_no_info); -#define OTHER_LABEL " or " -void edac_mc_handle_error(const enum hw_event_mc_err_type type, - struct mem_ctl_info *mci, - const unsigned long page_frame_number, - const unsigned long offset_in_page, - const unsigned long syndrome, - const int layer0, - const int layer1, - const int layer2, - const char *msg, - const char *other_detail, - const void *mcelog) +void edac_mc_handle_ue(struct mem_ctl_info *mci, + unsigned long page_frame_number, + unsigned long offset_in_page, int row, const char *msg) { - /* FIXME: too much for stack: move it to some pre-alocated area */ - char detail[80], location[80]; - char label[(EDAC_MC_LABEL_LEN + 1 + sizeof(OTHER_LABEL)) * mci->tot_dimms]; - char *p; - int row = -1, chan = -1; - int pos[EDAC_MAX_LAYERS] = { layer0, layer1, layer2 }; - int i; - u32 grain; - bool enable_per_layer_report = false; + int len = EDAC_MC_LABEL_LEN * 4; + char labels[len + 1]; + char *pos = labels; + int chan; + int chars; debugf3("MC%d: %s()\n", mci->mc_idx, __func__); - /* - * Check if the event report is consistent and if the memory - * location is known. If it is known, enable_per_layer_report will be - * true, the DIMM(s) label info will be filled and the per-layer - * error counters will be incremented. - */ - for (i = 0; i < mci->n_layers; i++) { - if (pos[i] >= (int)mci->layers[i].size) { - if (type == HW_EVENT_ERR_CORRECTED) - p = "CE"; - else - p = "UE"; - - edac_mc_printk(mci, KERN_ERR, - "INTERNAL ERROR: %s value is out of range (%d >= %d)\n", - edac_layer_name[mci->layers[i].type], - pos[i], mci->layers[i].size); - /* - * Instead of just returning it, let's use what's - * known about the error. The increment routines and - * the DIMM filter logic will do the right thing by - * pointing the likely damaged DIMMs. - */ - pos[i] = -1; - } - if (pos[i] >= 0) - enable_per_layer_report = true; + /* FIXME - maybe make panic on INTERNAL ERROR an option */ + if (row >= mci->nr_csrows || row < 0) { + /* something is wrong */ + edac_mc_printk(mci, KERN_ERR, + "INTERNAL ERROR: row out of range " + "(%d >= %d)\n", row, mci->nr_csrows); + edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR"); + return; } - /* - * Get the dimm label/grain that applies to the match criteria. - * As the error algorithm may not be able to point to just one memory - * stick, the logic here will get all possible labels that could - * pottentially be affected by the error. - * On FB-DIMM memory controllers, for uncorrected errors, it is common - * to have only the MC channel and the MC dimm (also called "branch") - * but the channel is not known, as the memory is arranged in pairs, - * where each memory belongs to a separate channel within the same - * branch. - */ - grain = 0; - p = label; - *p = '\0'; - for (i = 0; i < mci->tot_dimms; i++) { - struct dimm_info *dimm = &mci->dimms[i]; + chars = snprintf(pos, len + 1, "%s", + mci->csrows[row].channels[0].label); + len -= chars; + pos += chars; - if (layer0 >= 0 && layer0 != dimm->location[0]) - continue; - if (layer1 >= 0 && layer1 != dimm->location[1]) - continue; - if (layer2 >= 0 && layer2 != dimm->location[2]) - continue; + for (chan = 1; (chan < mci->csrows[row].nr_channels) && (len > 0); + chan++) { + chars = snprintf(pos, len + 1, ":%s", + mci->csrows[row].channels[chan].label); + len -= chars; + pos += chars; + } - /* get the max grain, over the error match range */ - if (dimm->grain > grain) - grain = dimm->grain; + if (edac_mc_get_log_ue()) + edac_mc_printk(mci, KERN_EMERG, + "UE page 0x%lx, offset 0x%lx, grain %d, row %d, " + "labels \"%s\": %s\n", page_frame_number, + offset_in_page, mci->csrows[row].grain, row, + labels, msg); - /* - * If the error is memory-controller wide, there's no need to - * seek for the affected DIMMs because the whole - * channel/memory controller/... may be affected. - * Also, don't show errors for empty DIMM slots. - */ - if (enable_per_layer_report && dimm->nr_pages) { - if (p != label) { - strcpy(p, OTHER_LABEL); - p += strlen(OTHER_LABEL); - } - strcpy(p, dimm->label); - p += strlen(p); - *p = '\0'; - - /* - * get csrow/channel of the DIMM, in order to allow - * incrementing the compat API counters - */ - debugf4("%s: %s csrows map: (%d,%d)\n", - __func__, - mci->mem_is_per_rank ? "rank" : "dimm", - dimm->csrow, dimm->cschannel); - - if (row == -1) - row = dimm->csrow; - else if (row >= 0 && row != dimm->csrow) - row = -2; - - if (chan == -1) - chan = dimm->cschannel; - else if (chan >= 0 && chan != dimm->cschannel) - chan = -2; - } - } + if (edac_mc_get_panic_on_ue()) + panic("EDAC MC%d: UE page 0x%lx, offset 0x%lx, grain %d, " + "row %d, labels \"%s\": %s\n", mci->mc_idx, + page_frame_number, offset_in_page, + mci->csrows[row].grain, row, labels, msg); - if (!enable_per_layer_report) { - strcpy(label, "any memory"); - } else { - debugf4("%s: csrow/channel to increment: (%d,%d)\n", - __func__, row, chan); - if (p == label) - strcpy(label, "unknown memory"); - if (type == HW_EVENT_ERR_CORRECTED) { - if (row >= 0) { - mci->csrows[row].ce_count++; - if (chan >= 0) - mci->csrows[row].channels[chan].ce_count++; - } - } else - if (row >= 0) - mci->csrows[row].ue_count++; + mci->ue_count++; + mci->csrows[row].ue_count++; +} +EXPORT_SYMBOL_GPL(edac_mc_handle_ue); + +void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg) +{ + if (edac_mc_get_panic_on_ue()) + panic("EDAC MC%d: Uncorrected Error", mci->mc_idx); + + if (edac_mc_get_log_ue()) + edac_mc_printk(mci, KERN_WARNING, + "UE - no information available: %s\n", msg); + mci->ue_noinfo_count++; + mci->ue_count++; +} +EXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info); + +/************************************************************* + * On Fully Buffered DIMM modules, this help function is + * called to process UE events + */ +void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci, + unsigned int csrow, + unsigned int channela, + unsigned int channelb, char *msg) +{ + int len = EDAC_MC_LABEL_LEN * 4; + char labels[len + 1]; + char *pos = labels; + int chars; + + if (csrow >= mci->nr_csrows) { + /* something is wrong */ + edac_mc_printk(mci, KERN_ERR, + "INTERNAL ERROR: row out of range (%d >= %d)\n", + csrow, mci->nr_csrows); + edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR"); + return; } - /* Fill the RAM location data */ - p = location; - for (i = 0; i < mci->n_layers; i++) { - if (pos[i] < 0) - continue; + if (channela >= mci->csrows[csrow].nr_channels) { + /* something is wrong */ + edac_mc_printk(mci, KERN_ERR, + "INTERNAL ERROR: channel-a out of range " + "(%d >= %d)\n", + channela, mci->csrows[csrow].nr_channels); + edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR"); + return; + } - p += sprintf(p, "%s:%d ", - edac_layer_name[mci->layers[i].type], - pos[i]); + if (channelb >= mci->csrows[csrow].nr_channels) { + /* something is wrong */ + edac_mc_printk(mci, KERN_ERR, + "INTERNAL ERROR: channel-b out of range " + "(%d >= %d)\n", + channelb, mci->csrows[csrow].nr_channels); + edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR"); + return; } - /* Memory type dependent details about the error */ - if (type == HW_EVENT_ERR_CORRECTED) { - snprintf(detail, sizeof(detail), - "page:0x%lx offset:0x%lx grain:%d syndrome:0x%lx", - page_frame_number, offset_in_page, - grain, syndrome); - edac_ce_error(mci, pos, msg, location, label, detail, - other_detail, enable_per_layer_report, - page_frame_number, offset_in_page, grain); - } else { - snprintf(detail, sizeof(detail), - "page:0x%lx offset:0x%lx grain:%d", - page_frame_number, offset_in_page, grain); + mci->ue_count++; + mci->csrows[csrow].ue_count++; + + /* Generate the DIMM labels from the specified channels */ + chars = snprintf(pos, len + 1, "%s", + mci->csrows[csrow].channels[channela].label); + len -= chars; + pos += chars; + chars = snprintf(pos, len + 1, "-%s", + mci->csrows[csrow].channels[channelb].label); - edac_ue_error(mci, pos, msg, location, label, detail, - other_detail, enable_per_layer_report); + if (edac_mc_get_log_ue()) + edac_mc_printk(mci, KERN_EMERG, + "UE row %d, channel-a= %d channel-b= %d " + "labels \"%s\": %s\n", csrow, channela, channelb, + labels, msg); + + if (edac_mc_get_panic_on_ue()) + panic("UE row %d, channel-a= %d channel-b= %d " + "labels \"%s\": %s\n", csrow, channela, + channelb, labels, msg); +} +EXPORT_SYMBOL(edac_mc_handle_fbd_ue); + +/************************************************************* + * On Fully Buffered DIMM modules, this help function is + * called to process CE events + */ +void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, + unsigned int csrow, unsigned int channel, char *msg) +{ + + /* Ensure boundary values */ + if (csrow >= mci->nr_csrows) { + /* something is wrong */ + edac_mc_printk(mci, KERN_ERR, + "INTERNAL ERROR: row out of range (%d >= %d)\n", + csrow, mci->nr_csrows); + edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR"); + return; + } + if (channel >= mci->csrows[csrow].nr_channels) { + /* something is wrong */ + edac_mc_printk(mci, KERN_ERR, + "INTERNAL ERROR: channel out of range (%d >= %d)\n", + channel, mci->csrows[csrow].nr_channels); + edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR"); + return; } + + if (edac_mc_get_log_ce()) + /* FIXME - put in DIMM location */ + edac_mc_printk(mci, KERN_WARNING, + "CE row %d, channel %d, label \"%s\": %s\n", + csrow, channel, + mci->csrows[csrow].channels[channel].label, msg); + + mci->ce_count++; + mci->csrows[csrow].ce_count++; + mci->csrows[csrow].channels[channel].ce_count++; } -EXPORT_SYMBOL_GPL(edac_mc_handle_error); +EXPORT_SYMBOL(edac_mc_handle_fbd_ce); diff --git a/trunk/drivers/edac/edac_mc_sysfs.c b/trunk/drivers/edac/edac_mc_sysfs.c index f6a29b0eedc8..e9a28f576d14 100644 --- a/trunk/drivers/edac/edac_mc_sysfs.c +++ b/trunk/drivers/edac/edac_mc_sysfs.c @@ -144,31 +144,25 @@ static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data, static ssize_t csrow_size_show(struct csrow_info *csrow, char *data, int private) { - int i; - u32 nr_pages = 0; - - for (i = 0; i < csrow->nr_channels; i++) - nr_pages += csrow->channels[i].dimm->nr_pages; - - return sprintf(data, "%u\n", PAGES_TO_MiB(nr_pages)); + return sprintf(data, "%u\n", PAGES_TO_MiB(csrow->nr_pages)); } static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data, int private) { - return sprintf(data, "%s\n", mem_types[csrow->channels[0].dimm->mtype]); + return sprintf(data, "%s\n", mem_types[csrow->mtype]); } static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data, int private) { - return sprintf(data, "%s\n", dev_types[csrow->channels[0].dimm->dtype]); + return sprintf(data, "%s\n", dev_types[csrow->dtype]); } static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data, int private) { - return sprintf(data, "%s\n", edac_caps[csrow->channels[0].dimm->edac_mode]); + return sprintf(data, "%s\n", edac_caps[csrow->edac_mode]); } /* show/store functions for DIMM Label attributes */ @@ -176,11 +170,11 @@ static ssize_t channel_dimm_label_show(struct csrow_info *csrow, char *data, int channel) { /* if field has not been initialized, there is nothing to send */ - if (!csrow->channels[channel].dimm->label[0]) + if (!csrow->channels[channel].label[0]) return 0; return snprintf(data, EDAC_MC_LABEL_LEN, "%s\n", - csrow->channels[channel].dimm->label); + csrow->channels[channel].label); } static ssize_t channel_dimm_label_store(struct csrow_info *csrow, @@ -190,8 +184,8 @@ static ssize_t channel_dimm_label_store(struct csrow_info *csrow, ssize_t max_size = 0; max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1); - strncpy(csrow->channels[channel].dimm->label, data, max_size); - csrow->channels[channel].dimm->label[max_size] = '\0'; + strncpy(csrow->channels[channel].label, data, max_size); + csrow->channels[channel].label[max_size] = '\0'; return max_size; } @@ -425,8 +419,8 @@ static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci, mci->ue_noinfo_count = 0; mci->ce_noinfo_count = 0; - mci->ue_mc = 0; - mci->ce_mc = 0; + mci->ue_count = 0; + mci->ce_count = 0; for (row = 0; row < mci->nr_csrows; row++) { struct csrow_info *ri = &mci->csrows[row]; @@ -495,12 +489,12 @@ static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data) /* default attribute files for the MCI object */ static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data) { - return sprintf(data, "%d\n", mci->ue_mc); + return sprintf(data, "%d\n", mci->ue_count); } static ssize_t mci_ce_count_show(struct mem_ctl_info *mci, char *data) { - return sprintf(data, "%d\n", mci->ce_mc); + return sprintf(data, "%d\n", mci->ce_count); } static ssize_t mci_ce_noinfo_show(struct mem_ctl_info *mci, char *data) @@ -525,16 +519,16 @@ static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data) static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data) { - int total_pages = 0, csrow_idx, j; + int total_pages, csrow_idx; - for (csrow_idx = 0; csrow_idx < mci->nr_csrows; csrow_idx++) { + for (total_pages = csrow_idx = 0; csrow_idx < mci->nr_csrows; + csrow_idx++) { struct csrow_info *csrow = &mci->csrows[csrow_idx]; - for (j = 0; j < csrow->nr_channels; j++) { - struct dimm_info *dimm = csrow->channels[j].dimm; + if (!csrow->nr_pages) + continue; - total_pages += dimm->nr_pages; - } + total_pages += csrow->nr_pages; } return sprintf(data, "%u\n", PAGES_TO_MiB(total_pages)); @@ -906,7 +900,7 @@ static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci, */ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) { - int i, j; + int i; int err; struct csrow_info *csrow; struct kobject *kobj_mci = &mci->edac_mci_kobj; @@ -940,13 +934,10 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) /* Make directories for each CSROW object under the mc kobject */ for (i = 0; i < mci->nr_csrows; i++) { - int nr_pages = 0; - csrow = &mci->csrows[i]; - for (j = 0; j < csrow->nr_channels; j++) - nr_pages += csrow->channels[j].dimm->nr_pages; - if (nr_pages > 0) { + /* Only expose populated CSROWs */ + if (csrow->nr_pages > 0) { err = edac_create_csrow_object(mci, csrow, i); if (err) { debugf1("%s() failure: create csrow %d obj\n", @@ -958,15 +949,12 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) return 0; + /* CSROW error: backout what has already been registered, */ fail1: for (i--; i >= 0; i--) { - int nr_pages = 0; - - csrow = &mci->csrows[i]; - for (j = 0; j < csrow->nr_channels; j++) - nr_pages += csrow->channels[j].dimm->nr_pages; - if (nr_pages > 0) + if (csrow->nr_pages > 0) { kobject_put(&mci->csrows[i].kobj); + } } /* remove the mci instance's attributes, if any */ @@ -985,20 +973,14 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) */ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) { - struct csrow_info *csrow; - int i, j; + int i; debugf0("%s()\n", __func__); /* remove all csrow kobjects */ debugf4("%s() unregister this mci kobj\n", __func__); for (i = 0; i < mci->nr_csrows; i++) { - int nr_pages = 0; - - csrow = &mci->csrows[i]; - for (j = 0; j < csrow->nr_channels; j++) - nr_pages += csrow->channels[j].dimm->nr_pages; - if (nr_pages > 0) { + if (mci->csrows[i].nr_pages > 0) { debugf0("%s() unreg csrow-%d\n", __func__, i); kobject_put(&mci->csrows[i].kobj); } diff --git a/trunk/drivers/edac/edac_module.h b/trunk/drivers/edac/edac_module.h index 0ea7d14cb930..00f81b47a51f 100644 --- a/trunk/drivers/edac/edac_module.h +++ b/trunk/drivers/edac/edac_module.h @@ -50,7 +50,7 @@ extern void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev, unsigned long value); extern void edac_mc_reset_delay_period(int value); -extern void *edac_align_ptr(void **p, unsigned size, int n_elems); +extern void *edac_align_ptr(void *ptr, unsigned size); /* * EDAC PCI functions diff --git a/trunk/drivers/edac/edac_pci.c b/trunk/drivers/edac/edac_pci.c index f1ac86649886..63af1c5673d1 100644 --- a/trunk/drivers/edac/edac_pci.c +++ b/trunk/drivers/edac/edac_pci.c @@ -42,13 +42,13 @@ struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt, const char *edac_pci_name) { struct edac_pci_ctl_info *pci; - void *p = NULL, *pvt; + void *pvt; unsigned int size; debugf1("%s()\n", __func__); - pci = edac_align_ptr(&p, sizeof(*pci), 1); - pvt = edac_align_ptr(&p, 1, sz_pvt); + pci = (struct edac_pci_ctl_info *)0; + pvt = edac_align_ptr(&pci[1], sz_pvt); size = ((unsigned long)pvt) + sz_pvt; /* Alloc the needed control struct memory */ diff --git a/trunk/drivers/edac/i3000_edac.c b/trunk/drivers/edac/i3000_edac.c index 8ad1744faacd..277689a68841 100644 --- a/trunk/drivers/edac/i3000_edac.c +++ b/trunk/drivers/edac/i3000_edac.c @@ -245,9 +245,7 @@ static int i3000_process_error_info(struct mem_ctl_info *mci, return 1; if ((info->errsts ^ info->errsts2) & I3000_ERRSTS_BITS) { - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0, - -1, -1, -1, - "UE overwrote CE", "", NULL); + edac_mc_handle_ce_no_info(mci, "UE overwrote CE"); info->errsts = info->errsts2; } @@ -258,15 +256,10 @@ static int i3000_process_error_info(struct mem_ctl_info *mci, row = edac_mc_find_csrow_by_page(mci, pfn); if (info->errsts & I3000_ERRSTS_UE) - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - pfn, offset, 0, - row, -1, -1, - "i3000 UE", "", NULL); + edac_mc_handle_ue(mci, pfn, offset, row, "i3000 UE"); else - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - pfn, offset, info->derrsyn, - row, multi_chan ? channel : 0, -1, - "i3000 CE", "", NULL); + edac_mc_handle_ce(mci, pfn, offset, info->derrsyn, row, + multi_chan ? channel : 0, "i3000 CE"); return 1; } @@ -311,10 +304,9 @@ static int i3000_is_interleaved(const unsigned char *c0dra, static int i3000_probe1(struct pci_dev *pdev, int dev_idx) { int rc; - int i, j; + int i; struct mem_ctl_info *mci = NULL; - struct edac_mc_layer layers[2]; - unsigned long last_cumul_size, nr_pages; + unsigned long last_cumul_size; int interleaved, nr_channels; unsigned char dra[I3000_RANKS / 2], drb[I3000_RANKS]; unsigned char *c0dra = dra, *c1dra = &dra[I3000_RANKS_PER_CHANNEL / 2]; @@ -355,14 +347,7 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx) */ interleaved = i3000_is_interleaved(c0dra, c1dra, c0drb, c1drb); nr_channels = interleaved ? 2 : 1; - - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = I3000_RANKS / nr_channels; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = nr_channels; - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0); + mci = edac_mc_alloc(0, I3000_RANKS / nr_channels, nr_channels, 0); if (!mci) return -ENOMEM; @@ -401,23 +386,19 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx) cumul_size <<= 1; debugf3("MC: %s(): (%d) cumul_size 0x%x\n", __func__, i, cumul_size); - if (cumul_size == last_cumul_size) + if (cumul_size == last_cumul_size) { + csrow->mtype = MEM_EMPTY; continue; + } csrow->first_page = last_cumul_size; csrow->last_page = cumul_size - 1; - nr_pages = cumul_size - last_cumul_size; + csrow->nr_pages = cumul_size - last_cumul_size; last_cumul_size = cumul_size; - - for (j = 0; j < nr_channels; j++) { - struct dimm_info *dimm = csrow->channels[j].dimm; - - dimm->nr_pages = nr_pages / nr_channels; - dimm->grain = I3000_DEAP_GRAIN; - dimm->mtype = MEM_DDR2; - dimm->dtype = DEV_UNKNOWN; - dimm->edac_mode = EDAC_UNKNOWN; - } + csrow->grain = I3000_DEAP_GRAIN; + csrow->mtype = MEM_DDR2; + csrow->dtype = DEV_UNKNOWN; + csrow->edac_mode = EDAC_UNKNOWN; } /* diff --git a/trunk/drivers/edac/i3200_edac.c b/trunk/drivers/edac/i3200_edac.c index bbe43ef71823..046808c6357d 100644 --- a/trunk/drivers/edac/i3200_edac.c +++ b/trunk/drivers/edac/i3200_edac.c @@ -23,7 +23,6 @@ #define PCI_DEVICE_ID_INTEL_3200_HB 0x29f0 -#define I3200_DIMMS 4 #define I3200_RANKS 8 #define I3200_RANKS_PER_CHANNEL 4 #define I3200_CHANNELS 2 @@ -218,25 +217,21 @@ static void i3200_process_error_info(struct mem_ctl_info *mci, return; if ((info->errsts ^ info->errsts2) & I3200_ERRSTS_BITS) { - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0, - -1, -1, -1, "UE overwrote CE", "", NULL); + edac_mc_handle_ce_no_info(mci, "UE overwrote CE"); info->errsts = info->errsts2; } for (channel = 0; channel < nr_channels; channel++) { log = info->eccerrlog[channel]; if (log & I3200_ECCERRLOG_UE) { - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - 0, 0, 0, - eccerrlog_row(channel, log), - -1, -1, - "i3000 UE", "", NULL); + edac_mc_handle_ue(mci, 0, 0, + eccerrlog_row(channel, log), + "i3200 UE"); } else if (log & I3200_ECCERRLOG_CE) { - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - 0, 0, eccerrlog_syndrome(log), - eccerrlog_row(channel, log), - -1, -1, - "i3000 UE", "", NULL); + edac_mc_handle_ce(mci, 0, 0, + eccerrlog_syndrome(log), + eccerrlog_row(channel, log), 0, + "i3200 CE"); } } } @@ -324,9 +319,9 @@ static unsigned long drb_to_nr_pages( static int i3200_probe1(struct pci_dev *pdev, int dev_idx) { int rc; - int i, j; + int i; struct mem_ctl_info *mci = NULL; - struct edac_mc_layer layers[2]; + unsigned long last_page; u16 drbs[I3200_CHANNELS][I3200_RANKS_PER_CHANNEL]; bool stacked; void __iomem *window; @@ -341,14 +336,8 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx) i3200_get_drbs(window, drbs); nr_channels = how_many_channels(pdev); - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = I3200_DIMMS; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = nr_channels; - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, - sizeof(struct i3200_priv)); + mci = edac_mc_alloc(sizeof(struct i3200_priv), I3200_RANKS, + nr_channels, 0); if (!mci) return -ENOMEM; @@ -377,6 +366,7 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx) * cumulative; the last one will contain the total memory * contained in all ranks. */ + last_page = -1UL; for (i = 0; i < mci->nr_csrows; i++) { unsigned long nr_pages; struct csrow_info *csrow = &mci->csrows[i]; @@ -385,18 +375,20 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx) i / I3200_RANKS_PER_CHANNEL, i % I3200_RANKS_PER_CHANNEL); - if (nr_pages == 0) + if (nr_pages == 0) { + csrow->mtype = MEM_EMPTY; continue; + } - for (j = 0; j < nr_channels; j++) { - struct dimm_info *dimm = csrow->channels[j].dimm; + csrow->first_page = last_page + 1; + last_page += nr_pages; + csrow->last_page = last_page; + csrow->nr_pages = nr_pages; - dimm->nr_pages = nr_pages / nr_channels; - dimm->grain = nr_pages << PAGE_SHIFT; - dimm->mtype = MEM_DDR2; - dimm->dtype = DEV_UNKNOWN; - dimm->edac_mode = EDAC_UNKNOWN; - } + csrow->grain = nr_pages << PAGE_SHIFT; + csrow->mtype = MEM_DDR2; + csrow->dtype = DEV_UNKNOWN; + csrow->edac_mode = EDAC_UNKNOWN; } i3200_clear_error_info(mci); diff --git a/trunk/drivers/edac/i5000_edac.c b/trunk/drivers/edac/i5000_edac.c index 11ea835f155a..a2680d8e744b 100644 --- a/trunk/drivers/edac/i5000_edac.c +++ b/trunk/drivers/edac/i5000_edac.c @@ -270,8 +270,7 @@ #define MTR3 0x8C #define NUM_MTRS 4 -#define CHANNELS_PER_BRANCH 2 -#define MAX_BRANCHES 2 +#define CHANNELS_PER_BRANCH (2) /* Defines to extract the vaious fields from the * MTRx - Memory Technology Registers @@ -474,6 +473,7 @@ static void i5000_process_fatal_error_info(struct mem_ctl_info *mci, char msg[EDAC_MC_LABEL_LEN + 1 + 160]; char *specific = NULL; u32 allErrors; + int branch; int channel; int bank; int rank; @@ -485,7 +485,8 @@ static void i5000_process_fatal_error_info(struct mem_ctl_info *mci, if (!allErrors) return; /* if no error, return now */ - channel = EXTRACT_FBDCHAN_INDX(info->ferr_fat_fbd); + branch = EXTRACT_FBDCHAN_INDX(info->ferr_fat_fbd); + channel = branch; /* Use the NON-Recoverable macros to extract data */ bank = NREC_BANK(info->nrecmema); @@ -494,9 +495,9 @@ static void i5000_process_fatal_error_info(struct mem_ctl_info *mci, ras = NREC_RAS(info->nrecmemb); cas = NREC_CAS(info->nrecmemb); - debugf0("\t\tCSROW= %d Channel= %d " - "(DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n", - rank, channel, bank, + debugf0("\t\tCSROW= %d Channels= %d,%d (Branch= %d " + "DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n", + rank, channel, channel + 1, branch >> 1, bank, rdwr ? "Write" : "Read", ras, cas); /* Only 1 bit will be on */ @@ -532,14 +533,13 @@ static void i5000_process_fatal_error_info(struct mem_ctl_info *mci, /* Form out message */ snprintf(msg, sizeof(msg), - "Bank=%d RAS=%d CAS=%d FATAL Err=0x%x (%s)", - bank, ras, cas, allErrors, specific); + "(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d CAS=%d " + "FATAL Err=0x%x (%s))", + branch >> 1, bank, rdwr ? "Write" : "Read", ras, cas, + allErrors, specific); /* Call the helper to output message */ - edac_mc_handle_error(HW_EVENT_ERR_FATAL, mci, 0, 0, 0, - channel >> 1, channel & 1, rank, - rdwr ? "Write error" : "Read error", - msg, NULL); + edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg); } /* @@ -633,14 +633,13 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci, /* Form out message */ snprintf(msg, sizeof(msg), - "Rank=%d Bank=%d RAS=%d CAS=%d, UE Err=0x%x (%s)", - rank, bank, ras, cas, ue_errors, specific); + "(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d " + "CAS=%d, UE Err=0x%x (%s))", + branch >> 1, bank, rdwr ? "Write" : "Read", ras, cas, + ue_errors, specific); /* Call the helper to output message */ - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0, - channel >> 1, -1, rank, - rdwr ? "Write error" : "Read error", - msg, NULL); + edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg); } /* Check correctable errors */ @@ -686,16 +685,13 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci, /* Form out message */ snprintf(msg, sizeof(msg), - "Rank=%d Bank=%d RDWR=%s RAS=%d " + "(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d " "CAS=%d, CE Err=0x%x (%s))", branch >> 1, bank, rdwr ? "Write" : "Read", ras, cas, ce_errors, specific); /* Call the helper to output message */ - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0, 0, - channel >> 1, channel % 2, rank, - rdwr ? "Write error" : "Read error", - msg, NULL); + edac_mc_handle_fbd_ce(mci, rank, channel, msg); } if (!misc_messages) @@ -735,12 +731,11 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci, /* Form out message */ snprintf(msg, sizeof(msg), - "Err=%#x (%s)", misc_errors, specific); + "(Branch=%d Err=%#x (%s))", branch >> 1, + misc_errors, specific); /* Call the helper to output message */ - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0, 0, - branch >> 1, -1, -1, - "Misc error", msg, NULL); + edac_mc_handle_fbd_ce(mci, 0, 0, msg); } } @@ -961,14 +956,14 @@ static int determine_amb_present_reg(struct i5000_pvt *pvt, int channel) * * return the proper MTR register as determine by the csrow and channel desired */ -static int determine_mtr(struct i5000_pvt *pvt, int slot, int channel) +static int determine_mtr(struct i5000_pvt *pvt, int csrow, int channel) { int mtr; if (channel < CHANNELS_PER_BRANCH) - mtr = pvt->b0_mtr[slot]; + mtr = pvt->b0_mtr[csrow >> 1]; else - mtr = pvt->b1_mtr[slot]; + mtr = pvt->b1_mtr[csrow >> 1]; return mtr; } @@ -993,34 +988,37 @@ static void decode_mtr(int slot_row, u16 mtr) debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]); } -static void handle_channel(struct i5000_pvt *pvt, int slot, int channel, +static void handle_channel(struct i5000_pvt *pvt, int csrow, int channel, struct i5000_dimm_info *dinfo) { int mtr; int amb_present_reg; int addrBits; - mtr = determine_mtr(pvt, slot, channel); + mtr = determine_mtr(pvt, csrow, channel); if (MTR_DIMMS_PRESENT(mtr)) { amb_present_reg = determine_amb_present_reg(pvt, channel); - /* Determine if there is a DIMM present in this DIMM slot */ - if (amb_present_reg) { + /* Determine if there is a DIMM present in this DIMM slot */ + if (amb_present_reg & (1 << (csrow >> 1))) { dinfo->dual_rank = MTR_DIMM_RANK(mtr); - /* Start with the number of bits for a Bank - * on the DRAM */ - addrBits = MTR_DRAM_BANKS_ADDR_BITS(mtr); - /* Add the number of ROW bits */ - addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr); - /* add the number of COLUMN bits */ - addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr); - - addrBits += 6; /* add 64 bits per DIMM */ - addrBits -= 20; /* divide by 2^^20 */ - addrBits -= 3; /* 8 bits per bytes */ - - dinfo->megabytes = 1 << addrBits; + if (!((dinfo->dual_rank == 0) && + ((csrow & 0x1) == 0x1))) { + /* Start with the number of bits for a Bank + * on the DRAM */ + addrBits = MTR_DRAM_BANKS_ADDR_BITS(mtr); + /* Add thenumber of ROW bits */ + addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr); + /* add the number of COLUMN bits */ + addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr); + + addrBits += 6; /* add 64 bits per DIMM */ + addrBits -= 20; /* divide by 2^^20 */ + addrBits -= 3; /* 8 bits per bytes */ + + dinfo->megabytes = 1 << addrBits; + } } } } @@ -1034,9 +1032,10 @@ static void handle_channel(struct i5000_pvt *pvt, int slot, int channel, static void calculate_dimm_size(struct i5000_pvt *pvt) { struct i5000_dimm_info *dinfo; - int slot, channel, branch; + int csrow, max_csrows; char *p, *mem_buffer; int space, n; + int channel; /* ================= Generate some debug output ================= */ space = PAGE_SIZE; @@ -1047,17 +1046,22 @@ static void calculate_dimm_size(struct i5000_pvt *pvt) return; } - /* Scan all the actual slots + n = snprintf(p, space, "\n"); + p += n; + space -= n; + + /* Scan all the actual CSROWS (which is # of DIMMS * 2) * and calculate the information for each DIMM - * Start with the highest slot first, to display it first - * and work toward the 0th slot + * Start with the highest csrow first, to display it first + * and work toward the 0th csrow */ - for (slot = pvt->maxdimmperch - 1; slot >= 0; slot--) { + max_csrows = pvt->maxdimmperch * 2; + for (csrow = max_csrows - 1; csrow >= 0; csrow--) { - /* on an odd slot, first output a 'boundary' marker, + /* on an odd csrow, first output a 'boundary' marker, * then reset the message buffer */ - if (slot & 0x1) { - n = snprintf(p, space, "--------------------------" + if (csrow & 0x1) { + n = snprintf(p, space, "---------------------------" "--------------------------------"); p += n; space -= n; @@ -1065,39 +1069,30 @@ static void calculate_dimm_size(struct i5000_pvt *pvt) p = mem_buffer; space = PAGE_SIZE; } - n = snprintf(p, space, "slot %2d ", slot); + n = snprintf(p, space, "csrow %2d ", csrow); p += n; space -= n; for (channel = 0; channel < pvt->maxch; channel++) { - dinfo = &pvt->dimm_info[slot][channel]; - handle_channel(pvt, slot, channel, dinfo); - if (dinfo->megabytes) - n = snprintf(p, space, "%4d MB %dR| ", - dinfo->megabytes, dinfo->dual_rank + 1); - else - n = snprintf(p, space, "%4d MB | ", 0); + dinfo = &pvt->dimm_info[csrow][channel]; + handle_channel(pvt, csrow, channel, dinfo); + n = snprintf(p, space, "%4d MB | ", dinfo->megabytes); p += n; space -= n; } + n = snprintf(p, space, "\n"); p += n; space -= n; - debugf2("%s\n", mem_buffer); - p = mem_buffer; - space = PAGE_SIZE; } /* Output the last bottom 'boundary' marker */ - n = snprintf(p, space, "--------------------------" - "--------------------------------"); + n = snprintf(p, space, "---------------------------" + "--------------------------------\n"); p += n; space -= n; - debugf2("%s\n", mem_buffer); - p = mem_buffer; - space = PAGE_SIZE; /* now output the 'channel' labels */ - n = snprintf(p, space, " "); + n = snprintf(p, space, " "); p += n; space -= n; for (channel = 0; channel < pvt->maxch; channel++) { @@ -1105,17 +1100,9 @@ static void calculate_dimm_size(struct i5000_pvt *pvt) p += n; space -= n; } - debugf2("%s\n", mem_buffer); - p = mem_buffer; - space = PAGE_SIZE; - - n = snprintf(p, space, " "); + n = snprintf(p, space, "\n"); p += n; - for (branch = 0; branch < MAX_BRANCHES; branch++) { - n = snprintf(p, space, " branch %d | ", branch); - p += n; - space -= n; - } + space -= n; /* output the last message and free buffer */ debugf2("%s\n", mem_buffer); @@ -1248,13 +1235,13 @@ static void i5000_get_mc_regs(struct mem_ctl_info *mci) static int i5000_init_csrows(struct mem_ctl_info *mci) { struct i5000_pvt *pvt; - struct dimm_info *dimm; + struct csrow_info *p_csrow; int empty, channel_count; int max_csrows; - int mtr; + int mtr, mtr1; int csrow_megs; int channel; - int slot; + int csrow; pvt = mci->pvt_info; @@ -1263,41 +1250,44 @@ static int i5000_init_csrows(struct mem_ctl_info *mci) empty = 1; /* Assume NO memory */ - /* - * FIXME: The memory layout used to map slot/channel into the - * real memory architecture is weird: branch+slot are "csrows" - * and channel is channel. That required an extra array (dimm_info) - * to map the dimms. A good cleanup would be to remove this array, - * and do a loop here with branch, channel, slot - */ - for (slot = 0; slot < max_csrows; slot++) { - for (channel = 0; channel < pvt->maxch; channel++) { - - mtr = determine_mtr(pvt, slot, channel); + for (csrow = 0; csrow < max_csrows; csrow++) { + p_csrow = &mci->csrows[csrow]; - if (!MTR_DIMMS_PRESENT(mtr)) - continue; + p_csrow->csrow_idx = csrow; - dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, mci->n_layers, - channel / MAX_BRANCHES, - channel % MAX_BRANCHES, slot); + /* use branch 0 for the basis */ + mtr = pvt->b0_mtr[csrow >> 1]; + mtr1 = pvt->b1_mtr[csrow >> 1]; - csrow_megs = pvt->dimm_info[slot][channel].megabytes; - dimm->grain = 8; + /* if no DIMMS on this row, continue */ + if (!MTR_DIMMS_PRESENT(mtr) && !MTR_DIMMS_PRESENT(mtr1)) + continue; - /* Assume DDR2 for now */ - dimm->mtype = MEM_FB_DDR2; + /* FAKE OUT VALUES, FIXME */ + p_csrow->first_page = 0 + csrow * 20; + p_csrow->last_page = 9 + csrow * 20; + p_csrow->page_mask = 0xFFF; - /* ask what device type on this row */ - if (MTR_DRAM_WIDTH(mtr)) - dimm->dtype = DEV_X8; - else - dimm->dtype = DEV_X4; + p_csrow->grain = 8; - dimm->edac_mode = EDAC_S8ECD8ED; - dimm->nr_pages = csrow_megs << 8; + csrow_megs = 0; + for (channel = 0; channel < pvt->maxch; channel++) { + csrow_megs += pvt->dimm_info[csrow][channel].megabytes; } + p_csrow->nr_pages = csrow_megs << 8; + + /* Assume DDR2 for now */ + p_csrow->mtype = MEM_FB_DDR2; + + /* ask what device type on this row */ + if (MTR_DRAM_WIDTH(mtr)) + p_csrow->dtype = DEV_X8; + else + p_csrow->dtype = DEV_X4; + + p_csrow->edac_mode = EDAC_S8ECD8ED; + empty = 0; } @@ -1327,7 +1317,7 @@ static void i5000_enable_error_reporting(struct mem_ctl_info *mci) } /* - * i5000_get_dimm_and_channel_counts(pdev, &nr_csrows, &num_channels) + * i5000_get_dimm_and_channel_counts(pdev, &num_csrows, &num_channels) * * ask the device how many channels are present and how many CSROWS * as well @@ -1342,7 +1332,7 @@ static void i5000_get_dimm_and_channel_counts(struct pci_dev *pdev, * supported on this memory controller */ pci_read_config_byte(pdev, MAXDIMMPERCH, &value); - *num_dimms_per_channel = (int)value; + *num_dimms_per_channel = (int)value *2; pci_read_config_byte(pdev, MAXCH, &value); *num_channels = (int)value; @@ -1358,10 +1348,10 @@ static void i5000_get_dimm_and_channel_counts(struct pci_dev *pdev, static int i5000_probe1(struct pci_dev *pdev, int dev_idx) { struct mem_ctl_info *mci; - struct edac_mc_layer layers[3]; struct i5000_pvt *pvt; int num_channels; int num_dimms_per_channel; + int num_csrows; debugf0("MC: %s: %s(), pdev bus %u dev=0x%x fn=0x%x\n", __FILE__, __func__, @@ -1387,22 +1377,14 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx) */ i5000_get_dimm_and_channel_counts(pdev, &num_dimms_per_channel, &num_channels); + num_csrows = num_dimms_per_channel * 2; - debugf0("MC: %s(): Number of Branches=2 Channels= %d DIMMS= %d\n", - __func__, num_channels, num_dimms_per_channel); + debugf0("MC: %s(): Number of - Channels= %d DIMMS= %d CSROWS= %d\n", + __func__, num_channels, num_dimms_per_channel, num_csrows); /* allocate a new MC control structure */ + mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); - layers[0].type = EDAC_MC_LAYER_BRANCH; - layers[0].size = MAX_BRANCHES; - layers[0].is_virt_csrow = false; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = num_channels / MAX_BRANCHES; - layers[1].is_virt_csrow = false; - layers[2].type = EDAC_MC_LAYER_SLOT; - layers[2].size = num_dimms_per_channel; - layers[2].is_virt_csrow = true; - mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt)); if (mci == NULL) return -ENOMEM; diff --git a/trunk/drivers/edac/i5100_edac.c b/trunk/drivers/edac/i5100_edac.c index e9e7c2a29dc3..d500749464ea 100644 --- a/trunk/drivers/edac/i5100_edac.c +++ b/trunk/drivers/edac/i5100_edac.c @@ -14,11 +14,6 @@ * rows for each respective channel are laid out one after another, * the first half belonging to channel 0, the second half belonging * to channel 1. - * - * This driver is for DDR2 DIMMs, and it uses chip select to select among the - * several ranks. However, instead of showing memories as ranks, it outputs - * them as DIMM's. An internal table creates the association between ranks - * and DIMM's. */ #include #include @@ -415,6 +410,14 @@ static int i5100_csrow_to_chan(const struct mem_ctl_info *mci, int csrow) return csrow / priv->ranksperchan; } +static unsigned i5100_rank_to_csrow(const struct mem_ctl_info *mci, + int chan, int rank) +{ + const struct i5100_priv *priv = mci->pvt_info; + + return chan * priv->ranksperchan + rank; +} + static void i5100_handle_ce(struct mem_ctl_info *mci, int chan, unsigned bank, @@ -424,17 +427,17 @@ static void i5100_handle_ce(struct mem_ctl_info *mci, unsigned ras, const char *msg) { - char detail[80]; + const int csrow = i5100_rank_to_csrow(mci, chan, rank); - /* Form out message */ - snprintf(detail, sizeof(detail), - "bank %u, cas %u, ras %u\n", - bank, cas, ras); + printk(KERN_ERR + "CE chan %d, bank %u, rank %u, syndrome 0x%lx, " + "cas %u, ras %u, csrow %u, label \"%s\": %s\n", + chan, bank, rank, syndrome, cas, ras, + csrow, mci->csrows[csrow].channels[0].label, msg); - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - 0, 0, syndrome, - chan, rank, -1, - msg, detail, NULL); + mci->ce_count++; + mci->csrows[csrow].ce_count++; + mci->csrows[csrow].channels[0].ce_count++; } static void i5100_handle_ue(struct mem_ctl_info *mci, @@ -446,17 +449,16 @@ static void i5100_handle_ue(struct mem_ctl_info *mci, unsigned ras, const char *msg) { - char detail[80]; + const int csrow = i5100_rank_to_csrow(mci, chan, rank); - /* Form out message */ - snprintf(detail, sizeof(detail), - "bank %u, cas %u, ras %u\n", - bank, cas, ras); + printk(KERN_ERR + "UE chan %d, bank %u, rank %u, syndrome 0x%lx, " + "cas %u, ras %u, csrow %u, label \"%s\": %s\n", + chan, bank, rank, syndrome, cas, ras, + csrow, mci->csrows[csrow].channels[0].label, msg); - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - 0, 0, syndrome, - chan, rank, -1, - msg, detail, NULL); + mci->ue_count++; + mci->csrows[csrow].ue_count++; } static void i5100_read_log(struct mem_ctl_info *mci, int chan, @@ -833,10 +835,10 @@ static void __devinit i5100_init_interleaving(struct pci_dev *pdev, static void __devinit i5100_init_csrows(struct mem_ctl_info *mci) { int i; + unsigned long total_pages = 0UL; struct i5100_priv *priv = mci->pvt_info; - for (i = 0; i < mci->tot_dimms; i++) { - struct dimm_info *dimm; + for (i = 0; i < mci->nr_csrows; i++) { const unsigned long npages = i5100_npages(mci, i); const unsigned chan = i5100_csrow_to_chan(mci, i); const unsigned rank = i5100_csrow_to_rank(mci, i); @@ -844,23 +846,33 @@ static void __devinit i5100_init_csrows(struct mem_ctl_info *mci) if (!npages) continue; - dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, mci->n_layers, - chan, rank, 0); - - dimm->nr_pages = npages; - if (npages) { - dimm->grain = 32; - dimm->dtype = (priv->mtr[chan][rank].width == 4) ? - DEV_X4 : DEV_X8; - dimm->mtype = MEM_RDDR2; - dimm->edac_mode = EDAC_SECDED; - snprintf(dimm->label, sizeof(dimm->label), - "DIMM%u", - i5100_rank_to_slot(mci, chan, rank)); - } - - debugf2("dimm channel %d, rank %d, size %ld\n", - chan, rank, (long)PAGES_TO_MiB(npages)); + /* + * FIXME: these two are totally bogus -- I don't see how to + * map them correctly to this structure... + */ + mci->csrows[i].first_page = total_pages; + mci->csrows[i].last_page = total_pages + npages - 1; + mci->csrows[i].page_mask = 0UL; + + mci->csrows[i].nr_pages = npages; + mci->csrows[i].grain = 32; + mci->csrows[i].csrow_idx = i; + mci->csrows[i].dtype = + (priv->mtr[chan][rank].width == 4) ? DEV_X4 : DEV_X8; + mci->csrows[i].ue_count = 0; + mci->csrows[i].ce_count = 0; + mci->csrows[i].mtype = MEM_RDDR2; + mci->csrows[i].edac_mode = EDAC_SECDED; + mci->csrows[i].mci = mci; + mci->csrows[i].nr_channels = 1; + mci->csrows[i].channels[0].chan_idx = 0; + mci->csrows[i].channels[0].ce_count = 0; + mci->csrows[i].channels[0].csrow = mci->csrows + i; + snprintf(mci->csrows[i].channels[0].label, + sizeof(mci->csrows[i].channels[0].label), + "DIMM%u", i5100_rank_to_slot(mci, chan, rank)); + + total_pages += npages; } } @@ -869,7 +881,6 @@ static int __devinit i5100_init_one(struct pci_dev *pdev, { int rc; struct mem_ctl_info *mci; - struct edac_mc_layer layers[2]; struct i5100_priv *priv; struct pci_dev *ch0mm, *ch1mm; int ret = 0; @@ -930,14 +941,7 @@ static int __devinit i5100_init_one(struct pci_dev *pdev, goto bail_ch1; } - layers[0].type = EDAC_MC_LAYER_CHANNEL; - layers[0].size = 2; - layers[0].is_virt_csrow = false; - layers[1].type = EDAC_MC_LAYER_SLOT; - layers[1].size = ranksperch; - layers[1].is_virt_csrow = true; - mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, - sizeof(*priv)); + mci = edac_mc_alloc(sizeof(*priv), ranksperch * 2, 1, 0); if (!mci) { ret = -ENOMEM; goto bail_disable_ch1; diff --git a/trunk/drivers/edac/i5400_edac.c b/trunk/drivers/edac/i5400_edac.c index 6640c29e1885..1869a1018fb5 100644 --- a/trunk/drivers/edac/i5400_edac.c +++ b/trunk/drivers/edac/i5400_edac.c @@ -18,10 +18,6 @@ * Intel 5400 Chipset Memory Controller Hub (MCH) - Datasheet * http://developer.intel.com/design/chipsets/datashts/313070.htm * - * This Memory Controller manages DDR2 FB-DIMMs. It has 2 branches, each with - * 2 channels operating in lockstep no-mirror mode. Each channel can have up to - * 4 dimm's, each with up to 8GB. - * */ #include @@ -48,10 +44,12 @@ edac_mc_chipset_printk(mci, level, "i5400", fmt, ##arg) /* Limits for i5400 */ -#define MAX_BRANCHES 2 +#define NUM_MTRS_PER_BRANCH 4 #define CHANNELS_PER_BRANCH 2 -#define DIMMS_PER_CHANNEL 4 -#define MAX_CHANNELS (MAX_BRANCHES * CHANNELS_PER_BRANCH) +#define MAX_DIMMS_PER_CHANNEL NUM_MTRS_PER_BRANCH +#define MAX_CHANNELS 4 +/* max possible csrows per channel */ +#define MAX_CSROWS (MAX_DIMMS_PER_CHANNEL) /* Device 16, * Function 0: System Address @@ -349,16 +347,16 @@ struct i5400_pvt { u16 mir0, mir1; - u16 b0_mtr[DIMMS_PER_CHANNEL]; /* Memory Technlogy Reg */ + u16 b0_mtr[NUM_MTRS_PER_BRANCH]; /* Memory Technlogy Reg */ u16 b0_ambpresent0; /* Branch 0, Channel 0 */ u16 b0_ambpresent1; /* Brnach 0, Channel 1 */ - u16 b1_mtr[DIMMS_PER_CHANNEL]; /* Memory Technlogy Reg */ + u16 b1_mtr[NUM_MTRS_PER_BRANCH]; /* Memory Technlogy Reg */ u16 b1_ambpresent0; /* Branch 1, Channel 8 */ u16 b1_ambpresent1; /* Branch 1, Channel 1 */ /* DIMM information matrix, allocating architecture maximums */ - struct i5400_dimm_info dimm_info[DIMMS_PER_CHANNEL][MAX_CHANNELS]; + struct i5400_dimm_info dimm_info[MAX_CSROWS][MAX_CHANNELS]; /* Actual values for this controller */ int maxch; /* Max channels */ @@ -534,15 +532,13 @@ static void i5400_proccess_non_recoverable_info(struct mem_ctl_info *mci, int ras, cas; int errnum; char *type = NULL; - enum hw_event_mc_err_type tp_event = HW_EVENT_ERR_UNCORRECTED; if (!allErrors) return; /* if no error, return now */ - if (allErrors & ERROR_FAT_MASK) { + if (allErrors & ERROR_FAT_MASK) type = "FATAL"; - tp_event = HW_EVENT_ERR_FATAL; - } else if (allErrors & FERR_NF_UNCORRECTABLE) + else if (allErrors & FERR_NF_UNCORRECTABLE) type = "NON-FATAL uncorrected"; else type = "NON-FATAL recoverable"; @@ -560,7 +556,7 @@ static void i5400_proccess_non_recoverable_info(struct mem_ctl_info *mci, ras = nrec_ras(info); cas = nrec_cas(info); - debugf0("\t\tDIMM= %d Channels= %d,%d (Branch= %d " + debugf0("\t\tCSROW= %d Channels= %d,%d (Branch= %d " "DRAM Bank= %d Buffer ID = %d rdwr= %s ras= %d cas= %d)\n", rank, channel, channel + 1, branch >> 1, bank, buf_id, rdwr_str(rdwr), ras, cas); @@ -570,13 +566,13 @@ static void i5400_proccess_non_recoverable_info(struct mem_ctl_info *mci, /* Form out message */ snprintf(msg, sizeof(msg), - "Bank=%d Buffer ID = %d RAS=%d CAS=%d Err=0x%lx (%s)", - bank, buf_id, ras, cas, allErrors, error_name[errnum]); + "%s (Branch=%d DRAM-Bank=%d Buffer ID = %d RDWR=%s " + "RAS=%d CAS=%d %s Err=0x%lx (%s))", + type, branch >> 1, bank, buf_id, rdwr_str(rdwr), ras, cas, + type, allErrors, error_name[errnum]); - edac_mc_handle_error(tp_event, mci, 0, 0, 0, - branch >> 1, -1, rank, - rdwr ? "Write error" : "Read error", - msg, NULL); + /* Call the helper to output message */ + edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg); } /* @@ -634,7 +630,7 @@ static void i5400_process_nonfatal_error_info(struct mem_ctl_info *mci, /* Only 1 bit will be on */ errnum = find_first_bit(&allErrors, ARRAY_SIZE(error_name)); - debugf0("\t\tDIMM= %d Channel= %d (Branch %d " + debugf0("\t\tCSROW= %d Channel= %d (Branch %d " "DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n", rank, channel, branch >> 1, bank, rdwr_str(rdwr), ras, cas); @@ -646,10 +642,8 @@ static void i5400_process_nonfatal_error_info(struct mem_ctl_info *mci, branch >> 1, bank, rdwr_str(rdwr), ras, cas, allErrors, error_name[errnum]); - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0, 0, - branch >> 1, channel % 2, rank, - rdwr ? "Write error" : "Read error", - msg, NULL); + /* Call the helper to output message */ + edac_mc_handle_fbd_ce(mci, rank, channel, msg); return; } @@ -837,8 +831,8 @@ static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx) /* * determine_amb_present * - * the information is contained in DIMMS_PER_CHANNEL different - * registers determining which of the DIMMS_PER_CHANNEL requires + * the information is contained in NUM_MTRS_PER_BRANCH different + * registers determining which of the NUM_MTRS_PER_BRANCH requires * knowing which channel is in question * * 2 branches, each with 2 channels @@ -867,11 +861,11 @@ static int determine_amb_present_reg(struct i5400_pvt *pvt, int channel) } /* - * determine_mtr(pvt, dimm, channel) + * determine_mtr(pvt, csrow, channel) * - * return the proper MTR register as determine by the dimm and desired channel + * return the proper MTR register as determine by the csrow and desired channel */ -static int determine_mtr(struct i5400_pvt *pvt, int dimm, int channel) +static int determine_mtr(struct i5400_pvt *pvt, int csrow, int channel) { int mtr; int n; @@ -879,11 +873,11 @@ static int determine_mtr(struct i5400_pvt *pvt, int dimm, int channel) /* There is one MTR for each slot pair of FB-DIMMs, Each slot pair may be at branch 0 or branch 1. */ - n = dimm; + n = csrow; - if (n >= DIMMS_PER_CHANNEL) { - debugf0("ERROR: trying to access an invalid dimm: %d\n", - dimm); + if (n >= NUM_MTRS_PER_BRANCH) { + debugf0("ERROR: trying to access an invalid csrow: %d\n", + csrow); return 0; } @@ -919,19 +913,19 @@ static void decode_mtr(int slot_row, u16 mtr) debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]); } -static void handle_channel(struct i5400_pvt *pvt, int dimm, int channel, +static void handle_channel(struct i5400_pvt *pvt, int csrow, int channel, struct i5400_dimm_info *dinfo) { int mtr; int amb_present_reg; int addrBits; - mtr = determine_mtr(pvt, dimm, channel); + mtr = determine_mtr(pvt, csrow, channel); if (MTR_DIMMS_PRESENT(mtr)) { amb_present_reg = determine_amb_present_reg(pvt, channel); /* Determine if there is a DIMM present in this DIMM slot */ - if (amb_present_reg & (1 << dimm)) { + if (amb_present_reg & (1 << csrow)) { /* Start with the number of bits for a Bank * on the DRAM */ addrBits = MTR_DRAM_BANKS_ADDR_BITS(mtr); @@ -960,10 +954,10 @@ static void handle_channel(struct i5400_pvt *pvt, int dimm, int channel, static void calculate_dimm_size(struct i5400_pvt *pvt) { struct i5400_dimm_info *dinfo; - int dimm, max_dimms; + int csrow, max_csrows; char *p, *mem_buffer; int space, n; - int channel, branch; + int channel; /* ================= Generate some debug output ================= */ space = PAGE_SIZE; @@ -974,32 +968,32 @@ static void calculate_dimm_size(struct i5400_pvt *pvt) return; } - /* Scan all the actual DIMMS + /* Scan all the actual CSROWS * and calculate the information for each DIMM - * Start with the highest dimm first, to display it first - * and work toward the 0th dimm + * Start with the highest csrow first, to display it first + * and work toward the 0th csrow */ - max_dimms = pvt->maxdimmperch; - for (dimm = max_dimms - 1; dimm >= 0; dimm--) { + max_csrows = pvt->maxdimmperch; + for (csrow = max_csrows - 1; csrow >= 0; csrow--) { - /* on an odd dimm, first output a 'boundary' marker, + /* on an odd csrow, first output a 'boundary' marker, * then reset the message buffer */ - if (dimm & 0x1) { + if (csrow & 0x1) { n = snprintf(p, space, "---------------------------" - "-------------------------------"); + "--------------------------------"); p += n; space -= n; debugf2("%s\n", mem_buffer); p = mem_buffer; space = PAGE_SIZE; } - n = snprintf(p, space, "dimm %2d ", dimm); + n = snprintf(p, space, "csrow %2d ", csrow); p += n; space -= n; for (channel = 0; channel < pvt->maxch; channel++) { - dinfo = &pvt->dimm_info[dimm][channel]; - handle_channel(pvt, dimm, channel, dinfo); + dinfo = &pvt->dimm_info[csrow][channel]; + handle_channel(pvt, csrow, channel, dinfo); n = snprintf(p, space, "%4d MB | ", dinfo->megabytes); p += n; space -= n; @@ -1011,7 +1005,7 @@ static void calculate_dimm_size(struct i5400_pvt *pvt) /* Output the last bottom 'boundary' marker */ n = snprintf(p, space, "---------------------------" - "-------------------------------"); + "--------------------------------"); p += n; space -= n; debugf2("%s\n", mem_buffer); @@ -1019,7 +1013,7 @@ static void calculate_dimm_size(struct i5400_pvt *pvt) space = PAGE_SIZE; /* now output the 'channel' labels */ - n = snprintf(p, space, " "); + n = snprintf(p, space, " "); p += n; space -= n; for (channel = 0; channel < pvt->maxch; channel++) { @@ -1028,19 +1022,6 @@ static void calculate_dimm_size(struct i5400_pvt *pvt) space -= n; } - space -= n; - debugf2("%s\n", mem_buffer); - p = mem_buffer; - space = PAGE_SIZE; - - n = snprintf(p, space, " "); - p += n; - for (branch = 0; branch < MAX_BRANCHES; branch++) { - n = snprintf(p, space, " branch %d | ", branch); - p += n; - space -= n; - } - /* output the last message and free buffer */ debugf2("%s\n", mem_buffer); kfree(mem_buffer); @@ -1099,7 +1080,7 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci) debugf2("MIR1: limit= 0x%x WAY1= %u WAY0= %x\n", limit, way1, way0); /* Get the set of MTR[0-3] regs by each branch */ - for (slot_row = 0; slot_row < DIMMS_PER_CHANNEL; slot_row++) { + for (slot_row = 0; slot_row < NUM_MTRS_PER_BRANCH; slot_row++) { int where = MTR0 + (slot_row * sizeof(u16)); /* Branch 0 set of MTR registers */ @@ -1124,7 +1105,7 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci) /* Read and dump branch 0's MTRs */ debugf2("\nMemory Technology Registers:\n"); debugf2(" Branch 0:\n"); - for (slot_row = 0; slot_row < DIMMS_PER_CHANNEL; slot_row++) + for (slot_row = 0; slot_row < NUM_MTRS_PER_BRANCH; slot_row++) decode_mtr(slot_row, pvt->b0_mtr[slot_row]); pci_read_config_word(pvt->branch_0, AMBPRESENT_0, @@ -1141,7 +1122,7 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci) } else { /* Read and dump branch 1's MTRs */ debugf2(" Branch 1:\n"); - for (slot_row = 0; slot_row < DIMMS_PER_CHANNEL; slot_row++) + for (slot_row = 0; slot_row < NUM_MTRS_PER_BRANCH; slot_row++) decode_mtr(slot_row, pvt->b1_mtr[slot_row]); pci_read_config_word(pvt->branch_1, AMBPRESENT_0, @@ -1160,7 +1141,7 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci) } /* - * i5400_init_dimms Initialize the 'dimms' table within + * i5400_init_csrows Initialize the 'csrows' table within * the mci control structure with the * addressing of memory. * @@ -1168,68 +1149,64 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci) * 0 success * 1 no actual memory found on this MC */ -static int i5400_init_dimms(struct mem_ctl_info *mci) +static int i5400_init_csrows(struct mem_ctl_info *mci) { struct i5400_pvt *pvt; - struct dimm_info *dimm; - int ndimms, channel_count; - int max_dimms; + struct csrow_info *p_csrow; + int empty, channel_count; + int max_csrows; int mtr; - int size_mb; - int channel, slot; + int csrow_megs; + int channel; + int csrow; pvt = mci->pvt_info; channel_count = pvt->maxch; - max_dimms = pvt->maxdimmperch; + max_csrows = pvt->maxdimmperch; - ndimms = 0; + empty = 1; /* Assume NO memory */ - /* - * FIXME: remove pvt->dimm_info[slot][channel] and use the 3 - * layers here. - */ - for (channel = 0; channel < mci->layers[0].size * mci->layers[1].size; - channel++) { - for (slot = 0; slot < mci->layers[2].size; slot++) { - mtr = determine_mtr(pvt, slot, channel); - - /* if no DIMMS on this slot, continue */ - if (!MTR_DIMMS_PRESENT(mtr)) - continue; - - dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, mci->n_layers, - channel / 2, channel % 2, slot); - - size_mb = pvt->dimm_info[slot][channel].megabytes; - - debugf2("%s: dimm%zd (branch %d channel %d slot %d): %d.%03d GB\n", - __func__, dimm - mci->dimms, - channel / 2, channel % 2, slot, - size_mb / 1000, size_mb % 1000); - - dimm->nr_pages = size_mb << 8; - dimm->grain = 8; - dimm->dtype = MTR_DRAM_WIDTH(mtr) ? DEV_X8 : DEV_X4; - dimm->mtype = MEM_FB_DDR2; - /* - * The eccc mechanism is SDDC (aka SECC), with - * is similar to Chipkill. - */ - dimm->edac_mode = MTR_DRAM_WIDTH(mtr) ? - EDAC_S8ECD8ED : EDAC_S4ECD4ED; - ndimms++; - } - } + for (csrow = 0; csrow < max_csrows; csrow++) { + p_csrow = &mci->csrows[csrow]; - /* - * When just one memory is provided, it should be at location (0,0,0). - * With such single-DIMM mode, the SDCC algorithm degrades to SECDEC+. - */ - if (ndimms == 1) - mci->dimms[0].edac_mode = EDAC_SECDED; + p_csrow->csrow_idx = csrow; - return (ndimms == 0); + /* use branch 0 for the basis */ + mtr = determine_mtr(pvt, csrow, 0); + + /* if no DIMMS on this row, continue */ + if (!MTR_DIMMS_PRESENT(mtr)) + continue; + + /* FAKE OUT VALUES, FIXME */ + p_csrow->first_page = 0 + csrow * 20; + p_csrow->last_page = 9 + csrow * 20; + p_csrow->page_mask = 0xFFF; + + p_csrow->grain = 8; + + csrow_megs = 0; + for (channel = 0; channel < pvt->maxch; channel++) + csrow_megs += pvt->dimm_info[csrow][channel].megabytes; + + p_csrow->nr_pages = csrow_megs << 8; + + /* Assume DDR2 for now */ + p_csrow->mtype = MEM_FB_DDR2; + + /* ask what device type on this row */ + if (MTR_DRAM_WIDTH(mtr)) + p_csrow->dtype = DEV_X8; + else + p_csrow->dtype = DEV_X4; + + p_csrow->edac_mode = EDAC_S8ECD8ED; + + empty = 0; + } + + return empty; } /* @@ -1265,7 +1242,9 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx) { struct mem_ctl_info *mci; struct i5400_pvt *pvt; - struct edac_mc_layer layers[3]; + int num_channels; + int num_dimms_per_channel; + int num_csrows; if (dev_idx >= ARRAY_SIZE(i5400_devs)) return -EINVAL; @@ -1279,21 +1258,23 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx) if (PCI_FUNC(pdev->devfn) != 0) return -ENODEV; - /* - * allocate a new MC control structure - * - * This drivers uses the DIMM slot as "csrow" and the rest as "channel". + /* As we don't have a motherboard identification routine to determine + * actual number of slots/dimms per channel, we thus utilize the + * resource as specified by the chipset. Thus, we might have + * have more DIMMs per channel than actually on the mobo, but this + * allows the driver to support up to the chipset max, without + * some fancy mobo determination. */ - layers[0].type = EDAC_MC_LAYER_BRANCH; - layers[0].size = MAX_BRANCHES; - layers[0].is_virt_csrow = false; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = CHANNELS_PER_BRANCH; - layers[1].is_virt_csrow = false; - layers[2].type = EDAC_MC_LAYER_SLOT; - layers[2].size = DIMMS_PER_CHANNEL; - layers[2].is_virt_csrow = true; - mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt)); + num_dimms_per_channel = MAX_DIMMS_PER_CHANNEL; + num_channels = MAX_CHANNELS; + num_csrows = num_dimms_per_channel; + + debugf0("MC: %s(): Number of - Channels= %d DIMMS= %d CSROWS= %d\n", + __func__, num_channels, num_dimms_per_channel, num_csrows); + + /* allocate a new MC control structure */ + mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); + if (mci == NULL) return -ENOMEM; @@ -1303,8 +1284,8 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx) pvt = mci->pvt_info; pvt->system_address = pdev; /* Record this device in our private */ - pvt->maxch = MAX_CHANNELS; - pvt->maxdimmperch = DIMMS_PER_CHANNEL; + pvt->maxch = num_channels; + pvt->maxdimmperch = num_dimms_per_channel; /* 'get' the pci devices we want to reserve for our use */ if (i5400_get_devices(mci, dev_idx)) @@ -1326,13 +1307,13 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx) /* Set the function pointer to an actual operation function */ mci->edac_check = i5400_check_error; - /* initialize the MC control structure 'dimms' table + /* initialize the MC control structure 'csrows' table * with the mapping and control information */ - if (i5400_init_dimms(mci)) { + if (i5400_init_csrows(mci)) { debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n" - " because i5400_init_dimms() returned nonzero " + " because i5400_init_csrows() returned nonzero " "value\n"); - mci->edac_cap = EDAC_FLAG_NONE; /* no dimms found */ + mci->edac_cap = EDAC_FLAG_NONE; /* no csrows found */ } else { debugf1("MC: Enable error reporting now\n"); i5400_enable_error_reporting(mci); diff --git a/trunk/drivers/edac/i7300_edac.c b/trunk/drivers/edac/i7300_edac.c index 97c22fd650ee..3bafa3bca148 100644 --- a/trunk/drivers/edac/i7300_edac.c +++ b/trunk/drivers/edac/i7300_edac.c @@ -464,14 +464,17 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci) FERR_FAT_FBD, error_reg); snprintf(pvt->tmp_prt_buffer, PAGE_SIZE, - "Bank=%d RAS=%d CAS=%d Err=0x%lx (%s))", - bank, ras, cas, errors, specific); - - edac_mc_handle_error(HW_EVENT_ERR_FATAL, mci, 0, 0, 0, - branch, -1, rank, - is_wr ? "Write error" : "Read error", - pvt->tmp_prt_buffer, NULL); - + "FATAL (Branch=%d DRAM-Bank=%d %s " + "RAS=%d CAS=%d Err=0x%lx (%s))", + branch, bank, + is_wr ? "RDWR" : "RD", + ras, cas, + errors, specific); + + /* Call the helper to output message */ + edac_mc_handle_fbd_ue(mci, rank, branch << 1, + (branch << 1) + 1, + pvt->tmp_prt_buffer); } /* read in the 1st NON-FATAL error register */ @@ -510,14 +513,23 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci) /* Form out message */ snprintf(pvt->tmp_prt_buffer, PAGE_SIZE, - "DRAM-Bank=%d RAS=%d CAS=%d, Err=0x%lx (%s))", - bank, ras, cas, errors, specific); - - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0, - syndrome, - branch >> 1, channel % 2, rank, - is_wr ? "Write error" : "Read error", - pvt->tmp_prt_buffer, NULL); + "Corrected error (Branch=%d, Channel %d), " + " DRAM-Bank=%d %s " + "RAS=%d CAS=%d, CE Err=0x%lx, Syndrome=0x%08x(%s))", + branch, channel, + bank, + is_wr ? "RDWR" : "RD", + ras, cas, + errors, syndrome, specific); + + /* + * Call the helper to output message + * NOTE: Errors are reported per-branch, and not per-channel + * Currently, we don't know how to identify the right + * channel. + */ + edac_mc_handle_fbd_ce(mci, rank, channel, + pvt->tmp_prt_buffer); } return; } @@ -605,7 +617,8 @@ static void i7300_enable_error_reporting(struct mem_ctl_info *mci) static int decode_mtr(struct i7300_pvt *pvt, int slot, int ch, int branch, struct i7300_dimm_info *dinfo, - struct dimm_info *dimm) + struct csrow_info *p_csrow, + u32 *nr_pages) { int mtr, ans, addrBits, channel; @@ -637,6 +650,7 @@ static int decode_mtr(struct i7300_pvt *pvt, addrBits -= 3; /* 8 bits per bytes */ dinfo->megabytes = 1 << addrBits; + *nr_pages = dinfo->megabytes << 8; debugf2("\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr)); @@ -649,6 +663,11 @@ static int decode_mtr(struct i7300_pvt *pvt, debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]); debugf2("\t\tSIZE: %d MB\n", dinfo->megabytes); + p_csrow->grain = 8; + p_csrow->mtype = MEM_FB_DDR2; + p_csrow->csrow_idx = slot; + p_csrow->page_mask = 0; + /* * The type of error detection actually depends of the * mode of operation. When it is just one single memory chip, at @@ -658,18 +677,15 @@ static int decode_mtr(struct i7300_pvt *pvt, * See datasheet Sections 7.3.6 to 7.3.8 */ - dimm->nr_pages = MiB_TO_PAGES(dinfo->megabytes); - dimm->grain = 8; - dimm->mtype = MEM_FB_DDR2; if (IS_SINGLE_MODE(pvt->mc_settings_a)) { - dimm->edac_mode = EDAC_SECDED; + p_csrow->edac_mode = EDAC_SECDED; debugf2("\t\tECC code is 8-byte-over-32-byte SECDED+ code\n"); } else { debugf2("\t\tECC code is on Lockstep mode\n"); if (MTR_DRAM_WIDTH(mtr) == 8) - dimm->edac_mode = EDAC_S8ECD8ED; + p_csrow->edac_mode = EDAC_S8ECD8ED; else - dimm->edac_mode = EDAC_S4ECD4ED; + p_csrow->edac_mode = EDAC_S4ECD4ED; } /* ask what device type on this row */ @@ -678,9 +694,9 @@ static int decode_mtr(struct i7300_pvt *pvt, IS_SCRBALGO_ENHANCED(pvt->mc_settings) ? "enhanced" : "normal"); - dimm->dtype = DEV_X8; + p_csrow->dtype = DEV_X8; } else - dimm->dtype = DEV_X4; + p_csrow->dtype = DEV_X4; return mtr; } @@ -758,10 +774,11 @@ static int i7300_init_csrows(struct mem_ctl_info *mci) { struct i7300_pvt *pvt; struct i7300_dimm_info *dinfo; + struct csrow_info *p_csrow; int rc = -ENODEV; int mtr; int ch, branch, slot, channel; - struct dimm_info *dimm; + u32 last_page = 0, nr_pages; pvt = mci->pvt_info; @@ -792,23 +809,25 @@ static int i7300_init_csrows(struct mem_ctl_info *mci) pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch], where, &pvt->mtr[slot][branch]); - for (ch = 0; ch < MAX_CH_PER_BRANCH; ch++) { + for (ch = 0; ch < MAX_BRANCHES; ch++) { int channel = to_channel(ch, branch); - dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, - mci->n_layers, branch, ch, slot); - dinfo = &pvt->dimm_info[slot][channel]; + p_csrow = &mci->csrows[slot]; mtr = decode_mtr(pvt, slot, ch, branch, - dinfo, dimm); - + dinfo, p_csrow, &nr_pages); /* if no DIMMS on this row, continue */ if (!MTR_DIMMS_PRESENT(mtr)) continue; - rc = 0; + /* Update per_csrow memory count */ + p_csrow->nr_pages += nr_pages; + p_csrow->first_page = last_page; + last_page += nr_pages; + p_csrow->last_page = last_page; + rc = 0; } } } @@ -1023,8 +1042,10 @@ static int __devinit i7300_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { struct mem_ctl_info *mci; - struct edac_mc_layer layers[3]; struct i7300_pvt *pvt; + int num_channels; + int num_dimms_per_channel; + int num_csrows; int rc; /* wake up device */ @@ -1041,17 +1062,23 @@ static int __devinit i7300_init_one(struct pci_dev *pdev, if (PCI_FUNC(pdev->devfn) != 0) return -ENODEV; + /* As we don't have a motherboard identification routine to determine + * actual number of slots/dimms per channel, we thus utilize the + * resource as specified by the chipset. Thus, we might have + * have more DIMMs per channel than actually on the mobo, but this + * allows the driver to support up to the chipset max, without + * some fancy mobo determination. + */ + num_dimms_per_channel = MAX_SLOTS; + num_channels = MAX_CHANNELS; + num_csrows = MAX_SLOTS * MAX_CHANNELS; + + debugf0("MC: %s(): Number of - Channels= %d DIMMS= %d CSROWS= %d\n", + __func__, num_channels, num_dimms_per_channel, num_csrows); + /* allocate a new MC control structure */ - layers[0].type = EDAC_MC_LAYER_BRANCH; - layers[0].size = MAX_BRANCHES; - layers[0].is_virt_csrow = false; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = MAX_CH_PER_BRANCH; - layers[1].is_virt_csrow = true; - layers[2].type = EDAC_MC_LAYER_SLOT; - layers[2].size = MAX_SLOTS; - layers[2].is_virt_csrow = true; - mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt)); + mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); + if (mci == NULL) return -ENOMEM; diff --git a/trunk/drivers/edac/i7core_edac.c b/trunk/drivers/edac/i7core_edac.c index d27778f65a5d..7f1dfcc4e597 100644 --- a/trunk/drivers/edac/i7core_edac.c +++ b/trunk/drivers/edac/i7core_edac.c @@ -221,9 +221,7 @@ struct i7core_inject { }; struct i7core_channel { - bool is_3dimms_present; - bool is_single_4rank; - bool has_4rank; + u32 ranks; u32 dimms; }; @@ -259,6 +257,7 @@ struct i7core_pvt { struct i7core_channel channel[NUM_CHANS]; int ce_count_available; + int csrow_map[NUM_CHANS][MAX_DIMMS]; /* ECC corrected errors counts per udimm */ unsigned long udimm_ce_count[MAX_DIMMS]; @@ -493,15 +492,116 @@ static void free_i7core_dev(struct i7core_dev *i7core_dev) /**************************************************************************** Memory check routines ****************************************************************************/ +static struct pci_dev *get_pdev_slot_func(u8 socket, unsigned slot, + unsigned func) +{ + struct i7core_dev *i7core_dev = get_i7core_dev(socket); + int i; + + if (!i7core_dev) + return NULL; + + for (i = 0; i < i7core_dev->n_devs; i++) { + if (!i7core_dev->pdev[i]) + continue; + + if (PCI_SLOT(i7core_dev->pdev[i]->devfn) == slot && + PCI_FUNC(i7core_dev->pdev[i]->devfn) == func) { + return i7core_dev->pdev[i]; + } + } + + return NULL; +} + +/** + * i7core_get_active_channels() - gets the number of channels and csrows + * @socket: Quick Path Interconnect socket + * @channels: Number of channels that will be returned + * @csrows: Number of csrows found + * + * Since EDAC core needs to know in advance the number of available channels + * and csrows, in order to allocate memory for csrows/channels, it is needed + * to run two similar steps. At the first step, implemented on this function, + * it checks the number of csrows/channels present at one socket. + * this is used in order to properly allocate the size of mci components. + * + * It should be noticed that none of the current available datasheets explain + * or even mention how csrows are seen by the memory controller. So, we need + * to add a fake description for csrows. + * So, this driver is attributing one DIMM memory for one csrow. + */ +static int i7core_get_active_channels(const u8 socket, unsigned *channels, + unsigned *csrows) +{ + struct pci_dev *pdev = NULL; + int i, j; + u32 status, control; + + *channels = 0; + *csrows = 0; + + pdev = get_pdev_slot_func(socket, 3, 0); + if (!pdev) { + i7core_printk(KERN_ERR, "Couldn't find socket %d fn 3.0!!!\n", + socket); + return -ENODEV; + } + + /* Device 3 function 0 reads */ + pci_read_config_dword(pdev, MC_STATUS, &status); + pci_read_config_dword(pdev, MC_CONTROL, &control); + + for (i = 0; i < NUM_CHANS; i++) { + u32 dimm_dod[3]; + /* Check if the channel is active */ + if (!(control & (1 << (8 + i)))) + continue; + + /* Check if the channel is disabled */ + if (status & (1 << i)) + continue; + + pdev = get_pdev_slot_func(socket, i + 4, 1); + if (!pdev) { + i7core_printk(KERN_ERR, "Couldn't find socket %d " + "fn %d.%d!!!\n", + socket, i + 4, 1); + return -ENODEV; + } + /* Devices 4-6 function 1 */ + pci_read_config_dword(pdev, + MC_DOD_CH_DIMM0, &dimm_dod[0]); + pci_read_config_dword(pdev, + MC_DOD_CH_DIMM1, &dimm_dod[1]); + pci_read_config_dword(pdev, + MC_DOD_CH_DIMM2, &dimm_dod[2]); -static int get_dimm_config(struct mem_ctl_info *mci) + (*channels)++; + + for (j = 0; j < 3; j++) { + if (!DIMM_PRESENT(dimm_dod[j])) + continue; + (*csrows)++; + } + } + + debugf0("Number of active channels on socket %d: %d\n", + socket, *channels); + + return 0; +} + +static int get_dimm_config(const struct mem_ctl_info *mci) { struct i7core_pvt *pvt = mci->pvt_info; + struct csrow_info *csr; struct pci_dev *pdev; int i, j; + int csrow = 0; + unsigned long last_page = 0; enum edac_type mode; enum mem_type mtype; - struct dimm_info *dimm; /* Get data from the MC register, function 0 */ pdev = pvt->pci_mcr[0]; @@ -557,20 +657,21 @@ static int get_dimm_config(struct mem_ctl_info *mci) pci_read_config_dword(pvt->pci_ch[i][0], MC_CHANNEL_DIMM_INIT_PARAMS, &data); - - if (data & THREE_DIMMS_PRESENT) - pvt->channel[i].is_3dimms_present = true; - - if (data & SINGLE_QUAD_RANK_PRESENT) - pvt->channel[i].is_single_4rank = true; - - if (data & QUAD_RANK_PRESENT) - pvt->channel[i].has_4rank = true; + pvt->channel[i].ranks = (data & QUAD_RANK_PRESENT) ? + 4 : 2; if (data & REGISTERED_DIMM) mtype = MEM_RDDR3; else mtype = MEM_DDR3; +#if 0 + if (data & THREE_DIMMS_PRESENT) + pvt->channel[i].dimms = 3; + else if (data & SINGLE_QUAD_RANK_PRESENT) + pvt->channel[i].dimms = 1; + else + pvt->channel[i].dimms = 2; +#endif /* Devices 4-6 function 1 */ pci_read_config_dword(pvt->pci_ch[i][1], @@ -581,13 +682,11 @@ static int get_dimm_config(struct mem_ctl_info *mci) MC_DOD_CH_DIMM2, &dimm_dod[2]); debugf0("Ch%d phy rd%d, wr%d (0x%08x): " - "%s%s%s%cDIMMs\n", + "%d ranks, %cDIMMs\n", i, RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i), data, - pvt->channel[i].is_3dimms_present ? "3DIMMS " : "", - pvt->channel[i].is_3dimms_present ? "SINGLE_4R " : "", - pvt->channel[i].has_4rank ? "HAS_4R " : "", + pvt->channel[i].ranks, (data & REGISTERED_DIMM) ? 'R' : 'U'); for (j = 0; j < 3; j++) { @@ -597,8 +696,6 @@ static int get_dimm_config(struct mem_ctl_info *mci) if (!DIMM_PRESENT(dimm_dod[j])) continue; - dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, mci->n_layers, - i, j, 0); banks = numbank(MC_DOD_NUMBANK(dimm_dod[j])); ranks = numrank(MC_DOD_NUMRANK(dimm_dod[j])); rows = numrow(MC_DOD_NUMROW(dimm_dod[j])); @@ -607,6 +704,8 @@ static int get_dimm_config(struct mem_ctl_info *mci) /* DDR3 has 8 I/O banks */ size = (rows * cols * banks * ranks) >> (20 - 3); + pvt->channel[i].dimms++; + debugf0("\tdimm %d %d Mb offset: %x, " "bank: %d, rank: %d, row: %#x, col: %#x\n", j, size, @@ -615,28 +714,44 @@ static int get_dimm_config(struct mem_ctl_info *mci) npages = MiB_TO_PAGES(size); - dimm->nr_pages = npages; + csr = &mci->csrows[csrow]; + csr->first_page = last_page + 1; + last_page += npages; + csr->last_page = last_page; + csr->nr_pages = npages; + + csr->page_mask = 0; + csr->grain = 8; + csr->csrow_idx = csrow; + csr->nr_channels = 1; + + csr->channels[0].chan_idx = i; + csr->channels[0].ce_count = 0; + + pvt->csrow_map[i][j] = csrow; switch (banks) { case 4: - dimm->dtype = DEV_X4; + csr->dtype = DEV_X4; break; case 8: - dimm->dtype = DEV_X8; + csr->dtype = DEV_X8; break; case 16: - dimm->dtype = DEV_X16; + csr->dtype = DEV_X16; break; default: - dimm->dtype = DEV_UNKNOWN; + csr->dtype = DEV_UNKNOWN; } - snprintf(dimm->label, sizeof(dimm->label), - "CPU#%uChannel#%u_DIMM#%u", - pvt->i7core_dev->socket, i, j); - dimm->grain = 8; - dimm->edac_mode = mode; - dimm->mtype = mtype; + csr->edac_mode = mode; + csr->mtype = mtype; + snprintf(csr->channels[0].label, + sizeof(csr->channels[0].label), + "CPU#%uChannel#%u_DIMM#%u", + pvt->i7core_dev->socket, i, j); + + csrow++; } pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]); @@ -1452,16 +1567,22 @@ static int mci_bind_devs(struct mem_ctl_info *mci, /**************************************************************************** Error check routines ****************************************************************************/ -static void i7core_rdimm_update_errcount(struct mem_ctl_info *mci, +static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci, const int chan, const int dimm, const int add) { - int i; + char *msg; + struct i7core_pvt *pvt = mci->pvt_info; + int row = pvt->csrow_map[chan][dimm], i; for (i = 0; i < add; i++) { - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0, 0, - chan, dimm, -1, "error", "", NULL); + msg = kasprintf(GFP_KERNEL, "Corrected error " + "(Socket=%d channel=%d dimm=%d)", + pvt->i7core_dev->socket, chan, dimm); + + edac_mc_handle_fbd_ce(mci, row, 0, msg); + kfree (msg); } } @@ -1502,11 +1623,11 @@ static void i7core_rdimm_update_ce_count(struct mem_ctl_info *mci, /*updated the edac core */ if (add0 != 0) - i7core_rdimm_update_errcount(mci, chan, 0, add0); + i7core_rdimm_update_csrow(mci, chan, 0, add0); if (add1 != 0) - i7core_rdimm_update_errcount(mci, chan, 1, add1); + i7core_rdimm_update_csrow(mci, chan, 1, add1); if (add2 != 0) - i7core_rdimm_update_errcount(mci, chan, 2, add2); + i7core_rdimm_update_csrow(mci, chan, 2, add2); } @@ -1626,30 +1747,20 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, const struct mce *m) { struct i7core_pvt *pvt = mci->pvt_info; - char *type, *optype, *err, msg[80]; - enum hw_event_mc_err_type tp_event; + char *type, *optype, *err, *msg; unsigned long error = m->status & 0x1ff0000l; - bool uncorrected_error = m->mcgstatus & 1ll << 61; - bool ripv = m->mcgstatus & 1; u32 optypenum = (m->status >> 4) & 0x07; u32 core_err_cnt = (m->status >> 38) & 0x7fff; u32 dimm = (m->misc >> 16) & 0x3; u32 channel = (m->misc >> 18) & 0x3; u32 syndrome = m->misc >> 32; u32 errnum = find_first_bit(&error, 32); + int csrow; - if (uncorrected_error) { - if (ripv) { - type = "FATAL"; - tp_event = HW_EVENT_ERR_FATAL; - } else { - type = "NON_FATAL"; - tp_event = HW_EVENT_ERR_UNCORRECTED; - } - } else { - type = "CORRECTED"; - tp_event = HW_EVENT_ERR_CORRECTED; - } + if (m->mcgstatus & 1) + type = "FATAL"; + else + type = "NON_FATAL"; switch (optypenum) { case 0: @@ -1704,20 +1815,27 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, err = "unknown"; } - snprintf(msg, sizeof(msg), "count=%d %s", core_err_cnt, optype); + /* FIXME: should convert addr into bank and rank information */ + msg = kasprintf(GFP_ATOMIC, + "%s (addr = 0x%08llx, cpu=%d, Dimm=%d, Channel=%d, " + "syndrome=0x%08x, count=%d, Err=%08llx:%08llx (%s: %s))\n", + type, (long long) m->addr, m->cpu, dimm, channel, + syndrome, core_err_cnt, (long long)m->status, + (long long)m->misc, optype, err); - /* - * Call the helper to output message - * FIXME: what to do if core_err_cnt > 1? Currently, it generates - * only one event - */ - if (uncorrected_error || !pvt->is_registered) - edac_mc_handle_error(tp_event, mci, - m->addr >> PAGE_SHIFT, - m->addr & ~PAGE_MASK, - syndrome, - channel, dimm, -1, - err, msg, m); + debugf0("%s", msg); + + csrow = pvt->csrow_map[channel][dimm]; + + /* Call the helper to output message */ + if (m->mcgstatus & 1) + edac_mc_handle_fbd_ue(mci, csrow, 0, + 0 /* FIXME: should be channel here */, msg); + else if (!pvt->is_registered) + edac_mc_handle_fbd_ce(mci, csrow, + 0 /* FIXME: should be channel here */, msg); + + kfree(msg); } /* @@ -2134,19 +2252,15 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev) { struct mem_ctl_info *mci; struct i7core_pvt *pvt; - int rc; - struct edac_mc_layer layers[2]; + int rc, channels, csrows; - /* allocate a new MC control structure */ + /* Check the number of active and not disabled channels */ + rc = i7core_get_active_channels(i7core_dev->socket, &channels, &csrows); + if (unlikely(rc < 0)) + return rc; - layers[0].type = EDAC_MC_LAYER_CHANNEL; - layers[0].size = NUM_CHANS; - layers[0].is_virt_csrow = false; - layers[1].type = EDAC_MC_LAYER_SLOT; - layers[1].size = MAX_DIMMS; - layers[1].is_virt_csrow = true; - mci = edac_mc_alloc(i7core_dev->socket, ARRAY_SIZE(layers), layers, - sizeof(*pvt)); + /* allocate a new MC control structure */ + mci = edac_mc_alloc(sizeof(*pvt), csrows, channels, i7core_dev->socket); if (unlikely(!mci)) return -ENOMEM; diff --git a/trunk/drivers/edac/i82443bxgx_edac.c b/trunk/drivers/edac/i82443bxgx_edac.c index 52072c28a8a6..3bf2b2f490e7 100644 --- a/trunk/drivers/edac/i82443bxgx_edac.c +++ b/trunk/drivers/edac/i82443bxgx_edac.c @@ -12,7 +12,7 @@ * 440GX fix by Jason Uhlenkott . * * Written with reference to 82443BX Host Bridge Datasheet: - * http://download.intel.com/design/chipsets/datashts/29063301.pdf + * http://download.intel.com/design/chipsets/datashts/29063301.pdf * references to this document given in []. * * This module doesn't support the 440LX, but it may be possible to @@ -156,19 +156,19 @@ static int i82443bxgx_edacmc_process_error_info(struct mem_ctl_info *mci, if (info->eap & I82443BXGX_EAP_OFFSET_SBE) { error_found = 1; if (handle_errors) - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - page, pageoffset, 0, - edac_mc_find_csrow_by_page(mci, page), - 0, -1, mci->ctl_name, "", NULL); + edac_mc_handle_ce(mci, page, pageoffset, + /* 440BX/GX don't make syndrome information + * available */ + 0, edac_mc_find_csrow_by_page(mci, page), 0, + mci->ctl_name); } if (info->eap & I82443BXGX_EAP_OFFSET_MBE) { error_found = 1; if (handle_errors) - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - page, pageoffset, 0, - edac_mc_find_csrow_by_page(mci, page), - 0, -1, mci->ctl_name, "", NULL); + edac_mc_handle_ue(mci, page, pageoffset, + edac_mc_find_csrow_by_page(mci, page), + mci->ctl_name); } return error_found; @@ -189,7 +189,6 @@ static void i82443bxgx_init_csrows(struct mem_ctl_info *mci, enum mem_type mtype) { struct csrow_info *csrow; - struct dimm_info *dimm; int index; u8 drbar, dramc; u32 row_base, row_high_limit, row_high_limit_last; @@ -198,8 +197,6 @@ static void i82443bxgx_init_csrows(struct mem_ctl_info *mci, row_high_limit_last = 0; for (index = 0; index < mci->nr_csrows; index++) { csrow = &mci->csrows[index]; - dimm = csrow->channels[0].dimm; - pci_read_config_byte(pdev, I82443BXGX_DRB + index, &drbar); debugf1("MC%d: %s: %s() Row=%d DRB = %#0x\n", mci->mc_idx, __FILE__, __func__, index, drbar); @@ -220,14 +217,14 @@ static void i82443bxgx_init_csrows(struct mem_ctl_info *mci, row_base = row_high_limit_last; csrow->first_page = row_base >> PAGE_SHIFT; csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1; - dimm->nr_pages = csrow->last_page - csrow->first_page + 1; + csrow->nr_pages = csrow->last_page - csrow->first_page + 1; /* EAP reports in 4kilobyte granularity [61] */ - dimm->grain = 1 << 12; - dimm->mtype = mtype; + csrow->grain = 1 << 12; + csrow->mtype = mtype; /* I don't think 440BX can tell you device type? FIXME? */ - dimm->dtype = DEV_UNKNOWN; + csrow->dtype = DEV_UNKNOWN; /* Mode is global to all rows on 440BX */ - dimm->edac_mode = edac_mode; + csrow->edac_mode = edac_mode; row_high_limit_last = row_high_limit; } } @@ -235,7 +232,6 @@ static void i82443bxgx_init_csrows(struct mem_ctl_info *mci, static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx) { struct mem_ctl_info *mci; - struct edac_mc_layer layers[2]; u8 dramc; u32 nbxcfg, ecc_mode; enum mem_type mtype; @@ -249,13 +245,8 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx) if (pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg)) return -EIO; - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = I82443BXGX_NR_CSROWS; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = I82443BXGX_NR_CHANS; - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0); + mci = edac_mc_alloc(0, I82443BXGX_NR_CSROWS, I82443BXGX_NR_CHANS, 0); + if (mci == NULL) return -ENOMEM; diff --git a/trunk/drivers/edac/i82860_edac.c b/trunk/drivers/edac/i82860_edac.c index 08045059d10b..c779092d18d1 100644 --- a/trunk/drivers/edac/i82860_edac.c +++ b/trunk/drivers/edac/i82860_edac.c @@ -99,7 +99,6 @@ static int i82860_process_error_info(struct mem_ctl_info *mci, struct i82860_error_info *info, int handle_errors) { - struct dimm_info *dimm; int row; if (!(info->errsts2 & 0x0003)) @@ -109,25 +108,18 @@ static int i82860_process_error_info(struct mem_ctl_info *mci, return 1; if ((info->errsts ^ info->errsts2) & 0x0003) { - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0, - -1, -1, -1, "UE overwrote CE", "", NULL); + edac_mc_handle_ce_no_info(mci, "UE overwrote CE"); info->errsts = info->errsts2; } info->eap >>= PAGE_SHIFT; row = edac_mc_find_csrow_by_page(mci, info->eap); - dimm = mci->csrows[row].channels[0].dimm; if (info->errsts & 0x0002) - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - info->eap, 0, 0, - dimm->location[0], dimm->location[1], -1, - "i82860 UE", "", NULL); + edac_mc_handle_ue(mci, info->eap, 0, row, "i82860 UE"); else - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - info->eap, 0, info->derrsyn, - dimm->location[0], dimm->location[1], -1, - "i82860 CE", "", NULL); + edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row, 0, + "i82860 UE"); return 1; } @@ -148,7 +140,6 @@ static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev) u16 value; u32 cumul_size; struct csrow_info *csrow; - struct dimm_info *dimm; int index; pci_read_config_word(pdev, I82860_MCHCFG, &mchcfg_ddim); @@ -162,8 +153,6 @@ static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev) */ for (index = 0; index < mci->nr_csrows; index++) { csrow = &mci->csrows[index]; - dimm = csrow->channels[0].dimm; - pci_read_config_word(pdev, I82860_GBA + index * 2, &value); cumul_size = (value & I82860_GBA_MASK) << (I82860_GBA_SHIFT - PAGE_SHIFT); @@ -175,38 +164,30 @@ static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev) csrow->first_page = last_cumul_size; csrow->last_page = cumul_size - 1; - dimm->nr_pages = cumul_size - last_cumul_size; + csrow->nr_pages = cumul_size - last_cumul_size; last_cumul_size = cumul_size; - dimm->grain = 1 << 12; /* I82860_EAP has 4KiB reolution */ - dimm->mtype = MEM_RMBS; - dimm->dtype = DEV_UNKNOWN; - dimm->edac_mode = mchcfg_ddim ? EDAC_SECDED : EDAC_NONE; + csrow->grain = 1 << 12; /* I82860_EAP has 4KiB reolution */ + csrow->mtype = MEM_RMBS; + csrow->dtype = DEV_UNKNOWN; + csrow->edac_mode = mchcfg_ddim ? EDAC_SECDED : EDAC_NONE; } } static int i82860_probe1(struct pci_dev *pdev, int dev_idx) { struct mem_ctl_info *mci; - struct edac_mc_layer layers[2]; struct i82860_error_info discard; - /* - * RDRAM has channels but these don't map onto the csrow abstraction. - * According with the datasheet, there are 2 Rambus channels, supporting - * up to 16 direct RDRAM devices. - * The device groups from the GRA registers seem to map reasonably - * well onto the notion of a chip select row. - * There are 16 GRA registers and since the name is associated with - * the channel and the GRA registers map to physical devices so we are - * going to make 1 channel for group. + /* RDRAM has channels but these don't map onto the abstractions that + edac uses. + The device groups from the GRA registers seem to map reasonably + well onto the notion of a chip select row. + There are 16 GRA registers and since the name is associated with + the channel and the GRA registers map to physical devices so we are + going to make 1 channel for group. */ - layers[0].type = EDAC_MC_LAYER_CHANNEL; - layers[0].size = 2; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_SLOT; - layers[1].size = 8; - layers[1].is_virt_csrow = true; - mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0); + mci = edac_mc_alloc(0, 16, 1, 0); + if (!mci) return -ENOMEM; diff --git a/trunk/drivers/edac/i82875p_edac.c b/trunk/drivers/edac/i82875p_edac.c index b613e31c16e5..10f15d85fb5e 100644 --- a/trunk/drivers/edac/i82875p_edac.c +++ b/trunk/drivers/edac/i82875p_edac.c @@ -38,8 +38,7 @@ #endif /* PCI_DEVICE_ID_INTEL_82875_6 */ /* four csrows in dual channel, eight in single channel */ -#define I82875P_NR_DIMMS 8 -#define I82875P_NR_CSROWS(nr_chans) (I82875P_NR_DIMMS / (nr_chans)) +#define I82875P_NR_CSROWS(nr_chans) (8/(nr_chans)) /* Intel 82875p register addresses - device 0 function 0 - DRAM Controller */ #define I82875P_EAP 0x58 /* Error Address Pointer (32b) @@ -236,9 +235,7 @@ static int i82875p_process_error_info(struct mem_ctl_info *mci, return 1; if ((info->errsts ^ info->errsts2) & 0x0081) { - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0, - -1, -1, -1, - "UE overwrote CE", "", NULL); + edac_mc_handle_ce_no_info(mci, "UE overwrote CE"); info->errsts = info->errsts2; } @@ -246,15 +243,11 @@ static int i82875p_process_error_info(struct mem_ctl_info *mci, row = edac_mc_find_csrow_by_page(mci, info->eap); if (info->errsts & 0x0080) - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - info->eap, 0, 0, - row, -1, -1, - "i82875p UE", "", NULL); + edac_mc_handle_ue(mci, info->eap, 0, row, "i82875p UE"); else - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - info->eap, 0, info->derrsyn, - row, multi_chan ? (info->des & 0x1) : 0, - -1, "i82875p CE", "", NULL); + edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row, + multi_chan ? (info->des & 0x1) : 0, + "i82875p CE"); return 1; } @@ -349,13 +342,11 @@ static void i82875p_init_csrows(struct mem_ctl_info *mci, void __iomem * ovrfl_window, u32 drc) { struct csrow_info *csrow; - struct dimm_info *dimm; - unsigned nr_chans = dual_channel_active(drc) + 1; unsigned long last_cumul_size; u8 value; u32 drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ - u32 cumul_size, nr_pages; - int index, j; + u32 cumul_size; + int index; drc_ddim = (drc >> 18) & 0x1; last_cumul_size = 0; @@ -378,18 +369,12 @@ static void i82875p_init_csrows(struct mem_ctl_info *mci, csrow->first_page = last_cumul_size; csrow->last_page = cumul_size - 1; - nr_pages = cumul_size - last_cumul_size; + csrow->nr_pages = cumul_size - last_cumul_size; last_cumul_size = cumul_size; - - for (j = 0; j < nr_chans; j++) { - dimm = csrow->channels[j].dimm; - - dimm->nr_pages = nr_pages / nr_chans; - dimm->grain = 1 << 12; /* I82875P_EAP has 4KiB reolution */ - dimm->mtype = MEM_DDR; - dimm->dtype = DEV_UNKNOWN; - dimm->edac_mode = drc_ddim ? EDAC_SECDED : EDAC_NONE; - } + csrow->grain = 1 << 12; /* I82875P_EAP has 4KiB reolution */ + csrow->mtype = MEM_DDR; + csrow->dtype = DEV_UNKNOWN; + csrow->edac_mode = drc_ddim ? EDAC_SECDED : EDAC_NONE; } } @@ -397,7 +382,6 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx) { int rc = -ENODEV; struct mem_ctl_info *mci; - struct edac_mc_layer layers[2]; struct i82875p_pvt *pvt; struct pci_dev *ovrfl_pdev; void __iomem *ovrfl_window; @@ -413,14 +397,9 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx) return -ENODEV; drc = readl(ovrfl_window + I82875P_DRC); nr_chans = dual_channel_active(drc) + 1; + mci = edac_mc_alloc(sizeof(*pvt), I82875P_NR_CSROWS(nr_chans), + nr_chans, 0); - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = I82875P_NR_CSROWS(nr_chans); - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = nr_chans; - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt)); if (!mci) { rc = -ENOMEM; goto fail0; diff --git a/trunk/drivers/edac/i82975x_edac.c b/trunk/drivers/edac/i82975x_edac.c index 433332c7cdba..0cd8368f88f8 100644 --- a/trunk/drivers/edac/i82975x_edac.c +++ b/trunk/drivers/edac/i82975x_edac.c @@ -29,8 +29,7 @@ #define PCI_DEVICE_ID_INTEL_82975_0 0x277c #endif /* PCI_DEVICE_ID_INTEL_82975_0 */ -#define I82975X_NR_DIMMS 8 -#define I82975X_NR_CSROWS(nr_chans) (I82975X_NR_DIMMS / (nr_chans)) +#define I82975X_NR_CSROWS(nr_chans) (8/(nr_chans)) /* Intel 82975X register addresses - device 0 function 0 - DRAM Controller */ #define I82975X_EAP 0x58 /* Dram Error Address Pointer (32b) @@ -288,8 +287,7 @@ static int i82975x_process_error_info(struct mem_ctl_info *mci, return 1; if ((info->errsts ^ info->errsts2) & 0x0003) { - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0, - -1, -1, -1, "UE overwrote CE", "", NULL); + edac_mc_handle_ce_no_info(mci, "UE overwrote CE"); info->errsts = info->errsts2; } @@ -311,18 +309,13 @@ static int i82975x_process_error_info(struct mem_ctl_info *mci, chan = (mci->csrows[row].nr_channels == 1) ? 0 : info->eap & 1; offst = info->eap & ((1 << PAGE_SHIFT) - - (1 << mci->csrows[row].channels[chan].dimm->grain)); + (1 << mci->csrows[row].grain)); if (info->errsts & 0x0002) - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - page, offst, 0, - row, -1, -1, - "i82975x UE", "", NULL); + edac_mc_handle_ue(mci, page, offst , row, "i82975x UE"); else - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - page, offst, info->derrsyn, - row, chan ? chan : 0, -1, - "i82975x CE", "", NULL); + edac_mc_handle_ce(mci, page, offst, info->derrsyn, row, + chan, "i82975x CE"); return 1; } @@ -377,10 +370,8 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci, struct csrow_info *csrow; unsigned long last_cumul_size; u8 value; - u32 cumul_size, nr_pages; + u32 cumul_size; int index, chan; - struct dimm_info *dimm; - enum dev_type dtype; last_cumul_size = 0; @@ -409,33 +400,28 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci, debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index, cumul_size); - nr_pages = cumul_size - last_cumul_size; - if (!nr_pages) - continue; - /* * Initialise dram labels * index values: * [0-7] for single-channel; i.e. csrow->nr_channels = 1 * [0-3] for dual-channel; i.e. csrow->nr_channels = 2 */ - dtype = i82975x_dram_type(mch_window, index); - for (chan = 0; chan < csrow->nr_channels; chan++) { - dimm = mci->csrows[index].channels[chan].dimm; - - dimm->nr_pages = nr_pages / csrow->nr_channels; - strncpy(csrow->channels[chan].dimm->label, + for (chan = 0; chan < csrow->nr_channels; chan++) + strncpy(csrow->channels[chan].label, labels[(index >> 1) + (chan * 2)], EDAC_MC_LABEL_LEN); - dimm->grain = 1 << 7; /* 128Byte cache-line resolution */ - dimm->dtype = i82975x_dram_type(mch_window, index); - dimm->mtype = MEM_DDR2; /* I82975x supports only DDR2 */ - dimm->edac_mode = EDAC_SECDED; /* only supported */ - } + + if (cumul_size == last_cumul_size) + continue; /* not populated */ csrow->first_page = last_cumul_size; csrow->last_page = cumul_size - 1; + csrow->nr_pages = cumul_size - last_cumul_size; last_cumul_size = cumul_size; + csrow->grain = 1 << 7; /* 128Byte cache-line resolution */ + csrow->mtype = MEM_DDR2; /* I82975x supports only DDR2 */ + csrow->dtype = i82975x_dram_type(mch_window, index); + csrow->edac_mode = EDAC_SECDED; /* only supported */ } } @@ -477,7 +463,6 @@ static int i82975x_probe1(struct pci_dev *pdev, int dev_idx) { int rc = -ENODEV; struct mem_ctl_info *mci; - struct edac_mc_layer layers[2]; struct i82975x_pvt *pvt; void __iomem *mch_window; u32 mchbar; @@ -546,13 +531,8 @@ static int i82975x_probe1(struct pci_dev *pdev, int dev_idx) chans = dual_channel_active(mch_window) + 1; /* assuming only one controller, index thus is 0 */ - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = I82975X_NR_DIMMS; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = I82975X_NR_CSROWS(chans); - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt)); + mci = edac_mc_alloc(sizeof(*pvt), I82975X_NR_CSROWS(chans), + chans, 0); if (!mci) { rc = -ENOMEM; goto fail1; diff --git a/trunk/drivers/edac/mce_amd.h b/trunk/drivers/edac/mce_amd.h index 8c87a5e87057..c6074c5cd1ef 100644 --- a/trunk/drivers/edac/mce_amd.h +++ b/trunk/drivers/edac/mce_amd.h @@ -5,6 +5,8 @@ #include +#define BIT_64(n) (U64_C(1) << (n)) + #define EC(x) ((x) & 0xffff) #define XEC(x, mask) (((x) >> 16) & mask) diff --git a/trunk/drivers/edac/mpc85xx_edac.c b/trunk/drivers/edac/mpc85xx_edac.c index 4c402353ba98..73464a62adf7 100644 --- a/trunk/drivers/edac/mpc85xx_edac.c +++ b/trunk/drivers/edac/mpc85xx_edac.c @@ -854,16 +854,12 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci) mpc85xx_mc_printk(mci, KERN_ERR, "PFN out of range!\n"); if (err_detect & DDR_EDE_SBE) - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - pfn, err_addr & ~PAGE_MASK, syndrome, - row_index, 0, -1, - mci->ctl_name, "", NULL); + edac_mc_handle_ce(mci, pfn, err_addr & ~PAGE_MASK, + syndrome, row_index, 0, mci->ctl_name); if (err_detect & DDR_EDE_MBE) - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - pfn, err_addr & ~PAGE_MASK, syndrome, - row_index, 0, -1, - mci->ctl_name, "", NULL); + edac_mc_handle_ue(mci, pfn, err_addr & ~PAGE_MASK, + row_index, mci->ctl_name); out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect); } @@ -887,7 +883,6 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci) { struct mpc85xx_mc_pdata *pdata = mci->pvt_info; struct csrow_info *csrow; - struct dimm_info *dimm; u32 sdram_ctl; u32 sdtype; enum mem_type mtype; @@ -934,8 +929,6 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci) u32 end; csrow = &mci->csrows[index]; - dimm = csrow->channels[0].dimm; - cs_bnds = in_be32(pdata->mc_vbase + MPC85XX_MC_CS_BNDS_0 + (index * MPC85XX_MC_CS_BNDS_OFS)); @@ -951,21 +944,19 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci) csrow->first_page = start; csrow->last_page = end; - - dimm->nr_pages = end + 1 - start; - dimm->grain = 8; - dimm->mtype = mtype; - dimm->dtype = DEV_UNKNOWN; + csrow->nr_pages = end + 1 - start; + csrow->grain = 8; + csrow->mtype = mtype; + csrow->dtype = DEV_UNKNOWN; if (sdram_ctl & DSC_X32_EN) - dimm->dtype = DEV_X32; - dimm->edac_mode = EDAC_SECDED; + csrow->dtype = DEV_X32; + csrow->edac_mode = EDAC_SECDED; } } static int __devinit mpc85xx_mc_err_probe(struct platform_device *op) { struct mem_ctl_info *mci; - struct edac_mc_layer layers[2]; struct mpc85xx_mc_pdata *pdata; struct resource r; u32 sdram_ctl; @@ -974,13 +965,7 @@ static int __devinit mpc85xx_mc_err_probe(struct platform_device *op) if (!devres_open_group(&op->dev, mpc85xx_mc_err_probe, GFP_KERNEL)) return -ENOMEM; - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = 4; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = 1; - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), sizeof(*pdata)); + mci = edac_mc_alloc(sizeof(*pdata), 4, 1, edac_mc_idx); if (!mci) { devres_release_group(&op->dev, mpc85xx_mc_err_probe); return -ENOMEM; diff --git a/trunk/drivers/edac/mv64x60_edac.c b/trunk/drivers/edac/mv64x60_edac.c index b0bb5a3d2527..7e5ff367705c 100644 --- a/trunk/drivers/edac/mv64x60_edac.c +++ b/trunk/drivers/edac/mv64x60_edac.c @@ -611,17 +611,12 @@ static void mv64x60_mc_check(struct mem_ctl_info *mci) /* first bit clear in ECC Err Reg, 1 bit error, correctable by HW */ if (!(reg & 0x1)) - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - err_addr >> PAGE_SHIFT, - err_addr & PAGE_MASK, syndrome, - 0, 0, -1, - mci->ctl_name, "", NULL); + edac_mc_handle_ce(mci, err_addr >> PAGE_SHIFT, + err_addr & PAGE_MASK, syndrome, 0, 0, + mci->ctl_name); else /* 2 bit error, UE */ - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - err_addr >> PAGE_SHIFT, - err_addr & PAGE_MASK, 0, - 0, 0, -1, - mci->ctl_name, "", NULL); + edac_mc_handle_ue(mci, err_addr >> PAGE_SHIFT, + err_addr & PAGE_MASK, 0, mci->ctl_name); /* clear the error */ out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR, 0); @@ -661,8 +656,6 @@ static void mv64x60_init_csrows(struct mem_ctl_info *mci, struct mv64x60_mc_pdata *pdata) { struct csrow_info *csrow; - struct dimm_info *dimm; - u32 devtype; u32 ctl; @@ -671,36 +664,35 @@ static void mv64x60_init_csrows(struct mem_ctl_info *mci, ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_CONFIG); csrow = &mci->csrows[0]; - dimm = csrow->channels[0].dimm; - - dimm->nr_pages = pdata->total_mem >> PAGE_SHIFT; - dimm->grain = 8; + csrow->first_page = 0; + csrow->nr_pages = pdata->total_mem >> PAGE_SHIFT; + csrow->last_page = csrow->first_page + csrow->nr_pages - 1; + csrow->grain = 8; - dimm->mtype = (ctl & MV64X60_SDRAM_REGISTERED) ? MEM_RDDR : MEM_DDR; + csrow->mtype = (ctl & MV64X60_SDRAM_REGISTERED) ? MEM_RDDR : MEM_DDR; devtype = (ctl >> 20) & 0x3; switch (devtype) { case 0x0: - dimm->dtype = DEV_X32; + csrow->dtype = DEV_X32; break; case 0x2: /* could be X8 too, but no way to tell */ - dimm->dtype = DEV_X16; + csrow->dtype = DEV_X16; break; case 0x3: - dimm->dtype = DEV_X4; + csrow->dtype = DEV_X4; break; default: - dimm->dtype = DEV_UNKNOWN; + csrow->dtype = DEV_UNKNOWN; break; } - dimm->edac_mode = EDAC_SECDED; + csrow->edac_mode = EDAC_SECDED; } static int __devinit mv64x60_mc_err_probe(struct platform_device *pdev) { struct mem_ctl_info *mci; - struct edac_mc_layer layers[2]; struct mv64x60_mc_pdata *pdata; struct resource *r; u32 ctl; @@ -709,14 +701,7 @@ static int __devinit mv64x60_mc_err_probe(struct platform_device *pdev) if (!devres_open_group(&pdev->dev, mv64x60_mc_err_probe, GFP_KERNEL)) return -ENOMEM; - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = 1; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = 1; - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), layers, - sizeof(struct mv64x60_mc_pdata)); + mci = edac_mc_alloc(sizeof(struct mv64x60_mc_pdata), 1, 1, edac_mc_idx); if (!mci) { printk(KERN_ERR "%s: No memory for CPU err\n", __func__); devres_release_group(&pdev->dev, mv64x60_mc_err_probe); diff --git a/trunk/drivers/edac/pasemi_edac.c b/trunk/drivers/edac/pasemi_edac.c index b095a906a994..7f71ee436744 100644 --- a/trunk/drivers/edac/pasemi_edac.c +++ b/trunk/drivers/edac/pasemi_edac.c @@ -110,16 +110,15 @@ static void pasemi_edac_process_error_info(struct mem_ctl_info *mci, u32 errsta) /* uncorrectable/multi-bit errors */ if (errsta & (MCDEBUG_ERRSTA_MBE_STATUS | MCDEBUG_ERRSTA_RFL_STATUS)) { - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - mci->csrows[cs].first_page, 0, 0, - cs, 0, -1, mci->ctl_name, "", NULL); + edac_mc_handle_ue(mci, mci->csrows[cs].first_page, 0, + cs, mci->ctl_name); } /* correctable/single-bit errors */ - if (errsta & MCDEBUG_ERRSTA_SBE_STATUS) - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - mci->csrows[cs].first_page, 0, 0, - cs, 0, -1, mci->ctl_name, "", NULL); + if (errsta & MCDEBUG_ERRSTA_SBE_STATUS) { + edac_mc_handle_ce(mci, mci->csrows[cs].first_page, 0, + 0, cs, 0, mci->ctl_name); + } } static void pasemi_edac_check(struct mem_ctl_info *mci) @@ -136,13 +135,11 @@ static int pasemi_edac_init_csrows(struct mem_ctl_info *mci, enum edac_type edac_mode) { struct csrow_info *csrow; - struct dimm_info *dimm; u32 rankcfg; int index; for (index = 0; index < mci->nr_csrows; index++) { csrow = &mci->csrows[index]; - dimm = csrow->channels[0].dimm; pci_read_config_dword(pdev, MCDRAM_RANKCFG + (index * 12), @@ -154,20 +151,20 @@ static int pasemi_edac_init_csrows(struct mem_ctl_info *mci, switch ((rankcfg & MCDRAM_RANKCFG_TYPE_SIZE_M) >> MCDRAM_RANKCFG_TYPE_SIZE_S) { case 0: - dimm->nr_pages = 128 << (20 - PAGE_SHIFT); + csrow->nr_pages = 128 << (20 - PAGE_SHIFT); break; case 1: - dimm->nr_pages = 256 << (20 - PAGE_SHIFT); + csrow->nr_pages = 256 << (20 - PAGE_SHIFT); break; case 2: case 3: - dimm->nr_pages = 512 << (20 - PAGE_SHIFT); + csrow->nr_pages = 512 << (20 - PAGE_SHIFT); break; case 4: - dimm->nr_pages = 1024 << (20 - PAGE_SHIFT); + csrow->nr_pages = 1024 << (20 - PAGE_SHIFT); break; case 5: - dimm->nr_pages = 2048 << (20 - PAGE_SHIFT); + csrow->nr_pages = 2048 << (20 - PAGE_SHIFT); break; default: edac_mc_printk(mci, KERN_ERR, @@ -177,13 +174,13 @@ static int pasemi_edac_init_csrows(struct mem_ctl_info *mci, } csrow->first_page = last_page_in_mmc; - csrow->last_page = csrow->first_page + dimm->nr_pages - 1; - last_page_in_mmc += dimm->nr_pages; + csrow->last_page = csrow->first_page + csrow->nr_pages - 1; + last_page_in_mmc += csrow->nr_pages; csrow->page_mask = 0; - dimm->grain = PASEMI_EDAC_ERROR_GRAIN; - dimm->mtype = MEM_DDR; - dimm->dtype = DEV_UNKNOWN; - dimm->edac_mode = edac_mode; + csrow->grain = PASEMI_EDAC_ERROR_GRAIN; + csrow->mtype = MEM_DDR; + csrow->dtype = DEV_UNKNOWN; + csrow->edac_mode = edac_mode; } return 0; } @@ -192,7 +189,6 @@ static int __devinit pasemi_edac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct mem_ctl_info *mci = NULL; - struct edac_mc_layer layers[2]; u32 errctl1, errcor, scrub, mcen; pci_read_config_dword(pdev, MCCFG_MCEN, &mcen); @@ -209,14 +205,9 @@ static int __devinit pasemi_edac_probe(struct pci_dev *pdev, MCDEBUG_ERRCTL1_RFL_LOG_EN; pci_write_config_dword(pdev, MCDEBUG_ERRCTL1, errctl1); - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = PASEMI_EDAC_NR_CSROWS; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = PASEMI_EDAC_NR_CHANS; - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(system_mmc_id++, ARRAY_SIZE(layers), layers, - 0); + mci = edac_mc_alloc(0, PASEMI_EDAC_NR_CSROWS, PASEMI_EDAC_NR_CHANS, + system_mmc_id++); + if (mci == NULL) return -ENOMEM; diff --git a/trunk/drivers/edac/ppc4xx_edac.c b/trunk/drivers/edac/ppc4xx_edac.c index f3f9fed06ad7..d427c69bb8b1 100644 --- a/trunk/drivers/edac/ppc4xx_edac.c +++ b/trunk/drivers/edac/ppc4xx_edac.c @@ -727,10 +727,7 @@ ppc4xx_edac_handle_ce(struct mem_ctl_info *mci, for (row = 0; row < mci->nr_csrows; row++) if (ppc4xx_edac_check_bank_error(status, row)) - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - 0, 0, 0, - row, 0, -1, - message, "", NULL); + edac_mc_handle_ce_no_info(mci, message); } /** @@ -758,10 +755,7 @@ ppc4xx_edac_handle_ue(struct mem_ctl_info *mci, for (row = 0; row < mci->nr_csrows; row++) if (ppc4xx_edac_check_bank_error(status, row)) - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - page, offset, 0, - row, 0, -1, - message, "", NULL); + edac_mc_handle_ue(mci, page, offset, row, message); } /** @@ -901,8 +895,9 @@ ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1) enum mem_type mtype; enum dev_type dtype; enum edac_type edac_mode; - int row, j; - u32 mbxcf, size, nr_pages; + int row; + u32 mbxcf, size; + static u32 ppc4xx_last_page; /* Establish the memory type and width */ @@ -953,7 +948,7 @@ ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1) case SDRAM_MBCF_SZ_2GB: case SDRAM_MBCF_SZ_4GB: case SDRAM_MBCF_SZ_8GB: - nr_pages = SDRAM_MBCF_SZ_TO_PAGES(size); + csi->nr_pages = SDRAM_MBCF_SZ_TO_PAGES(size); break; default: ppc4xx_edac_mc_printk(KERN_ERR, mci, @@ -964,6 +959,10 @@ ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1) goto done; } + csi->first_page = ppc4xx_last_page; + csi->last_page = csi->first_page + csi->nr_pages - 1; + csi->page_mask = 0; + /* * It's unclear exactly what grain should be set to * here. The SDRAM_ECCES register allows resolution of @@ -976,17 +975,15 @@ ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1) * possible values would be the PLB width (16), the * page size (PAGE_SIZE) or the memory width (2 or 4). */ - for (j = 0; j < csi->nr_channels; j++) { - struct dimm_info *dimm = csi->channels[j].dimm; - dimm->nr_pages = nr_pages / csi->nr_channels; - dimm->grain = 1; + csi->grain = 1; - dimm->mtype = mtype; - dimm->dtype = dtype; + csi->mtype = mtype; + csi->dtype = dtype; - dimm->edac_mode = edac_mode; - } + csi->edac_mode = edac_mode; + + ppc4xx_last_page += csi->nr_pages; } done: @@ -1239,7 +1236,6 @@ static int __devinit ppc4xx_edac_probe(struct platform_device *op) dcr_host_t dcr_host; const struct device_node *np = op->dev.of_node; struct mem_ctl_info *mci = NULL; - struct edac_mc_layer layers[2]; static int ppc4xx_edac_instance; /* @@ -1285,14 +1281,12 @@ static int __devinit ppc4xx_edac_probe(struct platform_device *op) * controller instance and perform the appropriate * initialization. */ - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = ppc4xx_edac_nr_csrows; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = ppc4xx_edac_nr_chans; - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(ppc4xx_edac_instance, ARRAY_SIZE(layers), layers, - sizeof(struct ppc4xx_edac_pdata)); + + mci = edac_mc_alloc(sizeof(struct ppc4xx_edac_pdata), + ppc4xx_edac_nr_csrows, + ppc4xx_edac_nr_chans, + ppc4xx_edac_instance); + if (mci == NULL) { ppc4xx_edac_printk(KERN_ERR, "%s: " "Failed to allocate EDAC MC instance!\n", diff --git a/trunk/drivers/edac/r82600_edac.c b/trunk/drivers/edac/r82600_edac.c index e1cacd164f31..6d908ad72d64 100644 --- a/trunk/drivers/edac/r82600_edac.c +++ b/trunk/drivers/edac/r82600_edac.c @@ -179,11 +179,10 @@ static int r82600_process_error_info(struct mem_ctl_info *mci, error_found = 1; if (handle_errors) - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - page, 0, syndrome, - edac_mc_find_csrow_by_page(mci, page), - 0, -1, - mci->ctl_name, "", NULL); + edac_mc_handle_ce(mci, page, 0, /* not avail */ + syndrome, + edac_mc_find_csrow_by_page(mci, page), + 0, mci->ctl_name); } if (info->eapr & BIT(1)) { /* UE? */ @@ -191,11 +190,9 @@ static int r82600_process_error_info(struct mem_ctl_info *mci, if (handle_errors) /* 82600 doesn't give enough info */ - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - page, 0, 0, - edac_mc_find_csrow_by_page(mci, page), - 0, -1, - mci->ctl_name, "", NULL); + edac_mc_handle_ue(mci, page, 0, + edac_mc_find_csrow_by_page(mci, page), + mci->ctl_name); } return error_found; @@ -219,7 +216,6 @@ static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, u8 dramcr) { struct csrow_info *csrow; - struct dimm_info *dimm; int index; u8 drbar; /* SDRAM Row Boundary Address Register */ u32 row_high_limit, row_high_limit_last; @@ -231,7 +227,6 @@ static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, for (index = 0; index < mci->nr_csrows; index++) { csrow = &mci->csrows[index]; - dimm = csrow->channels[0].dimm; /* find the DRAM Chip Select Base address and mask */ pci_read_config_byte(pdev, R82600_DRBA + index, &drbar); @@ -252,17 +247,16 @@ static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, csrow->first_page = row_base >> PAGE_SHIFT; csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1; - - dimm->nr_pages = csrow->last_page - csrow->first_page + 1; + csrow->nr_pages = csrow->last_page - csrow->first_page + 1; /* Error address is top 19 bits - so granularity is * * 14 bits */ - dimm->grain = 1 << 14; - dimm->mtype = reg_sdram ? MEM_RDDR : MEM_DDR; + csrow->grain = 1 << 14; + csrow->mtype = reg_sdram ? MEM_RDDR : MEM_DDR; /* FIXME - check that this is unknowable with this chipset */ - dimm->dtype = DEV_UNKNOWN; + csrow->dtype = DEV_UNKNOWN; /* Mode is global on 82600 */ - dimm->edac_mode = ecc_on ? EDAC_SECDED : EDAC_NONE; + csrow->edac_mode = ecc_on ? EDAC_SECDED : EDAC_NONE; row_high_limit_last = row_high_limit; } } @@ -270,7 +264,6 @@ static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, static int r82600_probe1(struct pci_dev *pdev, int dev_idx) { struct mem_ctl_info *mci; - struct edac_mc_layer layers[2]; u8 dramcr; u32 eapr; u32 scrub_disabled; @@ -285,13 +278,8 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx) debugf2("%s(): sdram refresh rate = %#0x\n", __func__, sdram_refresh_rate); debugf2("%s(): DRAMC register = %#0x\n", __func__, dramcr); - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = R82600_NR_CSROWS; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = R82600_NR_CHANS; - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0); + mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS, 0); + if (mci == NULL) return -ENOMEM; diff --git a/trunk/drivers/edac/sb_edac.c b/trunk/drivers/edac/sb_edac.c index 4adaf4b7da99..123204f8e23b 100644 --- a/trunk/drivers/edac/sb_edac.c +++ b/trunk/drivers/edac/sb_edac.c @@ -314,6 +314,8 @@ struct sbridge_pvt { struct sbridge_info info; struct sbridge_channel channel[NUM_CHANNELS]; + int csrow_map[NUM_CHANNELS][MAX_DIMMS]; + /* Memory type detection */ bool is_mirrored, is_lockstep, is_close_pg; @@ -485,14 +487,29 @@ static struct pci_dev *get_pdev_slot_func(u8 bus, unsigned slot, } /** - * check_if_ecc_is_active() - Checks if ECC is active + * sbridge_get_active_channels() - gets the number of channels and csrows * bus: Device bus + * @channels: Number of channels that will be returned + * @csrows: Number of csrows found + * + * Since EDAC core needs to know in advance the number of available channels + * and csrows, in order to allocate memory for csrows/channels, it is needed + * to run two similar steps. At the first step, implemented on this function, + * it checks the number of csrows/channels present at one socket, identified + * by the associated PCI bus. + * this is used in order to properly allocate the size of mci components. + * Note: one csrow is one dimm. */ -static int check_if_ecc_is_active(const u8 bus) +static int sbridge_get_active_channels(const u8 bus, unsigned *channels, + unsigned *csrows) { struct pci_dev *pdev = NULL; + int i, j; u32 mcmtr; + *channels = 0; + *csrows = 0; + pdev = get_pdev_slot_func(bus, 15, 0); if (!pdev) { sbridge_printk(KERN_ERR, "Couldn't find PCI device " @@ -506,14 +523,41 @@ static int check_if_ecc_is_active(const u8 bus) sbridge_printk(KERN_ERR, "ECC is disabled. Aborting\n"); return -ENODEV; } + + for (i = 0; i < NUM_CHANNELS; i++) { + u32 mtr; + + /* Device 15 functions 2 - 5 */ + pdev = get_pdev_slot_func(bus, 15, 2 + i); + if (!pdev) { + sbridge_printk(KERN_ERR, "Couldn't find PCI device " + "%2x.%02d.%d!!!\n", + bus, 15, 2 + i); + return -ENODEV; + } + (*channels)++; + + for (j = 0; j < ARRAY_SIZE(mtr_regs); j++) { + pci_read_config_dword(pdev, mtr_regs[j], &mtr); + debugf1("Bus#%02x channel #%d MTR%d = %x\n", bus, i, j, mtr); + if (IS_DIMM_PRESENT(mtr)) + (*csrows)++; + } + } + + debugf0("Number of active channels: %d, number of active dimms: %d\n", + *channels, *csrows); + return 0; } -static int get_dimm_config(struct mem_ctl_info *mci) +static int get_dimm_config(const struct mem_ctl_info *mci) { struct sbridge_pvt *pvt = mci->pvt_info; - struct dimm_info *dimm; + struct csrow_info *csr; int i, j, banks, ranks, rows, cols, size, npages; + int csrow = 0; + unsigned long last_page = 0; u32 reg; enum edac_type mode; enum mem_type mtype; @@ -572,8 +616,6 @@ static int get_dimm_config(struct mem_ctl_info *mci) u32 mtr; for (j = 0; j < ARRAY_SIZE(mtr_regs); j++) { - dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, mci->n_layers, - i, j, 0); pci_read_config_dword(pvt->pci_tad[i], mtr_regs[j], &mtr); debugf4("Channel #%d MTR%d = %x\n", i, j, mtr); @@ -592,15 +634,29 @@ static int get_dimm_config(struct mem_ctl_info *mci) pvt->sbridge_dev->mc, i, j, size, npages, banks, ranks, rows, cols); - - dimm->nr_pages = npages; - dimm->grain = 32; - dimm->dtype = (banks == 8) ? DEV_X8 : DEV_X4; - dimm->mtype = mtype; - dimm->edac_mode = mode; - snprintf(dimm->label, sizeof(dimm->label), + csr = &mci->csrows[csrow]; + + csr->first_page = last_page; + csr->last_page = last_page + npages - 1; + csr->page_mask = 0UL; /* Unused */ + csr->nr_pages = npages; + csr->grain = 32; + csr->csrow_idx = csrow; + csr->dtype = (banks == 8) ? DEV_X8 : DEV_X4; + csr->ce_count = 0; + csr->ue_count = 0; + csr->mtype = mtype; + csr->edac_mode = mode; + csr->nr_channels = 1; + csr->channels[0].chan_idx = i; + csr->channels[0].ce_count = 0; + pvt->csrow_map[i][j] = csrow; + snprintf(csr->channels[0].label, + sizeof(csr->channels[0].label), "CPU_SrcID#%u_Channel#%u_DIMM#%u", pvt->sbridge_dev->source_id, i, j); + last_page += npages; + csrow++; } } } @@ -788,10 +844,11 @@ static int get_memory_error_data(struct mem_ctl_info *mci, u8 *socket, long *channel_mask, u8 *rank, - char **area_type, char *msg) + char *area_type) { struct mem_ctl_info *new_mci; struct sbridge_pvt *pvt = mci->pvt_info; + char msg[256]; int n_rir, n_sads, n_tads, sad_way, sck_xch; int sad_interl, idx, base_ch; int interleave_mode; @@ -813,10 +870,12 @@ static int get_memory_error_data(struct mem_ctl_info *mci, */ if ((addr > (u64) pvt->tolm) && (addr < (1LL << 32))) { sprintf(msg, "Error at TOLM area, on addr 0x%08Lx", addr); + edac_mc_handle_ce_no_info(mci, msg); return -EINVAL; } if (addr >= (u64)pvt->tohm) { sprintf(msg, "Error at MMIOH area, on addr 0x%016Lx", addr); + edac_mc_handle_ce_no_info(mci, msg); return -EINVAL; } @@ -833,6 +892,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, limit = SAD_LIMIT(reg); if (limit <= prv) { sprintf(msg, "Can't discover the memory socket"); + edac_mc_handle_ce_no_info(mci, msg); return -EINVAL; } if (addr <= limit) @@ -841,9 +901,10 @@ static int get_memory_error_data(struct mem_ctl_info *mci, } if (n_sads == MAX_SAD) { sprintf(msg, "Can't discover the memory socket"); + edac_mc_handle_ce_no_info(mci, msg); return -EINVAL; } - *area_type = get_dram_attr(reg); + area_type = get_dram_attr(reg); interleave_mode = INTERLEAVE_MODE(reg); pci_read_config_dword(pvt->pci_sad0, interleave_list[n_sads], @@ -881,6 +942,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, break; default: sprintf(msg, "Can't discover socket interleave"); + edac_mc_handle_ce_no_info(mci, msg); return -EINVAL; } *socket = sad_interleave[idx]; @@ -895,6 +957,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, if (!new_mci) { sprintf(msg, "Struct for socket #%u wasn't initialized", *socket); + edac_mc_handle_ce_no_info(mci, msg); return -EINVAL; } mci = new_mci; @@ -910,6 +973,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, limit = TAD_LIMIT(reg); if (limit <= prv) { sprintf(msg, "Can't discover the memory channel"); + edac_mc_handle_ce_no_info(mci, msg); return -EINVAL; } if (addr <= limit) @@ -949,6 +1013,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, break; default: sprintf(msg, "Can't discover the TAD target"); + edac_mc_handle_ce_no_info(mci, msg); return -EINVAL; } *channel_mask = 1 << base_ch; @@ -962,6 +1027,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, break; default: sprintf(msg, "Invalid mirror set. Can't decode addr"); + edac_mc_handle_ce_no_info(mci, msg); return -EINVAL; } } else @@ -989,6 +1055,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, if (offset > addr) { sprintf(msg, "Can't calculate ch addr: TAD offset 0x%08Lx is too high for addr 0x%08Lx!", offset, addr); + edac_mc_handle_ce_no_info(mci, msg); return -EINVAL; } addr -= offset; @@ -1028,6 +1095,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, if (n_rir == MAX_RIR_RANGES) { sprintf(msg, "Can't discover the memory rank for ch addr 0x%08Lx", ch_addr); + edac_mc_handle_ce_no_info(mci, msg); return -EINVAL; } rir_way = RIR_WAY(reg); @@ -1341,8 +1409,7 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, { struct mem_ctl_info *new_mci; struct sbridge_pvt *pvt = mci->pvt_info; - enum hw_event_mc_err_type tp_event; - char *type, *optype, msg[256]; + char *type, *optype, *msg, *recoverable_msg; bool ripv = GET_BITFIELD(m->mcgstatus, 0, 0); bool overflow = GET_BITFIELD(m->status, 62, 62); bool uncorrected_error = GET_BITFIELD(m->status, 61, 61); @@ -1354,21 +1421,13 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, u32 optypenum = GET_BITFIELD(m->status, 4, 6); long channel_mask, first_channel; u8 rank, socket; - int rc, dimm; - char *area_type = NULL; - - if (uncorrected_error) { - if (ripv) { - type = "FATAL"; - tp_event = HW_EVENT_ERR_FATAL; - } else { - type = "NON_FATAL"; - tp_event = HW_EVENT_ERR_UNCORRECTED; - } - } else { - type = "CORRECTED"; - tp_event = HW_EVENT_ERR_CORRECTED; - } + int csrow, rc, dimm; + char *area_type = "Unknown"; + + if (ripv) + type = "NON_FATAL"; + else + type = "FATAL"; /* * According with Table 15-9 of the Intel Architecture spec vol 3A, @@ -1386,19 +1445,19 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, } else { switch (optypenum) { case 0: - optype = "generic undef request error"; + optype = "generic undef request"; break; case 1: - optype = "memory read error"; + optype = "memory read"; break; case 2: - optype = "memory write error"; + optype = "memory write"; break; case 3: - optype = "addr/cmd error"; + optype = "addr/cmd"; break; case 4: - optype = "memory scrubbing error"; + optype = "memory scrubbing"; break; default: optype = "reserved"; @@ -1407,13 +1466,13 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, } rc = get_memory_error_data(mci, m->addr, &socket, - &channel_mask, &rank, &area_type, msg); + &channel_mask, &rank, area_type); if (rc < 0) - goto err_parsing; + return; new_mci = get_mci_for_node_id(socket); if (!new_mci) { - strcpy(msg, "Error: socket got corrupted!"); - goto err_parsing; + edac_mc_handle_ce_no_info(mci, "Error: socket got corrupted!"); + return; } mci = new_mci; pvt = mci->pvt_info; @@ -1427,39 +1486,45 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, else dimm = 2; + csrow = pvt->csrow_map[first_channel][dimm]; + + if (uncorrected_error && recoverable) + recoverable_msg = " recoverable"; + else + recoverable_msg = ""; /* - * FIXME: On some memory configurations (mirror, lockstep), the - * Memory Controller can't point the error to a single DIMM. The - * EDAC core should be handling the channel mask, in order to point - * to the group of dimm's where the error may be happening. + * FIXME: What should we do with "channel" information on mcelog? + * Probably, we can just discard it, as the channel information + * comes from the get_memory_error_data() address decoding */ - snprintf(msg, sizeof(msg), - "count:%d%s%s area:%s err_code:%04x:%04x socket:%d channel_mask:%ld rank:%d", - core_err_cnt, - overflow ? " OVERFLOW" : "", - (uncorrected_error && recoverable) ? " recoverable" : "", - area_type, - mscod, errcode, - socket, - channel_mask, - rank); + msg = kasprintf(GFP_ATOMIC, + "%d %s error(s): %s on %s area %s%s: cpu=%d Err=%04x:%04x (ch=%d), " + "addr = 0x%08llx => socket=%d, Channel=%ld(mask=%ld), rank=%d\n", + core_err_cnt, + area_type, + optype, + type, + recoverable_msg, + overflow ? "OVERFLOW" : "", + m->cpu, + mscod, errcode, + channel, /* 1111b means not specified */ + (long long) m->addr, + socket, + first_channel, /* This is the real channel on SB */ + channel_mask, + rank); debugf0("%s", msg); - /* FIXME: need support for channel mask */ - /* Call the helper to output message */ - edac_mc_handle_error(tp_event, mci, - m->addr >> PAGE_SHIFT, m->addr & ~PAGE_MASK, 0, - channel, dimm, -1, - optype, msg, m); - return; -err_parsing: - edac_mc_handle_error(tp_event, mci, 0, 0, 0, - -1, -1, -1, - msg, "", m); + if (uncorrected_error) + edac_mc_handle_fbd_ue(mci, csrow, 0, 0, msg); + else + edac_mc_handle_fbd_ce(mci, csrow, 0, msg); + kfree(msg); } /* @@ -1618,25 +1683,16 @@ static void sbridge_unregister_mci(struct sbridge_dev *sbridge_dev) static int sbridge_register_mci(struct sbridge_dev *sbridge_dev) { struct mem_ctl_info *mci; - struct edac_mc_layer layers[2]; struct sbridge_pvt *pvt; - int rc; + int rc, channels, csrows; /* Check the number of active and not disabled channels */ - rc = check_if_ecc_is_active(sbridge_dev->bus); + rc = sbridge_get_active_channels(sbridge_dev->bus, &channels, &csrows); if (unlikely(rc < 0)) return rc; /* allocate a new MC control structure */ - layers[0].type = EDAC_MC_LAYER_CHANNEL; - layers[0].size = NUM_CHANNELS; - layers[0].is_virt_csrow = false; - layers[1].type = EDAC_MC_LAYER_SLOT; - layers[1].size = MAX_DIMMS; - layers[1].is_virt_csrow = true; - mci = edac_mc_alloc(sbridge_dev->mc, ARRAY_SIZE(layers), layers, - sizeof(*pvt)); - + mci = edac_mc_alloc(sizeof(*pvt), csrows, channels, sbridge_dev->mc); if (unlikely(!mci)) return -ENOMEM; diff --git a/trunk/drivers/edac/tile_edac.c b/trunk/drivers/edac/tile_edac.c index 7bb4614730db..e99d00976189 100644 --- a/trunk/drivers/edac/tile_edac.c +++ b/trunk/drivers/edac/tile_edac.c @@ -71,10 +71,7 @@ static void tile_edac_check(struct mem_ctl_info *mci) if (mem_error.sbe_count != priv->ce_count) { dev_dbg(mci->dev, "ECC CE err on node %d\n", priv->node); priv->ce_count = mem_error.sbe_count; - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - 0, 0, 0, - 0, 0, -1, - mci->ctl_name, "", NULL); + edac_mc_handle_ce(mci, 0, 0, 0, 0, 0, mci->ctl_name); } } @@ -87,7 +84,6 @@ static int __devinit tile_edac_init_csrows(struct mem_ctl_info *mci) struct csrow_info *csrow = &mci->csrows[0]; struct tile_edac_priv *priv = mci->pvt_info; struct mshim_mem_info mem_info; - struct dimm_info *dimm = csrow->channels[0].dimm; if (hv_dev_pread(priv->hv_devhdl, 0, (HV_VirtAddr)&mem_info, sizeof(struct mshim_mem_info), MSHIM_MEM_INFO_OFF) != @@ -97,25 +93,27 @@ static int __devinit tile_edac_init_csrows(struct mem_ctl_info *mci) } if (mem_info.mem_ecc) - dimm->edac_mode = EDAC_SECDED; + csrow->edac_mode = EDAC_SECDED; else - dimm->edac_mode = EDAC_NONE; + csrow->edac_mode = EDAC_NONE; switch (mem_info.mem_type) { case DDR2: - dimm->mtype = MEM_DDR2; + csrow->mtype = MEM_DDR2; break; case DDR3: - dimm->mtype = MEM_DDR3; + csrow->mtype = MEM_DDR3; break; default: return -1; } - dimm->nr_pages = mem_info.mem_size >> PAGE_SHIFT; - dimm->grain = TILE_EDAC_ERROR_GRAIN; - dimm->dtype = DEV_UNKNOWN; + csrow->first_page = 0; + csrow->nr_pages = mem_info.mem_size >> PAGE_SHIFT; + csrow->last_page = csrow->first_page + csrow->nr_pages - 1; + csrow->grain = TILE_EDAC_ERROR_GRAIN; + csrow->dtype = DEV_UNKNOWN; return 0; } @@ -125,7 +123,6 @@ static int __devinit tile_edac_mc_probe(struct platform_device *pdev) char hv_file[32]; int hv_devhdl; struct mem_ctl_info *mci; - struct edac_mc_layer layers[2]; struct tile_edac_priv *priv; int rc; @@ -135,14 +132,8 @@ static int __devinit tile_edac_mc_probe(struct platform_device *pdev) return -EINVAL; /* A TILE MC has a single channel and one chip-select row. */ - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = TILE_EDAC_NR_CSROWS; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = TILE_EDAC_NR_CHANS; - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(pdev->id, ARRAY_SIZE(layers), layers, - sizeof(struct tile_edac_priv)); + mci = edac_mc_alloc(sizeof(struct tile_edac_priv), + TILE_EDAC_NR_CSROWS, TILE_EDAC_NR_CHANS, pdev->id); if (mci == NULL) return -ENOMEM; priv = mci->pvt_info; diff --git a/trunk/drivers/edac/x38_edac.c b/trunk/drivers/edac/x38_edac.c index 1ac7962d63ea..a438297389e5 100644 --- a/trunk/drivers/edac/x38_edac.c +++ b/trunk/drivers/edac/x38_edac.c @@ -215,26 +215,19 @@ static void x38_process_error_info(struct mem_ctl_info *mci, return; if ((info->errsts ^ info->errsts2) & X38_ERRSTS_BITS) { - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0, - -1, -1, -1, - "UE overwrote CE", "", NULL); + edac_mc_handle_ce_no_info(mci, "UE overwrote CE"); info->errsts = info->errsts2; } for (channel = 0; channel < x38_channel_num; channel++) { log = info->eccerrlog[channel]; if (log & X38_ECCERRLOG_UE) { - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, - 0, 0, 0, - eccerrlog_row(channel, log), - -1, -1, - "x38 UE", "", NULL); + edac_mc_handle_ue(mci, 0, 0, + eccerrlog_row(channel, log), "x38 UE"); } else if (log & X38_ECCERRLOG_CE) { - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, - 0, 0, eccerrlog_syndrome(log), - eccerrlog_row(channel, log), - -1, -1, - "x38 CE", "", NULL); + edac_mc_handle_ce(mci, 0, 0, + eccerrlog_syndrome(log), + eccerrlog_row(channel, log), 0, "x38 CE"); } } } @@ -324,9 +317,9 @@ static unsigned long drb_to_nr_pages( static int x38_probe1(struct pci_dev *pdev, int dev_idx) { int rc; - int i, j; + int i; struct mem_ctl_info *mci = NULL; - struct edac_mc_layer layers[2]; + unsigned long last_page; u16 drbs[X38_CHANNELS][X38_RANKS_PER_CHANNEL]; bool stacked; void __iomem *window; @@ -342,13 +335,7 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx) how_many_channel(pdev); /* FIXME: unconventional pvt_info usage */ - layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = X38_RANKS; - layers[0].is_virt_csrow = true; - layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = x38_channel_num; - layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0); + mci = edac_mc_alloc(0, X38_RANKS, x38_channel_num, 0); if (!mci) return -ENOMEM; @@ -376,6 +363,7 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx) * cumulative; the last one will contain the total memory * contained in all ranks. */ + last_page = -1UL; for (i = 0; i < mci->nr_csrows; i++) { unsigned long nr_pages; struct csrow_info *csrow = &mci->csrows[i]; @@ -384,18 +372,20 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx) i / X38_RANKS_PER_CHANNEL, i % X38_RANKS_PER_CHANNEL); - if (nr_pages == 0) + if (nr_pages == 0) { + csrow->mtype = MEM_EMPTY; continue; + } - for (j = 0; j < x38_channel_num; j++) { - struct dimm_info *dimm = csrow->channels[j].dimm; + csrow->first_page = last_page + 1; + last_page += nr_pages; + csrow->last_page = last_page; + csrow->nr_pages = nr_pages; - dimm->nr_pages = nr_pages / x38_channel_num; - dimm->grain = nr_pages << PAGE_SHIFT; - dimm->mtype = MEM_DDR2; - dimm->dtype = DEV_UNKNOWN; - dimm->edac_mode = EDAC_UNKNOWN; - } + csrow->grain = nr_pages << PAGE_SHIFT; + csrow->mtype = MEM_DDR2; + csrow->dtype = DEV_UNKNOWN; + csrow->edac_mode = EDAC_UNKNOWN; } x38_clear_error_info(mci); diff --git a/trunk/drivers/gpio/Kconfig b/trunk/drivers/gpio/Kconfig index c4067d0141f7..0356099ae040 100644 --- a/trunk/drivers/gpio/Kconfig +++ b/trunk/drivers/gpio/Kconfig @@ -114,14 +114,6 @@ config GPIO_EP93XX depends on ARCH_EP93XX select GPIO_GENERIC -config GPIO_MM_LANTIQ - bool "Lantiq Memory mapped GPIOs" - depends on LANTIQ && SOC_XWAY - help - This enables support for memory mapped GPIOs on the External Bus Unit - (EBU) found on Lantiq SoCs. The gpios are output only as they are - created by attaching a 16bit latch to the bus. - config GPIO_MPC5200 def_bool y depends on PPC_MPC52xx @@ -366,16 +358,6 @@ config GPIO_STMPE This enables support for the GPIOs found on the STMPE I/O Expanders. -config GPIO_STP_XWAY - bool "XWAY STP GPIOs" - depends on SOC_XWAY - help - This enables support for the Serial To Parallel (STP) unit found on - XWAY SoC. The STP allows the SoC to drive a shift registers cascade, - that can be up to 24 bit. This peripheral is aimed at driving leds. - Some of the gpios/leds can be auto updated by the soc with dsl and - phy status. - config GPIO_TC3589X bool "TC3589X GPIOs" depends on MFD_TC3589X diff --git a/trunk/drivers/gpio/Makefile b/trunk/drivers/gpio/Makefile index 0f55662002c3..fde36e5e3537 100644 --- a/trunk/drivers/gpio/Makefile +++ b/trunk/drivers/gpio/Makefile @@ -33,7 +33,6 @@ obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o -obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o @@ -55,7 +54,6 @@ obj-$(CONFIG_GPIO_SCH) += gpio-sch.o obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o -obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o diff --git a/trunk/drivers/gpio/gpio-mm-lantiq.c b/trunk/drivers/gpio/gpio-mm-lantiq.c deleted file mode 100644 index 2983dfbd0668..000000000000 --- a/trunk/drivers/gpio/gpio-mm-lantiq.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2012 John Crispin - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * By attaching hardware latches to the EBU it is possible to create output - * only gpios. This driver configures a special memory address, which when - * written to outputs 16 bit to the latches. - */ - -#define LTQ_EBU_BUSCON 0x1e7ff /* 16 bit access, slowest timing */ -#define LTQ_EBU_WP 0x80000000 /* write protect bit */ - -struct ltq_mm { - struct of_mm_gpio_chip mmchip; - u16 shadow; /* shadow the latches state */ -}; - -/** - * ltq_mm_apply() - write the shadow value to the ebu address. - * @chip: Pointer to our private data structure. - * - * Write the shadow value to the EBU to set the gpios. We need to set the - * global EBU lock to make sure that PCI/MTD dont break. - */ -static void ltq_mm_apply(struct ltq_mm *chip) -{ - unsigned long flags; - - spin_lock_irqsave(&ebu_lock, flags); - ltq_ebu_w32(LTQ_EBU_BUSCON, LTQ_EBU_BUSCON1); - __raw_writew(chip->shadow, chip->mmchip.regs); - ltq_ebu_w32(LTQ_EBU_BUSCON | LTQ_EBU_WP, LTQ_EBU_BUSCON1); - spin_unlock_irqrestore(&ebu_lock, flags); -} - -/** - * ltq_mm_set() - gpio_chip->set - set gpios. - * @gc: Pointer to gpio_chip device structure. - * @gpio: GPIO signal number. - * @val: Value to be written to specified signal. - * - * Set the shadow value and call ltq_mm_apply. - */ -static void ltq_mm_set(struct gpio_chip *gc, unsigned offset, int value) -{ - struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - struct ltq_mm *chip = - container_of(mm_gc, struct ltq_mm, mmchip); - - if (value) - chip->shadow |= (1 << offset); - else - chip->shadow &= ~(1 << offset); - ltq_mm_apply(chip); -} - -/** - * ltq_mm_dir_out() - gpio_chip->dir_out - set gpio direction. - * @gc: Pointer to gpio_chip device structure. - * @gpio: GPIO signal number. - * @val: Value to be written to specified signal. - * - * Same as ltq_mm_set, always returns 0. - */ -static int ltq_mm_dir_out(struct gpio_chip *gc, unsigned offset, int value) -{ - ltq_mm_set(gc, offset, value); - - return 0; -} - -/** - * ltq_mm_save_regs() - Set initial values of GPIO pins - * @mm_gc: pointer to memory mapped GPIO chip structure - */ -static void ltq_mm_save_regs(struct of_mm_gpio_chip *mm_gc) -{ - struct ltq_mm *chip = - container_of(mm_gc, struct ltq_mm, mmchip); - - /* tell the ebu controller which memory address we will be using */ - ltq_ebu_w32(CPHYSADDR(chip->mmchip.regs) | 0x1, LTQ_EBU_ADDRSEL1); - - ltq_mm_apply(chip); -} - -static int ltq_mm_probe(struct platform_device *pdev) -{ - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct ltq_mm *chip; - const __be32 *shadow; - int ret = 0; - - if (!res) { - dev_err(&pdev->dev, "failed to get memory resource\n"); - return -ENOENT; - } - - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - chip->mmchip.gc.ngpio = 16; - chip->mmchip.gc.label = "gpio-mm-ltq"; - chip->mmchip.gc.direction_output = ltq_mm_dir_out; - chip->mmchip.gc.set = ltq_mm_set; - chip->mmchip.save_regs = ltq_mm_save_regs; - - /* store the shadow value if one was passed by the devicetree */ - shadow = of_get_property(pdev->dev.of_node, "lantiq,shadow", NULL); - if (shadow) - chip->shadow = be32_to_cpu(*shadow); - - ret = of_mm_gpiochip_add(pdev->dev.of_node, &chip->mmchip); - if (ret) - kfree(chip); - return ret; -} - -static const struct of_device_id ltq_mm_match[] = { - { .compatible = "lantiq,gpio-mm" }, - {}, -}; -MODULE_DEVICE_TABLE(of, ltq_mm_match); - -static struct platform_driver ltq_mm_driver = { - .probe = ltq_mm_probe, - .driver = { - .name = "gpio-mm-ltq", - .owner = THIS_MODULE, - .of_match_table = ltq_mm_match, - }, -}; - -static int __init ltq_mm_init(void) -{ - return platform_driver_register(<q_mm_driver); -} - -subsys_initcall(ltq_mm_init); diff --git a/trunk/drivers/gpio/gpio-stp-xway.c b/trunk/drivers/gpio/gpio-stp-xway.c deleted file mode 100644 index e35096bf3cfb..000000000000 --- a/trunk/drivers/gpio/gpio-stp-xway.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2012 John Crispin - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * The Serial To Parallel (STP) is found on MIPS based Lantiq socs. It is a - * peripheral controller used to drive external shift register cascades. At most - * 3 groups of 8 bits can be driven. The hardware is able to allow the DSL modem - * to drive the 2 LSBs of the cascade automatically. - */ - -/* control register 0 */ -#define XWAY_STP_CON0 0x00 -/* control register 1 */ -#define XWAY_STP_CON1 0x04 -/* data register 0 */ -#define XWAY_STP_CPU0 0x08 -/* data register 1 */ -#define XWAY_STP_CPU1 0x0C -/* access register */ -#define XWAY_STP_AR 0x10 - -/* software or hardware update select bit */ -#define XWAY_STP_CON_SWU BIT(31) - -/* automatic update rates */ -#define XWAY_STP_2HZ 0 -#define XWAY_STP_4HZ BIT(23) -#define XWAY_STP_8HZ BIT(24) -#define XWAY_STP_10HZ (BIT(24) | BIT(23)) -#define XWAY_STP_SPEED_MASK (0xf << 23) - -/* clock source for automatic update */ -#define XWAY_STP_UPD_FPI BIT(31) -#define XWAY_STP_UPD_MASK (BIT(31) | BIT(30)) - -/* let the adsl core drive the 2 LSBs */ -#define XWAY_STP_ADSL_SHIFT 24 -#define XWAY_STP_ADSL_MASK 0x3 - -/* 2 groups of 3 bits can be driven by the phys */ -#define XWAY_STP_PHY_MASK 0x3 -#define XWAY_STP_PHY1_SHIFT 27 -#define XWAY_STP_PHY2_SHIFT 15 - -/* STP has 3 groups of 8 bits */ -#define XWAY_STP_GROUP0 BIT(0) -#define XWAY_STP_GROUP1 BIT(1) -#define XWAY_STP_GROUP2 BIT(2) -#define XWAY_STP_GROUP_MASK (0x7) - -/* Edge configuration bits */ -#define XWAY_STP_FALLING BIT(26) -#define XWAY_STP_EDGE_MASK BIT(26) - -#define xway_stp_r32(m, reg) __raw_readl(m + reg) -#define xway_stp_w32(m, val, reg) __raw_writel(val, m + reg) -#define xway_stp_w32_mask(m, clear, set, reg) \ - ltq_w32((ltq_r32(m + reg) & ~(clear)) | (set), \ - m + reg) - -struct xway_stp { - struct gpio_chip gc; - void __iomem *virt; - u32 edge; /* rising or falling edge triggered shift register */ - u16 shadow; /* shadow the shift registers state */ - u8 groups; /* we can drive 1-3 groups of 8bit each */ - u8 dsl; /* the 2 LSBs can be driven by the dsl core */ - u8 phy1; /* 3 bits can be driven by phy1 */ - u8 phy2; /* 3 bits can be driven by phy2 */ - u8 reserved; /* mask out the hw driven bits in gpio_request */ -}; - -/** - * xway_stp_set() - gpio_chip->set - set gpios. - * @gc: Pointer to gpio_chip device structure. - * @gpio: GPIO signal number. - * @val: Value to be written to specified signal. - * - * Set the shadow value and call ltq_ebu_apply. - */ -static void xway_stp_set(struct gpio_chip *gc, unsigned gpio, int val) -{ - struct xway_stp *chip = - container_of(gc, struct xway_stp, gc); - - if (val) - chip->shadow |= BIT(gpio); - else - chip->shadow &= ~BIT(gpio); - xway_stp_w32(chip->virt, chip->shadow, XWAY_STP_CPU0); - xway_stp_w32_mask(chip->virt, 0, XWAY_STP_CON_SWU, XWAY_STP_CON0); -} - -/** - * xway_stp_dir_out() - gpio_chip->dir_out - set gpio direction. - * @gc: Pointer to gpio_chip device structure. - * @gpio: GPIO signal number. - * @val: Value to be written to specified signal. - * - * Same as xway_stp_set, always returns 0. - */ -static int xway_stp_dir_out(struct gpio_chip *gc, unsigned gpio, int val) -{ - xway_stp_set(gc, gpio, val); - - return 0; -} - -/** - * xway_stp_request() - gpio_chip->request - * @gc: Pointer to gpio_chip device structure. - * @gpio: GPIO signal number. - * - * We mask out the HW driven pins - */ -static int xway_stp_request(struct gpio_chip *gc, unsigned gpio) -{ - struct xway_stp *chip = - container_of(gc, struct xway_stp, gc); - - if ((gpio < 8) && (chip->reserved & BIT(gpio))) { - dev_err(gc->dev, "GPIO %d is driven by hardware\n", gpio); - return -ENODEV; - } - - return 0; -} - -/** - * xway_stp_hw_init() - Configure the STP unit and enable the clock gate - * @virt: pointer to the remapped register range - */ -static int xway_stp_hw_init(struct xway_stp *chip) -{ - /* sane defaults */ - xway_stp_w32(chip->virt, 0, XWAY_STP_AR); - xway_stp_w32(chip->virt, 0, XWAY_STP_CPU0); - xway_stp_w32(chip->virt, 0, XWAY_STP_CPU1); - xway_stp_w32(chip->virt, XWAY_STP_CON_SWU, XWAY_STP_CON0); - xway_stp_w32(chip->virt, 0, XWAY_STP_CON1); - - /* apply edge trigger settings for the shift register */ - xway_stp_w32_mask(chip->virt, XWAY_STP_EDGE_MASK, - chip->edge, XWAY_STP_CON0); - - /* apply led group settings */ - xway_stp_w32_mask(chip->virt, XWAY_STP_GROUP_MASK, - chip->groups, XWAY_STP_CON1); - - /* tell the hardware which pins are controlled by the dsl modem */ - xway_stp_w32_mask(chip->virt, - XWAY_STP_ADSL_MASK << XWAY_STP_ADSL_SHIFT, - chip->dsl << XWAY_STP_ADSL_SHIFT, - XWAY_STP_CON0); - - /* tell the hardware which pins are controlled by the phys */ - xway_stp_w32_mask(chip->virt, - XWAY_STP_PHY_MASK << XWAY_STP_PHY1_SHIFT, - chip->phy1 << XWAY_STP_PHY1_SHIFT, - XWAY_STP_CON0); - xway_stp_w32_mask(chip->virt, - XWAY_STP_PHY_MASK << XWAY_STP_PHY2_SHIFT, - chip->phy2 << XWAY_STP_PHY2_SHIFT, - XWAY_STP_CON1); - - /* mask out the hw driven bits in gpio_request */ - chip->reserved = (chip->phy2 << 5) | (chip->phy1 << 2) | chip->dsl; - - /* - * if we have pins that are driven by hw, we need to tell the stp what - * clock to use as a timer. - */ - if (chip->reserved) - xway_stp_w32_mask(chip->virt, XWAY_STP_UPD_MASK, - XWAY_STP_UPD_FPI, XWAY_STP_CON1); - - return 0; -} - -static int __devinit xway_stp_probe(struct platform_device *pdev) -{ - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - const __be32 *shadow, *groups, *dsl, *phy; - struct xway_stp *chip; - struct clk *clk; - int ret = 0; - - if (!res) { - dev_err(&pdev->dev, "failed to request STP resource\n"); - return -ENOENT; - } - - chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - chip->virt = devm_request_and_ioremap(&pdev->dev, res); - if (!chip->virt) { - dev_err(&pdev->dev, "failed to remap STP memory\n"); - return -ENOMEM; - } - chip->gc.dev = &pdev->dev; - chip->gc.label = "stp-xway"; - chip->gc.direction_output = xway_stp_dir_out; - chip->gc.set = xway_stp_set; - chip->gc.request = xway_stp_request; - chip->gc.base = -1; - chip->gc.owner = THIS_MODULE; - - /* store the shadow value if one was passed by the devicetree */ - shadow = of_get_property(pdev->dev.of_node, "lantiq,shadow", NULL); - if (shadow) - chip->shadow = be32_to_cpu(*shadow); - - /* find out which gpio groups should be enabled */ - groups = of_get_property(pdev->dev.of_node, "lantiq,groups", NULL); - if (groups) - chip->groups = be32_to_cpu(*groups) & XWAY_STP_GROUP_MASK; - else - chip->groups = XWAY_STP_GROUP0; - chip->gc.ngpio = fls(chip->groups) * 8; - - /* find out which gpios are controlled by the dsl core */ - dsl = of_get_property(pdev->dev.of_node, "lantiq,dsl", NULL); - if (dsl) - chip->dsl = be32_to_cpu(*dsl) & XWAY_STP_ADSL_MASK; - - /* find out which gpios are controlled by the phys */ - if (of_machine_is_compatible("lantiq,ar9") || - of_machine_is_compatible("lantiq,gr9") || - of_machine_is_compatible("lantiq,vr9")) { - phy = of_get_property(pdev->dev.of_node, "lantiq,phy1", NULL); - if (phy) - chip->phy1 = be32_to_cpu(*phy) & XWAY_STP_PHY_MASK; - phy = of_get_property(pdev->dev.of_node, "lantiq,phy2", NULL); - if (phy) - chip->phy2 = be32_to_cpu(*phy) & XWAY_STP_PHY_MASK; - } - - /* check which edge trigger we should use, default to a falling edge */ - if (!of_find_property(pdev->dev.of_node, "lantiq,rising", NULL)) - chip->edge = XWAY_STP_FALLING; - - clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(clk)) { - dev_err(&pdev->dev, "Failed to get clock\n"); - return PTR_ERR(clk); - } - clk_enable(clk); - - ret = xway_stp_hw_init(chip); - if (!ret) - ret = gpiochip_add(&chip->gc); - - if (!ret) - dev_info(&pdev->dev, "Init done\n"); - - return ret; -} - -static const struct of_device_id xway_stp_match[] = { - { .compatible = "lantiq,gpio-stp-xway" }, - {}, -}; -MODULE_DEVICE_TABLE(of, xway_stp_match); - -static struct platform_driver xway_stp_driver = { - .probe = xway_stp_probe, - .driver = { - .name = "gpio-stp-xway", - .owner = THIS_MODULE, - .of_match_table = xway_stp_match, - }, -}; - -int __init xway_stp_init(void) -{ - return platform_driver_register(&xway_stp_driver); -} - -subsys_initcall(xway_stp_init); diff --git a/trunk/drivers/gpu/drm/cirrus/cirrus_drv.c b/trunk/drivers/gpu/drm/cirrus/cirrus_drv.c index 7053140c6596..d7038230b71e 100644 --- a/trunk/drivers/gpu/drm/cirrus/cirrus_drv.c +++ b/trunk/drivers/gpu/drm/cirrus/cirrus_drv.c @@ -35,28 +35,9 @@ static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { {0,} }; - -static void cirrus_kick_out_firmware_fb(struct pci_dev *pdev) -{ - struct apertures_struct *ap; - bool primary = false; - - ap = alloc_apertures(1); - ap->ranges[0].base = pci_resource_start(pdev, 0); - ap->ranges[0].size = pci_resource_len(pdev, 0); - -#ifdef CONFIG_X86 - primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; -#endif - remove_conflicting_framebuffers(ap, "cirrusdrmfb", primary); - kfree(ap); -} - static int __devinit cirrus_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - cirrus_kick_out_firmware_fb(pdev); - return drm_get_pci_dev(pdev, ent, &driver); } diff --git a/trunk/drivers/gpu/drm/cirrus/cirrus_drv.h b/trunk/drivers/gpu/drm/cirrus/cirrus_drv.h index 64ea597cb6d3..21bdfa8836f7 100644 --- a/trunk/drivers/gpu/drm/cirrus/cirrus_drv.h +++ b/trunk/drivers/gpu/drm/cirrus/cirrus_drv.h @@ -145,7 +145,7 @@ struct cirrus_device { struct ttm_bo_device bdev; atomic_t validate_sequence; } ttm; - bool mm_inited; + }; diff --git a/trunk/drivers/gpu/drm/cirrus/cirrus_ttm.c b/trunk/drivers/gpu/drm/cirrus/cirrus_ttm.c index 50e170f879de..2ebcd11a5023 100644 --- a/trunk/drivers/gpu/drm/cirrus/cirrus_ttm.c +++ b/trunk/drivers/gpu/drm/cirrus/cirrus_ttm.c @@ -275,17 +275,12 @@ int cirrus_mm_init(struct cirrus_device *cirrus) pci_resource_len(dev->pdev, 0), DRM_MTRR_WC); - cirrus->mm_inited = true; return 0; } void cirrus_mm_fini(struct cirrus_device *cirrus) { struct drm_device *dev = cirrus->dev; - - if (!cirrus->mm_inited) - return; - ttm_bo_device_release(&cirrus->ttm.bdev); cirrus_ttm_global_release(cirrus); diff --git a/trunk/drivers/gpu/drm/drm_crtc.c b/trunk/drivers/gpu/drm/drm_crtc.c index 08a7aa722d6b..92cea9d77ec9 100644 --- a/trunk/drivers/gpu/drm/drm_crtc.c +++ b/trunk/drivers/gpu/drm/drm_crtc.c @@ -2116,7 +2116,7 @@ int drm_mode_addfb(struct drm_device *dev, return ret; } -static int format_check(const struct drm_mode_fb_cmd2 *r) +static int format_check(struct drm_mode_fb_cmd2 *r) { uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN; @@ -2185,7 +2185,7 @@ static int format_check(const struct drm_mode_fb_cmd2 *r) } } -static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) +static int framebuffer_check(struct drm_mode_fb_cmd2 *r) { int ret, hsub, vsub, num_planes, i; @@ -3126,7 +3126,7 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, EXPORT_SYMBOL(drm_mode_connector_update_edid_property); static bool drm_property_change_is_valid(struct drm_property *property, - uint64_t value) + __u64 value) { if (property->flags & DRM_MODE_PROP_IMMUTABLE) return false; @@ -3136,7 +3136,7 @@ static bool drm_property_change_is_valid(struct drm_property *property, return true; } else if (property->flags & DRM_MODE_PROP_BITMASK) { int i; - uint64_t valid_mask = 0; + __u64 valid_mask = 0; for (i = 0; i < property->num_values; i++) valid_mask |= (1ULL << property->values[i]); return !(value & ~valid_mask); diff --git a/trunk/drivers/gpu/drm/drm_edid.c b/trunk/drivers/gpu/drm/drm_edid.c index eb92fe257a39..608bddfc7e35 100644 --- a/trunk/drivers/gpu/drm/drm_edid.c +++ b/trunk/drivers/gpu/drm/drm_edid.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include "drmP.h" #include "drm_edid.h" #include "drm_edid_modes.h" @@ -66,8 +66,6 @@ #define EDID_QUIRK_FIRST_DETAILED_PREFERRED (1 << 5) /* use +hsync +vsync for detailed mode */ #define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6) -/* Force reduced-blanking timings for detailed modes */ -#define EDID_QUIRK_FORCE_REDUCED_BLANKING (1 << 7) struct detailed_mode_closure { struct drm_connector *connector; @@ -122,9 +120,6 @@ static struct edid_quirk { /* Samsung SyncMaster 22[5-6]BW */ { "SAM", 596, EDID_QUIRK_PREFER_LARGE_60 }, { "SAM", 638, EDID_QUIRK_PREFER_LARGE_60 }, - - /* ViewSonic VA2026w */ - { "VSC", 5020, EDID_QUIRK_FORCE_REDUCED_BLANKING }, }; /*** DDC fetch and block validation ***/ @@ -149,10 +144,6 @@ int drm_edid_header_is_valid(const u8 *raw_edid) } EXPORT_SYMBOL(drm_edid_header_is_valid); -static int edid_fixup __read_mostly = 6; -module_param_named(edid_fixup, edid_fixup, int, 0400); -MODULE_PARM_DESC(edid_fixup, - "Minimum number of valid EDID header bytes (0-8, default 6)"); /* * Sanity check the EDID block (base or extension). Return 0 if the block @@ -164,13 +155,10 @@ bool drm_edid_block_valid(u8 *raw_edid, int block) u8 csum = 0; struct edid *edid = (struct edid *)raw_edid; - if (edid_fixup > 8 || edid_fixup < 0) - edid_fixup = 6; - if (block == 0) { int score = drm_edid_header_is_valid(raw_edid); if (score == 8) ; - else if (score >= edid_fixup) { + else if (score >= 6) { DRM_DEBUG("Fixing EDID header, your hardware may be failing\n"); memcpy(raw_edid, edid_header, sizeof(edid_header)); } else { @@ -897,19 +885,12 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, "Wrong Hsync/Vsync pulse width\n"); return NULL; } - - if (quirks & EDID_QUIRK_FORCE_REDUCED_BLANKING) { - mode = drm_cvt_mode(dev, hactive, vactive, 60, true, false, false); - if (!mode) - return NULL; - - goto set_size; - } - mode = drm_mode_create(dev); if (!mode) return NULL; + mode->type = DRM_MODE_TYPE_DRIVER; + if (quirks & EDID_QUIRK_135_CLOCK_TOO_HIGH) timing->pixel_clock = cpu_to_le16(1088); @@ -933,6 +914,8 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, drm_mode_do_interlace_quirk(mode, pt); + drm_mode_set_name(mode); + if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) { pt->misc |= DRM_EDID_PT_HSYNC_POSITIVE | DRM_EDID_PT_VSYNC_POSITIVE; } @@ -942,7 +925,6 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, mode->flags |= (pt->misc & DRM_EDID_PT_VSYNC_POSITIVE) ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; -set_size: mode->width_mm = pt->width_mm_lo | (pt->width_height_mm_hi & 0xf0) << 4; mode->height_mm = pt->height_mm_lo | (pt->width_height_mm_hi & 0xf) << 8; @@ -956,9 +938,6 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, mode->height_mm = edid->height_cm * 10; } - mode->type = DRM_MODE_TYPE_DRIVER; - drm_mode_set_name(mode); - return mode; } diff --git a/trunk/drivers/gpu/drm/i810/i810_dma.c b/trunk/drivers/gpu/drm/i810/i810_dma.c index fa9439159ebd..f920fb5e42b6 100644 --- a/trunk/drivers/gpu/drm/i810/i810_dma.c +++ b/trunk/drivers/gpu/drm/i810/i810_dma.c @@ -130,10 +130,11 @@ static int i810_map_buffer(struct drm_buf *buf, struct drm_file *file_priv) return -EINVAL; /* This is all entirely broken */ + down_write(¤t->mm->mmap_sem); old_fops = file_priv->filp->f_op; file_priv->filp->f_op = &i810_buffer_fops; dev_priv->mmap_buffer = buf; - buf_priv->virtual = (void *)vm_mmap(file_priv->filp, 0, buf->total, + buf_priv->virtual = (void *)do_mmap(file_priv->filp, 0, buf->total, PROT_READ | PROT_WRITE, MAP_SHARED, buf->bus_address); dev_priv->mmap_buffer = NULL; @@ -144,6 +145,7 @@ static int i810_map_buffer(struct drm_buf *buf, struct drm_file *file_priv) retcode = PTR_ERR(buf_priv->virtual); buf_priv->virtual = NULL; } + up_write(¤t->mm->mmap_sem); return retcode; } diff --git a/trunk/drivers/gpu/drm/i915/i915_debugfs.c b/trunk/drivers/gpu/drm/i915/i915_debugfs.c index 5363e9c66c27..eb2b3c25b9e1 100644 --- a/trunk/drivers/gpu/drm/i915/i915_debugfs.c +++ b/trunk/drivers/gpu/drm/i915/i915_debugfs.c @@ -2032,8 +2032,6 @@ void i915_debugfs_cleanup(struct drm_minor *minor) 1, minor); drm_debugfs_remove_files((struct drm_info_list *) &i915_ring_stop_fops, 1, minor); - drm_debugfs_remove_files((struct drm_info_list *) &i915_error_state_fops, - 1, minor); } #endif /* CONFIG_DEBUG_FS */ diff --git a/trunk/drivers/gpu/drm/i915/i915_drv.h b/trunk/drivers/gpu/drm/i915/i915_drv.h index c9cfc67c2cf5..377c21f531e4 100644 --- a/trunk/drivers/gpu/drm/i915/i915_drv.h +++ b/trunk/drivers/gpu/drm/i915/i915_drv.h @@ -942,9 +942,6 @@ struct drm_i915_gem_object { /* prime dma-buf support */ struct sg_table *sg_table; - void *dma_buf_vmapping; - int vmapping_count; - /** * Used for performing relocations during execbuffer insertion. */ diff --git a/trunk/drivers/gpu/drm/i915/i915_gem.c b/trunk/drivers/gpu/drm/i915/i915_gem.c index 288d7b8f49ae..c1e5c66553df 100644 --- a/trunk/drivers/gpu/drm/i915/i915_gem.c +++ b/trunk/drivers/gpu/drm/i915/i915_gem.c @@ -2063,8 +2063,10 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj) if (obj->gtt_space == NULL) return 0; - if (obj->pin_count) - return -EBUSY; + if (obj->pin_count != 0) { + DRM_ERROR("Attempting to unbind pinned buffer\n"); + return -EINVAL; + } ret = i915_gem_object_finish_gpu(obj); if (ret) @@ -3291,7 +3293,6 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; struct address_space *mapping; - u32 mask; obj = kzalloc(sizeof(*obj), GFP_KERNEL); if (obj == NULL) @@ -3302,15 +3303,8 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, return NULL; } - mask = GFP_HIGHUSER | __GFP_RECLAIMABLE; - if (IS_CRESTLINE(dev) || IS_BROADWATER(dev)) { - /* 965gm cannot relocate objects above 4GiB. */ - mask &= ~__GFP_HIGHMEM; - mask |= __GFP_DMA32; - } - mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping; - mapping_set_gfp_mask(mapping, mask); + mapping_set_gfp_mask(mapping, GFP_HIGHUSER | __GFP_RECLAIMABLE); i915_gem_info_add_obj(dev_priv, size); diff --git a/trunk/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/trunk/drivers/gpu/drm/i915/i915_gem_dmabuf.c index aa308e1337db..8e269178d6a5 100644 --- a/trunk/drivers/gpu/drm/i915/i915_gem_dmabuf.c +++ b/trunk/drivers/gpu/drm/i915/i915_gem_dmabuf.c @@ -74,59 +74,6 @@ static void i915_gem_dmabuf_release(struct dma_buf *dma_buf) } } -static void *i915_gem_dmabuf_vmap(struct dma_buf *dma_buf) -{ - struct drm_i915_gem_object *obj = dma_buf->priv; - struct drm_device *dev = obj->base.dev; - int ret; - - ret = i915_mutex_lock_interruptible(dev); - if (ret) - return ERR_PTR(ret); - - if (obj->dma_buf_vmapping) { - obj->vmapping_count++; - goto out_unlock; - } - - if (!obj->pages) { - ret = i915_gem_object_get_pages_gtt(obj, __GFP_NORETRY | __GFP_NOWARN); - if (ret) { - mutex_unlock(&dev->struct_mutex); - return ERR_PTR(ret); - } - } - - obj->dma_buf_vmapping = vmap(obj->pages, obj->base.size / PAGE_SIZE, 0, PAGE_KERNEL); - if (!obj->dma_buf_vmapping) { - DRM_ERROR("failed to vmap object\n"); - goto out_unlock; - } - - obj->vmapping_count = 1; -out_unlock: - mutex_unlock(&dev->struct_mutex); - return obj->dma_buf_vmapping; -} - -static void i915_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr) -{ - struct drm_i915_gem_object *obj = dma_buf->priv; - struct drm_device *dev = obj->base.dev; - int ret; - - ret = i915_mutex_lock_interruptible(dev); - if (ret) - return; - - --obj->vmapping_count; - if (obj->vmapping_count == 0) { - vunmap(obj->dma_buf_vmapping); - obj->dma_buf_vmapping = NULL; - } - mutex_unlock(&dev->struct_mutex); -} - static void *i915_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf, unsigned long page_num) { return NULL; @@ -146,11 +93,6 @@ static void i915_gem_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_n } -static int i915_gem_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma) -{ - return -EINVAL; -} - static const struct dma_buf_ops i915_dmabuf_ops = { .map_dma_buf = i915_gem_map_dma_buf, .unmap_dma_buf = i915_gem_unmap_dma_buf, @@ -159,9 +101,6 @@ static const struct dma_buf_ops i915_dmabuf_ops = { .kmap_atomic = i915_gem_dmabuf_kmap_atomic, .kunmap = i915_gem_dmabuf_kunmap, .kunmap_atomic = i915_gem_dmabuf_kunmap_atomic, - .mmap = i915_gem_dmabuf_mmap, - .vmap = i915_gem_dmabuf_vmap, - .vunmap = i915_gem_dmabuf_vunmap, }; struct dma_buf *i915_gem_prime_export(struct drm_device *dev, diff --git a/trunk/drivers/gpu/drm/i915/i915_irq.c b/trunk/drivers/gpu/drm/i915/i915_irq.c index 1417660a93ec..cc4a63307611 100644 --- a/trunk/drivers/gpu/drm/i915/i915_irq.c +++ b/trunk/drivers/gpu/drm/i915/i915_irq.c @@ -350,8 +350,8 @@ static void gen6_pm_rps_work(struct work_struct *work) { drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, rps_work); + u8 new_delay = dev_priv->cur_delay; u32 pm_iir, pm_imr; - u8 new_delay; spin_lock_irq(&dev_priv->rps_lock); pm_iir = dev_priv->pm_iir; @@ -360,18 +360,41 @@ static void gen6_pm_rps_work(struct work_struct *work) I915_WRITE(GEN6_PMIMR, 0); spin_unlock_irq(&dev_priv->rps_lock); - if ((pm_iir & GEN6_PM_DEFERRED_EVENTS) == 0) + if (!pm_iir) return; mutex_lock(&dev_priv->dev->struct_mutex); - - if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) - new_delay = dev_priv->cur_delay + 1; - else - new_delay = dev_priv->cur_delay - 1; + if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) { + if (dev_priv->cur_delay != dev_priv->max_delay) + new_delay = dev_priv->cur_delay + 1; + if (new_delay > dev_priv->max_delay) + new_delay = dev_priv->max_delay; + } else if (pm_iir & (GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT)) { + gen6_gt_force_wake_get(dev_priv); + if (dev_priv->cur_delay != dev_priv->min_delay) + new_delay = dev_priv->cur_delay - 1; + if (new_delay < dev_priv->min_delay) { + new_delay = dev_priv->min_delay; + I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, + I915_READ(GEN6_RP_INTERRUPT_LIMITS) | + ((new_delay << 16) & 0x3f0000)); + } else { + /* Make sure we continue to get down interrupts + * until we hit the minimum frequency */ + I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, + I915_READ(GEN6_RP_INTERRUPT_LIMITS) & ~0x3f0000); + } + gen6_gt_force_wake_put(dev_priv); + } gen6_set_rps(dev_priv->dev, new_delay); + dev_priv->cur_delay = new_delay; + /* + * rps_lock not held here because clearing is non-destructive. There is + * an *extremely* unlikely race with gen6_rps_enable() that is prevented + * by holding struct_mutex for the duration of the write. + */ mutex_unlock(&dev_priv->dev->struct_mutex); } diff --git a/trunk/drivers/gpu/drm/i915/intel_display.c b/trunk/drivers/gpu/drm/i915/intel_display.c index 914789420906..ee61ad1e642b 100644 --- a/trunk/drivers/gpu/drm/i915/intel_display.c +++ b/trunk/drivers/gpu/drm/i915/intel_display.c @@ -910,10 +910,9 @@ static void assert_pll(struct drm_i915_private *dev_priv, /* For ILK+ */ static void assert_pch_pll(struct drm_i915_private *dev_priv, - struct intel_pch_pll *pll, - struct intel_crtc *crtc, - bool state) + struct intel_crtc *intel_crtc, bool state) { + int reg; u32 val; bool cur_state; @@ -922,37 +921,30 @@ static void assert_pch_pll(struct drm_i915_private *dev_priv, return; } - if (WARN (!pll, - "asserting PCH PLL %s with no PLL\n", state_string(state))) + if (!intel_crtc->pch_pll) { + WARN(1, "asserting PCH PLL enabled with no PLL\n"); return; + } - val = I915_READ(pll->pll_reg); - cur_state = !!(val & DPLL_VCO_ENABLE); - WARN(cur_state != state, - "PCH PLL state for reg %x assertion failure (expected %s, current %s), val=%08x\n", - pll->pll_reg, state_string(state), state_string(cur_state), val); - - /* Make sure the selected PLL is correctly attached to the transcoder */ - if (crtc && HAS_PCH_CPT(dev_priv->dev)) { + if (HAS_PCH_CPT(dev_priv->dev)) { u32 pch_dpll; pch_dpll = I915_READ(PCH_DPLL_SEL); - cur_state = pll->pll_reg == _PCH_DPLL_B; - if (!WARN(((pch_dpll >> (4 * crtc->pipe)) & 1) != cur_state, - "PLL[%d] not attached to this transcoder %d: %08x\n", - cur_state, crtc->pipe, pch_dpll)) { - cur_state = !!(val >> (4*crtc->pipe + 3)); - WARN(cur_state != state, - "PLL[%d] not %s on this transcoder %d: %08x\n", - pll->pll_reg == _PCH_DPLL_B, - state_string(state), - crtc->pipe, - val); - } + + /* Make sure the selected PLL is enabled to the transcoder */ + WARN(!((pch_dpll >> (4 * intel_crtc->pipe)) & 8), + "transcoder %d PLL not enabled\n", intel_crtc->pipe); } + + reg = intel_crtc->pch_pll->pll_reg; + val = I915_READ(reg); + cur_state = !!(val & DPLL_VCO_ENABLE); + WARN(cur_state != state, + "PCH PLL state assertion failure (expected %s, current %s)\n", + state_string(state), state_string(cur_state)); } -#define assert_pch_pll_enabled(d, p, c) assert_pch_pll(d, p, c, true) -#define assert_pch_pll_disabled(d, p, c) assert_pch_pll(d, p, c, false) +#define assert_pch_pll_enabled(d, p) assert_pch_pll(d, p, true) +#define assert_pch_pll_disabled(d, p) assert_pch_pll(d, p, false) static void assert_fdi_tx(struct drm_i915_private *dev_priv, enum pipe pipe, bool state) @@ -1432,7 +1424,7 @@ static void intel_enable_pch_pll(struct intel_crtc *intel_crtc) assert_pch_refclk_enabled(dev_priv); if (pll->active++ && pll->on) { - assert_pch_pll_enabled(dev_priv, pll, NULL); + assert_pch_pll_enabled(dev_priv, intel_crtc); return; } @@ -1468,12 +1460,12 @@ static void intel_disable_pch_pll(struct intel_crtc *intel_crtc) intel_crtc->base.base.id); if (WARN_ON(pll->active == 0)) { - assert_pch_pll_disabled(dev_priv, pll, NULL); + assert_pch_pll_disabled(dev_priv, intel_crtc); return; } if (--pll->active) { - assert_pch_pll_enabled(dev_priv, pll, NULL); + assert_pch_pll_enabled(dev_priv, intel_crtc); return; } @@ -1503,9 +1495,7 @@ static void intel_enable_transcoder(struct drm_i915_private *dev_priv, BUG_ON(dev_priv->info->gen < 5); /* Make sure PCH DPLL is enabled */ - assert_pch_pll_enabled(dev_priv, - to_intel_crtc(crtc)->pch_pll, - to_intel_crtc(crtc)); + assert_pch_pll_enabled(dev_priv, to_intel_crtc(crtc)); /* FDI must be feeding us bits for PCH ports */ assert_fdi_tx_enabled(dev_priv, pipe); diff --git a/trunk/drivers/gpu/drm/i915/intel_dp.c b/trunk/drivers/gpu/drm/i915/intel_dp.c index 296cfc201a81..71c7096e3869 100644 --- a/trunk/drivers/gpu/drm/i915/intel_dp.c +++ b/trunk/drivers/gpu/drm/i915/intel_dp.c @@ -266,9 +266,6 @@ intel_dp_mode_valid(struct drm_connector *connector, if (mode->clock < 10000) return MODE_CLOCK_LOW; - if (mode->flags & DRM_MODE_FLAG_DBLCLK) - return MODE_H_ILLEGAL; - return MODE_OK; } @@ -705,9 +702,6 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, mode->clock = intel_dp->panel_fixed_mode->clock; } - if (mode->flags & DRM_MODE_FLAG_DBLCLK) - return false; - DRM_DEBUG_KMS("DP link computation with max lane count %i " "max bw %02x pixel clock %iKHz\n", max_lane_count, bws[max_clock], mode->clock); @@ -1160,10 +1154,11 @@ static void ironlake_edp_panel_off(struct intel_dp *intel_dp) DRM_DEBUG_KMS("Turn eDP power off\n"); - WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n"); + WARN(intel_dp->want_panel_vdd, "Cannot turn power off while VDD is on\n"); + ironlake_panel_vdd_off_sync(intel_dp); /* finish any pending work */ pp = ironlake_get_pp_control(dev_priv); - pp &= ~(POWER_TARGET_ON | PANEL_POWER_RESET | EDP_BLC_ENABLE); + pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE); I915_WRITE(PCH_PP_CONTROL, pp); POSTING_READ(PCH_PP_CONTROL); @@ -1271,16 +1266,18 @@ static void intel_dp_prepare(struct drm_encoder *encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - - /* Make sure the panel is off before trying to change the mode. But also - * ensure that we have vdd while we switch off the panel. */ - ironlake_edp_panel_vdd_on(intel_dp); ironlake_edp_backlight_off(intel_dp); ironlake_edp_panel_off(intel_dp); + /* Wake up the sink first */ + ironlake_edp_panel_vdd_on(intel_dp); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); intel_dp_link_down(intel_dp); ironlake_edp_panel_vdd_off(intel_dp, false); + + /* Make sure the panel is off before trying to + * change the mode + */ } static void intel_dp_commit(struct drm_encoder *encoder) @@ -1312,11 +1309,10 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) uint32_t dp_reg = I915_READ(intel_dp->output_reg); if (mode != DRM_MODE_DPMS_ON) { - /* Switching the panel off requires vdd. */ - ironlake_edp_panel_vdd_on(intel_dp); ironlake_edp_backlight_off(intel_dp); ironlake_edp_panel_off(intel_dp); + ironlake_edp_panel_vdd_on(intel_dp); intel_dp_sink_dpms(intel_dp, mode); intel_dp_link_down(intel_dp); ironlake_edp_panel_vdd_off(intel_dp, false); diff --git a/trunk/drivers/gpu/drm/i915/intel_i2c.c b/trunk/drivers/gpu/drm/i915/intel_i2c.c index 1991a4408cf9..4a9707dd0f9c 100644 --- a/trunk/drivers/gpu/drm/i915/intel_i2c.c +++ b/trunk/drivers/gpu/drm/i915/intel_i2c.c @@ -396,22 +396,11 @@ gmbus_xfer(struct i2c_adapter *adapter, * Wait for bus to IDLE before clearing NAK. * If we clear the NAK while bus is still active, then it will stay * active and the next transaction may fail. - * - * If no ACK is received during the address phase of a transaction, the - * adapter must report -ENXIO. It is not clear what to return if no ACK - * is received at other times. But we have to be careful to not return - * spurious -ENXIO because that will prevent i2c and drm edid functions - * from retrying. So return -ENXIO only when gmbus properly quiescents - - * timing out seems to happen when there _is_ a ddc chip present, but - * it's slow responding and only answers on the 2nd retry. */ - ret = -ENXIO; if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0, - 10)) { + 10)) DRM_DEBUG_KMS("GMBUS [%s] timed out after NAK\n", adapter->name); - ret = -ETIMEDOUT; - } /* Toggle the Software Clear Interrupt bit. This has the effect * of resetting the GMBUS controller and so clearing the @@ -425,6 +414,14 @@ gmbus_xfer(struct i2c_adapter *adapter, adapter->name, msgs[i].addr, (msgs[i].flags & I2C_M_RD) ? 'r' : 'w', msgs[i].len); + /* + * If no ACK is received during the address phase of a transaction, + * the adapter must report -ENXIO. + * It is not clear what to return if no ACK is received at other times. + * So, we always return -ENXIO in all NAK cases, to ensure we send + * it at least during the one case that is specified. + */ + ret = -ENXIO; goto out; timeout: diff --git a/trunk/drivers/gpu/drm/i915/intel_lvds.c b/trunk/drivers/gpu/drm/i915/intel_lvds.c index 08eb04c787e8..9dee82350def 100644 --- a/trunk/drivers/gpu/drm/i915/intel_lvds.c +++ b/trunk/drivers/gpu/drm/i915/intel_lvds.c @@ -745,14 +745,6 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_MATCH(DMI_BOARD_NAME, "AT5NM10T-I"), }, }, - { - .callback = intel_no_lvds_dmi_callback, - .ident = "Hewlett-Packard HP t5740e Thin Client", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP t5740e Thin Client"), - }, - }, { .callback = intel_no_lvds_dmi_callback, .ident = "Hewlett-Packard t5745", diff --git a/trunk/drivers/gpu/drm/i915/intel_pm.c b/trunk/drivers/gpu/drm/i915/intel_pm.c index d0ce2a5b1d3f..8e79ff67ec98 100644 --- a/trunk/drivers/gpu/drm/i915/intel_pm.c +++ b/trunk/drivers/gpu/drm/i915/intel_pm.c @@ -2270,33 +2270,10 @@ void ironlake_disable_drps(struct drm_device *dev) void gen6_set_rps(struct drm_device *dev, u8 val) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 limits; + u32 swreq; - limits = 0; - if (val >= dev_priv->max_delay) - val = dev_priv->max_delay; - else - limits |= dev_priv->max_delay << 24; - - if (val <= dev_priv->min_delay) - val = dev_priv->min_delay; - else - limits |= dev_priv->min_delay << 16; - - if (val == dev_priv->cur_delay) - return; - - I915_WRITE(GEN6_RPNSWREQ, - GEN6_FREQUENCY(val) | - GEN6_OFFSET(0) | - GEN6_AGGRESSIVE_TURBO); - - /* Make sure we continue to get interrupts - * until we hit the minimum or maximum frequencies. - */ - I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits); - - dev_priv->cur_delay = val; + swreq = (val & 0x3ff) << 25; + I915_WRITE(GEN6_RPNSWREQ, swreq); } void gen6_disable_rps(struct drm_device *dev) @@ -2350,10 +2327,11 @@ int intel_enable_rc6(const struct drm_device *dev) void gen6_enable_rps(struct drm_i915_private *dev_priv) { struct intel_ring_buffer *ring; - u32 rp_state_cap; - u32 gt_perf_status; + u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); + u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); u32 pcu_mbox, rc6_mask = 0; u32 gtfifodbg; + int cur_freq, min_freq, max_freq; int rc6_mode; int i; @@ -2374,14 +2352,6 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv) gen6_gt_force_wake_get(dev_priv); - rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); - gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); - - /* In units of 100MHz */ - dev_priv->max_delay = rp_state_cap & 0xff; - dev_priv->min_delay = (rp_state_cap & 0xff0000) >> 16; - dev_priv->cur_delay = 0; - /* disable the counters and set deterministic thresholds */ I915_WRITE(GEN6_RC_CONTROL, 0); @@ -2429,8 +2399,8 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv) I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000); I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, - dev_priv->max_delay << 24 | - dev_priv->min_delay << 16); + 18 << 24 | + 6 << 16); I915_WRITE(GEN6_RP_UP_THRESHOLD, 10000); I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 1000000); I915_WRITE(GEN6_RP_UP_EI, 100000); @@ -2438,7 +2408,7 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv) I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10); I915_WRITE(GEN6_RP_CONTROL, GEN6_RP_MEDIA_TURBO | - GEN6_RP_MEDIA_HW_NORMAL_MODE | + GEN6_RP_MEDIA_HW_MODE | GEN6_RP_MEDIA_IS_GFX | GEN6_RP_ENABLE | GEN6_RP_UP_BUSY_AVG | @@ -2456,6 +2426,10 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv) 500)) DRM_ERROR("timeout waiting for pcode mailbox to finish\n"); + min_freq = (rp_state_cap & 0xff0000) >> 16; + max_freq = rp_state_cap & 0xff; + cur_freq = (gt_perf_status & 0xff00) >> 8; + /* Check for overclock support */ if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, 500)) @@ -2466,11 +2440,14 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv) 500)) DRM_ERROR("timeout waiting for pcode mailbox to finish\n"); if (pcu_mbox & (1<<31)) { /* OC supported */ - dev_priv->max_delay = pcu_mbox & 0xff; + max_freq = pcu_mbox & 0xff; DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50); } - gen6_set_rps(dev_priv->dev, (gt_perf_status & 0xff00) >> 8); + /* In units of 100MHz */ + dev_priv->max_delay = max_freq; + dev_priv->min_delay = min_freq; + dev_priv->cur_delay = cur_freq; /* requires MSI enabled */ I915_WRITE(GEN6_PMIER, @@ -3603,9 +3580,8 @@ static void gen6_sanitize_pm(struct drm_device *dev) limits |= (dev_priv->min_delay & 0x3f) << 16; if (old != limits) { - /* Note that the known failure case is to read back 0. */ - DRM_DEBUG_DRIVER("Power management discrepancy: GEN6_RP_INTERRUPT_LIMITS " - "expected %08x, was %08x\n", limits, old); + DRM_ERROR("Power management discrepancy: GEN6_RP_INTERRUPT_LIMITS expected %08x, was %08x\n", + limits, old); I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits); } diff --git a/trunk/drivers/gpu/drm/i915/intel_sdvo.c b/trunk/drivers/gpu/drm/i915/intel_sdvo.c index b6a9d45fc3c6..a949b73880c8 100644 --- a/trunk/drivers/gpu/drm/i915/intel_sdvo.c +++ b/trunk/drivers/gpu/drm/i915/intel_sdvo.c @@ -783,12 +783,10 @@ static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd, ((v_sync_len & 0x30) >> 4); dtd->part2.dtd_flags = 0x18; - if (mode->flags & DRM_MODE_FLAG_INTERLACE) - dtd->part2.dtd_flags |= DTD_FLAG_INTERLACE; if (mode->flags & DRM_MODE_FLAG_PHSYNC) - dtd->part2.dtd_flags |= DTD_FLAG_HSYNC_POSITIVE; + dtd->part2.dtd_flags |= 0x2; if (mode->flags & DRM_MODE_FLAG_PVSYNC) - dtd->part2.dtd_flags |= DTD_FLAG_VSYNC_POSITIVE; + dtd->part2.dtd_flags |= 0x4; dtd->part2.sdvo_flags = 0; dtd->part2.v_sync_off_high = v_sync_offset & 0xc0; @@ -822,11 +820,9 @@ static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode, mode->clock = dtd->part1.clock * 10; mode->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC); - if (dtd->part2.dtd_flags & DTD_FLAG_INTERLACE) - mode->flags |= DRM_MODE_FLAG_INTERLACE; - if (dtd->part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE) + if (dtd->part2.dtd_flags & 0x2) mode->flags |= DRM_MODE_FLAG_PHSYNC; - if (dtd->part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE) + if (dtd->part2.dtd_flags & 0x4) mode->flags |= DRM_MODE_FLAG_PVSYNC; } diff --git a/trunk/drivers/gpu/drm/i915/intel_sdvo_regs.h b/trunk/drivers/gpu/drm/i915/intel_sdvo_regs.h index 9d030142ee43..6b7b22f4d63e 100644 --- a/trunk/drivers/gpu/drm/i915/intel_sdvo_regs.h +++ b/trunk/drivers/gpu/drm/i915/intel_sdvo_regs.h @@ -61,11 +61,6 @@ struct intel_sdvo_caps { u16 output_flags; } __attribute__((packed)); -/* Note: SDVO detailed timing flags match EDID misc flags. */ -#define DTD_FLAG_HSYNC_POSITIVE (1 << 1) -#define DTD_FLAG_VSYNC_POSITIVE (1 << 2) -#define DTD_FLAG_INTERLACE (1 << 7) - /** This matches the EDID DTD structure, more or less */ struct intel_sdvo_dtd { struct { diff --git a/trunk/drivers/gpu/drm/i915/intel_tv.c b/trunk/drivers/gpu/drm/i915/intel_tv.c index a233a51fd7e6..3346612d2953 100644 --- a/trunk/drivers/gpu/drm/i915/intel_tv.c +++ b/trunk/drivers/gpu/drm/i915/intel_tv.c @@ -673,54 +673,6 @@ static const struct tv_mode tv_modes[] = { .filter_table = filter_table, }, - { - .name = "480p", - .clock = 107520, - .refresh = 59940, - .oversample = TV_OVERSAMPLE_4X, - .component_only = 1, - - .hsync_end = 64, .hblank_end = 122, - .hblank_start = 842, .htotal = 857, - - .progressive = true, .trilevel_sync = false, - - .vsync_start_f1 = 12, .vsync_start_f2 = 12, - .vsync_len = 12, - - .veq_ena = false, - - .vi_end_f1 = 44, .vi_end_f2 = 44, - .nbr_end = 479, - - .burst_ena = false, - - .filter_table = filter_table, - }, - { - .name = "576p", - .clock = 107520, - .refresh = 50000, - .oversample = TV_OVERSAMPLE_4X, - .component_only = 1, - - .hsync_end = 64, .hblank_end = 139, - .hblank_start = 859, .htotal = 863, - - .progressive = true, .trilevel_sync = false, - - .vsync_start_f1 = 10, .vsync_start_f2 = 10, - .vsync_len = 10, - - .veq_ena = false, - - .vi_end_f1 = 48, .vi_end_f2 = 48, - .nbr_end = 575, - - .burst_ena = false, - - .filter_table = filter_table, - }, { .name = "720p@60Hz", .clock = 148800, @@ -1242,11 +1194,6 @@ intel_tv_detect_type(struct intel_tv *intel_tv, I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN); I915_WRITE(TV_CTL, save_tv_ctl); - POSTING_READ(TV_CTL); - - /* For unknown reasons the hw barfs if we don't do this vblank wait. */ - intel_wait_for_vblank(intel_tv->base.base.dev, - to_intel_crtc(intel_tv->base.base.crtc)->pipe); /* Restore interrupt config */ if (connector->polled & DRM_CONNECTOR_POLL_HPD) { diff --git a/trunk/drivers/gpu/drm/mgag200/mgag200_drv.c b/trunk/drivers/gpu/drm/mgag200/mgag200_drv.c index 93e832d6c328..3c8e04f54713 100644 --- a/trunk/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/trunk/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -41,28 +41,9 @@ static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { MODULE_DEVICE_TABLE(pci, pciidlist); -static void mgag200_kick_out_firmware_fb(struct pci_dev *pdev) -{ - struct apertures_struct *ap; - bool primary = false; - - ap = alloc_apertures(1); - ap->ranges[0].base = pci_resource_start(pdev, 0); - ap->ranges[0].size = pci_resource_len(pdev, 0); - -#ifdef CONFIG_X86 - primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; -#endif - remove_conflicting_framebuffers(ap, "mgag200drmfb", primary); - kfree(ap); -} - - static int __devinit mga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - mgag200_kick_out_firmware_fb(pdev); - return drm_get_pci_dev(pdev, ent, &driver); } diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_drv.h b/trunk/drivers/gpu/drm/nouveau/nouveau_drv.h index 8613cb23808c..634d222c93de 100644 --- a/trunk/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/trunk/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -123,9 +123,6 @@ struct nouveau_bo { struct drm_gem_object *gem; int pin_refcnt; - - struct ttm_bo_kmap_obj dma_buf_vmap; - int vmapping_count; }; #define nouveau_bo_tile_layout(nvbo) \ diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_prime.c b/trunk/drivers/gpu/drm/nouveau/nouveau_prime.c index a89240e5fb29..c58aab7370c5 100644 --- a/trunk/drivers/gpu/drm/nouveau/nouveau_prime.c +++ b/trunk/drivers/gpu/drm/nouveau/nouveau_prime.c @@ -61,48 +61,6 @@ static void nouveau_gem_kunmap(struct dma_buf *dma_buf, unsigned long page_num, } -static int nouveau_gem_prime_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma) -{ - return -EINVAL; -} - -static void *nouveau_gem_prime_vmap(struct dma_buf *dma_buf) -{ - struct nouveau_bo *nvbo = dma_buf->priv; - struct drm_device *dev = nvbo->gem->dev; - int ret; - - mutex_lock(&dev->struct_mutex); - if (nvbo->vmapping_count) { - nvbo->vmapping_count++; - goto out_unlock; - } - - ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.num_pages, - &nvbo->dma_buf_vmap); - if (ret) { - mutex_unlock(&dev->struct_mutex); - return ERR_PTR(ret); - } - nvbo->vmapping_count = 1; -out_unlock: - mutex_unlock(&dev->struct_mutex); - return nvbo->dma_buf_vmap.virtual; -} - -static void nouveau_gem_prime_vunmap(struct dma_buf *dma_buf, void *vaddr) -{ - struct nouveau_bo *nvbo = dma_buf->priv; - struct drm_device *dev = nvbo->gem->dev; - - mutex_lock(&dev->struct_mutex); - nvbo->vmapping_count--; - if (nvbo->vmapping_count == 0) { - ttm_bo_kunmap(&nvbo->dma_buf_vmap); - } - mutex_unlock(&dev->struct_mutex); -} - static const struct dma_buf_ops nouveau_dmabuf_ops = { .map_dma_buf = nouveau_gem_map_dma_buf, .unmap_dma_buf = nouveau_gem_unmap_dma_buf, @@ -111,9 +69,6 @@ static const struct dma_buf_ops nouveau_dmabuf_ops = { .kmap_atomic = nouveau_gem_kmap_atomic, .kunmap = nouveau_gem_kunmap, .kunmap_atomic = nouveau_gem_kunmap_atomic, - .mmap = nouveau_gem_prime_mmap, - .vmap = nouveau_gem_prime_vmap, - .vunmap = nouveau_gem_prime_vunmap, }; static int diff --git a/trunk/drivers/gpu/drm/radeon/evergreen.c b/trunk/drivers/gpu/drm/radeon/evergreen.c index 01550d05e273..58991af90502 100644 --- a/trunk/drivers/gpu/drm/radeon/evergreen.c +++ b/trunk/drivers/gpu/drm/radeon/evergreen.c @@ -1029,11 +1029,6 @@ int evergreen_pcie_gart_enable(struct radeon_device *rdev) WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp); WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp); WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp); - if ((rdev->family == CHIP_JUNIPER) || - (rdev->family == CHIP_CYPRESS) || - (rdev->family == CHIP_HEMLOCK) || - (rdev->family == CHIP_BARTS)) - WREG32(MC_VM_MD_L1_TLB3_CNTL, tmp); } WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp); @@ -1558,10 +1553,163 @@ int evergreen_cp_resume(struct radeon_device *rdev) /* * Core functions */ +static u32 evergreen_get_tile_pipe_to_backend_map(struct radeon_device *rdev, + u32 num_tile_pipes, + u32 num_backends, + u32 backend_disable_mask) +{ + u32 backend_map = 0; + u32 enabled_backends_mask = 0; + u32 enabled_backends_count = 0; + u32 cur_pipe; + u32 swizzle_pipe[EVERGREEN_MAX_PIPES]; + u32 cur_backend = 0; + u32 i; + bool force_no_swizzle; + + if (num_tile_pipes > EVERGREEN_MAX_PIPES) + num_tile_pipes = EVERGREEN_MAX_PIPES; + if (num_tile_pipes < 1) + num_tile_pipes = 1; + if (num_backends > EVERGREEN_MAX_BACKENDS) + num_backends = EVERGREEN_MAX_BACKENDS; + if (num_backends < 1) + num_backends = 1; + + for (i = 0; i < EVERGREEN_MAX_BACKENDS; ++i) { + if (((backend_disable_mask >> i) & 1) == 0) { + enabled_backends_mask |= (1 << i); + ++enabled_backends_count; + } + if (enabled_backends_count == num_backends) + break; + } + + if (enabled_backends_count == 0) { + enabled_backends_mask = 1; + enabled_backends_count = 1; + } + + if (enabled_backends_count != num_backends) + num_backends = enabled_backends_count; + + memset((uint8_t *)&swizzle_pipe[0], 0, sizeof(u32) * EVERGREEN_MAX_PIPES); + switch (rdev->family) { + case CHIP_CEDAR: + case CHIP_REDWOOD: + case CHIP_PALM: + case CHIP_SUMO: + case CHIP_SUMO2: + case CHIP_TURKS: + case CHIP_CAICOS: + force_no_swizzle = false; + break; + case CHIP_CYPRESS: + case CHIP_HEMLOCK: + case CHIP_JUNIPER: + case CHIP_BARTS: + default: + force_no_swizzle = true; + break; + } + if (force_no_swizzle) { + bool last_backend_enabled = false; + + force_no_swizzle = false; + for (i = 0; i < EVERGREEN_MAX_BACKENDS; ++i) { + if (((enabled_backends_mask >> i) & 1) == 1) { + if (last_backend_enabled) + force_no_swizzle = true; + last_backend_enabled = true; + } else + last_backend_enabled = false; + } + } + + switch (num_tile_pipes) { + case 1: + case 3: + case 5: + case 7: + DRM_ERROR("odd number of pipes!\n"); + break; + case 2: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + break; + case 4: + if (force_no_swizzle) { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + swizzle_pipe[2] = 2; + swizzle_pipe[3] = 3; + } else { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 1; + swizzle_pipe[3] = 3; + } + break; + case 6: + if (force_no_swizzle) { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + swizzle_pipe[2] = 2; + swizzle_pipe[3] = 3; + swizzle_pipe[4] = 4; + swizzle_pipe[5] = 5; + } else { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 4; + swizzle_pipe[3] = 1; + swizzle_pipe[4] = 3; + swizzle_pipe[5] = 5; + } + break; + case 8: + if (force_no_swizzle) { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + swizzle_pipe[2] = 2; + swizzle_pipe[3] = 3; + swizzle_pipe[4] = 4; + swizzle_pipe[5] = 5; + swizzle_pipe[6] = 6; + swizzle_pipe[7] = 7; + } else { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 4; + swizzle_pipe[3] = 6; + swizzle_pipe[4] = 1; + swizzle_pipe[5] = 3; + swizzle_pipe[6] = 5; + swizzle_pipe[7] = 7; + } + break; + } + + for (cur_pipe = 0; cur_pipe < num_tile_pipes; ++cur_pipe) { + while (((1 << cur_backend) & enabled_backends_mask) == 0) + cur_backend = (cur_backend + 1) % EVERGREEN_MAX_BACKENDS; + + backend_map |= (((cur_backend & 0xf) << (swizzle_pipe[cur_pipe] * 4))); + + cur_backend = (cur_backend + 1) % EVERGREEN_MAX_BACKENDS; + } + + return backend_map; +} + static void evergreen_gpu_init(struct radeon_device *rdev) { - u32 gb_addr_config; + u32 cc_rb_backend_disable = 0; + u32 cc_gc_shader_pipe_config; + u32 gb_addr_config = 0; u32 mc_shared_chmap, mc_arb_ramcfg; + u32 gb_backend_map; + u32 grbm_gfx_index; u32 sx_debug_1; u32 smx_dc_ctl0; u32 sq_config; @@ -1576,7 +1724,6 @@ static void evergreen_gpu_init(struct radeon_device *rdev) u32 sq_stack_resource_mgmt_3; u32 vgt_cache_invalidation; u32 hdp_host_path_cntl, tmp; - u32 disabled_rb_mask; int i, j, num_shader_engines, ps_thread_count; switch (rdev->family) { @@ -1601,7 +1748,6 @@ static void evergreen_gpu_init(struct radeon_device *rdev) rdev->config.evergreen.sc_prim_fifo_size = 0x100; rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; - gb_addr_config = CYPRESS_GB_ADDR_CONFIG_GOLDEN; break; case CHIP_JUNIPER: rdev->config.evergreen.num_ses = 1; @@ -1623,7 +1769,6 @@ static void evergreen_gpu_init(struct radeon_device *rdev) rdev->config.evergreen.sc_prim_fifo_size = 0x100; rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; - gb_addr_config = JUNIPER_GB_ADDR_CONFIG_GOLDEN; break; case CHIP_REDWOOD: rdev->config.evergreen.num_ses = 1; @@ -1645,7 +1790,6 @@ static void evergreen_gpu_init(struct radeon_device *rdev) rdev->config.evergreen.sc_prim_fifo_size = 0x100; rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; - gb_addr_config = REDWOOD_GB_ADDR_CONFIG_GOLDEN; break; case CHIP_CEDAR: default: @@ -1668,7 +1812,6 @@ static void evergreen_gpu_init(struct radeon_device *rdev) rdev->config.evergreen.sc_prim_fifo_size = 0x40; rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; - gb_addr_config = CEDAR_GB_ADDR_CONFIG_GOLDEN; break; case CHIP_PALM: rdev->config.evergreen.num_ses = 1; @@ -1690,7 +1833,6 @@ static void evergreen_gpu_init(struct radeon_device *rdev) rdev->config.evergreen.sc_prim_fifo_size = 0x40; rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; - gb_addr_config = CEDAR_GB_ADDR_CONFIG_GOLDEN; break; case CHIP_SUMO: rdev->config.evergreen.num_ses = 1; @@ -1718,7 +1860,6 @@ static void evergreen_gpu_init(struct radeon_device *rdev) rdev->config.evergreen.sc_prim_fifo_size = 0x40; rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; - gb_addr_config = REDWOOD_GB_ADDR_CONFIG_GOLDEN; break; case CHIP_SUMO2: rdev->config.evergreen.num_ses = 1; @@ -1740,7 +1881,6 @@ static void evergreen_gpu_init(struct radeon_device *rdev) rdev->config.evergreen.sc_prim_fifo_size = 0x40; rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; - gb_addr_config = REDWOOD_GB_ADDR_CONFIG_GOLDEN; break; case CHIP_BARTS: rdev->config.evergreen.num_ses = 2; @@ -1762,7 +1902,6 @@ static void evergreen_gpu_init(struct radeon_device *rdev) rdev->config.evergreen.sc_prim_fifo_size = 0x100; rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; - gb_addr_config = BARTS_GB_ADDR_CONFIG_GOLDEN; break; case CHIP_TURKS: rdev->config.evergreen.num_ses = 1; @@ -1784,7 +1923,6 @@ static void evergreen_gpu_init(struct radeon_device *rdev) rdev->config.evergreen.sc_prim_fifo_size = 0x100; rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; - gb_addr_config = TURKS_GB_ADDR_CONFIG_GOLDEN; break; case CHIP_CAICOS: rdev->config.evergreen.num_ses = 1; @@ -1806,7 +1944,6 @@ static void evergreen_gpu_init(struct radeon_device *rdev) rdev->config.evergreen.sc_prim_fifo_size = 0x40; rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; - gb_addr_config = CAICOS_GB_ADDR_CONFIG_GOLDEN; break; } @@ -1823,6 +1960,20 @@ static void evergreen_gpu_init(struct radeon_device *rdev) evergreen_fix_pci_max_read_req_size(rdev); + cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & ~2; + + cc_gc_shader_pipe_config |= + INACTIVE_QD_PIPES((EVERGREEN_MAX_PIPES_MASK << rdev->config.evergreen.max_pipes) + & EVERGREEN_MAX_PIPES_MASK); + cc_gc_shader_pipe_config |= + INACTIVE_SIMDS((EVERGREEN_MAX_SIMDS_MASK << rdev->config.evergreen.max_simds) + & EVERGREEN_MAX_SIMDS_MASK); + + cc_rb_backend_disable = + BACKEND_DISABLE((EVERGREEN_MAX_BACKENDS_MASK << rdev->config.evergreen.max_backends) + & EVERGREEN_MAX_BACKENDS_MASK); + + mc_shared_chmap = RREG32(MC_SHARED_CHMAP); if ((rdev->family == CHIP_PALM) || (rdev->family == CHIP_SUMO) || @@ -1831,6 +1982,134 @@ static void evergreen_gpu_init(struct radeon_device *rdev) else mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG); + switch (rdev->config.evergreen.max_tile_pipes) { + case 1: + default: + gb_addr_config |= NUM_PIPES(0); + break; + case 2: + gb_addr_config |= NUM_PIPES(1); + break; + case 4: + gb_addr_config |= NUM_PIPES(2); + break; + case 8: + gb_addr_config |= NUM_PIPES(3); + break; + } + + gb_addr_config |= PIPE_INTERLEAVE_SIZE((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT); + gb_addr_config |= BANK_INTERLEAVE_SIZE(0); + gb_addr_config |= NUM_SHADER_ENGINES(rdev->config.evergreen.num_ses - 1); + gb_addr_config |= SHADER_ENGINE_TILE_SIZE(1); + gb_addr_config |= NUM_GPUS(0); /* Hemlock? */ + gb_addr_config |= MULTI_GPU_TILE_SIZE(2); + + if (((mc_arb_ramcfg & NOOFCOLS_MASK) >> NOOFCOLS_SHIFT) > 2) + gb_addr_config |= ROW_SIZE(2); + else + gb_addr_config |= ROW_SIZE((mc_arb_ramcfg & NOOFCOLS_MASK) >> NOOFCOLS_SHIFT); + + if (rdev->ddev->pdev->device == 0x689e) { + u32 efuse_straps_4; + u32 efuse_straps_3; + u8 efuse_box_bit_131_124; + + WREG32(RCU_IND_INDEX, 0x204); + efuse_straps_4 = RREG32(RCU_IND_DATA); + WREG32(RCU_IND_INDEX, 0x203); + efuse_straps_3 = RREG32(RCU_IND_DATA); + efuse_box_bit_131_124 = (u8)(((efuse_straps_4 & 0xf) << 4) | ((efuse_straps_3 & 0xf0000000) >> 28)); + + switch(efuse_box_bit_131_124) { + case 0x00: + gb_backend_map = 0x76543210; + break; + case 0x55: + gb_backend_map = 0x77553311; + break; + case 0x56: + gb_backend_map = 0x77553300; + break; + case 0x59: + gb_backend_map = 0x77552211; + break; + case 0x66: + gb_backend_map = 0x77443300; + break; + case 0x99: + gb_backend_map = 0x66552211; + break; + case 0x5a: + gb_backend_map = 0x77552200; + break; + case 0xaa: + gb_backend_map = 0x66442200; + break; + case 0x95: + gb_backend_map = 0x66553311; + break; + default: + DRM_ERROR("bad backend map, using default\n"); + gb_backend_map = + evergreen_get_tile_pipe_to_backend_map(rdev, + rdev->config.evergreen.max_tile_pipes, + rdev->config.evergreen.max_backends, + ((EVERGREEN_MAX_BACKENDS_MASK << + rdev->config.evergreen.max_backends) & + EVERGREEN_MAX_BACKENDS_MASK)); + break; + } + } else if (rdev->ddev->pdev->device == 0x68b9) { + u32 efuse_straps_3; + u8 efuse_box_bit_127_124; + + WREG32(RCU_IND_INDEX, 0x203); + efuse_straps_3 = RREG32(RCU_IND_DATA); + efuse_box_bit_127_124 = (u8)((efuse_straps_3 & 0xF0000000) >> 28); + + switch(efuse_box_bit_127_124) { + case 0x0: + gb_backend_map = 0x00003210; + break; + case 0x5: + case 0x6: + case 0x9: + case 0xa: + gb_backend_map = 0x00003311; + break; + default: + DRM_ERROR("bad backend map, using default\n"); + gb_backend_map = + evergreen_get_tile_pipe_to_backend_map(rdev, + rdev->config.evergreen.max_tile_pipes, + rdev->config.evergreen.max_backends, + ((EVERGREEN_MAX_BACKENDS_MASK << + rdev->config.evergreen.max_backends) & + EVERGREEN_MAX_BACKENDS_MASK)); + break; + } + } else { + switch (rdev->family) { + case CHIP_CYPRESS: + case CHIP_HEMLOCK: + case CHIP_BARTS: + gb_backend_map = 0x66442200; + break; + case CHIP_JUNIPER: + gb_backend_map = 0x00002200; + break; + default: + gb_backend_map = + evergreen_get_tile_pipe_to_backend_map(rdev, + rdev->config.evergreen.max_tile_pipes, + rdev->config.evergreen.max_backends, + ((EVERGREEN_MAX_BACKENDS_MASK << + rdev->config.evergreen.max_backends) & + EVERGREEN_MAX_BACKENDS_MASK)); + } + } + /* setup tiling info dword. gb_addr_config is not adequate since it does * not have bank info, so create a custom tiling dword. * bits 3:0 num_pipes @@ -1857,54 +2136,45 @@ static void evergreen_gpu_init(struct radeon_device *rdev) /* num banks is 8 on all fusion asics. 0 = 4, 1 = 8, 2 = 16 */ if (rdev->flags & RADEON_IS_IGP) rdev->config.evergreen.tile_config |= 1 << 4; - else { - if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) - rdev->config.evergreen.tile_config |= 1 << 4; - else - rdev->config.evergreen.tile_config |= 0 << 4; - } - rdev->config.evergreen.tile_config |= 0 << 8; + else + rdev->config.evergreen.tile_config |= + ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4; + rdev->config.evergreen.tile_config |= + ((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT) << 8; rdev->config.evergreen.tile_config |= ((gb_addr_config & 0x30000000) >> 28) << 12; - num_shader_engines = (gb_addr_config & NUM_SHADER_ENGINES(3) >> 12) + 1; + rdev->config.evergreen.backend_map = gb_backend_map; + WREG32(GB_BACKEND_MAP, gb_backend_map); + WREG32(GB_ADDR_CONFIG, gb_addr_config); + WREG32(DMIF_ADDR_CONFIG, gb_addr_config); + WREG32(HDP_ADDR_CONFIG, gb_addr_config); - if ((rdev->family >= CHIP_CEDAR) && (rdev->family <= CHIP_HEMLOCK)) { - u32 efuse_straps_4; - u32 efuse_straps_3; + num_shader_engines = ((RREG32(GB_ADDR_CONFIG) & NUM_SHADER_ENGINES(3)) >> 12) + 1; + grbm_gfx_index = INSTANCE_BROADCAST_WRITES; - WREG32(RCU_IND_INDEX, 0x204); - efuse_straps_4 = RREG32(RCU_IND_DATA); - WREG32(RCU_IND_INDEX, 0x203); - efuse_straps_3 = RREG32(RCU_IND_DATA); - tmp = (((efuse_straps_4 & 0xf) << 4) | - ((efuse_straps_3 & 0xf0000000) >> 28)); - } else { - tmp = 0; - for (i = (rdev->config.evergreen.num_ses - 1); i >= 0; i--) { - u32 rb_disable_bitmap; - - WREG32(GRBM_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_INDEX(i)); - WREG32(RLC_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_INDEX(i)); - rb_disable_bitmap = (RREG32(CC_RB_BACKEND_DISABLE) & 0x00ff0000) >> 16; - tmp <<= 4; - tmp |= rb_disable_bitmap; + for (i = 0; i < rdev->config.evergreen.num_ses; i++) { + u32 rb = cc_rb_backend_disable | (0xf0 << 16); + u32 sp = cc_gc_shader_pipe_config; + u32 gfx = grbm_gfx_index | SE_INDEX(i); + + if (i == num_shader_engines) { + rb |= BACKEND_DISABLE(EVERGREEN_MAX_BACKENDS_MASK); + sp |= INACTIVE_SIMDS(EVERGREEN_MAX_SIMDS_MASK); } - } - /* enabled rb are just the one not disabled :) */ - disabled_rb_mask = tmp; - WREG32(GRBM_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_BROADCAST_WRITES); - WREG32(RLC_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_BROADCAST_WRITES); + WREG32(GRBM_GFX_INDEX, gfx); + WREG32(RLC_GFX_INDEX, gfx); - WREG32(GB_ADDR_CONFIG, gb_addr_config); - WREG32(DMIF_ADDR_CONFIG, gb_addr_config); - WREG32(HDP_ADDR_CONFIG, gb_addr_config); + WREG32(CC_RB_BACKEND_DISABLE, rb); + WREG32(CC_SYS_RB_BACKEND_DISABLE, rb); + WREG32(GC_USER_RB_BACKEND_DISABLE, rb); + WREG32(CC_GC_SHADER_PIPE_CONFIG, sp); + } - tmp = gb_addr_config & NUM_PIPES_MASK; - tmp = r6xx_remap_render_backend(rdev, tmp, rdev->config.evergreen.max_backends, - EVERGREEN_MAX_BACKENDS, disabled_rb_mask); - WREG32(GB_BACKEND_MAP, tmp); + grbm_gfx_index |= SE_BROADCAST_WRITES; + WREG32(GRBM_GFX_INDEX, grbm_gfx_index); + WREG32(RLC_GFX_INDEX, grbm_gfx_index); WREG32(CGTS_SYS_TCC_DISABLE, 0); WREG32(CGTS_TCC_DISABLE, 0); diff --git a/trunk/drivers/gpu/drm/radeon/evergreend.h b/trunk/drivers/gpu/drm/radeon/evergreend.h index 2773039b4902..79130bfd1d6f 100644 --- a/trunk/drivers/gpu/drm/radeon/evergreend.h +++ b/trunk/drivers/gpu/drm/radeon/evergreend.h @@ -37,15 +37,6 @@ #define EVERGREEN_MAX_PIPES_MASK 0xFF #define EVERGREEN_MAX_LDS_NUM 0xFFFF -#define CYPRESS_GB_ADDR_CONFIG_GOLDEN 0x02011003 -#define BARTS_GB_ADDR_CONFIG_GOLDEN 0x02011003 -#define CAYMAN_GB_ADDR_CONFIG_GOLDEN 0x02011003 -#define JUNIPER_GB_ADDR_CONFIG_GOLDEN 0x02010002 -#define REDWOOD_GB_ADDR_CONFIG_GOLDEN 0x02010002 -#define TURKS_GB_ADDR_CONFIG_GOLDEN 0x02010002 -#define CEDAR_GB_ADDR_CONFIG_GOLDEN 0x02010001 -#define CAICOS_GB_ADDR_CONFIG_GOLDEN 0x02010001 - /* Registers */ #define RCU_IND_INDEX 0x100 @@ -63,7 +54,6 @@ #define BACKEND_DISABLE(x) ((x) << 16) #define GB_ADDR_CONFIG 0x98F8 #define NUM_PIPES(x) ((x) << 0) -#define NUM_PIPES_MASK 0x0000000f #define PIPE_INTERLEAVE_SIZE(x) ((x) << 4) #define BANK_INTERLEAVE_SIZE(x) ((x) << 8) #define NUM_SHADER_ENGINES(x) ((x) << 12) @@ -462,7 +452,6 @@ #define MC_VM_MD_L1_TLB0_CNTL 0x2654 #define MC_VM_MD_L1_TLB1_CNTL 0x2658 #define MC_VM_MD_L1_TLB2_CNTL 0x265C -#define MC_VM_MD_L1_TLB3_CNTL 0x2698 #define FUS_MC_VM_MD_L1_TLB0_CNTL 0x265C #define FUS_MC_VM_MD_L1_TLB1_CNTL 0x2660 diff --git a/trunk/drivers/gpu/drm/radeon/ni.c b/trunk/drivers/gpu/drm/radeon/ni.c index 3df4efa11942..b01c2dd627b0 100644 --- a/trunk/drivers/gpu/drm/radeon/ni.c +++ b/trunk/drivers/gpu/drm/radeon/ni.c @@ -417,17 +417,215 @@ int ni_init_microcode(struct radeon_device *rdev) /* * Core functions */ +static u32 cayman_get_tile_pipe_to_backend_map(struct radeon_device *rdev, + u32 num_tile_pipes, + u32 num_backends_per_asic, + u32 *backend_disable_mask_per_asic, + u32 num_shader_engines) +{ + u32 backend_map = 0; + u32 enabled_backends_mask = 0; + u32 enabled_backends_count = 0; + u32 num_backends_per_se; + u32 cur_pipe; + u32 swizzle_pipe[CAYMAN_MAX_PIPES]; + u32 cur_backend = 0; + u32 i; + bool force_no_swizzle; + + /* force legal values */ + if (num_tile_pipes < 1) + num_tile_pipes = 1; + if (num_tile_pipes > rdev->config.cayman.max_tile_pipes) + num_tile_pipes = rdev->config.cayman.max_tile_pipes; + if (num_shader_engines < 1) + num_shader_engines = 1; + if (num_shader_engines > rdev->config.cayman.max_shader_engines) + num_shader_engines = rdev->config.cayman.max_shader_engines; + if (num_backends_per_asic < num_shader_engines) + num_backends_per_asic = num_shader_engines; + if (num_backends_per_asic > (rdev->config.cayman.max_backends_per_se * num_shader_engines)) + num_backends_per_asic = rdev->config.cayman.max_backends_per_se * num_shader_engines; + + /* make sure we have the same number of backends per se */ + num_backends_per_asic = ALIGN(num_backends_per_asic, num_shader_engines); + /* set up the number of backends per se */ + num_backends_per_se = num_backends_per_asic / num_shader_engines; + if (num_backends_per_se > rdev->config.cayman.max_backends_per_se) { + num_backends_per_se = rdev->config.cayman.max_backends_per_se; + num_backends_per_asic = num_backends_per_se * num_shader_engines; + } + + /* create enable mask and count for enabled backends */ + for (i = 0; i < CAYMAN_MAX_BACKENDS; ++i) { + if (((*backend_disable_mask_per_asic >> i) & 1) == 0) { + enabled_backends_mask |= (1 << i); + ++enabled_backends_count; + } + if (enabled_backends_count == num_backends_per_asic) + break; + } + + /* force the backends mask to match the current number of backends */ + if (enabled_backends_count != num_backends_per_asic) { + u32 this_backend_enabled; + u32 shader_engine; + u32 backend_per_se; + + enabled_backends_mask = 0; + enabled_backends_count = 0; + *backend_disable_mask_per_asic = CAYMAN_MAX_BACKENDS_MASK; + for (i = 0; i < CAYMAN_MAX_BACKENDS; ++i) { + /* calc the current se */ + shader_engine = i / rdev->config.cayman.max_backends_per_se; + /* calc the backend per se */ + backend_per_se = i % rdev->config.cayman.max_backends_per_se; + /* default to not enabled */ + this_backend_enabled = 0; + if ((shader_engine < num_shader_engines) && + (backend_per_se < num_backends_per_se)) + this_backend_enabled = 1; + if (this_backend_enabled) { + enabled_backends_mask |= (1 << i); + *backend_disable_mask_per_asic &= ~(1 << i); + ++enabled_backends_count; + } + } + } + + + memset((uint8_t *)&swizzle_pipe[0], 0, sizeof(u32) * CAYMAN_MAX_PIPES); + switch (rdev->family) { + case CHIP_CAYMAN: + case CHIP_ARUBA: + force_no_swizzle = true; + break; + default: + force_no_swizzle = false; + break; + } + if (force_no_swizzle) { + bool last_backend_enabled = false; + + force_no_swizzle = false; + for (i = 0; i < CAYMAN_MAX_BACKENDS; ++i) { + if (((enabled_backends_mask >> i) & 1) == 1) { + if (last_backend_enabled) + force_no_swizzle = true; + last_backend_enabled = true; + } else + last_backend_enabled = false; + } + } + + switch (num_tile_pipes) { + case 1: + case 3: + case 5: + case 7: + DRM_ERROR("odd number of pipes!\n"); + break; + case 2: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + break; + case 4: + if (force_no_swizzle) { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + swizzle_pipe[2] = 2; + swizzle_pipe[3] = 3; + } else { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 1; + swizzle_pipe[3] = 3; + } + break; + case 6: + if (force_no_swizzle) { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + swizzle_pipe[2] = 2; + swizzle_pipe[3] = 3; + swizzle_pipe[4] = 4; + swizzle_pipe[5] = 5; + } else { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 4; + swizzle_pipe[3] = 1; + swizzle_pipe[4] = 3; + swizzle_pipe[5] = 5; + } + break; + case 8: + if (force_no_swizzle) { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + swizzle_pipe[2] = 2; + swizzle_pipe[3] = 3; + swizzle_pipe[4] = 4; + swizzle_pipe[5] = 5; + swizzle_pipe[6] = 6; + swizzle_pipe[7] = 7; + } else { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 4; + swizzle_pipe[3] = 6; + swizzle_pipe[4] = 1; + swizzle_pipe[5] = 3; + swizzle_pipe[6] = 5; + swizzle_pipe[7] = 7; + } + break; + } + + for (cur_pipe = 0; cur_pipe < num_tile_pipes; ++cur_pipe) { + while (((1 << cur_backend) & enabled_backends_mask) == 0) + cur_backend = (cur_backend + 1) % CAYMAN_MAX_BACKENDS; + + backend_map |= (((cur_backend & 0xf) << (swizzle_pipe[cur_pipe] * 4))); + + cur_backend = (cur_backend + 1) % CAYMAN_MAX_BACKENDS; + } + + return backend_map; +} + +static u32 cayman_get_disable_mask_per_asic(struct radeon_device *rdev, + u32 disable_mask_per_se, + u32 max_disable_mask_per_se, + u32 num_shader_engines) +{ + u32 disable_field_width_per_se = r600_count_pipe_bits(disable_mask_per_se); + u32 disable_mask_per_asic = disable_mask_per_se & max_disable_mask_per_se; + + if (num_shader_engines == 1) + return disable_mask_per_asic; + else if (num_shader_engines == 2) + return disable_mask_per_asic | (disable_mask_per_asic << disable_field_width_per_se); + else + return 0xffffffff; +} + static void cayman_gpu_init(struct radeon_device *rdev) { + u32 cc_rb_backend_disable = 0; + u32 cc_gc_shader_pipe_config; u32 gb_addr_config = 0; u32 mc_shared_chmap, mc_arb_ramcfg; + u32 gb_backend_map; u32 cgts_tcc_disable; u32 sx_debug_1; u32 smx_dc_ctl0; + u32 gc_user_shader_pipe_config; + u32 gc_user_rb_backend_disable; + u32 cgts_user_tcc_disable; u32 cgts_sm_ctrl_reg; u32 hdp_host_path_cntl; u32 tmp; - u32 disabled_rb_mask; int i, j; switch (rdev->family) { @@ -452,7 +650,6 @@ static void cayman_gpu_init(struct radeon_device *rdev) rdev->config.cayman.sc_prim_fifo_size = 0x100; rdev->config.cayman.sc_hiz_tile_fifo_size = 0x30; rdev->config.cayman.sc_earlyz_tile_fifo_size = 0x130; - gb_addr_config = CAYMAN_GB_ADDR_CONFIG_GOLDEN; break; case CHIP_ARUBA: default: @@ -490,7 +687,6 @@ static void cayman_gpu_init(struct radeon_device *rdev) rdev->config.cayman.sc_prim_fifo_size = 0x40; rdev->config.cayman.sc_hiz_tile_fifo_size = 0x30; rdev->config.cayman.sc_earlyz_tile_fifo_size = 0x130; - gb_addr_config = ARUBA_GB_ADDR_CONFIG_GOLDEN; break; } @@ -510,6 +706,39 @@ static void cayman_gpu_init(struct radeon_device *rdev) mc_shared_chmap = RREG32(MC_SHARED_CHMAP); mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG); + cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE); + cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG); + cgts_tcc_disable = 0xffff0000; + for (i = 0; i < rdev->config.cayman.max_texture_channel_caches; i++) + cgts_tcc_disable &= ~(1 << (16 + i)); + gc_user_rb_backend_disable = RREG32(GC_USER_RB_BACKEND_DISABLE); + gc_user_shader_pipe_config = RREG32(GC_USER_SHADER_PIPE_CONFIG); + cgts_user_tcc_disable = RREG32(CGTS_USER_TCC_DISABLE); + + rdev->config.cayman.num_shader_engines = rdev->config.cayman.max_shader_engines; + tmp = ((~gc_user_shader_pipe_config) & INACTIVE_QD_PIPES_MASK) >> INACTIVE_QD_PIPES_SHIFT; + rdev->config.cayman.num_shader_pipes_per_simd = r600_count_pipe_bits(tmp); + rdev->config.cayman.num_tile_pipes = rdev->config.cayman.max_tile_pipes; + tmp = ((~gc_user_shader_pipe_config) & INACTIVE_SIMDS_MASK) >> INACTIVE_SIMDS_SHIFT; + rdev->config.cayman.num_simds_per_se = r600_count_pipe_bits(tmp); + tmp = ((~gc_user_rb_backend_disable) & BACKEND_DISABLE_MASK) >> BACKEND_DISABLE_SHIFT; + rdev->config.cayman.num_backends_per_se = r600_count_pipe_bits(tmp); + tmp = (gc_user_rb_backend_disable & BACKEND_DISABLE_MASK) >> BACKEND_DISABLE_SHIFT; + rdev->config.cayman.backend_disable_mask_per_asic = + cayman_get_disable_mask_per_asic(rdev, tmp, CAYMAN_MAX_BACKENDS_PER_SE_MASK, + rdev->config.cayman.num_shader_engines); + rdev->config.cayman.backend_map = + cayman_get_tile_pipe_to_backend_map(rdev, rdev->config.cayman.num_tile_pipes, + rdev->config.cayman.num_backends_per_se * + rdev->config.cayman.num_shader_engines, + &rdev->config.cayman.backend_disable_mask_per_asic, + rdev->config.cayman.num_shader_engines); + tmp = ((~cgts_user_tcc_disable) & TCC_DISABLE_MASK) >> TCC_DISABLE_SHIFT; + rdev->config.cayman.num_texture_channel_caches = r600_count_pipe_bits(tmp); + tmp = (mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT; + rdev->config.cayman.mem_max_burst_length_bytes = (tmp + 1) * 256; + if (rdev->config.cayman.mem_max_burst_length_bytes > 512) + rdev->config.cayman.mem_max_burst_length_bytes = 512; tmp = (mc_arb_ramcfg & NOOFCOLS_MASK) >> NOOFCOLS_SHIFT; rdev->config.cayman.mem_row_size_in_kb = (4 * (1 << (8 + tmp))) / 1024; if (rdev->config.cayman.mem_row_size_in_kb > 4) @@ -519,6 +748,73 @@ static void cayman_gpu_init(struct radeon_device *rdev) rdev->config.cayman.num_gpus = 1; rdev->config.cayman.multi_gpu_tile_size = 64; + //gb_addr_config = 0x02011003 +#if 0 + gb_addr_config = RREG32(GB_ADDR_CONFIG); +#else + gb_addr_config = 0; + switch (rdev->config.cayman.num_tile_pipes) { + case 1: + default: + gb_addr_config |= NUM_PIPES(0); + break; + case 2: + gb_addr_config |= NUM_PIPES(1); + break; + case 4: + gb_addr_config |= NUM_PIPES(2); + break; + case 8: + gb_addr_config |= NUM_PIPES(3); + break; + } + + tmp = (rdev->config.cayman.mem_max_burst_length_bytes / 256) - 1; + gb_addr_config |= PIPE_INTERLEAVE_SIZE(tmp); + gb_addr_config |= NUM_SHADER_ENGINES(rdev->config.cayman.num_shader_engines - 1); + tmp = (rdev->config.cayman.shader_engine_tile_size / 16) - 1; + gb_addr_config |= SHADER_ENGINE_TILE_SIZE(tmp); + switch (rdev->config.cayman.num_gpus) { + case 1: + default: + gb_addr_config |= NUM_GPUS(0); + break; + case 2: + gb_addr_config |= NUM_GPUS(1); + break; + case 4: + gb_addr_config |= NUM_GPUS(2); + break; + } + switch (rdev->config.cayman.multi_gpu_tile_size) { + case 16: + gb_addr_config |= MULTI_GPU_TILE_SIZE(0); + break; + case 32: + default: + gb_addr_config |= MULTI_GPU_TILE_SIZE(1); + break; + case 64: + gb_addr_config |= MULTI_GPU_TILE_SIZE(2); + break; + case 128: + gb_addr_config |= MULTI_GPU_TILE_SIZE(3); + break; + } + switch (rdev->config.cayman.mem_row_size_in_kb) { + case 1: + default: + gb_addr_config |= ROW_SIZE(0); + break; + case 2: + gb_addr_config |= ROW_SIZE(1); + break; + case 4: + gb_addr_config |= ROW_SIZE(2); + break; + } +#endif + tmp = (gb_addr_config & NUM_PIPES_MASK) >> NUM_PIPES_SHIFT; rdev->config.cayman.num_tile_pipes = (1 << tmp); tmp = (gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT; @@ -532,7 +828,17 @@ static void cayman_gpu_init(struct radeon_device *rdev) tmp = (gb_addr_config & ROW_SIZE_MASK) >> ROW_SIZE_SHIFT; rdev->config.cayman.mem_row_size_in_kb = 1 << tmp; - + //gb_backend_map = 0x76541032; +#if 0 + gb_backend_map = RREG32(GB_BACKEND_MAP); +#else + gb_backend_map = + cayman_get_tile_pipe_to_backend_map(rdev, rdev->config.cayman.num_tile_pipes, + rdev->config.cayman.num_backends_per_se * + rdev->config.cayman.num_shader_engines, + &rdev->config.cayman.backend_disable_mask_per_asic, + rdev->config.cayman.num_shader_engines); +#endif /* setup tiling info dword. gb_addr_config is not adequate since it does * not have bank info, so create a custom tiling dword. * bits 3:0 num_pipes @@ -559,50 +865,34 @@ static void cayman_gpu_init(struct radeon_device *rdev) /* num banks is 8 on all fusion asics. 0 = 4, 1 = 8, 2 = 16 */ if (rdev->flags & RADEON_IS_IGP) - rdev->config.cayman.tile_config |= 1 << 4; - else { - if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) - rdev->config.cayman.tile_config |= 1 << 4; - else - rdev->config.cayman.tile_config |= 0 << 4; - } + rdev->config.evergreen.tile_config |= 1 << 4; + else + rdev->config.cayman.tile_config |= + ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4; rdev->config.cayman.tile_config |= ((gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT) << 8; rdev->config.cayman.tile_config |= ((gb_addr_config & ROW_SIZE_MASK) >> ROW_SIZE_SHIFT) << 12; - tmp = 0; - for (i = (rdev->config.cayman.max_shader_engines - 1); i >= 0; i--) { - u32 rb_disable_bitmap; - - WREG32(GRBM_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_INDEX(i)); - WREG32(RLC_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_INDEX(i)); - rb_disable_bitmap = (RREG32(CC_RB_BACKEND_DISABLE) & 0x00ff0000) >> 16; - tmp <<= 4; - tmp |= rb_disable_bitmap; - } - /* enabled rb are just the one not disabled :) */ - disabled_rb_mask = tmp; - - WREG32(GRBM_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_BROADCAST_WRITES); - WREG32(RLC_GFX_INDEX, INSTANCE_BROADCAST_WRITES | SE_BROADCAST_WRITES); - + rdev->config.cayman.backend_map = gb_backend_map; + WREG32(GB_BACKEND_MAP, gb_backend_map); WREG32(GB_ADDR_CONFIG, gb_addr_config); WREG32(DMIF_ADDR_CONFIG, gb_addr_config); WREG32(HDP_ADDR_CONFIG, gb_addr_config); - tmp = gb_addr_config & NUM_PIPES_MASK; - tmp = r6xx_remap_render_backend(rdev, tmp, - rdev->config.cayman.max_backends_per_se * - rdev->config.cayman.max_shader_engines, - CAYMAN_MAX_BACKENDS, disabled_rb_mask); - WREG32(GB_BACKEND_MAP, tmp); + /* primary versions */ + WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable); + WREG32(CC_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable); + WREG32(CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); - cgts_tcc_disable = 0xffff0000; - for (i = 0; i < rdev->config.cayman.max_texture_channel_caches; i++) - cgts_tcc_disable &= ~(1 << (16 + i)); WREG32(CGTS_TCC_DISABLE, cgts_tcc_disable); WREG32(CGTS_SYS_TCC_DISABLE, cgts_tcc_disable); + + /* user versions */ + WREG32(GC_USER_RB_BACKEND_DISABLE, cc_rb_backend_disable); + WREG32(GC_USER_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable); + WREG32(GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); + WREG32(CGTS_USER_SYS_TCC_DISABLE, cgts_tcc_disable); WREG32(CGTS_USER_TCC_DISABLE, cgts_tcc_disable); diff --git a/trunk/drivers/gpu/drm/radeon/nid.h b/trunk/drivers/gpu/drm/radeon/nid.h index a0b98066e207..2aa7046ada56 100644 --- a/trunk/drivers/gpu/drm/radeon/nid.h +++ b/trunk/drivers/gpu/drm/radeon/nid.h @@ -41,9 +41,6 @@ #define CAYMAN_MAX_TCC 16 #define CAYMAN_MAX_TCC_MASK 0xFF -#define CAYMAN_GB_ADDR_CONFIG_GOLDEN 0x02011003 -#define ARUBA_GB_ADDR_CONFIG_GOLDEN 0x12010001 - #define DMIF_ADDR_CONFIG 0xBD4 #define SRBM_GFX_CNTL 0x0E44 #define RINGID(x) (((x) & 0x3) << 0) @@ -151,8 +148,6 @@ #define CGTS_SYS_TCC_DISABLE 0x3F90 #define CGTS_USER_SYS_TCC_DISABLE 0x3F94 -#define RLC_GFX_INDEX 0x3FC4 - #define CONFIG_MEMSIZE 0x5428 #define HDP_MEM_COHERENCY_FLUSH_CNTL 0x5480 @@ -217,12 +212,6 @@ #define SOFT_RESET_VGT (1 << 14) #define SOFT_RESET_IA (1 << 15) -#define GRBM_GFX_INDEX 0x802C -#define INSTANCE_INDEX(x) ((x) << 0) -#define SE_INDEX(x) ((x) << 16) -#define INSTANCE_BROADCAST_WRITES (1 << 30) -#define SE_BROADCAST_WRITES (1 << 31) - #define SCRATCH_REG0 0x8500 #define SCRATCH_REG1 0x8504 #define SCRATCH_REG2 0x8508 diff --git a/trunk/drivers/gpu/drm/radeon/r600.c b/trunk/drivers/gpu/drm/radeon/r600.c index 45cfcea63507..f388a1d73b63 100644 --- a/trunk/drivers/gpu/drm/radeon/r600.c +++ b/trunk/drivers/gpu/drm/radeon/r600.c @@ -1376,51 +1376,113 @@ int r600_asic_reset(struct radeon_device *rdev) return r600_gpu_soft_reset(rdev); } -u32 r6xx_remap_render_backend(struct radeon_device *rdev, - u32 tiling_pipe_num, - u32 max_rb_num, - u32 total_max_rb_num, - u32 disabled_rb_mask) -{ - u32 rendering_pipe_num, rb_num_width, req_rb_num; - u32 pipe_rb_ratio, pipe_rb_remain; - u32 data = 0, mask = 1 << (max_rb_num - 1); - unsigned i, j; - - /* mask out the RBs that don't exist on that asic */ - disabled_rb_mask |= (0xff << max_rb_num) & 0xff; - - rendering_pipe_num = 1 << tiling_pipe_num; - req_rb_num = total_max_rb_num - r600_count_pipe_bits(disabled_rb_mask); - BUG_ON(rendering_pipe_num < req_rb_num); - - pipe_rb_ratio = rendering_pipe_num / req_rb_num; - pipe_rb_remain = rendering_pipe_num - pipe_rb_ratio * req_rb_num; - - if (rdev->family <= CHIP_RV740) { - /* r6xx/r7xx */ - rb_num_width = 2; - } else { - /* eg+ */ - rb_num_width = 4; - } +static u32 r600_get_tile_pipe_to_backend_map(u32 num_tile_pipes, + u32 num_backends, + u32 backend_disable_mask) +{ + u32 backend_map = 0; + u32 enabled_backends_mask; + u32 enabled_backends_count; + u32 cur_pipe; + u32 swizzle_pipe[R6XX_MAX_PIPES]; + u32 cur_backend; + u32 i; - for (i = 0; i < max_rb_num; i++) { - if (!(mask & disabled_rb_mask)) { - for (j = 0; j < pipe_rb_ratio; j++) { - data <<= rb_num_width; - data |= max_rb_num - i - 1; - } - if (pipe_rb_remain) { - data <<= rb_num_width; - data |= max_rb_num - i - 1; - pipe_rb_remain--; - } + if (num_tile_pipes > R6XX_MAX_PIPES) + num_tile_pipes = R6XX_MAX_PIPES; + if (num_tile_pipes < 1) + num_tile_pipes = 1; + if (num_backends > R6XX_MAX_BACKENDS) + num_backends = R6XX_MAX_BACKENDS; + if (num_backends < 1) + num_backends = 1; + + enabled_backends_mask = 0; + enabled_backends_count = 0; + for (i = 0; i < R6XX_MAX_BACKENDS; ++i) { + if (((backend_disable_mask >> i) & 1) == 0) { + enabled_backends_mask |= (1 << i); + ++enabled_backends_count; } - mask >>= 1; + if (enabled_backends_count == num_backends) + break; + } + + if (enabled_backends_count == 0) { + enabled_backends_mask = 1; + enabled_backends_count = 1; + } + + if (enabled_backends_count != num_backends) + num_backends = enabled_backends_count; + + memset((uint8_t *)&swizzle_pipe[0], 0, sizeof(u32) * R6XX_MAX_PIPES); + switch (num_tile_pipes) { + case 1: + swizzle_pipe[0] = 0; + break; + case 2: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + break; + case 3: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + swizzle_pipe[2] = 2; + break; + case 4: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + swizzle_pipe[2] = 2; + swizzle_pipe[3] = 3; + break; + case 5: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + swizzle_pipe[2] = 2; + swizzle_pipe[3] = 3; + swizzle_pipe[4] = 4; + break; + case 6: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 4; + swizzle_pipe[3] = 5; + swizzle_pipe[4] = 1; + swizzle_pipe[5] = 3; + break; + case 7: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 4; + swizzle_pipe[3] = 6; + swizzle_pipe[4] = 1; + swizzle_pipe[5] = 3; + swizzle_pipe[6] = 5; + break; + case 8: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 4; + swizzle_pipe[3] = 6; + swizzle_pipe[4] = 1; + swizzle_pipe[5] = 3; + swizzle_pipe[6] = 5; + swizzle_pipe[7] = 7; + break; } - return data; + cur_backend = 0; + for (cur_pipe = 0; cur_pipe < num_tile_pipes; ++cur_pipe) { + while (((1 << cur_backend) & enabled_backends_mask) == 0) + cur_backend = (cur_backend + 1) % R6XX_MAX_BACKENDS; + + backend_map |= (u32)(((cur_backend & 3) << (swizzle_pipe[cur_pipe] * 2))); + + cur_backend = (cur_backend + 1) % R6XX_MAX_BACKENDS; + } + + return backend_map; } int r600_count_pipe_bits(uint32_t val) @@ -1438,6 +1500,7 @@ void r600_gpu_init(struct radeon_device *rdev) { u32 tiling_config; u32 ramcfg; + u32 backend_map; u32 cc_rb_backend_disable; u32 cc_gc_shader_pipe_config; u32 tmp; @@ -1448,9 +1511,8 @@ void r600_gpu_init(struct radeon_device *rdev) u32 sq_thread_resource_mgmt = 0; u32 sq_stack_resource_mgmt_1 = 0; u32 sq_stack_resource_mgmt_2 = 0; - u32 disabled_rb_mask; - rdev->config.r600.tiling_group_size = 256; + /* FIXME: implement */ switch (rdev->family) { case CHIP_R600: rdev->config.r600.max_pipes = 4; @@ -1554,7 +1616,10 @@ void r600_gpu_init(struct radeon_device *rdev) rdev->config.r600.tiling_nbanks = 4 << ((ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT); tiling_config |= BANK_TILING((ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT); tiling_config |= GROUP_SIZE((ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT); - + if ((ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT) + rdev->config.r600.tiling_group_size = 512; + else + rdev->config.r600.tiling_group_size = 256; tmp = (ramcfg & NOOFROWS_MASK) >> NOOFROWS_SHIFT; if (tmp > 3) { tiling_config |= ROW_TILING(3); @@ -1566,36 +1631,32 @@ void r600_gpu_init(struct radeon_device *rdev) tiling_config |= BANK_SWAPS(1); cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE) & 0x00ff0000; - tmp = R6XX_MAX_BACKENDS - - r600_count_pipe_bits((cc_rb_backend_disable >> 16) & R6XX_MAX_BACKENDS_MASK); - if (tmp < rdev->config.r600.max_backends) { - rdev->config.r600.max_backends = tmp; - } - - cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & 0x00ffff00; - tmp = R6XX_MAX_PIPES - - r600_count_pipe_bits((cc_gc_shader_pipe_config >> 8) & R6XX_MAX_PIPES_MASK); - if (tmp < rdev->config.r600.max_pipes) { - rdev->config.r600.max_pipes = tmp; - } - tmp = R6XX_MAX_SIMDS - - r600_count_pipe_bits((cc_gc_shader_pipe_config >> 16) & R6XX_MAX_SIMDS_MASK); - if (tmp < rdev->config.r600.max_simds) { - rdev->config.r600.max_simds = tmp; - } - - disabled_rb_mask = (RREG32(CC_RB_BACKEND_DISABLE) >> 16) & R6XX_MAX_BACKENDS_MASK; - tmp = (tiling_config & PIPE_TILING__MASK) >> PIPE_TILING__SHIFT; - tmp = r6xx_remap_render_backend(rdev, tmp, rdev->config.r600.max_backends, - R6XX_MAX_BACKENDS, disabled_rb_mask); - tiling_config |= tmp << 16; - rdev->config.r600.backend_map = tmp; - + cc_rb_backend_disable |= + BACKEND_DISABLE((R6XX_MAX_BACKENDS_MASK << rdev->config.r600.max_backends) & R6XX_MAX_BACKENDS_MASK); + + cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & 0xffffff00; + cc_gc_shader_pipe_config |= + INACTIVE_QD_PIPES((R6XX_MAX_PIPES_MASK << rdev->config.r600.max_pipes) & R6XX_MAX_PIPES_MASK); + cc_gc_shader_pipe_config |= + INACTIVE_SIMDS((R6XX_MAX_SIMDS_MASK << rdev->config.r600.max_simds) & R6XX_MAX_SIMDS_MASK); + + backend_map = r600_get_tile_pipe_to_backend_map(rdev->config.r600.max_tile_pipes, + (R6XX_MAX_BACKENDS - + r600_count_pipe_bits((cc_rb_backend_disable & + R6XX_MAX_BACKENDS_MASK) >> 16)), + (cc_rb_backend_disable >> 16)); rdev->config.r600.tile_config = tiling_config; + rdev->config.r600.backend_map = backend_map; + tiling_config |= BACKEND_MAP(backend_map); WREG32(GB_TILING_CONFIG, tiling_config); WREG32(DCP_TILING_CONFIG, tiling_config & 0xffff); WREG32(HDP_TILING_CONFIG, tiling_config & 0xffff); + /* Setup pipes */ + WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable); + WREG32(CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); + WREG32(GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); + tmp = R6XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config & INACTIVE_QD_PIPES_MASK) >> 8); WREG32(VGT_OUT_DEALLOC_CNTL, (tmp * 4) & DEALLOC_DIST_MASK); WREG32(VGT_VERTEX_REUSE_BLOCK_CNTL, ((tmp * 4) - 2) & VTX_REUSE_DEPTH_MASK); diff --git a/trunk/drivers/gpu/drm/radeon/r600d.h b/trunk/drivers/gpu/drm/radeon/r600d.h index a0dbf1fe6a40..15bd3b216243 100644 --- a/trunk/drivers/gpu/drm/radeon/r600d.h +++ b/trunk/drivers/gpu/drm/radeon/r600d.h @@ -219,8 +219,6 @@ #define BACKEND_MAP(x) ((x) << 16) #define GB_TILING_CONFIG 0x98F0 -#define PIPE_TILING__SHIFT 1 -#define PIPE_TILING__MASK 0x0000000e #define GC_USER_SHADER_PIPE_CONFIG 0x8954 #define INACTIVE_QD_PIPES(x) ((x) << 8) diff --git a/trunk/drivers/gpu/drm/radeon/radeon.h b/trunk/drivers/gpu/drm/radeon/radeon.h index 85dac33e3cce..1dc3a4aba020 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon.h +++ b/trunk/drivers/gpu/drm/radeon/radeon.h @@ -346,9 +346,6 @@ struct radeon_bo { /* Constant after initialization */ struct radeon_device *rdev; struct drm_gem_object gem_base; - - struct ttm_bo_kmap_obj dma_buf_vmap; - int vmapping_count; }; #define gem_to_radeon_bo(gobj) container_of((gobj), struct radeon_bo, gem_base) @@ -851,6 +848,7 @@ struct radeon_cs_parser { s32 priority; }; +extern int radeon_cs_update_pages(struct radeon_cs_parser *p, int pg_idx); extern int radeon_cs_finish_pages(struct radeon_cs_parser *p); extern u32 radeon_get_ib_value(struct radeon_cs_parser *p, int idx); @@ -1848,11 +1846,6 @@ extern struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock); extern void r600_hdmi_enable(struct drm_encoder *encoder); extern void r600_hdmi_disable(struct drm_encoder *encoder); extern void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode); -extern u32 r6xx_remap_render_backend(struct radeon_device *rdev, - u32 tiling_pipe_num, - u32 max_rb_num, - u32 total_max_rb_num, - u32 enabled_rb_mask); /* * evergreen functions used by radeon_encoder.c diff --git a/trunk/drivers/gpu/drm/radeon/radeon_atombios.c b/trunk/drivers/gpu/drm/radeon/radeon_atombios.c index b1e3820df363..f6e69b8c06c6 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/trunk/drivers/gpu/drm/radeon/radeon_atombios.c @@ -444,9 +444,7 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, */ if ((dev->pdev->device == 0x9498) && (dev->pdev->subsystem_vendor == 0x1682) && - (dev->pdev->subsystem_device == 0x2452) && - (i2c_bus->valid == false) && - !(supported_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))) { + (dev->pdev->subsystem_device == 0x2452)) { struct radeon_device *rdev = dev->dev_private; *i2c_bus = radeon_lookup_i2c_gpio(rdev, 0x93); } diff --git a/trunk/drivers/gpu/drm/radeon/radeon_cs.c b/trunk/drivers/gpu/drm/radeon/radeon_cs.c index 142f89462aa4..c7d64a739033 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_cs.c +++ b/trunk/drivers/gpu/drm/radeon/radeon_cs.c @@ -147,7 +147,6 @@ static int radeon_cs_sync_rings(struct radeon_cs_parser *p) sync_to_ring, p->ring); } -/* XXX: note that this is called from the legacy UMS CS ioctl as well */ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) { struct drm_radeon_cs *cs = data; @@ -246,25 +245,23 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) } } - /* these are KMS only */ - if (p->rdev) { - if ((p->cs_flags & RADEON_CS_USE_VM) && - !p->rdev->vm_manager.enabled) { - DRM_ERROR("VM not active on asic!\n"); - return -EINVAL; - } - - /* we only support VM on SI+ */ - if ((p->rdev->family >= CHIP_TAHITI) && - ((p->cs_flags & RADEON_CS_USE_VM) == 0)) { - DRM_ERROR("VM required on SI+!\n"); - return -EINVAL; - } + if ((p->cs_flags & RADEON_CS_USE_VM) && + !p->rdev->vm_manager.enabled) { + DRM_ERROR("VM not active on asic!\n"); + return -EINVAL; + } - if (radeon_cs_get_ring(p, ring, priority)) - return -EINVAL; + /* we only support VM on SI+ */ + if ((p->rdev->family >= CHIP_TAHITI) && + ((p->cs_flags & RADEON_CS_USE_VM) == 0)) { + DRM_ERROR("VM required on SI+!\n"); + return -EINVAL; } + if (radeon_cs_get_ring(p, ring, priority)) + return -EINVAL; + + /* deal with non-vm */ if ((p->chunk_ib_idx != -1) && ((p->cs_flags & RADEON_CS_USE_VM) == 0) && @@ -583,7 +580,7 @@ int radeon_cs_finish_pages(struct radeon_cs_parser *p) return 0; } -static int radeon_cs_update_pages(struct radeon_cs_parser *p, int pg_idx) +int radeon_cs_update_pages(struct radeon_cs_parser *p, int pg_idx) { int new_page; struct radeon_cs_chunk *ibc = &p->chunks[p->chunk_ib_idx]; @@ -626,28 +623,3 @@ static int radeon_cs_update_pages(struct radeon_cs_parser *p, int pg_idx) return new_page; } - -u32 radeon_get_ib_value(struct radeon_cs_parser *p, int idx) -{ - struct radeon_cs_chunk *ibc = &p->chunks[p->chunk_ib_idx]; - u32 pg_idx, pg_offset; - u32 idx_value = 0; - int new_page; - - pg_idx = (idx * 4) / PAGE_SIZE; - pg_offset = (idx * 4) % PAGE_SIZE; - - if (ibc->kpage_idx[0] == pg_idx) - return ibc->kpage[0][pg_offset/4]; - if (ibc->kpage_idx[1] == pg_idx) - return ibc->kpage[1][pg_offset/4]; - - new_page = radeon_cs_update_pages(p, pg_idx); - if (new_page < 0) { - p->parser_error = new_page; - return 0; - } - - idx_value = ibc->kpage[new_page][pg_offset/4]; - return idx_value; -} diff --git a/trunk/drivers/gpu/drm/radeon/radeon_prime.c b/trunk/drivers/gpu/drm/radeon/radeon_prime.c index 8ddab4c76710..b8f835d8ecb4 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_prime.c +++ b/trunk/drivers/gpu/drm/radeon/radeon_prime.c @@ -85,47 +85,6 @@ static void radeon_gem_kunmap(struct dma_buf *dma_buf, unsigned long page_num, v } -static int radeon_gem_prime_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma) -{ - return -EINVAL; -} - -static void *radeon_gem_prime_vmap(struct dma_buf *dma_buf) -{ - struct radeon_bo *bo = dma_buf->priv; - struct drm_device *dev = bo->rdev->ddev; - int ret; - - mutex_lock(&dev->struct_mutex); - if (bo->vmapping_count) { - bo->vmapping_count++; - goto out_unlock; - } - - ret = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.num_pages, - &bo->dma_buf_vmap); - if (ret) { - mutex_unlock(&dev->struct_mutex); - return ERR_PTR(ret); - } - bo->vmapping_count = 1; -out_unlock: - mutex_unlock(&dev->struct_mutex); - return bo->dma_buf_vmap.virtual; -} - -static void radeon_gem_prime_vunmap(struct dma_buf *dma_buf, void *vaddr) -{ - struct radeon_bo *bo = dma_buf->priv; - struct drm_device *dev = bo->rdev->ddev; - - mutex_lock(&dev->struct_mutex); - bo->vmapping_count--; - if (bo->vmapping_count == 0) { - ttm_bo_kunmap(&bo->dma_buf_vmap); - } - mutex_unlock(&dev->struct_mutex); -} const static struct dma_buf_ops radeon_dmabuf_ops = { .map_dma_buf = radeon_gem_map_dma_buf, .unmap_dma_buf = radeon_gem_unmap_dma_buf, @@ -134,9 +93,6 @@ const static struct dma_buf_ops radeon_dmabuf_ops = { .kmap_atomic = radeon_gem_kmap_atomic, .kunmap = radeon_gem_kunmap, .kunmap_atomic = radeon_gem_kunmap_atomic, - .mmap = radeon_gem_prime_mmap, - .vmap = radeon_gem_prime_vmap, - .vunmap = radeon_gem_prime_vunmap, }; static int radeon_prime_create(struct drm_device *dev, diff --git a/trunk/drivers/gpu/drm/radeon/radeon_ring.c b/trunk/drivers/gpu/drm/radeon/radeon_ring.c index 983658c91358..493a7be75306 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_ring.c +++ b/trunk/drivers/gpu/drm/radeon/radeon_ring.c @@ -39,6 +39,31 @@ */ int radeon_debugfs_sa_init(struct radeon_device *rdev); +u32 radeon_get_ib_value(struct radeon_cs_parser *p, int idx) +{ + struct radeon_cs_chunk *ibc = &p->chunks[p->chunk_ib_idx]; + u32 pg_idx, pg_offset; + u32 idx_value = 0; + int new_page; + + pg_idx = (idx * 4) / PAGE_SIZE; + pg_offset = (idx * 4) % PAGE_SIZE; + + if (ibc->kpage_idx[0] == pg_idx) + return ibc->kpage[0][pg_offset/4]; + if (ibc->kpage_idx[1] == pg_idx) + return ibc->kpage[1][pg_offset/4]; + + new_page = radeon_cs_update_pages(p, pg_idx); + if (new_page < 0) { + p->parser_error = new_page; + return 0; + } + + idx_value = ibc->kpage[new_page][pg_offset/4]; + return idx_value; +} + int radeon_ib_get(struct radeon_device *rdev, int ring, struct radeon_ib *ib, unsigned size) { diff --git a/trunk/drivers/gpu/drm/radeon/rv770.c b/trunk/drivers/gpu/drm/radeon/rv770.c index 04ddc365a908..c2f473bc13b8 100644 --- a/trunk/drivers/gpu/drm/radeon/rv770.c +++ b/trunk/drivers/gpu/drm/radeon/rv770.c @@ -151,8 +151,6 @@ int rv770_pcie_gart_enable(struct radeon_device *rdev) WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp); WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp); WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp); - if (rdev->family == CHIP_RV740) - WREG32(MC_VM_MD_L1_TLB3_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp); @@ -365,6 +363,180 @@ void r700_cp_fini(struct radeon_device *rdev) /* * Core functions */ +static u32 r700_get_tile_pipe_to_backend_map(struct radeon_device *rdev, + u32 num_tile_pipes, + u32 num_backends, + u32 backend_disable_mask) +{ + u32 backend_map = 0; + u32 enabled_backends_mask; + u32 enabled_backends_count; + u32 cur_pipe; + u32 swizzle_pipe[R7XX_MAX_PIPES]; + u32 cur_backend; + u32 i; + bool force_no_swizzle; + + if (num_tile_pipes > R7XX_MAX_PIPES) + num_tile_pipes = R7XX_MAX_PIPES; + if (num_tile_pipes < 1) + num_tile_pipes = 1; + if (num_backends > R7XX_MAX_BACKENDS) + num_backends = R7XX_MAX_BACKENDS; + if (num_backends < 1) + num_backends = 1; + + enabled_backends_mask = 0; + enabled_backends_count = 0; + for (i = 0; i < R7XX_MAX_BACKENDS; ++i) { + if (((backend_disable_mask >> i) & 1) == 0) { + enabled_backends_mask |= (1 << i); + ++enabled_backends_count; + } + if (enabled_backends_count == num_backends) + break; + } + + if (enabled_backends_count == 0) { + enabled_backends_mask = 1; + enabled_backends_count = 1; + } + + if (enabled_backends_count != num_backends) + num_backends = enabled_backends_count; + + switch (rdev->family) { + case CHIP_RV770: + case CHIP_RV730: + force_no_swizzle = false; + break; + case CHIP_RV710: + case CHIP_RV740: + default: + force_no_swizzle = true; + break; + } + + memset((uint8_t *)&swizzle_pipe[0], 0, sizeof(u32) * R7XX_MAX_PIPES); + switch (num_tile_pipes) { + case 1: + swizzle_pipe[0] = 0; + break; + case 2: + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + break; + case 3: + if (force_no_swizzle) { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + swizzle_pipe[2] = 2; + } else { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 1; + } + break; + case 4: + if (force_no_swizzle) { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + swizzle_pipe[2] = 2; + swizzle_pipe[3] = 3; + } else { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 3; + swizzle_pipe[3] = 1; + } + break; + case 5: + if (force_no_swizzle) { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + swizzle_pipe[2] = 2; + swizzle_pipe[3] = 3; + swizzle_pipe[4] = 4; + } else { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 4; + swizzle_pipe[3] = 1; + swizzle_pipe[4] = 3; + } + break; + case 6: + if (force_no_swizzle) { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + swizzle_pipe[2] = 2; + swizzle_pipe[3] = 3; + swizzle_pipe[4] = 4; + swizzle_pipe[5] = 5; + } else { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 4; + swizzle_pipe[3] = 5; + swizzle_pipe[4] = 3; + swizzle_pipe[5] = 1; + } + break; + case 7: + if (force_no_swizzle) { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + swizzle_pipe[2] = 2; + swizzle_pipe[3] = 3; + swizzle_pipe[4] = 4; + swizzle_pipe[5] = 5; + swizzle_pipe[6] = 6; + } else { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 4; + swizzle_pipe[3] = 6; + swizzle_pipe[4] = 3; + swizzle_pipe[5] = 1; + swizzle_pipe[6] = 5; + } + break; + case 8: + if (force_no_swizzle) { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 1; + swizzle_pipe[2] = 2; + swizzle_pipe[3] = 3; + swizzle_pipe[4] = 4; + swizzle_pipe[5] = 5; + swizzle_pipe[6] = 6; + swizzle_pipe[7] = 7; + } else { + swizzle_pipe[0] = 0; + swizzle_pipe[1] = 2; + swizzle_pipe[2] = 4; + swizzle_pipe[3] = 6; + swizzle_pipe[4] = 3; + swizzle_pipe[5] = 1; + swizzle_pipe[6] = 7; + swizzle_pipe[7] = 5; + } + break; + } + + cur_backend = 0; + for (cur_pipe = 0; cur_pipe < num_tile_pipes; ++cur_pipe) { + while (((1 << cur_backend) & enabled_backends_mask) == 0) + cur_backend = (cur_backend + 1) % R7XX_MAX_BACKENDS; + + backend_map |= (u32)(((cur_backend & 3) << (swizzle_pipe[cur_pipe] * 2))); + + cur_backend = (cur_backend + 1) % R7XX_MAX_BACKENDS; + } + + return backend_map; +} + static void rv770_gpu_init(struct radeon_device *rdev) { int i, j, num_qd_pipes; @@ -380,17 +552,14 @@ static void rv770_gpu_init(struct radeon_device *rdev) u32 sq_thread_resource_mgmt; u32 hdp_host_path_cntl; u32 sq_dyn_gpr_size_simd_ab_0; + u32 backend_map; u32 gb_tiling_config = 0; u32 cc_rb_backend_disable = 0; u32 cc_gc_shader_pipe_config = 0; u32 mc_arb_ramcfg; - u32 db_debug4, tmp; - u32 inactive_pipes, shader_pipe_config; - u32 disabled_rb_mask; - unsigned active_number; + u32 db_debug4; /* setup chip specs */ - rdev->config.rv770.tiling_group_size = 256; switch (rdev->family) { case CHIP_RV770: rdev->config.rv770.max_pipes = 4; @@ -501,70 +670,33 @@ static void rv770_gpu_init(struct radeon_device *rdev) /* setup tiling, simd, pipe config */ mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG); - shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG); - inactive_pipes = (shader_pipe_config & INACTIVE_QD_PIPES_MASK) >> INACTIVE_QD_PIPES_SHIFT; - for (i = 0, tmp = 1, active_number = 0; i < R7XX_MAX_PIPES; i++) { - if (!(inactive_pipes & tmp)) { - active_number++; - } - tmp <<= 1; - } - if (active_number == 1) { - WREG32(SPI_CONFIG_CNTL, DISABLE_INTERP_1); - } else { - WREG32(SPI_CONFIG_CNTL, 0); - } - - cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE) & 0x00ff0000; - tmp = R7XX_MAX_BACKENDS - r600_count_pipe_bits(cc_rb_backend_disable >> 16); - if (tmp < rdev->config.rv770.max_backends) { - rdev->config.rv770.max_backends = tmp; - } - - cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & 0xffffff00; - tmp = R7XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config >> 8) & R7XX_MAX_PIPES_MASK); - if (tmp < rdev->config.rv770.max_pipes) { - rdev->config.rv770.max_pipes = tmp; - } - tmp = R7XX_MAX_SIMDS - r600_count_pipe_bits((cc_gc_shader_pipe_config >> 16) & R7XX_MAX_SIMDS_MASK); - if (tmp < rdev->config.rv770.max_simds) { - rdev->config.rv770.max_simds = tmp; - } - switch (rdev->config.rv770.max_tile_pipes) { case 1: default: - gb_tiling_config = PIPE_TILING(0); + gb_tiling_config |= PIPE_TILING(0); break; case 2: - gb_tiling_config = PIPE_TILING(1); + gb_tiling_config |= PIPE_TILING(1); break; case 4: - gb_tiling_config = PIPE_TILING(2); + gb_tiling_config |= PIPE_TILING(2); break; case 8: - gb_tiling_config = PIPE_TILING(3); + gb_tiling_config |= PIPE_TILING(3); break; } rdev->config.rv770.tiling_npipes = rdev->config.rv770.max_tile_pipes; - disabled_rb_mask = (RREG32(CC_RB_BACKEND_DISABLE) >> 16) & R7XX_MAX_BACKENDS_MASK; - tmp = (gb_tiling_config & PIPE_TILING__MASK) >> PIPE_TILING__SHIFT; - tmp = r6xx_remap_render_backend(rdev, tmp, rdev->config.rv770.max_backends, - R7XX_MAX_BACKENDS, disabled_rb_mask); - gb_tiling_config |= tmp << 16; - rdev->config.rv770.backend_map = tmp; - if (rdev->family == CHIP_RV770) gb_tiling_config |= BANK_TILING(1); - else { - if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) - gb_tiling_config |= BANK_TILING(1); - else - gb_tiling_config |= BANK_TILING(0); - } + else + gb_tiling_config |= BANK_TILING((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT); rdev->config.rv770.tiling_nbanks = 4 << ((gb_tiling_config >> 4) & 0x3); gb_tiling_config |= GROUP_SIZE((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT); + if ((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT) + rdev->config.rv770.tiling_group_size = 512; + else + rdev->config.rv770.tiling_group_size = 256; if (((mc_arb_ramcfg & NOOFROWS_MASK) >> NOOFROWS_SHIFT) > 3) { gb_tiling_config |= ROW_TILING(3); gb_tiling_config |= SAMPLE_SPLIT(3); @@ -576,19 +708,47 @@ static void rv770_gpu_init(struct radeon_device *rdev) } gb_tiling_config |= BANK_SWAPS(1); + + cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE) & 0x00ff0000; + cc_rb_backend_disable |= + BACKEND_DISABLE((R7XX_MAX_BACKENDS_MASK << rdev->config.rv770.max_backends) & R7XX_MAX_BACKENDS_MASK); + + cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & 0xffffff00; + cc_gc_shader_pipe_config |= + INACTIVE_QD_PIPES((R7XX_MAX_PIPES_MASK << rdev->config.rv770.max_pipes) & R7XX_MAX_PIPES_MASK); + cc_gc_shader_pipe_config |= + INACTIVE_SIMDS((R7XX_MAX_SIMDS_MASK << rdev->config.rv770.max_simds) & R7XX_MAX_SIMDS_MASK); + + if (rdev->family == CHIP_RV740) + backend_map = 0x28; + else + backend_map = r700_get_tile_pipe_to_backend_map(rdev, + rdev->config.rv770.max_tile_pipes, + (R7XX_MAX_BACKENDS - + r600_count_pipe_bits((cc_rb_backend_disable & + R7XX_MAX_BACKENDS_MASK) >> 16)), + (cc_rb_backend_disable >> 16)); + rdev->config.rv770.tile_config = gb_tiling_config; + rdev->config.rv770.backend_map = backend_map; + gb_tiling_config |= BACKEND_MAP(backend_map); WREG32(GB_TILING_CONFIG, gb_tiling_config); WREG32(DCP_TILING_CONFIG, (gb_tiling_config & 0xffff)); WREG32(HDP_TILING_CONFIG, (gb_tiling_config & 0xffff)); + WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable); + WREG32(CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); + WREG32(GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); + WREG32(CC_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable); + WREG32(CGTS_SYS_TCC_DISABLE, 0); WREG32(CGTS_TCC_DISABLE, 0); WREG32(CGTS_USER_SYS_TCC_DISABLE, 0); WREG32(CGTS_USER_TCC_DISABLE, 0); - - num_qd_pipes = R7XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config & INACTIVE_QD_PIPES_MASK) >> 8); + num_qd_pipes = + R7XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config & INACTIVE_QD_PIPES_MASK) >> 8); WREG32(VGT_OUT_DEALLOC_CNTL, (num_qd_pipes * 4) & DEALLOC_DIST_MASK); WREG32(VGT_VERTEX_REUSE_BLOCK_CNTL, ((num_qd_pipes * 4) - 2) & VTX_REUSE_DEPTH_MASK); @@ -649,6 +809,8 @@ static void rv770_gpu_init(struct radeon_device *rdev) WREG32(VGT_NUM_INSTANCES, 1); + WREG32(SPI_CONFIG_CNTL, GPR_WRITE_PRIORITY(0)); + WREG32(SPI_CONFIG_CNTL_1, VTX_DONE_DELAY(4)); WREG32(CP_PERFMON_CNTL, 0); diff --git a/trunk/drivers/gpu/drm/radeon/rv770d.h b/trunk/drivers/gpu/drm/radeon/rv770d.h index fdc089896011..9c549f702f2f 100644 --- a/trunk/drivers/gpu/drm/radeon/rv770d.h +++ b/trunk/drivers/gpu/drm/radeon/rv770d.h @@ -106,13 +106,10 @@ #define BACKEND_MAP(x) ((x) << 16) #define GB_TILING_CONFIG 0x98F0 -#define PIPE_TILING__SHIFT 1 -#define PIPE_TILING__MASK 0x0000000e #define GC_USER_SHADER_PIPE_CONFIG 0x8954 #define INACTIVE_QD_PIPES(x) ((x) << 8) #define INACTIVE_QD_PIPES_MASK 0x0000FF00 -#define INACTIVE_QD_PIPES_SHIFT 8 #define INACTIVE_SIMDS(x) ((x) << 16) #define INACTIVE_SIMDS_MASK 0x00FF0000 @@ -177,7 +174,6 @@ #define MC_VM_MD_L1_TLB0_CNTL 0x2654 #define MC_VM_MD_L1_TLB1_CNTL 0x2658 #define MC_VM_MD_L1_TLB2_CNTL 0x265C -#define MC_VM_MD_L1_TLB3_CNTL 0x2698 #define MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x203C #define MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2038 #define MC_VM_SYSTEM_APERTURE_LOW_ADDR 0x2034 diff --git a/trunk/drivers/gpu/drm/ttm/ttm_bo.c b/trunk/drivers/gpu/drm/ttm/ttm_bo.c index b67cfcaa661f..36792bd4da77 100644 --- a/trunk/drivers/gpu/drm/ttm/ttm_bo.c +++ b/trunk/drivers/gpu/drm/ttm/ttm_bo.c @@ -1834,7 +1834,6 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink) spin_unlock(&glob->lru_lock); (void) ttm_bo_cleanup_refs(bo, false, false, false); kref_put(&bo->list_kref, ttm_bo_release_list); - spin_lock(&glob->lru_lock); continue; } diff --git a/trunk/drivers/gpu/drm/udl/udl_fb.c b/trunk/drivers/gpu/drm/udl/udl_fb.c index ce9a61179925..a029ee39b0c5 100644 --- a/trunk/drivers/gpu/drm/udl/udl_fb.c +++ b/trunk/drivers/gpu/drm/udl/udl_fb.c @@ -156,17 +156,8 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, if (!fb->active_16) return 0; - if (!fb->obj->vmapping) { - ret = udl_gem_vmap(fb->obj); - if (ret == -ENOMEM) { - DRM_ERROR("failed to vmap fb\n"); - return 0; - } - if (!fb->obj->vmapping) { - DRM_ERROR("failed to vmapping\n"); - return 0; - } - } + if (!fb->obj->vmapping) + udl_gem_vmap(fb->obj); start_cycles = get_cycles(); diff --git a/trunk/drivers/gpu/drm/udl/udl_gem.c b/trunk/drivers/gpu/drm/udl/udl_gem.c index 7bd65bdd15a8..40efd32f7dce 100644 --- a/trunk/drivers/gpu/drm/udl/udl_gem.c +++ b/trunk/drivers/gpu/drm/udl/udl_gem.c @@ -180,18 +180,6 @@ int udl_gem_vmap(struct udl_gem_object *obj) int page_count = obj->base.size / PAGE_SIZE; int ret; - if (obj->base.import_attach) { - ret = dma_buf_begin_cpu_access(obj->base.import_attach->dmabuf, - 0, obj->base.size, DMA_BIDIRECTIONAL); - if (ret) - return -EINVAL; - - obj->vmapping = dma_buf_vmap(obj->base.import_attach->dmabuf); - if (!obj->vmapping) - return -ENOMEM; - return 0; - } - ret = udl_gem_get_pages(obj, GFP_KERNEL); if (ret) return ret; @@ -204,13 +192,6 @@ int udl_gem_vmap(struct udl_gem_object *obj) void udl_gem_vunmap(struct udl_gem_object *obj) { - if (obj->base.import_attach) { - dma_buf_vunmap(obj->base.import_attach->dmabuf, obj->vmapping); - dma_buf_end_cpu_access(obj->base.import_attach->dmabuf, 0, - obj->base.size, DMA_BIDIRECTIONAL); - return; - } - if (obj->vmapping) vunmap(obj->vmapping); @@ -221,12 +202,12 @@ void udl_gem_free_object(struct drm_gem_object *gem_obj) { struct udl_gem_object *obj = to_udl_bo(gem_obj); - if (obj->vmapping) - udl_gem_vunmap(obj); - if (gem_obj->import_attach) drm_prime_gem_destroy(gem_obj, obj->sg); + if (obj->vmapping) + udl_gem_vunmap(obj); + if (obj->pages) udl_gem_put_pages(obj); @@ -253,7 +234,7 @@ int udl_gem_mmap(struct drm_file *file, struct drm_device *dev, ret = udl_gem_get_pages(gobj, GFP_KERNEL); if (ret) - goto out; + return ret; if (!gobj->base.map_list.map) { ret = drm_gem_create_mmap_offset(obj); if (ret) @@ -276,6 +257,8 @@ static int udl_prime_create(struct drm_device *dev, { struct udl_gem_object *obj; int npages; + int i; + struct scatterlist *iter; npages = size / PAGE_SIZE; diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c index 21ee78226560..51c9ba5cd2fb 100644 --- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c +++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c @@ -66,7 +66,7 @@ static int vmw_gmr2_bind(struct vmw_private *dev_priv, cmd += sizeof(remap_cmd) / sizeof(uint32); for (i = 0; i < num_pages; ++i) { - if (VMW_PPN_SIZE <= 4) + if (VMW_PPN_SIZE > 4) *cmd = page_to_pfn(*pages++); else *((uint64_t *)cmd) = page_to_pfn(*pages++); diff --git a/trunk/drivers/hwmon/Kconfig b/trunk/drivers/hwmon/Kconfig index 6f1d167cb1ea..7cd9bf42108b 100644 --- a/trunk/drivers/hwmon/Kconfig +++ b/trunk/drivers/hwmon/Kconfig @@ -1036,9 +1036,8 @@ config SENSORS_SCH56XX_COMMON config SENSORS_SCH5627 tristate "SMSC SCH5627" - depends on !PPC && WATCHDOG + depends on !PPC select SENSORS_SCH56XX_COMMON - select WATCHDOG_CORE help If you say yes here you get support for the hardware monitoring features of the SMSC SCH5627 Super-I/O chip including support for @@ -1049,9 +1048,8 @@ config SENSORS_SCH5627 config SENSORS_SCH5636 tristate "SMSC SCH5636" - depends on !PPC && WATCHDOG + depends on !PPC select SENSORS_SCH56XX_COMMON - select WATCHDOG_CORE help SMSC SCH5636 Super I/O chips include an embedded microcontroller for hardware monitoring solutions, allowing motherboard manufacturers to diff --git a/trunk/drivers/hwmon/sch5627.c b/trunk/drivers/hwmon/sch5627.c index 8342275378b8..8ec6dfbccb64 100644 --- a/trunk/drivers/hwmon/sch5627.c +++ b/trunk/drivers/hwmon/sch5627.c @@ -579,7 +579,7 @@ static int __devinit sch5627_probe(struct platform_device *pdev) } /* Note failing to register the watchdog is not a fatal error */ - data->watchdog = sch56xx_watchdog_register(&pdev->dev, data->addr, + data->watchdog = sch56xx_watchdog_register(data->addr, (build_code << 24) | (build_id << 8) | hwmon_rev, &data->update_lock, 1); diff --git a/trunk/drivers/hwmon/sch5636.c b/trunk/drivers/hwmon/sch5636.c index 96a7e68718ca..906d4ed32d81 100644 --- a/trunk/drivers/hwmon/sch5636.c +++ b/trunk/drivers/hwmon/sch5636.c @@ -510,7 +510,7 @@ static int __devinit sch5636_probe(struct platform_device *pdev) } /* Note failing to register the watchdog is not a fatal error */ - data->watchdog = sch56xx_watchdog_register(&pdev->dev, data->addr, + data->watchdog = sch56xx_watchdog_register(data->addr, (revision[0] << 8) | revision[1], &data->update_lock, 0); diff --git a/trunk/drivers/hwmon/sch56xx-common.c b/trunk/drivers/hwmon/sch56xx-common.c index 4380f5d07be2..ce52fc57d41d 100644 --- a/trunk/drivers/hwmon/sch56xx-common.c +++ b/trunk/drivers/hwmon/sch56xx-common.c @@ -66,10 +66,15 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" struct sch56xx_watchdog_data { u16 addr; + u32 revision; struct mutex *io_lock; + struct mutex watchdog_lock; + struct list_head list; /* member of the watchdog_data_list */ struct kref kref; - struct watchdog_info wdinfo; - struct watchdog_device wddev; + struct miscdevice watchdog_miscdev; + unsigned long watchdog_is_open; + char watchdog_name[10]; /* must be unique to avoid sysfs conflict */ + char watchdog_expect_close; u8 watchdog_preset; u8 watchdog_control; u8 watchdog_output_enable; @@ -77,6 +82,15 @@ struct sch56xx_watchdog_data { static struct platform_device *sch56xx_pdev; +/* + * Somewhat ugly :( global data pointer list with all sch56xx devices, so that + * we can find our device data as when using misc_register there is no other + * method to get to ones device data from the open fop. + */ +static LIST_HEAD(watchdog_data_list); +/* Note this lock not only protect list access, but also data.kref access */ +static DEFINE_MUTEX(watchdog_data_mutex); + /* Super I/O functions */ static inline int superio_inb(int base, int reg) { @@ -258,22 +272,22 @@ EXPORT_SYMBOL(sch56xx_read_virtual_reg12); * Watchdog routines */ -/* Release our data struct when we're unregistered *and* - all references to our watchdog device are released */ -static void watchdog_release_resources(struct kref *r) +/* + * Release our data struct when the platform device has been released *and* + * all references to our watchdog device are released. + */ +static void sch56xx_watchdog_release_resources(struct kref *r) { struct sch56xx_watchdog_data *data = container_of(r, struct sch56xx_watchdog_data, kref); kfree(data); } -static int watchdog_set_timeout(struct watchdog_device *wddev, - unsigned int timeout) +static int watchdog_set_timeout(struct sch56xx_watchdog_data *data, + int timeout) { - struct sch56xx_watchdog_data *data = watchdog_get_drvdata(wddev); - unsigned int resolution; + int ret, resolution; u8 control; - int ret; /* 1 second or 60 second resolution? */ if (timeout <= 255) @@ -284,6 +298,12 @@ static int watchdog_set_timeout(struct watchdog_device *wddev, if (timeout < resolution || timeout > (resolution * 255)) return -EINVAL; + mutex_lock(&data->watchdog_lock); + if (!data->addr) { + ret = -ENODEV; + goto leave; + } + if (resolution == 1) control = data->watchdog_control | SCH56XX_WDOG_TIME_BASE_SEC; else @@ -296,7 +316,7 @@ static int watchdog_set_timeout(struct watchdog_device *wddev, control); mutex_unlock(data->io_lock); if (ret) - return ret; + goto leave; data->watchdog_control = control; } @@ -306,17 +326,38 @@ static int watchdog_set_timeout(struct watchdog_device *wddev, * the watchdog countdown. */ data->watchdog_preset = DIV_ROUND_UP(timeout, resolution); - wddev->timeout = data->watchdog_preset * resolution; - return 0; + ret = data->watchdog_preset * resolution; +leave: + mutex_unlock(&data->watchdog_lock); + return ret; +} + +static int watchdog_get_timeout(struct sch56xx_watchdog_data *data) +{ + int timeout; + + mutex_lock(&data->watchdog_lock); + if (data->watchdog_control & SCH56XX_WDOG_TIME_BASE_SEC) + timeout = data->watchdog_preset; + else + timeout = data->watchdog_preset * 60; + mutex_unlock(&data->watchdog_lock); + + return timeout; } -static int watchdog_start(struct watchdog_device *wddev) +static int watchdog_start(struct sch56xx_watchdog_data *data) { - struct sch56xx_watchdog_data *data = watchdog_get_drvdata(wddev); int ret; u8 val; + mutex_lock(&data->watchdog_lock); + if (!data->addr) { + ret = -ENODEV; + goto leave_unlock_watchdog; + } + /* * The sch56xx's watchdog cannot really be started / stopped * it is always running, but we can avoid the timer expiring @@ -344,14 +385,18 @@ static int watchdog_start(struct watchdog_device *wddev) if (ret) goto leave; - /* 2. Enable output */ - val = data->watchdog_output_enable | SCH56XX_WDOG_OUTPUT_ENABLE; - ret = sch56xx_write_virtual_reg(data->addr, - SCH56XX_REG_WDOG_OUTPUT_ENABLE, val); - if (ret) - goto leave; + /* 2. Enable output (if not already enabled) */ + if (!(data->watchdog_output_enable & SCH56XX_WDOG_OUTPUT_ENABLE)) { + val = data->watchdog_output_enable | + SCH56XX_WDOG_OUTPUT_ENABLE; + ret = sch56xx_write_virtual_reg(data->addr, + SCH56XX_REG_WDOG_OUTPUT_ENABLE, + val); + if (ret) + goto leave; - data->watchdog_output_enable = val; + data->watchdog_output_enable = val; + } /* 3. Clear the watchdog event bit if set */ val = inb(data->addr + 9); @@ -360,70 +405,234 @@ static int watchdog_start(struct watchdog_device *wddev) leave: mutex_unlock(data->io_lock); +leave_unlock_watchdog: + mutex_unlock(&data->watchdog_lock); return ret; } -static int watchdog_trigger(struct watchdog_device *wddev) +static int watchdog_trigger(struct sch56xx_watchdog_data *data) { - struct sch56xx_watchdog_data *data = watchdog_get_drvdata(wddev); int ret; + mutex_lock(&data->watchdog_lock); + if (!data->addr) { + ret = -ENODEV; + goto leave; + } + /* Reset the watchdog countdown counter */ mutex_lock(data->io_lock); ret = sch56xx_write_virtual_reg(data->addr, SCH56XX_REG_WDOG_PRESET, data->watchdog_preset); mutex_unlock(data->io_lock); - +leave: + mutex_unlock(&data->watchdog_lock); return ret; } -static int watchdog_stop(struct watchdog_device *wddev) +static int watchdog_stop_unlocked(struct sch56xx_watchdog_data *data) { - struct sch56xx_watchdog_data *data = watchdog_get_drvdata(wddev); int ret = 0; u8 val; - val = data->watchdog_output_enable & ~SCH56XX_WDOG_OUTPUT_ENABLE; - mutex_lock(data->io_lock); - ret = sch56xx_write_virtual_reg(data->addr, - SCH56XX_REG_WDOG_OUTPUT_ENABLE, val); - mutex_unlock(data->io_lock); - if (ret) - return ret; + if (!data->addr) + return -ENODEV; + + if (data->watchdog_output_enable & SCH56XX_WDOG_OUTPUT_ENABLE) { + val = data->watchdog_output_enable & + ~SCH56XX_WDOG_OUTPUT_ENABLE; + mutex_lock(data->io_lock); + ret = sch56xx_write_virtual_reg(data->addr, + SCH56XX_REG_WDOG_OUTPUT_ENABLE, + val); + mutex_unlock(data->io_lock); + if (ret) + return ret; + + data->watchdog_output_enable = val; + } + + return ret; +} + +static int watchdog_stop(struct sch56xx_watchdog_data *data) +{ + int ret; + + mutex_lock(&data->watchdog_lock); + ret = watchdog_stop_unlocked(data); + mutex_unlock(&data->watchdog_lock); + + return ret; +} + +static int watchdog_release(struct inode *inode, struct file *filp) +{ + struct sch56xx_watchdog_data *data = filp->private_data; + + if (data->watchdog_expect_close) { + watchdog_stop(data); + data->watchdog_expect_close = 0; + } else { + watchdog_trigger(data); + pr_crit("unexpected close, not stopping watchdog!\n"); + } + + clear_bit(0, &data->watchdog_is_open); + + mutex_lock(&watchdog_data_mutex); + kref_put(&data->kref, sch56xx_watchdog_release_resources); + mutex_unlock(&watchdog_data_mutex); - data->watchdog_output_enable = val; return 0; } -static void watchdog_ref(struct watchdog_device *wddev) +static int watchdog_open(struct inode *inode, struct file *filp) { - struct sch56xx_watchdog_data *data = watchdog_get_drvdata(wddev); + struct sch56xx_watchdog_data *pos, *data = NULL; + int ret, watchdog_is_open; + + /* + * We get called from drivers/char/misc.c with misc_mtx hold, and we + * call misc_register() from sch56xx_watchdog_probe() with + * watchdog_data_mutex hold, as misc_register() takes the misc_mtx + * lock, this is a possible deadlock, so we use mutex_trylock here. + */ + if (!mutex_trylock(&watchdog_data_mutex)) + return -ERESTARTSYS; + list_for_each_entry(pos, &watchdog_data_list, list) { + if (pos->watchdog_miscdev.minor == iminor(inode)) { + data = pos; + break; + } + } + /* Note we can never not have found data, so we don't check for this */ + watchdog_is_open = test_and_set_bit(0, &data->watchdog_is_open); + if (!watchdog_is_open) + kref_get(&data->kref); + mutex_unlock(&watchdog_data_mutex); + + if (watchdog_is_open) + return -EBUSY; + + filp->private_data = data; + + /* Start the watchdog */ + ret = watchdog_start(data); + if (ret) { + watchdog_release(inode, filp); + return ret; + } - kref_get(&data->kref); + return nonseekable_open(inode, filp); } -static void watchdog_unref(struct watchdog_device *wddev) +static ssize_t watchdog_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) { - struct sch56xx_watchdog_data *data = watchdog_get_drvdata(wddev); + int ret; + struct sch56xx_watchdog_data *data = filp->private_data; + + if (count) { + if (!nowayout) { + size_t i; + + /* Clear it in case it was set with a previous write */ + data->watchdog_expect_close = 0; + + for (i = 0; i != count; i++) { + char c; + if (get_user(c, buf + i)) + return -EFAULT; + if (c == 'V') + data->watchdog_expect_close = 1; + } + } + ret = watchdog_trigger(data); + if (ret) + return ret; + } + return count; +} + +static long watchdog_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct watchdog_info ident = { + .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT, + .identity = "sch56xx watchdog" + }; + int i, ret = 0; + struct sch56xx_watchdog_data *data = filp->private_data; + + switch (cmd) { + case WDIOC_GETSUPPORT: + ident.firmware_version = data->revision; + if (!nowayout) + ident.options |= WDIOF_MAGICCLOSE; + if (copy_to_user((void __user *)arg, &ident, sizeof(ident))) + ret = -EFAULT; + break; + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + ret = put_user(0, (int __user *)arg); + break; + + case WDIOC_KEEPALIVE: + ret = watchdog_trigger(data); + break; - kref_put(&data->kref, watchdog_release_resources); + case WDIOC_GETTIMEOUT: + i = watchdog_get_timeout(data); + ret = put_user(i, (int __user *)arg); + break; + + case WDIOC_SETTIMEOUT: + if (get_user(i, (int __user *)arg)) { + ret = -EFAULT; + break; + } + ret = watchdog_set_timeout(data, i); + if (ret >= 0) + ret = put_user(ret, (int __user *)arg); + break; + + case WDIOC_SETOPTIONS: + if (get_user(i, (int __user *)arg)) { + ret = -EFAULT; + break; + } + + if (i & WDIOS_DISABLECARD) + ret = watchdog_stop(data); + else if (i & WDIOS_ENABLECARD) + ret = watchdog_trigger(data); + else + ret = -EINVAL; + break; + + default: + ret = -ENOTTY; + } + return ret; } -static const struct watchdog_ops watchdog_ops = { - .owner = THIS_MODULE, - .start = watchdog_start, - .stop = watchdog_stop, - .ping = watchdog_trigger, - .set_timeout = watchdog_set_timeout, - .ref = watchdog_ref, - .unref = watchdog_unref, +static const struct file_operations watchdog_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .open = watchdog_open, + .release = watchdog_release, + .write = watchdog_write, + .unlocked_ioctl = watchdog_ioctl, }; -struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent, +struct sch56xx_watchdog_data *sch56xx_watchdog_register( u16 addr, u32 revision, struct mutex *io_lock, int check_enabled) { struct sch56xx_watchdog_data *data; - int err, control, output_enable; + int i, err, control, output_enable; + const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 }; /* Cache the watchdog registers */ mutex_lock(io_lock); @@ -447,55 +656,82 @@ struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent, return NULL; data->addr = addr; + data->revision = revision; data->io_lock = io_lock; + data->watchdog_control = control; + data->watchdog_output_enable = output_enable; + mutex_init(&data->watchdog_lock); + INIT_LIST_HEAD(&data->list); kref_init(&data->kref); - strlcpy(data->wdinfo.identity, "sch56xx watchdog", - sizeof(data->wdinfo.identity)); - data->wdinfo.firmware_version = revision; - data->wdinfo.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT; - if (!nowayout) - data->wdinfo.options |= WDIOF_MAGICCLOSE; - - data->wddev.info = &data->wdinfo; - data->wddev.ops = &watchdog_ops; - data->wddev.parent = parent; - data->wddev.timeout = 60; - data->wddev.min_timeout = 1; - data->wddev.max_timeout = 255 * 60; - if (nowayout) - set_bit(WDOG_NO_WAY_OUT, &data->wddev.status); - if (output_enable & SCH56XX_WDOG_OUTPUT_ENABLE) - set_bit(WDOG_ACTIVE, &data->wddev.status); - - /* Since the watchdog uses a downcounter there is no register to read - the BIOS set timeout from (if any was set at all) -> - Choose a preset which will give us a 1 minute timeout */ - if (control & SCH56XX_WDOG_TIME_BASE_SEC) - data->watchdog_preset = 60; /* seconds */ - else - data->watchdog_preset = 1; /* minute */ + err = watchdog_set_timeout(data, 60); + if (err < 0) + goto error; - data->watchdog_control = control; - data->watchdog_output_enable = output_enable; + /* + * We take the data_mutex lock early so that watchdog_open() cannot + * run when misc_register() has completed, but we've not yet added + * our data to the watchdog_data_list. + */ + mutex_lock(&watchdog_data_mutex); + for (i = 0; i < ARRAY_SIZE(watchdog_minors); i++) { + /* Register our watchdog part */ + snprintf(data->watchdog_name, sizeof(data->watchdog_name), + "watchdog%c", (i == 0) ? '\0' : ('0' + i)); + data->watchdog_miscdev.name = data->watchdog_name; + data->watchdog_miscdev.fops = &watchdog_fops; + data->watchdog_miscdev.minor = watchdog_minors[i]; + err = misc_register(&data->watchdog_miscdev); + if (err == -EBUSY) + continue; + if (err) + break; + + list_add(&data->list, &watchdog_data_list); + pr_info("Registered /dev/%s chardev major 10, minor: %d\n", + data->watchdog_name, watchdog_minors[i]); + break; + } + mutex_unlock(&watchdog_data_mutex); - watchdog_set_drvdata(&data->wddev, data); - err = watchdog_register_device(&data->wddev); if (err) { pr_err("Registering watchdog chardev: %d\n", err); - kfree(data); - return NULL; + goto error; + } + if (i == ARRAY_SIZE(watchdog_minors)) { + pr_warn("Couldn't register watchdog (no free minor)\n"); + goto error; } return data; + +error: + kfree(data); + return NULL; } EXPORT_SYMBOL(sch56xx_watchdog_register); void sch56xx_watchdog_unregister(struct sch56xx_watchdog_data *data) { - watchdog_unregister_device(&data->wddev); - kref_put(&data->kref, watchdog_release_resources); - /* Don't touch data after this it may have been free-ed! */ + mutex_lock(&watchdog_data_mutex); + misc_deregister(&data->watchdog_miscdev); + list_del(&data->list); + mutex_unlock(&watchdog_data_mutex); + + mutex_lock(&data->watchdog_lock); + if (data->watchdog_is_open) { + pr_warn("platform device unregistered with watchdog " + "open! Stopping watchdog.\n"); + watchdog_stop_unlocked(data); + } + /* Tell the wdog start/stop/trigger functions our dev is gone */ + data->addr = 0; + data->io_lock = NULL; + mutex_unlock(&data->watchdog_lock); + + mutex_lock(&watchdog_data_mutex); + kref_put(&data->kref, sch56xx_watchdog_release_resources); + mutex_unlock(&watchdog_data_mutex); } EXPORT_SYMBOL(sch56xx_watchdog_unregister); diff --git a/trunk/drivers/hwmon/sch56xx-common.h b/trunk/drivers/hwmon/sch56xx-common.h index 704ea2c6d28a..7475086eb978 100644 --- a/trunk/drivers/hwmon/sch56xx-common.h +++ b/trunk/drivers/hwmon/sch56xx-common.h @@ -27,6 +27,6 @@ int sch56xx_read_virtual_reg16(u16 addr, u16 reg); int sch56xx_read_virtual_reg12(u16 addr, u16 msb_reg, u16 lsn_reg, int high_nibble); -struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent, +struct sch56xx_watchdog_data *sch56xx_watchdog_register( u16 addr, u32 revision, struct mutex *io_lock, int check_enabled); void sch56xx_watchdog_unregister(struct sch56xx_watchdog_data *data); diff --git a/trunk/drivers/i2c/algos/i2c-algo-bit.c b/trunk/drivers/i2c/algos/i2c-algo-bit.c index fad22b0bb5b0..7f0b83219744 100644 --- a/trunk/drivers/i2c/algos/i2c-algo-bit.c +++ b/trunk/drivers/i2c/algos/i2c-algo-bit.c @@ -608,7 +608,7 @@ static int bit_xfer(struct i2c_adapter *i2c_adap, static u32 bit_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL | + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; diff --git a/trunk/drivers/i2c/busses/i2c-nuc900.c b/trunk/drivers/i2c/busses/i2c-nuc900.c index a26dfb8cd586..03b615778887 100644 --- a/trunk/drivers/i2c/busses/i2c-nuc900.c +++ b/trunk/drivers/i2c/busses/i2c-nuc900.c @@ -502,8 +502,7 @@ static int nuc900_i2c_xfer(struct i2c_adapter *adap, /* declare our i2c functionality */ static u32 nuc900_i2c_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART | - I2C_FUNC_PROTOCOL_MANGLING; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING; } /* i2c bus registration info */ diff --git a/trunk/drivers/i2c/busses/i2c-s3c2410.c b/trunk/drivers/i2c/busses/i2c-s3c2410.c index 01959154572d..fa0b13490873 100644 --- a/trunk/drivers/i2c/busses/i2c-s3c2410.c +++ b/trunk/drivers/i2c/busses/i2c-s3c2410.c @@ -626,8 +626,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, /* declare our i2c functionality */ static u32 s3c24xx_i2c_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART | - I2C_FUNC_PROTOCOL_MANGLING; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING; } /* i2c bus registration info */ diff --git a/trunk/drivers/i2c/i2c-dev.c b/trunk/drivers/i2c/i2c-dev.c index 5ec2261574ec..45048323b75e 100644 --- a/trunk/drivers/i2c/i2c-dev.c +++ b/trunk/drivers/i2c/i2c-dev.c @@ -265,41 +265,19 @@ static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client, res = 0; for (i = 0; i < rdwr_arg.nmsgs; i++) { - /* Limit the size of the message to a sane amount */ - if (rdwr_pa[i].len > 8192) { + /* Limit the size of the message to a sane amount; + * and don't let length change either. */ + if ((rdwr_pa[i].len > 8192) || + (rdwr_pa[i].flags & I2C_M_RECV_LEN)) { res = -EINVAL; break; } - data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf; rdwr_pa[i].buf = memdup_user(data_ptrs[i], rdwr_pa[i].len); if (IS_ERR(rdwr_pa[i].buf)) { res = PTR_ERR(rdwr_pa[i].buf); break; } - - /* - * If the message length is received from the slave (similar - * to SMBus block read), we must ensure that the buffer will - * be large enough to cope with a message length of - * I2C_SMBUS_BLOCK_MAX as this is the maximum underlying bus - * drivers allow. The first byte in the buffer must be - * pre-filled with the number of extra bytes, which must be - * at least one to hold the message length, but can be - * greater (for example to account for a checksum byte at - * the end of the message.) - */ - if (rdwr_pa[i].flags & I2C_M_RECV_LEN) { - if (!(rdwr_pa[i].flags & I2C_M_RD) || - rdwr_pa[i].buf[0] < 1 || - rdwr_pa[i].len < rdwr_pa[i].buf[0] + - I2C_SMBUS_BLOCK_MAX) { - res = -EINVAL; - break; - } - - rdwr_pa[i].len = rdwr_pa[i].buf[0]; - } } if (res < 0) { int j; diff --git a/trunk/drivers/input/joystick/as5011.c b/trunk/drivers/input/joystick/as5011.c index 57d19d4e0a2d..3063464474bf 100644 --- a/trunk/drivers/input/joystick/as5011.c +++ b/trunk/drivers/input/joystick/as5011.c @@ -231,7 +231,6 @@ static int __devinit as5011_probe(struct i2c_client *client, } if (!i2c_check_functionality(client->adapter, - I2C_FUNC_NOSTART | I2C_FUNC_PROTOCOL_MANGLING)) { dev_err(&client->dev, "need i2c bus that supports protocol mangling\n"); diff --git a/trunk/drivers/iommu/amd_iommu.c b/trunk/drivers/iommu/amd_iommu.c index d90a421e9cac..a5bee8e2dfce 100644 --- a/trunk/drivers/iommu/amd_iommu.c +++ b/trunk/drivers/iommu/amd_iommu.c @@ -450,27 +450,12 @@ static void dump_command(unsigned long phys_addr) static void iommu_print_event(struct amd_iommu *iommu, void *__evt) { - int type, devid, domid, flags; - volatile u32 *event = __evt; - int count = 0; - u64 address; - -retry: - type = (event[1] >> EVENT_TYPE_SHIFT) & EVENT_TYPE_MASK; - devid = (event[0] >> EVENT_DEVID_SHIFT) & EVENT_DEVID_MASK; - domid = (event[1] >> EVENT_DOMID_SHIFT) & EVENT_DOMID_MASK; - flags = (event[1] >> EVENT_FLAGS_SHIFT) & EVENT_FLAGS_MASK; - address = (u64)(((u64)event[3]) << 32) | event[2]; - - if (type == 0) { - /* Did we hit the erratum? */ - if (++count == LOOP_TIMEOUT) { - pr_err("AMD-Vi: No event written to event log\n"); - return; - } - udelay(1); - goto retry; - } + u32 *event = __evt; + int type = (event[1] >> EVENT_TYPE_SHIFT) & EVENT_TYPE_MASK; + int devid = (event[0] >> EVENT_DEVID_SHIFT) & EVENT_DEVID_MASK; + int domid = (event[1] >> EVENT_DOMID_SHIFT) & EVENT_DOMID_MASK; + int flags = (event[1] >> EVENT_FLAGS_SHIFT) & EVENT_FLAGS_MASK; + u64 address = (u64)(((u64)event[3]) << 32) | event[2]; printk(KERN_ERR "AMD-Vi: Event logged ["); @@ -523,8 +508,6 @@ static void iommu_print_event(struct amd_iommu *iommu, void *__evt) default: printk(KERN_ERR "UNKNOWN type=0x%02x]\n", type); } - - memset(__evt, 0, 4 * sizeof(u32)); } static void iommu_poll_events(struct amd_iommu *iommu) @@ -2052,20 +2035,20 @@ static int pdev_iommuv2_enable(struct pci_dev *pdev) } /* FIXME: Move this to PCI code */ -#define PCI_PRI_TLP_OFF (1 << 15) +#define PCI_PRI_TLP_OFF (1 << 2) bool pci_pri_tlp_required(struct pci_dev *pdev) { - u16 status; + u16 control; int pos; pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI); if (!pos) return false; - pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status); + pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control); - return (status & PCI_PRI_TLP_OFF) ? true : false; + return (control & PCI_PRI_TLP_OFF) ? true : false; } /* diff --git a/trunk/drivers/iommu/iommu.c b/trunk/drivers/iommu/iommu.c index 8b9ded88e6f5..2198b2dbbcd3 100644 --- a/trunk/drivers/iommu/iommu.c +++ b/trunk/drivers/iommu/iommu.c @@ -119,7 +119,6 @@ EXPORT_SYMBOL_GPL(iommu_present); * iommu_set_fault_handler() - set a fault handler for an iommu domain * @domain: iommu domain * @handler: fault handler - * @token: user data, will be passed back to the fault handler * * This function should be used by IOMMU users which want to be notified * whenever an IOMMU fault happens. @@ -128,13 +127,11 @@ EXPORT_SYMBOL_GPL(iommu_present); * error code otherwise. */ void iommu_set_fault_handler(struct iommu_domain *domain, - iommu_fault_handler_t handler, - void *token) + iommu_fault_handler_t handler) { BUG_ON(!domain); domain->handler = handler; - domain->handler_token = token; } EXPORT_SYMBOL_GPL(iommu_set_fault_handler); diff --git a/trunk/drivers/iommu/omap-iommu.c b/trunk/drivers/iommu/omap-iommu.c index e70ee2b59df9..6899dcd02dfa 100644 --- a/trunk/drivers/iommu/omap-iommu.c +++ b/trunk/drivers/iommu/omap-iommu.c @@ -41,13 +41,11 @@ * @pgtable: the page table * @iommu_dev: an omap iommu device attached to this domain. only a single * iommu device can be attached for now. - * @dev: Device using this domain. * @lock: domain lock, should be taken when attaching/detaching */ struct omap_iommu_domain { u32 *pgtable; struct omap_iommu *iommu_dev; - struct device *dev; spinlock_t lock; }; @@ -1083,7 +1081,6 @@ omap_iommu_attach_dev(struct iommu_domain *domain, struct device *dev) } omap_domain->iommu_dev = arch_data->iommu_dev = oiommu; - omap_domain->dev = dev; oiommu->domain = domain; out: @@ -1091,16 +1088,19 @@ omap_iommu_attach_dev(struct iommu_domain *domain, struct device *dev) return ret; } -static void _omap_iommu_detach_dev(struct omap_iommu_domain *omap_domain, - struct device *dev) +static void omap_iommu_detach_dev(struct iommu_domain *domain, + struct device *dev) { - struct omap_iommu *oiommu = dev_to_omap_iommu(dev); + struct omap_iommu_domain *omap_domain = domain->priv; struct omap_iommu_arch_data *arch_data = dev->archdata.iommu; + struct omap_iommu *oiommu = dev_to_omap_iommu(dev); + + spin_lock(&omap_domain->lock); /* only a single device is supported per domain for now */ if (omap_domain->iommu_dev != oiommu) { dev_err(dev, "invalid iommu device\n"); - return; + goto out; } iopgtable_clear_entry_all(oiommu); @@ -1108,16 +1108,8 @@ static void _omap_iommu_detach_dev(struct omap_iommu_domain *omap_domain, omap_iommu_detach(oiommu); omap_domain->iommu_dev = arch_data->iommu_dev = NULL; - omap_domain->dev = NULL; -} -static void omap_iommu_detach_dev(struct iommu_domain *domain, - struct device *dev) -{ - struct omap_iommu_domain *omap_domain = domain->priv; - - spin_lock(&omap_domain->lock); - _omap_iommu_detach_dev(omap_domain, dev); +out: spin_unlock(&omap_domain->lock); } @@ -1156,19 +1148,13 @@ static int omap_iommu_domain_init(struct iommu_domain *domain) return -ENOMEM; } +/* assume device was already detached */ static void omap_iommu_domain_destroy(struct iommu_domain *domain) { struct omap_iommu_domain *omap_domain = domain->priv; domain->priv = NULL; - /* - * An iommu device is still attached - * (currently, only one device can be attached) ? - */ - if (omap_domain->iommu_dev) - _omap_iommu_detach_dev(omap_domain, omap_domain->dev); - kfree(omap_domain->pgtable); kfree(omap_domain); } diff --git a/trunk/drivers/iommu/tegra-gart.c b/trunk/drivers/iommu/tegra-gart.c index 0c0a37792218..779306ee7b16 100644 --- a/trunk/drivers/iommu/tegra-gart.c +++ b/trunk/drivers/iommu/tegra-gart.c @@ -29,17 +29,15 @@ #include #include #include -#include #include /* bitmap of the page sizes currently supported */ #define GART_IOMMU_PGSIZES (SZ_4K) -#define GART_REG_BASE 0x24 -#define GART_CONFIG (0x24 - GART_REG_BASE) -#define GART_ENTRY_ADDR (0x28 - GART_REG_BASE) -#define GART_ENTRY_DATA (0x2c - GART_REG_BASE) +#define GART_CONFIG 0x24 +#define GART_ENTRY_ADDR 0x28 +#define GART_ENTRY_DATA 0x2c #define GART_ENTRY_PHYS_ADDR_VALID (1 << 31) #define GART_PAGE_SHIFT 12 @@ -160,7 +158,7 @@ static int gart_iommu_attach_dev(struct iommu_domain *domain, struct gart_client *client, *c; int err = 0; - gart = gart_handle; + gart = dev_get_drvdata(dev->parent); if (!gart) return -EINVAL; domain->priv = gart; @@ -424,14 +422,6 @@ const struct dev_pm_ops tegra_gart_pm_ops = { .resume = tegra_gart_resume, }; -#ifdef CONFIG_OF -static struct of_device_id tegra_gart_of_match[] __devinitdata = { - { .compatible = "nvidia,tegra20-gart", }, - { }, -}; -MODULE_DEVICE_TABLE(of, tegra_gart_of_match); -#endif - static struct platform_driver tegra_gart_driver = { .probe = tegra_gart_probe, .remove = tegra_gart_remove, @@ -439,7 +429,6 @@ static struct platform_driver tegra_gart_driver = { .owner = THIS_MODULE, .name = "tegra-gart", .pm = &tegra_gart_pm_ops, - .of_match_table = of_match_ptr(tegra_gart_of_match), }, }; @@ -459,5 +448,4 @@ module_exit(tegra_gart_exit); MODULE_DESCRIPTION("IOMMU API for GART in Tegra20"); MODULE_AUTHOR("Hiroshi DOYU "); -MODULE_ALIAS("platform:tegra-gart"); MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/iommu/tegra-smmu.c b/trunk/drivers/iommu/tegra-smmu.c index ecd679043d77..eb93c821f592 100644 --- a/trunk/drivers/iommu/tegra-smmu.c +++ b/trunk/drivers/iommu/tegra-smmu.c @@ -733,7 +733,7 @@ static int smmu_iommu_attach_dev(struct iommu_domain *domain, pr_info("Reserve \"page zero\" for AVP vectors using a common dummy\n"); } - dev_dbg(smmu->dev, "%s is attached\n", dev_name(dev)); + dev_dbg(smmu->dev, "%s is attached\n", dev_name(c->dev)); return 0; err_client: diff --git a/trunk/drivers/message/fusion/mptbase.c b/trunk/drivers/message/fusion/mptbase.c index d99db5623acf..48052b62ee08 100644 --- a/trunk/drivers/message/fusion/mptbase.c +++ b/trunk/drivers/message/fusion/mptbase.c @@ -6479,7 +6479,6 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) printk(MYIOC_s_INFO_FMT "%s: host reset in" " progress mpt_config timed out.!!\n", __func__, ioc->name); - mutex_unlock(&ioc->mptbase_cmds.mutex); return -EFAULT; } spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); diff --git a/trunk/drivers/mfd/db8500-prcmu.c b/trunk/drivers/mfd/db8500-prcmu.c index 50e83dc5dc49..671c8bc14bbc 100644 --- a/trunk/drivers/mfd/db8500-prcmu.c +++ b/trunk/drivers/mfd/db8500-prcmu.c @@ -2735,7 +2735,6 @@ static struct regulator_consumer_supply db8500_vape_consumers[] = { REGULATOR_SUPPLY("vcore", "uart2"), REGULATOR_SUPPLY("v-ape", "nmk-ske-keypad.0"), REGULATOR_SUPPLY("v-hsi", "ste_hsi.0"), - REGULATOR_SUPPLY("vddvario", "smsc911x.0"), }; static struct regulator_consumer_supply db8500_vsmps2_consumers[] = { diff --git a/trunk/drivers/mtd/Kconfig b/trunk/drivers/mtd/Kconfig index 27143e042af5..5760c1a4b3f6 100644 --- a/trunk/drivers/mtd/Kconfig +++ b/trunk/drivers/mtd/Kconfig @@ -128,7 +128,7 @@ config MTD_AFS_PARTS config MTD_OF_PARTS tristate "OpenFirmware partitioning information support" - default y + default Y depends on OF help This provides a partition parsing function which derives diff --git a/trunk/drivers/mtd/bcm63xxpart.c b/trunk/drivers/mtd/bcm63xxpart.c index 63d2a64331f7..608321ee056e 100644 --- a/trunk/drivers/mtd/bcm63xxpart.c +++ b/trunk/drivers/mtd/bcm63xxpart.c @@ -4,7 +4,7 @@ * Copyright © 2006-2008 Florian Fainelli * Mike Albon * Copyright © 2009-2010 Daniel Dickinson - * Copyright © 2011-2012 Jonas Gorski + * Copyright © 2011 Jonas Gorski * * 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 @@ -82,7 +82,6 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, int namelen = 0; int i; u32 computed_crc; - bool rootfs_first = false; if (bcm63xx_detect_cfe(master)) return -EINVAL; @@ -110,7 +109,6 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, char *boardid = &(buf->board_id[0]); char *tagversion = &(buf->tag_version[0]); - sscanf(buf->flash_image_start, "%u", &rootfsaddr); sscanf(buf->kernel_address, "%u", &kerneladdr); sscanf(buf->kernel_length, "%u", &kernellen); sscanf(buf->total_length, "%u", &totallen); @@ -119,19 +117,10 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, tagversion, boardid); kerneladdr = kerneladdr - BCM63XX_EXTENDED_SIZE; - rootfsaddr = rootfsaddr - BCM63XX_EXTENDED_SIZE; + rootfsaddr = kerneladdr + kernellen; spareaddr = roundup(totallen, master->erasesize) + cfelen; sparelen = master->size - spareaddr - nvramlen; - - if (rootfsaddr < kerneladdr) { - /* default Broadcom layout */ - rootfslen = kerneladdr - rootfsaddr; - rootfs_first = true; - } else { - /* OpenWrt layout */ - rootfsaddr = kerneladdr + kernellen; - rootfslen = spareaddr - rootfsaddr; - } + rootfslen = spareaddr - rootfsaddr; } else { pr_warn("CFE boot tag CRC invalid (expected %08x, actual %08x)\n", buf->header_crc, computed_crc); @@ -167,26 +156,18 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, curpart++; if (kernellen > 0) { - int kernelpart = curpart; - - if (rootfslen > 0 && rootfs_first) - kernelpart++; - parts[kernelpart].name = "kernel"; - parts[kernelpart].offset = kerneladdr; - parts[kernelpart].size = kernellen; + parts[curpart].name = "kernel"; + parts[curpart].offset = kerneladdr; + parts[curpart].size = kernellen; curpart++; } if (rootfslen > 0) { - int rootfspart = curpart; - - if (kernellen > 0 && rootfs_first) - rootfspart--; - parts[rootfspart].name = "rootfs"; - parts[rootfspart].offset = rootfsaddr; - parts[rootfspart].size = rootfslen; - if (sparelen > 0 && !rootfs_first) - parts[rootfspart].size += sparelen; + parts[curpart].name = "rootfs"; + parts[curpart].offset = rootfsaddr; + parts[curpart].size = rootfslen; + if (sparelen > 0) + parts[curpart].size += sparelen; curpart++; } diff --git a/trunk/drivers/mtd/chips/cfi_cmdset_0002.c b/trunk/drivers/mtd/chips/cfi_cmdset_0002.c index 22d0493a026f..d02592e6a0f0 100644 --- a/trunk/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/trunk/drivers/mtd/chips/cfi_cmdset_0002.c @@ -317,7 +317,7 @@ static void fixup_s29gl064n_sectors(struct mtd_info *mtd) if ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0x003f) { cfi->cfiq->EraseRegionInfo[0] |= 0x0040; - pr_warning("%s: Bad S29GL064N CFI data; adjust from 64 to 128 sectors\n", mtd->name); + pr_warning("%s: Bad S29GL064N CFI data, adjust from 64 to 128 sectors\n", mtd->name); } } @@ -328,23 +328,10 @@ static void fixup_s29gl032n_sectors(struct mtd_info *mtd) if ((cfi->cfiq->EraseRegionInfo[1] & 0xffff) == 0x007e) { cfi->cfiq->EraseRegionInfo[1] &= ~0x0040; - pr_warning("%s: Bad S29GL032N CFI data; adjust from 127 to 63 sectors\n", mtd->name); + pr_warning("%s: Bad S29GL032N CFI data, adjust from 127 to 63 sectors\n", mtd->name); } } -static void fixup_s29ns512p_sectors(struct mtd_info *mtd) -{ - struct map_info *map = mtd->priv; - struct cfi_private *cfi = map->fldrv_priv; - - /* - * S29NS512P flash uses more than 8bits to report number of sectors, - * which is not permitted by CFI. - */ - cfi->cfiq->EraseRegionInfo[0] = 0x020001ff; - pr_warning("%s: Bad S29NS512P CFI data; adjust to 512 sectors\n", mtd->name); -} - /* Used to fix CFI-Tables of chips without Extended Query Tables */ static struct cfi_fixup cfi_nopri_fixup_table[] = { { CFI_MFR_SST, 0x234a, fixup_sst39vf }, /* SST39VF1602 */ @@ -375,7 +362,6 @@ static struct cfi_fixup cfi_fixup_table[] = { { CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors }, { CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors }, { CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors }, - { CFI_MFR_AMD, 0x3f00, fixup_s29ns512p_sectors }, { CFI_MFR_SST, 0x536a, fixup_sst38vf640x_sectorsize }, /* SST38VF6402 */ { CFI_MFR_SST, 0x536b, fixup_sst38vf640x_sectorsize }, /* SST38VF6401 */ { CFI_MFR_SST, 0x536c, fixup_sst38vf640x_sectorsize }, /* SST38VF6404 */ diff --git a/trunk/drivers/mtd/cmdlinepart.c b/trunk/drivers/mtd/cmdlinepart.c index 4558e0f4d07f..ddf9ec6d9168 100644 --- a/trunk/drivers/mtd/cmdlinepart.c +++ b/trunk/drivers/mtd/cmdlinepart.c @@ -70,7 +70,7 @@ struct cmdline_mtd_partition { /* mtdpart_setup() parses into here */ static struct cmdline_mtd_partition *partitions; -/* the command line passed to mtdpart_setup() */ +/* the command line passed to mtdpart_setupd() */ static char *cmdline; static int cmdline_parsed = 0; diff --git a/trunk/drivers/mtd/devices/block2mtd.c b/trunk/drivers/mtd/devices/block2mtd.c index 681e2ee0f2d6..a4a80b742e65 100644 --- a/trunk/drivers/mtd/devices/block2mtd.c +++ b/trunk/drivers/mtd/devices/block2mtd.c @@ -52,6 +52,8 @@ static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len) while (pages) { page = page_read(mapping, index); + if (!page) + return -ENOMEM; if (IS_ERR(page)) return PTR_ERR(page); @@ -110,6 +112,8 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len, len = len - cpylen; page = page_read(dev->blkdev->bd_inode->i_mapping, index); + if (!page) + return -ENOMEM; if (IS_ERR(page)) return PTR_ERR(page); @@ -144,6 +148,8 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf, len = len - cpylen; page = page_read(mapping, index); + if (!page) + return -ENOMEM; if (IS_ERR(page)) return PTR_ERR(page); @@ -265,6 +271,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) dev->mtd.flags = MTD_CAP_RAM; dev->mtd._erase = block2mtd_erase; dev->mtd._write = block2mtd_write; + dev->mtd._writev = mtd_writev; dev->mtd._sync = block2mtd_sync; dev->mtd._read = block2mtd_read; dev->mtd.priv = dev; diff --git a/trunk/drivers/mtd/devices/docg3.c b/trunk/drivers/mtd/devices/docg3.c index f70854d728fe..50aa90aa7a7f 100644 --- a/trunk/drivers/mtd/devices/docg3.c +++ b/trunk/drivers/mtd/devices/docg3.c @@ -227,7 +227,7 @@ static void doc_read_data_area(struct docg3 *docg3, void *buf, int len, u8 data8, *dst8; doc_dbg("doc_read_data_area(buf=%p, len=%d)\n", buf, len); - cdr = len & 0x1; + cdr = len & 0x3; len4 = len - cdr; if (first) @@ -732,24 +732,12 @@ static int doc_read_page_prepare(struct docg3 *docg3, int block0, int block1, * @len: the number of bytes to be read (must be a multiple of 4) * @buf: the buffer to be filled in (or NULL is forget bytes) * @first: 1 if first time read, DOC_READADDRESS should be set - * @last_odd: 1 if last read ended up on an odd byte - * - * Reads bytes from a prepared page. There is a trickery here : if the last read - * ended up on an odd offset in the 1024 bytes double page, ie. between the 2 - * planes, the first byte must be read apart. If a word (16bit) read was used, - * the read would return the byte of plane 2 as low *and* high endian, which - * will mess the read. * */ static int doc_read_page_getbytes(struct docg3 *docg3, int len, u_char *buf, - int first, int last_odd) + int first) { - if (last_odd && len > 0) { - doc_read_data_area(docg3, buf, 1, first); - doc_read_data_area(docg3, buf ? buf + 1 : buf, len - 1, 0); - } else { - doc_read_data_area(docg3, buf, len, first); - } + doc_read_data_area(docg3, buf, len, first); doc_delay(docg3, 2); return len; } @@ -862,7 +850,6 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, u8 *buf = ops->datbuf; size_t len, ooblen, nbdata, nboob; u8 hwecc[DOC_ECC_BCH_SIZE], eccconf1; - int max_bitflips = 0; if (buf) len = ops->len; @@ -889,7 +876,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, ret = 0; skip = from % DOC_LAYOUT_PAGE_SIZE; mutex_lock(&docg3->cascade->lock); - while (ret >= 0 && (len > 0 || ooblen > 0)) { + while (!ret && (len > 0 || ooblen > 0)) { calc_block_sector(from - skip, &block0, &block1, &page, &ofs, docg3->reliable); nbdata = min_t(size_t, len, DOC_LAYOUT_PAGE_SIZE - skip); @@ -900,20 +887,20 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES); if (ret < 0) goto err_in_read; - ret = doc_read_page_getbytes(docg3, skip, NULL, 1, 0); + ret = doc_read_page_getbytes(docg3, skip, NULL, 1); if (ret < skip) goto err_in_read; - ret = doc_read_page_getbytes(docg3, nbdata, buf, 0, skip % 2); + ret = doc_read_page_getbytes(docg3, nbdata, buf, 0); if (ret < nbdata) goto err_in_read; doc_read_page_getbytes(docg3, DOC_LAYOUT_PAGE_SIZE - nbdata - skip, - NULL, 0, (skip + nbdata) % 2); - ret = doc_read_page_getbytes(docg3, nboob, oobbuf, 0, 0); + NULL, 0); + ret = doc_read_page_getbytes(docg3, nboob, oobbuf, 0); if (ret < nboob) goto err_in_read; doc_read_page_getbytes(docg3, DOC_LAYOUT_OOB_SIZE - nboob, - NULL, 0, nboob % 2); + NULL, 0); doc_get_bch_hw_ecc(docg3, hwecc); eccconf1 = doc_register_readb(docg3, DOC_ECCCONF1); @@ -949,8 +936,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from, } if (ret > 0) { mtd->ecc_stats.corrected += ret; - max_bitflips = max(max_bitflips, ret); - ret = max_bitflips; + ret = -EUCLEAN; } } @@ -1018,7 +1004,7 @@ static int doc_reload_bbt(struct docg3 *docg3) DOC_LAYOUT_PAGE_SIZE); if (!ret) doc_read_page_getbytes(docg3, DOC_LAYOUT_PAGE_SIZE, - buf, 1, 0); + buf, 1); buf += DOC_LAYOUT_PAGE_SIZE; } doc_read_page_finish(docg3); @@ -1078,10 +1064,10 @@ static int doc_get_erase_count(struct docg3 *docg3, loff_t from) ret = doc_reset_seq(docg3); if (!ret) ret = doc_read_page_prepare(docg3, block0, block1, page, - ofs + DOC_LAYOUT_WEAR_OFFSET, 0); + ofs + DOC_LAYOUT_WEAR_OFFSET); if (!ret) ret = doc_read_page_getbytes(docg3, DOC_LAYOUT_WEAR_SIZE, - buf, 1, 0); + buf, 1); doc_read_page_finish(docg3); if (ret || (buf[0] != DOC_ERASE_MARK) || (buf[2] != DOC_ERASE_MARK)) diff --git a/trunk/drivers/mtd/devices/m25p80.c b/trunk/drivers/mtd/devices/m25p80.c index 5d0d68c3fe27..1924d247c1cb 100644 --- a/trunk/drivers/mtd/devices/m25p80.c +++ b/trunk/drivers/mtd/devices/m25p80.c @@ -639,16 +639,12 @@ static const struct spi_device_id m25p_ids[] = { { "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) }, { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, - /* Everspin */ - { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2) }, - /* Intel/Numonyx -- xxxs33b */ { "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) }, { "320s33b", INFO(0x898912, 0, 64 * 1024, 64, 0) }, { "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) }, /* Macronix */ - { "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4, SECT_4K) }, { "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) }, { "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) }, { "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) }, @@ -732,7 +728,6 @@ static const struct spi_device_id m25p_ids[] = { { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, - { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, /* Catalyst / On Semiconductor -- non-JEDEC */ { "cat25c11", CAT25_INFO( 16, 8, 16, 1) }, diff --git a/trunk/drivers/mtd/devices/spear_smi.c b/trunk/drivers/mtd/devices/spear_smi.c index 67960362681e..797d43cd3550 100644 --- a/trunk/drivers/mtd/devices/spear_smi.c +++ b/trunk/drivers/mtd/devices/spear_smi.c @@ -990,9 +990,9 @@ static int __devinit spear_smi_probe(struct platform_device *pdev) goto err_clk; } - ret = clk_prepare_enable(dev->clk); + ret = clk_enable(dev->clk); if (ret) - goto err_clk_prepare_enable; + goto err_clk_enable; ret = request_irq(irq, spear_smi_int_handler, 0, pdev->name, dev); if (ret) { @@ -1020,8 +1020,8 @@ static int __devinit spear_smi_probe(struct platform_device *pdev) free_irq(irq, dev); platform_set_drvdata(pdev, NULL); err_irq: - clk_disable_unprepare(dev->clk); -err_clk_prepare_enable: + clk_disable(dev->clk); +err_clk_enable: clk_put(dev->clk); err_clk: iounmap(dev->io_base); @@ -1074,7 +1074,7 @@ static int __devexit spear_smi_remove(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); free_irq(irq, dev); - clk_disable_unprepare(dev->clk); + clk_disable(dev->clk); clk_put(dev->clk); iounmap(dev->io_base); kfree(dev); @@ -1091,7 +1091,7 @@ int spear_smi_suspend(struct platform_device *pdev, pm_message_t state) struct spear_smi *dev = platform_get_drvdata(pdev); if (dev && dev->clk) - clk_disable_unprepare(dev->clk); + clk_disable(dev->clk); return 0; } @@ -1102,7 +1102,7 @@ int spear_smi_resume(struct platform_device *pdev) int ret = -EPERM; if (dev && dev->clk) - ret = clk_prepare_enable(dev->clk); + ret = clk_enable(dev->clk); if (!ret) spear_smi_hw_init(dev); diff --git a/trunk/drivers/mtd/lpddr/qinfo_probe.c b/trunk/drivers/mtd/lpddr/qinfo_probe.c index 45abed67f1ef..dbfe17baf046 100644 --- a/trunk/drivers/mtd/lpddr/qinfo_probe.c +++ b/trunk/drivers/mtd/lpddr/qinfo_probe.c @@ -57,7 +57,7 @@ static struct qinfo_query_info qinfo_array[] = { static long lpddr_get_qinforec_pos(struct map_info *map, char *id_str) { - int qinfo_lines = ARRAY_SIZE(qinfo_array); + int qinfo_lines = sizeof(qinfo_array)/sizeof(struct qinfo_query_info); int i; int bankwidth = map_bankwidth(map) * 8; int major, minor; diff --git a/trunk/drivers/mtd/maps/Kconfig b/trunk/drivers/mtd/maps/Kconfig index 5ba2458e799a..8af67cfd671a 100644 --- a/trunk/drivers/mtd/maps/Kconfig +++ b/trunk/drivers/mtd/maps/Kconfig @@ -224,7 +224,7 @@ config MTD_CK804XROM config MTD_SCB2_FLASH tristate "BIOS flash chip on Intel SCB2 boards" - depends on X86 && MTD_JEDECPROBE && PCI + depends on X86 && MTD_JEDECPROBE help Support for treating the BIOS flash chip on Intel SCB2 boards as an MTD device - with this you can reprogram your BIOS. diff --git a/trunk/drivers/mtd/maps/intel_vr_nor.c b/trunk/drivers/mtd/maps/intel_vr_nor.c index 93f03175c82d..92e1f41634c7 100644 --- a/trunk/drivers/mtd/maps/intel_vr_nor.c +++ b/trunk/drivers/mtd/maps/intel_vr_nor.c @@ -260,7 +260,18 @@ static struct pci_driver vr_nor_pci_driver = { .id_table = vr_nor_pci_ids, }; -module_pci_driver(vr_nor_pci_driver); +static int __init vr_nor_mtd_init(void) +{ + return pci_register_driver(&vr_nor_pci_driver); +} + +static void __exit vr_nor_mtd_exit(void) +{ + pci_unregister_driver(&vr_nor_pci_driver); +} + +module_init(vr_nor_mtd_init); +module_exit(vr_nor_mtd_exit); MODULE_AUTHOR("Andy Lowe"); MODULE_DESCRIPTION("MTD map driver for NOR flash on Intel Vermilion Range"); diff --git a/trunk/drivers/mtd/maps/lantiq-flash.c b/trunk/drivers/mtd/maps/lantiq-flash.c index c03456f17004..b5401e355745 100644 --- a/trunk/drivers/mtd/maps/lantiq-flash.c +++ b/trunk/drivers/mtd/maps/lantiq-flash.c @@ -19,9 +19,9 @@ #include #include #include -#include #include +#include /* * The NOR flash is connected to the same external bus unit (EBU) as PCI. @@ -44,9 +44,8 @@ struct ltq_mtd { struct map_info *map; }; -static const char ltq_map_name[] = "ltq_nor"; -static const char *ltq_probe_types[] __devinitconst = { - "cmdlinepart", "ofpart", NULL }; +static char ltq_map_name[] = "ltq_nor"; +static const char *ltq_probe_types[] __devinitconst = { "cmdlinepart", NULL }; static map_word ltq_read16(struct map_info *map, unsigned long adr) @@ -109,40 +108,44 @@ ltq_copy_to(struct map_info *map, unsigned long to, spin_unlock_irqrestore(&ebu_lock, flags); } -static int __devinit +static int __init ltq_mtd_probe(struct platform_device *pdev) { - struct mtd_part_parser_data ppdata; + struct physmap_flash_data *ltq_mtd_data = dev_get_platdata(&pdev->dev); struct ltq_mtd *ltq_mtd; + struct resource *res; struct cfi_private *cfi; int err; - if (of_machine_is_compatible("lantiq,falcon") && - (ltq_boot_select() != BS_FLASH)) { - dev_err(&pdev->dev, "invalid bootstrap options\n"); - return -ENODEV; - } - ltq_mtd = kzalloc(sizeof(struct ltq_mtd), GFP_KERNEL); platform_set_drvdata(pdev, ltq_mtd); ltq_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!ltq_mtd->res) { - dev_err(&pdev->dev, "failed to get memory resource\n"); + dev_err(&pdev->dev, "failed to get memory resource"); err = -ENOENT; goto err_out; } - ltq_mtd->map = kzalloc(sizeof(struct map_info), GFP_KERNEL); - ltq_mtd->map->phys = ltq_mtd->res->start; - ltq_mtd->map->size = resource_size(ltq_mtd->res); - ltq_mtd->map->virt = devm_request_and_ioremap(&pdev->dev, ltq_mtd->res); - if (!ltq_mtd->map->virt) { - dev_err(&pdev->dev, "failed to remap mem resource\n"); + res = devm_request_mem_region(&pdev->dev, ltq_mtd->res->start, + resource_size(ltq_mtd->res), dev_name(&pdev->dev)); + if (!ltq_mtd->res) { + dev_err(&pdev->dev, "failed to request mem resource"); err = -EBUSY; goto err_out; } + ltq_mtd->map = kzalloc(sizeof(struct map_info), GFP_KERNEL); + ltq_mtd->map->phys = res->start; + ltq_mtd->map->size = resource_size(res); + ltq_mtd->map->virt = devm_ioremap_nocache(&pdev->dev, + ltq_mtd->map->phys, ltq_mtd->map->size); + if (!ltq_mtd->map->virt) { + dev_err(&pdev->dev, "failed to ioremap!\n"); + err = -ENOMEM; + goto err_free; + } + ltq_mtd->map->name = ltq_map_name; ltq_mtd->map->bankwidth = 2; ltq_mtd->map->read = ltq_read16; @@ -166,9 +169,9 @@ ltq_mtd_probe(struct platform_device *pdev) cfi->addr_unlock1 ^= 1; cfi->addr_unlock2 ^= 1; - ppdata.of_node = pdev->dev.of_node; - err = mtd_device_parse_register(ltq_mtd->mtd, ltq_probe_types, - &ppdata, NULL, 0); + err = mtd_device_parse_register(ltq_mtd->mtd, ltq_probe_types, NULL, + ltq_mtd_data->parts, + ltq_mtd_data->nr_parts); if (err) { dev_err(&pdev->dev, "failed to add partitions\n"); goto err_destroy; @@ -201,23 +204,32 @@ ltq_mtd_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id ltq_mtd_match[] = { - { .compatible = "lantiq,nor" }, - {}, -}; -MODULE_DEVICE_TABLE(of, ltq_mtd_match); - static struct platform_driver ltq_mtd_driver = { - .probe = ltq_mtd_probe, .remove = __devexit_p(ltq_mtd_remove), .driver = { - .name = "ltq-nor", + .name = "ltq_nor", .owner = THIS_MODULE, - .of_match_table = ltq_mtd_match, }, }; -module_platform_driver(ltq_mtd_driver); +static int __init +init_ltq_mtd(void) +{ + int ret = platform_driver_probe(<q_mtd_driver, ltq_mtd_probe); + + if (ret) + pr_err("ltq_nor: error registering platform driver"); + return ret; +} + +static void __exit +exit_ltq_mtd(void) +{ + platform_driver_unregister(<q_mtd_driver); +} + +module_init(init_ltq_mtd); +module_exit(exit_ltq_mtd); MODULE_LICENSE("GPL"); MODULE_AUTHOR("John Crispin "); diff --git a/trunk/drivers/mtd/maps/pci.c b/trunk/drivers/mtd/maps/pci.c index f14ce0af763f..1d005a3e9b41 100644 --- a/trunk/drivers/mtd/maps/pci.c +++ b/trunk/drivers/mtd/maps/pci.c @@ -352,7 +352,18 @@ static struct pci_driver mtd_pci_driver = { .id_table = mtd_pci_ids, }; -module_pci_driver(mtd_pci_driver); +static int __init mtd_pci_maps_init(void) +{ + return pci_register_driver(&mtd_pci_driver); +} + +static void __exit mtd_pci_maps_exit(void) +{ + pci_unregister_driver(&mtd_pci_driver); +} + +module_init(mtd_pci_maps_init); +module_exit(mtd_pci_maps_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Russell King "); diff --git a/trunk/drivers/mtd/maps/scb2_flash.c b/trunk/drivers/mtd/maps/scb2_flash.c index 9dcbc684abdb..934a72c80078 100644 --- a/trunk/drivers/mtd/maps/scb2_flash.c +++ b/trunk/drivers/mtd/maps/scb2_flash.c @@ -234,7 +234,20 @@ static struct pci_driver scb2_flash_driver = { .remove = __devexit_p(scb2_flash_remove), }; -module_pci_driver(scb2_flash_driver); +static int __init +scb2_flash_init(void) +{ + return pci_register_driver(&scb2_flash_driver); +} + +static void __exit +scb2_flash_exit(void) +{ + pci_unregister_driver(&scb2_flash_driver); +} + +module_init(scb2_flash_init); +module_exit(scb2_flash_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Tim Hockin "); diff --git a/trunk/drivers/mtd/maps/wr_sbc82xx_flash.c b/trunk/drivers/mtd/maps/wr_sbc82xx_flash.c index e7534c82f93a..71b0ba797912 100644 --- a/trunk/drivers/mtd/maps/wr_sbc82xx_flash.c +++ b/trunk/drivers/mtd/maps/wr_sbc82xx_flash.c @@ -59,7 +59,7 @@ static struct mtd_partition bigflash_parts[] = { } }; -static const char *part_probes[] __initconst = {"cmdlinepart", "RedBoot", NULL}; +static const char *part_probes[] __initdata = {"cmdlinepart", "RedBoot", NULL}; #define init_sbc82xx_one_flash(map, br, or) \ do { \ diff --git a/trunk/drivers/mtd/mtdcore.c b/trunk/drivers/mtd/mtdcore.c index 575730744fdb..c837507dfb1c 100644 --- a/trunk/drivers/mtd/mtdcore.c +++ b/trunk/drivers/mtd/mtdcore.c @@ -250,43 +250,6 @@ static ssize_t mtd_name_show(struct device *dev, } static DEVICE_ATTR(name, S_IRUGO, mtd_name_show, NULL); -static ssize_t mtd_ecc_strength_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct mtd_info *mtd = dev_get_drvdata(dev); - - return snprintf(buf, PAGE_SIZE, "%u\n", mtd->ecc_strength); -} -static DEVICE_ATTR(ecc_strength, S_IRUGO, mtd_ecc_strength_show, NULL); - -static ssize_t mtd_bitflip_threshold_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct mtd_info *mtd = dev_get_drvdata(dev); - - return snprintf(buf, PAGE_SIZE, "%u\n", mtd->bitflip_threshold); -} - -static ssize_t mtd_bitflip_threshold_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct mtd_info *mtd = dev_get_drvdata(dev); - unsigned int bitflip_threshold; - int retval; - - retval = kstrtouint(buf, 0, &bitflip_threshold); - if (retval) - return retval; - - mtd->bitflip_threshold = bitflip_threshold; - return count; -} -static DEVICE_ATTR(bitflip_threshold, S_IRUGO | S_IWUSR, - mtd_bitflip_threshold_show, - mtd_bitflip_threshold_store); - static struct attribute *mtd_attrs[] = { &dev_attr_type.attr, &dev_attr_flags.attr, @@ -297,8 +260,6 @@ static struct attribute *mtd_attrs[] = { &dev_attr_oobsize.attr, &dev_attr_numeraseregions.attr, &dev_attr_name.attr, - &dev_attr_ecc_strength.attr, - &dev_attr_bitflip_threshold.attr, NULL, }; @@ -361,10 +322,6 @@ int add_mtd_device(struct mtd_info *mtd) mtd->index = i; mtd->usecount = 0; - /* default value if not set by driver */ - if (mtd->bitflip_threshold == 0) - mtd->bitflip_threshold = mtd->ecc_strength; - if (is_power_of_2(mtd->erasesize)) mtd->erasesize_shift = ffs(mtd->erasesize) - 1; else @@ -800,24 +757,12 @@ EXPORT_SYMBOL_GPL(mtd_get_unmapped_area); int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { - int ret_code; *retlen = 0; if (from < 0 || from > mtd->size || len > mtd->size - from) return -EINVAL; if (!len) return 0; - - /* - * In the absence of an error, drivers return a non-negative integer - * representing the maximum number of bitflips that were corrected on - * any one ecc region (if applicable; zero otherwise). - */ - ret_code = mtd->_read(mtd, from, len, retlen, buf); - if (unlikely(ret_code < 0)) - return ret_code; - if (mtd->ecc_strength == 0) - return 0; /* device lacks ecc */ - return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0; + return mtd->_read(mtd, from, len, retlen, buf); } EXPORT_SYMBOL_GPL(mtd_read); diff --git a/trunk/drivers/mtd/mtdpart.c b/trunk/drivers/mtd/mtdpart.c index d518e4db8a0b..9651c06de0a9 100644 --- a/trunk/drivers/mtd/mtdpart.c +++ b/trunk/drivers/mtd/mtdpart.c @@ -67,12 +67,12 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len, stats = part->master->ecc_stats; res = part->master->_read(part->master, from + part->offset, len, retlen, buf); - if (unlikely(mtd_is_eccerr(res))) - mtd->ecc_stats.failed += - part->master->ecc_stats.failed - stats.failed; - else - mtd->ecc_stats.corrected += - part->master->ecc_stats.corrected - stats.corrected; + if (unlikely(res)) { + if (mtd_is_bitflip(res)) + mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected; + if (mtd_is_eccerr(res)) + mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed; + } return res; } @@ -517,8 +517,6 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, slave->mtd.ecclayout = master->ecclayout; slave->mtd.ecc_strength = master->ecc_strength; - slave->mtd.bitflip_threshold = master->bitflip_threshold; - if (master->_block_isbad) { uint64_t offs = 0; diff --git a/trunk/drivers/mtd/nand/Kconfig b/trunk/drivers/mtd/nand/Kconfig index 31bb7e5b504a..7d17cecad69d 100644 --- a/trunk/drivers/mtd/nand/Kconfig +++ b/trunk/drivers/mtd/nand/Kconfig @@ -115,46 +115,6 @@ config MTD_NAND_OMAP2 Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4 platforms. -config MTD_NAND_OMAP_BCH - depends on MTD_NAND && MTD_NAND_OMAP2 && ARCH_OMAP3 - bool "Enable support for hardware BCH error correction" - default n - select BCH - select BCH_CONST_PARAMS - help - Support for hardware BCH error correction. - -choice - prompt "BCH error correction capability" - depends on MTD_NAND_OMAP_BCH - -config MTD_NAND_OMAP_BCH8 - bool "8 bits / 512 bytes (recommended)" - help - Support correcting up to 8 bitflips per 512-byte block. - This will use 13 bytes of spare area per 512 bytes of page data. - This is the recommended mode, as 4-bit mode does not work - on some OMAP3 revisions, due to a hardware bug. - -config MTD_NAND_OMAP_BCH4 - bool "4 bits / 512 bytes" - help - Support correcting up to 4 bitflips per 512-byte block. - This will use 7 bytes of spare area per 512 bytes of page data. - Note that this mode does not work on some OMAP3 revisions, due to a - hardware bug. Please check your OMAP datasheet before selecting this - mode. - -endchoice - -if MTD_NAND_OMAP_BCH -config BCH_CONST_M - default 13 -config BCH_CONST_T - default 4 if MTD_NAND_OMAP_BCH4 - default 8 if MTD_NAND_OMAP_BCH8 -endif - config MTD_NAND_IDS tristate @@ -480,7 +440,7 @@ config MTD_NAND_NANDSIM config MTD_NAND_GPMI_NAND bool "GPMI NAND Flash Controller driver" - depends on MTD_NAND && (SOC_IMX23 || SOC_IMX28 || SOC_IMX6Q) + depends on MTD_NAND && (SOC_IMX23 || SOC_IMX28) help Enables NAND Flash support for IMX23 or IMX28. The GPMI controller is very powerful, with the help of BCH diff --git a/trunk/drivers/mtd/nand/alauda.c b/trunk/drivers/mtd/nand/alauda.c index 60a0dfdb0808..4f20e1d8bef1 100644 --- a/trunk/drivers/mtd/nand/alauda.c +++ b/trunk/drivers/mtd/nand/alauda.c @@ -414,7 +414,7 @@ static int alauda_bounce_read(struct mtd_info *mtd, loff_t from, size_t len, } err = 0; if (corrected) - err = 1; /* return max_bitflips per ecc step */ + err = -EUCLEAN; if (uncorrected) err = -EBADMSG; out: @@ -446,7 +446,7 @@ static int alauda_read(struct mtd_info *mtd, loff_t from, size_t len, } err = 0; if (corrected) - err = 1; /* return max_bitflips per ecc step */ + err = -EUCLEAN; if (uncorrected) err = -EBADMSG; return err; diff --git a/trunk/drivers/mtd/nand/atmel_nand.c b/trunk/drivers/mtd/nand/atmel_nand.c index 97ac6712bb19..2165576a1c67 100644 --- a/trunk/drivers/mtd/nand/atmel_nand.c +++ b/trunk/drivers/mtd/nand/atmel_nand.c @@ -324,10 +324,9 @@ static int atmel_nand_calculate(struct mtd_info *mtd, * mtd: mtd info structure * chip: nand chip info structure * buf: buffer to store read data - * oob_required: caller expects OOB data read to chip->oob_poi */ -static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int atmel_nand_read_page(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, int page) { int eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -336,7 +335,6 @@ static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *oob = chip->oob_poi; uint8_t *ecc_pos; int stat; - unsigned int max_bitflips = 0; /* * Errata: ALE is incorrectly wired up to the ECC controller @@ -373,12 +371,10 @@ static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, /* check if there's an error */ stat = chip->ecc.correct(mtd, p, oob, NULL); - if (stat < 0) { + if (stat < 0) mtd->ecc_stats.failed++; - } else { + else mtd->ecc_stats.corrected += stat; - max_bitflips = max_t(unsigned int, max_bitflips, stat); - } /* get back to oob start (end of page) */ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); @@ -386,7 +382,7 @@ static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, /* read the oob */ chip->read_buf(mtd, oob, mtd->oobsize); - return max_bitflips; + return 0; } /* diff --git a/trunk/drivers/mtd/nand/au1550nd.c b/trunk/drivers/mtd/nand/au1550nd.c index 9f609d2dcf62..73abbc3e093e 100644 --- a/trunk/drivers/mtd/nand/au1550nd.c +++ b/trunk/drivers/mtd/nand/au1550nd.c @@ -508,6 +508,8 @@ static int __devinit au1550nd_probe(struct platform_device *pdev) this->chip_delay = 30; this->ecc.mode = NAND_ECC_SOFT; + this->options = NAND_NO_AUTOINCR; + if (pd->devwidth) this->options |= NAND_BUSWIDTH_16; diff --git a/trunk/drivers/mtd/nand/bcm_umi_bch.c b/trunk/drivers/mtd/nand/bcm_umi_bch.c index 5914bb32e001..a930666d0687 100644 --- a/trunk/drivers/mtd/nand/bcm_umi_bch.c +++ b/trunk/drivers/mtd/nand/bcm_umi_bch.c @@ -22,9 +22,9 @@ /* ---- Private Function Prototypes -------------------------------------- */ static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, int page); + struct nand_chip *chip, uint8_t *buf, int page); static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, int oob_required); + struct nand_chip *chip, const uint8_t *buf); /* ---- Private Variables ------------------------------------------------ */ @@ -103,12 +103,11 @@ static struct nand_ecclayout nand_hw_eccoob_4096 = { * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data -* @oob_required: caller expects OOB data read to chip->oob_poi * ***************************************************************************/ static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t * buf, - int oob_required, int page) + int page) { int sectorIdx = 0; int eccsize = chip->ecc.size; @@ -117,7 +116,6 @@ static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd, uint8_t eccCalc[NAND_ECC_NUM_BYTES]; int sectorOobSize = mtd->oobsize / eccsteps; int stat; - unsigned int max_bitflips = 0; for (sectorIdx = 0; sectorIdx < eccsteps; sectorIdx++, datap += eccsize) { @@ -179,10 +177,9 @@ static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd, } #endif mtd->ecc_stats.corrected += stat; - max_bitflips = max_t(unsigned int, max_bitflips, stat); } } - return max_bitflips; + return 0; } /**************************************************************************** @@ -191,11 +188,10 @@ static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd, * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer -* @oob_required: must write chip->oob_poi to OOB * ***************************************************************************/ static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, int oob_required) + struct nand_chip *chip, const uint8_t *buf) { int sectorIdx = 0; int eccsize = chip->ecc.size; diff --git a/trunk/drivers/mtd/nand/bcm_umi_nand.c b/trunk/drivers/mtd/nand/bcm_umi_nand.c index c855e7cd337b..6908cdde3065 100644 --- a/trunk/drivers/mtd/nand/bcm_umi_nand.c +++ b/trunk/drivers/mtd/nand/bcm_umi_nand.c @@ -341,7 +341,7 @@ static int bcm_umi_nand_verify_buf(struct mtd_info *mtd, const u_char * buf, * for MLC parts which may have permanently stuck bits. */ struct nand_chip *chip = mtd->priv; - int ret = chip->ecc.read_page(mtd, chip, readbackbuf, 0, 0); + int ret = chip->ecc.read_page(mtd, chip, readbackbuf, 0); if (ret < 0) return -EFAULT; else { @@ -476,7 +476,12 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) this->badblock_pattern = &largepage_bbt; } - this->ecc.strength = 8; + /* + * FIXME: ecc strength value of 6 bits per 512 bytes of data is a + * conservative guess, given 13 ecc bytes and using bch alg. + * (Assume Galois field order m=15 to allow a margin of error.) + */ + this->ecc.strength = 6; #endif diff --git a/trunk/drivers/mtd/nand/bf5xx_nand.c b/trunk/drivers/mtd/nand/bf5xx_nand.c index 3f1c18599cbd..d7b86b925de5 100644 --- a/trunk/drivers/mtd/nand/bf5xx_nand.c +++ b/trunk/drivers/mtd/nand/bf5xx_nand.c @@ -558,7 +558,7 @@ static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd, } static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) + uint8_t *buf, int page) { bf5xx_nand_read_buf(mtd, buf, mtd->writesize); bf5xx_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize); @@ -567,7 +567,7 @@ static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip } static void bf5xx_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf) { bf5xx_nand_write_buf(mtd, buf, mtd->writesize); bf5xx_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize); diff --git a/trunk/drivers/mtd/nand/cafe_nand.c b/trunk/drivers/mtd/nand/cafe_nand.c index 41371ba1a811..2a96e1a12062 100644 --- a/trunk/drivers/mtd/nand/cafe_nand.c +++ b/trunk/drivers/mtd/nand/cafe_nand.c @@ -364,27 +364,25 @@ static int cafe_nand_write_oob(struct mtd_info *mtd, /* Don't use -- use nand_read_oob_std for now */ static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) + int page, int sndcmd) { chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - return 0; + return 1; } /** * cafe_nand_read_page_syndrome - [REPLACEABLE] hardware ecc syndrome based page read * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data - * @oob_required: caller expects OOB data read to chip->oob_poi * * The hw generator calculates the error syndrome automatically. Therefor * we need a special oob layout and handling. */ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) + uint8_t *buf, int page) { struct cafe_priv *cafe = mtd->priv; - unsigned int max_bitflips = 0; cafe_dev_dbg(&cafe->pdev->dev, "ECC result %08x SYN1,2 %08x\n", cafe_readl(cafe, NAND_ECC_RESULT), @@ -451,11 +449,10 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, } else { dev_dbg(&cafe->pdev->dev, "Corrected %d symbol errors\n", n); mtd->ecc_stats.corrected += n; - max_bitflips = max_t(unsigned int, max_bitflips, n); } } - return max_bitflips; + return 0; } static struct nand_ecclayout cafe_oobinfo_2048 = { @@ -521,8 +518,7 @@ static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = { static void cafe_nand_write_page_lowlevel(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf, int oob_required) + struct nand_chip *chip, const uint8_t *buf) { struct cafe_priv *cafe = mtd->priv; @@ -534,17 +530,16 @@ static void cafe_nand_write_page_lowlevel(struct mtd_info *mtd, } static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, int page, - int cached, int raw) + const uint8_t *buf, int page, int cached, int raw) { int status; chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); if (unlikely(raw)) - chip->ecc.write_page_raw(mtd, chip, buf, oob_required); + chip->ecc.write_page_raw(mtd, chip, buf); else - chip->ecc.write_page(mtd, chip, buf, oob_required); + chip->ecc.write_page(mtd, chip, buf); /* * Cached progamming disabled for now, Not sure if its worth the @@ -690,7 +685,7 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, /* Enable the following for a flash based bad block table */ cafe->nand.bbt_options = NAND_BBT_USE_FLASH; - cafe->nand.options = NAND_OWN_BUFFERS; + cafe->nand.options = NAND_NO_AUTOINCR | NAND_OWN_BUFFERS; if (skipbbt) { cafe->nand.options |= NAND_SKIP_BBTSCAN; @@ -893,7 +888,17 @@ static struct pci_driver cafe_nand_pci_driver = { .resume = cafe_nand_resume, }; -module_pci_driver(cafe_nand_pci_driver); +static int __init cafe_nand_init(void) +{ + return pci_register_driver(&cafe_nand_pci_driver); +} + +static void __exit cafe_nand_exit(void) +{ + pci_unregister_driver(&cafe_nand_pci_driver); +} +module_init(cafe_nand_init); +module_exit(cafe_nand_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("David Woodhouse "); diff --git a/trunk/drivers/mtd/nand/cs553x_nand.c b/trunk/drivers/mtd/nand/cs553x_nand.c index adb6c3ef37fb..821c34c62500 100644 --- a/trunk/drivers/mtd/nand/cs553x_nand.c +++ b/trunk/drivers/mtd/nand/cs553x_nand.c @@ -240,6 +240,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) /* Enable the following for a flash based bad block table */ this->bbt_options = NAND_BBT_USE_FLASH; + this->options = NAND_NO_AUTOINCR; /* Scan to find existence of the device */ if (nand_scan(new_mtd, 1)) { diff --git a/trunk/drivers/mtd/nand/denali.c b/trunk/drivers/mtd/nand/denali.c index 0650aafa0dd2..a9e57d686297 100644 --- a/trunk/drivers/mtd/nand/denali.c +++ b/trunk/drivers/mtd/nand/denali.c @@ -924,10 +924,9 @@ bool is_erased(uint8_t *buf, int len) #define ECC_LAST_ERR(x) ((x) & ERR_CORRECTION_INFO__LAST_ERR_INFO) static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, - uint32_t irq_status, unsigned int *max_bitflips) + uint32_t irq_status) { bool check_erased_page = false; - unsigned int bitflips = 0; if (irq_status & INTR_STATUS__ECC_ERR) { /* read the ECC errors. we'll ignore them for now */ @@ -966,7 +965,6 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, /* correct the ECC error */ buf[offset] ^= err_correction_value; denali->mtd.ecc_stats.corrected++; - bitflips++; } } else { /* if the error is not correctable, need to @@ -986,7 +984,6 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, clear_interrupts(denali); denali_set_intr_modes(denali, true); } - *max_bitflips = bitflips; return check_erased_page; } @@ -1087,7 +1084,7 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *chip, * by write_page above. * */ static void denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf) { /* for regular page writes, we let HW handle all the ECC * data written to the device. */ @@ -1099,7 +1096,7 @@ static void denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, * write_page() function above. */ static void denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf) { /* for raw page writes, we want to disable ECC and simply write whatever data is in the buffer. */ @@ -1113,17 +1110,17 @@ static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip, } static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) + int page, int sndcmd) { read_oob_data(mtd, chip->oob_poi, page); - return 0; + return 0; /* notify NAND core to send command to + NAND device. */ } static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) + uint8_t *buf, int page) { - unsigned int max_bitflips; struct denali_nand_info *denali = mtd_to_denali(mtd); dma_addr_t addr = denali->buf.dma_buf; @@ -1156,7 +1153,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, memcpy(buf, denali->buf.buf, mtd->writesize); - check_erased_page = handle_ecc(denali, buf, irq_status, &max_bitflips); + check_erased_page = handle_ecc(denali, buf, irq_status); denali_enable_dma(denali, false); if (check_erased_page) { @@ -1170,11 +1167,11 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, denali->mtd.ecc_stats.failed++; } } - return max_bitflips; + return 0; } static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) + uint8_t *buf, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); @@ -1705,4 +1702,17 @@ static struct pci_driver denali_pci_driver = { .remove = denali_pci_remove, }; -module_pci_driver(denali_pci_driver); +static int __devinit denali_init(void) +{ + printk(KERN_INFO "Spectra MTD driver\n"); + return pci_register_driver(&denali_pci_driver); +} + +/* Free memory */ +static void __devexit denali_exit(void) +{ + pci_unregister_driver(&denali_pci_driver); +} + +module_init(denali_init); +module_exit(denali_exit); diff --git a/trunk/drivers/mtd/nand/docg4.c b/trunk/drivers/mtd/nand/docg4.c index a225e49a5623..b08202664543 100644 --- a/trunk/drivers/mtd/nand/docg4.c +++ b/trunk/drivers/mtd/nand/docg4.c @@ -720,7 +720,6 @@ static int read_page(struct mtd_info *mtd, struct nand_chip *nand, struct docg4_priv *doc = nand->priv; void __iomem *docptr = doc->virtadr; uint16_t status, edc_err, *buf16; - int bits_corrected = 0; dev_dbg(doc->dev, "%s: page %08x\n", __func__, page); @@ -773,7 +772,7 @@ static int read_page(struct mtd_info *mtd, struct nand_chip *nand, /* If bitflips are reported, attempt to correct with ecc */ if (edc_err & DOC_ECCCONF1_BCH_SYNDROM_ERR) { - bits_corrected = correct_data(mtd, buf, page); + int bits_corrected = correct_data(mtd, buf, page); if (bits_corrected == -EBADMSG) mtd->ecc_stats.failed++; else @@ -782,24 +781,24 @@ static int read_page(struct mtd_info *mtd, struct nand_chip *nand, } writew(0, docptr + DOC_DATAEND); - return bits_corrected; + return 0; } static int docg4_read_page_raw(struct mtd_info *mtd, struct nand_chip *nand, - uint8_t *buf, int oob_required, int page) + uint8_t *buf, int page) { return read_page(mtd, nand, buf, page, false); } static int docg4_read_page(struct mtd_info *mtd, struct nand_chip *nand, - uint8_t *buf, int oob_required, int page) + uint8_t *buf, int page) { return read_page(mtd, nand, buf, page, true); } static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand, - int page) + int page, int sndcmd) { struct docg4_priv *doc = nand->priv; void __iomem *docptr = doc->virtadr; @@ -953,13 +952,13 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *nand, } static void docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand, - const uint8_t *buf, int oob_required) + const uint8_t *buf) { return write_page(mtd, nand, buf, false); } static void docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand, - const uint8_t *buf, int oob_required) + const uint8_t *buf) { return write_page(mtd, nand, buf, true); } @@ -1003,7 +1002,7 @@ static int __init read_factory_bbt(struct mtd_info *mtd) return -ENOMEM; read_page_prologue(mtd, g4_addr); - status = docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE); + status = docg4_read_page(mtd, nand, buf, DOCG4_FACTORY_BBT_PAGE); if (status) goto exit; @@ -1080,7 +1079,7 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs) /* write first page of block */ write_page_prologue(mtd, g4_addr); - docg4_write_page(mtd, nand, buf, 1); + docg4_write_page(mtd, nand, buf); ret = pageprog(mtd); if (!ret) mtd->ecc_stats.badblocks++; @@ -1193,7 +1192,8 @@ static void __init init_mtd_structs(struct mtd_info *mtd) nand->ecc.prepad = 8; nand->ecc.bytes = 8; nand->ecc.strength = DOCG4_T; - nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE; + nand->options = + NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE | NAND_NO_AUTOINCR; nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA; nand->controller = &nand->hwcontrol; spin_lock_init(&nand->controller->lock); diff --git a/trunk/drivers/mtd/nand/fsl_elbc_nand.c b/trunk/drivers/mtd/nand/fsl_elbc_nand.c index 784293806110..80b5264f0a32 100644 --- a/trunk/drivers/mtd/nand/fsl_elbc_nand.c +++ b/trunk/drivers/mtd/nand/fsl_elbc_nand.c @@ -75,7 +75,6 @@ struct fsl_elbc_fcm_ctrl { unsigned int use_mdr; /* Non zero if the MDR is to be set */ unsigned int oob; /* Non zero if operating on OOB data */ unsigned int counter; /* counter for the initializations */ - unsigned int max_bitflips; /* Saved during READ0 cmd */ }; /* These map to the positions used by the FCM hardware ECC generator */ @@ -254,8 +253,6 @@ static int fsl_elbc_run_command(struct mtd_info *mtd) if (chip->ecc.mode != NAND_ECC_HW) return 0; - elbc_fcm_ctrl->max_bitflips = 0; - if (elbc_fcm_ctrl->read_bytes == mtd->writesize + mtd->oobsize) { uint32_t lteccr = in_be32(&lbc->lteccr); /* @@ -265,16 +262,11 @@ static int fsl_elbc_run_command(struct mtd_info *mtd) * bits 28-31 are uncorrectable errors, marked elsewhere. * for small page nand only 1 bit is used. * if the ELBC doesn't have the lteccr register it reads 0 - * FIXME: 4 bits can be corrected on NANDs with 2k pages, so - * count the number of sub-pages with bitflips and update - * ecc_stats.corrected accordingly. */ if (lteccr & 0x000F000F) out_be32(&lbc->lteccr, 0x000F000F); /* clear lteccr */ - if (lteccr & 0x000F0000) { + if (lteccr & 0x000F0000) mtd->ecc_stats.corrected++; - elbc_fcm_ctrl->max_bitflips = 1; - } } return 0; @@ -746,28 +738,26 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) return 0; } -static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int fsl_elbc_read_page(struct mtd_info *mtd, + struct nand_chip *chip, + uint8_t *buf, + int page) { - struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_lbc_ctrl *ctrl = priv->ctrl; - struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand; - fsl_elbc_read_buf(mtd, buf, mtd->writesize); - if (oob_required) - fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize); + fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize); if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL) mtd->ecc_stats.failed++; - return elbc_fcm_ctrl->max_bitflips; + return 0; } /* ECC will be calculated automatically, and errors will be detected in * waitfunc. */ -static void fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) +static void fsl_elbc_write_page(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf) { fsl_elbc_write_buf(mtd, buf, mtd->writesize); fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); @@ -805,7 +795,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) chip->bbt_md = &bbt_mirror_descr; /* set up nand options */ - chip->options = NAND_NO_READRDY; + chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR; chip->bbt_options = NAND_BBT_USE_FLASH; chip->controller = &elbc_fcm_ctrl->controller; @@ -824,6 +814,11 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) chip->ecc.size = 512; chip->ecc.bytes = 3; chip->ecc.strength = 1; + /* + * FIXME: can hardware ecc correct 4 bitflips if page size is + * 2k? Then does hardware report number of corrections for this + * case? If so, ecc_stats reporting needs to be fixed as well. + */ } else { /* otherwise fall back to default software ECC */ chip->ecc.mode = NAND_ECC_SOFT; diff --git a/trunk/drivers/mtd/nand/fsl_ifc_nand.c b/trunk/drivers/mtd/nand/fsl_ifc_nand.c index 9602c1b7e27e..c30ac7b83d28 100644 --- a/trunk/drivers/mtd/nand/fsl_ifc_nand.c +++ b/trunk/drivers/mtd/nand/fsl_ifc_nand.c @@ -63,7 +63,6 @@ struct fsl_ifc_nand_ctrl { unsigned int oob; /* Non zero if operating on OOB data */ unsigned int eccread; /* Non zero for a full-page ECC read */ unsigned int counter; /* counter for the initializations */ - unsigned int max_bitflips; /* Saved during READ0 cmd */ }; static struct fsl_ifc_nand_ctrl *ifc_nand_ctrl; @@ -263,8 +262,6 @@ static void fsl_ifc_run_command(struct mtd_info *mtd) if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_WPER) dev_err(priv->dev, "NAND Flash Write Protect Error\n"); - nctrl->max_bitflips = 0; - if (nctrl->eccread) { int errors; int bufnum = nctrl->page & priv->bufnum_mask; @@ -293,9 +290,6 @@ static void fsl_ifc_run_command(struct mtd_info *mtd) } mtd->ecc_stats.corrected += errors; - nctrl->max_bitflips = max_t(unsigned int, - nctrl->max_bitflips, - errors); } nctrl->eccread = 0; @@ -381,31 +375,21 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, return; + /* READID must read all 8 possible bytes */ case NAND_CMD_READID: - case NAND_CMD_PARAM: { - int timing = IFC_FIR_OP_RB; - if (command == NAND_CMD_PARAM) - timing = IFC_FIR_OP_RBCD; - out_be32(&ifc->ifc_nand.nand_fir0, (IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) | (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | - (timing << IFC_NAND_FIR0_OP2_SHIFT)); + (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT)); out_be32(&ifc->ifc_nand.nand_fcr0, - command << IFC_NAND_FCR0_CMD0_SHIFT); - out_be32(&ifc->ifc_nand.row3, column); - - /* - * although currently it's 8 bytes for READID, we always read - * the maximum 256 bytes(for PARAM) - */ - out_be32(&ifc->ifc_nand.nand_fbcr, 256); - ifc_nand_ctrl->read_bytes = 256; + NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT); + /* 8 bytes for manuf, device and exts */ + out_be32(&ifc->ifc_nand.nand_fbcr, 8); + ifc_nand_ctrl->read_bytes = 8; set_addr(mtd, 0, 0, 0); fsl_ifc_run_command(mtd); return; - } /* ERASE1 stores the block and page address */ case NAND_CMD_ERASE1: @@ -698,16 +682,15 @@ static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip) return nand_fsr | NAND_STATUS_WP; } -static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) +static int fsl_ifc_read_page(struct mtd_info *mtd, + struct nand_chip *chip, + uint8_t *buf, int page) { struct fsl_ifc_mtd *priv = chip->priv; struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl; fsl_ifc_read_buf(mtd, buf, mtd->writesize); - if (oob_required) - fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize); + fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize); if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER) dev_err(priv->dev, "NAND Flash ECC Uncorrectable Error\n"); @@ -715,14 +698,15 @@ static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip, if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) mtd->ecc_stats.failed++; - return nctrl->max_bitflips; + return 0; } /* ECC will be calculated automatically, and errors will be detected in * waitfunc. */ -static void fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) +static void fsl_ifc_write_page(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf) { fsl_ifc_write_buf(mtd, buf, mtd->writesize); fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize); @@ -805,7 +789,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) out_be32(&ifc->ifc_nand.ncfgr, 0x0); /* set up nand options */ - chip->options = NAND_NO_READRDY; + chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR; chip->bbt_options = NAND_BBT_USE_FLASH; @@ -827,7 +811,6 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) /* Hardware generates ECC per 512 Bytes */ chip->ecc.size = 512; chip->ecc.bytes = 8; - chip->ecc.strength = 4; switch (csor & CSOR_NAND_PGS_MASK) { case CSOR_NAND_PGS_512: diff --git a/trunk/drivers/mtd/nand/fsmc_nand.c b/trunk/drivers/mtd/nand/fsmc_nand.c index 38d26240d8b1..1b8330e1155a 100644 --- a/trunk/drivers/mtd/nand/fsmc_nand.c +++ b/trunk/drivers/mtd/nand/fsmc_nand.c @@ -692,7 +692,6 @@ static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf, * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data - * @oob_required: caller expects OOB data read to chip->oob_poi * @page: page number to read * * This routine is needed for fsmc version 8 as reading from NAND chip has to be @@ -702,7 +701,7 @@ static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf, * max of 8 bits) */ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) + uint8_t *buf, int page) { struct fsmc_nand_data *host = container_of(mtd, struct fsmc_nand_data, mtd); @@ -721,7 +720,6 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, */ uint16_t ecc_oob[7]; uint8_t *oob = (uint8_t *)&ecc_oob[0]; - unsigned int max_bitflips = 0; for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) { chip->cmdfunc(mtd, NAND_CMD_READ0, s * eccsize, page); @@ -750,15 +748,13 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, chip->ecc.calculate(mtd, p, &ecc_calc[i]); stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); - if (stat < 0) { + if (stat < 0) mtd->ecc_stats.failed++; - } else { + else mtd->ecc_stats.corrected += stat; - max_bitflips = max_t(unsigned int, max_bitflips, stat); - } } - return max_bitflips; + return 0; } /* @@ -998,9 +994,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) return PTR_ERR(host->clk); } - ret = clk_prepare_enable(host->clk); + ret = clk_enable(host->clk); if (ret) - goto err_clk_prepare_enable; + goto err_clk_enable; /* * This device ID is actually a common AMBA ID as used on the @@ -1180,8 +1176,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) if (host->mode == USE_DMA_ACCESS) dma_release_channel(host->read_dma_chan); err_req_read_chnl: - clk_disable_unprepare(host->clk); -err_clk_prepare_enable: + clk_disable(host->clk); +err_clk_enable: clk_put(host->clk); return ret; } @@ -1202,7 +1198,7 @@ static int fsmc_nand_remove(struct platform_device *pdev) dma_release_channel(host->write_dma_chan); dma_release_channel(host->read_dma_chan); } - clk_disable_unprepare(host->clk); + clk_disable(host->clk); clk_put(host->clk); } @@ -1214,7 +1210,7 @@ static int fsmc_nand_suspend(struct device *dev) { struct fsmc_nand_data *host = dev_get_drvdata(dev); if (host) - clk_disable_unprepare(host->clk); + clk_disable(host->clk); return 0; } @@ -1222,7 +1218,7 @@ static int fsmc_nand_resume(struct device *dev) { struct fsmc_nand_data *host = dev_get_drvdata(dev); if (host) { - clk_prepare_enable(host->clk); + clk_enable(host->clk); fsmc_nand_setup(host->regs_va, host->bank, host->nand.options & NAND_BUSWIDTH_16, host->dev_timings); diff --git a/trunk/drivers/mtd/nand/gpmi-nand/bch-regs.h b/trunk/drivers/mtd/nand/gpmi-nand/bch-regs.h index a0924515c396..4effb8c579db 100644 --- a/trunk/drivers/mtd/nand/gpmi-nand/bch-regs.h +++ b/trunk/drivers/mtd/nand/gpmi-nand/bch-regs.h @@ -51,26 +51,15 @@ #define BP_BCH_FLASH0LAYOUT0_ECC0 12 #define BM_BCH_FLASH0LAYOUT0_ECC0 (0xf << BP_BCH_FLASH0LAYOUT0_ECC0) -#define MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0 11 -#define MX6Q_BM_BCH_FLASH0LAYOUT0_ECC0 (0x1f << MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0) -#define BF_BCH_FLASH0LAYOUT0_ECC0(v, x) \ - (GPMI_IS_MX6Q(x) \ - ? (((v) << MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0) \ - & MX6Q_BM_BCH_FLASH0LAYOUT0_ECC0) \ - : (((v) << BP_BCH_FLASH0LAYOUT0_ECC0) \ - & BM_BCH_FLASH0LAYOUT0_ECC0) \ - ) +#define BF_BCH_FLASH0LAYOUT0_ECC0(v) \ + (((v) << BP_BCH_FLASH0LAYOUT0_ECC0) & BM_BCH_FLASH0LAYOUT0_ECC0) #define BP_BCH_FLASH0LAYOUT0_DATA0_SIZE 0 #define BM_BCH_FLASH0LAYOUT0_DATA0_SIZE \ (0xfff << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE) -#define MX6Q_BM_BCH_FLASH0LAYOUT0_DATA0_SIZE \ - (0x3ff << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE) -#define BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(v, x) \ - (GPMI_IS_MX6Q(x) \ - ? (((v) >> 2) & MX6Q_BM_BCH_FLASH0LAYOUT0_DATA0_SIZE) \ - : ((v) & BM_BCH_FLASH0LAYOUT0_DATA0_SIZE) \ - ) +#define BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(v) \ + (((v) << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE)\ + & BM_BCH_FLASH0LAYOUT0_DATA0_SIZE) #define HW_BCH_FLASH0LAYOUT1 0x00000090 @@ -83,24 +72,13 @@ #define BP_BCH_FLASH0LAYOUT1_ECCN 12 #define BM_BCH_FLASH0LAYOUT1_ECCN (0xf << BP_BCH_FLASH0LAYOUT1_ECCN) -#define MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN 11 -#define MX6Q_BM_BCH_FLASH0LAYOUT1_ECCN (0x1f << MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN) -#define BF_BCH_FLASH0LAYOUT1_ECCN(v, x) \ - (GPMI_IS_MX6Q(x) \ - ? (((v) << MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN) \ - & MX6Q_BM_BCH_FLASH0LAYOUT1_ECCN) \ - : (((v) << BP_BCH_FLASH0LAYOUT1_ECCN) \ - & BM_BCH_FLASH0LAYOUT1_ECCN) \ - ) +#define BF_BCH_FLASH0LAYOUT1_ECCN(v) \ + (((v) << BP_BCH_FLASH0LAYOUT1_ECCN) & BM_BCH_FLASH0LAYOUT1_ECCN) #define BP_BCH_FLASH0LAYOUT1_DATAN_SIZE 0 #define BM_BCH_FLASH0LAYOUT1_DATAN_SIZE \ (0xfff << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE) -#define MX6Q_BM_BCH_FLASH0LAYOUT1_DATAN_SIZE \ - (0x3ff << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE) -#define BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(v, x) \ - (GPMI_IS_MX6Q(x) \ - ? (((v) >> 2) & MX6Q_BM_BCH_FLASH0LAYOUT1_DATAN_SIZE) \ - : ((v) & BM_BCH_FLASH0LAYOUT1_DATAN_SIZE) \ - ) +#define BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(v) \ + (((v) << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE) \ + & BM_BCH_FLASH0LAYOUT1_DATAN_SIZE) #endif diff --git a/trunk/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/trunk/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index a1f43329ad43..e8ea7107932e 100644 --- a/trunk/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/trunk/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "gpmi-nand.h" #include "gpmi-regs.h" @@ -36,8 +37,6 @@ struct timing_threshod timing_default_threshold = { .max_dll_delay_in_ns = 16, }; -#define MXS_SET_ADDR 0x4 -#define MXS_CLR_ADDR 0x8 /* * Clear the bit and poll it cleared. This is usually called with * a reset address and mask being either SFTRST(bit 31) or CLKGATE @@ -48,7 +47,7 @@ static int clear_poll_bit(void __iomem *addr, u32 mask) int timeout = 0x400; /* clear the bit */ - writel(mask, addr + MXS_CLR_ADDR); + __mxs_clrl(mask, addr); /* * SFTRST needs 3 GPMI clocks to settle, the reference manual @@ -93,11 +92,11 @@ static int gpmi_reset_block(void __iomem *reset_addr, bool just_enable) goto error; /* clear CLKGATE */ - writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR); + __mxs_clrl(MODULE_CLKGATE, reset_addr); if (!just_enable) { /* set SFTRST to reset the block */ - writel(MODULE_SFTRST, reset_addr + MXS_SET_ADDR); + __mxs_setl(MODULE_SFTRST, reset_addr); udelay(1); /* poll CLKGATE becoming set */ @@ -224,13 +223,13 @@ int bch_set_geometry(struct gpmi_nand_data *this) /* Configure layout 0. */ writel(BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count) | BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size) - | BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength, this) - | BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size, this), + | BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength) + | BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size), r->bch_regs + HW_BCH_FLASH0LAYOUT0); writel(BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size) - | BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength, this) - | BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size, this), + | BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength) + | BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size), r->bch_regs + HW_BCH_FLASH0LAYOUT1); /* Set *all* chip selects to use layout 0. */ @@ -256,12 +255,11 @@ static unsigned int ns_to_cycles(unsigned int time, return max(k, min); } -#define DEF_MIN_PROP_DELAY 5 -#define DEF_MAX_PROP_DELAY 9 /* Apply timing to current hardware conditions. */ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this, struct gpmi_nfc_hardware_timing *hw) { + struct gpmi_nand_platform_data *pdata = this->pdata; struct timing_threshod *nfc = &timing_default_threshold; struct nand_chip *nand = &this->nand; struct nand_timing target = this->timing; @@ -278,8 +276,8 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this, int ideal_sample_delay_in_ns; unsigned int sample_delay_factor; int tEYE; - unsigned int min_prop_delay_in_ns = DEF_MIN_PROP_DELAY; - unsigned int max_prop_delay_in_ns = DEF_MAX_PROP_DELAY; + unsigned int min_prop_delay_in_ns = pdata->min_prop_delay_in_ns; + unsigned int max_prop_delay_in_ns = pdata->max_prop_delay_in_ns; /* * If there are multiple chips, we need to relax the timings to allow @@ -805,8 +803,7 @@ int gpmi_is_ready(struct gpmi_nand_data *this, unsigned chip) if (GPMI_IS_MX23(this)) { mask = MX23_BM_GPMI_DEBUG_READY0 << chip; reg = readl(r->gpmi_regs + HW_GPMI_DEBUG); - } else if (GPMI_IS_MX28(this) || GPMI_IS_MX6Q(this)) { - /* MX28 shares the same R/B register as MX6Q. */ + } else if (GPMI_IS_MX28(this)) { mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip); reg = readl(r->gpmi_regs + HW_GPMI_STAT); } else diff --git a/trunk/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/trunk/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index a05b7b444d4f..b68e04310bd8 100644 --- a/trunk/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/trunk/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -25,8 +25,6 @@ #include #include #include -#include -#include #include "gpmi-nand.h" /* add our owner bbt descriptor */ @@ -389,7 +387,7 @@ static void release_bch_irq(struct gpmi_nand_data *this) static bool gpmi_dma_filter(struct dma_chan *chan, void *param) { struct gpmi_nand_data *this = param; - int dma_channel = (int)this->private; + struct resource *r = this->private; if (!mxs_dma_is_apbh(chan)) return false; @@ -401,7 +399,7 @@ static bool gpmi_dma_filter(struct dma_chan *chan, void *param) * for mx28 : MX28_DMA_GPMI0 ~ MX28_DMA_GPMI7 * (These eight channels share the same IRQ!) */ - if (dma_channel == chan->chan_id) { + if (r->start <= chan->chan_id && chan->chan_id <= r->end) { chan->private = &this->dma_data; return true; } @@ -421,45 +419,57 @@ static void release_dma_channels(struct gpmi_nand_data *this) static int __devinit acquire_dma_channels(struct gpmi_nand_data *this) { struct platform_device *pdev = this->pdev; - struct resource *r_dma; - struct device_node *dn; - int dma_channel; - unsigned int ret; - struct dma_chan *dma_chan; - dma_cap_mask_t mask; - - /* dma channel, we only use the first one. */ - dn = pdev->dev.of_node; - ret = of_property_read_u32(dn, "fsl,gpmi-dma-channel", &dma_channel); - if (ret) { - pr_err("unable to get DMA channel from dt.\n"); - goto acquire_err; - } - this->private = (void *)dma_channel; + struct gpmi_nand_platform_data *pdata = this->pdata; + struct resources *res = &this->resources; + struct resource *r, *r_dma; + unsigned int i; - /* gpmi dma interrupt */ + r = platform_get_resource_byname(pdev, IORESOURCE_DMA, + GPMI_NAND_DMA_CHANNELS_RES_NAME); r_dma = platform_get_resource_byname(pdev, IORESOURCE_IRQ, GPMI_NAND_DMA_INTERRUPT_RES_NAME); - if (!r_dma) { + if (!r || !r_dma) { pr_err("Can't get resource for DMA\n"); - goto acquire_err; + return -ENXIO; } - this->dma_data.chan_irq = r_dma->start; - /* request dma channel */ - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); + /* used in gpmi_dma_filter() */ + this->private = r; + + for (i = r->start; i <= r->end; i++) { + struct dma_chan *dma_chan; + dma_cap_mask_t mask; - dma_chan = dma_request_channel(mask, gpmi_dma_filter, this); - if (!dma_chan) { - pr_err("dma_request_channel failed.\n"); - goto acquire_err; + if (i - r->start >= pdata->max_chip_count) + break; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + /* get the DMA interrupt */ + if (r_dma->start == r_dma->end) { + /* only register the first. */ + if (i == r->start) + this->dma_data.chan_irq = r_dma->start; + else + this->dma_data.chan_irq = NO_IRQ; + } else + this->dma_data.chan_irq = r_dma->start + (i - r->start); + + dma_chan = dma_request_channel(mask, gpmi_dma_filter, this); + if (!dma_chan) + goto acquire_err; + + /* fill the first empty item */ + this->dma_chans[i - r->start] = dma_chan; } - this->dma_chans[0] = dma_chan; + res->dma_low_channel = r->start; + res->dma_high_channel = i; return 0; acquire_err: + pr_err("Can't acquire DMA channel %u\n", i); release_dma_channels(this); return -EINVAL; } @@ -841,7 +851,7 @@ static void block_mark_swapping(struct gpmi_nand_data *this, } static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) + uint8_t *buf, int page) { struct gpmi_nand_data *this = chip->priv; struct bch_geometry *nfc_geo = &this->bch_geometry; @@ -907,31 +917,28 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, mtd->ecc_stats.corrected += corrected; } - if (oob_required) { - /* - * It's time to deliver the OOB bytes. See gpmi_ecc_read_oob() - * for details about our policy for delivering the OOB. - * - * We fill the caller's buffer with set bits, and then copy the - * block mark to th caller's buffer. Note that, if block mark - * swapping was necessary, it has already been done, so we can - * rely on the first byte of the auxiliary buffer to contain - * the block mark. - */ - memset(chip->oob_poi, ~0, mtd->oobsize); - chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0]; + /* + * It's time to deliver the OOB bytes. See gpmi_ecc_read_oob() for + * details about our policy for delivering the OOB. + * + * We fill the caller's buffer with set bits, and then copy the block + * mark to th caller's buffer. Note that, if block mark swapping was + * necessary, it has already been done, so we can rely on the first + * byte of the auxiliary buffer to contain the block mark. + */ + memset(chip->oob_poi, ~0, mtd->oobsize); + chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0]; - read_page_swap_end(this, buf, mtd->writesize, - this->payload_virt, this->payload_phys, - nfc_geo->payload_size, - payload_virt, payload_phys); - } + read_page_swap_end(this, buf, mtd->writesize, + this->payload_virt, this->payload_phys, + nfc_geo->payload_size, + payload_virt, payload_phys); exit_nfc: return ret; } -static void gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) +static void gpmi_ecc_write_page(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf) { struct gpmi_nand_data *this = chip->priv; struct bch_geometry *nfc_geo = &this->bch_geometry; @@ -1070,7 +1077,7 @@ static void gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, * this driver. */ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) + int page, int sndcmd) { struct gpmi_nand_data *this = chip->priv; @@ -1093,7 +1100,11 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, chip->oob_poi[0] = chip->read_byte(mtd); } - return 0; + /* + * Return true, indicating that the next call to this function must send + * a command. + */ + return true; } static int @@ -1307,7 +1318,7 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this) /* Write the first page of the current stride. */ dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page); chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); - chip->ecc.write_page_raw(mtd, chip, buffer, 0); + chip->ecc.write_page_raw(mtd, chip, buffer); chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); /* Wait for the write to finish. */ @@ -1433,10 +1444,6 @@ static int gpmi_pre_bbt_scan(struct gpmi_nand_data *this) if (ret) return ret; - /* Adjust the ECC strength according to the chip. */ - this->nand.ecc.strength = this->bch_geometry.ecc_strength; - this->mtd.ecc_strength = this->bch_geometry.ecc_strength; - /* NAND boot init, depends on the gpmi_set_geometry(). */ return nand_boot_init(this); } @@ -1464,9 +1471,9 @@ void gpmi_nfc_exit(struct gpmi_nand_data *this) static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this) { + struct gpmi_nand_platform_data *pdata = this->pdata; struct mtd_info *mtd = &this->mtd; struct nand_chip *chip = &this->nand; - struct mtd_part_parser_data ppdata = {}; int ret; /* init current chip */ @@ -1495,7 +1502,6 @@ static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this) chip->options |= NAND_NO_SUBPAGE_WRITE; chip->ecc.mode = NAND_ECC_HW; chip->ecc.size = 1; - chip->ecc.strength = 8; chip->ecc.layout = &gpmi_hw_ecclayout; /* Allocate a temporary DMA buffer for reading ID in the nand_scan() */ @@ -1505,14 +1511,14 @@ static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this) if (ret) goto err_out; - ret = nand_scan(mtd, 1); + ret = nand_scan(mtd, pdata->max_chip_count); if (ret) { pr_err("Chip scan failed\n"); goto err_out; } - ppdata.of_node = this->pdev->dev.of_node; - ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); + ret = mtd_device_parse_register(mtd, NULL, NULL, + pdata->partitions, pdata->partition_count); if (ret) goto err_out; return 0; @@ -1522,41 +1528,12 @@ static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this) return ret; } -static const struct platform_device_id gpmi_ids[] = { - { .name = "imx23-gpmi-nand", .driver_data = IS_MX23, }, - { .name = "imx28-gpmi-nand", .driver_data = IS_MX28, }, - { .name = "imx6q-gpmi-nand", .driver_data = IS_MX6Q, }, - {}, -}; - -static const struct of_device_id gpmi_nand_id_table[] = { - { - .compatible = "fsl,imx23-gpmi-nand", - .data = (void *)&gpmi_ids[IS_MX23] - }, { - .compatible = "fsl,imx28-gpmi-nand", - .data = (void *)&gpmi_ids[IS_MX28] - }, { - .compatible = "fsl,imx6q-gpmi-nand", - .data = (void *)&gpmi_ids[IS_MX6Q] - }, {} -}; -MODULE_DEVICE_TABLE(of, gpmi_nand_id_table); - static int __devinit gpmi_nand_probe(struct platform_device *pdev) { + struct gpmi_nand_platform_data *pdata = pdev->dev.platform_data; struct gpmi_nand_data *this; - const struct of_device_id *of_id; int ret; - of_id = of_match_device(gpmi_nand_id_table, &pdev->dev); - if (of_id) { - pdev->id_entry = of_id->data; - } else { - pr_err("Failed to find the right device id.\n"); - return -ENOMEM; - } - this = kzalloc(sizeof(*this), GFP_KERNEL); if (!this) { pr_err("Failed to allocate per-device memory\n"); @@ -1566,6 +1543,13 @@ static int __devinit gpmi_nand_probe(struct platform_device *pdev) platform_set_drvdata(pdev, this); this->pdev = pdev; this->dev = &pdev->dev; + this->pdata = pdata; + + if (pdata->platform_init) { + ret = pdata->platform_init(); + if (ret) + goto platform_init_error; + } ret = acquire_resources(this); if (ret) @@ -1583,6 +1567,7 @@ static int __devinit gpmi_nand_probe(struct platform_device *pdev) exit_nfc_init: release_resources(this); +platform_init_error: exit_acquire_resources: platform_set_drvdata(pdev, NULL); kfree(this); @@ -1600,10 +1585,19 @@ static int __exit gpmi_nand_remove(struct platform_device *pdev) return 0; } +static const struct platform_device_id gpmi_ids[] = { + { + .name = "imx23-gpmi-nand", + .driver_data = IS_MX23, + }, { + .name = "imx28-gpmi-nand", + .driver_data = IS_MX28, + }, {}, +}; + static struct platform_driver gpmi_nand_driver = { .driver = { .name = "gpmi-nand", - .of_match_table = gpmi_nand_id_table, }, .probe = gpmi_nand_probe, .remove = __exit_p(gpmi_nand_remove), diff --git a/trunk/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/trunk/drivers/mtd/nand/gpmi-nand/gpmi-nand.h index ce5daa160920..ec6180d4ff8f 100644 --- a/trunk/drivers/mtd/nand/gpmi-nand/gpmi-nand.h +++ b/trunk/drivers/mtd/nand/gpmi-nand/gpmi-nand.h @@ -266,10 +266,8 @@ extern int gpmi_read_page(struct gpmi_nand_data *, #define STATUS_UNCORRECTABLE 0xfe /* Use the platform_id to distinguish different Archs. */ -#define IS_MX23 0x0 -#define IS_MX28 0x1 -#define IS_MX6Q 0x2 +#define IS_MX23 0x1 +#define IS_MX28 0x2 #define GPMI_IS_MX23(x) ((x)->pdev->id_entry->driver_data == IS_MX23) #define GPMI_IS_MX28(x) ((x)->pdev->id_entry->driver_data == IS_MX28) -#define GPMI_IS_MX6Q(x) ((x)->pdev->id_entry->driver_data == IS_MX6Q) #endif diff --git a/trunk/drivers/mtd/nand/h1910.c b/trunk/drivers/mtd/nand/h1910.c index 50166e93ba96..9bf5ce5fa22d 100644 --- a/trunk/drivers/mtd/nand/h1910.c +++ b/trunk/drivers/mtd/nand/h1910.c @@ -124,6 +124,7 @@ static int __init h1910_init(void) /* 15 us command delay time */ this->chip_delay = 50; this->ecc.mode = NAND_ECC_SOFT; + this->options = NAND_NO_AUTOINCR; /* Scan to find existence of the device */ if (nand_scan(h1910_nand_mtd, 1)) { diff --git a/trunk/drivers/mtd/nand/jz4740_nand.c b/trunk/drivers/mtd/nand/jz4740_nand.c index a6fa884ae49b..e4147e8acb7c 100644 --- a/trunk/drivers/mtd/nand/jz4740_nand.c +++ b/trunk/drivers/mtd/nand/jz4740_nand.c @@ -332,7 +332,11 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) chip->ecc.mode = NAND_ECC_HW_OOB_FIRST; chip->ecc.size = 512; chip->ecc.bytes = 9; - chip->ecc.strength = 4; + chip->ecc.strength = 2; + /* + * FIXME: ecc_strength value of 2 bits per 512 bytes of data is a + * conservative guess, given 9 ecc bytes and reed-solomon alg. + */ if (pdata) chip->ecc.layout = pdata->ecc_layout; diff --git a/trunk/drivers/mtd/nand/mpc5121_nfc.c b/trunk/drivers/mtd/nand/mpc5121_nfc.c index c259c24d7986..c240cf1af961 100644 --- a/trunk/drivers/mtd/nand/mpc5121_nfc.c +++ b/trunk/drivers/mtd/nand/mpc5121_nfc.c @@ -734,6 +734,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op) chip->write_buf = mpc5121_nfc_write_buf; chip->verify_buf = mpc5121_nfc_verify_buf; chip->select_chip = mpc5121_nfc_select_chip; + chip->options = NAND_NO_AUTOINCR; chip->bbt_options = NAND_BBT_USE_FLASH; chip->ecc.mode = NAND_ECC_SOFT; diff --git a/trunk/drivers/mtd/nand/mxc_nand.c b/trunk/drivers/mtd/nand/mxc_nand.c index c58e6a93f445..9e374e9bd296 100644 --- a/trunk/drivers/mtd/nand/mxc_nand.c +++ b/trunk/drivers/mtd/nand/mxc_nand.c @@ -32,8 +32,6 @@ #include #include #include -#include -#include #include #include @@ -142,47 +140,13 @@ #define NFC_V3_DELAY_LINE (host->regs_ip + 0x34) -struct mxc_nand_host; - -struct mxc_nand_devtype_data { - void (*preset)(struct mtd_info *); - void (*send_cmd)(struct mxc_nand_host *, uint16_t, int); - void (*send_addr)(struct mxc_nand_host *, uint16_t, int); - void (*send_page)(struct mtd_info *, unsigned int); - void (*send_read_id)(struct mxc_nand_host *); - uint16_t (*get_dev_status)(struct mxc_nand_host *); - int (*check_int)(struct mxc_nand_host *); - void (*irq_control)(struct mxc_nand_host *, int); - u32 (*get_ecc_status)(struct mxc_nand_host *); - struct nand_ecclayout *ecclayout_512, *ecclayout_2k, *ecclayout_4k; - void (*select_chip)(struct mtd_info *mtd, int chip); - int (*correct_data)(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc); - - /* - * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked - * (CONFIG1:INT_MSK is set). To handle this the driver uses - * enable_irq/disable_irq_nosync instead of CONFIG1:INT_MSK - */ - int irqpending_quirk; - int needs_ip; - - size_t regs_offset; - size_t spare0_offset; - size_t axi_offset; - - int spare_len; - int eccbytes; - int eccsize; -}; - struct mxc_nand_host { struct mtd_info mtd; struct nand_chip nand; struct device *dev; - void __iomem *spare0; - void __iomem *main_area0; + void *spare0; + void *main_area0; void __iomem *base; void __iomem *regs; @@ -199,9 +163,16 @@ struct mxc_nand_host { uint8_t *data_buf; unsigned int buf_start; - - const struct mxc_nand_devtype_data *devtype_data; - struct mxc_nand_platform_data pdata; + int spare_len; + + void (*preset)(struct mtd_info *); + void (*send_cmd)(struct mxc_nand_host *, uint16_t, int); + void (*send_addr)(struct mxc_nand_host *, uint16_t, int); + void (*send_page)(struct mtd_info *, unsigned int); + void (*send_read_id)(struct mxc_nand_host *); + uint16_t (*get_dev_status)(struct mxc_nand_host *); + int (*check_int)(struct mxc_nand_host *); + void (*irq_control)(struct mxc_nand_host *, int); }; /* OOB placement block for use with hardware ecc generation */ @@ -271,7 +242,21 @@ static struct nand_ecclayout nandv2_hw_eccoob_4k = { } }; -static const char *part_probes[] = { "RedBoot", "cmdlinepart", "ofpart", NULL }; +static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL }; + +static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) +{ + struct mxc_nand_host *host = dev_id; + + if (!host->check_int(host)) + return IRQ_NONE; + + host->irq_control(host, 0); + + complete(&host->op_completion); + + return IRQ_HANDLED; +} static int check_int_v3(struct mxc_nand_host *host) { @@ -295,12 +280,26 @@ static int check_int_v1_v2(struct mxc_nand_host *host) if (!(tmp & NFC_V1_V2_CONFIG2_INT)) return 0; - if (!host->devtype_data->irqpending_quirk) + if (!cpu_is_mx21()) writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2); return 1; } +/* + * It has been observed that the i.MX21 cannot read the CONFIG2:INT bit + * if interrupts are masked (CONFIG1:INT_MSK is set). To handle this, the + * driver can enable/disable the irq line rather than simply masking the + * interrupts. + */ +static void irq_control_mx21(struct mxc_nand_host *host, int activate) +{ + if (activate) + enable_irq(host->irq); + else + disable_irq_nosync(host->irq); +} + static void irq_control_v1_v2(struct mxc_nand_host *host, int activate) { uint16_t tmp; @@ -329,47 +328,6 @@ static void irq_control_v3(struct mxc_nand_host *host, int activate) writel(tmp, NFC_V3_CONFIG2); } -static void irq_control(struct mxc_nand_host *host, int activate) -{ - if (host->devtype_data->irqpending_quirk) { - if (activate) - enable_irq(host->irq); - else - disable_irq_nosync(host->irq); - } else { - host->devtype_data->irq_control(host, activate); - } -} - -static u32 get_ecc_status_v1(struct mxc_nand_host *host) -{ - return readw(NFC_V1_V2_ECC_STATUS_RESULT); -} - -static u32 get_ecc_status_v2(struct mxc_nand_host *host) -{ - return readl(NFC_V1_V2_ECC_STATUS_RESULT); -} - -static u32 get_ecc_status_v3(struct mxc_nand_host *host) -{ - return readl(NFC_V3_ECC_STATUS_RESULT); -} - -static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) -{ - struct mxc_nand_host *host = dev_id; - - if (!host->devtype_data->check_int(host)) - return IRQ_NONE; - - irq_control(host, 0); - - complete(&host->op_completion); - - return IRQ_HANDLED; -} - /* This function polls the NANDFC to wait for the basic operation to * complete by checking the INT bit of config2 register. */ @@ -378,14 +336,14 @@ static void wait_op_done(struct mxc_nand_host *host, int useirq) int max_retries = 8000; if (useirq) { - if (!host->devtype_data->check_int(host)) { + if (!host->check_int(host)) { INIT_COMPLETION(host->op_completion); - irq_control(host, 1); + host->irq_control(host, 1); wait_for_completion(&host->op_completion); } } else { while (max_retries-- > 0) { - if (host->devtype_data->check_int(host)) + if (host->check_int(host)) break; udelay(1); @@ -416,7 +374,7 @@ static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq) writew(cmd, NFC_V1_V2_FLASH_CMD); writew(NFC_CMD, NFC_V1_V2_CONFIG2); - if (host->devtype_data->irqpending_quirk && (cmd == NAND_CMD_RESET)) { + if (cpu_is_mx21() && (cmd == NAND_CMD_RESET)) { int max_retries = 100; /* Reset completion is indicated by NFC_CONFIG2 */ /* being set to 0 */ @@ -475,27 +433,13 @@ static void send_page_v3(struct mtd_info *mtd, unsigned int ops) wait_op_done(host, false); } -static void send_page_v2(struct mtd_info *mtd, unsigned int ops) -{ - struct nand_chip *nand_chip = mtd->priv; - struct mxc_nand_host *host = nand_chip->priv; - - /* NANDFC buffer 0 is used for page read/write */ - writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR); - - writew(ops, NFC_V1_V2_CONFIG2); - - /* Wait for operation to complete */ - wait_op_done(host, true); -} - -static void send_page_v1(struct mtd_info *mtd, unsigned int ops) +static void send_page_v1_v2(struct mtd_info *mtd, unsigned int ops) { struct nand_chip *nand_chip = mtd->priv; struct mxc_nand_host *host = nand_chip->priv; int bufs, i; - if (mtd->writesize > 512) + if (nfc_is_v1() && mtd->writesize > 512) bufs = 4; else bufs = 1; @@ -519,7 +463,7 @@ static void send_read_id_v3(struct mxc_nand_host *host) wait_op_done(host, true); - memcpy_fromio(host->data_buf, host->main_area0, 16); + memcpy(host->data_buf, host->main_area0, 16); } /* Request the NANDFC to perform a read of the NAND device ID. */ @@ -535,7 +479,7 @@ static void send_read_id_v1_v2(struct mxc_nand_host *host) /* Wait for operation to complete */ wait_op_done(host, true); - memcpy_fromio(host->data_buf, host->main_area0, 16); + memcpy(host->data_buf, host->main_area0, 16); if (this->options & NAND_BUSWIDTH_16) { /* compress the ID info */ @@ -611,7 +555,7 @@ static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat, * additional correction. 2-Bit errors cannot be corrected by * HW ECC, so we need to return failure */ - uint16_t ecc_status = get_ecc_status_v1(host); + uint16_t ecc_status = readw(NFC_V1_V2_ECC_STATUS_RESULT); if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { pr_debug("MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); @@ -636,7 +580,10 @@ static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat, no_subpages = mtd->writesize >> 9; - ecc_stat = host->devtype_data->get_ecc_status(host); + if (nfc_is_v21()) + ecc_stat = readl(NFC_V1_V2_ECC_STATUS_RESULT); + else + ecc_stat = readl(NFC_V3_ECC_STATUS_RESULT); do { err = ecc_stat & ecc_bit_mask; @@ -669,7 +616,7 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd) /* Check for status request */ if (host->status_request) - return host->devtype_data->get_dev_status(host) & 0xFF; + return host->get_dev_status(host) & 0xFF; ret = *(uint8_t *)(host->data_buf + host->buf_start); host->buf_start++; @@ -735,7 +682,7 @@ static int mxc_nand_verify_buf(struct mtd_info *mtd, /* This function is used by upper layer for select and * deselect of the NAND chip */ -static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip) +static void mxc_nand_select_chip(struct mtd_info *mtd, int chip) { struct nand_chip *nand_chip = mtd->priv; struct mxc_nand_host *host = nand_chip->priv; @@ -754,30 +701,11 @@ static void mxc_nand_select_chip_v1_v3(struct mtd_info *mtd, int chip) clk_prepare_enable(host->clk); host->clk_act = 1; } -} -static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip) -{ - struct nand_chip *nand_chip = mtd->priv; - struct mxc_nand_host *host = nand_chip->priv; - - if (chip == -1) { - /* Disable the NFC clock */ - if (host->clk_act) { - clk_disable(host->clk); - host->clk_act = 0; - } - return; - } - - if (!host->clk_act) { - /* Enable the NFC clock */ - clk_enable(host->clk); - host->clk_act = 1; + if (nfc_is_v21()) { + host->active_cs = chip; + writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR); } - - host->active_cs = chip; - writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR); } /* @@ -790,23 +718,23 @@ static void copy_spare(struct mtd_info *mtd, bool bfrom) u16 i, j; u16 n = mtd->writesize >> 9; u8 *d = host->data_buf + mtd->writesize; - u8 __iomem *s = host->spare0; - u16 t = host->devtype_data->spare_len; + u8 *s = host->spare0; + u16 t = host->spare_len; j = (mtd->oobsize / n >> 1) << 1; if (bfrom) { for (i = 0; i < n - 1; i++) - memcpy_fromio(d + i * j, s + i * t, j); + memcpy(d + i * j, s + i * t, j); /* the last section */ - memcpy_fromio(d + i * j, s + i * t, mtd->oobsize - i * j); + memcpy(d + i * j, s + i * t, mtd->oobsize - i * j); } else { for (i = 0; i < n - 1; i++) - memcpy_toio(&s[i * t], &d[i * j], j); + memcpy(&s[i * t], &d[i * j], j); /* the last section */ - memcpy_toio(&s[i * t], &d[i * j], mtd->oobsize - i * j); + memcpy(&s[i * t], &d[i * j], mtd->oobsize - i * j); } } @@ -823,44 +751,34 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) * perform a read/write buf operation, the saved column * address is used to index into the full page. */ - host->devtype_data->send_addr(host, 0, page_addr == -1); + host->send_addr(host, 0, page_addr == -1); if (mtd->writesize > 512) /* another col addr cycle for 2k page */ - host->devtype_data->send_addr(host, 0, false); + host->send_addr(host, 0, false); } /* Write out page address, if necessary */ if (page_addr != -1) { /* paddr_0 - p_addr_7 */ - host->devtype_data->send_addr(host, (page_addr & 0xff), false); + host->send_addr(host, (page_addr & 0xff), false); if (mtd->writesize > 512) { if (mtd->size >= 0x10000000) { /* paddr_8 - paddr_15 */ - host->devtype_data->send_addr(host, - (page_addr >> 8) & 0xff, - false); - host->devtype_data->send_addr(host, - (page_addr >> 16) & 0xff, - true); + host->send_addr(host, (page_addr >> 8) & 0xff, false); + host->send_addr(host, (page_addr >> 16) & 0xff, true); } else /* paddr_8 - paddr_15 */ - host->devtype_data->send_addr(host, - (page_addr >> 8) & 0xff, true); + host->send_addr(host, (page_addr >> 8) & 0xff, true); } else { /* One more address cycle for higher density devices */ if (mtd->size >= 0x4000000) { /* paddr_8 - paddr_15 */ - host->devtype_data->send_addr(host, - (page_addr >> 8) & 0xff, - false); - host->devtype_data->send_addr(host, - (page_addr >> 16) & 0xff, - true); + host->send_addr(host, (page_addr >> 8) & 0xff, false); + host->send_addr(host, (page_addr >> 16) & 0xff, true); } else /* paddr_8 - paddr_15 */ - host->devtype_data->send_addr(host, - (page_addr >> 8) & 0xff, true); + host->send_addr(host, (page_addr >> 8) & 0xff, true); } } } @@ -882,35 +800,7 @@ static int get_eccsize(struct mtd_info *mtd) return 8; } -static void preset_v1(struct mtd_info *mtd) -{ - struct nand_chip *nand_chip = mtd->priv; - struct mxc_nand_host *host = nand_chip->priv; - uint16_t config1 = 0; - - if (nand_chip->ecc.mode == NAND_ECC_HW) - config1 |= NFC_V1_V2_CONFIG1_ECC_EN; - - if (!host->devtype_data->irqpending_quirk) - config1 |= NFC_V1_V2_CONFIG1_INT_MSK; - - host->eccsize = 1; - - writew(config1, NFC_V1_V2_CONFIG1); - /* preset operation */ - - /* Unlock the internal RAM Buffer */ - writew(0x2, NFC_V1_V2_CONFIG); - - /* Blocks to be unlocked */ - writew(0x0, NFC_V1_UNLOCKSTART_BLKADDR); - writew(0xffff, NFC_V1_UNLOCKEND_BLKADDR); - - /* Unlock Block Command for given address range */ - writew(0x4, NFC_V1_V2_WRPROT); -} - -static void preset_v2(struct mtd_info *mtd) +static void preset_v1_v2(struct mtd_info *mtd) { struct nand_chip *nand_chip = mtd->priv; struct mxc_nand_host *host = nand_chip->priv; @@ -919,12 +809,13 @@ static void preset_v2(struct mtd_info *mtd) if (nand_chip->ecc.mode == NAND_ECC_HW) config1 |= NFC_V1_V2_CONFIG1_ECC_EN; - config1 |= NFC_V2_CONFIG1_FP_INT; + if (nfc_is_v21()) + config1 |= NFC_V2_CONFIG1_FP_INT; - if (!host->devtype_data->irqpending_quirk) + if (!cpu_is_mx21()) config1 |= NFC_V1_V2_CONFIG1_INT_MSK; - if (mtd->writesize) { + if (nfc_is_v21() && mtd->writesize) { uint16_t pages_per_block = mtd->erasesize / mtd->writesize; host->eccsize = get_eccsize(mtd); @@ -943,14 +834,20 @@ static void preset_v2(struct mtd_info *mtd) writew(0x2, NFC_V1_V2_CONFIG); /* Blocks to be unlocked */ - writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR0); - writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR1); - writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR2); - writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR3); - writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR0); - writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR1); - writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR2); - writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR3); + if (nfc_is_v21()) { + writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR0); + writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR1); + writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR2); + writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR3); + writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR0); + writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR1); + writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR2); + writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR3); + } else if (nfc_is_v1()) { + writew(0x0, NFC_V1_UNLOCKSTART_BLKADDR); + writew(0xffff, NFC_V1_UNLOCKEND_BLKADDR); + } else + BUG(); /* Unlock Block Command for given address range */ writew(0x4, NFC_V1_V2_WRPROT); @@ -1040,15 +937,15 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, /* Command pre-processing step */ switch (command) { case NAND_CMD_RESET: - host->devtype_data->preset(mtd); - host->devtype_data->send_cmd(host, command, false); + host->preset(mtd); + host->send_cmd(host, command, false); break; case NAND_CMD_STATUS: host->buf_start = 0; host->status_request = true; - host->devtype_data->send_cmd(host, command, true); + host->send_cmd(host, command, true); mxc_do_addr_cycle(mtd, column, page_addr); break; @@ -1061,16 +958,15 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, command = NAND_CMD_READ0; /* only READ0 is valid */ - host->devtype_data->send_cmd(host, command, false); + host->send_cmd(host, command, false); mxc_do_addr_cycle(mtd, column, page_addr); if (mtd->writesize > 512) - host->devtype_data->send_cmd(host, - NAND_CMD_READSTART, true); + host->send_cmd(host, NAND_CMD_READSTART, true); - host->devtype_data->send_page(mtd, NFC_OUTPUT); + host->send_page(mtd, NFC_OUTPUT); - memcpy_fromio(host->data_buf, host->main_area0, mtd->writesize); + memcpy(host->data_buf, host->main_area0, mtd->writesize); copy_spare(mtd, true); break; @@ -1081,28 +977,28 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, host->buf_start = column; - host->devtype_data->send_cmd(host, command, false); + host->send_cmd(host, command, false); mxc_do_addr_cycle(mtd, column, page_addr); break; case NAND_CMD_PAGEPROG: - memcpy_toio(host->main_area0, host->data_buf, mtd->writesize); + memcpy(host->main_area0, host->data_buf, mtd->writesize); copy_spare(mtd, false); - host->devtype_data->send_page(mtd, NFC_INPUT); - host->devtype_data->send_cmd(host, command, true); + host->send_page(mtd, NFC_INPUT); + host->send_cmd(host, command, true); mxc_do_addr_cycle(mtd, column, page_addr); break; case NAND_CMD_READID: - host->devtype_data->send_cmd(host, command, true); + host->send_cmd(host, command, true); mxc_do_addr_cycle(mtd, column, page_addr); - host->devtype_data->send_read_id(host); + host->send_read_id(host); host->buf_start = column; break; case NAND_CMD_ERASE1: case NAND_CMD_ERASE2: - host->devtype_data->send_cmd(host, command, false); + host->send_cmd(host, command, false); mxc_do_addr_cycle(mtd, column, page_addr); break; @@ -1136,191 +1032,15 @@ static struct nand_bbt_descr bbt_mirror_descr = { .pattern = mirror_pattern, }; -/* v1 + irqpending_quirk: i.MX21 */ -static const struct mxc_nand_devtype_data imx21_nand_devtype_data = { - .preset = preset_v1, - .send_cmd = send_cmd_v1_v2, - .send_addr = send_addr_v1_v2, - .send_page = send_page_v1, - .send_read_id = send_read_id_v1_v2, - .get_dev_status = get_dev_status_v1_v2, - .check_int = check_int_v1_v2, - .irq_control = irq_control_v1_v2, - .get_ecc_status = get_ecc_status_v1, - .ecclayout_512 = &nandv1_hw_eccoob_smallpage, - .ecclayout_2k = &nandv1_hw_eccoob_largepage, - .ecclayout_4k = &nandv1_hw_eccoob_smallpage, /* XXX: needs fix */ - .select_chip = mxc_nand_select_chip_v1_v3, - .correct_data = mxc_nand_correct_data_v1, - .irqpending_quirk = 1, - .needs_ip = 0, - .regs_offset = 0xe00, - .spare0_offset = 0x800, - .spare_len = 16, - .eccbytes = 3, - .eccsize = 1, -}; - -/* v1 + !irqpending_quirk: i.MX27, i.MX31 */ -static const struct mxc_nand_devtype_data imx27_nand_devtype_data = { - .preset = preset_v1, - .send_cmd = send_cmd_v1_v2, - .send_addr = send_addr_v1_v2, - .send_page = send_page_v1, - .send_read_id = send_read_id_v1_v2, - .get_dev_status = get_dev_status_v1_v2, - .check_int = check_int_v1_v2, - .irq_control = irq_control_v1_v2, - .get_ecc_status = get_ecc_status_v1, - .ecclayout_512 = &nandv1_hw_eccoob_smallpage, - .ecclayout_2k = &nandv1_hw_eccoob_largepage, - .ecclayout_4k = &nandv1_hw_eccoob_smallpage, /* XXX: needs fix */ - .select_chip = mxc_nand_select_chip_v1_v3, - .correct_data = mxc_nand_correct_data_v1, - .irqpending_quirk = 0, - .needs_ip = 0, - .regs_offset = 0xe00, - .spare0_offset = 0x800, - .axi_offset = 0, - .spare_len = 16, - .eccbytes = 3, - .eccsize = 1, -}; - -/* v21: i.MX25, i.MX35 */ -static const struct mxc_nand_devtype_data imx25_nand_devtype_data = { - .preset = preset_v2, - .send_cmd = send_cmd_v1_v2, - .send_addr = send_addr_v1_v2, - .send_page = send_page_v2, - .send_read_id = send_read_id_v1_v2, - .get_dev_status = get_dev_status_v1_v2, - .check_int = check_int_v1_v2, - .irq_control = irq_control_v1_v2, - .get_ecc_status = get_ecc_status_v2, - .ecclayout_512 = &nandv2_hw_eccoob_smallpage, - .ecclayout_2k = &nandv2_hw_eccoob_largepage, - .ecclayout_4k = &nandv2_hw_eccoob_4k, - .select_chip = mxc_nand_select_chip_v2, - .correct_data = mxc_nand_correct_data_v2_v3, - .irqpending_quirk = 0, - .needs_ip = 0, - .regs_offset = 0x1e00, - .spare0_offset = 0x1000, - .axi_offset = 0, - .spare_len = 64, - .eccbytes = 9, - .eccsize = 0, -}; - -/* v3: i.MX51, i.MX53 */ -static const struct mxc_nand_devtype_data imx51_nand_devtype_data = { - .preset = preset_v3, - .send_cmd = send_cmd_v3, - .send_addr = send_addr_v3, - .send_page = send_page_v3, - .send_read_id = send_read_id_v3, - .get_dev_status = get_dev_status_v3, - .check_int = check_int_v3, - .irq_control = irq_control_v3, - .get_ecc_status = get_ecc_status_v3, - .ecclayout_512 = &nandv2_hw_eccoob_smallpage, - .ecclayout_2k = &nandv2_hw_eccoob_largepage, - .ecclayout_4k = &nandv2_hw_eccoob_smallpage, /* XXX: needs fix */ - .select_chip = mxc_nand_select_chip_v1_v3, - .correct_data = mxc_nand_correct_data_v2_v3, - .irqpending_quirk = 0, - .needs_ip = 1, - .regs_offset = 0, - .spare0_offset = 0x1000, - .axi_offset = 0x1e00, - .spare_len = 64, - .eccbytes = 0, - .eccsize = 0, -}; - -#ifdef CONFIG_OF_MTD -static const struct of_device_id mxcnd_dt_ids[] = { - { - .compatible = "fsl,imx21-nand", - .data = &imx21_nand_devtype_data, - }, { - .compatible = "fsl,imx27-nand", - .data = &imx27_nand_devtype_data, - }, { - .compatible = "fsl,imx25-nand", - .data = &imx25_nand_devtype_data, - }, { - .compatible = "fsl,imx51-nand", - .data = &imx51_nand_devtype_data, - }, - { /* sentinel */ } -}; - -static int __init mxcnd_probe_dt(struct mxc_nand_host *host) -{ - struct device_node *np = host->dev->of_node; - struct mxc_nand_platform_data *pdata = &host->pdata; - const struct of_device_id *of_id = - of_match_device(mxcnd_dt_ids, host->dev); - int buswidth; - - if (!np) - return 1; - - if (of_get_nand_ecc_mode(np) >= 0) - pdata->hw_ecc = 1; - - pdata->flash_bbt = of_get_nand_on_flash_bbt(np); - - buswidth = of_get_nand_bus_width(np); - if (buswidth < 0) - return buswidth; - - pdata->width = buswidth / 8; - - host->devtype_data = of_id->data; - - return 0; -} -#else -static int __init mxcnd_probe_dt(struct mxc_nand_host *host) -{ - return 1; -} -#endif - -static int __init mxcnd_probe_pdata(struct mxc_nand_host *host) -{ - struct mxc_nand_platform_data *pdata = host->dev->platform_data; - - if (!pdata) - return -ENODEV; - - host->pdata = *pdata; - - if (nfc_is_v1()) { - if (cpu_is_mx21()) - host->devtype_data = &imx21_nand_devtype_data; - else - host->devtype_data = &imx27_nand_devtype_data; - } else if (nfc_is_v21()) { - host->devtype_data = &imx25_nand_devtype_data; - } else if (nfc_is_v3_2()) { - host->devtype_data = &imx51_nand_devtype_data; - } else - BUG(); - - return 0; -} - static int __init mxcnd_probe(struct platform_device *pdev) { struct nand_chip *this; struct mtd_info *mtd; + struct mxc_nand_platform_data *pdata = pdev->dev.platform_data; struct mxc_nand_host *host; struct resource *res; int err = 0; + struct nand_ecclayout *oob_smallpage, *oob_largepage; /* Allocate memory for MTD device structure and private data */ host = kzalloc(sizeof(struct mxc_nand_host) + NAND_MAX_PAGESIZE + @@ -1345,6 +1065,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) this->priv = host; this->dev_ready = mxc_nand_dev_ready; this->cmdfunc = mxc_nand_command; + this->select_chip = mxc_nand_select_chip; this->read_byte = mxc_nand_read_byte; this->read_word = mxc_nand_read_word; this->write_buf = mxc_nand_write_buf; @@ -1374,26 +1095,36 @@ static int __init mxcnd_probe(struct platform_device *pdev) host->main_area0 = host->base; - err = mxcnd_probe_dt(host); - if (err > 0) - err = mxcnd_probe_pdata(host); - if (err < 0) - goto eirq; - - if (host->devtype_data->regs_offset) - host->regs = host->base + host->devtype_data->regs_offset; - host->spare0 = host->base + host->devtype_data->spare0_offset; - if (host->devtype_data->axi_offset) - host->regs_axi = host->base + host->devtype_data->axi_offset; - - this->ecc.bytes = host->devtype_data->eccbytes; - host->eccsize = host->devtype_data->eccsize; - - this->select_chip = host->devtype_data->select_chip; - this->ecc.size = 512; - this->ecc.layout = host->devtype_data->ecclayout_512; + if (nfc_is_v1() || nfc_is_v21()) { + host->preset = preset_v1_v2; + host->send_cmd = send_cmd_v1_v2; + host->send_addr = send_addr_v1_v2; + host->send_page = send_page_v1_v2; + host->send_read_id = send_read_id_v1_v2; + host->get_dev_status = get_dev_status_v1_v2; + host->check_int = check_int_v1_v2; + if (cpu_is_mx21()) + host->irq_control = irq_control_mx21; + else + host->irq_control = irq_control_v1_v2; + } - if (host->devtype_data->needs_ip) { + if (nfc_is_v21()) { + host->regs = host->base + 0x1e00; + host->spare0 = host->base + 0x1000; + host->spare_len = 64; + oob_smallpage = &nandv2_hw_eccoob_smallpage; + oob_largepage = &nandv2_hw_eccoob_largepage; + this->ecc.bytes = 9; + } else if (nfc_is_v1()) { + host->regs = host->base + 0xe00; + host->spare0 = host->base + 0x800; + host->spare_len = 16; + oob_smallpage = &nandv1_hw_eccoob_smallpage; + oob_largepage = &nandv1_hw_eccoob_largepage; + this->ecc.bytes = 3; + host->eccsize = 1; + } else if (nfc_is_v3_2()) { res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!res) { err = -ENODEV; @@ -1404,22 +1135,42 @@ static int __init mxcnd_probe(struct platform_device *pdev) err = -ENOMEM; goto eirq; } - } + host->regs_axi = host->base + 0x1e00; + host->spare0 = host->base + 0x1000; + host->spare_len = 64; + host->preset = preset_v3; + host->send_cmd = send_cmd_v3; + host->send_addr = send_addr_v3; + host->send_page = send_page_v3; + host->send_read_id = send_read_id_v3; + host->check_int = check_int_v3; + host->get_dev_status = get_dev_status_v3; + host->irq_control = irq_control_v3; + oob_smallpage = &nandv2_hw_eccoob_smallpage; + oob_largepage = &nandv2_hw_eccoob_largepage; + } else + BUG(); + + this->ecc.size = 512; + this->ecc.layout = oob_smallpage; - if (host->pdata.hw_ecc) { + if (pdata->hw_ecc) { this->ecc.calculate = mxc_nand_calculate_ecc; this->ecc.hwctl = mxc_nand_enable_hwecc; - this->ecc.correct = host->devtype_data->correct_data; + if (nfc_is_v1()) + this->ecc.correct = mxc_nand_correct_data_v1; + else + this->ecc.correct = mxc_nand_correct_data_v2_v3; this->ecc.mode = NAND_ECC_HW; } else { this->ecc.mode = NAND_ECC_SOFT; } - /* NAND bus width determines access functions used by upper layer */ - if (host->pdata.width == 2) + /* NAND bus width determines access funtions used by upper layer */ + if (pdata->width == 2) this->options |= NAND_BUSWIDTH_16; - if (host->pdata.flash_bbt) { + if (pdata->flash_bbt) { this->bbt_td = &bbt_main_descr; this->bbt_md = &bbt_mirror_descr; /* update flash based bbt */ @@ -1431,25 +1182,28 @@ static int __init mxcnd_probe(struct platform_device *pdev) host->irq = platform_get_irq(pdev, 0); /* - * Use host->devtype_data->irq_control() here instead of irq_control() - * because we must not disable_irq_nosync without having requested the - * irq. + * mask the interrupt. For i.MX21 explicitely call + * irq_control_v1_v2 to use the mask bit. We can't call + * disable_irq_nosync() for an interrupt we do not own yet. */ - host->devtype_data->irq_control(host, 0); + if (cpu_is_mx21()) + irq_control_v1_v2(host, 0); + else + host->irq_control(host, 0); err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host); if (err) goto eirq; + host->irq_control(host, 0); + /* - * Now that we "own" the interrupt make sure the interrupt mask bit is - * cleared on i.MX21. Otherwise we can't read the interrupt status bit - * on this machine. + * Now that the interrupt is disabled make sure the interrupt + * mask bit is cleared on i.MX21. Otherwise we can't read + * the interrupt status bit on this machine. */ - if (host->devtype_data->irqpending_quirk) { - disable_irq_nosync(host->irq); - host->devtype_data->irq_control(host, 1); - } + if (cpu_is_mx21()) + irq_control_v1_v2(host, 1); /* first scan to find the device and get the page size */ if (nand_scan_ident(mtd, nfc_is_v21() ? 4 : 1, NULL)) { @@ -1458,12 +1212,18 @@ static int __init mxcnd_probe(struct platform_device *pdev) } /* Call preset again, with correct writesize this time */ - host->devtype_data->preset(mtd); + host->preset(mtd); if (mtd->writesize == 2048) - this->ecc.layout = host->devtype_data->ecclayout_2k; - else if (mtd->writesize == 4096) - this->ecc.layout = host->devtype_data->ecclayout_4k; + this->ecc.layout = oob_largepage; + if (nfc_is_v21() && mtd->writesize == 4096) + this->ecc.layout = &nandv2_hw_eccoob_4k; + + /* second phase scan */ + if (nand_scan_tail(mtd)) { + err = -ENXIO; + goto escan; + } if (this->ecc.mode == NAND_ECC_HW) { if (nfc_is_v1()) @@ -1472,19 +1232,9 @@ static int __init mxcnd_probe(struct platform_device *pdev) this->ecc.strength = (host->eccsize == 4) ? 4 : 8; } - /* second phase scan */ - if (nand_scan_tail(mtd)) { - err = -ENXIO; - goto escan; - } - /* Register the partitions */ - mtd_device_parse_register(mtd, part_probes, - &(struct mtd_part_parser_data){ - .of_node = pdev->dev.of_node, - }, - host->pdata.parts, - host->pdata.nr_parts); + mtd_device_parse_register(mtd, part_probes, NULL, pdata->parts, + pdata->nr_parts); platform_set_drvdata(pdev, host); @@ -1525,8 +1275,6 @@ static int __devexit mxcnd_remove(struct platform_device *pdev) static struct platform_driver mxcnd_driver = { .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(mxcnd_dt_ids), }, .remove = __devexit_p(mxcnd_remove), }; diff --git a/trunk/drivers/mtd/nand/nand_base.c b/trunk/drivers/mtd/nand/nand_base.c index d47586cf64ce..47b19c0bb070 100644 --- a/trunk/drivers/mtd/nand/nand_base.c +++ b/trunk/drivers/mtd/nand/nand_base.c @@ -1066,17 +1066,15 @@ EXPORT_SYMBOL(nand_lock); * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data - * @oob_required: caller requires OOB data read to chip->oob_poi * @page: page number to read * * Not for syndrome calculating ECC controllers, which use a special oob layout. */ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) + uint8_t *buf, int page) { chip->read_buf(mtd, buf, mtd->writesize); - if (oob_required) - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); return 0; } @@ -1085,14 +1083,13 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data - * @oob_required: caller requires OOB data read to chip->oob_poi * @page: page number to read * * We need a special oob layout and handling even when OOB isn't used. */ static int nand_read_page_raw_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, - int oob_required, int page) + struct nand_chip *chip, + uint8_t *buf, int page) { int eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -1129,11 +1126,10 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd, * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data - * @oob_required: caller requires OOB data read to chip->oob_poi * @page: page number to read */ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) + uint8_t *buf, int page) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -1142,9 +1138,8 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *ecc_calc = chip->buffers->ecccalc; uint8_t *ecc_code = chip->buffers->ecccode; uint32_t *eccpos = chip->ecc.layout->eccpos; - unsigned int max_bitflips = 0; - chip->ecc.read_page_raw(mtd, chip, buf, 1, page); + chip->ecc.read_page_raw(mtd, chip, buf, page); for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) chip->ecc.calculate(mtd, p, &ecc_calc[i]); @@ -1159,14 +1154,12 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, int stat; stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); - if (stat < 0) { + if (stat < 0) mtd->ecc_stats.failed++; - } else { + else mtd->ecc_stats.corrected += stat; - max_bitflips = max_t(unsigned int, max_bitflips, stat); - } } - return max_bitflips; + return 0; } /** @@ -1187,7 +1180,6 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, int datafrag_len, eccfrag_len, aligned_len, aligned_pos; int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; int index = 0; - unsigned int max_bitflips = 0; /* Column address within the page aligned to ECC size (256bytes) */ start_step = data_offs / chip->ecc.size; @@ -1252,14 +1244,12 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, stat = chip->ecc.correct(mtd, p, &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]); - if (stat < 0) { + if (stat < 0) mtd->ecc_stats.failed++; - } else { + else mtd->ecc_stats.corrected += stat; - max_bitflips = max_t(unsigned int, max_bitflips, stat); - } } - return max_bitflips; + return 0; } /** @@ -1267,13 +1257,12 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data - * @oob_required: caller requires OOB data read to chip->oob_poi * @page: page number to read * * Not for syndrome calculating ECC controllers which need a special oob layout. */ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) + uint8_t *buf, int page) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -1282,7 +1271,6 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *ecc_calc = chip->buffers->ecccalc; uint8_t *ecc_code = chip->buffers->ecccode; uint32_t *eccpos = chip->ecc.layout->eccpos; - unsigned int max_bitflips = 0; for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { chip->ecc.hwctl(mtd, NAND_ECC_READ); @@ -1301,14 +1289,12 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, int stat; stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); - if (stat < 0) { + if (stat < 0) mtd->ecc_stats.failed++; - } else { + else mtd->ecc_stats.corrected += stat; - max_bitflips = max_t(unsigned int, max_bitflips, stat); - } } - return max_bitflips; + return 0; } /** @@ -1316,7 +1302,6 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data - * @oob_required: caller requires OOB data read to chip->oob_poi * @page: page number to read * * Hardware ECC for large page chips, require OOB to be read first. For this @@ -1326,7 +1311,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, * the data area, by overwriting the NAND manufacturer bad block markings. */ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, int page) + struct nand_chip *chip, uint8_t *buf, int page) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -1335,7 +1320,6 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, uint8_t *ecc_code = chip->buffers->ecccode; uint32_t *eccpos = chip->ecc.layout->eccpos; uint8_t *ecc_calc = chip->buffers->ecccalc; - unsigned int max_bitflips = 0; /* Read the OOB area first */ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); @@ -1353,14 +1337,12 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, chip->ecc.calculate(mtd, p, &ecc_calc[i]); stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL); - if (stat < 0) { + if (stat < 0) mtd->ecc_stats.failed++; - } else { + else mtd->ecc_stats.corrected += stat; - max_bitflips = max_t(unsigned int, max_bitflips, stat); - } } - return max_bitflips; + return 0; } /** @@ -1368,21 +1350,19 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data - * @oob_required: caller requires OOB data read to chip->oob_poi * @page: page number to read * * The hw generator calculates the error syndrome automatically. Therefore we * need a special oob layout and handling. */ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) + uint8_t *buf, int page) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; uint8_t *p = buf; uint8_t *oob = chip->oob_poi; - unsigned int max_bitflips = 0; for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { int stat; @@ -1399,12 +1379,10 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, chip->read_buf(mtd, oob, eccbytes); stat = chip->ecc.correct(mtd, p, oob, NULL); - if (stat < 0) { + if (stat < 0) mtd->ecc_stats.failed++; - } else { + else mtd->ecc_stats.corrected += stat; - max_bitflips = max_t(unsigned int, max_bitflips, stat); - } oob += eccbytes; @@ -1419,7 +1397,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, if (i) chip->read_buf(mtd, oob, i); - return max_bitflips; + return 0; } /** @@ -1481,9 +1459,11 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { - int chipnr, page, realpage, col, bytes, aligned, oob_required; + int chipnr, page, realpage, col, bytes, aligned; struct nand_chip *chip = mtd->priv; struct mtd_ecc_stats stats; + int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; + int sndcmd = 1; int ret = 0; uint32_t readlen = ops->len; uint32_t oobreadlen = ops->ooblen; @@ -1491,7 +1471,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, mtd->oobavail : mtd->oobsize; uint8_t *bufpoi, *oob, *buf; - unsigned int max_bitflips = 0; stats = mtd->ecc_stats; @@ -1505,7 +1484,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, buf = ops->datbuf; oob = ops->oobbuf; - oob_required = oob ? 1 : 0; while (1) { bytes = min(mtd->writesize - col, readlen); @@ -1515,22 +1493,21 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, if (realpage != chip->pagebuf || oob) { bufpoi = aligned ? buf : chip->buffers->databuf; - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); + if (likely(sndcmd)) { + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); + sndcmd = 0; + } - /* - * Now read the page into the buffer. Absent an error, - * the read methods return max bitflips per ecc step. - */ + /* Now read the page into the buffer */ if (unlikely(ops->mode == MTD_OPS_RAW)) - ret = chip->ecc.read_page_raw(mtd, chip, bufpoi, - oob_required, - page); + ret = chip->ecc.read_page_raw(mtd, chip, + bufpoi, page); else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi); else ret = chip->ecc.read_page(mtd, chip, bufpoi, - oob_required, page); + page); if (ret < 0) { if (!aligned) /* Invalidate page cache */ @@ -1538,25 +1515,22 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, break; } - max_bitflips = max_t(unsigned int, max_bitflips, ret); - /* Transfer not aligned data */ if (!aligned) { if (!NAND_SUBPAGE_READ(chip) && !oob && !(mtd->ecc_stats.failed - stats.failed) && - (ops->mode != MTD_OPS_RAW)) { + (ops->mode != MTD_OPS_RAW)) chip->pagebuf = realpage; - chip->pagebuf_bitflips = ret; - } else { + else /* Invalidate page cache */ chip->pagebuf = -1; - } memcpy(buf, chip->buffers->databuf + col, bytes); } buf += bytes; if (unlikely(oob)) { + int toread = min(oobreadlen, max_oobsize); if (toread) { @@ -1567,7 +1541,13 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, } if (!(chip->options & NAND_NO_READRDY)) { - /* 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 (!chip->dev_ready) udelay(chip->chip_delay); else @@ -1576,8 +1556,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, } else { memcpy(buf, chip->buffers->databuf + col, bytes); buf += bytes; - max_bitflips = max_t(unsigned int, max_bitflips, - chip->pagebuf_bitflips); } readlen -= bytes; @@ -1597,19 +1575,26 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, chip->select_chip(mtd, -1); chip->select_chip(mtd, chipnr); } + + /* + * Check, if the chip supports auto page increment or if we + * have hit a block boundary. + */ + if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck)) + sndcmd = 1; } ops->retlen = ops->len - (size_t) readlen; if (oob) ops->oobretlen = ops->ooblen - oobreadlen; - if (ret < 0) + if (ret) return ret; if (mtd->ecc_stats.failed - stats.failed) return -EBADMSG; - return max_bitflips; + return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; } /** @@ -1645,13 +1630,17 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, * @mtd: mtd info structure * @chip: nand chip info structure * @page: page number to read + * @sndcmd: flag whether to issue read command or not */ static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, - int page) + int page, int sndcmd) { - chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + if (sndcmd) { + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + sndcmd = 0; + } chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - return 0; + return sndcmd; } /** @@ -1660,9 +1649,10 @@ static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, * @mtd: mtd info structure * @chip: nand chip info structure * @page: page number to read + * @sndcmd: flag whether to issue read command or not */ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - int page) + int page, int sndcmd) { uint8_t *buf = chip->oob_poi; int length = mtd->oobsize; @@ -1689,7 +1679,7 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, if (length > 0) chip->read_buf(mtd, bufpoi, length); - return 0; + return 1; } /** @@ -1785,13 +1775,13 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd, static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { - int page, realpage, chipnr; + int page, realpage, chipnr, sndcmd = 1; struct nand_chip *chip = mtd->priv; struct mtd_ecc_stats stats; + int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; int readlen = ops->ooblen; int len; uint8_t *buf = ops->oobbuf; - int ret = 0; pr_debug("%s: from = 0x%08Lx, len = %i\n", __func__, (unsigned long long)from, readlen); @@ -1827,18 +1817,20 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, while (1) { if (ops->mode == MTD_OPS_RAW) - ret = chip->ecc.read_oob_raw(mtd, chip, page); + sndcmd = chip->ecc.read_oob_raw(mtd, chip, page, sndcmd); else - ret = chip->ecc.read_oob(mtd, chip, page); - - if (ret < 0) - break; + sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); len = min(len, readlen); buf = nand_transfer_oob(chip, buf, ops, len); if (!(chip->options & NAND_NO_READRDY)) { - /* 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 (!chip->dev_ready) udelay(chip->chip_delay); else @@ -1859,12 +1851,16 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, chip->select_chip(mtd, -1); chip->select_chip(mtd, chipnr); } - } - ops->oobretlen = ops->ooblen - readlen; + /* + * Check, if the chip supports auto page increment or if we + * have hit a block boundary. + */ + if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck)) + sndcmd = 1; + } - if (ret < 0) - return ret; + ops->oobretlen = ops->ooblen; if (mtd->ecc_stats.failed - stats.failed) return -EBADMSG; @@ -1923,16 +1919,14 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer - * @oob_required: must write chip->oob_poi to OOB * * Not for syndrome calculating ECC controllers, which use a special oob layout. */ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf) { chip->write_buf(mtd, buf, mtd->writesize); - if (oob_required) - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); } /** @@ -1940,13 +1934,12 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer - * @oob_required: must write chip->oob_poi to OOB * * We need a special oob layout and handling even when ECC isn't checked. */ static void nand_write_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf) { int eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -1980,10 +1973,9 @@ static void nand_write_page_raw_syndrome(struct mtd_info *mtd, * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer - * @oob_required: must write chip->oob_poi to OOB */ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -1999,7 +1991,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, for (i = 0; i < chip->ecc.total; i++) chip->oob_poi[eccpos[i]] = ecc_calc[i]; - chip->ecc.write_page_raw(mtd, chip, buf, 1); + chip->ecc.write_page_raw(mtd, chip, buf); } /** @@ -2007,10 +1999,9 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer - * @oob_required: must write chip->oob_poi to OOB */ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -2036,14 +2027,12 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, * @mtd: mtd info structure * @chip: nand chip info structure * @buf: data buffer - * @oob_required: must write chip->oob_poi to OOB * * The hw generator calculates the error syndrome automatically. Therefore we * need a special oob layout and handling. */ static void nand_write_page_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf, int oob_required) + struct nand_chip *chip, const uint8_t *buf) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -2082,23 +2071,21 @@ static void nand_write_page_syndrome(struct mtd_info *mtd, * @mtd: MTD device structure * @chip: NAND chip descriptor * @buf: the data to write - * @oob_required: must write chip->oob_poi to OOB * @page: page number to write * @cached: cached programming * @raw: use _raw version of write_page */ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, int page, - int cached, int raw) + const uint8_t *buf, int page, int cached, int raw) { int status; chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); if (unlikely(raw)) - chip->ecc.write_page_raw(mtd, chip, buf, oob_required); + chip->ecc.write_page_raw(mtd, chip, buf); else - chip->ecc.write_page(mtd, chip, buf, oob_required); + chip->ecc.write_page(mtd, chip, buf); /* * Cached progamming disabled for now. Not sure if it's worth the @@ -2131,9 +2118,6 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, if (chip->verify_buf(mtd, buf, mtd->writesize)) return -EIO; - - /* Make sure the next page prog is preceded by a status read */ - chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); #endif return 0; } @@ -2218,7 +2202,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, uint8_t *oob = ops->oobbuf; uint8_t *buf = ops->datbuf; int ret, subpage; - int oob_required = oob ? 1 : 0; ops->retlen = 0; if (!writelen) @@ -2281,8 +2264,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, memset(chip->oob_poi, 0xff, mtd->oobsize); } - ret = chip->write_page(mtd, chip, wbuf, oob_required, page, - cached, (ops->mode == MTD_OPS_RAW)); + ret = chip->write_page(mtd, chip, wbuf, page, cached, + (ops->mode == MTD_OPS_RAW)); if (ret) break; @@ -2915,7 +2898,8 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, *busw = NAND_BUSWIDTH_16; chip->options &= ~NAND_CHIPOPTIONS_MSK; - chip->options |= NAND_NO_READRDY & NAND_CHIPOPTIONS_MSK; + chip->options |= (NAND_NO_READRDY | + NAND_NO_AUTOINCR) & NAND_CHIPOPTIONS_MSK; pr_info("ONFI flash detected\n"); return 1; @@ -3092,6 +3076,11 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; ident_done: + /* + * Set chip as a default. Board drivers can override it, if necessary. + */ + chip->options |= NAND_NO_AUTOINCR; + /* Try to identify manufacturer */ for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) { if (nand_manuf_ids[maf_idx].id == *maf_id) @@ -3165,11 +3154,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, if (mtd->writesize > 512 && chip->cmdfunc == nand_command) chip->cmdfunc = nand_command_lp; - pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s)," - " page size: %d, OOB size: %d\n", - *maf_id, *dev_id, nand_manuf_ids[maf_idx].name, - chip->onfi_version ? chip->onfi_params.model : type->name, - mtd->writesize, mtd->oobsize); + pr_info("NAND device: Manufacturer ID:" + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id, + nand_manuf_ids[maf_idx].name, + chip->onfi_version ? chip->onfi_params.model : type->name); return type; } @@ -3341,13 +3329,8 @@ int nand_scan_tail(struct mtd_info *mtd) if (!chip->ecc.write_oob) chip->ecc.write_oob = nand_write_oob_syndrome; - if (mtd->writesize >= chip->ecc.size) { - if (!chip->ecc.strength) { - pr_warn("Driver must set ecc.strength when using hardware ECC\n"); - BUG(); - } + if (mtd->writesize >= chip->ecc.size) break; - } pr_warn("%d byte HW ECC not possible on " "%d byte page size, fallback to SW ECC\n", chip->ecc.size, mtd->writesize); @@ -3402,7 +3385,7 @@ int nand_scan_tail(struct mtd_info *mtd) BUG(); } chip->ecc.strength = - chip->ecc.bytes * 8 / fls(8 * chip->ecc.size); + chip->ecc.bytes*8 / fls(8*chip->ecc.size); break; case NAND_ECC_NONE: @@ -3500,7 +3483,7 @@ int nand_scan_tail(struct mtd_info *mtd) /* propagate ecc info to mtd_info */ mtd->ecclayout = chip->ecc.layout; - mtd->ecc_strength = chip->ecc.strength; + mtd->ecc_strength = chip->ecc.strength * chip->ecc.steps; /* Check, if we should skip the bad block table scan */ if (chip->options & NAND_SKIP_BBTSCAN) diff --git a/trunk/drivers/mtd/nand/nand_bbt.c b/trunk/drivers/mtd/nand/nand_bbt.c index 30d1319ff065..20a112f591fe 100644 --- a/trunk/drivers/mtd/nand/nand_bbt.c +++ b/trunk/drivers/mtd/nand/nand_bbt.c @@ -324,7 +324,6 @@ static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, buf += mtd->oobsize + mtd->writesize; len -= mtd->writesize; - offs += mtd->writesize; } return 0; } diff --git a/trunk/drivers/mtd/nand/nand_ids.c b/trunk/drivers/mtd/nand/nand_ids.c index 621b70b7a159..af4fe8ca7b5e 100644 --- a/trunk/drivers/mtd/nand/nand_ids.c +++ b/trunk/drivers/mtd/nand/nand_ids.c @@ -70,7 +70,7 @@ struct nand_flash_dev nand_flash_ids[] = { * These are the new chips with large page size. The pagesize and the * erasesize is determined from the extended id bytes */ -#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY) +#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR) #define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16) /* 512 Megabit */ @@ -157,7 +157,9 @@ struct nand_flash_dev nand_flash_ids[] = { * writes possible, but not implemented now */ {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, - NAND_IS_AND | NAND_NO_READRDY | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH}, + NAND_IS_AND | NAND_NO_AUTOINCR |NAND_NO_READRDY | NAND_4PAGE_ARRAY | + BBT_AUTO_REFRESH + }, {NULL,} }; diff --git a/trunk/drivers/mtd/nand/nandsim.c b/trunk/drivers/mtd/nand/nandsim.c index 6cc8fbfabb8e..261f478f8cc3 100644 --- a/trunk/drivers/mtd/nand/nandsim.c +++ b/trunk/drivers/mtd/nand/nandsim.c @@ -268,6 +268,7 @@ MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should " #define OPT_PAGE512 0x00000002 /* 512-byte page chips */ #define OPT_PAGE2048 0x00000008 /* 2048-byte page chips */ #define OPT_SMARTMEDIA 0x00000010 /* SmartMedia technology chips */ +#define OPT_AUTOINCR 0x00000020 /* page number auto incrementation is possible */ #define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */ #define OPT_PAGE4096 0x00000080 /* 4096-byte page chips */ #define OPT_LARGEPAGE (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */ @@ -593,7 +594,7 @@ static int init_nandsim(struct mtd_info *mtd) ns->options |= OPT_PAGE256; } else if (ns->geom.pgsz == 512) { - ns->options |= OPT_PAGE512; + ns->options |= (OPT_PAGE512 | OPT_AUTOINCR); if (ns->busw == 8) ns->options |= OPT_PAGE512_8BIT; } else if (ns->geom.pgsz == 2048) { @@ -662,6 +663,8 @@ static int init_nandsim(struct mtd_info *mtd) for (i = 0; nand_flash_ids[i].name != NULL; i++) { if (second_id_byte != nand_flash_ids[i].id) continue; + if (!(nand_flash_ids[i].options & NAND_NO_AUTOINCR)) + ns->options |= OPT_AUTOINCR; } if (ns->busw == 16) @@ -1933,8 +1936,20 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd) if (ns->regs.count == ns->regs.num) { NS_DBG("read_byte: all bytes were read\n"); - if (NS_STATE(ns->nxstate) == STATE_READY) + /* + * The OPT_AUTOINCR allows to read next consecutive pages without + * new read operation cycle. + */ + if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) { + ns->regs.count = 0; + if (ns->regs.row + 1 < ns->geom.pgnum) + ns->regs.row += 1; + NS_DBG("read_byte: switch to the next page (%#x)\n", ns->regs.row); + do_state_action(ns, ACTION_CPY); + } + else if (NS_STATE(ns->nxstate) == STATE_READY) switch_state(ns); + } return outb; @@ -2188,7 +2203,14 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) ns->regs.count += len; if (ns->regs.count == ns->regs.num) { - if (NS_STATE(ns->nxstate) == STATE_READY) + if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) { + ns->regs.count = 0; + if (ns->regs.row + 1 < ns->geom.pgnum) + ns->regs.row += 1; + NS_DBG("read_buf: switch to the next page (%#x)\n", ns->regs.row); + do_state_action(ns, ACTION_CPY); + } + else if (NS_STATE(ns->nxstate) == STATE_READY) switch_state(ns); } diff --git a/trunk/drivers/mtd/nand/omap2.c b/trunk/drivers/mtd/nand/omap2.c index d7f681d0c9b9..c2b0bba9d8b3 100644 --- a/trunk/drivers/mtd/nand/omap2.c +++ b/trunk/drivers/mtd/nand/omap2.c @@ -21,10 +21,6 @@ #include #include -#ifdef CONFIG_MTD_NAND_OMAP_BCH -#include -#endif - #include #include #include @@ -131,11 +127,6 @@ struct omap_nand_info { } iomode; u_char *buf; int buf_len; - -#ifdef CONFIG_MTD_NAND_OMAP_BCH - struct bch_control *bch; - struct nand_ecclayout ecclayout; -#endif }; /** @@ -411,7 +402,7 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write); if (ret) /* PFPW engine is busy, use cpu copy method */ - goto out_copy_unmap; + goto out_copy; init_completion(&info->comp); @@ -430,8 +421,6 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, dma_unmap_single(&info->pdev->dev, dma_addr, len, dir); return 0; -out_copy_unmap: - dma_unmap_single(&info->pdev->dev, dma_addr, len, dir); out_copy: if (info->nand.options & NAND_BUSWIDTH_16) is_write == 0 ? omap_read_buf16(mtd, (u_char *) addr, len) @@ -890,7 +879,7 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip) struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); unsigned long timeo = jiffies; - int status, state = this->state; + int status = NAND_STATUS_FAIL, state = this->state; if (state == FL_ERASING) timeo += (HZ * 400) / 1000; @@ -905,8 +894,6 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip) break; cond_resched(); } - - status = gpmc_nand_read(info->gpmc_cs, GPMC_NAND_DATA); return status; } @@ -938,226 +925,6 @@ static int omap_dev_ready(struct mtd_info *mtd) return 1; } -#ifdef CONFIG_MTD_NAND_OMAP_BCH - -/** - * omap3_enable_hwecc_bch - Program OMAP3 GPMC to perform BCH ECC correction - * @mtd: MTD device structure - * @mode: Read/Write mode - */ -static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode) -{ - int nerrors; - unsigned int dev_width; - struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, - mtd); - struct nand_chip *chip = mtd->priv; - - nerrors = (info->nand.ecc.bytes == 13) ? 8 : 4; - dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0; - /* - * Program GPMC to perform correction on one 512-byte sector at a time. - * Using 4 sectors at a time (i.e. ecc.size = 2048) is also possible and - * gives a slight (5%) performance gain (but requires additional code). - */ - (void)gpmc_enable_hwecc_bch(info->gpmc_cs, mode, dev_width, 1, nerrors); -} - -/** - * omap3_calculate_ecc_bch4 - Generate 7 bytes of ECC bytes - * @mtd: MTD device structure - * @dat: The pointer to data on which ecc is computed - * @ecc_code: The ecc_code buffer - */ -static int omap3_calculate_ecc_bch4(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) -{ - struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, - mtd); - return gpmc_calculate_ecc_bch4(info->gpmc_cs, dat, ecc_code); -} - -/** - * omap3_calculate_ecc_bch8 - Generate 13 bytes of ECC bytes - * @mtd: MTD device structure - * @dat: The pointer to data on which ecc is computed - * @ecc_code: The ecc_code buffer - */ -static int omap3_calculate_ecc_bch8(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) -{ - struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, - mtd); - return gpmc_calculate_ecc_bch8(info->gpmc_cs, dat, ecc_code); -} - -/** - * omap3_correct_data_bch - Decode received data and correct errors - * @mtd: MTD device structure - * @data: page data - * @read_ecc: ecc read from nand flash - * @calc_ecc: ecc read from HW ECC registers - */ -static int omap3_correct_data_bch(struct mtd_info *mtd, u_char *data, - u_char *read_ecc, u_char *calc_ecc) -{ - int i, count; - /* cannot correct more than 8 errors */ - unsigned int errloc[8]; - struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, - mtd); - - count = decode_bch(info->bch, NULL, 512, read_ecc, calc_ecc, NULL, - errloc); - if (count > 0) { - /* correct errors */ - for (i = 0; i < count; i++) { - /* correct data only, not ecc bytes */ - if (errloc[i] < 8*512) - data[errloc[i]/8] ^= 1 << (errloc[i] & 7); - pr_debug("corrected bitflip %u\n", errloc[i]); - } - } else if (count < 0) { - pr_err("ecc unrecoverable error\n"); - } - return count; -} - -/** - * omap3_free_bch - Release BCH ecc resources - * @mtd: MTD device structure - */ -static void omap3_free_bch(struct mtd_info *mtd) -{ - struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, - mtd); - if (info->bch) { - free_bch(info->bch); - info->bch = NULL; - } -} - -/** - * omap3_init_bch - Initialize BCH ECC - * @mtd: MTD device structure - * @ecc_opt: OMAP ECC mode (OMAP_ECC_BCH4_CODE_HW or OMAP_ECC_BCH8_CODE_HW) - */ -static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt) -{ - int ret, max_errors; - struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, - mtd); -#ifdef CONFIG_MTD_NAND_OMAP_BCH8 - const int hw_errors = 8; -#else - const int hw_errors = 4; -#endif - info->bch = NULL; - - max_errors = (ecc_opt == OMAP_ECC_BCH8_CODE_HW) ? 8 : 4; - if (max_errors != hw_errors) { - pr_err("cannot configure %d-bit BCH ecc, only %d-bit supported", - max_errors, hw_errors); - goto fail; - } - - /* initialize GPMC BCH engine */ - ret = gpmc_init_hwecc_bch(info->gpmc_cs, 1, max_errors); - if (ret) - goto fail; - - /* software bch library is only used to detect and locate errors */ - info->bch = init_bch(13, max_errors, 0x201b /* hw polynomial */); - if (!info->bch) - goto fail; - - info->nand.ecc.size = 512; - info->nand.ecc.hwctl = omap3_enable_hwecc_bch; - info->nand.ecc.correct = omap3_correct_data_bch; - info->nand.ecc.mode = NAND_ECC_HW; - - /* - * The number of corrected errors in an ecc block that will trigger - * block scrubbing defaults to the ecc strength (4 or 8). - * Set mtd->bitflip_threshold here to define a custom threshold. - */ - - if (max_errors == 8) { - info->nand.ecc.strength = 8; - info->nand.ecc.bytes = 13; - info->nand.ecc.calculate = omap3_calculate_ecc_bch8; - } else { - info->nand.ecc.strength = 4; - info->nand.ecc.bytes = 7; - info->nand.ecc.calculate = omap3_calculate_ecc_bch4; - } - - pr_info("enabling NAND BCH ecc with %d-bit correction\n", max_errors); - return 0; -fail: - omap3_free_bch(mtd); - return -1; -} - -/** - * omap3_init_bch_tail - Build an oob layout for BCH ECC correction. - * @mtd: MTD device structure - */ -static int omap3_init_bch_tail(struct mtd_info *mtd) -{ - int i, steps; - struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, - mtd); - struct nand_ecclayout *layout = &info->ecclayout; - - /* build oob layout */ - steps = mtd->writesize/info->nand.ecc.size; - layout->eccbytes = steps*info->nand.ecc.bytes; - - /* do not bother creating special oob layouts for small page devices */ - if (mtd->oobsize < 64) { - pr_err("BCH ecc is not supported on small page devices\n"); - goto fail; - } - - /* reserve 2 bytes for bad block marker */ - if (layout->eccbytes+2 > mtd->oobsize) { - pr_err("no oob layout available for oobsize %d eccbytes %u\n", - mtd->oobsize, layout->eccbytes); - goto fail; - } - - /* put ecc bytes at oob tail */ - for (i = 0; i < layout->eccbytes; i++) - layout->eccpos[i] = mtd->oobsize-layout->eccbytes+i; - - layout->oobfree[0].offset = 2; - layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes; - info->nand.ecc.layout = layout; - - if (!(info->nand.options & NAND_BUSWIDTH_16)) - info->nand.badblock_pattern = &bb_descrip_flashbased; - return 0; -fail: - omap3_free_bch(mtd); - return -1; -} - -#else -static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt) -{ - pr_err("CONFIG_MTD_NAND_OMAP_BCH is not enabled\n"); - return -1; -} -static int omap3_init_bch_tail(struct mtd_info *mtd) -{ - return -1; -} -static void omap3_free_bch(struct mtd_info *mtd) -{ -} -#endif /* CONFIG_MTD_NAND_OMAP_BCH */ - static int __devinit omap_nand_probe(struct platform_device *pdev) { struct omap_nand_info *info; @@ -1296,13 +1063,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) info->nand.ecc.hwctl = omap_enable_hwecc; info->nand.ecc.correct = omap_correct_data; info->nand.ecc.mode = NAND_ECC_HW; - } else if ((pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW) || - (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)) { - err = omap3_init_bch(&info->mtd, pdata->ecc_opt); - if (err) { - err = -EINVAL; - goto out_release_mem_region; - } } /* DIP switches on some boards change between 8 and 16 bit @@ -1334,14 +1094,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) (offset + omap_oobinfo.eccbytes); info->nand.ecc.layout = &omap_oobinfo; - } else if ((pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW) || - (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)) { - /* build OOB layout for BCH ECC correction */ - err = omap3_init_bch_tail(&info->mtd); - if (err) { - err = -EINVAL; - goto out_release_mem_region; - } } /* second phase scan */ @@ -1370,7 +1122,6 @@ static int omap_nand_remove(struct platform_device *pdev) struct mtd_info *mtd = platform_get_drvdata(pdev); struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); - omap3_free_bch(&info->mtd); platform_set_drvdata(pdev, NULL); if (info->dma_ch != -1) diff --git a/trunk/drivers/mtd/nand/pasemi_nand.c b/trunk/drivers/mtd/nand/pasemi_nand.c index 1440e51cedcc..974dbf8251c9 100644 --- a/trunk/drivers/mtd/nand/pasemi_nand.c +++ b/trunk/drivers/mtd/nand/pasemi_nand.c @@ -155,6 +155,7 @@ static int __devinit pasemi_nand_probe(struct platform_device *ofdev) chip->ecc.mode = NAND_ECC_SOFT; /* Enable the following for a flash based bad block table */ + chip->options = NAND_NO_AUTOINCR; chip->bbt_options = NAND_BBT_USE_FLASH; /* Scan to find existence of the device */ diff --git a/trunk/drivers/mtd/nand/plat_nand.c b/trunk/drivers/mtd/nand/plat_nand.c index 1bcb52040422..6404e6e81b10 100644 --- a/trunk/drivers/mtd/nand/plat_nand.c +++ b/trunk/drivers/mtd/nand/plat_nand.c @@ -23,18 +23,14 @@ struct plat_nand_data { void __iomem *io_base; }; -static const char *part_probe_types[] = { "cmdlinepart", NULL }; - /* * Probe for the NAND device. */ static int __devinit plat_nand_probe(struct platform_device *pdev) { struct platform_nand_data *pdata = pdev->dev.platform_data; - struct mtd_part_parser_data ppdata; struct plat_nand_data *data; struct resource *res; - const char **part_types; int err = 0; if (pdata->chip.nr_chips < 1) { @@ -79,7 +75,6 @@ static int __devinit plat_nand_probe(struct platform_device *pdev) data->chip.select_chip = pdata->ctrl.select_chip; data->chip.write_buf = pdata->ctrl.write_buf; data->chip.read_buf = pdata->ctrl.read_buf; - data->chip.read_byte = pdata->ctrl.read_byte; data->chip.chip_delay = pdata->chip.chip_delay; data->chip.options |= pdata->chip.options; data->chip.bbt_options |= pdata->chip.bbt_options; @@ -103,10 +98,8 @@ static int __devinit plat_nand_probe(struct platform_device *pdev) goto out; } - part_types = pdata->chip.part_probe_types ? : part_probe_types; - - ppdata.of_node = pdev->dev.of_node; - err = mtd_device_parse_register(&data->mtd, part_types, &ppdata, + err = mtd_device_parse_register(&data->mtd, + pdata->chip.part_probe_types, NULL, pdata->chip.partitions, pdata->chip.nr_partitions); @@ -147,19 +140,12 @@ static int __devexit plat_nand_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id plat_nand_match[] = { - { .compatible = "gen_nand" }, - {}, -}; -MODULE_DEVICE_TABLE(of, plat_nand_match); - static struct platform_driver plat_nand_driver = { - .probe = plat_nand_probe, - .remove = __devexit_p(plat_nand_remove), - .driver = { - .name = "gen_nand", - .owner = THIS_MODULE, - .of_match_table = plat_nand_match, + .probe = plat_nand_probe, + .remove = __devexit_p(plat_nand_remove), + .driver = { + .name = "gen_nand", + .owner = THIS_MODULE, }, }; diff --git a/trunk/drivers/mtd/nand/pxa3xx_nand.c b/trunk/drivers/mtd/nand/pxa3xx_nand.c index 252aaefcacfa..def50caa6f84 100644 --- a/trunk/drivers/mtd/nand/pxa3xx_nand.c +++ b/trunk/drivers/mtd/nand/pxa3xx_nand.c @@ -682,15 +682,14 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, } static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf, int oob_required) + struct nand_chip *chip, const uint8_t *buf) { chip->write_buf(mtd, buf, mtd->writesize); chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); } static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int oob_required, - int page) + struct nand_chip *chip, uint8_t *buf, int page) { struct pxa3xx_nand_host *host = mtd->priv; struct pxa3xx_nand_info *info = host->info_data; @@ -1005,6 +1004,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) chip->ecc.size = host->page_size; chip->ecc.strength = 1; + chip->options = NAND_NO_AUTOINCR; chip->options |= NAND_NO_READRDY; if (host->reg_ndcr & NDCR_DWIDTH_M) chip->options |= NAND_BUSWIDTH_16; diff --git a/trunk/drivers/mtd/nand/r852.c b/trunk/drivers/mtd/nand/r852.c index 8cb627751c9c..c2040187c813 100644 --- a/trunk/drivers/mtd/nand/r852.c +++ b/trunk/drivers/mtd/nand/r852.c @@ -539,11 +539,14 @@ int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat, * nand_read_oob_syndrome assumes we can send column address - we can't */ static int r852_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page) + int page, int sndcmd) { - chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + if (sndcmd) { + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + sndcmd = 0; + } chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - return 0; + return sndcmd; } /* @@ -1101,7 +1104,18 @@ static struct pci_driver r852_pci_driver = { .driver.pm = &r852_pm_ops, }; -module_pci_driver(r852_pci_driver); +static __init int r852_module_init(void) +{ + return pci_register_driver(&r852_pci_driver); +} + +static void __exit r852_module_exit(void) +{ + pci_unregister_driver(&r852_pci_driver); +} + +module_init(r852_module_init); +module_exit(r852_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Maxim Levitsky "); diff --git a/trunk/drivers/mtd/nand/sh_flctl.c b/trunk/drivers/mtd/nand/sh_flctl.c index aa9b8a5e0b8f..e9b2b260de3a 100644 --- a/trunk/drivers/mtd/nand/sh_flctl.c +++ b/trunk/drivers/mtd/nand/sh_flctl.c @@ -344,7 +344,7 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va } static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page) + uint8_t *buf, int page) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -359,14 +359,14 @@ static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, if (flctl->hwecc_cant_correct[i]) mtd->ecc_stats.failed++; else - mtd->ecc_stats.corrected += 0; /* FIXME */ + mtd->ecc_stats.corrected += 0; } return 0; } static void flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required) + const uint8_t *buf) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -881,6 +881,8 @@ static int __devinit flctl_probe(struct platform_device *pdev) flctl->hwecc = pdata->has_hwecc; flctl->holden = pdata->use_holden; + nand->options = NAND_NO_AUTOINCR; + /* Set address of hardware control function */ /* 20 us command delay time */ nand->chip_delay = 20; diff --git a/trunk/drivers/mtd/nand/sm_common.c b/trunk/drivers/mtd/nand/sm_common.c index 082bcdcd6bcf..774c3c266713 100644 --- a/trunk/drivers/mtd/nand/sm_common.c +++ b/trunk/drivers/mtd/nand/sm_common.c @@ -94,16 +94,17 @@ static struct nand_flash_dev nand_smartmedia_flash_ids[] = { {NULL,} }; +#define XD_TYPEM (NAND_NO_AUTOINCR | NAND_BROKEN_XD) static struct nand_flash_dev nand_xd_flash_ids[] = { {"xD 16MiB 3,3V", 0x73, 512, 16, 0x4000, 0}, {"xD 32MiB 3,3V", 0x75, 512, 32, 0x4000, 0}, {"xD 64MiB 3,3V", 0x76, 512, 64, 0x4000, 0}, {"xD 128MiB 3,3V", 0x79, 512, 128, 0x4000, 0}, - {"xD 256MiB 3,3V", 0x71, 512, 256, 0x4000, NAND_BROKEN_XD}, - {"xD 512MiB 3,3V", 0xdc, 512, 512, 0x4000, NAND_BROKEN_XD}, - {"xD 1GiB 3,3V", 0xd3, 512, 1024, 0x4000, NAND_BROKEN_XD}, - {"xD 2GiB 3,3V", 0xd5, 512, 2048, 0x4000, NAND_BROKEN_XD}, + {"xD 256MiB 3,3V", 0x71, 512, 256, 0x4000, XD_TYPEM}, + {"xD 512MiB 3,3V", 0xdc, 512, 512, 0x4000, XD_TYPEM}, + {"xD 1GiB 3,3V", 0xd3, 512, 1024, 0x4000, XD_TYPEM}, + {"xD 2GiB 3,3V", 0xd5, 512, 2048, 0x4000, XD_TYPEM}, {NULL,} }; diff --git a/trunk/drivers/mtd/onenand/onenand_base.c b/trunk/drivers/mtd/onenand/onenand_base.c index 7153e0d27101..b3ce12ef359e 100644 --- a/trunk/drivers/mtd/onenand/onenand_base.c +++ b/trunk/drivers/mtd/onenand/onenand_base.c @@ -1201,8 +1201,7 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from, if (mtd->ecc_stats.failed - stats.failed) return -EBADMSG; - /* return max bitflips per ecc step; ONENANDs correct 1 bit only */ - return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0; + return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; } /** @@ -1334,8 +1333,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, if (mtd->ecc_stats.failed - stats.failed) return -EBADMSG; - /* return max bitflips per ecc step; ONENANDs correct 1 bit only */ - return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0; + return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; } /** diff --git a/trunk/drivers/net/ethernet/rdc/r6040.c b/trunk/drivers/net/ethernet/rdc/r6040.c index d1827e887f4e..4de73643fec6 100644 --- a/trunk/drivers/net/ethernet/rdc/r6040.c +++ b/trunk/drivers/net/ethernet/rdc/r6040.c @@ -1096,20 +1096,20 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, if (err) { dev_err(&pdev->dev, "32-bit PCI DMA addresses" "not supported by the card\n"); - goto err_out_disable_dev; + goto err_out; } err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (err) { dev_err(&pdev->dev, "32-bit PCI DMA addresses" "not supported by the card\n"); - goto err_out_disable_dev; + goto err_out; } /* IO Size check */ if (pci_resource_len(pdev, bar) < io_size) { dev_err(&pdev->dev, "Insufficient PCI resources, aborting\n"); err = -EIO; - goto err_out_disable_dev; + goto err_out; } pci_set_master(pdev); @@ -1117,7 +1117,7 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, dev = alloc_etherdev(sizeof(struct r6040_private)); if (!dev) { err = -ENOMEM; - goto err_out_disable_dev; + goto err_out; } SET_NETDEV_DEV(dev, &pdev->dev); lp = netdev_priv(dev); @@ -1233,15 +1233,11 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, err_out_mdio: mdiobus_free(lp->mii_bus); err_out_unmap: - netif_napi_del(&lp->napi); - pci_set_drvdata(pdev, NULL); pci_iounmap(pdev, ioaddr); err_out_free_res: pci_release_regions(pdev); err_out_free_dev: free_netdev(dev); -err_out_disable_dev: - pci_disable_device(pdev); err_out: return err; } @@ -1255,9 +1251,6 @@ static void __devexit r6040_remove_one(struct pci_dev *pdev) mdiobus_unregister(lp->mii_bus); kfree(lp->mii_bus->irq); mdiobus_free(lp->mii_bus); - netif_napi_del(&lp->napi); - pci_set_drvdata(pdev, NULL); - pci_iounmap(pdev, lp->base); pci_release_regions(pdev); free_netdev(dev); pci_disable_device(pdev); diff --git a/trunk/drivers/net/ethernet/renesas/sh_eth.c b/trunk/drivers/net/ethernet/renesas/sh_eth.c index 667169b82526..be3c22179161 100644 --- a/trunk/drivers/net/ethernet/renesas/sh_eth.c +++ b/trunk/drivers/net/ethernet/renesas/sh_eth.c @@ -1101,12 +1101,8 @@ static int sh_eth_rx(struct net_device *ndev) /* Restart Rx engine if stopped. */ /* If we don't need to check status, don't. -KDU */ - if (!(sh_eth_read(ndev, EDRRR) & EDRRR_R)) { - /* fix the values for the next receiving */ - mdp->cur_rx = mdp->dirty_rx = (sh_eth_read(ndev, RDFAR) - - sh_eth_read(ndev, RDLAR)) >> 4; + if (!(sh_eth_read(ndev, EDRRR) & EDRRR_R)) sh_eth_write(ndev, EDRRR_R, EDRRR); - } return 0; } @@ -1203,6 +1199,8 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) /* Receive Descriptor Empty int */ ndev->stats.rx_over_errors++; + if (sh_eth_read(ndev, EDRRR) ^ EDRRR_R) + sh_eth_write(ndev, EDRRR_R, EDRRR); if (netif_msg_rx_err(mdp)) dev_err(&ndev->dev, "Receive Descriptor Empty\n"); } diff --git a/trunk/drivers/net/ethernet/smsc/smsc911x.c b/trunk/drivers/net/ethernet/smsc/smsc911x.c index 1466e5d2af44..dab9c6f671ec 100644 --- a/trunk/drivers/net/ethernet/smsc/smsc911x.c +++ b/trunk/drivers/net/ethernet/smsc/smsc911x.c @@ -2390,11 +2390,11 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) retval = smsc911x_request_resources(pdev); if (retval) - goto out_request_resources_fail; + goto out_return_resources; retval = smsc911x_enable_resources(pdev); if (retval) - goto out_enable_resources_fail; + goto out_disable_resources; if (pdata->ioaddr == NULL) { SMSC_WARN(pdata, probe, "Error smsc911x base address invalid"); @@ -2501,9 +2501,8 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) free_irq(dev->irq, dev); out_disable_resources: (void)smsc911x_disable_resources(pdev); -out_enable_resources_fail: +out_return_resources: smsc911x_free_resources(pdev); -out_request_resources_fail: platform_set_drvdata(pdev, NULL); iounmap(pdata->ioaddr); free_netdev(dev); diff --git a/trunk/drivers/net/usb/asix.c b/trunk/drivers/net/usb/asix.c index 3ae80eccd0ef..71e2b0523bc2 100644 --- a/trunk/drivers/net/usb/asix.c +++ b/trunk/drivers/net/usb/asix.c @@ -35,7 +35,6 @@ #include #include #include -#include #define DRIVER_VERSION "22-Dec-2011" #define DRIVER_NAME "asix" @@ -322,7 +321,7 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) return 0; } - if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) || + if ((size > dev->net->mtu + ETH_HLEN) || (size + offset > skb->len)) { netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n", size); diff --git a/trunk/drivers/net/usb/qmi_wwan.c b/trunk/drivers/net/usb/qmi_wwan.c index 3b206786b5e7..380dbea6109d 100644 --- a/trunk/drivers/net/usb/qmi_wwan.c +++ b/trunk/drivers/net/usb/qmi_wwan.c @@ -547,8 +547,6 @@ static const struct usb_device_id products[] = { {QMI_GOBI_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */ {QMI_GOBI_DEVICE(0x05c6, 0x9205)}, /* Gobi 2000 Modem device */ {QMI_GOBI_DEVICE(0x1199, 0x9013)}, /* Sierra Wireless Gobi 3000 Modem device (MC8355) */ - {QMI_GOBI_DEVICE(0x1199, 0x9015)}, /* Sierra Wireless Gobi 3000 Modem device */ - {QMI_GOBI_DEVICE(0x1199, 0x9019)}, /* Sierra Wireless Gobi 3000 Modem device */ { } /* END */ }; MODULE_DEVICE_TABLE(usb, products); diff --git a/trunk/drivers/net/virtio_net.c b/trunk/drivers/net/virtio_net.c index 5214b1eceb95..9ce6995e8d08 100644 --- a/trunk/drivers/net/virtio_net.c +++ b/trunk/drivers/net/virtio_net.c @@ -1231,6 +1231,11 @@ static int virtnet_freeze(struct virtio_device *vdev) vi->config_enable = false; mutex_unlock(&vi->config_lock); + virtqueue_disable_cb(vi->rvq); + virtqueue_disable_cb(vi->svq); + if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)) + virtqueue_disable_cb(vi->cvq); + netif_device_detach(vi->dev); cancel_delayed_work_sync(&vi->refill); diff --git a/trunk/drivers/net/wireless/ath/ath5k/base.c b/trunk/drivers/net/wireless/ath/ath5k/base.c index fbaa30930076..0ba81a66061f 100644 --- a/trunk/drivers/net/wireless/ath/ath5k/base.c +++ b/trunk/drivers/net/wireless/ath/ath5k/base.c @@ -2415,22 +2415,6 @@ ath5k_tx_complete_poll_work(struct work_struct *work) * Initialization routines * \*************************/ -static const struct ieee80211_iface_limit if_limits[] = { - { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) }, - { .max = 4, .types = -#ifdef CONFIG_MAC80211_MESH - BIT(NL80211_IFTYPE_MESH_POINT) | -#endif - BIT(NL80211_IFTYPE_AP) }, -}; - -static const struct ieee80211_iface_combination if_comb = { - .limits = if_limits, - .n_limits = ARRAY_SIZE(if_limits), - .max_interfaces = 2048, - .num_different_channels = 1, -}; - int __devinit ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) { @@ -2452,9 +2436,6 @@ ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MESH_POINT); - hw->wiphy->iface_combinations = &if_comb; - hw->wiphy->n_iface_combinations = 1; - /* SW support for IBSS_RSN is provided by mac80211 */ hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; diff --git a/trunk/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/trunk/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index dfb0441f406c..ac53d901801d 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/trunk/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3809,7 +3809,7 @@ static bool is_pmu_set(struct ath_hw *ah, u32 pmu_reg, int pmu_set) return true; } -void ar9003_hw_internal_regulator_apply(struct ath_hw *ah) +static void ar9003_hw_internal_regulator_apply(struct ath_hw *ah) { int internal_regulator = ath9k_hw_ar9300_get_eeprom(ah, EEP_INTERNAL_REGULATOR); diff --git a/trunk/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/trunk/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h index 8396d150ce01..2505ac44f0c1 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h +++ b/trunk/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h @@ -334,7 +334,4 @@ u8 *ar9003_get_spur_chan_ptr(struct ath_hw *ah, bool is_2ghz); unsigned int ar9003_get_paprd_scale_factor(struct ath_hw *ah, struct ath9k_channel *chan); - -void ar9003_hw_internal_regulator_apply(struct ath_hw *ah); - #endif diff --git a/trunk/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h b/trunk/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h index 1bd3a3d22101..f11d9b2677fd 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h +++ b/trunk/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h @@ -1,6 +1,5 @@ /* - * Copyright (c) 2010-2011 Atheros Communications Inc. - * Copyright (c) 2011-2012 Qualcomm Atheros Inc. + * Copyright (c) 2011 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,7 +18,7 @@ #define INITVALS_9330_1P1_H static const u32 ar9331_1p1_baseband_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, {0x00009820, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e}, {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, @@ -28,10 +27,10 @@ static const u32 ar9331_1p1_baseband_postamble[][5] = { {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c}, {0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044}, {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a4, 0x037216a4}, - {0x00009e04, 0x00202020, 0x00202020, 0x00202020, 0x00202020}, + {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020}, {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, {0x00009e10, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e}, - {0x00009e14, 0x31365d5e, 0x3136605e, 0x3136605e, 0x31365d5e}, + {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, @@ -56,7 +55,7 @@ static const u32 ar9331_1p1_baseband_postamble[][5] = { {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, - {0x0000a2d0, 0x00071982, 0x00071982, 0x00071982, 0x00071982}, + {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071981}, {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000ae04, 0x00802020, 0x00802020, 0x00802020, 0x00802020}, @@ -64,7 +63,7 @@ static const u32 ar9331_1p1_baseband_postamble[][5] = { }; static const u32 ar9331_modes_lowest_ob_db_tx_gain_1p1[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x0000a2d8, 0x7999a83a, 0x7999a83a, 0x7999a83a, 0x7999a83a}, {0x0000a2dc, 0xffff2a52, 0xffff2a52, 0xffff2a52, 0xffff2a52}, {0x0000a2e0, 0xffffcc84, 0xffffcc84, 0xffffcc84, 0xffffcc84}, @@ -156,7 +155,7 @@ static const u32 ar9331_modes_lowest_ob_db_tx_gain_1p1[][5] = { }; static const u32 ar9331_modes_high_ob_db_tx_gain_1p1[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x0000a2d8, 0x7999a83a, 0x7999a83a, 0x7999a83a, 0x7999a83a}, {0x0000a2dc, 0xffaa9a52, 0xffaa9a52, 0xffaa9a52, 0xffaa9a52}, {0x0000a2e0, 0xffb31c84, 0xffb31c84, 0xffb31c84, 0xffb31c84}, @@ -246,7 +245,7 @@ static const u32 ar9331_modes_high_ob_db_tx_gain_1p1[][5] = { }; static const u32 ar9331_modes_low_ob_db_tx_gain_1p1[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x0000a2d8, 0x7999a83a, 0x7999a83a, 0x7999a83a, 0x7999a83a}, {0x0000a2dc, 0xffff2a52, 0xffff2a52, 0xffff2a52, 0xffff2a52}, {0x0000a2e0, 0xffffcc84, 0xffffcc84, 0xffffcc84, 0xffffcc84}, @@ -378,14 +377,14 @@ static const u32 ar9331_1p1_radio_core[][2] = { {0x000160b4, 0x92480040}, {0x000160c0, 0x006db6db}, {0x000160c4, 0x0186db60}, - {0x000160c8, 0x6db4db6c}, + {0x000160c8, 0x6db6db6c}, {0x000160cc, 0x6de6c300}, {0x000160d0, 0x14500820}, {0x00016100, 0x04cb0001}, {0x00016104, 0xfff80015}, {0x00016108, 0x00080010}, {0x0001610c, 0x00170000}, - {0x00016140, 0x10800000}, + {0x00016140, 0x10804000}, {0x00016144, 0x01884080}, {0x00016148, 0x000080c0}, {0x00016280, 0x01000015}, @@ -418,7 +417,7 @@ static const u32 ar9331_1p1_radio_core[][2] = { }; static const u32 ar9331_1p1_soc_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00007010, 0x00000022, 0x00000022, 0x00000022, 0x00000022}, }; @@ -692,7 +691,7 @@ static const u32 ar9331_1p1_baseband_core[][2] = { }; static const u32 ar9331_modes_high_power_tx_gain_1p1[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x0000a2d8, 0x7999a83a, 0x7999a83a, 0x7999a83a, 0x7999a83a}, {0x0000a2dc, 0xffff2a52, 0xffff2a52, 0xffff2a52, 0xffff2a52}, {0x0000a2e0, 0xffffcc84, 0xffffcc84, 0xffffcc84, 0xffffcc84}, @@ -784,7 +783,7 @@ static const u32 ar9331_modes_high_power_tx_gain_1p1[][5] = { }; static const u32 ar9331_1p1_mac_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, @@ -974,27 +973,26 @@ static const u32 ar9331_1p1_mac_core[][2] = { static const u32 ar9331_common_rx_gain_1p1[][2] = { /* Addr allmodes */ - {0x00009e18, 0x05000000}, - {0x0000a000, 0x00060005}, - {0x0000a004, 0x00810080}, - {0x0000a008, 0x00830082}, - {0x0000a00c, 0x00850084}, - {0x0000a010, 0x01820181}, - {0x0000a014, 0x01840183}, - {0x0000a018, 0x01880185}, - {0x0000a01c, 0x018a0189}, - {0x0000a020, 0x02850284}, - {0x0000a024, 0x02890288}, - {0x0000a028, 0x028b028a}, - {0x0000a02c, 0x03850384}, - {0x0000a030, 0x03890388}, - {0x0000a034, 0x038b038a}, - {0x0000a038, 0x038d038c}, - {0x0000a03c, 0x03910390}, - {0x0000a040, 0x03930392}, - {0x0000a044, 0x03950394}, - {0x0000a048, 0x00000396}, - {0x0000a04c, 0x00000000}, + {0x0000a000, 0x00010000}, + {0x0000a004, 0x00030002}, + {0x0000a008, 0x00050004}, + {0x0000a00c, 0x00810080}, + {0x0000a010, 0x00830082}, + {0x0000a014, 0x01810180}, + {0x0000a018, 0x01830182}, + {0x0000a01c, 0x01850184}, + {0x0000a020, 0x01890188}, + {0x0000a024, 0x018b018a}, + {0x0000a028, 0x018d018c}, + {0x0000a02c, 0x01910190}, + {0x0000a030, 0x01930192}, + {0x0000a034, 0x01950194}, + {0x0000a038, 0x038a0196}, + {0x0000a03c, 0x038c038b}, + {0x0000a040, 0x0390038d}, + {0x0000a044, 0x03920391}, + {0x0000a048, 0x03940393}, + {0x0000a04c, 0x03960395}, {0x0000a050, 0x00000000}, {0x0000a054, 0x00000000}, {0x0000a058, 0x00000000}, @@ -1007,15 +1005,15 @@ static const u32 ar9331_common_rx_gain_1p1[][2] = { {0x0000a074, 0x00000000}, {0x0000a078, 0x00000000}, {0x0000a07c, 0x00000000}, - {0x0000a080, 0x28282828}, - {0x0000a084, 0x28282828}, - {0x0000a088, 0x28282828}, - {0x0000a08c, 0x28282828}, - {0x0000a090, 0x28282828}, - {0x0000a094, 0x24242428}, - {0x0000a098, 0x171e1e1e}, - {0x0000a09c, 0x02020b0b}, - {0x0000a0a0, 0x02020202}, + {0x0000a080, 0x22222229}, + {0x0000a084, 0x1d1d1d1d}, + {0x0000a088, 0x1d1d1d1d}, + {0x0000a08c, 0x1d1d1d1d}, + {0x0000a090, 0x171d1d1d}, + {0x0000a094, 0x11111717}, + {0x0000a098, 0x00030311}, + {0x0000a09c, 0x00000000}, + {0x0000a0a0, 0x00000000}, {0x0000a0a4, 0x00000000}, {0x0000a0a8, 0x00000000}, {0x0000a0ac, 0x00000000}, @@ -1023,27 +1021,27 @@ static const u32 ar9331_common_rx_gain_1p1[][2] = { {0x0000a0b4, 0x00000000}, {0x0000a0b8, 0x00000000}, {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x22072208}, - {0x0000a0c4, 0x22052206}, - {0x0000a0c8, 0x22032204}, - {0x0000a0cc, 0x22012202}, - {0x0000a0d0, 0x221f2200}, - {0x0000a0d4, 0x221d221e}, - {0x0000a0d8, 0x33023303}, - {0x0000a0dc, 0x33003301}, - {0x0000a0e0, 0x331e331f}, - {0x0000a0e4, 0x4402331d}, - {0x0000a0e8, 0x44004401}, - {0x0000a0ec, 0x441e441f}, - {0x0000a0f0, 0x55025503}, - {0x0000a0f4, 0x55005501}, - {0x0000a0f8, 0x551e551f}, - {0x0000a0fc, 0x6602551d}, - {0x0000a100, 0x66006601}, - {0x0000a104, 0x661e661f}, - {0x0000a108, 0x7703661d}, - {0x0000a10c, 0x77017702}, - {0x0000a110, 0x00007700}, + {0x0000a0c0, 0x001f0000}, + {0x0000a0c4, 0x01000101}, + {0x0000a0c8, 0x011e011f}, + {0x0000a0cc, 0x011c011d}, + {0x0000a0d0, 0x02030204}, + {0x0000a0d4, 0x02010202}, + {0x0000a0d8, 0x021f0200}, + {0x0000a0dc, 0x0302021e}, + {0x0000a0e0, 0x03000301}, + {0x0000a0e4, 0x031e031f}, + {0x0000a0e8, 0x0402031d}, + {0x0000a0ec, 0x04000401}, + {0x0000a0f0, 0x041e041f}, + {0x0000a0f4, 0x0502041d}, + {0x0000a0f8, 0x05000501}, + {0x0000a0fc, 0x051e051f}, + {0x0000a100, 0x06010602}, + {0x0000a104, 0x061f0600}, + {0x0000a108, 0x061d061e}, + {0x0000a10c, 0x07020703}, + {0x0000a110, 0x07000701}, {0x0000a114, 0x00000000}, {0x0000a118, 0x00000000}, {0x0000a11c, 0x00000000}, @@ -1056,26 +1054,26 @@ static const u32 ar9331_common_rx_gain_1p1[][2] = { {0x0000a138, 0x00000000}, {0x0000a13c, 0x00000000}, {0x0000a140, 0x001f0000}, - {0x0000a144, 0x111f1100}, - {0x0000a148, 0x111d111e}, - {0x0000a14c, 0x111b111c}, - {0x0000a150, 0x22032204}, - {0x0000a154, 0x22012202}, - {0x0000a158, 0x221f2200}, - {0x0000a15c, 0x221d221e}, - {0x0000a160, 0x33013302}, - {0x0000a164, 0x331f3300}, - {0x0000a168, 0x4402331e}, - {0x0000a16c, 0x44004401}, - {0x0000a170, 0x441e441f}, - {0x0000a174, 0x55015502}, - {0x0000a178, 0x551f5500}, - {0x0000a17c, 0x6602551e}, - {0x0000a180, 0x66006601}, - {0x0000a184, 0x661e661f}, - {0x0000a188, 0x7703661d}, - {0x0000a18c, 0x77017702}, - {0x0000a190, 0x00007700}, + {0x0000a144, 0x01000101}, + {0x0000a148, 0x011e011f}, + {0x0000a14c, 0x011c011d}, + {0x0000a150, 0x02030204}, + {0x0000a154, 0x02010202}, + {0x0000a158, 0x021f0200}, + {0x0000a15c, 0x0302021e}, + {0x0000a160, 0x03000301}, + {0x0000a164, 0x031e031f}, + {0x0000a168, 0x0402031d}, + {0x0000a16c, 0x04000401}, + {0x0000a170, 0x041e041f}, + {0x0000a174, 0x0502041d}, + {0x0000a178, 0x05000501}, + {0x0000a17c, 0x051e051f}, + {0x0000a180, 0x06010602}, + {0x0000a184, 0x061f0600}, + {0x0000a188, 0x061d061e}, + {0x0000a18c, 0x07020703}, + {0x0000a190, 0x07000701}, {0x0000a194, 0x00000000}, {0x0000a198, 0x00000000}, {0x0000a19c, 0x00000000}, @@ -1102,14 +1100,14 @@ static const u32 ar9331_common_rx_gain_1p1[][2] = { {0x0000a1f0, 0x00000396}, {0x0000a1f4, 0x00000396}, {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000296}, + {0x0000a1fc, 0x00000196}, }; static const u32 ar9331_common_tx_gain_offset1_1[][1] = { - {0x00000000}, - {0x00000003}, - {0x00000000}, - {0x00000000}, + {0}, + {3}, + {0}, + {0}, }; static const u32 ar9331_1p1_chansel_xtal_25M[] = { diff --git a/trunk/drivers/net/wireless/ath/ath9k/hw.c b/trunk/drivers/net/wireless/ath/ath9k/hw.c index 7db1890448f2..abe05ec85d50 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/hw.c +++ b/trunk/drivers/net/wireless/ath/ath9k/hw.c @@ -1468,9 +1468,6 @@ static bool ath9k_hw_chip_reset(struct ath_hw *ah, return false; ah->chip_fullsleep = false; - - if (AR_SREV_9330(ah)) - ar9003_hw_internal_regulator_apply(ah); ath9k_hw_init_pll(ah, chan); ath9k_hw_set_rfmode(ah, chan); diff --git a/trunk/drivers/net/wireless/ath/ath9k/main.c b/trunk/drivers/net/wireless/ath/ath9k/main.c index 4de4473776ac..dfa78e8b6470 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/main.c +++ b/trunk/drivers/net/wireless/ath/ath9k/main.c @@ -239,7 +239,7 @@ static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - bool ret = true; + bool ret; ieee80211_stop_queues(sc->hw); @@ -250,10 +250,9 @@ static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) ath9k_debug_samp_bb_mac(sc); ath9k_hw_disable_interrupts(ah); - if (!ath_stoprecv(sc)) - ret = false; + ret = ath_drain_all_txq(sc, retry_tx); - if (!ath_drain_all_txq(sc, retry_tx)) + if (!ath_stoprecv(sc)) ret = false; if (!flush) { diff --git a/trunk/drivers/net/wireless/ath/ath9k/xmit.c b/trunk/drivers/net/wireless/ath/ath9k/xmit.c index d59dd01d6cde..23eaa1b26ebe 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/xmit.c +++ b/trunk/drivers/net/wireless/ath/ath9k/xmit.c @@ -64,8 +64,7 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, - struct sk_buff *skb, - bool dequeue); + struct sk_buff *skb); enum { MCS_HT20, @@ -812,7 +811,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, fi = get_frame_info(skb); bf = fi->bf; if (!fi->bf) - bf = ath_tx_setup_buffer(sc, txq, tid, skb, true); + bf = ath_tx_setup_buffer(sc, txq, tid, skb); if (!bf) continue; @@ -1727,7 +1726,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, return; } - bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false); + bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb); if (!bf) return; @@ -1754,7 +1753,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, bf = fi->bf; if (!bf) - bf = ath_tx_setup_buffer(sc, txq, tid, skb, false); + bf = ath_tx_setup_buffer(sc, txq, tid, skb); if (!bf) return; @@ -1815,8 +1814,7 @@ u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate) static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, - struct sk_buff *skb, - bool dequeue) + struct sk_buff *skb) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_frame_info *fi = get_frame_info(skb); @@ -1865,8 +1863,6 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, return bf; error: - if (dequeue) - __skb_unlink(skb, &tid->buf_q); dev_kfree_skb_any(skb); return NULL; } @@ -1897,7 +1893,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb, */ ath_tx_send_ampdu(sc, tid, skb, txctl); } else { - bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false); + bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb); if (!bf) return; diff --git a/trunk/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/trunk/drivers/net/wireless/brcm80211/brcmfmac/usb.c index a299d42da8e7..c5a34ffe6459 100644 --- a/trunk/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/trunk/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -1240,7 +1239,7 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo) return -EINVAL; } - devinfo->image = vmalloc(fw->size); /* plus nvram */ + devinfo->image = kmalloc(fw->size, GFP_ATOMIC); /* plus nvram */ if (!devinfo->image) return -ENOMEM; @@ -1604,7 +1603,7 @@ static struct usb_driver brcmf_usbdrvr = { void brcmf_usb_exit(void) { usb_deregister(&brcmf_usbdrvr); - vfree(g_image.data); + kfree(g_image.data); g_image.data = NULL; g_image.len = 0; } diff --git a/trunk/drivers/net/wireless/iwlwifi/Kconfig b/trunk/drivers/net/wireless/iwlwifi/Kconfig index 2463c0626438..db6c6e528022 100644 --- a/trunk/drivers/net/wireless/iwlwifi/Kconfig +++ b/trunk/drivers/net/wireless/iwlwifi/Kconfig @@ -137,3 +137,11 @@ config IWLWIFI_EXPERIMENTAL_MFP even if the microcode doesn't advertise it. Say Y only if you want to experiment with MFP. + +config IWLWIFI_UCODE16 + bool "support uCode 16.0" + depends on IWLWIFI + help + This option enables support for uCode version 16.0. + + Say Y if you want to use 16.0 microcode. diff --git a/trunk/drivers/net/wireless/iwlwifi/Makefile b/trunk/drivers/net/wireless/iwlwifi/Makefile index d615eacbf050..406f297a9a56 100644 --- a/trunk/drivers/net/wireless/iwlwifi/Makefile +++ b/trunk/drivers/net/wireless/iwlwifi/Makefile @@ -18,6 +18,7 @@ iwlwifi-objs += iwl-notif-wait.o iwlwifi-objs += iwl-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o +iwlwifi-$(CONFIG_IWLWIFI_UCODE16) += iwl-phy-db.o iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TESTMODE) += iwl-testmode.o diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-2000.c b/trunk/drivers/net/wireless/iwlwifi/iwl-2000.c index 8133105ac645..7f793417c787 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -79,7 +79,7 @@ static const struct iwl_base_params iwl2000_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 512, - .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ + .shadow_reg_enable = true, .hd_v2 = true, }; @@ -97,7 +97,7 @@ static const struct iwl_base_params iwl2030_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, - .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ + .shadow_reg_enable = true, .hd_v2 = true, }; diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-6000.c b/trunk/drivers/net/wireless/iwlwifi/iwl-6000.c index 19f7ee84ae89..381b02cf339c 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -86,7 +86,7 @@ static const struct iwl_base_params iwl6000_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 512, - .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ + .shadow_reg_enable = true, }; static const struct iwl_base_params iwl6050_base_params = { @@ -102,7 +102,7 @@ static const struct iwl_base_params iwl6050_base_params = { .chain_noise_scale = 1500, .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 1024, - .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ + .shadow_reg_enable = true, }; static const struct iwl_base_params iwl6000_g2_base_params = { @@ -118,7 +118,7 @@ static const struct iwl_base_params iwl6000_g2_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, - .shadow_reg_enable = false, /* TODO: fix bugs using this feature */ + .shadow_reg_enable = true, }; static const struct iwl_ht_params iwl6000_ht_params = { diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 8cebd7c363fc..51e1a69ffdda 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -884,7 +884,6 @@ static void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, if ((priv->bt_traffic_load != priv->last_bt_traffic_load) || (priv->bt_full_concurrent != full_concurrent)) { priv->bt_full_concurrent = full_concurrent; - priv->last_bt_traffic_load = priv->bt_traffic_load; /* Update uCode's rate table. */ tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index aea07aab3c9e..b31584e87bc7 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-sta.c @@ -772,7 +772,7 @@ void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx) ~IWL_STA_DRIVER_ACTIVE; priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS; - continue; + spin_unlock_bh(&priv->sta_lock); } /* * Rate scaling has already been initialized, send diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-drv.c b/trunk/drivers/net/wireless/iwlwifi/iwl-drv.c index d742900969ea..3c72bad0ae56 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -657,17 +657,17 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, return -EINVAL; } -static int iwl_alloc_ucode(struct iwl_drv *drv, - struct iwl_firmware_pieces *pieces, - enum iwl_ucode_type type) +static int alloc_pci_desc(struct iwl_drv *drv, + struct iwl_firmware_pieces *pieces, + enum iwl_ucode_type type) { int i; for (i = 0; i < IWL_UCODE_SECTION_MAX && get_sec_size(pieces, type, i); i++) if (iwl_alloc_fw_desc(drv, &(drv->fw.img[type].sec[i]), - get_sec(pieces, type, i))) - return -ENOMEM; + get_sec(pieces, type, i))) + return -1; return 0; } @@ -825,8 +825,8 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) * 1) unmodified from disk * 2) backup cache for save/restore during power-downs */ for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) - if (iwl_alloc_ucode(drv, &pieces, i)) - goto out_free_fw; + if (alloc_pci_desc(drv, &pieces, i)) + goto err_pci_alloc; /* Now that we can no longer fail, copy information */ @@ -866,7 +866,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) drv->op_mode = iwl_dvm_ops.start(drv->trans, drv->cfg, &drv->fw); if (!drv->op_mode) - goto out_free_fw; + goto out_unbind; return; @@ -877,7 +877,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) goto out_unbind; return; - out_free_fw: + err_pci_alloc: IWL_ERR(drv, "failed to allocate pci memory\n"); iwl_dealloc_ucode(drv); release_firmware(ucode_raw); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-phy-db.c b/trunk/drivers/net/wireless/iwlwifi/iwl-phy-db.c new file mode 100644 index 000000000000..f166955340fe --- /dev/null +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-phy-db.c @@ -0,0 +1,288 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#include +#include + +#include "iwl-debug.h" +#include "iwl-dev.h" + +#include "iwl-phy-db.h" + +#define CHANNEL_NUM_SIZE 4 /* num of channels in calib_ch size */ + +struct iwl_phy_db *iwl_phy_db_init(struct device *dev) +{ + struct iwl_phy_db *phy_db = kzalloc(sizeof(struct iwl_phy_db), + GFP_KERNEL); + + if (!phy_db) + return phy_db; + + phy_db->dev = dev; + + /* TODO: add default values of the phy db. */ + return phy_db; +} + +/* + * get phy db section: returns a pointer to a phy db section specified by + * type and channel group id. + */ +static struct iwl_phy_db_entry * +iwl_phy_db_get_section(struct iwl_phy_db *phy_db, + enum iwl_phy_db_section_type type, + u16 chg_id) +{ + if (!phy_db || type < 0 || type >= IWL_PHY_DB_MAX) + return NULL; + + switch (type) { + case IWL_PHY_DB_CFG: + return &phy_db->cfg; + case IWL_PHY_DB_CALIB_NCH: + return &phy_db->calib_nch; + case IWL_PHY_DB_CALIB_CH: + return &phy_db->calib_ch; + case IWL_PHY_DB_CALIB_CHG_PAPD: + if (chg_id < 0 || chg_id >= IWL_NUM_PAPD_CH_GROUPS) + return NULL; + return &phy_db->calib_ch_group_papd[chg_id]; + case IWL_PHY_DB_CALIB_CHG_TXP: + if (chg_id < 0 || chg_id >= IWL_NUM_TXP_CH_GROUPS) + return NULL; + return &phy_db->calib_ch_group_txp[chg_id]; + default: + return NULL; + } + return NULL; +} + +static void iwl_phy_db_free_section(struct iwl_phy_db *phy_db, + enum iwl_phy_db_section_type type, + u16 chg_id) +{ + struct iwl_phy_db_entry *entry = + iwl_phy_db_get_section(phy_db, type, chg_id); + if (!entry) + return; + + kfree(entry->data); + entry->data = NULL; + entry->size = 0; +} + +void iwl_phy_db_free(struct iwl_phy_db *phy_db) +{ + int i; + + if (!phy_db) + return; + + iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CFG, 0); + iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_NCH, 0); + iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CH, 0); + for (i = 0; i < IWL_NUM_PAPD_CH_GROUPS; i++) + iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_PAPD, i); + for (i = 0; i < IWL_NUM_TXP_CH_GROUPS; i++) + iwl_phy_db_free_section(phy_db, IWL_PHY_DB_CALIB_CHG_TXP, i); + + kfree(phy_db); +} + +int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, + enum iwl_phy_db_section_type type, u8 *data, + u16 size, gfp_t alloc_ctx) +{ + struct iwl_phy_db_entry *entry; + u16 chg_id = 0; + + if (!phy_db) + return -EINVAL; + + if (type == IWL_PHY_DB_CALIB_CHG_PAPD || + type == IWL_PHY_DB_CALIB_CHG_TXP) + chg_id = le16_to_cpup((__le16 *)data); + + entry = iwl_phy_db_get_section(phy_db, type, chg_id); + if (!entry) + return -EINVAL; + + kfree(entry->data); + entry->data = kmemdup(data, size, alloc_ctx); + if (!entry->data) { + entry->size = 0; + return -ENOMEM; + } + + entry->size = size; + + if (type == IWL_PHY_DB_CALIB_CH) { + phy_db->channel_num = le32_to_cpup((__le32 *)data); + phy_db->channel_size = + (size - CHANNEL_NUM_SIZE) / phy_db->channel_num; + } + + return 0; +} + +static int is_valid_channel(u16 ch_id) +{ + if (ch_id <= 14 || + (36 <= ch_id && ch_id <= 64 && ch_id % 4 == 0) || + (100 <= ch_id && ch_id <= 140 && ch_id % 4 == 0) || + (145 <= ch_id && ch_id <= 165 && ch_id % 4 == 1)) + return 1; + return 0; +} + +static u8 ch_id_to_ch_index(u16 ch_id) +{ + if (WARN_ON(!is_valid_channel(ch_id))) + return 0xff; + + if (ch_id <= 14) + return ch_id - 1; + if (ch_id <= 64) + return (ch_id + 20) / 4; + if (ch_id <= 140) + return (ch_id - 12) / 4; + return (ch_id - 13) / 4; +} + + +static u16 channel_id_to_papd(u16 ch_id) +{ + if (WARN_ON(!is_valid_channel(ch_id))) + return 0xff; + + if (1 <= ch_id && ch_id <= 14) + return 0; + if (36 <= ch_id && ch_id <= 64) + return 1; + if (100 <= ch_id && ch_id <= 140) + return 2; + return 3; +} + +static u16 channel_id_to_txp(struct iwl_phy_db *phy_db, u16 ch_id) +{ + struct iwl_phy_db_chg_txp *txp_chg; + int i; + u8 ch_index = ch_id_to_ch_index(ch_id); + if (ch_index == 0xff) + return 0xff; + + for (i = 0; i < IWL_NUM_TXP_CH_GROUPS; i++) { + txp_chg = (void *)phy_db->calib_ch_group_txp[i].data; + if (!txp_chg) + return 0xff; + /* + * Looking for the first channel group that its max channel is + * higher then wanted channel. + */ + if (le16_to_cpu(txp_chg->max_channel_idx) >= ch_index) + return i; + } + return 0xff; +} + +int iwl_phy_db_get_section_data(struct iwl_phy_db *phy_db, + enum iwl_phy_db_section_type type, u8 **data, + u16 *size, u16 ch_id) +{ + struct iwl_phy_db_entry *entry; + u32 channel_num; + u32 channel_size; + u16 ch_group_id = 0; + u16 index; + + if (!phy_db) + return -EINVAL; + + /* find wanted channel group */ + if (type == IWL_PHY_DB_CALIB_CHG_PAPD) + ch_group_id = channel_id_to_papd(ch_id); + else if (type == IWL_PHY_DB_CALIB_CHG_TXP) + ch_group_id = channel_id_to_txp(phy_db, ch_id); + + entry = iwl_phy_db_get_section(phy_db, type, ch_group_id); + if (!entry) + return -EINVAL; + + if (type == IWL_PHY_DB_CALIB_CH) { + index = ch_id_to_ch_index(ch_id); + channel_num = phy_db->channel_num; + channel_size = phy_db->channel_size; + if (index >= channel_num) { + IWL_ERR(phy_db, "Wrong channel number %d", ch_id); + return -EINVAL; + } + *data = entry->data + CHANNEL_NUM_SIZE + index * channel_size; + *size = channel_size; + } else { + *data = entry->data; + *size = entry->size; + } + return 0; +} diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-phy-db.h b/trunk/drivers/net/wireless/iwlwifi/iwl-phy-db.h new file mode 100644 index 000000000000..c34c6a9303ab --- /dev/null +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-phy-db.h @@ -0,0 +1,129 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __IWL_PHYDB_H__ +#define __IWL_PHYDB_H__ + +#include + +#define IWL_NUM_PAPD_CH_GROUPS 4 +#define IWL_NUM_TXP_CH_GROUPS 8 + +struct iwl_phy_db_entry { + u16 size; + u8 *data; +}; + +struct iwl_shared; + +/** + * struct iwl_phy_db - stores phy configuration and calibration data. + * + * @cfg: phy configuration. + * @calib_nch: non channel specific calibration data. + * @calib_ch: channel specific calibration data. + * @calib_ch_group_papd: calibration data related to papd channel group. + * @calib_ch_group_txp: calibration data related to tx power chanel group. + */ +struct iwl_phy_db { + struct iwl_phy_db_entry cfg; + struct iwl_phy_db_entry calib_nch; + struct iwl_phy_db_entry calib_ch; + struct iwl_phy_db_entry calib_ch_group_papd[IWL_NUM_PAPD_CH_GROUPS]; + struct iwl_phy_db_entry calib_ch_group_txp[IWL_NUM_TXP_CH_GROUPS]; + + u32 channel_num; + u32 channel_size; + + /* for an access to the logger */ + struct device *dev; +}; + +enum iwl_phy_db_section_type { + IWL_PHY_DB_CFG = 1, + IWL_PHY_DB_CALIB_NCH, + IWL_PHY_DB_CALIB_CH, + IWL_PHY_DB_CALIB_CHG_PAPD, + IWL_PHY_DB_CALIB_CHG_TXP, + IWL_PHY_DB_MAX +}; + +/* for parsing of tx power channel group data that comes from the firmware*/ +struct iwl_phy_db_chg_txp { + __le32 space; + __le16 max_channel_idx; +} __packed; + +struct iwl_phy_db *iwl_phy_db_init(struct device *dev); + +void iwl_phy_db_free(struct iwl_phy_db *phy_db); + +int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, + enum iwl_phy_db_section_type type, u8 *data, + u16 size, gfp_t alloc_ctx); + +int iwl_phy_db_get_section_data(struct iwl_phy_db *phy_db, + enum iwl_phy_db_section_type type, u8 **data, + u16 *size, u16 ch_id); + +#endif /* __IWL_PHYDB_H__ */ diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h b/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h index e959207c630a..6213c05a4b52 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h @@ -347,7 +347,7 @@ void iwl_trans_tx_queue_set_status(struct iwl_trans *trans, void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, int queue, int fifo, int sta_id, int tid, int frame_limit, u16 ssn); void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq, - enum dma_data_direction dma_dir); + int index, enum dma_data_direction dma_dir); int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index, struct sk_buff_head *skbs); int iwl_queue_space(const struct iwl_queue *q); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c b/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c index a8750238ee09..21a8a672fbb2 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c @@ -204,39 +204,33 @@ static void iwlagn_unmap_tfd(struct iwl_trans *trans, struct iwl_cmd_meta *meta, for (i = 1; i < num_tbs; i++) dma_unmap_single(trans->dev, iwl_tfd_tb_get_addr(tfd, i), iwl_tfd_tb_get_len(tfd, i), dma_dir); - - tfd->num_tbs = 0; } /** * iwlagn_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr] * @trans - transport private data * @txq - tx queue - * @dma_dir - the direction of the DMA mapping + * @index - the index of the TFD to be freed + *@dma_dir - the direction of the DMA mapping * * Does NOT advance any TFD circular buffer read/write indexes * Does NOT free the TFD itself (which is within circular buffer) */ void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq, - enum dma_data_direction dma_dir) + int index, enum dma_data_direction dma_dir) { struct iwl_tfd *tfd_tmp = txq->tfds; - /* rd_ptr is bounded by n_bd and idx is bounded by n_window */ - int rd_ptr = txq->q.read_ptr; - int idx = get_cmd_index(&txq->q, rd_ptr); - lockdep_assert_held(&txq->lock); - /* We have only q->n_window txq->entries, but we use q->n_bd tfds */ - iwlagn_unmap_tfd(trans, &txq->entries[idx].meta, - &tfd_tmp[rd_ptr], dma_dir); + iwlagn_unmap_tfd(trans, &txq->entries[index].meta, + &tfd_tmp[index], dma_dir); /* free SKB */ if (txq->entries) { struct sk_buff *skb; - skb = txq->entries[idx].skb; + skb = txq->entries[index].skb; /* Can be called from irqs-disabled context * If skb is not NULL, it means that the whole queue is being @@ -244,7 +238,7 @@ void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq, */ if (skb) { iwl_op_mode_free_skb(trans->op_mode, skb); - txq->entries[idx].skb = NULL; + txq->entries[index].skb = NULL; } } } @@ -979,7 +973,7 @@ int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index, iwlagn_txq_inval_byte_cnt_tbl(trans, txq); - iwlagn_txq_free_tfd(trans, txq, DMA_TO_DEVICE); + iwlagn_txq_free_tfd(trans, txq, txq->q.read_ptr, DMA_TO_DEVICE); freed++; } diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c index ec6fb395b84d..2e57161854b9 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c @@ -435,7 +435,9 @@ static void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id) spin_lock_bh(&txq->lock); while (q->write_ptr != q->read_ptr) { - iwlagn_txq_free_tfd(trans, txq, dma_dir); + /* The read_ptr needs to bound by q->n_window */ + iwlagn_txq_free_tfd(trans, txq, get_cmd_index(q, q->read_ptr), + dma_dir); q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); } spin_unlock_bh(&txq->lock); diff --git a/trunk/drivers/net/wireless/ti/wl1251/sdio.c b/trunk/drivers/net/wireless/ti/wl1251/sdio.c index e2750a12c6f1..1b851f650e07 100644 --- a/trunk/drivers/net/wireless/ti/wl1251/sdio.c +++ b/trunk/drivers/net/wireless/ti/wl1251/sdio.c @@ -260,7 +260,6 @@ static int wl1251_sdio_probe(struct sdio_func *func, } if (wl->irq) { - irq_set_status_flags(wl->irq, IRQ_NOAUTOEN); ret = request_irq(wl->irq, wl1251_line_irq, 0, "wl1251", wl); if (ret < 0) { wl1251_error("request_irq() failed: %d", ret); @@ -268,6 +267,7 @@ static int wl1251_sdio_probe(struct sdio_func *func, } irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); + disable_irq(wl->irq); wl1251_sdio_ops.enable_irq = wl1251_enable_line_irq; wl1251_sdio_ops.disable_irq = wl1251_disable_line_irq; diff --git a/trunk/drivers/net/wireless/ti/wl1251/spi.c b/trunk/drivers/net/wireless/ti/wl1251/spi.c index 87f6305bda2c..6248c354fc5c 100644 --- a/trunk/drivers/net/wireless/ti/wl1251/spi.c +++ b/trunk/drivers/net/wireless/ti/wl1251/spi.c @@ -281,7 +281,6 @@ static int __devinit wl1251_spi_probe(struct spi_device *spi) wl->use_eeprom = pdata->use_eeprom; - irq_set_status_flags(wl->irq, IRQ_NOAUTOEN); ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl); if (ret < 0) { wl1251_error("request_irq() failed: %d", ret); @@ -290,6 +289,8 @@ static int __devinit wl1251_spi_probe(struct spi_device *spi) irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); + disable_irq(wl->irq); + ret = wl1251_init_ieee80211(wl); if (ret) goto out_irq; diff --git a/trunk/drivers/net/wireless/ti/wlcore/acx.c b/trunk/drivers/net/wireless/ti/wlcore/acx.c index f3d6fa508269..509aa881d790 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/acx.c +++ b/trunk/drivers/net/wireless/ti/wlcore/acx.c @@ -1715,7 +1715,6 @@ int wl12xx_acx_config_hangover(struct wl1271 *wl) } -#ifdef CONFIG_PM /* Set the global behaviour of RX filters - On/Off + default action */ int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable, enum rx_filter_action action) @@ -1795,4 +1794,3 @@ int wl1271_acx_set_rx_filter(struct wl1271 *wl, u8 index, bool enable, kfree(acx); return ret; } -#endif /* CONFIG_PM */ diff --git a/trunk/drivers/net/wireless/ti/wlcore/acx.h b/trunk/drivers/net/wireless/ti/wlcore/acx.h index e6a74869a5ff..8106b2ebfe60 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/acx.h +++ b/trunk/drivers/net/wireless/ti/wlcore/acx.h @@ -1330,11 +1330,9 @@ int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); int wl1271_acx_fm_coex(struct wl1271 *wl); int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl); int wl12xx_acx_config_hangover(struct wl1271 *wl); - -#ifdef CONFIG_PM int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable, enum rx_filter_action action); int wl1271_acx_set_rx_filter(struct wl1271 *wl, u8 index, bool enable, struct wl12xx_rx_filter *filter); -#endif /* CONFIG_PM */ + #endif /* __WL1271_ACX_H__ */ diff --git a/trunk/drivers/net/wireless/ti/wlcore/rx.c b/trunk/drivers/net/wireless/ti/wlcore/rx.c index d6a3c6b07827..1f1d9488dfb6 100644 --- a/trunk/drivers/net/wireless/ti/wlcore/rx.c +++ b/trunk/drivers/net/wireless/ti/wlcore/rx.c @@ -279,7 +279,6 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status) wl12xx_rearm_rx_streaming(wl, active_hlids); } -#ifdef CONFIG_PM int wl1271_rx_filter_enable(struct wl1271 *wl, int index, bool enable, struct wl12xx_rx_filter *filter) @@ -315,4 +314,3 @@ void wl1271_rx_filter_clear_all(struct wl1271 *wl) wl1271_rx_filter_enable(wl, i, 0, NULL); } } -#endif /* CONFIG_PM */ diff --git a/trunk/drivers/net/xen-netback/netback.c b/trunk/drivers/net/xen-netback/netback.c index f4a6fcaeffb1..2596401308a8 100644 --- a/trunk/drivers/net/xen-netback/netback.c +++ b/trunk/drivers/net/xen-netback/netback.c @@ -325,7 +325,8 @@ unsigned int xen_netbk_count_skb_slots(struct xenvif *vif, struct sk_buff *skb) unsigned int count; int i, copy_off; - count = DIV_ROUND_UP(skb_headlen(skb), PAGE_SIZE); + count = DIV_ROUND_UP( + offset_in_page(skb->data)+skb_headlen(skb), PAGE_SIZE); copy_off = skb_headlen(skb) % PAGE_SIZE; diff --git a/trunk/drivers/nfc/pn544_hci.c b/trunk/drivers/nfc/pn544_hci.c index 281f18c2fb82..46f4a9f9f5e4 100644 --- a/trunk/drivers/nfc/pn544_hci.c +++ b/trunk/drivers/nfc/pn544_hci.c @@ -232,7 +232,7 @@ static int pn544_hci_i2c_write(struct i2c_client *client, u8 *buf, int len) static int check_crc(u8 *buf, int buflen) { - int len; + u8 len; u16 crc; len = buf[0] + 1; diff --git a/trunk/drivers/of/of_pci_irq.c b/trunk/drivers/of/of_pci_irq.c index 677053813211..93125163dea2 100644 --- a/trunk/drivers/of/of_pci_irq.c +++ b/trunk/drivers/of/of_pci_irq.c @@ -15,7 +15,7 @@ * PCI tree until an device-node is found, at which point it will finish * resolving using the OF tree walking. */ -int of_irq_map_pci(const struct pci_dev *pdev, struct of_irq *out_irq) +int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) { struct device_node *dn, *ppnode; struct pci_dev *ppdev; diff --git a/trunk/drivers/pci/pci.c b/trunk/drivers/pci/pci.c index 447e83472c01..8f169002dc7e 100644 --- a/trunk/drivers/pci/pci.c +++ b/trunk/drivers/pci/pci.c @@ -2370,7 +2370,7 @@ void pci_enable_acs(struct pci_dev *dev) * number is always 0 (see the Implementation Note in section 2.2.8.1 of * the PCI Express Base Specification, Revision 2.1) */ -u8 pci_swizzle_interrupt_pin(const struct pci_dev *dev, u8 pin) +u8 pci_swizzle_interrupt_pin(struct pci_dev *dev, u8 pin) { int slot; diff --git a/trunk/drivers/pinctrl/pinctrl-nomadik.c b/trunk/drivers/pinctrl/pinctrl-nomadik.c index b26395d16347..b8e01c3eaa95 100644 --- a/trunk/drivers/pinctrl/pinctrl-nomadik.c +++ b/trunk/drivers/pinctrl/pinctrl-nomadik.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -1689,34 +1688,18 @@ static struct pinctrl_desc nmk_pinctrl_desc = { .owner = THIS_MODULE, }; -static const struct of_device_id nmk_pinctrl_match[] = { - { - .compatible = "stericsson,nmk_pinctrl", - .data = (void *)PINCTRL_NMK_DB8500, - }, - {}, -}; - static int __devinit nmk_pinctrl_probe(struct platform_device *pdev) { const struct platform_device_id *platid = platform_get_device_id(pdev); - struct device_node *np = pdev->dev.of_node; struct nmk_pinctrl *npct; - unsigned int version = 0; int i; npct = devm_kzalloc(&pdev->dev, sizeof(*npct), GFP_KERNEL); if (!npct) return -ENOMEM; - if (platid) - version = platid->driver_data; - else if (np) - version = (unsigned int) - of_match_device(nmk_pinctrl_match, &pdev->dev)->data; - /* Poke in other ASIC variants here */ - if (version == PINCTRL_NMK_DB8500) + if (platid->driver_data == PINCTRL_NMK_DB8500) nmk_pinctrl_db8500_init(&npct->soc); /* @@ -1775,7 +1758,6 @@ static struct platform_driver nmk_pinctrl_driver = { .driver = { .owner = THIS_MODULE, .name = "pinctrl-nomadik", - .of_match_table = nmk_pinctrl_match, }, .probe = nmk_pinctrl_probe, .id_table = nmk_pinctrl_id, diff --git a/trunk/drivers/platform/x86/acer-wmi.c b/trunk/drivers/platform/x86/acer-wmi.c index ce875dc365e5..c1a3fd8e1243 100644 --- a/trunk/drivers/platform/x86/acer-wmi.c +++ b/trunk/drivers/platform/x86/acer-wmi.c @@ -523,30 +523,6 @@ static const struct dmi_system_id video_vendor_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"), }, }, - { - .callback = video_set_backlight_video_vendor, - .ident = "Acer Extensa 5235", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5235"), - }, - }, - { - .callback = video_set_backlight_video_vendor, - .ident = "Acer TravelMate 5760", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5760"), - }, - }, - { - .callback = video_set_backlight_video_vendor, - .ident = "Acer Aspire 5750", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), - DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"), - }, - }, {} }; diff --git a/trunk/drivers/platform/x86/apple-gmux.c b/trunk/drivers/platform/x86/apple-gmux.c index 694a15a56230..8a582bdfdc76 100644 --- a/trunk/drivers/platform/x86/apple-gmux.c +++ b/trunk/drivers/platform/x86/apple-gmux.c @@ -87,9 +87,6 @@ static int gmux_update_status(struct backlight_device *bd) struct apple_gmux_data *gmux_data = bl_get_data(bd); u32 brightness = bd->props.brightness; - if (bd->props.state & BL_CORE_SUSPENDED) - return 0; - /* * Older gmux versions require writing out lower bytes first then * setting the upper byte to 0 to flush the values. Newer versions @@ -105,7 +102,6 @@ static int gmux_update_status(struct backlight_device *bd) } static const struct backlight_ops gmux_bl_ops = { - .options = BL_CORE_SUSPENDRESUME, .get_brightness = gmux_get_brightness, .update_status = gmux_update_status, }; diff --git a/trunk/drivers/platform/x86/dell-laptop.c b/trunk/drivers/platform/x86/dell-laptop.c index 5f78aac9b163..e6c08ee8d46c 100644 --- a/trunk/drivers/platform/x86/dell-laptop.c +++ b/trunk/drivers/platform/x86/dell-laptop.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -89,8 +90,11 @@ static struct platform_driver platform_driver = { static struct platform_device *platform_device; static struct backlight_device *dell_backlight_device; +static struct rfkill *wifi_rfkill; +static struct rfkill *bluetooth_rfkill; +static struct rfkill *wwan_rfkill; -static const struct dmi_system_id dell_device_table[] __initconst = { +static const struct dmi_system_id __initdata dell_device_table[] = { { .ident = "Dell laptop", .matches = { @@ -115,94 +119,96 @@ static const struct dmi_system_id dell_device_table[] __initconst = { }; MODULE_DEVICE_TABLE(dmi, dell_device_table); -static struct dmi_system_id __devinitdata dell_quirks[] = { +static struct dmi_system_id __devinitdata dell_blacklist[] = { + /* Supported by compal-laptop */ { - .callback = dmi_matched, - .ident = "Dell Vostro V130", + .ident = "Dell Mini 9", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V130"), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"), }, - .driver_data = &quirk_dell_vostro_v130, }, { - .callback = dmi_matched, - .ident = "Dell Vostro V131", + .ident = "Dell Mini 10", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"), }, - .driver_data = &quirk_dell_vostro_v130, }, { - .callback = dmi_matched, - .ident = "Dell Vostro 3350", + .ident = "Dell Mini 10v", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3350"), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"), }, - .driver_data = &quirk_dell_vostro_v130, }, { - .callback = dmi_matched, - .ident = "Dell Vostro 3555", + .ident = "Dell Mini 1012", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3555"), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"), }, - .driver_data = &quirk_dell_vostro_v130, }, { - .callback = dmi_matched, - .ident = "Dell Inspiron N311z", + .ident = "Dell Inspiron 11z", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron N311z"), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"), + }, + }, + { + .ident = "Dell Mini 12", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"), }, - .driver_data = &quirk_dell_vostro_v130, }, + {} +}; + +static struct dmi_system_id __devinitdata dell_quirks[] = { { .callback = dmi_matched, - .ident = "Dell Inspiron M5110", + .ident = "Dell Vostro V130", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron M5110"), + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V130"), }, .driver_data = &quirk_dell_vostro_v130, }, { .callback = dmi_matched, - .ident = "Dell Vostro 3360", + .ident = "Dell Vostro V131", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3360"), + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"), }, .driver_data = &quirk_dell_vostro_v130, }, { .callback = dmi_matched, - .ident = "Dell Vostro 3460", + .ident = "Dell Vostro 3555", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3460"), + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3555"), }, .driver_data = &quirk_dell_vostro_v130, }, { .callback = dmi_matched, - .ident = "Dell Vostro 3560", + .ident = "Dell Inspiron N311z", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3560"), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron N311z"), }, .driver_data = &quirk_dell_vostro_v130, }, { .callback = dmi_matched, - .ident = "Dell Vostro 3450", + .ident = "Dell Inspiron M5110", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Dell System Vostro 3450"), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron M5110"), }, .driver_data = &quirk_dell_vostro_v130, }, @@ -299,6 +305,94 @@ dell_send_request(struct calling_interface_buffer *buffer, int class, return buffer; } +/* Derived from information in DellWirelessCtl.cpp: + Class 17, select 11 is radio control. It returns an array of 32-bit values. + + Input byte 0 = 0: Wireless information + + result[0]: return code + result[1]: + Bit 0: Hardware switch supported + Bit 1: Wifi locator supported + Bit 2: Wifi is supported + Bit 3: Bluetooth is supported + Bit 4: WWAN is supported + Bit 5: Wireless keyboard supported + Bits 6-7: Reserved + Bit 8: Wifi is installed + Bit 9: Bluetooth is installed + Bit 10: WWAN is installed + Bits 11-15: Reserved + Bit 16: Hardware switch is on + Bit 17: Wifi is blocked + Bit 18: Bluetooth is blocked + Bit 19: WWAN is blocked + Bits 20-31: Reserved + result[2]: NVRAM size in bytes + result[3]: NVRAM format version number + + Input byte 0 = 2: Wireless switch configuration + result[0]: return code + result[1]: + Bit 0: Wifi controlled by switch + Bit 1: Bluetooth controlled by switch + Bit 2: WWAN controlled by switch + Bits 3-6: Reserved + Bit 7: Wireless switch config locked + Bit 8: Wifi locator enabled + Bits 9-14: Reserved + Bit 15: Wifi locator setting locked + Bits 16-31: Reserved +*/ + +static int dell_rfkill_set(void *data, bool blocked) +{ + int disable = blocked ? 1 : 0; + unsigned long radio = (unsigned long)data; + int hwswitch_bit = (unsigned long)data - 1; + int ret = 0; + + get_buffer(); + dell_send_request(buffer, 17, 11); + + /* If the hardware switch controls this radio, and the hardware + switch is disabled, don't allow changing the software state */ + if ((hwswitch_state & BIT(hwswitch_bit)) && + !(buffer->output[1] & BIT(16))) { + ret = -EINVAL; + goto out; + } + + buffer->input[0] = (1 | (radio<<8) | (disable << 16)); + dell_send_request(buffer, 17, 11); + +out: + release_buffer(); + return ret; +} + +static void dell_rfkill_query(struct rfkill *rfkill, void *data) +{ + int status; + int bit = (unsigned long)data + 16; + int hwswitch_bit = (unsigned long)data - 1; + + get_buffer(); + dell_send_request(buffer, 17, 11); + status = buffer->output[1]; + release_buffer(); + + rfkill_set_sw_state(rfkill, !!(status & BIT(bit))); + + if (hwswitch_state & (BIT(hwswitch_bit))) + rfkill_set_hw_state(rfkill, !(status & BIT(16))); +} + +static const struct rfkill_ops dell_rfkill_ops = { + .set_block = dell_rfkill_set, + .query = dell_rfkill_query, +}; + static struct dentry *dell_laptop_dir; static int dell_debugfs_show(struct seq_file *s, void *data) @@ -368,6 +462,108 @@ static const struct file_operations dell_debugfs_fops = { .release = single_release, }; +static void dell_update_rfkill(struct work_struct *ignored) +{ + if (wifi_rfkill) + dell_rfkill_query(wifi_rfkill, (void *)1); + if (bluetooth_rfkill) + dell_rfkill_query(bluetooth_rfkill, (void *)2); + if (wwan_rfkill) + dell_rfkill_query(wwan_rfkill, (void *)3); +} +static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill); + + +static int __init dell_setup_rfkill(void) +{ + int status; + int ret; + + if (dmi_check_system(dell_blacklist)) { + pr_info("Blacklisted hardware detected - not enabling rfkill\n"); + return 0; + } + + get_buffer(); + dell_send_request(buffer, 17, 11); + status = buffer->output[1]; + buffer->input[0] = 0x2; + dell_send_request(buffer, 17, 11); + hwswitch_state = buffer->output[1]; + release_buffer(); + + if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { + wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev, + RFKILL_TYPE_WLAN, + &dell_rfkill_ops, (void *) 1); + if (!wifi_rfkill) { + ret = -ENOMEM; + goto err_wifi; + } + ret = rfkill_register(wifi_rfkill); + if (ret) + goto err_wifi; + } + + if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { + bluetooth_rfkill = rfkill_alloc("dell-bluetooth", + &platform_device->dev, + RFKILL_TYPE_BLUETOOTH, + &dell_rfkill_ops, (void *) 2); + if (!bluetooth_rfkill) { + ret = -ENOMEM; + goto err_bluetooth; + } + ret = rfkill_register(bluetooth_rfkill); + if (ret) + goto err_bluetooth; + } + + if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { + wwan_rfkill = rfkill_alloc("dell-wwan", + &platform_device->dev, + RFKILL_TYPE_WWAN, + &dell_rfkill_ops, (void *) 3); + if (!wwan_rfkill) { + ret = -ENOMEM; + goto err_wwan; + } + ret = rfkill_register(wwan_rfkill); + if (ret) + goto err_wwan; + } + + return 0; +err_wwan: + rfkill_destroy(wwan_rfkill); + if (bluetooth_rfkill) + rfkill_unregister(bluetooth_rfkill); +err_bluetooth: + rfkill_destroy(bluetooth_rfkill); + if (wifi_rfkill) + rfkill_unregister(wifi_rfkill); +err_wifi: + rfkill_destroy(wifi_rfkill); + + return ret; +} + +static void dell_cleanup_rfkill(void) +{ + if (wifi_rfkill) { + rfkill_unregister(wifi_rfkill); + rfkill_destroy(wifi_rfkill); + } + if (bluetooth_rfkill) { + rfkill_unregister(bluetooth_rfkill); + rfkill_destroy(bluetooth_rfkill); + } + if (wwan_rfkill) { + rfkill_unregister(wwan_rfkill); + rfkill_destroy(wwan_rfkill); + } +} + static int dell_send_intensity(struct backlight_device *bd) { int ret = 0; @@ -459,6 +655,30 @@ static void touchpad_led_exit(void) led_classdev_unregister(&touchpad_led); } +static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str, + struct serio *port) +{ + static bool extended; + + if (str & 0x20) + return false; + + if (unlikely(data == 0xe0)) { + extended = true; + return false; + } else if (unlikely(extended)) { + switch (data) { + case 0x8: + schedule_delayed_work(&dell_rfkill_work, + round_jiffies_relative(HZ)); + break; + } + extended = false; + } + + return false; +} + static int __init dell_init(void) { int max_intensity = 0; @@ -500,10 +720,26 @@ static int __init dell_init(void) goto fail_buffer; buffer = page_address(bufferpage); + ret = dell_setup_rfkill(); + + if (ret) { + pr_warn("Unable to setup rfkill\n"); + goto fail_rfkill; + } + + ret = i8042_install_filter(dell_laptop_i8042_filter); + if (ret) { + pr_warn("Unable to install key filter\n"); + goto fail_filter; + } + if (quirks && quirks->touchpad_led) touchpad_led_init(&platform_device->dev); dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL); + if (dell_laptop_dir != NULL) + debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL, + &dell_debugfs_fops); #ifdef CONFIG_ACPI /* In the event of an ACPI backlight being available, don't @@ -546,6 +782,11 @@ static int __init dell_init(void) return 0; fail_backlight: + i8042_remove_filter(dell_laptop_i8042_filter); + cancel_delayed_work_sync(&dell_rfkill_work); +fail_filter: + dell_cleanup_rfkill(); +fail_rfkill: free_page((unsigned long)bufferpage); fail_buffer: platform_device_del(platform_device); @@ -563,7 +804,10 @@ static void __exit dell_exit(void) debugfs_remove_recursive(dell_laptop_dir); if (quirks && quirks->touchpad_led) touchpad_led_exit(); + i8042_remove_filter(dell_laptop_i8042_filter); + cancel_delayed_work_sync(&dell_rfkill_work); backlight_device_unregister(dell_backlight_device); + dell_cleanup_rfkill(); if (platform_device) { platform_device_unregister(platform_device); platform_driver_unregister(&platform_driver); diff --git a/trunk/drivers/platform/x86/fujitsu-tablet.c b/trunk/drivers/platform/x86/fujitsu-tablet.c index da267eae8ba8..580d80a73c3a 100644 --- a/trunk/drivers/platform/x86/fujitsu-tablet.c +++ b/trunk/drivers/platform/x86/fujitsu-tablet.c @@ -16,8 +16,6 @@ * 59 Temple Place Suite 330, Boston, MA 02111-1307, USA. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include #include @@ -36,8 +34,7 @@ #define ACPI_FUJITSU_CLASS "fujitsu" #define INVERT_TABLET_MODE_BIT 0x01 -#define INVERT_DOCK_STATE_BIT 0x02 -#define FORCE_TABLET_MODE_IF_UNDOCK 0x04 +#define FORCE_TABLET_MODE_IF_UNDOCK 0x02 #define KEYMAP_LEN 16 @@ -164,8 +161,6 @@ static void fujitsu_send_state(void) state = fujitsu_read_register(0xdd); dock = state & 0x02; - if (fujitsu.config.quirks & INVERT_DOCK_STATE_BIT) - dock = !dock; if ((fujitsu.config.quirks & FORCE_TABLET_MODE_IF_UNDOCK) && (!dock)) { tablet_mode = 1; @@ -226,6 +221,9 @@ static int __devinit input_fujitsu_setup(struct device *parent, input_set_capability(idev, EV_SW, SW_DOCK); input_set_capability(idev, EV_SW, SW_TABLET_MODE); + input_set_capability(idev, EV_SW, SW_DOCK); + input_set_capability(idev, EV_SW, SW_TABLET_MODE); + error = input_register_device(idev); if (error) { input_free_device(idev); @@ -277,31 +275,25 @@ static irqreturn_t fujitsu_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void __devinit fujitsu_dmi_common(const struct dmi_system_id *dmi) +static int __devinit fujitsu_dmi_default(const struct dmi_system_id *dmi) { - pr_info("%s\n", dmi->ident); + printk(KERN_INFO MODULENAME ": %s\n", dmi->ident); memcpy(fujitsu.config.keymap, dmi->driver_data, sizeof(fujitsu.config.keymap)); -} - -static int __devinit fujitsu_dmi_lifebook(const struct dmi_system_id *dmi) -{ - fujitsu_dmi_common(dmi); - fujitsu.config.quirks |= INVERT_TABLET_MODE_BIT; return 1; } static int __devinit fujitsu_dmi_stylistic(const struct dmi_system_id *dmi) { - fujitsu_dmi_common(dmi); + fujitsu_dmi_default(dmi); fujitsu.config.quirks |= FORCE_TABLET_MODE_IF_UNDOCK; - fujitsu.config.quirks |= INVERT_DOCK_STATE_BIT; + fujitsu.config.quirks |= INVERT_TABLET_MODE_BIT; return 1; } static struct dmi_system_id dmi_ids[] __initconst = { { - .callback = fujitsu_dmi_lifebook, + .callback = fujitsu_dmi_default, .ident = "Fujitsu Siemens P/T Series", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), @@ -310,7 +302,7 @@ static struct dmi_system_id dmi_ids[] __initconst = { .driver_data = keymap_Lifebook_Tseries }, { - .callback = fujitsu_dmi_lifebook, + .callback = fujitsu_dmi_default, .ident = "Fujitsu Lifebook T Series", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), @@ -328,7 +320,7 @@ static struct dmi_system_id dmi_ids[] __initconst = { .driver_data = keymap_Stylistic_Tseries }, { - .callback = fujitsu_dmi_lifebook, + .callback = fujitsu_dmi_default, .ident = "Fujitsu LifeBook U810", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), @@ -355,7 +347,7 @@ static struct dmi_system_id dmi_ids[] __initconst = { .driver_data = keymap_Stylistic_ST5xxx }, { - .callback = fujitsu_dmi_lifebook, + .callback = fujitsu_dmi_default, .ident = "Unknown (using defaults)", .matches = { DMI_MATCH(DMI_SYS_VENDOR, ""), @@ -481,6 +473,6 @@ module_exit(fujitsu_module_exit); MODULE_AUTHOR("Robert Gerlach "); MODULE_DESCRIPTION("Fujitsu tablet pc extras driver"); MODULE_LICENSE("GPL"); -MODULE_VERSION("2.5"); +MODULE_VERSION("2.4"); MODULE_DEVICE_TABLE(acpi, fujitsu_ids); diff --git a/trunk/drivers/platform/x86/hdaps.c b/trunk/drivers/platform/x86/hdaps.c index 24a3ae065f1b..7387f97a2941 100644 --- a/trunk/drivers/platform/x86/hdaps.c +++ b/trunk/drivers/platform/x86/hdaps.c @@ -2,7 +2,7 @@ * hdaps.c - driver for IBM's Hard Drive Active Protection System * * Copyright (C) 2005 Robert Love - * Copyright (C) 2005 Jesper Juhl + * Copyright (C) 2005 Jesper Juhl * * The HardDisk Active Protection System (hdaps) is present in IBM ThinkPads * starting with the R40, T41, and X40. It provides a basic two-axis diff --git a/trunk/drivers/platform/x86/hp-wmi.c b/trunk/drivers/platform/x86/hp-wmi.c index 387183a2d6dd..e2faa3cbb792 100644 --- a/trunk/drivers/platform/x86/hp-wmi.c +++ b/trunk/drivers/platform/x86/hp-wmi.c @@ -634,8 +634,6 @@ static int __devinit hp_wmi_rfkill_setup(struct platform_device *device) RFKILL_TYPE_WLAN, &hp_wmi_rfkill_ops, (void *) HPWMI_WIFI); - if (!wifi_rfkill) - return -ENOMEM; rfkill_init_sw_state(wifi_rfkill, hp_wmi_get_sw_state(HPWMI_WIFI)); rfkill_set_hw_state(wifi_rfkill, @@ -650,10 +648,6 @@ static int __devinit hp_wmi_rfkill_setup(struct platform_device *device) RFKILL_TYPE_BLUETOOTH, &hp_wmi_rfkill_ops, (void *) HPWMI_BLUETOOTH); - if (!bluetooth_rfkill) { - err = -ENOMEM; - goto register_wifi_error; - } rfkill_init_sw_state(bluetooth_rfkill, hp_wmi_get_sw_state(HPWMI_BLUETOOTH)); rfkill_set_hw_state(bluetooth_rfkill, @@ -668,10 +662,6 @@ static int __devinit hp_wmi_rfkill_setup(struct platform_device *device) RFKILL_TYPE_WWAN, &hp_wmi_rfkill_ops, (void *) HPWMI_WWAN); - if (!wwan_rfkill) { - err = -ENOMEM; - goto register_bluetooth_error; - } rfkill_init_sw_state(wwan_rfkill, hp_wmi_get_sw_state(HPWMI_WWAN)); rfkill_set_hw_state(wwan_rfkill, diff --git a/trunk/drivers/platform/x86/ideapad-laptop.c b/trunk/drivers/platform/x86/ideapad-laptop.c index 4f20f8dd3d7c..ac902f7a9baa 100644 --- a/trunk/drivers/platform/x86/ideapad-laptop.c +++ b/trunk/drivers/platform/x86/ideapad-laptop.c @@ -194,6 +194,7 @@ static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data) /* * debugfs */ +#define DEBUGFS_EVENT_LEN (4096) static int debugfs_status_show(struct seq_file *s, void *data) { unsigned long value; @@ -314,7 +315,7 @@ static int __devinit ideapad_debugfs_init(struct ideapad_private *priv) node = debugfs_create_file("status", S_IRUGO, priv->debug, NULL, &debugfs_status_fops); if (!node) { - pr_err("failed to create status in debugfs"); + pr_err("failed to create event in debugfs"); goto errout; } @@ -784,10 +785,6 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event) case 9: ideapad_sync_rfk_state(priv); break; - case 13: - case 6: - ideapad_input_report(priv, vpc_bit); - break; case 4: ideapad_backlight_notify_brightness(priv); break; @@ -798,7 +795,7 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event) ideapad_backlight_notify_power(priv); break; default: - pr_info("Unknown event: %lu\n", vpc_bit); + ideapad_input_report(priv, vpc_bit); } } } diff --git a/trunk/drivers/platform/x86/sony-laptop.c b/trunk/drivers/platform/x86/sony-laptop.c index 210d4ae547c2..8a51795aa02a 100644 --- a/trunk/drivers/platform/x86/sony-laptop.c +++ b/trunk/drivers/platform/x86/sony-laptop.c @@ -141,27 +141,6 @@ MODULE_PARM_DESC(kbd_backlight_timeout, "(default: 0)"); static void sony_nc_kbd_backlight_resume(void); -static int sony_nc_kbd_backlight_setup(struct platform_device *pd, - unsigned int handle); -static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd); - -static int sony_nc_battery_care_setup(struct platform_device *pd, - unsigned int handle); -static void sony_nc_battery_care_cleanup(struct platform_device *pd); - -static int sony_nc_thermal_setup(struct platform_device *pd); -static void sony_nc_thermal_cleanup(struct platform_device *pd); -static void sony_nc_thermal_resume(void); - -static int sony_nc_lid_resume_setup(struct platform_device *pd); -static void sony_nc_lid_resume_cleanup(struct platform_device *pd); - -static int sony_nc_highspeed_charging_setup(struct platform_device *pd); -static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd); - -static int sony_nc_touchpad_setup(struct platform_device *pd, - unsigned int handle); -static void sony_nc_touchpad_cleanup(struct platform_device *pd); enum sony_nc_rfkill { SONY_WIFI, @@ -174,9 +153,6 @@ enum sony_nc_rfkill { static int sony_rfkill_handle; static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL]; static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900}; -static int sony_nc_rfkill_setup(struct acpi_device *device, - unsigned int handle); -static void sony_nc_rfkill_cleanup(void); static void sony_nc_rfkill_update(void); /*********** Input Devices ***********/ @@ -715,97 +691,59 @@ static struct acpi_device *sony_nc_acpi_device = NULL; /* * acpi_evaluate_object wrappers - * all useful calls into SNC methods take one or zero parameters and return - * integers or arrays. */ -static union acpi_object *__call_snc_method(acpi_handle handle, char *method, - u64 *value) +static int acpi_callgetfunc(acpi_handle handle, char *name, int *result) { - union acpi_object *result = NULL; - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_buffer output; + union acpi_object out_obj; acpi_status status; - if (value) { - struct acpi_object_list params; - union acpi_object in; - in.type = ACPI_TYPE_INTEGER; - in.integer.value = *value; - params.count = 1; - params.pointer = ∈ - status = acpi_evaluate_object(handle, method, ¶ms, &output); - dprintk("__call_snc_method: [%s:0x%.8x%.8x]\n", method, - (unsigned int)(*value >> 32), - (unsigned int)*value & 0xffffffff); - } else { - status = acpi_evaluate_object(handle, method, NULL, &output); - dprintk("__call_snc_method: [%s]\n", method); - } - - if (ACPI_FAILURE(status)) { - pr_err("Failed to evaluate [%s]\n", method); - return NULL; - } - - result = (union acpi_object *) output.pointer; - if (!result) - dprintk("No return object [%s]\n", method); - - return result; -} - -static int sony_nc_int_call(acpi_handle handle, char *name, int *value, - int *result) -{ - union acpi_object *object = NULL; - if (value) { - u64 v = *value; - object = __call_snc_method(handle, name, &v); - } else - object = __call_snc_method(handle, name, NULL); - - if (!object) - return -EINVAL; + output.length = sizeof(out_obj); + output.pointer = &out_obj; - if (object->type != ACPI_TYPE_INTEGER) { - pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n", - ACPI_TYPE_INTEGER, object->type); - kfree(object); - return -EINVAL; + status = acpi_evaluate_object(handle, name, NULL, &output); + if ((status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER)) { + *result = out_obj.integer.value; + return 0; } - if (result) - *result = object->integer.value; + pr_warn("acpi_callreadfunc failed\n"); - kfree(object); - return 0; + return -1; } -#define MIN(a, b) (a > b ? b : a) -static int sony_nc_buffer_call(acpi_handle handle, char *name, u64 *value, - void *buffer, size_t buflen) +static int acpi_callsetfunc(acpi_handle handle, char *name, int value, + int *result) { - size_t len = len; - union acpi_object *object = __call_snc_method(handle, name, value); - - if (!object) - return -EINVAL; + struct acpi_object_list params; + union acpi_object in_obj; + struct acpi_buffer output; + union acpi_object out_obj; + acpi_status status; - if (object->type == ACPI_TYPE_BUFFER) - len = MIN(buflen, object->buffer.length); + params.count = 1; + params.pointer = &in_obj; + in_obj.type = ACPI_TYPE_INTEGER; + in_obj.integer.value = value; - else if (object->type == ACPI_TYPE_INTEGER) - len = MIN(buflen, sizeof(object->integer.value)); + output.length = sizeof(out_obj); + output.pointer = &out_obj; - else { - pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n", - ACPI_TYPE_BUFFER, object->type); - kfree(object); - return -EINVAL; + status = acpi_evaluate_object(handle, name, ¶ms, &output); + if (status == AE_OK) { + if (result != NULL) { + if (out_obj.type != ACPI_TYPE_INTEGER) { + pr_warn("acpi_evaluate_object bad return type\n"); + return -1; + } + *result = out_obj.integer.value; + } + return 0; } - memcpy(buffer, object->buffer.pointer, len); - kfree(object); - return 0; + pr_warn("acpi_evaluate_object failed\n"); + + return -1; } struct sony_nc_handles { @@ -832,17 +770,16 @@ static ssize_t sony_nc_handles_show(struct device *dev, static int sony_nc_handles_setup(struct platform_device *pd) { - int i, r, result, arg; + int i; + int result; handles = kzalloc(sizeof(*handles), GFP_KERNEL); if (!handles) return -ENOMEM; for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { - arg = i + 0x20; - r = sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg, - &result); - if (!r) { + if (!acpi_callsetfunc(sony_nc_acpi_handle, + "SN00", i + 0x20, &result)) { dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n", result, i); handles->cap[i] = result; @@ -882,8 +819,8 @@ static int sony_find_snc_handle(int handle) int i; /* not initialized yet, return early */ - if (!handles || !handle) - return -EINVAL; + if (!handles) + return -1; for (i = 0; i < 0x10; i++) { if (handles->cap[i] == handle) { @@ -893,20 +830,21 @@ static int sony_find_snc_handle(int handle) } } dprintk("handle 0x%.4x not found\n", handle); - return -EINVAL; + return -1; } static int sony_call_snc_handle(int handle, int argument, int *result) { - int arg, ret = 0; + int ret = 0; int offset = sony_find_snc_handle(handle); if (offset < 0) - return offset; + return -1; - arg = offset | argument; - ret = sony_nc_int_call(sony_nc_acpi_handle, "SN07", &arg, result); - dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", arg, *result); + ret = acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument, + result); + dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", offset | argument, + *result); return ret; } @@ -951,16 +889,14 @@ static int boolean_validate(const int direction, const int value) static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr, char *buffer) { - int value, ret = 0; + int value; struct sony_nc_value *item = container_of(attr, struct sony_nc_value, devattr); if (!*item->acpiget) return -EIO; - ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiget, NULL, - &value); - if (ret < 0) + if (acpi_callgetfunc(sony_nc_acpi_handle, *item->acpiget, &value) < 0) return -EIO; if (item->validate) @@ -973,8 +909,7 @@ static ssize_t sony_nc_sysfs_store(struct device *dev, struct device_attribute *attr, const char *buffer, size_t count) { - unsigned long value = 0; - int ret = 0; + int value; struct sony_nc_value *item = container_of(attr, struct sony_nc_value, devattr); @@ -984,8 +919,7 @@ static ssize_t sony_nc_sysfs_store(struct device *dev, if (count > 31) return -EINVAL; - if (kstrtoul(buffer, 10, &value)) - return -EINVAL; + value = simple_strtoul(buffer, NULL, 10); if (item->validate) value = item->validate(SNC_VALIDATE_IN, value); @@ -993,11 +927,8 @@ static ssize_t sony_nc_sysfs_store(struct device *dev, if (value < 0) return value; - ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset, - (int *)&value, NULL); - if (ret < 0) + if (acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, value, NULL) < 0) return -EIO; - item->value = value; item->valid = 1; return count; @@ -1017,15 +948,15 @@ struct sony_backlight_props sony_bl_props; static int sony_backlight_update_status(struct backlight_device *bd) { - int arg = bd->props.brightness + 1; - return sony_nc_int_call(sony_nc_acpi_handle, "SBRT", &arg, NULL); + return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", + bd->props.brightness + 1, NULL); } static int sony_backlight_get_brightness(struct backlight_device *bd) { int value; - if (sony_nc_int_call(sony_nc_acpi_handle, "GBRT", NULL, &value)) + if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) return 0; /* brightness levels are 1-based, while backlight ones are 0-based */ return value - 1; @@ -1093,14 +1024,10 @@ static struct sony_nc_event sony_100_events[] = { { 0x06, SONYPI_EVENT_FNKEY_RELEASED }, { 0x87, SONYPI_EVENT_FNKEY_F7 }, { 0x07, SONYPI_EVENT_FNKEY_RELEASED }, - { 0x88, SONYPI_EVENT_FNKEY_F8 }, - { 0x08, SONYPI_EVENT_FNKEY_RELEASED }, { 0x89, SONYPI_EVENT_FNKEY_F9 }, { 0x09, SONYPI_EVENT_FNKEY_RELEASED }, { 0x8A, SONYPI_EVENT_FNKEY_F10 }, { 0x0A, SONYPI_EVENT_FNKEY_RELEASED }, - { 0x8B, SONYPI_EVENT_FNKEY_F11 }, - { 0x0B, SONYPI_EVENT_FNKEY_RELEASED }, { 0x8C, SONYPI_EVENT_FNKEY_F12 }, { 0x0C, SONYPI_EVENT_FNKEY_RELEASED }, { 0x9d, SONYPI_EVENT_ZOOM_PRESSED }, @@ -1136,116 +1063,63 @@ static struct sony_nc_event sony_127_events[] = { { 0, 0 }, }; -static int sony_nc_hotkeys_decode(u32 event, unsigned int handle) -{ - int ret = -EINVAL; - unsigned int result = 0; - struct sony_nc_event *key_event; - - if (sony_call_snc_handle(handle, 0x200, &result)) { - dprintk("Unable to decode event 0x%.2x 0x%.2x\n", handle, - event); - return -EINVAL; - } - - result &= 0xFF; - - if (handle == 0x0100) - key_event = sony_100_events; - else - key_event = sony_127_events; - - for (; key_event->data; key_event++) { - if (key_event->data == result) { - ret = key_event->event; - break; - } - } - - if (!key_event->data) - pr_info("Unknown hotkey 0x%.2x/0x%.2x (handle 0x%.2x)\n", - event, result, handle); - - return ret; -} - /* * ACPI callbacks */ static void sony_nc_notify(struct acpi_device *device, u32 event) { - u32 real_ev = event; - u8 ev_type = 0; - dprintk("sony_nc_notify, event: 0x%.2x\n", event); - - if (event >= 0x90) { - unsigned int result = 0; - unsigned int arg = 0; - unsigned int handle = 0; - unsigned int offset = event - 0x90; - - if (offset >= ARRAY_SIZE(handles->cap)) { - pr_err("Event 0x%x outside of capabilities list\n", - event); - return; - } - handle = handles->cap[offset]; - - /* list of handles known for generating events */ - switch (handle) { - /* hotkey event */ - case 0x0100: - case 0x0127: - ev_type = 1; - real_ev = sony_nc_hotkeys_decode(event, handle); - - if (real_ev > 0) - sony_laptop_report_input_event(real_ev); - else - /* restore the original event for reporting */ - real_ev = event; - - break; + u32 ev = event; - /* wlan switch */ - case 0x0124: - case 0x0135: - /* events on this handle are reported when the - * switch changes position or for battery - * events. We'll notify both of them but only - * update the rfkill device status when the - * switch is moved. - */ - ev_type = 2; - sony_call_snc_handle(handle, 0x0100, &result); - real_ev = result & 0x03; - - /* hw switch event */ - if (real_ev == 1) - sony_nc_rfkill_update(); - - break; + if (ev >= 0x90) { + /* New-style event */ + int result; + int key_handle = 0; + ev -= 0x90; + + if (sony_find_snc_handle(0x100) == ev) + key_handle = 0x100; + if (sony_find_snc_handle(0x127) == ev) + key_handle = 0x127; + + if (key_handle) { + struct sony_nc_event *key_event; + + if (sony_call_snc_handle(key_handle, 0x200, &result)) { + dprintk("sony_nc_notify, unable to decode" + " event 0x%.2x 0x%.2x\n", key_handle, + ev); + /* restore the original event */ + ev = event; + } else { + ev = result & 0xFF; + + if (key_handle == 0x100) + key_event = sony_100_events; + else + key_event = sony_127_events; + + for (; key_event->data; key_event++) { + if (key_event->data == ev) { + ev = key_event->event; + break; + } + } - default: - dprintk("Unknown event 0x%x for handle 0x%x\n", - event, handle); - break; + if (!key_event->data) + pr_info("Unknown event: 0x%x 0x%x\n", + key_handle, ev); + else + sony_laptop_report_input_event(ev); + } + } else if (sony_find_snc_handle(sony_rfkill_handle) == ev) { + sony_nc_rfkill_update(); + return; } + } else + sony_laptop_report_input_event(ev); - /* clear the event (and the event reason when present) */ - arg = 1 << offset; - sony_nc_int_call(sony_nc_acpi_handle, "SN05", &arg, &result); - - } else { - /* old style event */ - ev_type = 1; - sony_laptop_report_input_event(real_ev); - } - - acpi_bus_generate_proc_event(sony_nc_acpi_device, ev_type, real_ev); - - acpi_bus_generate_netlink_event(sony_nc_acpi_device->pnp.device_class, - dev_name(&sony_nc_acpi_device->dev), ev_type, real_ev); + dprintk("sony_nc_notify, event: 0x%.2x\n", ev); + acpi_bus_generate_proc_event(sony_nc_acpi_device, 1, ev); } static acpi_status sony_walk_callback(acpi_handle handle, u32 level, @@ -1266,190 +1140,20 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level, /* * ACPI device */ -static void sony_nc_function_setup(struct acpi_device *device, - struct platform_device *pf_device) +static int sony_nc_function_setup(struct acpi_device *device) { - unsigned int i, result, bitmask, arg; - - if (!handles) - return; - - /* setup found handles here */ - for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { - unsigned int handle = handles->cap[i]; - - if (!handle) - continue; - - dprintk("setting up handle 0x%.4x\n", handle); - - switch (handle) { - case 0x0100: - case 0x0101: - case 0x0127: - /* setup hotkeys */ - sony_call_snc_handle(handle, 0, &result); - break; - case 0x0102: - /* setup hotkeys */ - sony_call_snc_handle(handle, 0x100, &result); - break; - case 0x0105: - case 0x0148: - /* touchpad enable/disable */ - result = sony_nc_touchpad_setup(pf_device, handle); - if (result) - pr_err("couldn't set up touchpad control function (%d)\n", - result); - break; - case 0x0115: - case 0x0136: - case 0x013f: - result = sony_nc_battery_care_setup(pf_device, handle); - if (result) - pr_err("couldn't set up battery care function (%d)\n", - result); - break; - case 0x0119: - result = sony_nc_lid_resume_setup(pf_device); - if (result) - pr_err("couldn't set up lid resume function (%d)\n", - result); - break; - case 0x0122: - result = sony_nc_thermal_setup(pf_device); - if (result) - pr_err("couldn't set up thermal profile function (%d)\n", - result); - break; - case 0x0131: - result = sony_nc_highspeed_charging_setup(pf_device); - if (result) - pr_err("couldn't set up high speed charging function (%d)\n", - result); - break; - case 0x0124: - case 0x0135: - result = sony_nc_rfkill_setup(device, handle); - if (result) - pr_err("couldn't set up rfkill support (%d)\n", - result); - break; - case 0x0137: - case 0x0143: - result = sony_nc_kbd_backlight_setup(pf_device, handle); - if (result) - pr_err("couldn't set up keyboard backlight function (%d)\n", - result); - break; - default: - continue; - } - } + int result; /* Enable all events */ - arg = 0x10; - if (!sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg, &bitmask)) - sony_nc_int_call(sony_nc_acpi_handle, "SN02", &bitmask, - &result); -} - -static void sony_nc_function_cleanup(struct platform_device *pd) -{ - unsigned int i, result, bitmask, handle; - - /* get enabled events and disable them */ - sony_nc_int_call(sony_nc_acpi_handle, "SN01", NULL, &bitmask); - sony_nc_int_call(sony_nc_acpi_handle, "SN03", &bitmask, &result); - - /* cleanup handles here */ - for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { - - handle = handles->cap[i]; - - if (!handle) - continue; - - switch (handle) { - case 0x0105: - case 0x0148: - sony_nc_touchpad_cleanup(pd); - break; - case 0x0115: - case 0x0136: - case 0x013f: - sony_nc_battery_care_cleanup(pd); - break; - case 0x0119: - sony_nc_lid_resume_cleanup(pd); - break; - case 0x0122: - sony_nc_thermal_cleanup(pd); - break; - case 0x0131: - sony_nc_highspeed_charging_cleanup(pd); - break; - case 0x0124: - case 0x0135: - sony_nc_rfkill_cleanup(); - break; - case 0x0137: - case 0x0143: - sony_nc_kbd_backlight_cleanup(pd); - break; - default: - continue; - } - } - - /* finally cleanup the handles list */ - sony_nc_handles_cleanup(pd); -} - -static void sony_nc_function_resume(void) -{ - unsigned int i, result, bitmask, arg; - - dprintk("Resuming SNC device\n"); + acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0xffff, &result); - for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { - unsigned int handle = handles->cap[i]; - - if (!handle) - continue; - - switch (handle) { - case 0x0100: - case 0x0101: - case 0x0127: - /* re-enable hotkeys */ - sony_call_snc_handle(handle, 0, &result); - break; - case 0x0102: - /* re-enable hotkeys */ - sony_call_snc_handle(handle, 0x100, &result); - break; - case 0x0122: - sony_nc_thermal_resume(); - break; - case 0x0124: - case 0x0135: - sony_nc_rfkill_update(); - break; - case 0x0137: - case 0x0143: - sony_nc_kbd_backlight_resume(); - break; - default: - continue; - } - } + /* Setup hotkeys */ + sony_call_snc_handle(0x0100, 0, &result); + sony_call_snc_handle(0x0101, 0, &result); + sony_call_snc_handle(0x0102, 0x100, &result); + sony_call_snc_handle(0x0127, 0, &result); - /* Enable all events */ - arg = 0x10; - if (!sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg, &bitmask)) - sony_nc_int_call(sony_nc_acpi_handle, "SN02", &bitmask, - &result); + return 0; } static int sony_nc_resume(struct acpi_device *device) @@ -1462,8 +1166,8 @@ static int sony_nc_resume(struct acpi_device *device) if (!item->valid) continue; - ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset, - &item->value, NULL); + ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, + item->value, NULL); if (ret < 0) { pr_err("%s: %d\n", __func__, ret); break; @@ -1472,14 +1176,21 @@ static int sony_nc_resume(struct acpi_device *device) if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON", &handle))) { - int arg = 1; - if (sony_nc_int_call(sony_nc_acpi_handle, "ECON", &arg, NULL)) + if (acpi_callsetfunc(sony_nc_acpi_handle, "ECON", 1, NULL)) dprintk("ECON Method failed\n"); } if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", - &handle))) - sony_nc_function_resume(); + &handle))) { + dprintk("Doing SNC setup\n"); + sony_nc_function_setup(device); + } + + /* re-read rfkill state */ + sony_nc_rfkill_update(); + + /* restore kbd backlight states */ + sony_nc_kbd_backlight_resume(); return 0; } @@ -1502,7 +1213,7 @@ static int sony_nc_rfkill_set(void *data, bool blocked) int argument = sony_rfkill_address[(long) data] + 0x100; if (!blocked) - argument |= 0x030000; + argument |= 0xff0000; return sony_call_snc_handle(sony_rfkill_handle, argument, &result); } @@ -1519,7 +1230,7 @@ static int sony_nc_setup_rfkill(struct acpi_device *device, enum rfkill_type type; const char *name; int result; - bool hwblock, swblock; + bool hwblock; switch (nc_type) { case SONY_WIFI: @@ -1547,21 +1258,8 @@ static int sony_nc_setup_rfkill(struct acpi_device *device, if (!rfk) return -ENOMEM; - if (sony_call_snc_handle(sony_rfkill_handle, 0x200, &result) < 0) { - rfkill_destroy(rfk); - return -1; - } + sony_call_snc_handle(sony_rfkill_handle, 0x200, &result); hwblock = !(result & 0x1); - - if (sony_call_snc_handle(sony_rfkill_handle, - sony_rfkill_address[nc_type], - &result) < 0) { - rfkill_destroy(rfk); - return -1; - } - swblock = !(result & 0x2); - - rfkill_init_sw_state(rfk, swblock); rfkill_set_hw_state(rfk, hwblock); err = rfkill_register(rfk); @@ -1597,79 +1295,101 @@ static void sony_nc_rfkill_update(void) sony_call_snc_handle(sony_rfkill_handle, argument, &result); rfkill_set_states(sony_rfkill_devices[i], - !(result & 0x2), false); + !(result & 0xf), false); } } -static int sony_nc_rfkill_setup(struct acpi_device *device, - unsigned int handle) +static void sony_nc_rfkill_setup(struct acpi_device *device) { - u64 offset; - int i; - unsigned char buffer[32] = { 0 }; + int offset; + u8 dev_code, i; + acpi_status status; + struct acpi_object_list params; + union acpi_object in_obj; + union acpi_object *device_enum; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + + offset = sony_find_snc_handle(0x124); + if (offset == -1) { + offset = sony_find_snc_handle(0x135); + if (offset == -1) + return; + else + sony_rfkill_handle = 0x135; + } else + sony_rfkill_handle = 0x124; + dprintk("Found rkfill handle: 0x%.4x\n", sony_rfkill_handle); - offset = sony_find_snc_handle(handle); - sony_rfkill_handle = handle; - - i = sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &offset, buffer, - 32); - if (i < 0) - return i; - - /* The buffer is filled with magic numbers describing the devices - * available, 0xff terminates the enumeration. - * Known codes: - * 0x00 WLAN - * 0x10 BLUETOOTH - * 0x20 WWAN GPRS-EDGE - * 0x21 WWAN HSDPA - * 0x22 WWAN EV-DO - * 0x23 WWAN GPS - * 0x25 Gobi WWAN no GPS - * 0x26 Gobi WWAN + GPS - * 0x28 Gobi WWAN no GPS - * 0x29 Gobi WWAN + GPS - * 0x30 WIMAX - * 0x50 Gobi WWAN no GPS - * 0x51 Gobi WWAN + GPS - * 0x70 no SIM card slot - * 0x71 SIM card slot + /* need to read the whole buffer returned by the acpi call to SN06 + * here otherwise we may miss some features + */ + params.count = 1; + params.pointer = &in_obj; + in_obj.type = ACPI_TYPE_INTEGER; + in_obj.integer.value = offset; + status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", ¶ms, + &buffer); + if (ACPI_FAILURE(status)) { + dprintk("Radio device enumeration failed\n"); + return; + } + + device_enum = (union acpi_object *) buffer.pointer; + if (!device_enum) { + pr_err("No SN06 return object\n"); + goto out_no_enum; + } + if (device_enum->type != ACPI_TYPE_BUFFER) { + pr_err("Invalid SN06 return object 0x%.2x\n", + device_enum->type); + goto out_no_enum; + } + + /* the buffer is filled with magic numbers describing the devices + * available, 0xff terminates the enumeration */ - for (i = 0; i < ARRAY_SIZE(buffer); i++) { + for (i = 0; i < device_enum->buffer.length; i++) { - if (buffer[i] == 0xff) + dev_code = *(device_enum->buffer.pointer + i); + if (dev_code == 0xff) break; - dprintk("Radio devices, found 0x%.2x\n", buffer[i]); + dprintk("Radio devices, looking at 0x%.2x\n", dev_code); - if (buffer[i] == 0 && !sony_rfkill_devices[SONY_WIFI]) + if (dev_code == 0 && !sony_rfkill_devices[SONY_WIFI]) sony_nc_setup_rfkill(device, SONY_WIFI); - if (buffer[i] == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH]) + if (dev_code == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH]) sony_nc_setup_rfkill(device, SONY_BLUETOOTH); - if (((0xf0 & buffer[i]) == 0x20 || - (0xf0 & buffer[i]) == 0x50) && + if ((0xf0 & dev_code) == 0x20 && !sony_rfkill_devices[SONY_WWAN]) sony_nc_setup_rfkill(device, SONY_WWAN); - if (buffer[i] == 0x30 && !sony_rfkill_devices[SONY_WIMAX]) + if (dev_code == 0x30 && !sony_rfkill_devices[SONY_WIMAX]) sony_nc_setup_rfkill(device, SONY_WIMAX); } - return 0; + +out_no_enum: + kfree(buffer.pointer); + return; } /* Keyboard backlight feature */ +#define KBDBL_HANDLER 0x137 +#define KBDBL_PRESENT 0xB00 +#define SET_MODE 0xC00 +#define SET_STATE 0xD00 +#define SET_TIMEOUT 0xE00 + struct kbd_backlight { - unsigned int handle; - unsigned int base; - unsigned int mode; - unsigned int timeout; + int mode; + int timeout; struct device_attribute mode_attr; struct device_attribute timeout_attr; }; -static struct kbd_backlight *kbdbl_ctl; +static struct kbd_backlight *kbdbl_handle; static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value) { @@ -1678,15 +1398,15 @@ static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value) if (value > 1) return -EINVAL; - if (sony_call_snc_handle(kbdbl_ctl->handle, - (value << 0x10) | (kbdbl_ctl->base), &result)) + if (sony_call_snc_handle(KBDBL_HANDLER, + (value << 0x10) | SET_MODE, &result)) return -EIO; /* Try to turn the light on/off immediately */ - sony_call_snc_handle(kbdbl_ctl->handle, - (value << 0x10) | (kbdbl_ctl->base + 0x100), &result); + sony_call_snc_handle(KBDBL_HANDLER, (value << 0x10) | SET_STATE, + &result); - kbdbl_ctl->mode = value; + kbdbl_handle->mode = value; return 0; } @@ -1701,7 +1421,7 @@ static ssize_t sony_nc_kbd_backlight_mode_store(struct device *dev, if (count > 31) return -EINVAL; - if (kstrtoul(buffer, 10, &value)) + if (strict_strtoul(buffer, 10, &value)) return -EINVAL; ret = __sony_nc_kbd_backlight_mode_set(value); @@ -1715,7 +1435,7 @@ static ssize_t sony_nc_kbd_backlight_mode_show(struct device *dev, struct device_attribute *attr, char *buffer) { ssize_t count = 0; - count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_ctl->mode); + count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->mode); return count; } @@ -1726,11 +1446,11 @@ static int __sony_nc_kbd_backlight_timeout_set(u8 value) if (value > 3) return -EINVAL; - if (sony_call_snc_handle(kbdbl_ctl->handle, (value << 0x10) | - (kbdbl_ctl->base + 0x200), &result)) + if (sony_call_snc_handle(KBDBL_HANDLER, + (value << 0x10) | SET_TIMEOUT, &result)) return -EIO; - kbdbl_ctl->timeout = value; + kbdbl_handle->timeout = value; return 0; } @@ -1745,7 +1465,7 @@ static ssize_t sony_nc_kbd_backlight_timeout_store(struct device *dev, if (count > 31) return -EINVAL; - if (kstrtoul(buffer, 10, &value)) + if (strict_strtoul(buffer, 10, &value)) return -EINVAL; ret = __sony_nc_kbd_backlight_timeout_set(value); @@ -1759,58 +1479,39 @@ static ssize_t sony_nc_kbd_backlight_timeout_show(struct device *dev, struct device_attribute *attr, char *buffer) { ssize_t count = 0; - count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_ctl->timeout); + count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->timeout); return count; } -static int sony_nc_kbd_backlight_setup(struct platform_device *pd, - unsigned int handle) +static int sony_nc_kbd_backlight_setup(struct platform_device *pd) { int result; - int ret = 0; - - /* verify the kbd backlight presence, these handles are not used for - * keyboard backlight only - */ - ret = sony_call_snc_handle(handle, handle == 0x0137 ? 0x0B00 : 0x0100, - &result); - if (ret) - return ret; - if ((handle == 0x0137 && !(result & 0x02)) || - !(result & 0x01)) { - dprintk("no backlight keyboard found\n"); + if (sony_call_snc_handle(KBDBL_HANDLER, KBDBL_PRESENT, &result)) + return 0; + if (!(result & 0x02)) return 0; - } - kbdbl_ctl = kzalloc(sizeof(*kbdbl_ctl), GFP_KERNEL); - if (!kbdbl_ctl) + kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL); + if (!kbdbl_handle) return -ENOMEM; - kbdbl_ctl->handle = handle; - if (handle == 0x0137) - kbdbl_ctl->base = 0x0C00; - else - kbdbl_ctl->base = 0x4000; - - sysfs_attr_init(&kbdbl_ctl->mode_attr.attr); - kbdbl_ctl->mode_attr.attr.name = "kbd_backlight"; - kbdbl_ctl->mode_attr.attr.mode = S_IRUGO | S_IWUSR; - kbdbl_ctl->mode_attr.show = sony_nc_kbd_backlight_mode_show; - kbdbl_ctl->mode_attr.store = sony_nc_kbd_backlight_mode_store; + sysfs_attr_init(&kbdbl_handle->mode_attr.attr); + kbdbl_handle->mode_attr.attr.name = "kbd_backlight"; + kbdbl_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR; + kbdbl_handle->mode_attr.show = sony_nc_kbd_backlight_mode_show; + kbdbl_handle->mode_attr.store = sony_nc_kbd_backlight_mode_store; - sysfs_attr_init(&kbdbl_ctl->timeout_attr.attr); - kbdbl_ctl->timeout_attr.attr.name = "kbd_backlight_timeout"; - kbdbl_ctl->timeout_attr.attr.mode = S_IRUGO | S_IWUSR; - kbdbl_ctl->timeout_attr.show = sony_nc_kbd_backlight_timeout_show; - kbdbl_ctl->timeout_attr.store = sony_nc_kbd_backlight_timeout_store; + sysfs_attr_init(&kbdbl_handle->timeout_attr.attr); + kbdbl_handle->timeout_attr.attr.name = "kbd_backlight_timeout"; + kbdbl_handle->timeout_attr.attr.mode = S_IRUGO | S_IWUSR; + kbdbl_handle->timeout_attr.show = sony_nc_kbd_backlight_timeout_show; + kbdbl_handle->timeout_attr.store = sony_nc_kbd_backlight_timeout_store; - ret = device_create_file(&pd->dev, &kbdbl_ctl->mode_attr); - if (ret) + if (device_create_file(&pd->dev, &kbdbl_handle->mode_attr)) goto outkzalloc; - ret = device_create_file(&pd->dev, &kbdbl_ctl->timeout_attr); - if (ret) + if (device_create_file(&pd->dev, &kbdbl_handle->timeout_attr)) goto outmode; __sony_nc_kbd_backlight_mode_set(kbd_backlight); @@ -1819,711 +1520,126 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd, return 0; outmode: - device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr); + device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); outkzalloc: - kfree(kbdbl_ctl); - kbdbl_ctl = NULL; - return ret; + kfree(kbdbl_handle); + kbdbl_handle = NULL; + return -1; } -static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd) +static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd) { - if (kbdbl_ctl) { + if (kbdbl_handle) { int result; - device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr); - device_remove_file(&pd->dev, &kbdbl_ctl->timeout_attr); + device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); + device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr); /* restore the default hw behaviour */ - sony_call_snc_handle(kbdbl_ctl->handle, - kbdbl_ctl->base | 0x10000, &result); - sony_call_snc_handle(kbdbl_ctl->handle, - kbdbl_ctl->base + 0x200, &result); + sony_call_snc_handle(KBDBL_HANDLER, 0x1000 | SET_MODE, &result); + sony_call_snc_handle(KBDBL_HANDLER, SET_TIMEOUT, &result); - kfree(kbdbl_ctl); - kbdbl_ctl = NULL; + kfree(kbdbl_handle); } + return 0; } static void sony_nc_kbd_backlight_resume(void) { int ignore = 0; - if (!kbdbl_ctl) + if (!kbdbl_handle) return; - if (kbdbl_ctl->mode == 0) - sony_call_snc_handle(kbdbl_ctl->handle, kbdbl_ctl->base, - &ignore); + if (kbdbl_handle->mode == 0) + sony_call_snc_handle(KBDBL_HANDLER, SET_MODE, &ignore); - if (kbdbl_ctl->timeout != 0) - sony_call_snc_handle(kbdbl_ctl->handle, - (kbdbl_ctl->base + 0x200) | - (kbdbl_ctl->timeout << 0x10), &ignore); + if (kbdbl_handle->timeout != 0) + sony_call_snc_handle(KBDBL_HANDLER, + (kbdbl_handle->timeout << 0x10) | SET_TIMEOUT, + &ignore); } -struct battery_care_control { - struct device_attribute attrs[2]; - unsigned int handle; -}; -static struct battery_care_control *bcare_ctl; - -static ssize_t sony_nc_battery_care_limit_store(struct device *dev, - struct device_attribute *attr, - const char *buffer, size_t count) +static void sony_nc_backlight_ng_read_limits(int handle, + struct sony_backlight_props *props) { - unsigned int result, cmd; - unsigned long value; - - if (count > 31) - return -EINVAL; + int offset; + acpi_status status; + u8 brlvl, i; + u8 min = 0xff, max = 0x00; + struct acpi_object_list params; + union acpi_object in_obj; + union acpi_object *lvl_enum; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - if (kstrtoul(buffer, 10, &value)) - return -EINVAL; + props->handle = handle; + props->offset = 0; + props->maxlvl = 0xff; - /* limit values (2 bits): - * 00 - none - * 01 - 80% - * 10 - 50% - * 11 - 100% - * - * bit 0: 0 disable BCL, 1 enable BCL - * bit 1: 1 tell to store the battery limit (see bits 6,7) too - * bits 2,3: reserved - * bits 4,5: store the limit into the EC - * bits 6,7: store the limit into the battery - */ + offset = sony_find_snc_handle(handle); + if (offset < 0) + return; - /* - * handle 0x0115 should allow storing on battery too; - * handle 0x0136 same as 0x0115 + health status; - * handle 0x013f, same as 0x0136 but no storing on the battery - * - * Store only inside the EC for now, regardless the handle number + /* try to read the boundaries from ACPI tables, if we fail the above + * defaults should be reasonable */ - if (value == 0) - /* disable limits */ - cmd = 0x0; + params.count = 1; + params.pointer = &in_obj; + in_obj.type = ACPI_TYPE_INTEGER; + in_obj.integer.value = offset; + status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", ¶ms, + &buffer); + if (ACPI_FAILURE(status)) + return; - else if (value <= 50) - cmd = 0x21; + lvl_enum = (union acpi_object *) buffer.pointer; + if (!lvl_enum) { + pr_err("No SN06 return object."); + return; + } + if (lvl_enum->type != ACPI_TYPE_BUFFER) { + pr_err("Invalid SN06 return object 0x%.2x\n", + lvl_enum->type); + goto out_invalid; + } - else if (value <= 80) - cmd = 0x11; + /* the buffer lists brightness levels available, brightness levels are + * from 0 to 8 in the array, other values are used by ALS control. + */ + for (i = 0; i < 9 && i < lvl_enum->buffer.length; i++) { - else if (value <= 100) - cmd = 0x31; + brlvl = *(lvl_enum->buffer.pointer + i); + dprintk("Brightness level: %d\n", brlvl); - else - return -EINVAL; + if (!brlvl) + break; - if (sony_call_snc_handle(bcare_ctl->handle, (cmd << 0x10) | 0x0100, - &result)) - return -EIO; + if (brlvl > max) + max = brlvl; + if (brlvl < min) + min = brlvl; + } + props->offset = min; + props->maxlvl = max; + dprintk("Brightness levels: min=%d max=%d\n", props->offset, + props->maxlvl); - return count; +out_invalid: + kfree(buffer.pointer); + return; } -static ssize_t sony_nc_battery_care_limit_show(struct device *dev, - struct device_attribute *attr, char *buffer) +static void sony_nc_backlight_setup(void) { - unsigned int result, status; + acpi_handle unused; + int max_brightness = 0; + const struct backlight_ops *ops = NULL; + struct backlight_properties props; - if (sony_call_snc_handle(bcare_ctl->handle, 0x0000, &result)) - return -EIO; - - status = (result & 0x01) ? ((result & 0x30) >> 0x04) : 0; - switch (status) { - case 1: - status = 80; - break; - case 2: - status = 50; - break; - case 3: - status = 100; - break; - default: - status = 0; - break; - } - - return snprintf(buffer, PAGE_SIZE, "%d\n", status); -} - -static ssize_t sony_nc_battery_care_health_show(struct device *dev, - struct device_attribute *attr, char *buffer) -{ - ssize_t count = 0; - unsigned int health; - - if (sony_call_snc_handle(bcare_ctl->handle, 0x0200, &health)) - return -EIO; - - count = snprintf(buffer, PAGE_SIZE, "%d\n", health & 0xff); - - return count; -} - -static int sony_nc_battery_care_setup(struct platform_device *pd, - unsigned int handle) -{ - int ret = 0; - - bcare_ctl = kzalloc(sizeof(struct battery_care_control), GFP_KERNEL); - if (!bcare_ctl) - return -ENOMEM; - - bcare_ctl->handle = handle; - - sysfs_attr_init(&bcare_ctl->attrs[0].attr); - bcare_ctl->attrs[0].attr.name = "battery_care_limiter"; - bcare_ctl->attrs[0].attr.mode = S_IRUGO | S_IWUSR; - bcare_ctl->attrs[0].show = sony_nc_battery_care_limit_show; - bcare_ctl->attrs[0].store = sony_nc_battery_care_limit_store; - - ret = device_create_file(&pd->dev, &bcare_ctl->attrs[0]); - if (ret) - goto outkzalloc; - - /* 0x0115 is for models with no health reporting capability */ - if (handle == 0x0115) - return 0; - - sysfs_attr_init(&bcare_ctl->attrs[1].attr); - bcare_ctl->attrs[1].attr.name = "battery_care_health"; - bcare_ctl->attrs[1].attr.mode = S_IRUGO; - bcare_ctl->attrs[1].show = sony_nc_battery_care_health_show; - - ret = device_create_file(&pd->dev, &bcare_ctl->attrs[1]); - if (ret) - goto outlimiter; - - return 0; - -outlimiter: - device_remove_file(&pd->dev, &bcare_ctl->attrs[0]); - -outkzalloc: - kfree(bcare_ctl); - bcare_ctl = NULL; - - return ret; -} - -static void sony_nc_battery_care_cleanup(struct platform_device *pd) -{ - if (bcare_ctl) { - device_remove_file(&pd->dev, &bcare_ctl->attrs[0]); - if (bcare_ctl->handle != 0x0115) - device_remove_file(&pd->dev, &bcare_ctl->attrs[1]); - - kfree(bcare_ctl); - bcare_ctl = NULL; - } -} - -struct snc_thermal_ctrl { - unsigned int mode; - unsigned int profiles; - struct device_attribute mode_attr; - struct device_attribute profiles_attr; -}; -static struct snc_thermal_ctrl *th_handle; - -#define THM_PROFILE_MAX 3 -static const char * const snc_thermal_profiles[] = { - "balanced", - "silent", - "performance" -}; - -static int sony_nc_thermal_mode_set(unsigned short mode) -{ - unsigned int result; - - /* the thermal profile seems to be a two bit bitmask: - * lsb -> silent - * msb -> performance - * no bit set is the normal operation and is always valid - * Some vaio models only have "balanced" and "performance" - */ - if ((mode && !(th_handle->profiles & mode)) || mode >= THM_PROFILE_MAX) - return -EINVAL; - - if (sony_call_snc_handle(0x0122, mode << 0x10 | 0x0200, &result)) - return -EIO; - - th_handle->mode = mode; - - return 0; -} - -static int sony_nc_thermal_mode_get(void) -{ - unsigned int result; - - if (sony_call_snc_handle(0x0122, 0x0100, &result)) - return -EIO; - - return result & 0xff; -} - -static ssize_t sony_nc_thermal_profiles_show(struct device *dev, - struct device_attribute *attr, char *buffer) -{ - short cnt; - size_t idx = 0; - - for (cnt = 0; cnt < THM_PROFILE_MAX; cnt++) { - if (!cnt || (th_handle->profiles & cnt)) - idx += snprintf(buffer + idx, PAGE_SIZE - idx, "%s ", - snc_thermal_profiles[cnt]); - } - idx += snprintf(buffer + idx, PAGE_SIZE - idx, "\n"); - - return idx; -} - -static ssize_t sony_nc_thermal_mode_store(struct device *dev, - struct device_attribute *attr, - const char *buffer, size_t count) -{ - unsigned short cmd; - size_t len = count; - - if (count == 0) - return -EINVAL; - - /* skip the newline if present */ - if (buffer[len - 1] == '\n') - len--; - - for (cmd = 0; cmd < THM_PROFILE_MAX; cmd++) - if (strncmp(buffer, snc_thermal_profiles[cmd], len) == 0) - break; - - if (sony_nc_thermal_mode_set(cmd)) - return -EIO; - - return count; -} - -static ssize_t sony_nc_thermal_mode_show(struct device *dev, - struct device_attribute *attr, char *buffer) -{ - ssize_t count = 0; - unsigned int mode = sony_nc_thermal_mode_get(); - - if (mode < 0) - return mode; - - count = snprintf(buffer, PAGE_SIZE, "%s\n", snc_thermal_profiles[mode]); - - return count; -} - -static int sony_nc_thermal_setup(struct platform_device *pd) -{ - int ret = 0; - th_handle = kzalloc(sizeof(struct snc_thermal_ctrl), GFP_KERNEL); - if (!th_handle) - return -ENOMEM; - - ret = sony_call_snc_handle(0x0122, 0x0000, &th_handle->profiles); - if (ret) { - pr_warn("couldn't to read the thermal profiles\n"); - goto outkzalloc; - } - - ret = sony_nc_thermal_mode_get(); - if (ret < 0) { - pr_warn("couldn't to read the current thermal profile"); - goto outkzalloc; - } - th_handle->mode = ret; - - sysfs_attr_init(&th_handle->profiles_attr.attr); - th_handle->profiles_attr.attr.name = "thermal_profiles"; - th_handle->profiles_attr.attr.mode = S_IRUGO; - th_handle->profiles_attr.show = sony_nc_thermal_profiles_show; - - sysfs_attr_init(&th_handle->mode_attr.attr); - th_handle->mode_attr.attr.name = "thermal_control"; - th_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR; - th_handle->mode_attr.show = sony_nc_thermal_mode_show; - th_handle->mode_attr.store = sony_nc_thermal_mode_store; - - ret = device_create_file(&pd->dev, &th_handle->profiles_attr); - if (ret) - goto outkzalloc; - - ret = device_create_file(&pd->dev, &th_handle->mode_attr); - if (ret) - goto outprofiles; - - return 0; - -outprofiles: - device_remove_file(&pd->dev, &th_handle->profiles_attr); -outkzalloc: - kfree(th_handle); - th_handle = NULL; - return ret; -} - -static void sony_nc_thermal_cleanup(struct platform_device *pd) -{ - if (th_handle) { - device_remove_file(&pd->dev, &th_handle->profiles_attr); - device_remove_file(&pd->dev, &th_handle->mode_attr); - kfree(th_handle); - th_handle = NULL; - } -} - -static void sony_nc_thermal_resume(void) -{ - unsigned int status = sony_nc_thermal_mode_get(); - - if (status != th_handle->mode) - sony_nc_thermal_mode_set(th_handle->mode); -} - -/* resume on LID open */ -struct snc_lid_resume_control { - struct device_attribute attrs[3]; - unsigned int status; -}; -static struct snc_lid_resume_control *lid_ctl; - -static ssize_t sony_nc_lid_resume_store(struct device *dev, - struct device_attribute *attr, - const char *buffer, size_t count) -{ - unsigned int result, pos; - unsigned long value; - if (count > 31) - return -EINVAL; - - if (kstrtoul(buffer, 10, &value) || value > 1) - return -EINVAL; - - /* the value we have to write to SNC is a bitmask: - * +--------------+ - * | S3 | S4 | S5 | - * +--------------+ - * 2 1 0 - */ - if (strcmp(attr->attr.name, "lid_resume_S3") == 0) - pos = 2; - else if (strcmp(attr->attr.name, "lid_resume_S4") == 0) - pos = 1; - else if (strcmp(attr->attr.name, "lid_resume_S5") == 0) - pos = 0; - else - return -EINVAL; - - if (value) - value = lid_ctl->status | (1 << pos); - else - value = lid_ctl->status & ~(1 << pos); - - if (sony_call_snc_handle(0x0119, value << 0x10 | 0x0100, &result)) - return -EIO; - - lid_ctl->status = value; - - return count; -} - -static ssize_t sony_nc_lid_resume_show(struct device *dev, - struct device_attribute *attr, char *buffer) -{ - unsigned int pos; - - if (strcmp(attr->attr.name, "lid_resume_S3") == 0) - pos = 2; - else if (strcmp(attr->attr.name, "lid_resume_S4") == 0) - pos = 1; - else if (strcmp(attr->attr.name, "lid_resume_S5") == 0) - pos = 0; - else - return -EINVAL; - - return snprintf(buffer, PAGE_SIZE, "%d\n", - (lid_ctl->status >> pos) & 0x01); -} - -static int sony_nc_lid_resume_setup(struct platform_device *pd) -{ - unsigned int result; - int i; - - if (sony_call_snc_handle(0x0119, 0x0000, &result)) - return -EIO; - - lid_ctl = kzalloc(sizeof(struct snc_lid_resume_control), GFP_KERNEL); - if (!lid_ctl) - return -ENOMEM; - - lid_ctl->status = result & 0x7; - - sysfs_attr_init(&lid_ctl->attrs[0].attr); - lid_ctl->attrs[0].attr.name = "lid_resume_S3"; - lid_ctl->attrs[0].attr.mode = S_IRUGO | S_IWUSR; - lid_ctl->attrs[0].show = sony_nc_lid_resume_show; - lid_ctl->attrs[0].store = sony_nc_lid_resume_store; - - sysfs_attr_init(&lid_ctl->attrs[1].attr); - lid_ctl->attrs[1].attr.name = "lid_resume_S4"; - lid_ctl->attrs[1].attr.mode = S_IRUGO | S_IWUSR; - lid_ctl->attrs[1].show = sony_nc_lid_resume_show; - lid_ctl->attrs[1].store = sony_nc_lid_resume_store; - - sysfs_attr_init(&lid_ctl->attrs[2].attr); - lid_ctl->attrs[2].attr.name = "lid_resume_S5"; - lid_ctl->attrs[2].attr.mode = S_IRUGO | S_IWUSR; - lid_ctl->attrs[2].show = sony_nc_lid_resume_show; - lid_ctl->attrs[2].store = sony_nc_lid_resume_store; - - for (i = 0; i < 3; i++) { - result = device_create_file(&pd->dev, &lid_ctl->attrs[i]); - if (result) - goto liderror; - } - - return 0; - -liderror: - for (; i > 0; i--) - device_remove_file(&pd->dev, &lid_ctl->attrs[i]); - - kfree(lid_ctl); - lid_ctl = NULL; - - return result; -} - -static void sony_nc_lid_resume_cleanup(struct platform_device *pd) -{ - int i; - - if (lid_ctl) { - for (i = 0; i < 3; i++) - device_remove_file(&pd->dev, &lid_ctl->attrs[i]); - - kfree(lid_ctl); - lid_ctl = NULL; - } -} - -/* High speed charging function */ -static struct device_attribute *hsc_handle; - -static ssize_t sony_nc_highspeed_charging_store(struct device *dev, - struct device_attribute *attr, - const char *buffer, size_t count) -{ - unsigned int result; - unsigned long value; - - if (count > 31) - return -EINVAL; - - if (kstrtoul(buffer, 10, &value) || value > 1) - return -EINVAL; - - if (sony_call_snc_handle(0x0131, value << 0x10 | 0x0200, &result)) - return -EIO; - - return count; -} - -static ssize_t sony_nc_highspeed_charging_show(struct device *dev, - struct device_attribute *attr, char *buffer) -{ - unsigned int result; - - if (sony_call_snc_handle(0x0131, 0x0100, &result)) - return -EIO; - - return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01); -} - -static int sony_nc_highspeed_charging_setup(struct platform_device *pd) -{ - unsigned int result; - - if (sony_call_snc_handle(0x0131, 0x0000, &result) || !(result & 0x01)) { - /* some models advertise the handle but have no implementation - * for it - */ - pr_info("No High Speed Charging capability found\n"); - return 0; - } - - hsc_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL); - if (!hsc_handle) - return -ENOMEM; - - sysfs_attr_init(&hsc_handle->attr); - hsc_handle->attr.name = "battery_highspeed_charging"; - hsc_handle->attr.mode = S_IRUGO | S_IWUSR; - hsc_handle->show = sony_nc_highspeed_charging_show; - hsc_handle->store = sony_nc_highspeed_charging_store; - - result = device_create_file(&pd->dev, hsc_handle); - if (result) { - kfree(hsc_handle); - hsc_handle = NULL; - return result; - } - - return 0; -} - -static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd) -{ - if (hsc_handle) { - device_remove_file(&pd->dev, hsc_handle); - kfree(hsc_handle); - hsc_handle = NULL; - } -} - -/* Touchpad enable/disable */ -struct touchpad_control { - struct device_attribute attr; - int handle; -}; -static struct touchpad_control *tp_ctl; - -static ssize_t sony_nc_touchpad_store(struct device *dev, - struct device_attribute *attr, const char *buffer, size_t count) -{ - unsigned int result; - unsigned long value; - - if (count > 31) - return -EINVAL; - - if (kstrtoul(buffer, 10, &value) || value > 1) - return -EINVAL; - - /* sysfs: 0 disabled, 1 enabled - * EC: 0 enabled, 1 disabled - */ - if (sony_call_snc_handle(tp_ctl->handle, - (!value << 0x10) | 0x100, &result)) - return -EIO; - - return count; -} - -static ssize_t sony_nc_touchpad_show(struct device *dev, - struct device_attribute *attr, char *buffer) -{ - unsigned int result; - - if (sony_call_snc_handle(tp_ctl->handle, 0x000, &result)) - return -EINVAL; - - return snprintf(buffer, PAGE_SIZE, "%d\n", !(result & 0x01)); -} - -static int sony_nc_touchpad_setup(struct platform_device *pd, - unsigned int handle) -{ - int ret = 0; - - tp_ctl = kzalloc(sizeof(struct touchpad_control), GFP_KERNEL); - if (!tp_ctl) - return -ENOMEM; - - tp_ctl->handle = handle; - - sysfs_attr_init(&tp_ctl->attr.attr); - tp_ctl->attr.attr.name = "touchpad"; - tp_ctl->attr.attr.mode = S_IRUGO | S_IWUSR; - tp_ctl->attr.show = sony_nc_touchpad_show; - tp_ctl->attr.store = sony_nc_touchpad_store; - - ret = device_create_file(&pd->dev, &tp_ctl->attr); - if (ret) { - kfree(tp_ctl); - tp_ctl = NULL; - } - - return ret; -} - -static void sony_nc_touchpad_cleanup(struct platform_device *pd) -{ - if (tp_ctl) { - device_remove_file(&pd->dev, &tp_ctl->attr); - kfree(tp_ctl); - tp_ctl = NULL; - } -} - -static void sony_nc_backlight_ng_read_limits(int handle, - struct sony_backlight_props *props) -{ - u64 offset; - int i; - u8 min = 0xff, max = 0x00; - unsigned char buffer[32] = { 0 }; - - props->handle = handle; - props->offset = 0; - props->maxlvl = 0xff; - - offset = sony_find_snc_handle(handle); - if (offset < 0) - return; - - /* try to read the boundaries from ACPI tables, if we fail the above - * defaults should be reasonable - */ - i = sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &offset, buffer, - 32); - if (i < 0) - return; - - /* the buffer lists brightness levels available, brightness levels are - * from position 0 to 8 in the array, other values are used by ALS - * control. - */ - for (i = 0; i < 9 && i < ARRAY_SIZE(buffer); i++) { - - dprintk("Brightness level: %d\n", buffer[i]); - - if (!buffer[i]) - break; - - if (buffer[i] > max) - max = buffer[i]; - if (buffer[i] < min) - min = buffer[i]; - } - props->offset = min; - props->maxlvl = max; - dprintk("Brightness levels: min=%d max=%d\n", props->offset, - props->maxlvl); -} - -static void sony_nc_backlight_setup(void) -{ - acpi_handle unused; - int max_brightness = 0; - const struct backlight_ops *ops = NULL; - struct backlight_properties props; - - if (sony_find_snc_handle(0x12f) != -1) { - ops = &sony_backlight_ng_ops; - sony_nc_backlight_ng_read_limits(0x12f, &sony_bl_props); - max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset; + if (sony_find_snc_handle(0x12f) != -1) { + ops = &sony_backlight_ng_ops; + sony_nc_backlight_ng_read_limits(0x12f, &sony_bl_props); + max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset; } else if (sony_find_snc_handle(0x137) != -1) { ops = &sony_backlight_ng_ops; @@ -2599,25 +1715,28 @@ static int sony_nc_add(struct acpi_device *device) if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON", &handle))) { - int arg = 1; - if (sony_nc_int_call(sony_nc_acpi_handle, "ECON", &arg, NULL)) + if (acpi_callsetfunc(sony_nc_acpi_handle, "ECON", 1, NULL)) dprintk("ECON Method failed\n"); } if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", &handle))) { dprintk("Doing SNC setup\n"); - /* retrieve the available handles */ result = sony_nc_handles_setup(sony_pf_device); - if (!result) - sony_nc_function_setup(device, sony_pf_device); + if (result) + goto outpresent; + result = sony_nc_kbd_backlight_setup(sony_pf_device); + if (result) + goto outsnc; + sony_nc_function_setup(device); + sony_nc_rfkill_setup(device); } /* setup input devices and helper fifo */ result = sony_laptop_setup_input(device); if (result) { pr_err("Unable to create input devices\n"); - goto outsnc; + goto outkbdbacklight; } if (acpi_video_backlight_support()) { @@ -2675,8 +1794,10 @@ static int sony_nc_add(struct acpi_device *device) sony_laptop_remove_input(); + outkbdbacklight: + sony_nc_kbd_backlight_cleanup(sony_pf_device); + outsnc: - sony_nc_function_cleanup(sony_pf_device); sony_nc_handles_cleanup(sony_pf_device); outpresent: @@ -2699,10 +1820,11 @@ static int sony_nc_remove(struct acpi_device *device, int type) device_remove_file(&sony_pf_device->dev, &item->devattr); } - sony_nc_function_cleanup(sony_pf_device); + sony_nc_kbd_backlight_cleanup(sony_pf_device); sony_nc_handles_cleanup(sony_pf_device); sony_pf_remove(); sony_laptop_remove_input(); + sony_nc_rfkill_cleanup(); dprintk(SONY_NC_DRIVER_NAME " removed.\n"); return 0; @@ -3315,9 +2437,7 @@ static ssize_t sony_pic_wwanpower_store(struct device *dev, if (count > 31) return -EINVAL; - if (kstrtoul(buffer, 10, &value)) - return -EINVAL; - + value = simple_strtoul(buffer, NULL, 10); mutex_lock(&spic_dev.lock); __sony_pic_set_wwanpower(value); mutex_unlock(&spic_dev.lock); @@ -3354,9 +2474,7 @@ static ssize_t sony_pic_bluetoothpower_store(struct device *dev, if (count > 31) return -EINVAL; - if (kstrtoul(buffer, 10, &value)) - return -EINVAL; - + value = simple_strtoul(buffer, NULL, 10); mutex_lock(&spic_dev.lock); __sony_pic_set_bluetoothpower(value); mutex_unlock(&spic_dev.lock); @@ -3395,9 +2513,7 @@ static ssize_t sony_pic_fanspeed_store(struct device *dev, if (count > 31) return -EINVAL; - if (kstrtoul(buffer, 10, &value)) - return -EINVAL; - + value = simple_strtoul(buffer, NULL, 10); if (sony_pic_set_fanspeed(value)) return -EIO; @@ -3555,8 +2671,7 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd, ret = -EIO; break; } - if (sony_nc_int_call(sony_nc_acpi_handle, "GBRT", NULL, - &value)) { + if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) { ret = -EIO; break; } @@ -3573,9 +2688,8 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd, ret = -EFAULT; break; } - value = (val8 >> 5) + 1; - if (sony_nc_int_call(sony_nc_acpi_handle, "SBRT", &value, - NULL)) { + if (acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", + (val8 >> 5) + 1, NULL)) { ret = -EIO; break; } diff --git a/trunk/drivers/platform/x86/thinkpad_acpi.c b/trunk/drivers/platform/x86/thinkpad_acpi.c index 8b5610d88418..d68c0002f4a2 100644 --- a/trunk/drivers/platform/x86/thinkpad_acpi.c +++ b/trunk/drivers/platform/x86/thinkpad_acpi.c @@ -3402,7 +3402,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) /* Do not issue duplicate brightness change events to * userspace. tpacpi_detect_brightness_capabilities() must have * been called before this point */ - if (acpi_video_backlight_support()) { + if (tp_features.bright_acpimode && acpi_video_backlight_support()) { pr_info("This ThinkPad has standard ACPI backlight " "brightness control, supported by the ACPI " "video driver\n"); diff --git a/trunk/drivers/platform/x86/toshiba_acpi.c b/trunk/drivers/platform/x86/toshiba_acpi.c index dab10f6edcd4..57787d87d9a4 100644 --- a/trunk/drivers/platform/x86/toshiba_acpi.c +++ b/trunk/drivers/platform/x86/toshiba_acpi.c @@ -95,7 +95,6 @@ MODULE_LICENSE("GPL"); /* registers */ #define HCI_FAN 0x0004 -#define HCI_TR_BACKLIGHT 0x0005 #define HCI_SYSTEM_EVENT 0x0016 #define HCI_VIDEO_OUT 0x001c #define HCI_HOTKEY_EVENT 0x001e @@ -135,7 +134,6 @@ struct toshiba_acpi_dev { unsigned int system_event_supported:1; unsigned int ntfy_supported:1; unsigned int info_supported:1; - unsigned int tr_backlight_supported:1; struct mutex mutex; }; @@ -480,70 +478,34 @@ static const struct rfkill_ops toshiba_rfk_ops = { .poll = bt_rfkill_poll, }; -static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled) -{ - u32 hci_result; - u32 status; - - hci_read1(dev, HCI_TR_BACKLIGHT, &status, &hci_result); - *enabled = !status; - return hci_result == HCI_SUCCESS ? 0 : -EIO; -} - -static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable) -{ - u32 hci_result; - u32 value = !enable; - - hci_write1(dev, HCI_TR_BACKLIGHT, value, &hci_result); - return hci_result == HCI_SUCCESS ? 0 : -EIO; -} - static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; -static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) +static int get_lcd(struct backlight_device *bd) { + struct toshiba_acpi_dev *dev = bl_get_data(bd); u32 hci_result; u32 value; - int brightness = 0; - - if (dev->tr_backlight_supported) { - bool enabled; - int ret = get_tr_backlight_status(dev, &enabled); - if (ret) - return ret; - if (enabled) - return 0; - brightness++; - } hci_read1(dev, HCI_LCD_BRIGHTNESS, &value, &hci_result); if (hci_result == HCI_SUCCESS) - return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT); + return (value >> HCI_LCD_BRIGHTNESS_SHIFT); return -EIO; } -static int get_lcd_brightness(struct backlight_device *bd) -{ - struct toshiba_acpi_dev *dev = bl_get_data(bd); - return __get_lcd_brightness(dev); -} - static int lcd_proc_show(struct seq_file *m, void *v) { struct toshiba_acpi_dev *dev = m->private; int value; - int levels; if (!dev->backlight_dev) return -ENODEV; - levels = dev->backlight_dev->props.max_brightness + 1; - value = get_lcd_brightness(dev->backlight_dev); + value = get_lcd(dev->backlight_dev); if (value >= 0) { seq_printf(m, "brightness: %d\n", value); - seq_printf(m, "brightness_levels: %d\n", levels); + seq_printf(m, "brightness_levels: %d\n", + HCI_LCD_BRIGHTNESS_LEVELS); return 0; } @@ -556,19 +518,10 @@ static int lcd_proc_open(struct inode *inode, struct file *file) return single_open(file, lcd_proc_show, PDE(inode)->data); } -static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) +static int set_lcd(struct toshiba_acpi_dev *dev, int value) { u32 hci_result; - if (dev->tr_backlight_supported) { - bool enable = !value; - int ret = set_tr_backlight_status(dev, enable); - if (ret) - return ret; - if (value) - value--; - } - value = value << HCI_LCD_BRIGHTNESS_SHIFT; hci_write1(dev, HCI_LCD_BRIGHTNESS, value, &hci_result); return hci_result == HCI_SUCCESS ? 0 : -EIO; @@ -577,7 +530,7 @@ static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) static int set_lcd_status(struct backlight_device *bd) { struct toshiba_acpi_dev *dev = bl_get_data(bd); - return set_lcd_brightness(dev, bd->props.brightness); + return set_lcd(dev, bd->props.brightness); } static ssize_t lcd_proc_write(struct file *file, const char __user *buf, @@ -588,7 +541,6 @@ static ssize_t lcd_proc_write(struct file *file, const char __user *buf, size_t len; int value; int ret; - int levels = dev->backlight_dev->props.max_brightness + 1; len = min(count, sizeof(cmd) - 1); if (copy_from_user(cmd, buf, len)) @@ -596,8 +548,8 @@ static ssize_t lcd_proc_write(struct file *file, const char __user *buf, cmd[len] = '\0'; if (sscanf(cmd, " brightness : %i", &value) == 1 && - value >= 0 && value < levels) { - ret = set_lcd_brightness(dev, value); + value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) { + ret = set_lcd(dev, value); if (ret == 0) ret = count; } else { @@ -908,9 +860,8 @@ static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev) } static const struct backlight_ops toshiba_backlight_data = { - .options = BL_CORE_SUSPENDRESUME, - .get_brightness = get_lcd_brightness, - .update_status = set_lcd_status, + .get_brightness = get_lcd, + .update_status = set_lcd_status, }; static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, @@ -1069,56 +1020,6 @@ static int __devinit toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) return error; } -static int __devinit toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) -{ - struct backlight_properties props; - int brightness; - int ret; - bool enabled; - - /* - * Some machines don't support the backlight methods at all, and - * others support it read-only. Either of these is pretty useless, - * so only register the backlight device if the backlight method - * supports both reads and writes. - */ - brightness = __get_lcd_brightness(dev); - if (brightness < 0) - return 0; - ret = set_lcd_brightness(dev, brightness); - if (ret) { - pr_debug("Backlight method is read-only, disabling backlight support\n"); - return 0; - } - - /* Determine whether or not BIOS supports transflective backlight */ - ret = get_tr_backlight_status(dev, &enabled); - dev->tr_backlight_supported = !ret; - - memset(&props, 0, sizeof(props)); - props.type = BACKLIGHT_PLATFORM; - props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; - - /* adding an extra level and having 0 change to transflective mode */ - if (dev->tr_backlight_supported) - props.max_brightness++; - - dev->backlight_dev = backlight_device_register("toshiba", - &dev->acpi_dev->dev, - dev, - &toshiba_backlight_data, - &props); - if (IS_ERR(dev->backlight_dev)) { - ret = PTR_ERR(dev->backlight_dev); - pr_err("Could not register toshiba backlight device\n"); - dev->backlight_dev = NULL; - return ret; - } - - dev->backlight_dev->props.brightness = brightness; - return 0; -} - static int toshiba_acpi_remove(struct acpi_device *acpi_dev, int type) { struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); @@ -1177,6 +1078,7 @@ static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev) u32 dummy; bool bt_present; int ret = 0; + struct backlight_properties props; if (toshiba_acpi) return -EBUSY; @@ -1202,9 +1104,22 @@ static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev) mutex_init(&dev->mutex); - ret = toshiba_acpi_setup_backlight(dev); - if (ret) + memset(&props, 0, sizeof(props)); + props.type = BACKLIGHT_PLATFORM; + props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; + dev->backlight_dev = backlight_device_register("toshiba", + &acpi_dev->dev, + dev, + &toshiba_backlight_data, + &props); + if (IS_ERR(dev->backlight_dev)) { + ret = PTR_ERR(dev->backlight_dev); + + pr_err("Could not register toshiba backlight device\n"); + dev->backlight_dev = NULL; goto error; + } + dev->backlight_dev->props.brightness = get_lcd(dev->backlight_dev); /* Register rfkill switch for Bluetooth */ if (hci_get_bt_present(dev, &bt_present) == HCI_SUCCESS && bt_present) { diff --git a/trunk/drivers/platform/x86/xo1-rfkill.c b/trunk/drivers/platform/x86/xo1-rfkill.c index b57ad8641480..41781ed8301c 100644 --- a/trunk/drivers/platform/x86/xo1-rfkill.c +++ b/trunk/drivers/platform/x86/xo1-rfkill.c @@ -15,26 +15,15 @@ #include -static bool card_blocked; - static int rfkill_set_block(void *data, bool blocked) { unsigned char cmd; - int r; - - if (blocked == card_blocked) - return 0; - if (blocked) cmd = EC_WLAN_ENTER_RESET; else cmd = EC_WLAN_LEAVE_RESET; - r = olpc_ec_cmd(cmd, NULL, 0, NULL, 0); - if (r == 0) - card_blocked = blocked; - - return r; + return olpc_ec_cmd(cmd, NULL, 0, NULL, 0); } static const struct rfkill_ops rfkill_ops = { diff --git a/trunk/drivers/power/Kconfig b/trunk/drivers/power/Kconfig index e3a3b4956f08..99dc29f2f2f2 100644 --- a/trunk/drivers/power/Kconfig +++ b/trunk/drivers/power/Kconfig @@ -1,5 +1,5 @@ menuconfig POWER_SUPPLY - bool "Power supply class support" + tristate "Power supply class support" help Say Y here to enable power supply class support. This allows power supply (batteries, AC, USB) monitoring by userspace @@ -77,7 +77,7 @@ config BATTERY_DS2780 Say Y here to enable support for batteries with ds2780 chip. config BATTERY_DS2781 - tristate "DS2781 battery driver" + tristate "2781 battery driver" depends on HAS_IOMEM select W1 select W1_SLAVE_DS2781 @@ -181,15 +181,14 @@ config BATTERY_MAX17040 to operate with a single lithium cell config BATTERY_MAX17042 - tristate "Maxim MAX17042/17047/17050/8997/8966 Fuel Gauge" + tristate "Maxim MAX17042/8997/8966 Fuel Gauge" depends on I2C help MAX17042 is fuel-gauge systems for lithium-ion (Li+) batteries in handheld and portable equipment. The MAX17042 is configured to operate with a single lithium cell. MAX8997 and MAX8966 are multi-function devices that include fuel gauages that are compatible - with MAX17042. This driver also supports max17047/50 chips which are - improved version of max17042. + with MAX17042. config BATTERY_Z2 tristate "Z2 battery driver" @@ -292,7 +291,6 @@ config CHARGER_MAX8998 config CHARGER_SMB347 tristate "Summit Microelectronics SMB347 Battery Charger" depends on I2C - select REGMAP_I2C help Say Y to include support for Summit Microelectronics SMB347 Battery Charger. diff --git a/trunk/drivers/power/ab8500_btemp.c b/trunk/drivers/power/ab8500_btemp.c index bba3ccac72fe..d8bb99394ac0 100644 --- a/trunk/drivers/power/ab8500_btemp.c +++ b/trunk/drivers/power/ab8500_btemp.c @@ -964,15 +964,10 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev) { int irq, i, ret = 0; u8 val; - struct abx500_bm_plat_data *plat_data = pdev->dev.platform_data; - struct ab8500_btemp *di; - - if (!plat_data) { - dev_err(&pdev->dev, "No platform data\n"); - return -EINVAL; - } + struct abx500_bm_plat_data *plat_data; - di = kzalloc(sizeof(*di), GFP_KERNEL); + struct ab8500_btemp *di = + kzalloc(sizeof(struct ab8500_btemp), GFP_KERNEL); if (!di) return -ENOMEM; @@ -982,6 +977,7 @@ static int __devinit ab8500_btemp_probe(struct platform_device *pdev) di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); /* get btemp specific platform data */ + plat_data = pdev->dev.platform_data; di->pdata = plat_data->btemp; if (!di->pdata) { dev_err(di->dev, "no btemp platform data supplied\n"); diff --git a/trunk/drivers/power/ab8500_charger.c b/trunk/drivers/power/ab8500_charger.c index d2303d0b7c75..e2b4accbec88 100644 --- a/trunk/drivers/power/ab8500_charger.c +++ b/trunk/drivers/power/ab8500_charger.c @@ -2534,15 +2534,10 @@ static int __devexit ab8500_charger_remove(struct platform_device *pdev) static int __devinit ab8500_charger_probe(struct platform_device *pdev) { int irq, i, charger_status, ret = 0; - struct abx500_bm_plat_data *plat_data = pdev->dev.platform_data; - struct ab8500_charger *di; - - if (!plat_data) { - dev_err(&pdev->dev, "No platform data\n"); - return -EINVAL; - } + struct abx500_bm_plat_data *plat_data; - di = kzalloc(sizeof(*di), GFP_KERNEL); + struct ab8500_charger *di = + kzalloc(sizeof(struct ab8500_charger), GFP_KERNEL); if (!di) return -ENOMEM; @@ -2555,7 +2550,9 @@ static int __devinit ab8500_charger_probe(struct platform_device *pdev) spin_lock_init(&di->usb_state.usb_lock); /* get charger specific platform data */ + plat_data = pdev->dev.platform_data; di->pdata = plat_data->charger; + if (!di->pdata) { dev_err(di->dev, "no charger platform data supplied\n"); ret = -EINVAL; diff --git a/trunk/drivers/power/ab8500_fg.c b/trunk/drivers/power/ab8500_fg.c index bf022255994c..c22f2f05657e 100644 --- a/trunk/drivers/power/ab8500_fg.c +++ b/trunk/drivers/power/ab8500_fg.c @@ -2446,15 +2446,10 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev) { int i, irq; int ret = 0; - struct abx500_bm_plat_data *plat_data = pdev->dev.platform_data; - struct ab8500_fg *di; - - if (!plat_data) { - dev_err(&pdev->dev, "No platform data\n"); - return -EINVAL; - } + struct abx500_bm_plat_data *plat_data; - di = kzalloc(sizeof(*di), GFP_KERNEL); + struct ab8500_fg *di = + kzalloc(sizeof(struct ab8500_fg), GFP_KERNEL); if (!di) return -ENOMEM; @@ -2466,6 +2461,7 @@ static int __devinit ab8500_fg_probe(struct platform_device *pdev) di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); /* get fg specific platform data */ + plat_data = pdev->dev.platform_data; di->pdata = plat_data->fg; if (!di->pdata) { dev_err(di->dev, "no fg platform data supplied\n"); diff --git a/trunk/drivers/power/charger-manager.c b/trunk/drivers/power/charger-manager.c index 86935ec18954..9eca9f1ff0ea 100644 --- a/trunk/drivers/power/charger-manager.c +++ b/trunk/drivers/power/charger-manager.c @@ -23,16 +23,6 @@ #include #include -static const char * const default_event_names[] = { - [CM_EVENT_UNKNOWN] = "Unknown", - [CM_EVENT_BATT_FULL] = "Battery Full", - [CM_EVENT_BATT_IN] = "Battery Inserted", - [CM_EVENT_BATT_OUT] = "Battery Pulled Out", - [CM_EVENT_EXT_PWR_IN_OUT] = "External Power Attach/Detach", - [CM_EVENT_CHG_START_STOP] = "Charging Start/Stop", - [CM_EVENT_OTHERS] = "Other battery events" -}; - /* * Regard CM_JIFFIES_SMALL jiffies is small enough to ignore for * delayed works so that we can run delayed works with CM_JIFFIES_SMALL @@ -67,12 +57,6 @@ static bool cm_suspended; static bool cm_rtc_set; static unsigned long cm_suspend_duration_ms; -/* About normal (not suspended) monitoring */ -static unsigned long polling_jiffy = ULONG_MAX; /* ULONG_MAX: no polling */ -static unsigned long next_polling; /* Next appointed polling time */ -static struct workqueue_struct *cm_wq; /* init at driver add */ -static struct delayed_work cm_monitor_work; /* init at driver add */ - /* Global charger-manager description */ static struct charger_global_desc *g_desc; /* init with setup_charger_manager */ @@ -87,11 +71,6 @@ static bool is_batt_present(struct charger_manager *cm) int i, ret; switch (cm->desc->battery_present) { - case CM_BATTERY_PRESENT: - present = true; - break; - case CM_NO_BATTERY: - break; case CM_FUEL_GAUGE: ret = cm->fuel_gauge->get_property(cm->fuel_gauge, POWER_SUPPLY_PROP_PRESENT, &val); @@ -299,26 +278,6 @@ static int try_charger_enable(struct charger_manager *cm, bool enable) return err; } -/** - * try_charger_restart - Restart charging. - * @cm: the Charger Manager representing the battery. - * - * Restart charging by turning off and on the charger. - */ -static int try_charger_restart(struct charger_manager *cm) -{ - int err; - - if (cm->emergency_stop) - return -EAGAIN; - - err = try_charger_enable(cm, false); - if (err) - return err; - - return try_charger_enable(cm, true); -} - /** * uevent_notify - Let users know something has changed. * @cm: the Charger Manager representing the battery. @@ -374,46 +333,6 @@ static void uevent_notify(struct charger_manager *cm, const char *event) dev_info(cm->dev, event); } -/** - * fullbatt_vchk - Check voltage drop some times after "FULL" event. - * @work: the work_struct appointing the function - * - * If a user has designated "fullbatt_vchkdrop_ms/uV" values with - * charger_desc, Charger Manager checks voltage drop after the battery - * "FULL" event. It checks whether the voltage has dropped more than - * fullbatt_vchkdrop_uV by calling this function after fullbatt_vchkrop_ms. - */ -static void fullbatt_vchk(struct work_struct *work) -{ - struct delayed_work *dwork = to_delayed_work(work); - struct charger_manager *cm = container_of(dwork, - struct charger_manager, fullbatt_vchk_work); - struct charger_desc *desc = cm->desc; - int batt_uV, err, diff; - - /* remove the appointment for fullbatt_vchk */ - cm->fullbatt_vchk_jiffies_at = 0; - - if (!desc->fullbatt_vchkdrop_uV || !desc->fullbatt_vchkdrop_ms) - return; - - err = get_batt_uV(cm, &batt_uV); - if (err) { - dev_err(cm->dev, "%s: get_batt_uV error(%d).\n", __func__, err); - return; - } - - diff = cm->fullbatt_vchk_uV; - diff -= batt_uV; - - dev_dbg(cm->dev, "VBATT dropped %duV after full-batt.\n", diff); - - if (diff > desc->fullbatt_vchkdrop_uV) { - try_charger_restart(cm); - uevent_notify(cm, "Recharge"); - } -} - /** * _cm_monitor - Monitor the temperature and return true for exceptions. * @cm: the Charger Manager representing the battery. @@ -473,131 +392,6 @@ static bool cm_monitor(void) return stop; } -/** - * _setup_polling - Setup the next instance of polling. - * @work: work_struct of the function _setup_polling. - */ -static void _setup_polling(struct work_struct *work) -{ - unsigned long min = ULONG_MAX; - struct charger_manager *cm; - bool keep_polling = false; - unsigned long _next_polling; - - mutex_lock(&cm_list_mtx); - - list_for_each_entry(cm, &cm_list, entry) { - if (is_polling_required(cm) && cm->desc->polling_interval_ms) { - keep_polling = true; - - if (min > cm->desc->polling_interval_ms) - min = cm->desc->polling_interval_ms; - } - } - - polling_jiffy = msecs_to_jiffies(min); - if (polling_jiffy <= CM_JIFFIES_SMALL) - polling_jiffy = CM_JIFFIES_SMALL + 1; - - if (!keep_polling) - polling_jiffy = ULONG_MAX; - if (polling_jiffy == ULONG_MAX) - goto out; - - WARN(cm_wq == NULL, "charger-manager: workqueue not initialized" - ". try it later. %s\n", __func__); - - _next_polling = jiffies + polling_jiffy; - - if (!delayed_work_pending(&cm_monitor_work) || - (delayed_work_pending(&cm_monitor_work) && - time_after(next_polling, _next_polling))) { - cancel_delayed_work_sync(&cm_monitor_work); - next_polling = jiffies + polling_jiffy; - queue_delayed_work(cm_wq, &cm_monitor_work, polling_jiffy); - } - -out: - mutex_unlock(&cm_list_mtx); -} -static DECLARE_WORK(setup_polling, _setup_polling); - -/** - * cm_monitor_poller - The Monitor / Poller. - * @work: work_struct of the function cm_monitor_poller - * - * During non-suspended state, cm_monitor_poller is used to poll and monitor - * the batteries. - */ -static void cm_monitor_poller(struct work_struct *work) -{ - cm_monitor(); - schedule_work(&setup_polling); -} - -/** - * fullbatt_handler - Event handler for CM_EVENT_BATT_FULL - * @cm: the Charger Manager representing the battery. - */ -static void fullbatt_handler(struct charger_manager *cm) -{ - struct charger_desc *desc = cm->desc; - - if (!desc->fullbatt_vchkdrop_uV || !desc->fullbatt_vchkdrop_ms) - goto out; - - if (cm_suspended) - device_set_wakeup_capable(cm->dev, true); - - if (delayed_work_pending(&cm->fullbatt_vchk_work)) - cancel_delayed_work(&cm->fullbatt_vchk_work); - queue_delayed_work(cm_wq, &cm->fullbatt_vchk_work, - msecs_to_jiffies(desc->fullbatt_vchkdrop_ms)); - cm->fullbatt_vchk_jiffies_at = jiffies + msecs_to_jiffies( - desc->fullbatt_vchkdrop_ms); - - if (cm->fullbatt_vchk_jiffies_at == 0) - cm->fullbatt_vchk_jiffies_at = 1; - -out: - dev_info(cm->dev, "EVENT_HANDLE: Battery Fully Charged.\n"); - uevent_notify(cm, default_event_names[CM_EVENT_BATT_FULL]); -} - -/** - * battout_handler - Event handler for CM_EVENT_BATT_OUT - * @cm: the Charger Manager representing the battery. - */ -static void battout_handler(struct charger_manager *cm) -{ - if (cm_suspended) - device_set_wakeup_capable(cm->dev, true); - - if (!is_batt_present(cm)) { - dev_emerg(cm->dev, "Battery Pulled Out!\n"); - uevent_notify(cm, default_event_names[CM_EVENT_BATT_OUT]); - } else { - uevent_notify(cm, "Battery Reinserted?"); - } -} - -/** - * misc_event_handler - Handler for other evnets - * @cm: the Charger Manager representing the battery. - * @type: the Charger Manager representing the battery. - */ -static void misc_event_handler(struct charger_manager *cm, - enum cm_event_types type) -{ - if (cm_suspended) - device_set_wakeup_capable(cm->dev, true); - - if (!delayed_work_pending(&cm_monitor_work) && - is_polling_required(cm) && cm->desc->polling_interval_ms) - schedule_work(&setup_polling); - uevent_notify(cm, default_event_names[type]); -} - static int charger_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) @@ -819,21 +613,6 @@ static bool cm_setup_timer(void) mutex_lock(&cm_list_mtx); list_for_each_entry(cm, &cm_list, entry) { - unsigned int fbchk_ms = 0; - - /* fullbatt_vchk is required. setup timer for that */ - if (cm->fullbatt_vchk_jiffies_at) { - fbchk_ms = jiffies_to_msecs(cm->fullbatt_vchk_jiffies_at - - jiffies); - if (time_is_before_eq_jiffies( - cm->fullbatt_vchk_jiffies_at) || - msecs_to_jiffies(fbchk_ms) < CM_JIFFIES_SMALL) { - fullbatt_vchk(&cm->fullbatt_vchk_work.work); - fbchk_ms = 0; - } - } - CM_MIN_VALID(wakeup_ms, fbchk_ms); - /* Skip if polling is not required for this CM */ if (!is_polling_required(cm) && !cm->emergency_stop) continue; @@ -893,23 +672,6 @@ static bool cm_setup_timer(void) return false; } -static void _cm_fbchk_in_suspend(struct charger_manager *cm) -{ - unsigned long jiffy_now = jiffies; - - if (!cm->fullbatt_vchk_jiffies_at) - return; - - if (g_desc && g_desc->assume_timer_stops_in_suspend) - jiffy_now += msecs_to_jiffies(cm_suspend_duration_ms); - - /* Execute now if it's going to be executed not too long after */ - jiffy_now += CM_JIFFIES_SMALL; - - if (time_after_eq(jiffy_now, cm->fullbatt_vchk_jiffies_at)) - fullbatt_vchk(&cm->fullbatt_vchk_work.work); -} - /** * cm_suspend_again - Determine whether suspend again or not * @@ -931,8 +693,6 @@ bool cm_suspend_again(void) ret = true; mutex_lock(&cm_list_mtx); list_for_each_entry(cm, &cm_list, entry) { - _cm_fbchk_in_suspend(cm); - if (cm->status_save_ext_pwr_inserted != is_ext_pwr_online(cm) || cm->status_save_batt != is_batt_present(cm)) { ret = false; @@ -1036,21 +796,6 @@ static int charger_manager_probe(struct platform_device *pdev) memcpy(cm->desc, desc, sizeof(struct charger_desc)); cm->last_temp_mC = INT_MIN; /* denotes "unmeasured, yet" */ - /* - * The following two do not need to be errors. - * Users may intentionally ignore those two features. - */ - if (desc->fullbatt_uV == 0) { - dev_info(&pdev->dev, "Ignoring full-battery voltage threshold" - " as it is not supplied."); - } - if (!desc->fullbatt_vchkdrop_ms || !desc->fullbatt_vchkdrop_uV) { - dev_info(&pdev->dev, "Disabling full-battery voltage drop " - "checking mechanism as it is not supplied."); - desc->fullbatt_vchkdrop_ms = 0; - desc->fullbatt_vchkdrop_uV = 0; - } - if (!desc->charger_regulators || desc->num_charger_regulators < 1) { ret = -EINVAL; dev_err(&pdev->dev, "charger_regulators undefined.\n"); @@ -1158,8 +903,6 @@ static int charger_manager_probe(struct platform_device *pdev) cm->charger_psy.num_properties++; } - INIT_DELAYED_WORK(&cm->fullbatt_vchk_work, fullbatt_vchk); - ret = power_supply_register(NULL, &cm->charger_psy); if (ret) { dev_err(&pdev->dev, "Cannot register charger-manager with" @@ -1185,15 +928,6 @@ static int charger_manager_probe(struct platform_device *pdev) list_add(&cm->entry, &cm_list); mutex_unlock(&cm_list_mtx); - /* - * Charger-manager is capable of waking up the systme from sleep - * when event is happend through cm_notify_event() - */ - device_init_wakeup(&pdev->dev, true); - device_set_wakeup_capable(&pdev->dev, false); - - schedule_work(&setup_polling); - return 0; err_chg_enable: @@ -1224,17 +958,9 @@ static int __devexit charger_manager_remove(struct platform_device *pdev) list_del(&cm->entry); mutex_unlock(&cm_list_mtx); - if (work_pending(&setup_polling)) - cancel_work_sync(&setup_polling); - if (delayed_work_pending(&cm_monitor_work)) - cancel_delayed_work_sync(&cm_monitor_work); - regulator_bulk_free(desc->num_charger_regulators, desc->charger_regulators); power_supply_unregister(&cm->charger_psy); - - try_charger_enable(cm, false); - kfree(cm->charger_psy.properties); kfree(cm->charger_stat); kfree(cm->desc); @@ -1249,18 +975,6 @@ static const struct platform_device_id charger_manager_id[] = { }; MODULE_DEVICE_TABLE(platform, charger_manager_id); -static int cm_suspend_noirq(struct device *dev) -{ - int ret = 0; - - if (device_may_wakeup(dev)) { - device_set_wakeup_capable(dev, false); - ret = -EAGAIN; - } - - return ret; -} - static int cm_suspend_prepare(struct device *dev) { struct charger_manager *cm = dev_get_drvdata(dev); @@ -1286,8 +1000,6 @@ static int cm_suspend_prepare(struct device *dev) cm_suspended = true; } - if (delayed_work_pending(&cm->fullbatt_vchk_work)) - cancel_delayed_work(&cm->fullbatt_vchk_work); cm->status_save_ext_pwr_inserted = is_ext_pwr_online(cm); cm->status_save_batt = is_batt_present(cm); @@ -1315,40 +1027,11 @@ static void cm_suspend_complete(struct device *dev) cm_rtc_set = false; } - /* Re-enqueue delayed work (fullbatt_vchk_work) */ - if (cm->fullbatt_vchk_jiffies_at) { - unsigned long delay = 0; - unsigned long now = jiffies + CM_JIFFIES_SMALL; - - if (time_after_eq(now, cm->fullbatt_vchk_jiffies_at)) { - delay = (unsigned long)((long)now - - (long)(cm->fullbatt_vchk_jiffies_at)); - delay = jiffies_to_msecs(delay); - } else { - delay = 0; - } - - /* - * Account for cm_suspend_duration_ms if - * assume_timer_stops_in_suspend is active - */ - if (g_desc && g_desc->assume_timer_stops_in_suspend) { - if (delay > cm_suspend_duration_ms) - delay -= cm_suspend_duration_ms; - else - delay = 0; - } - - queue_delayed_work(cm_wq, &cm->fullbatt_vchk_work, - msecs_to_jiffies(delay)); - } - device_set_wakeup_capable(cm->dev, false); uevent_notify(cm, NULL); } static const struct dev_pm_ops charger_manager_pm = { .prepare = cm_suspend_prepare, - .suspend_noirq = cm_suspend_noirq, .complete = cm_suspend_complete, }; @@ -1365,91 +1048,16 @@ static struct platform_driver charger_manager_driver = { static int __init charger_manager_init(void) { - cm_wq = create_freezable_workqueue("charger_manager"); - INIT_DELAYED_WORK(&cm_monitor_work, cm_monitor_poller); - return platform_driver_register(&charger_manager_driver); } late_initcall(charger_manager_init); static void __exit charger_manager_cleanup(void) { - destroy_workqueue(cm_wq); - cm_wq = NULL; - platform_driver_unregister(&charger_manager_driver); } module_exit(charger_manager_cleanup); -/** - * find_power_supply - find the associated power_supply of charger - * @cm: the Charger Manager representing the battery - * @psy: pointer to instance of charger's power_supply - */ -static bool find_power_supply(struct charger_manager *cm, - struct power_supply *psy) -{ - int i; - bool found = false; - - for (i = 0; cm->charger_stat[i]; i++) { - if (psy == cm->charger_stat[i]) { - found = true; - break; - } - } - - return found; -} - -/** - * cm_notify_event - charger driver notify Charger Manager of charger event - * @psy: pointer to instance of charger's power_supply - * @type: type of charger event - * @msg: optional message passed to uevent_notify fuction - */ -void cm_notify_event(struct power_supply *psy, enum cm_event_types type, - char *msg) -{ - struct charger_manager *cm; - bool found_power_supply = false; - - if (psy == NULL) - return; - - mutex_lock(&cm_list_mtx); - list_for_each_entry(cm, &cm_list, entry) { - found_power_supply = find_power_supply(cm, psy); - if (found_power_supply) - break; - } - mutex_unlock(&cm_list_mtx); - - if (!found_power_supply) - return; - - switch (type) { - case CM_EVENT_BATT_FULL: - fullbatt_handler(cm); - break; - case CM_EVENT_BATT_OUT: - battout_handler(cm); - break; - case CM_EVENT_BATT_IN: - case CM_EVENT_EXT_PWR_IN_OUT ... CM_EVENT_CHG_START_STOP: - misc_event_handler(cm, type); - break; - case CM_EVENT_UNKNOWN: - case CM_EVENT_OTHERS: - uevent_notify(cm, msg ? msg : default_event_names[type]); - break; - default: - dev_err(cm->dev, "%s type not specified.\n", __func__); - break; - } -} -EXPORT_SYMBOL_GPL(cm_notify_event); - MODULE_AUTHOR("MyungJoo Ham "); MODULE_DESCRIPTION("Charger Manager"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/power/ds2781_battery.c b/trunk/drivers/power/ds2781_battery.c index 975684a40f15..ca0d653d0a7a 100644 --- a/trunk/drivers/power/ds2781_battery.c +++ b/trunk/drivers/power/ds2781_battery.c @@ -643,7 +643,9 @@ static ssize_t ds2781_read_param_eeprom_bin(struct file *filp, struct power_supply *psy = to_power_supply(dev); struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); - count = min_t(loff_t, count, DS2781_PARAM_EEPROM_SIZE - off); + count = min_t(loff_t, count, + DS2781_EEPROM_BLOCK1_END - + DS2781_EEPROM_BLOCK1_START + 1 - off); return ds2781_read_block(dev_info, buf, DS2781_EEPROM_BLOCK1_START + off, count); @@ -659,7 +661,9 @@ static ssize_t ds2781_write_param_eeprom_bin(struct file *filp, struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); int ret; - count = min_t(loff_t, count, DS2781_PARAM_EEPROM_SIZE - off); + count = min_t(loff_t, count, + DS2781_EEPROM_BLOCK1_END - + DS2781_EEPROM_BLOCK1_START + 1 - off); ret = ds2781_write(dev_info, buf, DS2781_EEPROM_BLOCK1_START + off, count); @@ -678,7 +682,7 @@ static struct bin_attribute ds2781_param_eeprom_bin_attr = { .name = "param_eeprom", .mode = S_IRUGO | S_IWUSR, }, - .size = DS2781_PARAM_EEPROM_SIZE, + .size = DS2781_EEPROM_BLOCK1_END - DS2781_EEPROM_BLOCK1_START + 1, .read = ds2781_read_param_eeprom_bin, .write = ds2781_write_param_eeprom_bin, }; @@ -692,7 +696,9 @@ static ssize_t ds2781_read_user_eeprom_bin(struct file *filp, struct power_supply *psy = to_power_supply(dev); struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); - count = min_t(loff_t, count, DS2781_USER_EEPROM_SIZE - off); + count = min_t(loff_t, count, + DS2781_EEPROM_BLOCK0_END - + DS2781_EEPROM_BLOCK0_START + 1 - off); return ds2781_read_block(dev_info, buf, DS2781_EEPROM_BLOCK0_START + off, count); @@ -709,7 +715,9 @@ static ssize_t ds2781_write_user_eeprom_bin(struct file *filp, struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); int ret; - count = min_t(loff_t, count, DS2781_USER_EEPROM_SIZE - off); + count = min_t(loff_t, count, + DS2781_EEPROM_BLOCK0_END - + DS2781_EEPROM_BLOCK0_START + 1 - off); ret = ds2781_write(dev_info, buf, DS2781_EEPROM_BLOCK0_START + off, count); @@ -728,7 +736,7 @@ static struct bin_attribute ds2781_user_eeprom_bin_attr = { .name = "user_eeprom", .mode = S_IRUGO | S_IWUSR, }, - .size = DS2781_USER_EEPROM_SIZE, + .size = DS2781_EEPROM_BLOCK0_END - DS2781_EEPROM_BLOCK0_START + 1, .read = ds2781_read_user_eeprom_bin, .write = ds2781_write_user_eeprom_bin, }; diff --git a/trunk/drivers/power/isp1704_charger.c b/trunk/drivers/power/isp1704_charger.c index e5ccd2979773..39eb50f35f09 100644 --- a/trunk/drivers/power/isp1704_charger.c +++ b/trunk/drivers/power/isp1704_charger.c @@ -474,13 +474,13 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev) fail2: power_supply_unregister(&isp->psy); fail1: - isp1704_charger_set_power(isp, 0); usb_put_transceiver(isp->phy); fail0: kfree(isp); dev_err(&pdev->dev, "failed to register isp1704 with error %d\n", ret); + isp1704_charger_set_power(isp, 0); return ret; } diff --git a/trunk/drivers/power/max17042_battery.c b/trunk/drivers/power/max17042_battery.c index 140788b309f8..04620c2cb388 100644 --- a/trunk/drivers/power/max17042_battery.c +++ b/trunk/drivers/power/max17042_battery.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -62,13 +61,9 @@ #define dP_ACC_100 0x1900 #define dP_ACC_200 0x3200 -#define MAX17042_IC_VERSION 0x0092 -#define MAX17047_IC_VERSION 0x00AC /* same for max17050 */ - struct max17042_chip { struct i2c_client *client; struct power_supply battery; - enum max170xx_chip_type chip_type; struct max17042_platform_data *pdata; struct work_struct work; int init_complete; @@ -110,7 +105,6 @@ static enum power_supply_property max17042_battery_props[] = { POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_VOLTAGE_AVG, - POWER_SUPPLY_PROP_VOLTAGE_OCV, POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_TEMP, @@ -156,10 +150,7 @@ static int max17042_get_property(struct power_supply *psy, val->intval *= 20000; /* Units of LSB = 20mV */ break; case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: - if (chip->chip_type == MAX17042) - ret = max17042_read_reg(chip->client, MAX17042_V_empty); - else - ret = max17042_read_reg(chip->client, MAX17047_V_empty); + ret = max17042_read_reg(chip->client, MAX17042_V_empty); if (ret < 0) return ret; @@ -178,13 +169,6 @@ static int max17042_get_property(struct power_supply *psy, if (ret < 0) return ret; - val->intval = ret * 625 / 8; - break; - case POWER_SUPPLY_PROP_VOLTAGE_OCV: - ret = max17042_read_reg(chip->client, MAX17042_OCVInternal); - if (ret < 0) - return ret; - val->intval = ret * 625 / 8; break; case POWER_SUPPLY_PROP_CAPACITY: @@ -341,10 +325,11 @@ static inline int max17042_model_data_compare(struct max17042_chip *chip, static int max17042_init_model(struct max17042_chip *chip) { int ret; - int table_size = ARRAY_SIZE(chip->pdata->config_data->cell_char_tbl); + int table_size = + sizeof(chip->pdata->config_data->cell_char_tbl)/sizeof(u16); u16 *temp_data; - temp_data = kcalloc(table_size, sizeof(*temp_data), GFP_KERNEL); + temp_data = kzalloc(table_size, GFP_KERNEL); if (!temp_data) return -ENOMEM; @@ -369,11 +354,12 @@ static int max17042_init_model(struct max17042_chip *chip) static int max17042_verify_model_lock(struct max17042_chip *chip) { int i; - int table_size = ARRAY_SIZE(chip->pdata->config_data->cell_char_tbl); + int table_size = + sizeof(chip->pdata->config_data->cell_char_tbl); u16 *temp_data; int ret = 0; - temp_data = kcalloc(table_size, sizeof(*temp_data), GFP_KERNEL); + temp_data = kzalloc(table_size, GFP_KERNEL); if (!temp_data) return -ENOMEM; @@ -396,9 +382,6 @@ static void max17042_write_config_regs(struct max17042_chip *chip) max17042_write_reg(chip->client, MAX17042_FilterCFG, config->filter_cfg); max17042_write_reg(chip->client, MAX17042_RelaxCFG, config->relax_cfg); - if (chip->chip_type == MAX17047) - max17042_write_reg(chip->client, MAX17047_FullSOCThr, - config->full_soc_thresh); } static void max17042_write_custom_regs(struct max17042_chip *chip) @@ -409,23 +392,12 @@ static void max17042_write_custom_regs(struct max17042_chip *chip) config->rcomp0); max17042_write_verify_reg(chip->client, MAX17042_TempCo, config->tcompc0); + max17042_write_reg(chip->client, MAX17042_EmptyTempCo, + config->empty_tempco); + max17042_write_verify_reg(chip->client, MAX17042_K_empty0, + config->kempty0); max17042_write_verify_reg(chip->client, MAX17042_ICHGTerm, config->ichgt_term); - if (chip->chip_type == MAX17042) { - max17042_write_reg(chip->client, MAX17042_EmptyTempCo, - config->empty_tempco); - max17042_write_verify_reg(chip->client, MAX17042_K_empty0, - config->kempty0); - } else { - max17042_write_verify_reg(chip->client, MAX17047_QRTbl00, - config->qrtbl00); - max17042_write_verify_reg(chip->client, MAX17047_QRTbl10, - config->qrtbl10); - max17042_write_verify_reg(chip->client, MAX17047_QRTbl20, - config->qrtbl20); - max17042_write_verify_reg(chip->client, MAX17047_QRTbl30, - config->qrtbl30); - } } static void max17042_update_capacity_regs(struct max17042_chip *chip) @@ -481,8 +453,6 @@ static void max17042_load_new_capacity_params(struct max17042_chip *chip) config->design_cap); max17042_write_verify_reg(chip->client, MAX17042_FullCAPNom, config->fullcapnom); - /* Update SOC register with new SOC */ - max17042_write_reg(chip->client, MAX17042_RepSOC, vfSoc); } /* @@ -519,28 +489,20 @@ static inline void max17042_override_por_values(struct max17042_chip *chip) max17042_override_por(client, MAX17042_FullCAP, config->fullcap); max17042_override_por(client, MAX17042_FullCAPNom, config->fullcapnom); - if (chip->chip_type == MAX17042) - max17042_override_por(client, MAX17042_SOC_empty, - config->socempty); + max17042_override_por(client, MAX17042_SOC_empty, config->socempty); max17042_override_por(client, MAX17042_LAvg_empty, config->lavg_empty); max17042_override_por(client, MAX17042_dQacc, config->dqacc); max17042_override_por(client, MAX17042_dPacc, config->dpacc); - if (chip->chip_type == MAX17042) - max17042_override_por(client, MAX17042_V_empty, config->vempty); - else - max17042_override_por(client, MAX17047_V_empty, config->vempty); + max17042_override_por(client, MAX17042_V_empty, config->vempty); max17042_override_por(client, MAX17042_TempNom, config->temp_nom); max17042_override_por(client, MAX17042_TempLim, config->temp_lim); max17042_override_por(client, MAX17042_FCTC, config->fctc); max17042_override_por(client, MAX17042_RCOMP0, config->rcomp0); max17042_override_por(client, MAX17042_TempCo, config->tcompc0); - if (chip->chip_type) { - max17042_override_por(client, MAX17042_EmptyTempCo, - config->empty_tempco); - max17042_override_por(client, MAX17042_K_empty0, - config->kempty0); - } + max17042_override_por(client, MAX17042_EmptyTempCo, + config->empty_tempco); + max17042_override_por(client, MAX17042_K_empty0, config->kempty0); } static int max17042_init_chip(struct max17042_chip *chip) @@ -697,19 +659,7 @@ static int __devinit max17042_probe(struct i2c_client *client, i2c_set_clientdata(client, chip); - ret = max17042_read_reg(chip->client, MAX17042_DevName); - if (ret == MAX17042_IC_VERSION) { - dev_dbg(&client->dev, "chip type max17042 detected\n"); - chip->chip_type = MAX17042; - } else if (ret == MAX17047_IC_VERSION) { - dev_dbg(&client->dev, "chip type max17047/50 detected\n"); - chip->chip_type = MAX17047; - } else { - dev_err(&client->dev, "device version mismatch: %x\n", ret); - return -EIO; - } - - chip->battery.name = "max170xx_battery"; + chip->battery.name = "max17042_battery"; chip->battery.type = POWER_SUPPLY_TYPE_BATTERY; chip->battery.get_property = max17042_get_property; chip->battery.properties = max17042_battery_props; @@ -733,12 +683,6 @@ static int __devinit max17042_probe(struct i2c_client *client, max17042_write_reg(client, MAX17042_LearnCFG, 0x0007); } - ret = power_supply_register(&client->dev, &chip->battery); - if (ret) { - dev_err(&client->dev, "failed: power supply register\n"); - return ret; - } - if (client->irq) { ret = request_threaded_irq(client->irq, NULL, max17042_thread_handler, @@ -749,14 +693,13 @@ static int __devinit max17042_probe(struct i2c_client *client, reg |= CONFIG_ALRT_BIT_ENBL; max17042_write_reg(client, MAX17042_CONFIG, reg); max17042_set_soc_threshold(chip, 1); - } else { - client->irq = 0; + } else dev_err(&client->dev, "%s(): cannot get IRQ\n", __func__); - } } reg = max17042_read_reg(chip->client, MAX17042_STATUS); + if (reg & STATUS_POR_BIT) { INIT_WORK(&chip->work, max17042_init_worker); schedule_work(&chip->work); @@ -764,65 +707,23 @@ static int __devinit max17042_probe(struct i2c_client *client, chip->init_complete = 1; } - return 0; + ret = power_supply_register(&client->dev, &chip->battery); + if (ret) + dev_err(&client->dev, "failed: power supply register\n"); + return ret; } static int __devexit max17042_remove(struct i2c_client *client) { struct max17042_chip *chip = i2c_get_clientdata(client); - if (client->irq) - free_irq(client->irq, chip); power_supply_unregister(&chip->battery); return 0; } -#ifdef CONFIG_PM -static int max17042_suspend(struct device *dev) -{ - struct max17042_chip *chip = dev_get_drvdata(dev); - - /* - * disable the irq and enable irq_wake - * capability to the interrupt line. - */ - if (chip->client->irq) { - disable_irq(chip->client->irq); - enable_irq_wake(chip->client->irq); - } - - return 0; -} - -static int max17042_resume(struct device *dev) -{ - struct max17042_chip *chip = dev_get_drvdata(dev); - - if (chip->client->irq) { - disable_irq_wake(chip->client->irq); - enable_irq(chip->client->irq); - /* re-program the SOC thresholds to 1% change */ - max17042_set_soc_threshold(chip, 1); - } - - return 0; -} - -static const struct dev_pm_ops max17042_pm_ops = { - .suspend = max17042_suspend, - .resume = max17042_resume, -}; - -#define MAX17042_PM_OPS (&max17042_pm_ops) -#else -#define MAX17042_PM_OPS NULL -#endif - #ifdef CONFIG_OF static const struct of_device_id max17042_dt_match[] = { { .compatible = "maxim,max17042" }, - { .compatible = "maxim,max17047" }, - { .compatible = "maxim,max17050" }, { }, }; MODULE_DEVICE_TABLE(of, max17042_dt_match); @@ -830,8 +731,6 @@ MODULE_DEVICE_TABLE(of, max17042_dt_match); static const struct i2c_device_id max17042_id[] = { { "max17042", 0 }, - { "max17047", 1 }, - { "max17050", 2 }, { } }; MODULE_DEVICE_TABLE(i2c, max17042_id); @@ -840,7 +739,6 @@ static struct i2c_driver max17042_i2c_driver = { .driver = { .name = "max17042", .of_match_table = of_match_ptr(max17042_dt_match), - .pm = MAX17042_PM_OPS, }, .probe = max17042_probe, .remove = __devexit_p(max17042_remove), diff --git a/trunk/drivers/power/power_supply_sysfs.c b/trunk/drivers/power/power_supply_sysfs.c index 4150747f9186..4368e7d61316 100644 --- a/trunk/drivers/power/power_supply_sysfs.c +++ b/trunk/drivers/power/power_supply_sysfs.c @@ -146,7 +146,6 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(voltage_min_design), POWER_SUPPLY_ATTR(voltage_now), POWER_SUPPLY_ATTR(voltage_avg), - POWER_SUPPLY_ATTR(voltage_ocv), POWER_SUPPLY_ATTR(current_max), POWER_SUPPLY_ATTR(current_now), POWER_SUPPLY_ATTR(current_avg), diff --git a/trunk/drivers/power/sbs-battery.c b/trunk/drivers/power/sbs-battery.c index a5b6849d4123..06b659d91790 100644 --- a/trunk/drivers/power/sbs-battery.c +++ b/trunk/drivers/power/sbs-battery.c @@ -89,7 +89,7 @@ static const struct chip_data { [REG_CURRENT] = SBS_DATA(POWER_SUPPLY_PROP_CURRENT_NOW, 0x0A, -32768, 32767), [REG_CAPACITY] = - SBS_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0D, 0, 100), + SBS_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100), [REG_REMAINING_CAPACITY] = SBS_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535), [REG_REMAINING_CAPACITY_CHARGE] = diff --git a/trunk/drivers/power/smb347-charger.c b/trunk/drivers/power/smb347-charger.c index f8eedd8a676f..ce1694d1a365 100644 --- a/trunk/drivers/power/smb347-charger.c +++ b/trunk/drivers/power/smb347-charger.c @@ -11,7 +11,7 @@ * published by the Free Software Foundation. */ -#include +#include #include #include #include @@ -21,7 +21,7 @@ #include #include #include -#include +#include /* * Configuration registers. These are mirrored to volatile RAM and can be @@ -39,7 +39,6 @@ #define CFG_CURRENT_LIMIT_DC_SHIFT 4 #define CFG_CURRENT_LIMIT_USB_MASK 0x0f #define CFG_FLOAT_VOLTAGE 0x03 -#define CFG_FLOAT_VOLTAGE_FLOAT_MASK 0x3f #define CFG_FLOAT_VOLTAGE_THRESHOLD_MASK 0xc0 #define CFG_FLOAT_VOLTAGE_THRESHOLD_SHIFT 6 #define CFG_STAT 0x05 @@ -114,31 +113,29 @@ #define STAT_C_CHARGER_ERROR BIT(6) #define STAT_E 0x3f -#define SMB347_MAX_REGISTER 0x3f - /** * struct smb347_charger - smb347 charger instance * @lock: protects concurrent access to online variables - * @dev: pointer to device - * @regmap: pointer to driver regmap + * @client: pointer to i2c client * @mains: power_supply instance for AC/DC power * @usb: power_supply instance for USB power * @battery: power_supply instance for battery * @mains_online: is AC/DC input connected * @usb_online: is USB input connected * @charging_enabled: is charging enabled + * @dentry: for debugfs * @pdata: pointer to platform data */ struct smb347_charger { struct mutex lock; - struct device *dev; - struct regmap *regmap; + struct i2c_client *client; struct power_supply mains; struct power_supply usb; struct power_supply battery; bool mains_online; bool usb_online; bool charging_enabled; + struct dentry *dentry; const struct smb347_charger_platform_data *pdata; }; @@ -196,6 +193,14 @@ static const unsigned int ccc_tbl[] = { 1200000, }; +/* Convert register value to current using lookup table */ +static int hw_to_current(const unsigned int *tbl, size_t size, unsigned int val) +{ + if (val >= size) + return -EINVAL; + return tbl[val]; +} + /* Convert current to register value using lookup table */ static int current_to_hw(const unsigned int *tbl, size_t size, unsigned int val) { @@ -207,22 +212,43 @@ static int current_to_hw(const unsigned int *tbl, size_t size, unsigned int val) return i > 0 ? i - 1 : -EINVAL; } +static int smb347_read(struct smb347_charger *smb, u8 reg) +{ + int ret; + + ret = i2c_smbus_read_byte_data(smb->client, reg); + if (ret < 0) + dev_warn(&smb->client->dev, "failed to read reg 0x%x: %d\n", + reg, ret); + return ret; +} + +static int smb347_write(struct smb347_charger *smb, u8 reg, u8 val) +{ + int ret; + + ret = i2c_smbus_write_byte_data(smb->client, reg, val); + if (ret < 0) + dev_warn(&smb->client->dev, "failed to write reg 0x%x: %d\n", + reg, ret); + return ret; +} + /** - * smb347_update_ps_status - refreshes the power source status + * smb347_update_status - updates the charging status * @smb: pointer to smb347 charger instance * - * Function checks whether any power source is connected to the charger and - * updates internal state accordingly. If there is a change to previous state - * function returns %1, otherwise %0 and negative errno in case of errror. + * Function checks status of the charging and updates internal state + * accordingly. Returns %0 if there is no change in status, %1 if the + * status has changed and negative errno in case of failure. */ -static int smb347_update_ps_status(struct smb347_charger *smb) +static int smb347_update_status(struct smb347_charger *smb) { bool usb = false; bool dc = false; - unsigned int val; int ret; - ret = regmap_read(smb->regmap, IRQSTAT_E, &val); + ret = smb347_read(smb, IRQSTAT_E); if (ret < 0) return ret; @@ -231,9 +257,9 @@ static int smb347_update_ps_status(struct smb347_charger *smb) * platform data _and_ whether corresponding undervoltage is set. */ if (smb->pdata->use_mains) - dc = !(val & IRQSTAT_E_DCIN_UV_STAT); + dc = !(ret & IRQSTAT_E_DCIN_UV_STAT); if (smb->pdata->use_usb) - usb = !(val & IRQSTAT_E_USBIN_UV_STAT); + usb = !(ret & IRQSTAT_E_USBIN_UV_STAT); mutex_lock(&smb->lock); ret = smb->mains_online != dc || smb->usb_online != usb; @@ -245,15 +271,15 @@ static int smb347_update_ps_status(struct smb347_charger *smb) } /* - * smb347_is_ps_online - returns whether input power source is connected + * smb347_is_online - returns whether input power source is connected * @smb: pointer to smb347 charger instance * * Returns %true if input power source is connected. Note that this is * dependent on what platform has configured for usable power sources. For - * example if USB is disabled, this will return %false even if the USB cable - * is connected. + * example if USB is disabled, this will return %false even if the USB + * cable is connected. */ -static bool smb347_is_ps_online(struct smb347_charger *smb) +static bool smb347_is_online(struct smb347_charger *smb) { bool ret; @@ -273,17 +299,16 @@ static bool smb347_is_ps_online(struct smb347_charger *smb) */ static int smb347_charging_status(struct smb347_charger *smb) { - unsigned int val; int ret; - if (!smb347_is_ps_online(smb)) + if (!smb347_is_online(smb)) return 0; - ret = regmap_read(smb->regmap, STAT_C, &val); + ret = smb347_read(smb, STAT_C); if (ret < 0) return 0; - return (val & STAT_C_CHG_MASK) >> STAT_C_CHG_SHIFT; + return (ret & STAT_C_CHG_MASK) >> STAT_C_CHG_SHIFT; } static int smb347_charging_set(struct smb347_charger *smb, bool enable) @@ -291,17 +316,27 @@ static int smb347_charging_set(struct smb347_charger *smb, bool enable) int ret = 0; if (smb->pdata->enable_control != SMB347_CHG_ENABLE_SW) { - dev_dbg(smb->dev, "charging enable/disable in SW disabled\n"); + dev_dbg(&smb->client->dev, + "charging enable/disable in SW disabled\n"); return 0; } mutex_lock(&smb->lock); if (smb->charging_enabled != enable) { - ret = regmap_update_bits(smb->regmap, CMD_A, CMD_A_CHG_ENABLED, - enable ? CMD_A_CHG_ENABLED : 0); - if (!ret) - smb->charging_enabled = enable; + ret = smb347_read(smb, CMD_A); + if (ret < 0) + goto out; + + smb->charging_enabled = enable; + + if (enable) + ret |= CMD_A_CHG_ENABLED; + else + ret &= ~CMD_A_CHG_ENABLED; + + ret = smb347_write(smb, CMD_A, ret); } +out: mutex_unlock(&smb->lock); return ret; } @@ -316,7 +351,7 @@ static inline int smb347_charging_disable(struct smb347_charger *smb) return smb347_charging_set(smb, false); } -static int smb347_start_stop_charging(struct smb347_charger *smb) +static int smb347_update_online(struct smb347_charger *smb) { int ret; @@ -325,14 +360,16 @@ static int smb347_start_stop_charging(struct smb347_charger *smb) * disable or enable the charging. We do it manually because it * depends on how the platform has configured the valid inputs. */ - if (smb347_is_ps_online(smb)) { + if (smb347_is_online(smb)) { ret = smb347_charging_enable(smb); if (ret < 0) - dev_err(smb->dev, "failed to enable charging\n"); + dev_err(&smb->client->dev, + "failed to enable charging\n"); } else { ret = smb347_charging_disable(smb); if (ret < 0) - dev_err(smb->dev, "failed to disable charging\n"); + dev_err(&smb->client->dev, + "failed to disable charging\n"); } return ret; @@ -340,120 +377,112 @@ static int smb347_start_stop_charging(struct smb347_charger *smb) static int smb347_set_charge_current(struct smb347_charger *smb) { - int ret; + int ret, val; + + ret = smb347_read(smb, CFG_CHARGE_CURRENT); + if (ret < 0) + return ret; if (smb->pdata->max_charge_current) { - ret = current_to_hw(fcc_tbl, ARRAY_SIZE(fcc_tbl), + val = current_to_hw(fcc_tbl, ARRAY_SIZE(fcc_tbl), smb->pdata->max_charge_current); - if (ret < 0) - return ret; + if (val < 0) + return val; - ret = regmap_update_bits(smb->regmap, CFG_CHARGE_CURRENT, - CFG_CHARGE_CURRENT_FCC_MASK, - ret << CFG_CHARGE_CURRENT_FCC_SHIFT); - if (ret < 0) - return ret; + ret &= ~CFG_CHARGE_CURRENT_FCC_MASK; + ret |= val << CFG_CHARGE_CURRENT_FCC_SHIFT; } if (smb->pdata->pre_charge_current) { - ret = current_to_hw(pcc_tbl, ARRAY_SIZE(pcc_tbl), + val = current_to_hw(pcc_tbl, ARRAY_SIZE(pcc_tbl), smb->pdata->pre_charge_current); - if (ret < 0) - return ret; + if (val < 0) + return val; - ret = regmap_update_bits(smb->regmap, CFG_CHARGE_CURRENT, - CFG_CHARGE_CURRENT_PCC_MASK, - ret << CFG_CHARGE_CURRENT_PCC_SHIFT); - if (ret < 0) - return ret; + ret &= ~CFG_CHARGE_CURRENT_PCC_MASK; + ret |= val << CFG_CHARGE_CURRENT_PCC_SHIFT; } if (smb->pdata->termination_current) { - ret = current_to_hw(tc_tbl, ARRAY_SIZE(tc_tbl), + val = current_to_hw(tc_tbl, ARRAY_SIZE(tc_tbl), smb->pdata->termination_current); - if (ret < 0) - return ret; + if (val < 0) + return val; - ret = regmap_update_bits(smb->regmap, CFG_CHARGE_CURRENT, - CFG_CHARGE_CURRENT_TC_MASK, ret); - if (ret < 0) - return ret; + ret &= ~CFG_CHARGE_CURRENT_TC_MASK; + ret |= val; } - return 0; + return smb347_write(smb, CFG_CHARGE_CURRENT, ret); } static int smb347_set_current_limits(struct smb347_charger *smb) { - int ret; + int ret, val; + + ret = smb347_read(smb, CFG_CURRENT_LIMIT); + if (ret < 0) + return ret; if (smb->pdata->mains_current_limit) { - ret = current_to_hw(icl_tbl, ARRAY_SIZE(icl_tbl), + val = current_to_hw(icl_tbl, ARRAY_SIZE(icl_tbl), smb->pdata->mains_current_limit); - if (ret < 0) - return ret; + if (val < 0) + return val; - ret = regmap_update_bits(smb->regmap, CFG_CURRENT_LIMIT, - CFG_CURRENT_LIMIT_DC_MASK, - ret << CFG_CURRENT_LIMIT_DC_SHIFT); - if (ret < 0) - return ret; + ret &= ~CFG_CURRENT_LIMIT_DC_MASK; + ret |= val << CFG_CURRENT_LIMIT_DC_SHIFT; } if (smb->pdata->usb_hc_current_limit) { - ret = current_to_hw(icl_tbl, ARRAY_SIZE(icl_tbl), + val = current_to_hw(icl_tbl, ARRAY_SIZE(icl_tbl), smb->pdata->usb_hc_current_limit); - if (ret < 0) - return ret; + if (val < 0) + return val; - ret = regmap_update_bits(smb->regmap, CFG_CURRENT_LIMIT, - CFG_CURRENT_LIMIT_USB_MASK, ret); - if (ret < 0) - return ret; + ret &= ~CFG_CURRENT_LIMIT_USB_MASK; + ret |= val; } - return 0; + return smb347_write(smb, CFG_CURRENT_LIMIT, ret); } static int smb347_set_voltage_limits(struct smb347_charger *smb) { - int ret; + int ret, val; + + ret = smb347_read(smb, CFG_FLOAT_VOLTAGE); + if (ret < 0) + return ret; if (smb->pdata->pre_to_fast_voltage) { - ret = smb->pdata->pre_to_fast_voltage; + val = smb->pdata->pre_to_fast_voltage; /* uV */ - ret = clamp_val(ret, 2400000, 3000000) - 2400000; - ret /= 200000; + val = clamp_val(val, 2400000, 3000000) - 2400000; + val /= 200000; - ret = regmap_update_bits(smb->regmap, CFG_FLOAT_VOLTAGE, - CFG_FLOAT_VOLTAGE_THRESHOLD_MASK, - ret << CFG_FLOAT_VOLTAGE_THRESHOLD_SHIFT); - if (ret < 0) - return ret; + ret &= ~CFG_FLOAT_VOLTAGE_THRESHOLD_MASK; + ret |= val << CFG_FLOAT_VOLTAGE_THRESHOLD_SHIFT; } if (smb->pdata->max_charge_voltage) { - ret = smb->pdata->max_charge_voltage; + val = smb->pdata->max_charge_voltage; /* uV */ - ret = clamp_val(ret, 3500000, 4500000) - 3500000; - ret /= 20000; + val = clamp_val(val, 3500000, 4500000) - 3500000; + val /= 20000; - ret = regmap_update_bits(smb->regmap, CFG_FLOAT_VOLTAGE, - CFG_FLOAT_VOLTAGE_FLOAT_MASK, ret); - if (ret < 0) - return ret; + ret |= val; } - return 0; + return smb347_write(smb, CFG_FLOAT_VOLTAGE, ret); } static int smb347_set_temp_limits(struct smb347_charger *smb) { bool enable_therm_monitor = false; - int ret = 0; - int val; + int ret, val; if (smb->pdata->chip_temp_threshold) { val = smb->pdata->chip_temp_threshold; @@ -462,13 +491,22 @@ static int smb347_set_temp_limits(struct smb347_charger *smb) val = clamp_val(val, 100, 130) - 100; val /= 10; - ret = regmap_update_bits(smb->regmap, CFG_OTG, - CFG_OTG_TEMP_THRESHOLD_MASK, - val << CFG_OTG_TEMP_THRESHOLD_SHIFT); + ret = smb347_read(smb, CFG_OTG); + if (ret < 0) + return ret; + + ret &= ~CFG_OTG_TEMP_THRESHOLD_MASK; + ret |= val << CFG_OTG_TEMP_THRESHOLD_SHIFT; + + ret = smb347_write(smb, CFG_OTG, ret); if (ret < 0) return ret; } + ret = smb347_read(smb, CFG_TEMP_LIMIT); + if (ret < 0) + return ret; + if (smb->pdata->soft_cold_temp_limit != SMB347_TEMP_USE_DEFAULT) { val = smb->pdata->soft_cold_temp_limit; @@ -477,11 +515,8 @@ static int smb347_set_temp_limits(struct smb347_charger *smb) /* this goes from higher to lower so invert the value */ val = ~val & 0x3; - ret = regmap_update_bits(smb->regmap, CFG_TEMP_LIMIT, - CFG_TEMP_LIMIT_SOFT_COLD_MASK, - val << CFG_TEMP_LIMIT_SOFT_COLD_SHIFT); - if (ret < 0) - return ret; + ret &= ~CFG_TEMP_LIMIT_SOFT_COLD_MASK; + ret |= val << CFG_TEMP_LIMIT_SOFT_COLD_SHIFT; enable_therm_monitor = true; } @@ -492,11 +527,8 @@ static int smb347_set_temp_limits(struct smb347_charger *smb) val = clamp_val(val, 40, 55) - 40; val /= 5; - ret = regmap_update_bits(smb->regmap, CFG_TEMP_LIMIT, - CFG_TEMP_LIMIT_SOFT_HOT_MASK, - val << CFG_TEMP_LIMIT_SOFT_HOT_SHIFT); - if (ret < 0) - return ret; + ret &= ~CFG_TEMP_LIMIT_SOFT_HOT_MASK; + ret |= val << CFG_TEMP_LIMIT_SOFT_HOT_SHIFT; enable_therm_monitor = true; } @@ -509,11 +541,8 @@ static int smb347_set_temp_limits(struct smb347_charger *smb) /* this goes from higher to lower so invert the value */ val = ~val & 0x3; - ret = regmap_update_bits(smb->regmap, CFG_TEMP_LIMIT, - CFG_TEMP_LIMIT_HARD_COLD_MASK, - val << CFG_TEMP_LIMIT_HARD_COLD_SHIFT); - if (ret < 0) - return ret; + ret &= ~CFG_TEMP_LIMIT_HARD_COLD_MASK; + ret |= val << CFG_TEMP_LIMIT_HARD_COLD_SHIFT; enable_therm_monitor = true; } @@ -524,15 +553,16 @@ static int smb347_set_temp_limits(struct smb347_charger *smb) val = clamp_val(val, 50, 65) - 50; val /= 5; - ret = regmap_update_bits(smb->regmap, CFG_TEMP_LIMIT, - CFG_TEMP_LIMIT_HARD_HOT_MASK, - val << CFG_TEMP_LIMIT_HARD_HOT_SHIFT); - if (ret < 0) - return ret; + ret &= ~CFG_TEMP_LIMIT_HARD_HOT_MASK; + ret |= val << CFG_TEMP_LIMIT_HARD_HOT_SHIFT; enable_therm_monitor = true; } + ret = smb347_write(smb, CFG_TEMP_LIMIT, ret); + if (ret < 0) + return ret; + /* * If any of the temperature limits are set, we also enable the * thermistor monitoring. @@ -544,15 +574,25 @@ static int smb347_set_temp_limits(struct smb347_charger *smb) * depending on the configuration. */ if (enable_therm_monitor) { - ret = regmap_update_bits(smb->regmap, CFG_THERM, - CFG_THERM_MONITOR_DISABLED, 0); + ret = smb347_read(smb, CFG_THERM); + if (ret < 0) + return ret; + + ret &= ~CFG_THERM_MONITOR_DISABLED; + + ret = smb347_write(smb, CFG_THERM, ret); if (ret < 0) return ret; } if (smb->pdata->suspend_on_hard_temp_limit) { - ret = regmap_update_bits(smb->regmap, CFG_SYSOK, - CFG_SYSOK_SUSPEND_HARD_LIMIT_DISABLED, 0); + ret = smb347_read(smb, CFG_SYSOK); + if (ret < 0) + return ret; + + ret &= ~CFG_SYSOK_SUSPEND_HARD_LIMIT_DISABLED; + + ret = smb347_write(smb, CFG_SYSOK, ret); if (ret < 0) return ret; } @@ -561,15 +601,17 @@ static int smb347_set_temp_limits(struct smb347_charger *smb) SMB347_SOFT_TEMP_COMPENSATE_DEFAULT) { val = smb->pdata->soft_temp_limit_compensation & 0x3; - ret = regmap_update_bits(smb->regmap, CFG_THERM, - CFG_THERM_SOFT_HOT_COMPENSATION_MASK, - val << CFG_THERM_SOFT_HOT_COMPENSATION_SHIFT); + ret = smb347_read(smb, CFG_THERM); if (ret < 0) return ret; - ret = regmap_update_bits(smb->regmap, CFG_THERM, - CFG_THERM_SOFT_COLD_COMPENSATION_MASK, - val << CFG_THERM_SOFT_COLD_COMPENSATION_SHIFT); + ret &= ~CFG_THERM_SOFT_HOT_COMPENSATION_MASK; + ret |= val << CFG_THERM_SOFT_HOT_COMPENSATION_SHIFT; + + ret &= ~CFG_THERM_SOFT_COLD_COMPENSATION_MASK; + ret |= val << CFG_THERM_SOFT_COLD_COMPENSATION_SHIFT; + + ret = smb347_write(smb, CFG_THERM, ret); if (ret < 0) return ret; } @@ -580,9 +622,14 @@ static int smb347_set_temp_limits(struct smb347_charger *smb) if (val < 0) return val; - ret = regmap_update_bits(smb->regmap, CFG_OTG, - CFG_OTG_CC_COMPENSATION_MASK, - (val & 0x3) << CFG_OTG_CC_COMPENSATION_SHIFT); + ret = smb347_read(smb, CFG_OTG); + if (ret < 0) + return ret; + + ret &= ~CFG_OTG_CC_COMPENSATION_MASK; + ret |= (val & 0x3) << CFG_OTG_CC_COMPENSATION_SHIFT; + + ret = smb347_write(smb, CFG_OTG, ret); if (ret < 0) return ret; } @@ -601,13 +648,22 @@ static int smb347_set_temp_limits(struct smb347_charger *smb) */ static int smb347_set_writable(struct smb347_charger *smb, bool writable) { - return regmap_update_bits(smb->regmap, CMD_A, CMD_A_ALLOW_WRITE, - writable ? CMD_A_ALLOW_WRITE : 0); + int ret; + + ret = smb347_read(smb, CMD_A); + if (ret < 0) + return ret; + + if (writable) + ret |= CMD_A_ALLOW_WRITE; + else + ret &= ~CMD_A_ALLOW_WRITE; + + return smb347_write(smb, CMD_A, ret); } static int smb347_hw_init(struct smb347_charger *smb) { - unsigned int val; int ret; ret = smb347_set_writable(smb, true); @@ -636,19 +692,34 @@ static int smb347_hw_init(struct smb347_charger *smb) /* If USB charging is disabled we put the USB in suspend mode */ if (!smb->pdata->use_usb) { - ret = regmap_update_bits(smb->regmap, CMD_A, - CMD_A_SUSPEND_ENABLED, - CMD_A_SUSPEND_ENABLED); + ret = smb347_read(smb, CMD_A); + if (ret < 0) + goto fail; + + ret |= CMD_A_SUSPEND_ENABLED; + + ret = smb347_write(smb, CMD_A, ret); if (ret < 0) goto fail; } + ret = smb347_read(smb, CFG_OTHER); + if (ret < 0) + goto fail; + /* * If configured by platform data, we enable hardware Auto-OTG * support for driving VBUS. Otherwise we disable it. */ - ret = regmap_update_bits(smb->regmap, CFG_OTHER, CFG_OTHER_RID_MASK, - smb->pdata->use_usb_otg ? CFG_OTHER_RID_ENABLED_AUTO_OTG : 0); + ret &= ~CFG_OTHER_RID_MASK; + if (smb->pdata->use_usb_otg) + ret |= CFG_OTHER_RID_ENABLED_AUTO_OTG; + + ret = smb347_write(smb, CFG_OTHER, ret); + if (ret < 0) + goto fail; + + ret = smb347_read(smb, CFG_PIN); if (ret < 0) goto fail; @@ -657,33 +728,32 @@ static int smb347_hw_init(struct smb347_charger *smb) * command register unless pin control is specified in the platform * data. */ + ret &= ~CFG_PIN_EN_CTRL_MASK; + switch (smb->pdata->enable_control) { + case SMB347_CHG_ENABLE_SW: + /* Do nothing, 0 means i2c control */ + break; case SMB347_CHG_ENABLE_PIN_ACTIVE_LOW: - val = CFG_PIN_EN_CTRL_ACTIVE_LOW; + ret |= CFG_PIN_EN_CTRL_ACTIVE_LOW; break; case SMB347_CHG_ENABLE_PIN_ACTIVE_HIGH: - val = CFG_PIN_EN_CTRL_ACTIVE_HIGH; - break; - default: - val = 0; + ret |= CFG_PIN_EN_CTRL_ACTIVE_HIGH; break; } - ret = regmap_update_bits(smb->regmap, CFG_PIN, CFG_PIN_EN_CTRL_MASK, - val); - if (ret < 0) - goto fail; - /* Disable Automatic Power Source Detection (APSD) interrupt. */ - ret = regmap_update_bits(smb->regmap, CFG_PIN, CFG_PIN_EN_APSD_IRQ, 0); + ret &= ~CFG_PIN_EN_APSD_IRQ; + + ret = smb347_write(smb, CFG_PIN, ret); if (ret < 0) goto fail; - ret = smb347_update_ps_status(smb); + ret = smb347_update_status(smb); if (ret < 0) goto fail; - ret = smb347_start_stop_charging(smb); + ret = smb347_update_online(smb); fail: smb347_set_writable(smb, false); @@ -693,25 +763,24 @@ static int smb347_hw_init(struct smb347_charger *smb) static irqreturn_t smb347_interrupt(int irq, void *data) { struct smb347_charger *smb = data; - unsigned int stat_c, irqstat_e, irqstat_c; - bool handled = false; - int ret; + int stat_c, irqstat_e, irqstat_c; + irqreturn_t ret = IRQ_NONE; - ret = regmap_read(smb->regmap, STAT_C, &stat_c); - if (ret < 0) { - dev_warn(smb->dev, "reading STAT_C failed\n"); + stat_c = smb347_read(smb, STAT_C); + if (stat_c < 0) { + dev_warn(&smb->client->dev, "reading STAT_C failed\n"); return IRQ_NONE; } - ret = regmap_read(smb->regmap, IRQSTAT_C, &irqstat_c); - if (ret < 0) { - dev_warn(smb->dev, "reading IRQSTAT_C failed\n"); + irqstat_c = smb347_read(smb, IRQSTAT_C); + if (irqstat_c < 0) { + dev_warn(&smb->client->dev, "reading IRQSTAT_C failed\n"); return IRQ_NONE; } - ret = regmap_read(smb->regmap, IRQSTAT_E, &irqstat_e); - if (ret < 0) { - dev_warn(smb->dev, "reading IRQSTAT_E failed\n"); + irqstat_e = smb347_read(smb, IRQSTAT_E); + if (irqstat_e < 0) { + dev_warn(&smb->client->dev, "reading IRQSTAT_E failed\n"); return IRQ_NONE; } @@ -720,11 +789,13 @@ static irqreturn_t smb347_interrupt(int irq, void *data) * disable charging. */ if (stat_c & STAT_C_CHARGER_ERROR) { - dev_err(smb->dev, "error in charger, disabling charging\n"); + dev_err(&smb->client->dev, + "error in charger, disabling charging\n"); smb347_charging_disable(smb); power_supply_changed(&smb->battery); - handled = true; + + ret = IRQ_HANDLED; } /* @@ -735,7 +806,7 @@ static irqreturn_t smb347_interrupt(int irq, void *data) if (irqstat_c & (IRQSTAT_C_TERMINATION_IRQ | IRQSTAT_C_TAPER_IRQ)) { if (irqstat_c & IRQSTAT_C_TERMINATION_STAT) power_supply_changed(&smb->battery); - handled = true; + ret = IRQ_HANDLED; } /* @@ -743,17 +814,15 @@ static irqreturn_t smb347_interrupt(int irq, void *data) * was connected or disconnected. */ if (irqstat_e & (IRQSTAT_E_USBIN_UV_IRQ | IRQSTAT_E_DCIN_UV_IRQ)) { - if (smb347_update_ps_status(smb) > 0) { - smb347_start_stop_charging(smb); - if (smb->pdata->use_mains) - power_supply_changed(&smb->mains); - if (smb->pdata->use_usb) - power_supply_changed(&smb->usb); + if (smb347_update_status(smb) > 0) { + smb347_update_online(smb); + power_supply_changed(&smb->mains); + power_supply_changed(&smb->usb); } - handled = true; + ret = IRQ_HANDLED; } - return handled ? IRQ_HANDLED : IRQ_NONE; + return ret; } static int smb347_irq_set(struct smb347_charger *smb, bool enable) @@ -770,18 +839,41 @@ static int smb347_irq_set(struct smb347_charger *smb, bool enable) * - termination current reached * - charger error */ - ret = regmap_update_bits(smb->regmap, CFG_FAULT_IRQ, 0xff, - enable ? CFG_FAULT_IRQ_DCIN_UV : 0); - if (ret < 0) - goto fail; + if (enable) { + ret = smb347_write(smb, CFG_FAULT_IRQ, CFG_FAULT_IRQ_DCIN_UV); + if (ret < 0) + goto fail; - ret = regmap_update_bits(smb->regmap, CFG_STATUS_IRQ, 0xff, - enable ? CFG_STATUS_IRQ_TERMINATION_OR_TAPER : 0); - if (ret < 0) - goto fail; + ret = smb347_write(smb, CFG_STATUS_IRQ, + CFG_STATUS_IRQ_TERMINATION_OR_TAPER); + if (ret < 0) + goto fail; + + ret = smb347_read(smb, CFG_PIN); + if (ret < 0) + goto fail; + + ret |= CFG_PIN_EN_CHARGER_ERROR; + + ret = smb347_write(smb, CFG_PIN, ret); + } else { + ret = smb347_write(smb, CFG_FAULT_IRQ, 0); + if (ret < 0) + goto fail; + + ret = smb347_write(smb, CFG_STATUS_IRQ, 0); + if (ret < 0) + goto fail; + + ret = smb347_read(smb, CFG_PIN); + if (ret < 0) + goto fail; + + ret &= ~CFG_PIN_EN_CHARGER_ERROR; + + ret = smb347_write(smb, CFG_PIN, ret); + } - ret = regmap_update_bits(smb->regmap, CFG_PIN, CFG_PIN_EN_CHARGER_ERROR, - enable ? CFG_PIN_EN_CHARGER_ERROR : 0); fail: smb347_set_writable(smb, false); return ret; @@ -797,18 +889,18 @@ static inline int smb347_irq_disable(struct smb347_charger *smb) return smb347_irq_set(smb, false); } -static int smb347_irq_init(struct smb347_charger *smb, - struct i2c_client *client) +static int smb347_irq_init(struct smb347_charger *smb) { const struct smb347_charger_platform_data *pdata = smb->pdata; int ret, irq = gpio_to_irq(pdata->irq_gpio); - ret = gpio_request_one(pdata->irq_gpio, GPIOF_IN, client->name); + ret = gpio_request_one(pdata->irq_gpio, GPIOF_IN, smb->client->name); if (ret < 0) goto fail; ret = request_threaded_irq(irq, NULL, smb347_interrupt, - IRQF_TRIGGER_FALLING, client->name, smb); + IRQF_TRIGGER_FALLING, smb->client->name, + smb); if (ret < 0) goto fail_gpio; @@ -820,14 +912,23 @@ static int smb347_irq_init(struct smb347_charger *smb, * Configure the STAT output to be suitable for interrupts: disable * all other output (except interrupts) and make it active low. */ - ret = regmap_update_bits(smb->regmap, CFG_STAT, - CFG_STAT_ACTIVE_HIGH | CFG_STAT_DISABLED, - CFG_STAT_DISABLED); + ret = smb347_read(smb, CFG_STAT); + if (ret < 0) + goto fail_readonly; + + ret &= ~CFG_STAT_ACTIVE_HIGH; + ret |= CFG_STAT_DISABLED; + + ret = smb347_write(smb, CFG_STAT, ret); + if (ret < 0) + goto fail_readonly; + + ret = smb347_irq_enable(smb); if (ret < 0) goto fail_readonly; smb347_set_writable(smb, false); - client->irq = irq; + smb->client->irq = irq; return 0; fail_readonly: @@ -837,7 +938,7 @@ static int smb347_irq_init(struct smb347_charger *smb, fail_gpio: gpio_free(pdata->irq_gpio); fail: - client->irq = 0; + smb->client->irq = 0; return ret; } @@ -886,13 +987,13 @@ static int smb347_battery_get_property(struct power_supply *psy, const struct smb347_charger_platform_data *pdata = smb->pdata; int ret; - ret = smb347_update_ps_status(smb); + ret = smb347_update_status(smb); if (ret < 0) return ret; switch (prop) { case POWER_SUPPLY_PROP_STATUS: - if (!smb347_is_ps_online(smb)) { + if (!smb347_is_online(smb)) { val->intval = POWER_SUPPLY_STATUS_DISCHARGING; break; } @@ -903,7 +1004,7 @@ static int smb347_battery_get_property(struct power_supply *psy, break; case POWER_SUPPLY_PROP_CHARGE_TYPE: - if (!smb347_is_ps_online(smb)) + if (!smb347_is_online(smb)) return -ENODATA; /* @@ -935,6 +1036,44 @@ static int smb347_battery_get_property(struct power_supply *psy, val->intval = pdata->battery_info.voltage_max_design; break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + if (!smb347_is_online(smb)) + return -ENODATA; + ret = smb347_read(smb, STAT_A); + if (ret < 0) + return ret; + + ret &= STAT_A_FLOAT_VOLTAGE_MASK; + if (ret > 0x3d) + ret = 0x3d; + + val->intval = 3500000 + ret * 20000; + break; + + case POWER_SUPPLY_PROP_CURRENT_NOW: + if (!smb347_is_online(smb)) + return -ENODATA; + + ret = smb347_read(smb, STAT_B); + if (ret < 0) + return ret; + + /* + * The current value is composition of FCC and PCC values + * and we can detect which table to use from bit 5. + */ + if (ret & 0x20) { + val->intval = hw_to_current(fcc_tbl, + ARRAY_SIZE(fcc_tbl), + ret & 7); + } else { + ret >>= 3; + val->intval = hw_to_current(pcc_tbl, + ARRAY_SIZE(pcc_tbl), + ret & 7); + } + break; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: val->intval = pdata->battery_info.charge_full_design; break; @@ -956,58 +1095,64 @@ static enum power_supply_property smb347_battery_properties[] = { POWER_SUPPLY_PROP_TECHNOLOGY, POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_MODEL_NAME, }; -static bool smb347_volatile_reg(struct device *dev, unsigned int reg) +static int smb347_debugfs_show(struct seq_file *s, void *data) { - switch (reg) { - case IRQSTAT_A: - case IRQSTAT_C: - case IRQSTAT_E: - case IRQSTAT_F: - case STAT_A: - case STAT_B: - case STAT_C: - case STAT_E: - return true; + struct smb347_charger *smb = s->private; + int ret; + u8 reg; + + seq_printf(s, "Control registers:\n"); + seq_printf(s, "==================\n"); + for (reg = CFG_CHARGE_CURRENT; reg <= CFG_ADDRESS; reg++) { + ret = smb347_read(smb, reg); + seq_printf(s, "0x%02x:\t0x%02x\n", reg, ret); + } + seq_printf(s, "\n"); + + seq_printf(s, "Command registers:\n"); + seq_printf(s, "==================\n"); + ret = smb347_read(smb, CMD_A); + seq_printf(s, "0x%02x:\t0x%02x\n", CMD_A, ret); + ret = smb347_read(smb, CMD_B); + seq_printf(s, "0x%02x:\t0x%02x\n", CMD_B, ret); + ret = smb347_read(smb, CMD_C); + seq_printf(s, "0x%02x:\t0x%02x\n", CMD_C, ret); + seq_printf(s, "\n"); + + seq_printf(s, "Interrupt status registers:\n"); + seq_printf(s, "===========================\n"); + for (reg = IRQSTAT_A; reg <= IRQSTAT_F; reg++) { + ret = smb347_read(smb, reg); + seq_printf(s, "0x%02x:\t0x%02x\n", reg, ret); + } + seq_printf(s, "\n"); + + seq_printf(s, "Status registers:\n"); + seq_printf(s, "=================\n"); + for (reg = STAT_A; reg <= STAT_E; reg++) { + ret = smb347_read(smb, reg); + seq_printf(s, "0x%02x:\t0x%02x\n", reg, ret); } - return false; + return 0; } -static bool smb347_readable_reg(struct device *dev, unsigned int reg) +static int smb347_debugfs_open(struct inode *inode, struct file *file) { - switch (reg) { - case CFG_CHARGE_CURRENT: - case CFG_CURRENT_LIMIT: - case CFG_FLOAT_VOLTAGE: - case CFG_STAT: - case CFG_PIN: - case CFG_THERM: - case CFG_SYSOK: - case CFG_OTHER: - case CFG_OTG: - case CFG_TEMP_LIMIT: - case CFG_FAULT_IRQ: - case CFG_STATUS_IRQ: - case CFG_ADDRESS: - case CMD_A: - case CMD_B: - case CMD_C: - return true; - } - - return smb347_volatile_reg(dev, reg); + return single_open(file, smb347_debugfs_show, inode->i_private); } -static const struct regmap_config smb347_regmap = { - .reg_bits = 8, - .val_bits = 8, - .max_register = SMB347_MAX_REGISTER, - .volatile_reg = smb347_volatile_reg, - .readable_reg = smb347_readable_reg, +static const struct file_operations smb347_debugfs_fops = { + .open = smb347_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, }; static int smb347_probe(struct i2c_client *client, @@ -1033,45 +1178,28 @@ static int smb347_probe(struct i2c_client *client, i2c_set_clientdata(client, smb); mutex_init(&smb->lock); - smb->dev = &client->dev; + smb->client = client; smb->pdata = pdata; - smb->regmap = devm_regmap_init_i2c(client, &smb347_regmap); - if (IS_ERR(smb->regmap)) - return PTR_ERR(smb->regmap); - ret = smb347_hw_init(smb); if (ret < 0) return ret; - if (smb->pdata->use_mains) { - smb->mains.name = "smb347-mains"; - smb->mains.type = POWER_SUPPLY_TYPE_MAINS; - smb->mains.get_property = smb347_mains_get_property; - smb->mains.properties = smb347_mains_properties; - smb->mains.num_properties = ARRAY_SIZE(smb347_mains_properties); - smb->mains.supplied_to = battery; - smb->mains.num_supplicants = ARRAY_SIZE(battery); - ret = power_supply_register(dev, &smb->mains); - if (ret < 0) - return ret; - } - - if (smb->pdata->use_usb) { - smb->usb.name = "smb347-usb"; - smb->usb.type = POWER_SUPPLY_TYPE_USB; - smb->usb.get_property = smb347_usb_get_property; - smb->usb.properties = smb347_usb_properties; - smb->usb.num_properties = ARRAY_SIZE(smb347_usb_properties); - smb->usb.supplied_to = battery; - smb->usb.num_supplicants = ARRAY_SIZE(battery); - ret = power_supply_register(dev, &smb->usb); - if (ret < 0) { - if (smb->pdata->use_mains) - power_supply_unregister(&smb->mains); - return ret; - } - } + smb->mains.name = "smb347-mains"; + smb->mains.type = POWER_SUPPLY_TYPE_MAINS; + smb->mains.get_property = smb347_mains_get_property; + smb->mains.properties = smb347_mains_properties; + smb->mains.num_properties = ARRAY_SIZE(smb347_mains_properties); + smb->mains.supplied_to = battery; + smb->mains.num_supplicants = ARRAY_SIZE(battery); + + smb->usb.name = "smb347-usb"; + smb->usb.type = POWER_SUPPLY_TYPE_USB; + smb->usb.get_property = smb347_usb_get_property; + smb->usb.properties = smb347_usb_properties; + smb->usb.num_properties = ARRAY_SIZE(smb347_usb_properties); + smb->usb.supplied_to = battery; + smb->usb.num_supplicants = ARRAY_SIZE(battery); smb->battery.name = "smb347-battery"; smb->battery.type = POWER_SUPPLY_TYPE_BATTERY; @@ -1079,13 +1207,20 @@ static int smb347_probe(struct i2c_client *client, smb->battery.properties = smb347_battery_properties; smb->battery.num_properties = ARRAY_SIZE(smb347_battery_properties); + ret = power_supply_register(dev, &smb->mains); + if (ret < 0) + return ret; + + ret = power_supply_register(dev, &smb->usb); + if (ret < 0) { + power_supply_unregister(&smb->mains); + return ret; + } ret = power_supply_register(dev, &smb->battery); if (ret < 0) { - if (smb->pdata->use_usb) - power_supply_unregister(&smb->usb); - if (smb->pdata->use_mains) - power_supply_unregister(&smb->mains); + power_supply_unregister(&smb->usb); + power_supply_unregister(&smb->mains); return ret; } @@ -1094,15 +1229,15 @@ static int smb347_probe(struct i2c_client *client, * interrupt support here. */ if (pdata->irq_gpio >= 0) { - ret = smb347_irq_init(smb, client); + ret = smb347_irq_init(smb); if (ret < 0) { dev_warn(dev, "failed to initialize IRQ: %d\n", ret); dev_warn(dev, "disabling IRQ support\n"); - } else { - smb347_irq_enable(smb); } } + smb->dentry = debugfs_create_file("smb347-regs", S_IRUSR, NULL, smb, + &smb347_debugfs_fops); return 0; } @@ -1110,6 +1245,9 @@ static int smb347_remove(struct i2c_client *client) { struct smb347_charger *smb = i2c_get_clientdata(client); + if (!IS_ERR_OR_NULL(smb->dentry)) + debugfs_remove(smb->dentry); + if (client->irq) { smb347_irq_disable(smb); free_irq(client->irq, smb); @@ -1117,10 +1255,8 @@ static int smb347_remove(struct i2c_client *client) } power_supply_unregister(&smb->battery); - if (smb->pdata->use_usb) - power_supply_unregister(&smb->usb); - if (smb->pdata->use_mains) - power_supply_unregister(&smb->mains); + power_supply_unregister(&smb->usb); + power_supply_unregister(&smb->mains); return 0; } @@ -1139,7 +1275,17 @@ static struct i2c_driver smb347_driver = { .id_table = smb347_id, }; -module_i2c_driver(smb347_driver); +static int __init smb347_init(void) +{ + return i2c_add_driver(&smb347_driver); +} +module_init(smb347_init); + +static void __exit smb347_exit(void) +{ + i2c_del_driver(&smb347_driver); +} +module_exit(smb347_exit); MODULE_AUTHOR("Bruce E. Robertson "); MODULE_AUTHOR("Mika Westerberg "); diff --git a/trunk/drivers/remoteproc/remoteproc_core.c b/trunk/drivers/remoteproc/remoteproc_core.c index 8ea7bccc7100..d6f8adaa26ef 100644 --- a/trunk/drivers/remoteproc/remoteproc_core.c +++ b/trunk/drivers/remoteproc/remoteproc_core.c @@ -78,7 +78,7 @@ typedef int (*rproc_handle_resource_t)(struct rproc *rproc, void *, int avail); * the recovery of the remote processor. */ static int rproc_iommu_fault(struct iommu_domain *domain, struct device *dev, - unsigned long iova, int flags, void *token) + unsigned long iova, int flags) { dev_err(dev, "iommu fault: da 0x%lx flags 0x%x\n", iova, flags); @@ -117,7 +117,7 @@ static int rproc_enable_iommu(struct rproc *rproc) return -ENOMEM; } - iommu_set_fault_handler(domain, rproc_iommu_fault, rproc); + iommu_set_fault_handler(domain, rproc_iommu_fault); ret = iommu_attach_device(domain, dev); if (ret) { diff --git a/trunk/drivers/s390/block/dasd_int.h b/trunk/drivers/s390/block/dasd_int.h index c05da00583f0..33a6743ddc55 100644 --- a/trunk/drivers/s390/block/dasd_int.h +++ b/trunk/drivers/s390/block/dasd_int.h @@ -10,6 +10,8 @@ #ifndef DASD_INT_H #define DASD_INT_H +#ifdef __KERNEL__ + /* we keep old device allocation scheme; IOW, minors are still in 0..255 */ #define DASD_PER_MAJOR (1U << (MINORBITS - DASD_PARTN_BITS)) #define DASD_PARTN_MASK ((1 << DASD_PARTN_BITS) - 1) @@ -789,4 +791,6 @@ static inline int dasd_eer_enabled(struct dasd_device *device) #define dasd_eer_enabled(d) (0) #endif /* CONFIG_DASD_ERR */ +#endif /* __KERNEL__ */ + #endif /* DASD_H */ diff --git a/trunk/drivers/s390/char/sclp_sdias.c b/trunk/drivers/s390/char/sclp_sdias.c index 50f7115990ff..69e6c50d4cfb 100644 --- a/trunk/drivers/s390/char/sclp_sdias.c +++ b/trunk/drivers/s390/char/sclp_sdias.c @@ -211,7 +211,7 @@ int sclp_sdias_copy(void *dest, int start_blk, int nr_blks) sccb.evbuf.event_qual = EQ_STORE_DATA; sccb.evbuf.data_id = DI_FCP_DUMP; sccb.evbuf.event_id = 4712; -#ifdef CONFIG_64BIT +#ifdef __s390x__ sccb.evbuf.asa_size = ASA_SIZE_64; #else sccb.evbuf.asa_size = ASA_SIZE_32; diff --git a/trunk/drivers/scsi/be2iscsi/be_mgmt.c b/trunk/drivers/scsi/be2iscsi/be_mgmt.c index 2a096795b9aa..01bb04cd9e75 100644 --- a/trunk/drivers/scsi/be2iscsi/be_mgmt.c +++ b/trunk/drivers/scsi/be2iscsi/be_mgmt.c @@ -571,12 +571,13 @@ static int mgmt_exec_nonemb_cmd(struct beiscsi_hba *phba, static int mgmt_alloc_cmd_data(struct beiscsi_hba *phba, struct be_dma_mem *cmd, int iscsi_cmd, int size) { - cmd->va = pci_alloc_consistent(phba->ctrl.pdev, size, &cmd->dma); + cmd->va = pci_alloc_consistent(phba->ctrl.pdev, sizeof(size), + &cmd->dma); if (!cmd->va) { SE_DEBUG(DBG_LVL_1, "Failed to allocate memory for if info\n"); return -ENOMEM; } - memset(cmd->va, 0, size); + memset(cmd->va, 0, sizeof(size)); cmd->size = size; be_cmd_hdr_prepare(cmd->va, CMD_SUBSYSTEM_ISCSI, iscsi_cmd, size); return 0; diff --git a/trunk/drivers/scsi/bfa/bfad_attr.c b/trunk/drivers/scsi/bfa/bfad_attr.c index b83927440171..8b6c6bf7837e 100644 --- a/trunk/drivers/scsi/bfa/bfad_attr.c +++ b/trunk/drivers/scsi/bfa/bfad_attr.c @@ -426,23 +426,6 @@ bfad_im_vport_create(struct fc_vport *fc_vport, bool disable) vshost = vport->drv_port.im_port->shost; fc_host_node_name(vshost) = wwn_to_u64((u8 *)&port_cfg.nwwn); fc_host_port_name(vshost) = wwn_to_u64((u8 *)&port_cfg.pwwn); - fc_host_supported_classes(vshost) = FC_COS_CLASS3; - - memset(fc_host_supported_fc4s(vshost), 0, - sizeof(fc_host_supported_fc4s(vshost))); - - /* For FCP type 0x08 */ - if (supported_fc4s & BFA_LPORT_ROLE_FCP_IM) - fc_host_supported_fc4s(vshost)[2] = 1; - - /* For fibre channel services type 0x20 */ - fc_host_supported_fc4s(vshost)[7] = 1; - - fc_host_supported_speeds(vshost) = - bfad_im_supported_speeds(&bfad->bfa); - fc_host_maxframe_size(vshost) = - bfa_fcport_get_maxfrsize(&bfad->bfa); - fc_vport->dd_data = vport; vport->drv_port.im_port->fc_vport = fc_vport; } else if (rc == BFA_STATUS_INVALID_WWN) diff --git a/trunk/drivers/scsi/bfa/bfad_im.c b/trunk/drivers/scsi/bfa/bfad_im.c index 1ac09afe35ee..3153923f5b60 100644 --- a/trunk/drivers/scsi/bfa/bfad_im.c +++ b/trunk/drivers/scsi/bfa/bfad_im.c @@ -987,7 +987,7 @@ bfad_im_slave_alloc(struct scsi_device *sdev) return 0; } -u32 +static u32 bfad_im_supported_speeds(struct bfa_s *bfa) { struct bfa_ioc_attr_s *ioc_attr; diff --git a/trunk/drivers/scsi/bfa/bfad_im.h b/trunk/drivers/scsi/bfa/bfad_im.h index f6c1023e502a..0814367ef101 100644 --- a/trunk/drivers/scsi/bfa/bfad_im.h +++ b/trunk/drivers/scsi/bfa/bfad_im.h @@ -37,7 +37,6 @@ int bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port, struct device *dev); void bfad_im_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port); -u32 bfad_im_supported_speeds(struct bfa_s *bfa); #define MAX_FCP_TARGET 1024 #define MAX_FCP_LUN 16384 diff --git a/trunk/drivers/scsi/bnx2fc/bnx2fc.h b/trunk/drivers/scsi/bnx2fc/bnx2fc.h index 0578fa0dc14b..a4953ef9e53a 100644 --- a/trunk/drivers/scsi/bnx2fc/bnx2fc.h +++ b/trunk/drivers/scsi/bnx2fc/bnx2fc.h @@ -62,7 +62,7 @@ #include "bnx2fc_constants.h" #define BNX2FC_NAME "bnx2fc" -#define BNX2FC_VERSION "1.0.11" +#define BNX2FC_VERSION "1.0.10" #define PFX "bnx2fc: " @@ -228,16 +228,13 @@ struct bnx2fc_interface { struct packet_type fip_packet_type; struct workqueue_struct *timer_work_queue; struct kref kref; + struct fcoe_ctlr ctlr; u8 vlan_enabled; int vlan_id; bool enabled; }; -#define bnx2fc_from_ctlr(x) \ - ((struct bnx2fc_interface *)((x) + 1)) - -#define bnx2fc_to_ctlr(x) \ - ((struct fcoe_ctlr *)(((struct fcoe_ctlr *)(x)) - 1)) +#define bnx2fc_from_ctlr(fip) container_of(fip, struct bnx2fc_interface, ctlr) struct bnx2fc_lport { struct list_head list; diff --git a/trunk/drivers/scsi/bnx2fc/bnx2fc_els.c b/trunk/drivers/scsi/bnx2fc/bnx2fc_els.c index bdbbb13b8534..ce0ce3e32f33 100644 --- a/trunk/drivers/scsi/bnx2fc/bnx2fc_els.c +++ b/trunk/drivers/scsi/bnx2fc/bnx2fc_els.c @@ -854,6 +854,7 @@ static void bnx2fc_flogi_resp(struct fc_seq *seq, struct fc_frame *fp, struct fc_exch *exch = fc_seq_exch(seq); struct fc_lport *lport = exch->lp; u8 *mac; + struct fc_frame_header *fh; u8 op; if (IS_ERR(fp)) @@ -861,6 +862,13 @@ static void bnx2fc_flogi_resp(struct fc_seq *seq, struct fc_frame *fp, mac = fr_cb(fp)->granted_mac; if (is_zero_ether_addr(mac)) { + fh = fc_frame_header_get(fp); + if (fh->fh_type != FC_TYPE_ELS) { + printk(KERN_ERR PFX "bnx2fc_flogi_resp:" + "fh_type != FC_TYPE_ELS\n"); + fc_frame_free(fp); + return; + } op = fc_frame_payload_op(fp); if (lport->vport) { if (op == ELS_LS_RJT) { @@ -870,10 +878,12 @@ static void bnx2fc_flogi_resp(struct fc_seq *seq, struct fc_frame *fp, return; } } - fcoe_ctlr_recv_flogi(fip, lport, fp); + if (fcoe_ctlr_recv_flogi(fip, lport, fp)) { + fc_frame_free(fp); + return; + } } - if (!is_zero_ether_addr(mac)) - fip->update_mac(lport, mac); + fip->update_mac(lport, mac); done: fc_lport_flogi_resp(seq, fp, lport); } @@ -900,7 +910,7 @@ struct fc_seq *bnx2fc_elsct_send(struct fc_lport *lport, u32 did, { struct fcoe_port *port = lport_priv(lport); struct bnx2fc_interface *interface = port->priv; - struct fcoe_ctlr *fip = bnx2fc_to_ctlr(interface); + struct fcoe_ctlr *fip = &interface->ctlr; struct fc_frame_header *fh = fc_frame_header_get(fp); switch (op) { diff --git a/trunk/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/trunk/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index f52f668fd247..c1c6a92a0b98 100644 --- a/trunk/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/trunk/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -22,7 +22,7 @@ DEFINE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu); #define DRV_MODULE_NAME "bnx2fc" #define DRV_MODULE_VERSION BNX2FC_VERSION -#define DRV_MODULE_RELDATE "Apr 24, 2012" +#define DRV_MODULE_RELDATE "Jan 22, 2011" static char version[] __devinitdata = @@ -54,7 +54,6 @@ static struct cnic_ulp_ops bnx2fc_cnic_cb; static struct libfc_function_template bnx2fc_libfc_fcn_templ; static struct scsi_host_template bnx2fc_shost_template; static struct fc_function_template bnx2fc_transport_function; -static struct fcoe_sysfs_function_template bnx2fc_fcoe_sysfs_templ; static struct fc_function_template bnx2fc_vport_xport_function; static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode); static void __bnx2fc_destroy(struct bnx2fc_interface *interface); @@ -89,7 +88,6 @@ static void bnx2fc_port_shutdown(struct fc_lport *lport); static void bnx2fc_stop(struct bnx2fc_interface *interface); static int __init bnx2fc_mod_init(void); static void __exit bnx2fc_mod_exit(void); -static void bnx2fc_ctlr_get_lesb(struct fcoe_ctlr_device *ctlr_dev); unsigned int bnx2fc_debug_level; module_param_named(debug_logging, bnx2fc_debug_level, int, S_IRUGO|S_IWUSR); @@ -120,41 +118,6 @@ static void bnx2fc_get_lesb(struct fc_lport *lport, __fcoe_get_lesb(lport, fc_lesb, netdev); } -static void bnx2fc_ctlr_get_lesb(struct fcoe_ctlr_device *ctlr_dev) -{ - struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr_dev); - struct net_device *netdev = bnx2fc_netdev(fip->lp); - struct fcoe_fc_els_lesb *fcoe_lesb; - struct fc_els_lesb fc_lesb; - - __fcoe_get_lesb(fip->lp, &fc_lesb, netdev); - fcoe_lesb = (struct fcoe_fc_els_lesb *)(&fc_lesb); - - ctlr_dev->lesb.lesb_link_fail = - ntohl(fcoe_lesb->lesb_link_fail); - ctlr_dev->lesb.lesb_vlink_fail = - ntohl(fcoe_lesb->lesb_vlink_fail); - ctlr_dev->lesb.lesb_miss_fka = - ntohl(fcoe_lesb->lesb_miss_fka); - ctlr_dev->lesb.lesb_symb_err = - ntohl(fcoe_lesb->lesb_symb_err); - ctlr_dev->lesb.lesb_err_block = - ntohl(fcoe_lesb->lesb_err_block); - ctlr_dev->lesb.lesb_fcs_error = - ntohl(fcoe_lesb->lesb_fcs_error); -} -EXPORT_SYMBOL(bnx2fc_ctlr_get_lesb); - -static void bnx2fc_fcf_get_vlan_id(struct fcoe_fcf_device *fcf_dev) -{ - struct fcoe_ctlr_device *ctlr_dev = - fcoe_fcf_dev_to_ctlr_dev(fcf_dev); - struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev); - struct bnx2fc_interface *fcoe = fcoe_ctlr_priv(ctlr); - - fcf_dev->vlan_id = fcoe->vlan_id; -} - static void bnx2fc_clean_rx_queue(struct fc_lport *lp) { struct fcoe_percpu_s *bg; @@ -281,7 +244,6 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp) struct sk_buff *skb; struct fc_frame_header *fh; struct bnx2fc_interface *interface; - struct fcoe_ctlr *ctlr; struct bnx2fc_hba *hba; struct fcoe_port *port; struct fcoe_hdr *hp; @@ -294,7 +256,6 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp) port = (struct fcoe_port *)lport_priv(lport); interface = port->priv; - ctlr = bnx2fc_to_ctlr(interface); hba = interface->hba; fh = fc_frame_header_get(fp); @@ -307,12 +268,12 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp) } if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ)) { - if (!ctlr->sel_fcf) { + if (!interface->ctlr.sel_fcf) { BNX2FC_HBA_DBG(lport, "FCF not selected yet!\n"); kfree_skb(skb); return -EINVAL; } - if (fcoe_ctlr_els_send(ctlr, lport, skb)) + if (fcoe_ctlr_els_send(&interface->ctlr, lport, skb)) return 0; } @@ -385,14 +346,14 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp) /* fill up mac and fcoe headers */ eh = eth_hdr(skb); eh->h_proto = htons(ETH_P_FCOE); - if (ctlr->map_dest) + if (interface->ctlr.map_dest) fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id); else /* insert GW address */ - memcpy(eh->h_dest, ctlr->dest_addr, ETH_ALEN); + memcpy(eh->h_dest, interface->ctlr.dest_addr, ETH_ALEN); - if (unlikely(ctlr->flogi_oxid != FC_XID_UNKNOWN)) - memcpy(eh->h_source, ctlr->ctl_src_addr, ETH_ALEN); + if (unlikely(interface->ctlr.flogi_oxid != FC_XID_UNKNOWN)) + memcpy(eh->h_source, interface->ctlr.ctl_src_addr, ETH_ALEN); else memcpy(eh->h_source, port->data_src_addr, ETH_ALEN); @@ -442,7 +403,6 @@ static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev, { struct fc_lport *lport; struct bnx2fc_interface *interface; - struct fcoe_ctlr *ctlr; struct fc_frame_header *fh; struct fcoe_rcv_info *fr; struct fcoe_percpu_s *bg; @@ -450,8 +410,7 @@ static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev, interface = container_of(ptype, struct bnx2fc_interface, fcoe_packet_type); - ctlr = bnx2fc_to_ctlr(interface); - lport = ctlr->lp; + lport = interface->ctlr.lp; if (unlikely(lport == NULL)) { printk(KERN_ERR PFX "bnx2fc_rcv: lport is NULL\n"); @@ -799,13 +758,11 @@ static int bnx2fc_net_config(struct fc_lport *lport, struct net_device *netdev) { struct bnx2fc_hba *hba; struct bnx2fc_interface *interface; - struct fcoe_ctlr *ctlr; struct fcoe_port *port; u64 wwnn, wwpn; port = lport_priv(lport); interface = port->priv; - ctlr = bnx2fc_to_ctlr(interface); hba = interface->hba; /* require support for get_pauseparam ethtool op. */ @@ -824,13 +781,13 @@ static int bnx2fc_net_config(struct fc_lport *lport, struct net_device *netdev) if (!lport->vport) { if (fcoe_get_wwn(netdev, &wwnn, NETDEV_FCOE_WWNN)) - wwnn = fcoe_wwn_from_mac(ctlr->ctl_src_addr, + wwnn = fcoe_wwn_from_mac(interface->ctlr.ctl_src_addr, 1, 0); BNX2FC_HBA_DBG(lport, "WWNN = 0x%llx\n", wwnn); fc_set_wwnn(lport, wwnn); if (fcoe_get_wwn(netdev, &wwpn, NETDEV_FCOE_WWPN)) - wwpn = fcoe_wwn_from_mac(ctlr->ctl_src_addr, + wwpn = fcoe_wwn_from_mac(interface->ctlr.ctl_src_addr, 2, 0); BNX2FC_HBA_DBG(lport, "WWPN = 0x%llx\n", wwpn); @@ -867,7 +824,6 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event, struct fc_lport *lport; struct fc_lport *vport; struct bnx2fc_interface *interface, *tmp; - struct fcoe_ctlr *ctlr; int wait_for_upload = 0; u32 link_possible = 1; @@ -918,8 +874,7 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event, if (interface->hba != hba) continue; - ctlr = bnx2fc_to_ctlr(interface); - lport = ctlr->lp; + lport = interface->ctlr.lp; BNX2FC_HBA_DBG(lport, "netevent handler - event=%s %ld\n", interface->netdev->name, event); @@ -934,8 +889,8 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event, * on a stale vlan */ if (interface->enabled) - fcoe_ctlr_link_up(ctlr); - } else if (fcoe_ctlr_link_down(ctlr)) { + fcoe_ctlr_link_up(&interface->ctlr); + } else if (fcoe_ctlr_link_down(&interface->ctlr)) { mutex_lock(&lport->lp_mutex); list_for_each_entry(vport, &lport->vports, list) fc_host_port_type(vport->host) = @@ -1040,11 +995,9 @@ static int bnx2fc_fip_recv(struct sk_buff *skb, struct net_device *dev, struct net_device *orig_dev) { struct bnx2fc_interface *interface; - struct fcoe_ctlr *ctlr; interface = container_of(ptype, struct bnx2fc_interface, fip_packet_type); - ctlr = bnx2fc_to_ctlr(interface); - fcoe_ctlr_recv(ctlr, skb); + fcoe_ctlr_recv(&interface->ctlr, skb); return 0; } @@ -1202,7 +1155,6 @@ static int bnx2fc_interface_setup(struct bnx2fc_interface *interface) { struct net_device *netdev = interface->netdev; struct net_device *physdev = interface->hba->phys_dev; - struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); struct netdev_hw_addr *ha; int sel_san_mac = 0; @@ -1217,7 +1169,7 @@ static int bnx2fc_interface_setup(struct bnx2fc_interface *interface) if ((ha->type == NETDEV_HW_ADDR_T_SAN) && (is_valid_ether_addr(ha->addr))) { - memcpy(ctlr->ctl_src_addr, ha->addr, + memcpy(interface->ctlr.ctl_src_addr, ha->addr, ETH_ALEN); sel_san_mac = 1; BNX2FC_MISC_DBG("Found SAN MAC\n"); @@ -1272,23 +1224,19 @@ static void bnx2fc_release_transport(void) static void bnx2fc_interface_release(struct kref *kref) { - struct fcoe_ctlr_device *ctlr_dev; struct bnx2fc_interface *interface; - struct fcoe_ctlr *ctlr; struct net_device *netdev; interface = container_of(kref, struct bnx2fc_interface, kref); BNX2FC_MISC_DBG("Interface is being released\n"); - ctlr = bnx2fc_to_ctlr(interface); - ctlr_dev = fcoe_ctlr_to_ctlr_dev(ctlr); netdev = interface->netdev; /* tear-down FIP controller */ if (test_and_clear_bit(BNX2FC_CTLR_INIT_DONE, &interface->if_flags)) - fcoe_ctlr_destroy(ctlr); + fcoe_ctlr_destroy(&interface->ctlr); - fcoe_ctlr_device_delete(ctlr_dev); + kfree(interface); dev_put(netdev); module_put(THIS_MODULE); @@ -1381,40 +1329,33 @@ struct bnx2fc_interface *bnx2fc_interface_create(struct bnx2fc_hba *hba, struct net_device *netdev, enum fip_state fip_mode) { - struct fcoe_ctlr_device *ctlr_dev; struct bnx2fc_interface *interface; - struct fcoe_ctlr *ctlr; - int size; int rc = 0; - size = (sizeof(*interface) + sizeof(struct fcoe_ctlr)); - ctlr_dev = fcoe_ctlr_device_add(&netdev->dev, &bnx2fc_fcoe_sysfs_templ, - size); - if (!ctlr_dev) { + interface = kzalloc(sizeof(*interface), GFP_KERNEL); + if (!interface) { printk(KERN_ERR PFX "Unable to allocate interface structure\n"); return NULL; } - ctlr = fcoe_ctlr_device_priv(ctlr_dev); - interface = fcoe_ctlr_priv(ctlr); dev_hold(netdev); kref_init(&interface->kref); interface->hba = hba; interface->netdev = netdev; /* Initialize FIP */ - fcoe_ctlr_init(ctlr, fip_mode); - ctlr->send = bnx2fc_fip_send; - ctlr->update_mac = bnx2fc_update_src_mac; - ctlr->get_src_addr = bnx2fc_get_src_mac; + fcoe_ctlr_init(&interface->ctlr, fip_mode); + interface->ctlr.send = bnx2fc_fip_send; + interface->ctlr.update_mac = bnx2fc_update_src_mac; + interface->ctlr.get_src_addr = bnx2fc_get_src_mac; set_bit(BNX2FC_CTLR_INIT_DONE, &interface->if_flags); rc = bnx2fc_interface_setup(interface); if (!rc) return interface; - fcoe_ctlr_destroy(ctlr); + fcoe_ctlr_destroy(&interface->ctlr); dev_put(netdev); - fcoe_ctlr_device_delete(ctlr_dev); + kfree(interface); return NULL; } @@ -1432,7 +1373,6 @@ struct bnx2fc_interface *bnx2fc_interface_create(struct bnx2fc_hba *hba, static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface, struct device *parent, int npiv) { - struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); struct fc_lport *lport, *n_port; struct fcoe_port *port; struct Scsi_Host *shost; @@ -1443,7 +1383,7 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface, blport = kzalloc(sizeof(struct bnx2fc_lport), GFP_KERNEL); if (!blport) { - BNX2FC_HBA_DBG(ctlr->lp, "Unable to alloc blport\n"); + BNX2FC_HBA_DBG(interface->ctlr.lp, "Unable to alloc blport\n"); return NULL; } @@ -1539,8 +1479,7 @@ static void bnx2fc_net_cleanup(struct bnx2fc_interface *interface) static void bnx2fc_interface_cleanup(struct bnx2fc_interface *interface) { - struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); - struct fc_lport *lport = ctlr->lp; + struct fc_lport *lport = interface->ctlr.lp; struct fcoe_port *port = lport_priv(lport); struct bnx2fc_hba *hba = interface->hba; @@ -1580,8 +1519,7 @@ static void bnx2fc_if_destroy(struct fc_lport *lport) static void __bnx2fc_destroy(struct bnx2fc_interface *interface) { - struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); - struct fc_lport *lport = ctlr->lp; + struct fc_lport *lport = interface->ctlr.lp; struct fcoe_port *port = lport_priv(lport); bnx2fc_interface_cleanup(interface); @@ -1605,15 +1543,13 @@ static int bnx2fc_destroy(struct net_device *netdev) { struct bnx2fc_interface *interface = NULL; struct workqueue_struct *timer_work_queue; - struct fcoe_ctlr *ctlr; int rc = 0; rtnl_lock(); mutex_lock(&bnx2fc_dev_lock); interface = bnx2fc_interface_lookup(netdev); - ctlr = bnx2fc_to_ctlr(interface); - if (!interface || !ctlr->lp) { + if (!interface || !interface->ctlr.lp) { rc = -ENODEV; printk(KERN_ERR PFX "bnx2fc_destroy: interface or lport not found\n"); goto netdev_err; @@ -1710,7 +1646,6 @@ static void bnx2fc_ulp_start(void *handle) { struct bnx2fc_hba *hba = handle; struct bnx2fc_interface *interface; - struct fcoe_ctlr *ctlr; struct fc_lport *lport; mutex_lock(&bnx2fc_dev_lock); @@ -1722,8 +1657,7 @@ static void bnx2fc_ulp_start(void *handle) list_for_each_entry(interface, &if_list, list) { if (interface->hba == hba) { - ctlr = bnx2fc_to_ctlr(interface); - lport = ctlr->lp; + lport = interface->ctlr.lp; /* Kick off Fabric discovery*/ printk(KERN_ERR PFX "ulp_init: start discovery\n"); lport->tt.frame_send = bnx2fc_xmit; @@ -1743,14 +1677,13 @@ static void bnx2fc_port_shutdown(struct fc_lport *lport) static void bnx2fc_stop(struct bnx2fc_interface *interface) { - struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); struct fc_lport *lport; struct fc_lport *vport; if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &interface->hba->flags)) return; - lport = ctlr->lp; + lport = interface->ctlr.lp; bnx2fc_port_shutdown(lport); mutex_lock(&lport->lp_mutex); @@ -1759,7 +1692,7 @@ static void bnx2fc_stop(struct bnx2fc_interface *interface) FC_PORTTYPE_UNKNOWN; mutex_unlock(&lport->lp_mutex); fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN; - fcoe_ctlr_link_down(ctlr); + fcoe_ctlr_link_down(&interface->ctlr); fcoe_clean_pending_queue(lport); } @@ -1871,7 +1804,6 @@ static void bnx2fc_ulp_stop(void *handle) static void bnx2fc_start_disc(struct bnx2fc_interface *interface) { - struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); struct fc_lport *lport; int wait_cnt = 0; @@ -1882,18 +1814,18 @@ static void bnx2fc_start_disc(struct bnx2fc_interface *interface) return; } - lport = ctlr->lp; + lport = interface->ctlr.lp; BNX2FC_HBA_DBG(lport, "calling fc_fabric_login\n"); if (!bnx2fc_link_ok(lport) && interface->enabled) { BNX2FC_HBA_DBG(lport, "ctlr_link_up\n"); - fcoe_ctlr_link_up(ctlr); + fcoe_ctlr_link_up(&interface->ctlr); fc_host_port_type(lport->host) = FC_PORTTYPE_NPORT; set_bit(ADAPTER_STATE_READY, &interface->hba->adapter_state); } /* wait for the FCF to be selected before issuing FLOGI */ - while (!ctlr->sel_fcf) { + while (!interface->ctlr.sel_fcf) { msleep(250); /* give up after 3 secs */ if (++wait_cnt > 12) @@ -1957,21 +1889,19 @@ static void bnx2fc_ulp_init(struct cnic_dev *dev) static int bnx2fc_disable(struct net_device *netdev) { struct bnx2fc_interface *interface; - struct fcoe_ctlr *ctlr; int rc = 0; rtnl_lock(); mutex_lock(&bnx2fc_dev_lock); interface = bnx2fc_interface_lookup(netdev); - ctlr = bnx2fc_to_ctlr(interface); - if (!interface || !ctlr->lp) { + if (!interface || !interface->ctlr.lp) { rc = -ENODEV; printk(KERN_ERR PFX "bnx2fc_disable: interface or lport not found\n"); } else { interface->enabled = false; - fcoe_ctlr_link_down(ctlr); - fcoe_clean_pending_queue(ctlr->lp); + fcoe_ctlr_link_down(&interface->ctlr); + fcoe_clean_pending_queue(interface->ctlr.lp); } mutex_unlock(&bnx2fc_dev_lock); @@ -1983,19 +1913,17 @@ static int bnx2fc_disable(struct net_device *netdev) static int bnx2fc_enable(struct net_device *netdev) { struct bnx2fc_interface *interface; - struct fcoe_ctlr *ctlr; int rc = 0; rtnl_lock(); mutex_lock(&bnx2fc_dev_lock); interface = bnx2fc_interface_lookup(netdev); - ctlr = bnx2fc_to_ctlr(interface); - if (!interface || !ctlr->lp) { + if (!interface || !interface->ctlr.lp) { rc = -ENODEV; printk(KERN_ERR PFX "bnx2fc_enable: interface or lport not found\n"); - } else if (!bnx2fc_link_ok(ctlr->lp)) { - fcoe_ctlr_link_up(ctlr); + } else if (!bnx2fc_link_ok(interface->ctlr.lp)) { + fcoe_ctlr_link_up(&interface->ctlr); interface->enabled = true; } @@ -2016,7 +1944,6 @@ static int bnx2fc_enable(struct net_device *netdev) */ static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode) { - struct fcoe_ctlr *ctlr; struct bnx2fc_interface *interface; struct bnx2fc_hba *hba; struct net_device *phys_dev; @@ -2083,7 +2010,6 @@ static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode) goto ifput_err; } - ctlr = bnx2fc_to_ctlr(interface); interface->vlan_id = vlan_id; interface->vlan_enabled = 1; @@ -2109,10 +2035,10 @@ static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode) lport->boot_time = jiffies; /* Make this master N_port */ - ctlr->lp = lport; + interface->ctlr.lp = lport; if (!bnx2fc_link_ok(lport)) { - fcoe_ctlr_link_up(ctlr); + fcoe_ctlr_link_up(&interface->ctlr); fc_host_port_type(lport->host) = FC_PORTTYPE_NPORT; set_bit(ADAPTER_STATE_READY, &interface->hba->adapter_state); } @@ -2513,19 +2439,6 @@ static void __exit bnx2fc_mod_exit(void) module_init(bnx2fc_mod_init); module_exit(bnx2fc_mod_exit); -static struct fcoe_sysfs_function_template bnx2fc_fcoe_sysfs_templ = { - .get_fcoe_ctlr_mode = fcoe_ctlr_get_fip_mode, - .get_fcoe_ctlr_link_fail = bnx2fc_ctlr_get_lesb, - .get_fcoe_ctlr_vlink_fail = bnx2fc_ctlr_get_lesb, - .get_fcoe_ctlr_miss_fka = bnx2fc_ctlr_get_lesb, - .get_fcoe_ctlr_symb_err = bnx2fc_ctlr_get_lesb, - .get_fcoe_ctlr_err_block = bnx2fc_ctlr_get_lesb, - .get_fcoe_ctlr_fcs_error = bnx2fc_ctlr_get_lesb, - - .get_fcoe_fcf_selected = fcoe_fcf_get_selected, - .get_fcoe_fcf_vlan_id = bnx2fc_fcf_get_vlan_id, -}; - static struct fc_function_template bnx2fc_transport_function = { .show_host_node_name = 1, .show_host_port_name = 1, diff --git a/trunk/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/trunk/drivers/scsi/bnx2fc/bnx2fc_hwi.c index 2ca6bfe4ce5e..afd570962b8c 100644 --- a/trunk/drivers/scsi/bnx2fc/bnx2fc_hwi.c +++ b/trunk/drivers/scsi/bnx2fc/bnx2fc_hwi.c @@ -167,7 +167,6 @@ int bnx2fc_send_session_ofld_req(struct fcoe_port *port, { struct fc_lport *lport = port->lport; struct bnx2fc_interface *interface = port->priv; - struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); struct bnx2fc_hba *hba = interface->hba; struct kwqe *kwqe_arr[4]; struct fcoe_kwqe_conn_offload1 ofld_req1; @@ -315,13 +314,13 @@ int bnx2fc_send_session_ofld_req(struct fcoe_port *port, ofld_req4.src_mac_addr_mid[1] = port->data_src_addr[2]; ofld_req4.src_mac_addr_hi[0] = port->data_src_addr[1]; ofld_req4.src_mac_addr_hi[1] = port->data_src_addr[0]; - ofld_req4.dst_mac_addr_lo[0] = ctlr->dest_addr[5]; + ofld_req4.dst_mac_addr_lo[0] = interface->ctlr.dest_addr[5]; /* fcf mac */ - ofld_req4.dst_mac_addr_lo[1] = ctlr->dest_addr[4]; - ofld_req4.dst_mac_addr_mid[0] = ctlr->dest_addr[3]; - ofld_req4.dst_mac_addr_mid[1] = ctlr->dest_addr[2]; - ofld_req4.dst_mac_addr_hi[0] = ctlr->dest_addr[1]; - ofld_req4.dst_mac_addr_hi[1] = ctlr->dest_addr[0]; + ofld_req4.dst_mac_addr_lo[1] = interface->ctlr.dest_addr[4]; + ofld_req4.dst_mac_addr_mid[0] = interface->ctlr.dest_addr[3]; + ofld_req4.dst_mac_addr_mid[1] = interface->ctlr.dest_addr[2]; + ofld_req4.dst_mac_addr_hi[0] = interface->ctlr.dest_addr[1]; + ofld_req4.dst_mac_addr_hi[1] = interface->ctlr.dest_addr[0]; ofld_req4.lcq_addr_lo = (u32) tgt->lcq_dma; ofld_req4.lcq_addr_hi = (u32)((u64) tgt->lcq_dma >> 32); @@ -352,7 +351,6 @@ static int bnx2fc_send_session_enable_req(struct fcoe_port *port, { struct kwqe *kwqe_arr[2]; struct bnx2fc_interface *interface = port->priv; - struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); struct bnx2fc_hba *hba = interface->hba; struct fcoe_kwqe_conn_enable_disable enbl_req; struct fc_lport *lport = port->lport; @@ -376,12 +374,12 @@ static int bnx2fc_send_session_enable_req(struct fcoe_port *port, enbl_req.src_mac_addr_hi[1] = port->data_src_addr[0]; memcpy(tgt->src_addr, port->data_src_addr, ETH_ALEN); - enbl_req.dst_mac_addr_lo[0] = ctlr->dest_addr[5]; - enbl_req.dst_mac_addr_lo[1] = ctlr->dest_addr[4]; - enbl_req.dst_mac_addr_mid[0] = ctlr->dest_addr[3]; - enbl_req.dst_mac_addr_mid[1] = ctlr->dest_addr[2]; - enbl_req.dst_mac_addr_hi[0] = ctlr->dest_addr[1]; - enbl_req.dst_mac_addr_hi[1] = ctlr->dest_addr[0]; + enbl_req.dst_mac_addr_lo[0] = interface->ctlr.dest_addr[5]; + enbl_req.dst_mac_addr_lo[1] = interface->ctlr.dest_addr[4]; + enbl_req.dst_mac_addr_mid[0] = interface->ctlr.dest_addr[3]; + enbl_req.dst_mac_addr_mid[1] = interface->ctlr.dest_addr[2]; + enbl_req.dst_mac_addr_hi[0] = interface->ctlr.dest_addr[1]; + enbl_req.dst_mac_addr_hi[1] = interface->ctlr.dest_addr[0]; port_id = fc_host_port_id(lport->host); if (port_id != tgt->sid) { @@ -421,7 +419,6 @@ int bnx2fc_send_session_disable_req(struct fcoe_port *port, struct bnx2fc_rport *tgt) { struct bnx2fc_interface *interface = port->priv; - struct fcoe_ctlr *ctlr = bnx2fc_to_ctlr(interface); struct bnx2fc_hba *hba = interface->hba; struct fcoe_kwqe_conn_enable_disable disable_req; struct kwqe *kwqe_arr[2]; @@ -443,12 +440,12 @@ int bnx2fc_send_session_disable_req(struct fcoe_port *port, disable_req.src_mac_addr_hi[0] = tgt->src_addr[1]; disable_req.src_mac_addr_hi[1] = tgt->src_addr[0]; - disable_req.dst_mac_addr_lo[0] = ctlr->dest_addr[5]; - disable_req.dst_mac_addr_lo[1] = ctlr->dest_addr[4]; - disable_req.dst_mac_addr_mid[0] = ctlr->dest_addr[3]; - disable_req.dst_mac_addr_mid[1] = ctlr->dest_addr[2]; - disable_req.dst_mac_addr_hi[0] = ctlr->dest_addr[1]; - disable_req.dst_mac_addr_hi[1] = ctlr->dest_addr[0]; + disable_req.dst_mac_addr_lo[0] = interface->ctlr.dest_addr[5]; + disable_req.dst_mac_addr_lo[1] = interface->ctlr.dest_addr[4]; + disable_req.dst_mac_addr_mid[0] = interface->ctlr.dest_addr[3]; + disable_req.dst_mac_addr_mid[1] = interface->ctlr.dest_addr[2]; + disable_req.dst_mac_addr_hi[0] = interface->ctlr.dest_addr[1]; + disable_req.dst_mac_addr_hi[1] = interface->ctlr.dest_addr[0]; port_id = tgt->sid; disable_req.s_id[0] = (port_id & 0x000000FF); diff --git a/trunk/drivers/scsi/bnx2fc/bnx2fc_io.c b/trunk/drivers/scsi/bnx2fc/bnx2fc_io.c index 4f7453b9e41e..e897ce975bb8 100644 --- a/trunk/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/trunk/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -810,22 +810,8 @@ static int bnx2fc_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) spin_lock_bh(&tgt->tgt_lock); io_req->wait_for_comp = 0; - if (!(test_bit(BNX2FC_FLAG_TM_COMPL, &io_req->req_flags))) { + if (!(test_bit(BNX2FC_FLAG_TM_COMPL, &io_req->req_flags))) set_bit(BNX2FC_FLAG_TM_TIMEOUT, &io_req->req_flags); - if (io_req->on_tmf_queue) { - list_del_init(&io_req->link); - io_req->on_tmf_queue = 0; - } - io_req->wait_for_comp = 1; - bnx2fc_initiate_cleanup(io_req); - spin_unlock_bh(&tgt->tgt_lock); - rc = wait_for_completion_timeout(&io_req->tm_done, - BNX2FC_FW_TIMEOUT); - spin_lock_bh(&tgt->tgt_lock); - io_req->wait_for_comp = 0; - if (!rc) - kref_put(&io_req->refcount, bnx2fc_cmd_release); - } spin_unlock_bh(&tgt->tgt_lock); @@ -1103,48 +1089,6 @@ int bnx2fc_eh_device_reset(struct scsi_cmnd *sc_cmd) return bnx2fc_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET); } -int bnx2fc_expl_logo(struct fc_lport *lport, struct bnx2fc_cmd *io_req) -{ - struct bnx2fc_rport *tgt = io_req->tgt; - struct fc_rport_priv *rdata = tgt->rdata; - int logo_issued; - int rc = SUCCESS; - int wait_cnt = 0; - - BNX2FC_IO_DBG(io_req, "Expl logo - tgt flags = 0x%lx\n", - tgt->flags); - logo_issued = test_and_set_bit(BNX2FC_FLAG_EXPL_LOGO, - &tgt->flags); - io_req->wait_for_comp = 1; - bnx2fc_initiate_cleanup(io_req); - - spin_unlock_bh(&tgt->tgt_lock); - - wait_for_completion(&io_req->tm_done); - - io_req->wait_for_comp = 0; - /* - * release the reference taken in eh_abort to allow the - * target to re-login after flushing IOs - */ - kref_put(&io_req->refcount, bnx2fc_cmd_release); - - if (!logo_issued) { - clear_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags); - mutex_lock(&lport->disc.disc_mutex); - lport->tt.rport_logoff(rdata); - mutex_unlock(&lport->disc.disc_mutex); - do { - msleep(BNX2FC_RELOGIN_WAIT_TIME); - if (wait_cnt++ > BNX2FC_RELOGIN_WAIT_CNT) { - rc = FAILED; - break; - } - } while (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)); - } - spin_lock_bh(&tgt->tgt_lock); - return rc; -} /** * bnx2fc_eh_abort - eh_abort_handler api to abort an outstanding * SCSI command @@ -1159,7 +1103,10 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) struct fc_rport_libfc_priv *rp = rport->dd_data; struct bnx2fc_cmd *io_req; struct fc_lport *lport; + struct fc_rport_priv *rdata; struct bnx2fc_rport *tgt; + int logo_issued; + int wait_cnt = 0; int rc = FAILED; @@ -1236,31 +1183,58 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) list_add_tail(&io_req->link, &tgt->io_retire_queue); init_completion(&io_req->tm_done); + io_req->wait_for_comp = 1; - if (test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) { + if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) { + /* Cancel the current timer running on this io_req */ + if (cancel_delayed_work(&io_req->timeout_work)) + kref_put(&io_req->refcount, + bnx2fc_cmd_release); /* drop timer hold */ + set_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags); + rc = bnx2fc_initiate_abts(io_req); + } else { printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) " "already in abts processing\n", io_req->xid); if (cancel_delayed_work(&io_req->timeout_work)) kref_put(&io_req->refcount, bnx2fc_cmd_release); /* drop timer hold */ - rc = bnx2fc_expl_logo(lport, io_req); - goto out; - } - - /* Cancel the current timer running on this io_req */ - if (cancel_delayed_work(&io_req->timeout_work)) - kref_put(&io_req->refcount, - bnx2fc_cmd_release); /* drop timer hold */ - set_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags); - io_req->wait_for_comp = 1; - rc = bnx2fc_initiate_abts(io_req); - if (rc == FAILED) { bnx2fc_initiate_cleanup(io_req); + spin_unlock_bh(&tgt->tgt_lock); + wait_for_completion(&io_req->tm_done); + spin_lock_bh(&tgt->tgt_lock); io_req->wait_for_comp = 0; - goto done; + rdata = io_req->tgt->rdata; + logo_issued = test_and_set_bit(BNX2FC_FLAG_EXPL_LOGO, + &tgt->flags); + kref_put(&io_req->refcount, bnx2fc_cmd_release); + spin_unlock_bh(&tgt->tgt_lock); + + if (!logo_issued) { + BNX2FC_IO_DBG(io_req, "Expl logo - tgt flags = 0x%lx\n", + tgt->flags); + mutex_lock(&lport->disc.disc_mutex); + lport->tt.rport_logoff(rdata); + mutex_unlock(&lport->disc.disc_mutex); + do { + msleep(BNX2FC_RELOGIN_WAIT_TIME); + /* + * If session not recovered, let SCSI-ml + * escalate error recovery. + */ + if (wait_cnt++ > BNX2FC_RELOGIN_WAIT_CNT) + return FAILED; + } while (!test_bit(BNX2FC_FLAG_SESSION_READY, + &tgt->flags)); + } + return SUCCESS; + } + if (rc == FAILED) { + kref_put(&io_req->refcount, bnx2fc_cmd_release); + spin_unlock_bh(&tgt->tgt_lock); + return rc; } spin_unlock_bh(&tgt->tgt_lock); @@ -1273,8 +1247,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) /* Let the scsi-ml try to recover this command */ printk(KERN_ERR PFX "abort failed, xid = 0x%x\n", io_req->xid); - rc = bnx2fc_expl_logo(lport, io_req); - goto out; + rc = FAILED; } else { /* * We come here even when there was a race condition @@ -1286,10 +1259,9 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) bnx2fc_scsi_done(io_req, DID_ABORT); kref_put(&io_req->refcount, bnx2fc_cmd_release); } -done: + /* release the reference taken in eh_abort */ kref_put(&io_req->refcount, bnx2fc_cmd_release); -out: spin_unlock_bh(&tgt->tgt_lock); return rc; } diff --git a/trunk/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/trunk/drivers/scsi/bnx2fc/bnx2fc_tgt.c index 082a25c3117e..c1800b531270 100644 --- a/trunk/drivers/scsi/bnx2fc/bnx2fc_tgt.c +++ b/trunk/drivers/scsi/bnx2fc/bnx2fc_tgt.c @@ -185,16 +185,6 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt) BUG_ON(rc); } - list_for_each_safe(list, tmp, &tgt->active_tm_queue) { - i++; - io_req = (struct bnx2fc_cmd *)list; - list_del_init(&io_req->link); - io_req->on_tmf_queue = 0; - BNX2FC_IO_DBG(io_req, "tm_queue cleanup\n"); - if (io_req->wait_for_comp) - complete(&io_req->tm_done); - } - list_for_each_safe(list, tmp, &tgt->els_queue) { i++; io_req = (struct bnx2fc_cmd *)list; @@ -223,17 +213,8 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt) BNX2FC_IO_DBG(io_req, "retire_queue flush\n"); - if (cancel_delayed_work(&io_req->timeout_work)) { - if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT, - &io_req->req_flags)) { - /* Handle eh_abort timeout */ - BNX2FC_IO_DBG(io_req, "eh_abort for IO " - "in retire_q\n"); - if (io_req->wait_for_comp) - complete(&io_req->tm_done); - } + if (cancel_delayed_work(&io_req->timeout_work)) kref_put(&io_req->refcount, bnx2fc_cmd_release); - } clear_bit(BNX2FC_FLAG_ISSUE_RRQ, &io_req->req_flags); } diff --git a/trunk/drivers/scsi/fcoe/Makefile b/trunk/drivers/scsi/fcoe/Makefile index aed0f5db3668..f6d37d0271f7 100644 --- a/trunk/drivers/scsi/fcoe/Makefile +++ b/trunk/drivers/scsi/fcoe/Makefile @@ -1,4 +1,4 @@ obj-$(CONFIG_FCOE) += fcoe.o obj-$(CONFIG_LIBFCOE) += libfcoe.o -libfcoe-objs := fcoe_ctlr.o fcoe_transport.o fcoe_sysfs.o +libfcoe-objs := fcoe_ctlr.o fcoe_transport.o diff --git a/trunk/drivers/scsi/fcoe/fcoe.c b/trunk/drivers/scsi/fcoe/fcoe.c index fe30b1b65e1d..76e3d0b5bfa6 100644 --- a/trunk/drivers/scsi/fcoe/fcoe.c +++ b/trunk/drivers/scsi/fcoe/fcoe.c @@ -41,7 +41,6 @@ #include #include -#include #include #include @@ -151,21 +150,6 @@ static int fcoe_vport_create(struct fc_vport *, bool disabled); static int fcoe_vport_disable(struct fc_vport *, bool disable); static void fcoe_set_vport_symbolic_name(struct fc_vport *); static void fcoe_set_port_id(struct fc_lport *, u32, struct fc_frame *); -static void fcoe_ctlr_get_lesb(struct fcoe_ctlr_device *); -static void fcoe_fcf_get_vlan_id(struct fcoe_fcf_device *); - -static struct fcoe_sysfs_function_template fcoe_sysfs_templ = { - .get_fcoe_ctlr_mode = fcoe_ctlr_get_fip_mode, - .get_fcoe_ctlr_link_fail = fcoe_ctlr_get_lesb, - .get_fcoe_ctlr_vlink_fail = fcoe_ctlr_get_lesb, - .get_fcoe_ctlr_miss_fka = fcoe_ctlr_get_lesb, - .get_fcoe_ctlr_symb_err = fcoe_ctlr_get_lesb, - .get_fcoe_ctlr_err_block = fcoe_ctlr_get_lesb, - .get_fcoe_ctlr_fcs_error = fcoe_ctlr_get_lesb, - - .get_fcoe_fcf_selected = fcoe_fcf_get_selected, - .get_fcoe_fcf_vlan_id = fcoe_fcf_get_vlan_id, -}; static struct libfc_function_template fcoe_libfc_fcn_templ = { .frame_send = fcoe_xmit, @@ -298,7 +282,7 @@ static struct scsi_host_template fcoe_shost_template = { static int fcoe_interface_setup(struct fcoe_interface *fcoe, struct net_device *netdev) { - struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe); + struct fcoe_ctlr *fip = &fcoe->ctlr; struct netdev_hw_addr *ha; struct net_device *real_dev; u8 flogi_maddr[ETH_ALEN]; @@ -382,10 +366,7 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe, static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev, enum fip_state fip_mode) { - struct fcoe_ctlr_device *ctlr_dev; - struct fcoe_ctlr *ctlr; struct fcoe_interface *fcoe; - int size; int err; if (!try_module_get(THIS_MODULE)) { @@ -395,32 +376,27 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev, goto out; } - size = sizeof(struct fcoe_ctlr) + sizeof(struct fcoe_interface); - ctlr_dev = fcoe_ctlr_device_add(&netdev->dev, &fcoe_sysfs_templ, - size); - if (!ctlr_dev) { - FCOE_DBG("Failed to add fcoe_ctlr_device\n"); + fcoe = kzalloc(sizeof(*fcoe), GFP_KERNEL); + if (!fcoe) { + FCOE_NETDEV_DBG(netdev, "Could not allocate fcoe structure\n"); fcoe = ERR_PTR(-ENOMEM); goto out_putmod; } - ctlr = fcoe_ctlr_device_priv(ctlr_dev); - fcoe = fcoe_ctlr_priv(ctlr); - dev_hold(netdev); /* * Initialize FIP. */ - fcoe_ctlr_init(ctlr, fip_mode); - ctlr->send = fcoe_fip_send; - ctlr->update_mac = fcoe_update_src_mac; - ctlr->get_src_addr = fcoe_get_src_mac; + fcoe_ctlr_init(&fcoe->ctlr, fip_mode); + fcoe->ctlr.send = fcoe_fip_send; + fcoe->ctlr.update_mac = fcoe_update_src_mac; + fcoe->ctlr.get_src_addr = fcoe_get_src_mac; err = fcoe_interface_setup(fcoe, netdev); if (err) { - fcoe_ctlr_destroy(ctlr); - fcoe_ctlr_device_delete(ctlr_dev); + fcoe_ctlr_destroy(&fcoe->ctlr); + kfree(fcoe); dev_put(netdev); fcoe = ERR_PTR(err); goto out_putmod; @@ -443,7 +419,7 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev, static void fcoe_interface_remove(struct fcoe_interface *fcoe) { struct net_device *netdev = fcoe->netdev; - struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe); + struct fcoe_ctlr *fip = &fcoe->ctlr; u8 flogi_maddr[ETH_ALEN]; const struct net_device_ops *ops; @@ -486,8 +462,7 @@ static void fcoe_interface_remove(struct fcoe_interface *fcoe) static void fcoe_interface_cleanup(struct fcoe_interface *fcoe) { struct net_device *netdev = fcoe->netdev; - struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe); - struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip); + struct fcoe_ctlr *fip = &fcoe->ctlr; rtnl_lock(); if (!fcoe->removed) @@ -497,8 +472,8 @@ static void fcoe_interface_cleanup(struct fcoe_interface *fcoe) /* Release the self-reference taken during fcoe_interface_create() */ /* tear-down the FCoE controller */ fcoe_ctlr_destroy(fip); - scsi_host_put(fip->lp->host); - fcoe_ctlr_device_delete(ctlr_dev); + scsi_host_put(fcoe->ctlr.lp->host); + kfree(fcoe); dev_put(netdev); module_put(THIS_MODULE); } @@ -518,11 +493,9 @@ static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *netdev, struct net_device *orig_dev) { struct fcoe_interface *fcoe; - struct fcoe_ctlr *ctlr; fcoe = container_of(ptype, struct fcoe_interface, fip_packet_type); - ctlr = fcoe_to_ctlr(fcoe); - fcoe_ctlr_recv(ctlr, skb); + fcoe_ctlr_recv(&fcoe->ctlr, skb); return 0; } @@ -672,13 +645,11 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev) u32 mfs; u64 wwnn, wwpn; struct fcoe_interface *fcoe; - struct fcoe_ctlr *ctlr; struct fcoe_port *port; /* Setup lport private data to point to fcoe softc */ port = lport_priv(lport); fcoe = port->priv; - ctlr = fcoe_to_ctlr(fcoe); /* * Determine max frame size based on underlying device and optional @@ -705,10 +676,10 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev) if (!lport->vport) { if (fcoe_get_wwn(netdev, &wwnn, NETDEV_FCOE_WWNN)) - wwnn = fcoe_wwn_from_mac(ctlr->ctl_src_addr, 1, 0); + wwnn = fcoe_wwn_from_mac(fcoe->ctlr.ctl_src_addr, 1, 0); fc_set_wwnn(lport, wwnn); if (fcoe_get_wwn(netdev, &wwpn, NETDEV_FCOE_WWPN)) - wwpn = fcoe_wwn_from_mac(ctlr->ctl_src_addr, + wwpn = fcoe_wwn_from_mac(fcoe->ctlr.ctl_src_addr, 2, 0); fc_set_wwpn(lport, wwpn); } @@ -1085,7 +1056,6 @@ static int fcoe_ddp_done(struct fc_lport *lport, u16 xid) static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, struct device *parent, int npiv) { - struct fcoe_ctlr *ctlr = fcoe_to_ctlr(fcoe); struct net_device *netdev = fcoe->netdev; struct fc_lport *lport, *n_port; struct fcoe_port *port; @@ -1149,7 +1119,7 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, } /* Initialize the library */ - rc = fcoe_libfc_config(lport, ctlr, &fcoe_libfc_fcn_templ, 1); + rc = fcoe_libfc_config(lport, &fcoe->ctlr, &fcoe_libfc_fcn_templ, 1); if (rc) { FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the " "interface\n"); @@ -1416,7 +1386,6 @@ static int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, { struct fc_lport *lport; struct fcoe_rcv_info *fr; - struct fcoe_ctlr *ctlr; struct fcoe_interface *fcoe; struct fc_frame_header *fh; struct fcoe_percpu_s *fps; @@ -1424,8 +1393,7 @@ static int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, unsigned int cpu; fcoe = container_of(ptype, struct fcoe_interface, fcoe_packet_type); - ctlr = fcoe_to_ctlr(fcoe); - lport = ctlr->lp; + lport = fcoe->ctlr.lp; if (unlikely(!lport)) { FCOE_NETDEV_DBG(netdev, "Cannot find hba structure"); goto err2; @@ -1441,8 +1409,8 @@ static int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, eh = eth_hdr(skb); - if (is_fip_mode(ctlr) && - compare_ether_addr(eh->h_source, ctlr->dest_addr)) { + if (is_fip_mode(&fcoe->ctlr) && + compare_ether_addr(eh->h_source, fcoe->ctlr.dest_addr)) { FCOE_NETDEV_DBG(netdev, "wrong source mac address:%pM\n", eh->h_source); goto err; @@ -1576,7 +1544,6 @@ static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) unsigned int elen; /* eth header, may include vlan */ struct fcoe_port *port = lport_priv(lport); struct fcoe_interface *fcoe = port->priv; - struct fcoe_ctlr *ctlr = fcoe_to_ctlr(fcoe); u8 sof, eof; struct fcoe_hdr *hp; @@ -1592,7 +1559,7 @@ static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) } if (unlikely(fh->fh_type == FC_TYPE_ELS) && - fcoe_ctlr_els_send(ctlr, lport, skb)) + fcoe_ctlr_els_send(&fcoe->ctlr, lport, skb)) return 0; sof = fr_sof(fp); @@ -1656,12 +1623,12 @@ static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) /* fill up mac and fcoe headers */ eh = eth_hdr(skb); eh->h_proto = htons(ETH_P_FCOE); - memcpy(eh->h_dest, ctlr->dest_addr, ETH_ALEN); - if (ctlr->map_dest) + memcpy(eh->h_dest, fcoe->ctlr.dest_addr, ETH_ALEN); + if (fcoe->ctlr.map_dest) memcpy(eh->h_dest + 3, fh->fh_d_id, 3); - if (unlikely(ctlr->flogi_oxid != FC_XID_UNKNOWN)) - memcpy(eh->h_source, ctlr->ctl_src_addr, ETH_ALEN); + if (unlikely(fcoe->ctlr.flogi_oxid != FC_XID_UNKNOWN)) + memcpy(eh->h_source, fcoe->ctlr.ctl_src_addr, ETH_ALEN); else memcpy(eh->h_source, port->data_src_addr, ETH_ALEN); @@ -1710,7 +1677,6 @@ static void fcoe_percpu_flush_done(struct sk_buff *skb) static inline int fcoe_filter_frames(struct fc_lport *lport, struct fc_frame *fp) { - struct fcoe_ctlr *ctlr; struct fcoe_interface *fcoe; struct fc_frame_header *fh; struct sk_buff *skb = (struct sk_buff *)fp; @@ -1732,8 +1698,7 @@ static inline int fcoe_filter_frames(struct fc_lport *lport, return 0; fcoe = ((struct fcoe_port *)lport_priv(lport))->priv; - ctlr = fcoe_to_ctlr(fcoe); - if (is_fip_mode(ctlr) && fc_frame_payload_op(fp) == ELS_LOGO && + if (is_fip_mode(&fcoe->ctlr) && fc_frame_payload_op(fp) == ELS_LOGO && ntoh24(fh->fh_s_id) == FC_FID_FLOGI) { FCOE_DBG("fcoe: dropping FCoE lport LOGO in fip mode\n"); return -EINVAL; @@ -1912,7 +1877,6 @@ static int fcoe_dcb_app_notification(struct notifier_block *notifier, ulong event, void *ptr) { struct dcb_app_type *entry = ptr; - struct fcoe_ctlr *ctlr; struct fcoe_interface *fcoe; struct net_device *netdev; struct fcoe_port *port; @@ -1930,8 +1894,6 @@ static int fcoe_dcb_app_notification(struct notifier_block *notifier, if (!fcoe) return NOTIFY_OK; - ctlr = fcoe_to_ctlr(fcoe); - if (entry->dcbx & DCB_CAP_DCBX_VER_CEE) prio = ffs(entry->app.priority) - 1; else @@ -1942,10 +1904,10 @@ static int fcoe_dcb_app_notification(struct notifier_block *notifier, if (entry->app.protocol == ETH_P_FIP || entry->app.protocol == ETH_P_FCOE) - ctlr->priority = prio; + fcoe->ctlr.priority = prio; if (entry->app.protocol == ETH_P_FCOE) { - port = lport_priv(ctlr->lp); + port = lport_priv(fcoe->ctlr.lp); port->priority = prio; } @@ -1967,7 +1929,6 @@ static int fcoe_device_notification(struct notifier_block *notifier, { struct fc_lport *lport = NULL; struct net_device *netdev = ptr; - struct fcoe_ctlr *ctlr; struct fcoe_interface *fcoe; struct fcoe_port *port; struct fcoe_dev_stats *stats; @@ -1977,8 +1938,7 @@ static int fcoe_device_notification(struct notifier_block *notifier, list_for_each_entry(fcoe, &fcoe_hostlist, list) { if (fcoe->netdev == netdev) { - ctlr = fcoe_to_ctlr(fcoe); - lport = ctlr->lp; + lport = fcoe->ctlr.lp; break; } } @@ -2007,7 +1967,7 @@ static int fcoe_device_notification(struct notifier_block *notifier, break; case NETDEV_UNREGISTER: list_del(&fcoe->list); - port = lport_priv(ctlr->lp); + port = lport_priv(fcoe->ctlr.lp); queue_work(fcoe_wq, &port->destroy_work); goto out; break; @@ -2022,8 +1982,8 @@ static int fcoe_device_notification(struct notifier_block *notifier, fcoe_link_speed_update(lport); if (link_possible && !fcoe_link_ok(lport)) - fcoe_ctlr_link_up(ctlr); - else if (fcoe_ctlr_link_down(ctlr)) { + fcoe_ctlr_link_up(&fcoe->ctlr); + else if (fcoe_ctlr_link_down(&fcoe->ctlr)) { stats = per_cpu_ptr(lport->dev_stats, get_cpu()); stats->LinkFailureCount++; put_cpu(); @@ -2043,7 +2003,6 @@ static int fcoe_device_notification(struct notifier_block *notifier, */ static int fcoe_disable(struct net_device *netdev) { - struct fcoe_ctlr *ctlr; struct fcoe_interface *fcoe; int rc = 0; @@ -2054,9 +2013,8 @@ static int fcoe_disable(struct net_device *netdev) rtnl_unlock(); if (fcoe) { - ctlr = fcoe_to_ctlr(fcoe); - fcoe_ctlr_link_down(ctlr); - fcoe_clean_pending_queue(ctlr->lp); + fcoe_ctlr_link_down(&fcoe->ctlr); + fcoe_clean_pending_queue(fcoe->ctlr.lp); } else rc = -ENODEV; @@ -2074,7 +2032,6 @@ static int fcoe_disable(struct net_device *netdev) */ static int fcoe_enable(struct net_device *netdev) { - struct fcoe_ctlr *ctlr; struct fcoe_interface *fcoe; int rc = 0; @@ -2083,17 +2040,11 @@ static int fcoe_enable(struct net_device *netdev) fcoe = fcoe_hostlist_lookup_port(netdev); rtnl_unlock(); - if (!fcoe) { + if (!fcoe) rc = -ENODEV; - goto out; - } - - ctlr = fcoe_to_ctlr(fcoe); - - if (!fcoe_link_ok(ctlr->lp)) - fcoe_ctlr_link_up(ctlr); + else if (!fcoe_link_ok(fcoe->ctlr.lp)) + fcoe_ctlr_link_up(&fcoe->ctlr); -out: mutex_unlock(&fcoe_config_mutex); return rc; } @@ -2108,7 +2059,6 @@ static int fcoe_enable(struct net_device *netdev) */ static int fcoe_destroy(struct net_device *netdev) { - struct fcoe_ctlr *ctlr; struct fcoe_interface *fcoe; struct fc_lport *lport; struct fcoe_port *port; @@ -2121,8 +2071,7 @@ static int fcoe_destroy(struct net_device *netdev) rc = -ENODEV; goto out_nodev; } - ctlr = fcoe_to_ctlr(fcoe); - lport = ctlr->lp; + lport = fcoe->ctlr.lp; port = lport_priv(lport); list_del(&fcoe->list); queue_work(fcoe_wq, &port->destroy_work); @@ -2177,8 +2126,7 @@ static void fcoe_dcb_create(struct fcoe_interface *fcoe) int dcbx; u8 fup, up; struct net_device *netdev = fcoe->realdev; - struct fcoe_ctlr *ctlr = fcoe_to_ctlr(fcoe); - struct fcoe_port *port = lport_priv(ctlr->lp); + struct fcoe_port *port = lport_priv(fcoe->ctlr.lp); struct dcb_app app = { .priority = 0, .protocol = ETH_P_FCOE @@ -2201,7 +2149,7 @@ static void fcoe_dcb_create(struct fcoe_interface *fcoe) } port->priority = ffs(up) ? ffs(up) - 1 : 0; - ctlr->priority = ffs(fup) ? ffs(fup) - 1 : port->priority; + fcoe->ctlr.priority = ffs(fup) ? ffs(fup) - 1 : port->priority; } #endif } @@ -2218,8 +2166,6 @@ static void fcoe_dcb_create(struct fcoe_interface *fcoe) static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) { int rc = 0; - struct fcoe_ctlr_device *ctlr_dev; - struct fcoe_ctlr *ctlr; struct fcoe_interface *fcoe; struct fc_lport *lport; @@ -2238,9 +2184,7 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) goto out_nodev; } - ctlr = fcoe_to_ctlr(fcoe); - ctlr_dev = fcoe_ctlr_to_ctlr_dev(ctlr); - lport = fcoe_if_create(fcoe, &ctlr_dev->dev, 0); + lport = fcoe_if_create(fcoe, &netdev->dev, 0); if (IS_ERR(lport)) { printk(KERN_ERR "fcoe: Failed to create interface (%s)\n", netdev->name); @@ -2251,7 +2195,7 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) } /* Make this the "master" N_Port */ - ctlr->lp = lport; + fcoe->ctlr.lp = lport; /* setup DCB priority attributes. */ fcoe_dcb_create(fcoe); @@ -2264,7 +2208,7 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) fc_fabric_login(lport); if (!fcoe_link_ok(lport)) { rtnl_unlock(); - fcoe_ctlr_link_up(ctlr); + fcoe_ctlr_link_up(&fcoe->ctlr); mutex_unlock(&fcoe_config_mutex); return rc; } @@ -2376,12 +2320,11 @@ static int fcoe_reset(struct Scsi_Host *shost) struct fc_lport *lport = shost_priv(shost); struct fcoe_port *port = lport_priv(lport); struct fcoe_interface *fcoe = port->priv; - struct fcoe_ctlr *ctlr = fcoe_to_ctlr(fcoe); - fcoe_ctlr_link_down(ctlr); - fcoe_clean_pending_queue(ctlr->lp); - if (!fcoe_link_ok(ctlr->lp)) - fcoe_ctlr_link_up(ctlr); + fcoe_ctlr_link_down(&fcoe->ctlr); + fcoe_clean_pending_queue(fcoe->ctlr.lp); + if (!fcoe_link_ok(fcoe->ctlr.lp)) + fcoe_ctlr_link_up(&fcoe->ctlr); return 0; } @@ -2416,12 +2359,10 @@ fcoe_hostlist_lookup_port(const struct net_device *netdev) */ static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev) { - struct fcoe_ctlr *ctlr; struct fcoe_interface *fcoe; fcoe = fcoe_hostlist_lookup_port(netdev); - ctlr = fcoe_to_ctlr(fcoe); - return (fcoe) ? ctlr->lp : NULL; + return (fcoe) ? fcoe->ctlr.lp : NULL; } /** @@ -2525,7 +2466,6 @@ module_init(fcoe_init); static void __exit fcoe_exit(void) { struct fcoe_interface *fcoe, *tmp; - struct fcoe_ctlr *ctlr; struct fcoe_port *port; unsigned int cpu; @@ -2537,8 +2477,7 @@ static void __exit fcoe_exit(void) rtnl_lock(); list_for_each_entry_safe(fcoe, tmp, &fcoe_hostlist, list) { list_del(&fcoe->list); - ctlr = fcoe_to_ctlr(fcoe); - port = lport_priv(ctlr->lp); + port = lport_priv(fcoe->ctlr.lp); queue_work(fcoe_wq, &port->destroy_work); } rtnl_unlock(); @@ -2634,7 +2573,7 @@ static struct fc_seq *fcoe_elsct_send(struct fc_lport *lport, u32 did, { struct fcoe_port *port = lport_priv(lport); struct fcoe_interface *fcoe = port->priv; - struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe); + struct fcoe_ctlr *fip = &fcoe->ctlr; struct fc_frame_header *fh = fc_frame_header_get(fp); switch (op) { @@ -2791,40 +2730,6 @@ static void fcoe_get_lesb(struct fc_lport *lport, __fcoe_get_lesb(lport, fc_lesb, netdev); } -static void fcoe_ctlr_get_lesb(struct fcoe_ctlr_device *ctlr_dev) -{ - struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr_dev); - struct net_device *netdev = fcoe_netdev(fip->lp); - struct fcoe_fc_els_lesb *fcoe_lesb; - struct fc_els_lesb fc_lesb; - - __fcoe_get_lesb(fip->lp, &fc_lesb, netdev); - fcoe_lesb = (struct fcoe_fc_els_lesb *)(&fc_lesb); - - ctlr_dev->lesb.lesb_link_fail = - ntohl(fcoe_lesb->lesb_link_fail); - ctlr_dev->lesb.lesb_vlink_fail = - ntohl(fcoe_lesb->lesb_vlink_fail); - ctlr_dev->lesb.lesb_miss_fka = - ntohl(fcoe_lesb->lesb_miss_fka); - ctlr_dev->lesb.lesb_symb_err = - ntohl(fcoe_lesb->lesb_symb_err); - ctlr_dev->lesb.lesb_err_block = - ntohl(fcoe_lesb->lesb_err_block); - ctlr_dev->lesb.lesb_fcs_error = - ntohl(fcoe_lesb->lesb_fcs_error); -} - -static void fcoe_fcf_get_vlan_id(struct fcoe_fcf_device *fcf_dev) -{ - struct fcoe_ctlr_device *ctlr_dev = - fcoe_fcf_dev_to_ctlr_dev(fcf_dev); - struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev); - struct fcoe_interface *fcoe = fcoe_ctlr_priv(ctlr); - - fcf_dev->vlan_id = vlan_dev_vlan_id(fcoe->netdev); -} - /** * fcoe_set_port_id() - Callback from libfc when Port_ID is set. * @lport: the local port @@ -2842,8 +2747,7 @@ static void fcoe_set_port_id(struct fc_lport *lport, { struct fcoe_port *port = lport_priv(lport); struct fcoe_interface *fcoe = port->priv; - struct fcoe_ctlr *ctlr = fcoe_to_ctlr(fcoe); if (fp && fc_frame_payload_op(fp) == ELS_FLOGI) - fcoe_ctlr_recv_flogi(ctlr, lport, fp); + fcoe_ctlr_recv_flogi(&fcoe->ctlr, lport, fp); } diff --git a/trunk/drivers/scsi/fcoe/fcoe.h b/trunk/drivers/scsi/fcoe/fcoe.h index a624add4f8ec..96ac938d39cc 100644 --- a/trunk/drivers/scsi/fcoe/fcoe.h +++ b/trunk/drivers/scsi/fcoe/fcoe.h @@ -68,6 +68,7 @@ do { \ * @netdev: The associated net device * @fcoe_packet_type: FCoE packet type * @fip_packet_type: FIP packet type + * @ctlr: The FCoE controller (for FIP) * @oem: The offload exchange manager for all local port * instances associated with this port * @removed: Indicates fcoe interface removed from net device @@ -79,15 +80,12 @@ struct fcoe_interface { struct net_device *realdev; struct packet_type fcoe_packet_type; struct packet_type fip_packet_type; + struct fcoe_ctlr ctlr; struct fc_exch_mgr *oem; u8 removed; }; -#define fcoe_to_ctlr(x) \ - (struct fcoe_ctlr *)(((struct fcoe_ctlr *)(x)) - 1) - -#define fcoe_from_ctlr(x) \ - ((struct fcoe_interface *)((x) + 1)) +#define fcoe_from_ctlr(fip) container_of(fip, struct fcoe_interface, ctlr) /** * fcoe_netdev() - Return the net device associated with a local port diff --git a/trunk/drivers/scsi/fcoe/fcoe_ctlr.c b/trunk/drivers/scsi/fcoe/fcoe_ctlr.c index d68d57241ee6..5a4c7250aa77 100644 --- a/trunk/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/trunk/drivers/scsi/fcoe/fcoe_ctlr.c @@ -160,76 +160,6 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip, enum fip_state mode) } EXPORT_SYMBOL(fcoe_ctlr_init); -static int fcoe_sysfs_fcf_add(struct fcoe_fcf *new) -{ - struct fcoe_ctlr *fip = new->fip; - struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip); - struct fcoe_fcf_device temp, *fcf_dev; - int rc = 0; - - LIBFCOE_FIP_DBG(fip, "New FCF fab %16.16llx mac %pM\n", - new->fabric_name, new->fcf_mac); - - mutex_lock(&ctlr_dev->lock); - - temp.fabric_name = new->fabric_name; - temp.switch_name = new->switch_name; - temp.fc_map = new->fc_map; - temp.vfid = new->vfid; - memcpy(temp.mac, new->fcf_mac, ETH_ALEN); - temp.priority = new->pri; - temp.fka_period = new->fka_period; - temp.selected = 0; /* default to unselected */ - - fcf_dev = fcoe_fcf_device_add(ctlr_dev, &temp); - if (unlikely(!fcf_dev)) { - rc = -ENOMEM; - goto out; - } - - /* - * The fcoe_sysfs layer can return a CONNECTED fcf that - * has a priv (fcf was never deleted) or a CONNECTED fcf - * that doesn't have a priv (fcf was deleted). However, - * libfcoe will always delete FCFs before trying to add - * them. This is ensured because both recv_adv and - * age_fcfs are protected by the the fcoe_ctlr's mutex. - * This means that we should never get a FCF with a - * non-NULL priv pointer. - */ - BUG_ON(fcf_dev->priv); - - fcf_dev->priv = new; - new->fcf_dev = fcf_dev; - - list_add(&new->list, &fip->fcfs); - fip->fcf_count++; - -out: - mutex_unlock(&ctlr_dev->lock); - return rc; -} - -static void fcoe_sysfs_fcf_del(struct fcoe_fcf *new) -{ - struct fcoe_ctlr *fip = new->fip; - struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip); - struct fcoe_fcf_device *fcf_dev; - - list_del(&new->list); - fip->fcf_count--; - - mutex_lock(&ctlr_dev->lock); - - fcf_dev = fcoe_fcf_to_fcf_dev(new); - WARN_ON(!fcf_dev); - new->fcf_dev = NULL; - fcoe_fcf_device_delete(fcf_dev); - kfree(new); - - mutex_unlock(&ctlr_dev->lock); -} - /** * fcoe_ctlr_reset_fcfs() - Reset and free all FCFs for a controller * @fip: The FCoE controller whose FCFs are to be reset @@ -243,10 +173,10 @@ static void fcoe_ctlr_reset_fcfs(struct fcoe_ctlr *fip) fip->sel_fcf = NULL; list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { - fcoe_sysfs_fcf_del(fcf); + list_del(&fcf->list); + kfree(fcf); } - WARN_ON(fip->fcf_count); - + fip->fcf_count = 0; fip->sel_time = 0; } @@ -787,11 +717,8 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD); unsigned long deadline; unsigned long sel_time = 0; - struct list_head del_list; struct fcoe_dev_stats *stats; - INIT_LIST_HEAD(&del_list); - stats = per_cpu_ptr(fip->lp->dev_stats, get_cpu()); list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { @@ -812,13 +739,10 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) if (time_after_eq(jiffies, deadline)) { if (fip->sel_fcf == fcf) fip->sel_fcf = NULL; - /* - * Move to delete list so we can call - * fcoe_sysfs_fcf_del (which can sleep) - * after the put_cpu(). - */ list_del(&fcf->list); - list_add(&fcf->list, &del_list); + WARN_ON(!fip->fcf_count); + fip->fcf_count--; + kfree(fcf); stats->VLinkFailureCount++; } else { if (time_after(next_timer, deadline)) @@ -829,12 +753,6 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) } } put_cpu(); - - list_for_each_entry_safe(fcf, next, &del_list, list) { - /* Removes fcf from current list */ - fcoe_sysfs_fcf_del(fcf); - } - if (sel_time && !fip->sel_fcf && !fip->sel_time) { sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY); fip->sel_time = sel_time; @@ -985,23 +903,23 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) { struct fcoe_fcf *fcf; struct fcoe_fcf new; + struct fcoe_fcf *found; unsigned long sol_tov = msecs_to_jiffies(FCOE_CTRL_SOL_TOV); int first = 0; int mtu_valid; - int found = 0; - int rc = 0; if (fcoe_ctlr_parse_adv(fip, skb, &new)) return; mutex_lock(&fip->ctlr_mutex); first = list_empty(&fip->fcfs); + found = NULL; list_for_each_entry(fcf, &fip->fcfs, list) { if (fcf->switch_name == new.switch_name && fcf->fabric_name == new.fabric_name && fcf->fc_map == new.fc_map && compare_ether_addr(fcf->fcf_mac, new.fcf_mac) == 0) { - found = 1; + found = fcf; break; } } @@ -1013,16 +931,9 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) if (!fcf) goto out; + fip->fcf_count++; memcpy(fcf, &new, sizeof(new)); - fcf->fip = fip; - rc = fcoe_sysfs_fcf_add(fcf); - if (rc) { - printk(KERN_ERR "Failed to allocate sysfs instance " - "for FCF, fab %16.16llx mac %pM\n", - new.fabric_name, new.fcf_mac); - kfree(fcf); - goto out; - } + list_add(&fcf->list, &fip->fcfs); } else { /* * Update the FCF's keep-alive descriptor flags. @@ -1043,7 +954,6 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) fcf->fka_period = new.fka_period; memcpy(fcf->fcf_mac, new.fcf_mac, ETH_ALEN); } - mtu_valid = fcoe_ctlr_mtu_valid(fcf); fcf->time = jiffies; if (!found) @@ -1086,7 +996,6 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) time_before(fip->sel_time, fip->timer.expires)) mod_timer(&fip->timer, fip->sel_time); } - out: mutex_unlock(&fip->ctlr_mutex); } @@ -2809,9 +2718,9 @@ static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *fip) /** * fcoe_libfc_config() - Sets up libfc related properties for local port - * @lport: The local port to configure libfc for - * @fip: The FCoE controller in use by the local port - * @tt: The libfc function template + * @lp: The local port to configure libfc for + * @fip: The FCoE controller in use by the local port + * @tt: The libfc function template * @init_fcp: If non-zero, the FCP portion of libfc should be initialized * * Returns : 0 for success @@ -2844,43 +2753,3 @@ int fcoe_libfc_config(struct fc_lport *lport, struct fcoe_ctlr *fip, return 0; } EXPORT_SYMBOL_GPL(fcoe_libfc_config); - -void fcoe_fcf_get_selected(struct fcoe_fcf_device *fcf_dev) -{ - struct fcoe_ctlr_device *ctlr_dev = fcoe_fcf_dev_to_ctlr_dev(fcf_dev); - struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr_dev); - struct fcoe_fcf *fcf; - - mutex_lock(&fip->ctlr_mutex); - mutex_lock(&ctlr_dev->lock); - - fcf = fcoe_fcf_device_priv(fcf_dev); - if (fcf) - fcf_dev->selected = (fcf == fip->sel_fcf) ? 1 : 0; - else - fcf_dev->selected = 0; - - mutex_unlock(&ctlr_dev->lock); - mutex_unlock(&fip->ctlr_mutex); -} -EXPORT_SYMBOL(fcoe_fcf_get_selected); - -void fcoe_ctlr_get_fip_mode(struct fcoe_ctlr_device *ctlr_dev) -{ - struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev); - - mutex_lock(&ctlr->ctlr_mutex); - switch (ctlr->mode) { - case FIP_MODE_FABRIC: - ctlr_dev->mode = FIP_CONN_TYPE_FABRIC; - break; - case FIP_MODE_VN2VN: - ctlr_dev->mode = FIP_CONN_TYPE_VN2VN; - break; - default: - ctlr_dev->mode = FIP_CONN_TYPE_UNKNOWN; - break; - } - mutex_unlock(&ctlr->ctlr_mutex); -} -EXPORT_SYMBOL(fcoe_ctlr_get_fip_mode); diff --git a/trunk/drivers/scsi/fcoe/fcoe_sysfs.c b/trunk/drivers/scsi/fcoe/fcoe_sysfs.c deleted file mode 100644 index 2bc163198d33..000000000000 --- a/trunk/drivers/scsi/fcoe/fcoe_sysfs.c +++ /dev/null @@ -1,832 +0,0 @@ -/* - * Copyright(c) 2011 - 2012 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Maintained at www.Open-FCoE.org - */ - -#include -#include -#include -#include - -#include - -static atomic_t ctlr_num; -static atomic_t fcf_num; - -/* - * fcoe_fcf_dev_loss_tmo: the default number of seconds that fcoe sysfs - * should insulate the loss of a fcf. - */ -static unsigned int fcoe_fcf_dev_loss_tmo = 1800; /* seconds */ - -module_param_named(fcf_dev_loss_tmo, fcoe_fcf_dev_loss_tmo, - uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(fcf_dev_loss_tmo, - "Maximum number of seconds that libfcoe should" - " insulate the loss of a fcf. Once this value is" - " exceeded, the fcf is removed."); - -/* - * These are used by the fcoe_*_show_function routines, they - * are intentionally placed in the .c file as they're not intended - * for use throughout the code. - */ -#define fcoe_ctlr_id(x) \ - ((x)->id) -#define fcoe_ctlr_work_q_name(x) \ - ((x)->work_q_name) -#define fcoe_ctlr_work_q(x) \ - ((x)->work_q) -#define fcoe_ctlr_devloss_work_q_name(x) \ - ((x)->devloss_work_q_name) -#define fcoe_ctlr_devloss_work_q(x) \ - ((x)->devloss_work_q) -#define fcoe_ctlr_mode(x) \ - ((x)->mode) -#define fcoe_ctlr_fcf_dev_loss_tmo(x) \ - ((x)->fcf_dev_loss_tmo) -#define fcoe_ctlr_link_fail(x) \ - ((x)->lesb.lesb_link_fail) -#define fcoe_ctlr_vlink_fail(x) \ - ((x)->lesb.lesb_vlink_fail) -#define fcoe_ctlr_miss_fka(x) \ - ((x)->lesb.lesb_miss_fka) -#define fcoe_ctlr_symb_err(x) \ - ((x)->lesb.lesb_symb_err) -#define fcoe_ctlr_err_block(x) \ - ((x)->lesb.lesb_err_block) -#define fcoe_ctlr_fcs_error(x) \ - ((x)->lesb.lesb_fcs_error) -#define fcoe_fcf_state(x) \ - ((x)->state) -#define fcoe_fcf_fabric_name(x) \ - ((x)->fabric_name) -#define fcoe_fcf_switch_name(x) \ - ((x)->switch_name) -#define fcoe_fcf_fc_map(x) \ - ((x)->fc_map) -#define fcoe_fcf_vfid(x) \ - ((x)->vfid) -#define fcoe_fcf_mac(x) \ - ((x)->mac) -#define fcoe_fcf_priority(x) \ - ((x)->priority) -#define fcoe_fcf_fka_period(x) \ - ((x)->fka_period) -#define fcoe_fcf_dev_loss_tmo(x) \ - ((x)->dev_loss_tmo) -#define fcoe_fcf_selected(x) \ - ((x)->selected) -#define fcoe_fcf_vlan_id(x) \ - ((x)->vlan_id) - -/* - * dev_loss_tmo attribute - */ -static int fcoe_str_to_dev_loss(const char *buf, unsigned long *val) -{ - int ret; - - ret = kstrtoul(buf, 0, val); - if (ret || *val < 0) - return -EINVAL; - /* - * Check for overflow; dev_loss_tmo is u32 - */ - if (*val > UINT_MAX) - return -EINVAL; - - return 0; -} - -static int fcoe_fcf_set_dev_loss_tmo(struct fcoe_fcf_device *fcf, - unsigned long val) -{ - if ((fcf->state == FCOE_FCF_STATE_UNKNOWN) || - (fcf->state == FCOE_FCF_STATE_DISCONNECTED) || - (fcf->state == FCOE_FCF_STATE_DELETED)) - return -EBUSY; - /* - * Check for overflow; dev_loss_tmo is u32 - */ - if (val > UINT_MAX) - return -EINVAL; - - fcoe_fcf_dev_loss_tmo(fcf) = val; - return 0; -} - -#define FCOE_DEVICE_ATTR(_prefix, _name, _mode, _show, _store) \ -struct device_attribute device_attr_fcoe_##_prefix##_##_name = \ - __ATTR(_name, _mode, _show, _store) - -#define fcoe_ctlr_show_function(field, format_string, sz, cast) \ -static ssize_t show_fcoe_ctlr_device_##field(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev); \ - if (ctlr->f->get_fcoe_ctlr_##field) \ - ctlr->f->get_fcoe_ctlr_##field(ctlr); \ - return snprintf(buf, sz, format_string, \ - cast fcoe_ctlr_##field(ctlr)); \ -} - -#define fcoe_fcf_show_function(field, format_string, sz, cast) \ -static ssize_t show_fcoe_fcf_device_##field(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct fcoe_fcf_device *fcf = dev_to_fcf(dev); \ - struct fcoe_ctlr_device *ctlr = fcoe_fcf_dev_to_ctlr_dev(fcf); \ - if (ctlr->f->get_fcoe_fcf_##field) \ - ctlr->f->get_fcoe_fcf_##field(fcf); \ - return snprintf(buf, sz, format_string, \ - cast fcoe_fcf_##field(fcf)); \ -} - -#define fcoe_ctlr_private_show_function(field, format_string, sz, cast) \ -static ssize_t show_fcoe_ctlr_device_##field(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev); \ - return snprintf(buf, sz, format_string, cast fcoe_ctlr_##field(ctlr)); \ -} - -#define fcoe_fcf_private_show_function(field, format_string, sz, cast) \ -static ssize_t show_fcoe_fcf_device_##field(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct fcoe_fcf_device *fcf = dev_to_fcf(dev); \ - return snprintf(buf, sz, format_string, cast fcoe_fcf_##field(fcf)); \ -} - -#define fcoe_ctlr_private_rd_attr(field, format_string, sz) \ - fcoe_ctlr_private_show_function(field, format_string, sz, ) \ - static FCOE_DEVICE_ATTR(ctlr, field, S_IRUGO, \ - show_fcoe_ctlr_device_##field, NULL) - -#define fcoe_ctlr_rd_attr(field, format_string, sz) \ - fcoe_ctlr_show_function(field, format_string, sz, ) \ - static FCOE_DEVICE_ATTR(ctlr, field, S_IRUGO, \ - show_fcoe_ctlr_device_##field, NULL) - -#define fcoe_fcf_rd_attr(field, format_string, sz) \ - fcoe_fcf_show_function(field, format_string, sz, ) \ - static FCOE_DEVICE_ATTR(fcf, field, S_IRUGO, \ - show_fcoe_fcf_device_##field, NULL) - -#define fcoe_fcf_private_rd_attr(field, format_string, sz) \ - fcoe_fcf_private_show_function(field, format_string, sz, ) \ - static FCOE_DEVICE_ATTR(fcf, field, S_IRUGO, \ - show_fcoe_fcf_device_##field, NULL) - -#define fcoe_ctlr_private_rd_attr_cast(field, format_string, sz, cast) \ - fcoe_ctlr_private_show_function(field, format_string, sz, (cast)) \ - static FCOE_DEVICE_ATTR(ctlr, field, S_IRUGO, \ - show_fcoe_ctlr_device_##field, NULL) - -#define fcoe_fcf_private_rd_attr_cast(field, format_string, sz, cast) \ - fcoe_fcf_private_show_function(field, format_string, sz, (cast)) \ - static FCOE_DEVICE_ATTR(fcf, field, S_IRUGO, \ - show_fcoe_fcf_device_##field, NULL) - -#define fcoe_enum_name_search(title, table_type, table) \ -static const char *get_fcoe_##title##_name(enum table_type table_key) \ -{ \ - int i; \ - char *name = NULL; \ - \ - for (i = 0; i < ARRAY_SIZE(table); i++) { \ - if (table[i].value == table_key) { \ - name = table[i].name; \ - break; \ - } \ - } \ - return name; \ -} - -static struct { - enum fcf_state value; - char *name; -} fcf_state_names[] = { - { FCOE_FCF_STATE_UNKNOWN, "Unknown" }, - { FCOE_FCF_STATE_DISCONNECTED, "Disconnected" }, - { FCOE_FCF_STATE_CONNECTED, "Connected" }, -}; -fcoe_enum_name_search(fcf_state, fcf_state, fcf_state_names) -#define FCOE_FCF_STATE_MAX_NAMELEN 50 - -static ssize_t show_fcf_state(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct fcoe_fcf_device *fcf = dev_to_fcf(dev); - const char *name; - name = get_fcoe_fcf_state_name(fcf->state); - if (!name) - return -EINVAL; - return snprintf(buf, FCOE_FCF_STATE_MAX_NAMELEN, "%s\n", name); -} -static FCOE_DEVICE_ATTR(fcf, state, S_IRUGO, show_fcf_state, NULL); - -static struct { - enum fip_conn_type value; - char *name; -} fip_conn_type_names[] = { - { FIP_CONN_TYPE_UNKNOWN, "Unknown" }, - { FIP_CONN_TYPE_FABRIC, "Fabric" }, - { FIP_CONN_TYPE_VN2VN, "VN2VN" }, -}; -fcoe_enum_name_search(ctlr_mode, fip_conn_type, fip_conn_type_names) -#define FCOE_CTLR_MODE_MAX_NAMELEN 50 - -static ssize_t show_ctlr_mode(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev); - const char *name; - - if (ctlr->f->get_fcoe_ctlr_mode) - ctlr->f->get_fcoe_ctlr_mode(ctlr); - - name = get_fcoe_ctlr_mode_name(ctlr->mode); - if (!name) - return -EINVAL; - return snprintf(buf, FCOE_CTLR_MODE_MAX_NAMELEN, - "%s\n", name); -} -static FCOE_DEVICE_ATTR(ctlr, mode, S_IRUGO, - show_ctlr_mode, NULL); - -static ssize_t -store_private_fcoe_ctlr_fcf_dev_loss_tmo(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev); - struct fcoe_fcf_device *fcf; - unsigned long val; - int rc; - - rc = fcoe_str_to_dev_loss(buf, &val); - if (rc) - return rc; - - fcoe_ctlr_fcf_dev_loss_tmo(ctlr) = val; - mutex_lock(&ctlr->lock); - list_for_each_entry(fcf, &ctlr->fcfs, peers) - fcoe_fcf_set_dev_loss_tmo(fcf, val); - mutex_unlock(&ctlr->lock); - return count; -} -fcoe_ctlr_private_show_function(fcf_dev_loss_tmo, "%d\n", 20, ); -static FCOE_DEVICE_ATTR(ctlr, fcf_dev_loss_tmo, S_IRUGO | S_IWUSR, - show_fcoe_ctlr_device_fcf_dev_loss_tmo, - store_private_fcoe_ctlr_fcf_dev_loss_tmo); - -/* Link Error Status Block (LESB) */ -fcoe_ctlr_rd_attr(link_fail, "%u\n", 20); -fcoe_ctlr_rd_attr(vlink_fail, "%u\n", 20); -fcoe_ctlr_rd_attr(miss_fka, "%u\n", 20); -fcoe_ctlr_rd_attr(symb_err, "%u\n", 20); -fcoe_ctlr_rd_attr(err_block, "%u\n", 20); -fcoe_ctlr_rd_attr(fcs_error, "%u\n", 20); - -fcoe_fcf_private_rd_attr_cast(fabric_name, "0x%llx\n", 20, unsigned long long); -fcoe_fcf_private_rd_attr_cast(switch_name, "0x%llx\n", 20, unsigned long long); -fcoe_fcf_private_rd_attr(priority, "%u\n", 20); -fcoe_fcf_private_rd_attr(fc_map, "0x%x\n", 20); -fcoe_fcf_private_rd_attr(vfid, "%u\n", 20); -fcoe_fcf_private_rd_attr(mac, "%pM\n", 20); -fcoe_fcf_private_rd_attr(fka_period, "%u\n", 20); -fcoe_fcf_rd_attr(selected, "%u\n", 20); -fcoe_fcf_rd_attr(vlan_id, "%u\n", 20); - -fcoe_fcf_private_show_function(dev_loss_tmo, "%d\n", 20, ) -static ssize_t -store_fcoe_fcf_dev_loss_tmo(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct fcoe_fcf_device *fcf = dev_to_fcf(dev); - unsigned long val; - int rc; - - rc = fcoe_str_to_dev_loss(buf, &val); - if (rc) - return rc; - - rc = fcoe_fcf_set_dev_loss_tmo(fcf, val); - if (rc) - return rc; - return count; -} -static FCOE_DEVICE_ATTR(fcf, dev_loss_tmo, S_IRUGO | S_IWUSR, - show_fcoe_fcf_device_dev_loss_tmo, - store_fcoe_fcf_dev_loss_tmo); - -static struct attribute *fcoe_ctlr_lesb_attrs[] = { - &device_attr_fcoe_ctlr_link_fail.attr, - &device_attr_fcoe_ctlr_vlink_fail.attr, - &device_attr_fcoe_ctlr_miss_fka.attr, - &device_attr_fcoe_ctlr_symb_err.attr, - &device_attr_fcoe_ctlr_err_block.attr, - &device_attr_fcoe_ctlr_fcs_error.attr, - NULL, -}; - -static struct attribute_group fcoe_ctlr_lesb_attr_group = { - .name = "lesb", - .attrs = fcoe_ctlr_lesb_attrs, -}; - -static struct attribute *fcoe_ctlr_attrs[] = { - &device_attr_fcoe_ctlr_fcf_dev_loss_tmo.attr, - &device_attr_fcoe_ctlr_mode.attr, - NULL, -}; - -static struct attribute_group fcoe_ctlr_attr_group = { - .attrs = fcoe_ctlr_attrs, -}; - -static const struct attribute_group *fcoe_ctlr_attr_groups[] = { - &fcoe_ctlr_attr_group, - &fcoe_ctlr_lesb_attr_group, - NULL, -}; - -static struct attribute *fcoe_fcf_attrs[] = { - &device_attr_fcoe_fcf_fabric_name.attr, - &device_attr_fcoe_fcf_switch_name.attr, - &device_attr_fcoe_fcf_dev_loss_tmo.attr, - &device_attr_fcoe_fcf_fc_map.attr, - &device_attr_fcoe_fcf_vfid.attr, - &device_attr_fcoe_fcf_mac.attr, - &device_attr_fcoe_fcf_priority.attr, - &device_attr_fcoe_fcf_fka_period.attr, - &device_attr_fcoe_fcf_state.attr, - &device_attr_fcoe_fcf_selected.attr, - &device_attr_fcoe_fcf_vlan_id.attr, - NULL -}; - -static struct attribute_group fcoe_fcf_attr_group = { - .attrs = fcoe_fcf_attrs, -}; - -static const struct attribute_group *fcoe_fcf_attr_groups[] = { - &fcoe_fcf_attr_group, - NULL, -}; - -struct bus_type fcoe_bus_type; - -static int fcoe_bus_match(struct device *dev, - struct device_driver *drv) -{ - if (dev->bus == &fcoe_bus_type) - return 1; - return 0; -} - -/** - * fcoe_ctlr_device_release() - Release the FIP ctlr memory - * @dev: Pointer to the FIP ctlr's embedded device - * - * Called when the last FIP ctlr reference is released. - */ -static void fcoe_ctlr_device_release(struct device *dev) -{ - struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev); - kfree(ctlr); -} - -/** - * fcoe_fcf_device_release() - Release the FIP fcf memory - * @dev: Pointer to the fcf's embedded device - * - * Called when the last FIP fcf reference is released. - */ -static void fcoe_fcf_device_release(struct device *dev) -{ - struct fcoe_fcf_device *fcf = dev_to_fcf(dev); - kfree(fcf); -} - -struct device_type fcoe_ctlr_device_type = { - .name = "fcoe_ctlr", - .groups = fcoe_ctlr_attr_groups, - .release = fcoe_ctlr_device_release, -}; - -struct device_type fcoe_fcf_device_type = { - .name = "fcoe_fcf", - .groups = fcoe_fcf_attr_groups, - .release = fcoe_fcf_device_release, -}; - -struct bus_type fcoe_bus_type = { - .name = "fcoe", - .match = &fcoe_bus_match, -}; - -/** - * fcoe_ctlr_device_flush_work() - Flush a FIP ctlr's workqueue - * @ctlr: Pointer to the FIP ctlr whose workqueue is to be flushed - */ -void fcoe_ctlr_device_flush_work(struct fcoe_ctlr_device *ctlr) -{ - if (!fcoe_ctlr_work_q(ctlr)) { - printk(KERN_ERR - "ERROR: FIP Ctlr '%d' attempted to flush work, " - "when no workqueue created.\n", ctlr->id); - dump_stack(); - return; - } - - flush_workqueue(fcoe_ctlr_work_q(ctlr)); -} - -/** - * fcoe_ctlr_device_queue_work() - Schedule work for a FIP ctlr's workqueue - * @ctlr: Pointer to the FIP ctlr who owns the devloss workqueue - * @work: Work to queue for execution - * - * Return value: - * 1 on success / 0 already queued / < 0 for error - */ -int fcoe_ctlr_device_queue_work(struct fcoe_ctlr_device *ctlr, - struct work_struct *work) -{ - if (unlikely(!fcoe_ctlr_work_q(ctlr))) { - printk(KERN_ERR - "ERROR: FIP Ctlr '%d' attempted to queue work, " - "when no workqueue created.\n", ctlr->id); - dump_stack(); - - return -EINVAL; - } - - return queue_work(fcoe_ctlr_work_q(ctlr), work); -} - -/** - * fcoe_ctlr_device_flush_devloss() - Flush a FIP ctlr's devloss workqueue - * @ctlr: Pointer to FIP ctlr whose workqueue is to be flushed - */ -void fcoe_ctlr_device_flush_devloss(struct fcoe_ctlr_device *ctlr) -{ - if (!fcoe_ctlr_devloss_work_q(ctlr)) { - printk(KERN_ERR - "ERROR: FIP Ctlr '%d' attempted to flush work, " - "when no workqueue created.\n", ctlr->id); - dump_stack(); - return; - } - - flush_workqueue(fcoe_ctlr_devloss_work_q(ctlr)); -} - -/** - * fcoe_ctlr_device_queue_devloss_work() - Schedule work for a FIP ctlr's devloss workqueue - * @ctlr: Pointer to the FIP ctlr who owns the devloss workqueue - * @work: Work to queue for execution - * @delay: jiffies to delay the work queuing - * - * Return value: - * 1 on success / 0 already queued / < 0 for error - */ -int fcoe_ctlr_device_queue_devloss_work(struct fcoe_ctlr_device *ctlr, - struct delayed_work *work, - unsigned long delay) -{ - if (unlikely(!fcoe_ctlr_devloss_work_q(ctlr))) { - printk(KERN_ERR - "ERROR: FIP Ctlr '%d' attempted to queue work, " - "when no workqueue created.\n", ctlr->id); - dump_stack(); - - return -EINVAL; - } - - return queue_delayed_work(fcoe_ctlr_devloss_work_q(ctlr), work, delay); -} - -static int fcoe_fcf_device_match(struct fcoe_fcf_device *new, - struct fcoe_fcf_device *old) -{ - if (new->switch_name == old->switch_name && - new->fabric_name == old->fabric_name && - new->fc_map == old->fc_map && - compare_ether_addr(new->mac, old->mac) == 0) - return 1; - return 0; -} - -/** - * fcoe_ctlr_device_add() - Add a FIP ctlr to sysfs - * @parent: The parent device to which the fcoe_ctlr instance - * should be attached - * @f: The LLD's FCoE sysfs function template pointer - * @priv_size: Size to be allocated with the fcoe_ctlr_device for the LLD - * - * This routine allocates a FIP ctlr object with some additional memory - * for the LLD. The FIP ctlr is initialized, added to sysfs and then - * attributes are added to it. - */ -struct fcoe_ctlr_device *fcoe_ctlr_device_add(struct device *parent, - struct fcoe_sysfs_function_template *f, - int priv_size) -{ - struct fcoe_ctlr_device *ctlr; - int error = 0; - - ctlr = kzalloc(sizeof(struct fcoe_ctlr_device) + priv_size, - GFP_KERNEL); - if (!ctlr) - goto out; - - ctlr->id = atomic_inc_return(&ctlr_num) - 1; - ctlr->f = f; - INIT_LIST_HEAD(&ctlr->fcfs); - mutex_init(&ctlr->lock); - ctlr->dev.parent = parent; - ctlr->dev.bus = &fcoe_bus_type; - ctlr->dev.type = &fcoe_ctlr_device_type; - - ctlr->fcf_dev_loss_tmo = fcoe_fcf_dev_loss_tmo; - - snprintf(ctlr->work_q_name, sizeof(ctlr->work_q_name), - "ctlr_wq_%d", ctlr->id); - ctlr->work_q = create_singlethread_workqueue( - ctlr->work_q_name); - if (!ctlr->work_q) - goto out_del; - - snprintf(ctlr->devloss_work_q_name, - sizeof(ctlr->devloss_work_q_name), - "ctlr_dl_wq_%d", ctlr->id); - ctlr->devloss_work_q = create_singlethread_workqueue( - ctlr->devloss_work_q_name); - if (!ctlr->devloss_work_q) - goto out_del_q; - - dev_set_name(&ctlr->dev, "ctlr_%d", ctlr->id); - error = device_register(&ctlr->dev); - if (error) - goto out_del_q2; - - return ctlr; - -out_del_q2: - destroy_workqueue(ctlr->devloss_work_q); - ctlr->devloss_work_q = NULL; -out_del_q: - destroy_workqueue(ctlr->work_q); - ctlr->work_q = NULL; -out_del: - kfree(ctlr); -out: - return NULL; -} -EXPORT_SYMBOL_GPL(fcoe_ctlr_device_add); - -/** - * fcoe_ctlr_device_delete() - Delete a FIP ctlr and its subtree from sysfs - * @ctlr: A pointer to the ctlr to be deleted - * - * Deletes a FIP ctlr and any fcfs attached - * to it. Deleting fcfs will cause their childen - * to be deleted as well. - * - * The ctlr is detached from sysfs and it's resources - * are freed (work q), but the memory is not freed - * until its last reference is released. - * - * This routine expects no locks to be held before - * calling. - * - * TODO: Currently there are no callbacks to clean up LLD data - * for a fcoe_fcf_device. LLDs must keep this in mind as they need - * to clean up each of their LLD data for all fcoe_fcf_device before - * calling fcoe_ctlr_device_delete. - */ -void fcoe_ctlr_device_delete(struct fcoe_ctlr_device *ctlr) -{ - struct fcoe_fcf_device *fcf, *next; - /* Remove any attached fcfs */ - mutex_lock(&ctlr->lock); - list_for_each_entry_safe(fcf, next, - &ctlr->fcfs, peers) { - list_del(&fcf->peers); - fcf->state = FCOE_FCF_STATE_DELETED; - fcoe_ctlr_device_queue_work(ctlr, &fcf->delete_work); - } - mutex_unlock(&ctlr->lock); - - fcoe_ctlr_device_flush_work(ctlr); - - destroy_workqueue(ctlr->devloss_work_q); - ctlr->devloss_work_q = NULL; - destroy_workqueue(ctlr->work_q); - ctlr->work_q = NULL; - - device_unregister(&ctlr->dev); -} -EXPORT_SYMBOL_GPL(fcoe_ctlr_device_delete); - -/** - * fcoe_fcf_device_final_delete() - Final delete routine - * @work: The FIP fcf's embedded work struct - * - * It is expected that the fcf has been removed from - * the FIP ctlr's list before calling this routine. - */ -static void fcoe_fcf_device_final_delete(struct work_struct *work) -{ - struct fcoe_fcf_device *fcf = - container_of(work, struct fcoe_fcf_device, delete_work); - struct fcoe_ctlr_device *ctlr = fcoe_fcf_dev_to_ctlr_dev(fcf); - - /* - * Cancel any outstanding timers. These should really exist - * only when rmmod'ing the LLDD and we're asking for - * immediate termination of the rports - */ - if (!cancel_delayed_work(&fcf->dev_loss_work)) - fcoe_ctlr_device_flush_devloss(ctlr); - - device_unregister(&fcf->dev); -} - -/** - * fip_timeout_deleted_fcf() - Delete a fcf when the devloss timer fires - * @work: The FIP fcf's embedded work struct - * - * Removes the fcf from the FIP ctlr's list of fcfs and - * queues the final deletion. - */ -static void fip_timeout_deleted_fcf(struct work_struct *work) -{ - struct fcoe_fcf_device *fcf = - container_of(work, struct fcoe_fcf_device, dev_loss_work.work); - struct fcoe_ctlr_device *ctlr = fcoe_fcf_dev_to_ctlr_dev(fcf); - - mutex_lock(&ctlr->lock); - - /* - * If the fcf is deleted or reconnected before the timer - * fires the devloss queue will be flushed, but the state will - * either be CONNECTED or DELETED. If that is the case we - * cancel deleting the fcf. - */ - if (fcf->state != FCOE_FCF_STATE_DISCONNECTED) - goto out; - - dev_printk(KERN_ERR, &fcf->dev, - "FIP fcf connection time out: removing fcf\n"); - - list_del(&fcf->peers); - fcf->state = FCOE_FCF_STATE_DELETED; - fcoe_ctlr_device_queue_work(ctlr, &fcf->delete_work); - -out: - mutex_unlock(&ctlr->lock); -} - -/** - * fcoe_fcf_device_delete() - Delete a FIP fcf - * @fcf: Pointer to the fcf which is to be deleted - * - * Queues the FIP fcf on the devloss workqueue - * - * Expects the ctlr_attrs mutex to be held for fcf - * state change. - */ -void fcoe_fcf_device_delete(struct fcoe_fcf_device *fcf) -{ - struct fcoe_ctlr_device *ctlr = fcoe_fcf_dev_to_ctlr_dev(fcf); - int timeout = fcf->dev_loss_tmo; - - if (fcf->state != FCOE_FCF_STATE_CONNECTED) - return; - - fcf->state = FCOE_FCF_STATE_DISCONNECTED; - - /* - * FCF will only be re-connected by the LLD calling - * fcoe_fcf_device_add, and it should be setting up - * priv then. - */ - fcf->priv = NULL; - - fcoe_ctlr_device_queue_devloss_work(ctlr, &fcf->dev_loss_work, - timeout * HZ); -} -EXPORT_SYMBOL_GPL(fcoe_fcf_device_delete); - -/** - * fcoe_fcf_device_add() - Add a FCoE sysfs fcoe_fcf_device to the system - * @ctlr: The fcoe_ctlr_device that will be the fcoe_fcf_device parent - * @new_fcf: A temporary FCF used for lookups on the current list of fcfs - * - * Expects to be called with the ctlr->lock held - */ -struct fcoe_fcf_device *fcoe_fcf_device_add(struct fcoe_ctlr_device *ctlr, - struct fcoe_fcf_device *new_fcf) -{ - struct fcoe_fcf_device *fcf; - int error = 0; - - list_for_each_entry(fcf, &ctlr->fcfs, peers) { - if (fcoe_fcf_device_match(new_fcf, fcf)) { - if (fcf->state == FCOE_FCF_STATE_CONNECTED) - return fcf; - - fcf->state = FCOE_FCF_STATE_CONNECTED; - - if (!cancel_delayed_work(&fcf->dev_loss_work)) - fcoe_ctlr_device_flush_devloss(ctlr); - - return fcf; - } - } - - fcf = kzalloc(sizeof(struct fcoe_fcf_device), GFP_ATOMIC); - if (unlikely(!fcf)) - goto out; - - INIT_WORK(&fcf->delete_work, fcoe_fcf_device_final_delete); - INIT_DELAYED_WORK(&fcf->dev_loss_work, fip_timeout_deleted_fcf); - - fcf->dev.parent = &ctlr->dev; - fcf->dev.bus = &fcoe_bus_type; - fcf->dev.type = &fcoe_fcf_device_type; - fcf->id = atomic_inc_return(&fcf_num) - 1; - fcf->state = FCOE_FCF_STATE_UNKNOWN; - - fcf->dev_loss_tmo = ctlr->fcf_dev_loss_tmo; - - dev_set_name(&fcf->dev, "fcf_%d", fcf->id); - - fcf->fabric_name = new_fcf->fabric_name; - fcf->switch_name = new_fcf->switch_name; - fcf->fc_map = new_fcf->fc_map; - fcf->vfid = new_fcf->vfid; - memcpy(fcf->mac, new_fcf->mac, ETH_ALEN); - fcf->priority = new_fcf->priority; - fcf->fka_period = new_fcf->fka_period; - fcf->selected = new_fcf->selected; - - error = device_register(&fcf->dev); - if (error) - goto out_del; - - fcf->state = FCOE_FCF_STATE_CONNECTED; - list_add_tail(&fcf->peers, &ctlr->fcfs); - - return fcf; - -out_del: - kfree(fcf); -out: - return NULL; -} -EXPORT_SYMBOL_GPL(fcoe_fcf_device_add); - -int __init fcoe_sysfs_setup(void) -{ - int error; - - atomic_set(&ctlr_num, 0); - atomic_set(&fcf_num, 0); - - error = bus_register(&fcoe_bus_type); - if (error) - return error; - - return 0; -} - -void __exit fcoe_sysfs_teardown(void) -{ - bus_unregister(&fcoe_bus_type); -} diff --git a/trunk/drivers/scsi/fcoe/fcoe_transport.c b/trunk/drivers/scsi/fcoe/fcoe_transport.c index b46f43dced78..710e149d41b6 100644 --- a/trunk/drivers/scsi/fcoe/fcoe_transport.c +++ b/trunk/drivers/scsi/fcoe/fcoe_transport.c @@ -815,17 +815,9 @@ static int fcoe_transport_enable(const char *buffer, struct kernel_param *kp) */ static int __init libfcoe_init(void) { - int rc = 0; - - rc = fcoe_transport_init(); - if (rc) - return rc; + fcoe_transport_init(); - rc = fcoe_sysfs_setup(); - if (rc) - fcoe_transport_exit(); - - return rc; + return 0; } module_init(libfcoe_init); @@ -834,7 +826,6 @@ module_init(libfcoe_init); */ static void __exit libfcoe_exit(void) { - fcoe_sysfs_teardown(); fcoe_transport_exit(); } module_exit(libfcoe_exit); diff --git a/trunk/drivers/scsi/qla2xxx/Kconfig b/trunk/drivers/scsi/qla2xxx/Kconfig index 317a7fdc3b82..6208d562890d 100644 --- a/trunk/drivers/scsi/qla2xxx/Kconfig +++ b/trunk/drivers/scsi/qla2xxx/Kconfig @@ -25,12 +25,3 @@ config SCSI_QLA_FC Firmware images can be retrieved from: ftp://ftp.qlogic.com/outgoing/linux/firmware/ - -config TCM_QLA2XXX - tristate "TCM_QLA2XXX fabric module for Qlogic 2xxx series target mode HBAs" - depends on SCSI_QLA_FC && TARGET_CORE - select LIBFC - select BTREE - default n - ---help--- - Say Y here to enable the TCM_QLA2XXX fabric module for Qlogic 2xxx series target mode HBAs diff --git a/trunk/drivers/scsi/qla2xxx/Makefile b/trunk/drivers/scsi/qla2xxx/Makefile index dce7d788cdc9..5df782f4a097 100644 --- a/trunk/drivers/scsi/qla2xxx/Makefile +++ b/trunk/drivers/scsi/qla2xxx/Makefile @@ -1,6 +1,5 @@ qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \ qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o qla_bsg.o \ - qla_nx.o qla_target.o + qla_nx.o obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o -obj-$(CONFIG_TCM_QLA2XXX) += tcm_qla2xxx.o diff --git a/trunk/drivers/scsi/qla2xxx/qla_attr.c b/trunk/drivers/scsi/qla2xxx/qla_attr.c index 5ab953029f8d..5926f5a87ea8 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_attr.c +++ b/trunk/drivers/scsi/qla2xxx/qla_attr.c @@ -5,7 +5,6 @@ * See LICENSE.qla2xxx for copyright and licensing details. */ #include "qla_def.h" -#include "qla_target.h" #include #include @@ -577,7 +576,6 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj, scsi_block_requests(vha->host); set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); if (IS_QLA82XX(ha)) { - ha->flags.isp82xx_no_md_cap = 1; qla82xx_idc_lock(ha); qla82xx_set_reset_owner(vha); qla82xx_idc_unlock(ha); @@ -587,7 +585,7 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj, scsi_unblock_requests(vha->host); break; case 0x2025d: - if (!IS_QLA81XX(ha) || !IS_QLA8031(ha)) + if (!IS_QLA81XX(ha)) return -EPERM; ql_log(ql_log_info, vha, 0x706f, @@ -1107,8 +1105,9 @@ qla2x00_total_isp_aborts_show(struct device *dev, struct device_attribute *attr, char *buf) { scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + struct qla_hw_data *ha = vha->hw; return snprintf(buf, PAGE_SIZE, "%d\n", - vha->qla_stats.total_isp_aborts); + ha->qla_stats.total_isp_aborts); } static ssize_t @@ -1155,7 +1154,7 @@ qla2x00_phy_version_show(struct device *dev, struct device_attribute *attr, scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); struct qla_hw_data *ha = vha->hw; - if (!IS_QLA81XX(ha) && !IS_QLA8031(ha)) + if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha)) return snprintf(buf, PAGE_SIZE, "\n"); return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d\n", @@ -1538,7 +1537,7 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost) dma_addr_t stats_dma; struct fc_host_statistics *pfc_host_stat; - pfc_host_stat = &vha->fc_host_stat; + pfc_host_stat = &ha->fc_host_stat; memset(pfc_host_stat, -1, sizeof(struct fc_host_statistics)); if (test_bit(UNLOADING, &vha->dpc_flags)) @@ -1581,8 +1580,8 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost) pfc_host_stat->dumped_frames = stats->dumped_frames; pfc_host_stat->nos_count = stats->nos_rcvd; } - pfc_host_stat->fcp_input_megabytes = vha->qla_stats.input_bytes >> 20; - pfc_host_stat->fcp_output_megabytes = vha->qla_stats.output_bytes >> 20; + pfc_host_stat->fcp_input_megabytes = ha->qla_stats.input_bytes >> 20; + pfc_host_stat->fcp_output_megabytes = ha->qla_stats.output_bytes >> 20; done_free: dma_pool_free(ha->s_dma_pool, stats, stats_dma); @@ -1738,7 +1737,6 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) fc_host_supported_speeds(vha->host) = fc_host_supported_speeds(base_vha->host); - qlt_vport_create(vha, ha); qla24xx_vport_disable(fc_vport, disable); if (ha->flags.cpu_affinity_enabled) { @@ -1953,16 +1951,12 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha) fc_host_dev_loss_tmo(vha->host) = ha->port_down_retry_count; fc_host_node_name(vha->host) = wwn_to_u64(vha->node_name); fc_host_port_name(vha->host) = wwn_to_u64(vha->port_name); - fc_host_supported_classes(vha->host) = ha->tgt.enable_class_2 ? - (FC_COS_CLASS2|FC_COS_CLASS3) : FC_COS_CLASS3; + fc_host_supported_classes(vha->host) = FC_COS_CLASS3; fc_host_max_npiv_vports(vha->host) = ha->max_npiv_vports; fc_host_npiv_vports_inuse(vha->host) = ha->cur_vport_count; if (IS_CNA_CAPABLE(ha)) speed = FC_PORTSPEED_10GBIT; - else if (IS_QLA2031(ha)) - speed = FC_PORTSPEED_16GBIT | FC_PORTSPEED_8GBIT | - FC_PORTSPEED_4GBIT; else if (IS_QLA25XX(ha)) speed = FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT; diff --git a/trunk/drivers/scsi/qla2xxx/qla_bsg.c b/trunk/drivers/scsi/qla2xxx/qla_bsg.c index c68883806c54..bc3cc6d91117 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_bsg.c +++ b/trunk/drivers/scsi/qla2xxx/qla_bsg.c @@ -297,6 +297,7 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job) /* Initialize all required fields of fcport */ fcport->vha = vha; + fcport->vp_idx = vha->vp_idx; fcport->d_id.b.al_pa = bsg_job->request->rqst_data.h_els.port_id[0]; fcport->d_id.b.area = @@ -482,6 +483,7 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job) /* Initialize all required fields of fcport */ fcport->vha = vha; + fcport->vp_idx = vha->vp_idx; fcport->d_id.b.al_pa = bsg_job->request->rqst_data.h_ct.port_id[0]; fcport->d_id.b.area = bsg_job->request->rqst_data.h_ct.port_id[1]; fcport->d_id.b.domain = bsg_job->request->rqst_data.h_ct.port_id[2]; @@ -542,7 +544,7 @@ qla81xx_set_internal_loopback(scsi_qla_host_t *vha, uint16_t *config, int rval = 0; struct qla_hw_data *ha = vha->hw; - if (!IS_QLA81XX(ha) && !IS_QLA8031(ha)) + if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha)) goto done_set_internal; new_config[0] = config[0] | (ENABLE_INTERNAL_LOOPBACK << 1); @@ -584,7 +586,7 @@ qla81xx_reset_internal_loopback(scsi_qla_host_t *vha, uint16_t *config, uint16_t new_config[4]; struct qla_hw_data *ha = vha->hw; - if (!IS_QLA81XX(ha) && !IS_QLA8031(ha)) + if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha)) goto done_reset_internal; memset(new_config, 0 , sizeof(new_config)); @@ -708,7 +710,8 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job) elreq.options = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1]; if ((ha->current_topology == ISP_CFG_F || - ((IS_QLA81XX(ha) || IS_QLA8031(ha)) && + (atomic_read(&vha->loop_state) == LOOP_DOWN) || + ((IS_QLA81XX(ha) || IS_QLA83XX(ha)) && le32_to_cpu(*(uint32_t *)req_data) == ELS_OPCODE_BYTE && req_data_len == MAX_ELS_FRAME_PAYLOAD)) && elreq.options == EXTERNAL_LOOPBACK) { @@ -1399,9 +1402,6 @@ qla2x00_update_optrom(struct fc_bsg_job *bsg_job) if (rval) return rval; - /* Set the isp82xx_no_md_cap not to capture minidump */ - ha->flags.isp82xx_no_md_cap = 1; - sg_copy_to_buffer(bsg_job->request_payload.sg_list, bsg_job->request_payload.sg_cnt, ha->optrom_buffer, ha->optrom_region_size); diff --git a/trunk/drivers/scsi/qla2xxx/qla_dbg.c b/trunk/drivers/scsi/qla2xxx/qla_dbg.c index fdee5611f3e2..62324a1d5573 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_dbg.c +++ b/trunk/drivers/scsi/qla2xxx/qla_dbg.c @@ -11,31 +11,27 @@ * ---------------------------------------------------------------------- * | Level | Last Value Used | Holes | * ---------------------------------------------------------------------- - * | Module Init and Probe | 0x0122 | 0x4b,0xba,0xfa | - * | Mailbox commands | 0x1140 | 0x111a-0x111b | - * | | | 0x112c-0x112e | + * | Module Init and Probe | 0x0120 | 0x4b,0xba,0xfa | + * | Mailbox commands | 0x113e | 0x112c-0x112e | * | | | 0x113a | * | Device Discovery | 0x2086 | 0x2020-0x2022 | * | Queue Command and IO tracing | 0x3030 | 0x3006,0x3008 | * | | | 0x302d-0x302e | - * | DPC Thread | 0x401c | 0x4002,0x4013 | - * | Async Events | 0x505f | 0x502b-0x502f | + * | DPC Thread | 0x401c | | + * | Async Events | 0x505d | 0x502b-0x502f | * | | | 0x5047,0x5052 | - * | Timer Routines | 0x6011 | | + * | Timer Routines | 0x6011 | 0x600e-0x600f | * | User Space Interactions | 0x709f | 0x7018,0x702e, | * | | | 0x7039,0x7045, | * | | | 0x7073-0x7075, | * | | | 0x708c | * | Task Management | 0x803c | 0x8025-0x8026 | * | | | 0x800b,0x8039 | - * | AER/EEH | 0x9011 | | + * | AER/EEH | 0x900f | | * | Virtual Port | 0xa007 | | - * | ISP82XX Specific | 0xb054 | 0xb024 | + * | ISP82XX Specific | 0xb054 | 0xb053 | * | MultiQ | 0xc00c | | * | Misc | 0xd010 | | - * | Target Mode | 0xe06f | | - * | Target Mode Management | 0xf071 | | - * | Target Mode Task Management | 0x1000b | | * ---------------------------------------------------------------------- */ @@ -382,54 +378,6 @@ qla25xx_copy_fce(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) return (char *)iter_reg + ntohl(fcec->size); } -static inline void * -qla2xxx_copy_atioqueues(struct qla_hw_data *ha, void *ptr, - uint32_t **last_chain) -{ - struct qla2xxx_mqueue_chain *q; - struct qla2xxx_mqueue_header *qh; - uint32_t num_queues; - int que; - struct { - int length; - void *ring; - } aq, *aqp; - - if (!ha->tgt.atio_q_length) - return ptr; - - num_queues = 1; - aqp = &aq; - aqp->length = ha->tgt.atio_q_length; - aqp->ring = ha->tgt.atio_ring; - - for (que = 0; que < num_queues; que++) { - /* aqp = ha->atio_q_map[que]; */ - q = ptr; - *last_chain = &q->type; - q->type = __constant_htonl(DUMP_CHAIN_QUEUE); - q->chain_size = htonl( - sizeof(struct qla2xxx_mqueue_chain) + - sizeof(struct qla2xxx_mqueue_header) + - (aqp->length * sizeof(request_t))); - ptr += sizeof(struct qla2xxx_mqueue_chain); - - /* Add header. */ - qh = ptr; - qh->queue = __constant_htonl(TYPE_ATIO_QUEUE); - qh->number = htonl(que); - qh->size = htonl(aqp->length * sizeof(request_t)); - ptr += sizeof(struct qla2xxx_mqueue_header); - - /* Add data. */ - memcpy(ptr, aqp->ring, aqp->length * sizeof(request_t)); - - ptr += aqp->length * sizeof(request_t); - } - - return ptr; -} - static inline void * qla25xx_copy_mqueues(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) { @@ -925,8 +873,6 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) struct qla24xx_fw_dump *fw; uint32_t ext_mem_cnt; void *nxt; - void *nxt_chain; - uint32_t *last_chain = NULL; struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); if (IS_QLA82XX(ha)) @@ -1145,16 +1091,6 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) qla24xx_copy_eft(ha, nxt); - nxt_chain = (void *)ha->fw_dump + ha->chain_offset; - nxt_chain = qla2xxx_copy_atioqueues(ha, nxt_chain, &last_chain); - if (last_chain) { - ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT); - *last_chain |= __constant_htonl(DUMP_CHAIN_LAST); - } - - /* Adjust valid length. */ - ha->fw_dump_len = (nxt_chain - (void *)ha->fw_dump); - qla24xx_fw_dump_failed_0: qla2xxx_dump_post_process(base_vha, rval); @@ -1463,7 +1399,6 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) /* Chain entries -- started with MQ. */ nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain); nxt_chain = qla25xx_copy_mqueues(ha, nxt_chain, &last_chain); - nxt_chain = qla2xxx_copy_atioqueues(ha, nxt_chain, &last_chain); if (last_chain) { ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT); *last_chain |= __constant_htonl(DUMP_CHAIN_LAST); @@ -1782,7 +1717,6 @@ qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) /* Chain entries -- started with MQ. */ nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain); nxt_chain = qla25xx_copy_mqueues(ha, nxt_chain, &last_chain); - nxt_chain = qla2xxx_copy_atioqueues(ha, nxt_chain, &last_chain); if (last_chain) { ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT); *last_chain |= __constant_htonl(DUMP_CHAIN_LAST); @@ -2284,7 +2218,6 @@ qla83xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) /* Chain entries -- started with MQ. */ nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain); nxt_chain = qla25xx_copy_mqueues(ha, nxt_chain, &last_chain); - nxt_chain = qla2xxx_copy_atioqueues(ha, nxt_chain, &last_chain); if (last_chain) { ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT); *last_chain |= __constant_htonl(DUMP_CHAIN_LAST); diff --git a/trunk/drivers/scsi/qla2xxx/qla_dbg.h b/trunk/drivers/scsi/qla2xxx/qla_dbg.h index f278df8cce0f..2157bdf1569a 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_dbg.h +++ b/trunk/drivers/scsi/qla2xxx/qla_dbg.h @@ -244,7 +244,6 @@ struct qla2xxx_mqueue_header { uint32_t queue; #define TYPE_REQUEST_QUEUE 0x1 #define TYPE_RESPONSE_QUEUE 0x2 -#define TYPE_ATIO_QUEUE 0x3 uint32_t number; uint32_t size; }; @@ -340,11 +339,3 @@ ql_log_pci(uint32_t, struct pci_dev *pdev, int32_t, const char *fmt, ...); #define ql_dbg_misc 0x00010000 /* For dumping everything that is not * not covered by upper categories */ -#define ql_dbg_verbose 0x00008000 /* More verbosity for each level - * This is to be used with other levels where - * more verbosity is required. It might not - * be applicable to all the levels. - */ -#define ql_dbg_tgt 0x00004000 /* Target mode */ -#define ql_dbg_tgt_mgt 0x00002000 /* Target mode management */ -#define ql_dbg_tgt_tmr 0x00001000 /* Target mode task management */ diff --git a/trunk/drivers/scsi/qla2xxx/qla_def.h b/trunk/drivers/scsi/qla2xxx/qla_def.h index 39007f53aec0..a2443031dbe7 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_def.h +++ b/trunk/drivers/scsi/qla2xxx/qla_def.h @@ -186,7 +186,6 @@ #define RESPONSE_ENTRY_CNT_2100 64 /* Number of response entries.*/ #define RESPONSE_ENTRY_CNT_2300 512 /* Number of response entries.*/ #define RESPONSE_ENTRY_CNT_MQ 128 /* Number of response entries.*/ -#define ATIO_ENTRY_CNT_24XX 4096 /* Number of ATIO entries. */ struct req_que; @@ -1235,27 +1234,11 @@ typedef struct { * ISP queue - response queue entry definition. */ typedef struct { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - uint32_t handle; /* System defined handle */ - uint8_t data[52]; + uint8_t data[60]; uint32_t signature; #define RESPONSE_PROCESSED 0xDEADDEAD /* Signature */ } response_t; -/* - * ISP queue - ATIO queue entry definition. - */ -struct atio { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t data[58]; - uint32_t signature; -#define ATIO_PROCESSED 0xDEADDEAD /* Signature */ -}; - typedef union { uint16_t extended; struct { @@ -1736,13 +1719,11 @@ typedef struct fc_port { struct fc_rport *rport, *drport; u32 supported_classes; + uint16_t vp_idx; uint8_t fc4_type; uint8_t scan_state; } fc_port_t; -#define QLA_FCPORT_SCAN_NONE 0 -#define QLA_FCPORT_SCAN_FOUND 1 - /* * Fibre channel port/lun states. */ @@ -1766,7 +1747,6 @@ static const char * const port_state_str[] = { #define FCF_LOGIN_NEEDED BIT_1 #define FCF_FCP2_DEVICE BIT_2 #define FCF_ASYNC_SENT BIT_3 -#define FCF_CONF_COMP_SUPPORTED BIT_4 /* No loop ID flag. */ #define FC_NO_LOOP_ID 0x1000 @@ -2439,40 +2419,6 @@ struct qlfc_fw { uint32_t len; }; -struct qlt_hw_data { - /* Protected by hw lock */ - uint32_t enable_class_2:1; - uint32_t enable_explicit_conf:1; - uint32_t ini_mode_force_reverse:1; - uint32_t node_name_set:1; - - dma_addr_t atio_dma; /* Physical address. */ - struct atio *atio_ring; /* Base virtual address */ - struct atio *atio_ring_ptr; /* Current address. */ - uint16_t atio_ring_index; /* Current index. */ - uint16_t atio_q_length; - - void *target_lport_ptr; - struct qla_tgt_func_tmpl *tgt_ops; - struct qla_tgt *qla_tgt; - struct qla_tgt_cmd *cmds[MAX_OUTSTANDING_COMMANDS]; - uint16_t current_handle; - - struct qla_tgt_vp_map *tgt_vp_map; - struct mutex tgt_mutex; - struct mutex tgt_host_action_mutex; - - int saved_set; - uint16_t saved_exchange_count; - uint32_t saved_firmware_options_1; - uint32_t saved_firmware_options_2; - uint32_t saved_firmware_options_3; - uint8_t saved_firmware_options[2]; - uint8_t saved_add_firmware_options[2]; - - uint8_t tgt_node_name[WWN_SIZE]; -}; - /* * Qlogic host adapter specific data structure. */ @@ -2514,9 +2460,7 @@ struct qla_hw_data { uint32_t thermal_supported:1; uint32_t isp82xx_reset_hdlr_active:1; uint32_t isp82xx_reset_owner:1; - uint32_t isp82xx_no_md_cap:1; - uint32_t host_shutting_down:1; - /* 30 bits */ + /* 28 bits */ } flags; /* This spinlock is used to protect "io transactions", you must @@ -2860,6 +2804,7 @@ struct qla_hw_data { /* ISP2322: red, green, amber. */ uint16_t zio_mode; uint16_t zio_timer; + struct fc_host_statistics fc_host_stat; struct qla_msix_entry *msix_entries; @@ -2872,6 +2817,7 @@ struct qla_hw_data { int cur_vport_count; struct qla_chip_state_84xx *cs84xx; + struct qla_statistics qla_stats; struct isp_operations *isp_ops; struct workqueue_struct *wq; struct qlfc_fw fw_buf; @@ -2917,8 +2863,6 @@ struct qla_hw_data { dma_addr_t md_tmplt_hdr_dma; void *md_dump; uint32_t md_dump_size; - - struct qlt_hw_data tgt; }; /* @@ -2976,7 +2920,6 @@ typedef struct scsi_qla_host { #define FCOE_CTX_RESET_NEEDED 18 /* Initiate FCoE context reset */ #define MPI_RESET_NEEDED 19 /* Initiate MPI FW reset */ #define ISP_QUIESCE_NEEDED 20 /* Driver need some quiescence */ -#define SCR_PENDING 21 /* SCR in target mode */ uint32_t device_flags; #define SWITCH_FOUND BIT_0 @@ -3036,21 +2979,10 @@ typedef struct scsi_qla_host { struct req_que *req; int fw_heartbeat_counter; int seconds_since_last_heartbeat; - struct fc_host_statistics fc_host_stat; - struct qla_statistics qla_stats; atomic_t vref_count; } scsi_qla_host_t; -#define SET_VP_IDX 1 -#define SET_AL_PA 2 -#define RESET_VP_IDX 3 -#define RESET_AL_PA 4 -struct qla_tgt_vp_map { - uint8_t idx; - scsi_qla_host_t *vha; -}; - /* * Macros to help code, maintain, etc. */ diff --git a/trunk/drivers/scsi/qla2xxx/qla_gbl.h b/trunk/drivers/scsi/qla2xxx/qla_gbl.h index 9eacd2df111b..9f065804bd12 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_gbl.h +++ b/trunk/drivers/scsi/qla2xxx/qla_gbl.h @@ -175,7 +175,6 @@ extern int qla2x00_vp_abort_isp(scsi_qla_host_t *); /* * Global Function Prototypes in qla_iocb.c source file. */ - extern uint16_t qla2x00_calc_iocbs_32(uint16_t); extern uint16_t qla2x00_calc_iocbs_64(uint16_t); extern void qla2x00_build_scsi_iocbs_32(srb_t *, cmd_entry_t *, uint16_t); @@ -189,8 +188,6 @@ extern uint16_t qla24xx_calc_iocbs(scsi_qla_host_t *, uint16_t); extern void qla24xx_build_scsi_iocbs(srb_t *, struct cmd_type_7 *, uint16_t); extern int qla24xx_dif_start_scsi(srb_t *); -extern void *qla2x00_alloc_iocbs(scsi_qla_host_t *, srb_t *); -extern int qla2x00_issue_marker(scsi_qla_host_t *, int); /* * Global Function Prototypes in qla_mbx.c source file. @@ -241,9 +238,6 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *, uint8_t *, uint8_t *, uint16_t *); extern int qla2x00_init_firmware(scsi_qla_host_t *, uint16_t); -extern int -qla2x00_get_node_name_list(scsi_qla_host_t *, void **, int *); - extern int qla2x00_get_port_database(scsi_qla_host_t *, fc_port_t *, uint8_t); @@ -389,8 +383,6 @@ extern int qla2x00_request_irqs(struct qla_hw_data *, struct rsp_que *); extern void qla2x00_free_irqs(scsi_qla_host_t *); extern int qla2x00_get_data_rate(scsi_qla_host_t *); -extern char *qla2x00_get_link_speed_str(struct qla_hw_data *); - /* * Global Function Prototypes in qla_sup.c source file. */ @@ -554,7 +546,6 @@ extern void qla2x00_sp_free(void *, void *); extern void qla2x00_sp_timeout(unsigned long); extern void qla2x00_bsg_job_done(void *, void *, int); extern void qla2x00_bsg_sp_free(void *, void *); -extern void qla2x00_start_iocbs(struct scsi_qla_host *, struct req_que *); /* Interrupt related */ extern irqreturn_t qla82xx_intr_handler(int, void *); diff --git a/trunk/drivers/scsi/qla2xxx/qla_gs.c b/trunk/drivers/scsi/qla2xxx/qla_gs.c index 05260d25fe46..3128f80441f5 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_gs.c +++ b/trunk/drivers/scsi/qla2xxx/qla_gs.c @@ -5,7 +5,6 @@ * See LICENSE.qla2xxx for copyright and licensing details. */ #include "qla_def.h" -#include "qla_target.h" static int qla2x00_sns_ga_nxt(scsi_qla_host_t *, fc_port_t *); static int qla2x00_sns_gid_pt(scsi_qla_host_t *, sw_info_t *); @@ -557,8 +556,7 @@ qla2x00_rff_id(scsi_qla_host_t *vha) ct_req->req.rff_id.port_id[1] = vha->d_id.b.area; ct_req->req.rff_id.port_id[2] = vha->d_id.b.al_pa; - qlt_rff_id(vha, ct_req); - + ct_req->req.rff_id.fc4_feature = BIT_1; ct_req->req.rff_id.fc4_type = 0x08; /* SCSI - FCP */ /* Execute MS IOCB */ diff --git a/trunk/drivers/scsi/qla2xxx/qla_init.c b/trunk/drivers/scsi/qla2xxx/qla_init.c index ca5084743135..b9465643396b 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_init.c +++ b/trunk/drivers/scsi/qla2xxx/qla_init.c @@ -17,9 +17,6 @@ #include #endif -#include -#include "qla_target.h" - /* * QLogic ISP2x00 Hardware Support Function Prototypes. */ @@ -521,10 +518,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) return QLA_FUNCTION_FAILED; } } - - if (qla_ini_mode_enabled(vha)) - rval = qla2x00_init_rings(vha); - + rval = qla2x00_init_rings(vha); ha->flags.chip_reset_done = 1; if (rval == QLA_SUCCESS && IS_QLA84XX(ha)) { @@ -1239,8 +1233,6 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) mq_size += ha->max_rsp_queues * (rsp->length * sizeof(response_t)); } - if (ha->tgt.atio_q_length) - mq_size += ha->tgt.atio_q_length * sizeof(request_t); /* Allocate memory for Fibre Channel Event Buffer. */ if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha)) goto try_eft; @@ -1704,12 +1696,6 @@ qla24xx_config_rings(struct scsi_qla_host *vha) icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma)); icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma)); - /* Setup ATIO queue dma pointers for target mode */ - icb->atio_q_inpointer = __constant_cpu_to_le16(0); - icb->atio_q_length = cpu_to_le16(ha->tgt.atio_q_length); - icb->atio_q_address[0] = cpu_to_le32(LSD(ha->tgt.atio_dma)); - icb->atio_q_address[1] = cpu_to_le32(MSD(ha->tgt.atio_dma)); - if (ha->mqenable || IS_QLA83XX(ha)) { icb->qos = __constant_cpu_to_le16(QLA_DEFAULT_QUE_QOS); icb->rid = __constant_cpu_to_le16(rid); @@ -1753,8 +1739,6 @@ qla24xx_config_rings(struct scsi_qla_host *vha) WRT_REG_DWORD(®->isp24.rsp_q_in, 0); WRT_REG_DWORD(®->isp24.rsp_q_out, 0); } - qlt_24xx_config_rings(vha, reg); - /* PCI posting */ RD_REG_DWORD(&ioreg->hccr); } @@ -1810,11 +1794,6 @@ qla2x00_init_rings(scsi_qla_host_t *vha) spin_unlock(&ha->vport_slock); - ha->tgt.atio_ring_ptr = ha->tgt.atio_ring; - ha->tgt.atio_ring_index = 0; - /* Initialize ATIO queue entries */ - qlt_init_atio_q_entries(vha); - ha->isp_ops->config_rings(vha); spin_unlock_irqrestore(&ha->hardware_lock, flags); @@ -2072,10 +2051,6 @@ qla2x00_configure_hba(scsi_qla_host_t *vha) vha->d_id.b.area = area; vha->d_id.b.al_pa = al_pa; - spin_lock(&ha->vport_slock); - qlt_update_vp_map(vha, SET_AL_PA); - spin_unlock(&ha->vport_slock); - if (!vha->flags.init_done) ql_log(ql_log_info, vha, 0x2010, "Topology - %s, Host Loop address 0x%x.\n", @@ -2210,7 +2185,7 @@ qla2x00_nvram_config(scsi_qla_host_t *vha) nv->id[2] != 'P' || nv->id[3] != ' ' || nv->nvram_version < 1) { /* Reset NVRAM data. */ ql_log(ql_log_warn, vha, 0x0064, - "Inconsistent NVRAM " + "Inconisistent NVRAM " "detected: checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0], nv->nvram_version); ql_log(ql_log_warn, vha, 0x0065, @@ -2295,7 +2270,7 @@ qla2x00_nvram_config(scsi_qla_host_t *vha) if (IS_QLA23XX(ha)) { nv->firmware_options[0] |= BIT_2; nv->firmware_options[0] &= ~BIT_3; - nv->special_options[0] &= ~BIT_6; + nv->firmware_options[0] &= ~BIT_6; nv->add_firmware_options[1] |= BIT_5 | BIT_4; if (IS_QLA2300(ha)) { @@ -2492,21 +2467,14 @@ qla2x00_rport_del(void *data) { fc_port_t *fcport = data; struct fc_rport *rport; - scsi_qla_host_t *vha = fcport->vha; unsigned long flags; spin_lock_irqsave(fcport->vha->host->host_lock, flags); rport = fcport->drport ? fcport->drport: fcport->rport; fcport->drport = NULL; spin_unlock_irqrestore(fcport->vha->host->host_lock, flags); - if (rport) { + if (rport) fc_remote_port_delete(rport); - /* - * Release the target mode FC NEXUS in qla_target.c code - * if target mod is enabled. - */ - qlt_fc_port_deleted(vha, fcport); - } } /** @@ -2527,11 +2495,11 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags) /* Setup fcport template structure. */ fcport->vha = vha; + fcport->vp_idx = vha->vp_idx; fcport->port_type = FCT_UNKNOWN; fcport->loop_id = FC_NO_LOOP_ID; qla2x00_set_fcport_state(fcport, FCS_UNCONFIGURED); fcport->supported_classes = FC_COS_UNSPECIFIED; - fcport->scan_state = QLA_FCPORT_SCAN_NONE; return fcport; } @@ -2758,6 +2726,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) new_fcport->d_id.b.area = area; new_fcport->d_id.b.al_pa = al_pa; new_fcport->loop_id = loop_id; + new_fcport->vp_idx = vha->vp_idx; rval2 = qla2x00_get_port_database(vha, new_fcport, 0); if (rval2 != QLA_SUCCESS) { ql_dbg(ql_dbg_disc, vha, 0x201a, @@ -2791,6 +2760,10 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) if (!found) { /* New device, add to fcports list. */ + if (vha->vp_idx) { + new_fcport->vha = vha; + new_fcport->vp_idx = vha->vp_idx; + } list_add_tail(&new_fcport->list, &vha->vp_fcports); /* Allocate a new replacement fcport. */ @@ -2827,6 +2800,8 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) static void qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) { +#define LS_UNKNOWN 2 + static char *link_speeds[] = { "1", "2", "?", "4", "8", "10" }; char *link_speed; int rval; uint16_t mb[4]; @@ -2854,7 +2829,11 @@ qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) fcport->port_name[6], fcport->port_name[7], rval, fcport->fp_speed, mb[0], mb[1]); } else { - link_speed = qla2x00_get_link_speed_str(ha); + link_speed = link_speeds[LS_UNKNOWN]; + if (fcport->fp_speed < 5) + link_speed = link_speeds[fcport->fp_speed]; + else if (fcport->fp_speed == 0x13) + link_speed = link_speeds[5]; ql_dbg(ql_dbg_disc, vha, 0x2005, "iIDMA adjusted to %s GB/s " "on %02x%02x%02x%02x%02x%02x%02x%02x.\n", link_speed, @@ -2885,12 +2864,6 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport) "Unable to allocate fc remote port.\n"); return; } - /* - * Create target mode FC NEXUS in qla_target.c if target mode is - * enabled.. - */ - qlt_fc_port_added(vha, fcport); - spin_lock_irqsave(fcport->vha->host->host_lock, flags); *((fc_port_t **)rport->dd_data) = fcport; spin_unlock_irqrestore(fcport->vha->host->host_lock, flags); @@ -2948,7 +2921,7 @@ static int qla2x00_configure_fabric(scsi_qla_host_t *vha) { int rval; - fc_port_t *fcport; + fc_port_t *fcport, *fcptemp; uint16_t next_loopid; uint16_t mb[MAILBOX_REGISTER_COUNT]; uint16_t loop_id; @@ -2986,7 +2959,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha) 0xfc, mb, BIT_1|BIT_0); if (rval != QLA_SUCCESS) { set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); - break; + return rval; } if (mb[0] != MBS_COMMAND_COMPLETE) { ql_dbg(ql_dbg_disc, vha, 0x2042, @@ -3018,16 +2991,21 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha) } } +#define QLA_FCPORT_SCAN 1 +#define QLA_FCPORT_FOUND 2 + + list_for_each_entry(fcport, &vha->vp_fcports, list) { + fcport->scan_state = QLA_FCPORT_SCAN; + } + rval = qla2x00_find_all_fabric_devs(vha, &new_fcports); if (rval != QLA_SUCCESS) break; - /* Add new ports to existing port list */ - list_splice_tail_init(&new_fcports, &vha->vp_fcports); - - /* Starting free loop ID. */ - next_loopid = ha->min_external_loopid; - + /* + * Logout all previous fabric devices marked lost, except + * FCP2 devices. + */ list_for_each_entry(fcport, &vha->vp_fcports, list) { if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) break; @@ -3035,8 +3013,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha) if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) continue; - /* Logout lost/gone fabric devices (non-FCP2) */ - if (fcport->scan_state != QLA_FCPORT_SCAN_FOUND && + if (fcport->scan_state == QLA_FCPORT_SCAN && atomic_read(&fcport->state) == FCS_ONLINE) { qla2x00_mark_device_lost(vha, fcport, ql2xplogiabsentdevice, 0); @@ -3049,30 +3026,78 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha) fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa); + fcport->loop_id = FC_NO_LOOP_ID; } - continue; } - fcport->scan_state = QLA_FCPORT_SCAN_NONE; - - /* Login fabric devices that need a login */ - if ((fcport->flags & FCF_LOGIN_NEEDED) != 0 && - atomic_read(&vha->loop_down_timer) == 0) { - if (fcport->loop_id == FC_NO_LOOP_ID) { - fcport->loop_id = next_loopid; - rval = qla2x00_find_new_loop_id( - base_vha, fcport); - if (rval != QLA_SUCCESS) { - /* Ran out of IDs to use */ - continue; - } + } + + /* Starting free loop ID. */ + next_loopid = ha->min_external_loopid; + + /* + * Scan through our port list and login entries that need to be + * logged in. + */ + list_for_each_entry(fcport, &vha->vp_fcports, list) { + if (atomic_read(&vha->loop_down_timer) || + test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) + break; + + if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 || + (fcport->flags & FCF_LOGIN_NEEDED) == 0) + continue; + + if (fcport->loop_id == FC_NO_LOOP_ID) { + fcport->loop_id = next_loopid; + rval = qla2x00_find_new_loop_id( + base_vha, fcport); + if (rval != QLA_SUCCESS) { + /* Ran out of IDs to use */ + break; } } + /* Login and update database */ + qla2x00_fabric_dev_login(vha, fcport, &next_loopid); + } + + /* Exit if out of loop IDs. */ + if (rval != QLA_SUCCESS) { + break; + } + + /* + * Login and add the new devices to our port list. + */ + list_for_each_entry_safe(fcport, fcptemp, &new_fcports, list) { + if (atomic_read(&vha->loop_down_timer) || + test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) + break; + + /* Find a new loop ID to use. */ + fcport->loop_id = next_loopid; + rval = qla2x00_find_new_loop_id(base_vha, fcport); + if (rval != QLA_SUCCESS) { + /* Ran out of IDs to use */ + break; + } /* Login and update database */ qla2x00_fabric_dev_login(vha, fcport, &next_loopid); + + if (vha->vp_idx) { + fcport->vha = vha; + fcport->vp_idx = vha->vp_idx; + } + list_move_tail(&fcport->list, &vha->vp_fcports); } } while (0); + /* Free all new device structures not processed. */ + list_for_each_entry_safe(fcport, fcptemp, &new_fcports, list) { + list_del(&fcport->list); + kfree(fcport); + } + if (rval) { ql_dbg(ql_dbg_disc, vha, 0x2068, "Configure fabric error exit rval=%d.\n", rval); @@ -3262,7 +3287,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha, WWN_SIZE)) continue; - fcport->scan_state = QLA_FCPORT_SCAN_FOUND; + fcport->scan_state = QLA_FCPORT_FOUND; found++; @@ -3570,12 +3595,6 @@ qla2x00_fabric_login(scsi_qla_host_t *vha, fc_port_t *fcport, if (mb[10] & BIT_1) fcport->supported_classes |= FC_COS_CLASS3; - if (IS_FWI2_CAPABLE(ha)) { - if (mb[10] & BIT_7) - fcport->flags |= - FCF_CONF_COMP_SUPPORTED; - } - rval = QLA_SUCCESS; break; } else if (mb[0] == MBS_LOOP_ID_USED) { @@ -3822,7 +3841,7 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) vha->flags.online = 0; ha->flags.chip_reset_done = 0; clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - vha->qla_stats.total_isp_aborts++; + ha->qla_stats.total_isp_aborts++; ql_log(ql_log_info, vha, 0x00af, "Performing ISP error recovery - ha=%p.\n", ha); @@ -4047,7 +4066,6 @@ qla2x00_restart_isp(scsi_qla_host_t *vha) struct qla_hw_data *ha = vha->hw; struct req_que *req = ha->req_q_map[0]; struct rsp_que *rsp = ha->rsp_q_map[0]; - unsigned long flags; /* If firmware needs to be loaded */ if (qla2x00_isp_firmware(vha)) { @@ -4072,16 +4090,6 @@ qla2x00_restart_isp(scsi_qla_host_t *vha) qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL); vha->flags.online = 1; - - /* - * Process any ATIO queue entries that came in - * while we weren't online. - */ - spin_lock_irqsave(&ha->hardware_lock, flags); - if (qla_tgt_mode_enabled(vha)) - qlt_24xx_process_atio_queue(vha); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - /* Wait at most MAX_TARGET RSCNs for a stable link. */ wait_time = 256; do { @@ -4271,7 +4279,7 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) { /* Reset NVRAM data. */ ql_log(ql_log_warn, vha, 0x006b, - "Inconsistent NVRAM detected: checksum=0x%x id=%c " + "Inconisistent NVRAM detected: checksum=0x%x id=%c " "version=0x%x.\n", chksum, nv->id[0], nv->nvram_version); ql_log(ql_log_warn, vha, 0x006c, "Falling back to functioning (yet invalid -- WWPN) " @@ -4322,15 +4330,6 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) rval = 1; } - if (!qla_ini_mode_enabled(vha)) { - /* Don't enable full login after initial LIP */ - nv->firmware_options_1 &= __constant_cpu_to_le32(~BIT_13); - /* Don't enable LIP full login for initiator */ - nv->host_p &= __constant_cpu_to_le32(~BIT_10); - } - - qlt_24xx_config_nvram_stage1(vha, nv); - /* Reset Initialization control block */ memset(icb, 0, ha->init_cb_size); @@ -4358,10 +4357,8 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) qla2x00_set_model_info(vha, nv->model_name, sizeof(nv->model_name), "QLA2462"); - qlt_24xx_config_nvram_stage2(vha, icb); - + /* Use alternate WWN? */ if (nv->host_p & __constant_cpu_to_le32(BIT_15)) { - /* Use alternate WWN? */ memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE); memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE); } @@ -5032,7 +5029,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) { /* Reset NVRAM data. */ ql_log(ql_log_info, vha, 0x0073, - "Inconsistent NVRAM detected: checksum=0x%x id=%c " + "Inconisistent NVRAM detected: checksum=0x%x id=%c " "version=0x%x.\n", chksum, nv->id[0], le16_to_cpu(nv->nvram_version)); ql_log(ql_log_info, vha, 0x0074, diff --git a/trunk/drivers/scsi/qla2xxx/qla_iocb.c b/trunk/drivers/scsi/qla2xxx/qla_iocb.c index 70dbf53d9e0f..eac950924497 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_iocb.c +++ b/trunk/drivers/scsi/qla2xxx/qla_iocb.c @@ -5,7 +5,6 @@ * See LICENSE.qla2xxx for copyright and licensing details. */ #include "qla_def.h" -#include "qla_target.h" #include #include @@ -24,17 +23,18 @@ qla2x00_get_cmd_direction(srb_t *sp) { uint16_t cflags; struct scsi_cmnd *cmd = GET_CMD_SP(sp); - struct scsi_qla_host *vha = sp->fcport->vha; cflags = 0; /* Set transfer direction */ if (cmd->sc_data_direction == DMA_TO_DEVICE) { cflags = CF_WRITE; - vha->qla_stats.output_bytes += scsi_bufflen(cmd); + sp->fcport->vha->hw->qla_stats.output_bytes += + scsi_bufflen(cmd); } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { cflags = CF_READ; - vha->qla_stats.input_bytes += scsi_bufflen(cmd); + sp->fcport->vha->hw->qla_stats.input_bytes += + scsi_bufflen(cmd); } return (cflags); } @@ -385,10 +385,9 @@ qla2x00_start_scsi(srb_t *sp) else req->cnt = req->length - (req->ring_index - cnt); - /* If still no head room then bail out */ - if (req->cnt < (req_cnt + 2)) - goto queuing_error; } + if (req->cnt < (req_cnt + 2)) + goto queuing_error; /* Build command packet */ req->current_outstanding_cmd = handle; @@ -471,7 +470,7 @@ qla2x00_start_scsi(srb_t *sp) /** * qla2x00_start_iocbs() - Execute the IOCB command */ -void +static void qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req) { struct qla_hw_data *ha = vha->hw; @@ -572,29 +571,6 @@ qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req, return (ret); } -/* - * qla2x00_issue_marker - * - * Issue marker - * Caller CAN have hardware lock held as specified by ha_locked parameter. - * Might release it, then reaquire. - */ -int qla2x00_issue_marker(scsi_qla_host_t *vha, int ha_locked) -{ - if (ha_locked) { - if (__qla2x00_marker(vha, vha->req, vha->req->rsp, 0, 0, - MK_SYNC_ALL) != QLA_SUCCESS) - return QLA_FUNCTION_FAILED; - } else { - if (qla2x00_marker(vha, vha->req, vha->req->rsp, 0, 0, - MK_SYNC_ALL) != QLA_SUCCESS) - return QLA_FUNCTION_FAILED; - } - vha->marker_needed = 0; - - return QLA_SUCCESS; -} - /** * qla24xx_calc_iocbs() - Determine number of Command Type 3 and * Continuation Type 1 IOCBs to allocate. @@ -653,11 +629,11 @@ qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt, if (cmd->sc_data_direction == DMA_TO_DEVICE) { cmd_pkt->control_flags = __constant_cpu_to_le16(CF_WRITE_DATA); - vha->qla_stats.output_bytes += scsi_bufflen(cmd); + ha->qla_stats.output_bytes += scsi_bufflen(cmd); } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { cmd_pkt->control_flags = __constant_cpu_to_le16(CF_READ_DATA); - vha->qla_stats.input_bytes += scsi_bufflen(cmd); + ha->qla_stats.input_bytes += scsi_bufflen(cmd); } cur_seg = scsi_sglist(cmd); @@ -769,11 +745,13 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, if (cmd->sc_data_direction == DMA_TO_DEVICE) { cmd_pkt->task_mgmt_flags = __constant_cpu_to_le16(TMF_WRITE_DATA); - vha->qla_stats.output_bytes += scsi_bufflen(cmd); + sp->fcport->vha->hw->qla_stats.output_bytes += + scsi_bufflen(cmd); } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { cmd_pkt->task_mgmt_flags = __constant_cpu_to_le16(TMF_READ_DATA); - vha->qla_stats.input_bytes += scsi_bufflen(cmd); + sp->fcport->vha->hw->qla_stats.input_bytes += + scsi_bufflen(cmd); } /* One DSD is available in the Command Type 3 IOCB */ @@ -1267,7 +1245,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, return QLA_SUCCESS; } - cmd_pkt->vp_index = sp->fcport->vha->vp_idx; + cmd_pkt->vp_index = sp->fcport->vp_idx; /* Set transfer direction */ if (cmd->sc_data_direction == DMA_TO_DEVICE) { @@ -1524,9 +1502,9 @@ qla24xx_start_scsi(srb_t *sp) else req->cnt = req->length - (req->ring_index - cnt); - if (req->cnt < (req_cnt + 2)) - goto queuing_error; } + if (req->cnt < (req_cnt + 2)) + goto queuing_error; /* Build command packet. */ req->current_outstanding_cmd = handle; @@ -1549,7 +1527,7 @@ qla24xx_start_scsi(srb_t *sp) cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; - cmd_pkt->vp_index = sp->fcport->vha->vp_idx; + cmd_pkt->vp_index = sp->fcport->vp_idx; int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); @@ -1739,10 +1717,11 @@ qla24xx_dif_start_scsi(srb_t *sp) else req->cnt = req->length - (req->ring_index - cnt); - if (req->cnt < (req_cnt + 2)) - goto queuing_error; } + if (req->cnt < (req_cnt + 2)) + goto queuing_error; + status |= QDSS_GOT_Q_SPACE; /* Build header part of command packet (excluding the OPCODE). */ @@ -1919,7 +1898,7 @@ qla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio) logio->port_id[0] = sp->fcport->d_id.b.al_pa; logio->port_id[1] = sp->fcport->d_id.b.area; logio->port_id[2] = sp->fcport->d_id.b.domain; - logio->vp_index = sp->fcport->vha->vp_idx; + logio->vp_index = sp->fcport->vp_idx; } static void @@ -1943,7 +1922,7 @@ qla2x00_login_iocb(srb_t *sp, struct mbx_entry *mbx) mbx->mb2 = cpu_to_le16(sp->fcport->d_id.b.domain); mbx->mb3 = cpu_to_le16(sp->fcport->d_id.b.area << 8 | sp->fcport->d_id.b.al_pa); - mbx->mb9 = cpu_to_le16(sp->fcport->vha->vp_idx); + mbx->mb9 = cpu_to_le16(sp->fcport->vp_idx); } static void @@ -1956,7 +1935,7 @@ qla24xx_logout_iocb(srb_t *sp, struct logio_entry_24xx *logio) logio->port_id[0] = sp->fcport->d_id.b.al_pa; logio->port_id[1] = sp->fcport->d_id.b.area; logio->port_id[2] = sp->fcport->d_id.b.domain; - logio->vp_index = sp->fcport->vha->vp_idx; + logio->vp_index = sp->fcport->vp_idx; } static void @@ -1973,7 +1952,7 @@ qla2x00_logout_iocb(srb_t *sp, struct mbx_entry *mbx) mbx->mb2 = cpu_to_le16(sp->fcport->d_id.b.domain); mbx->mb3 = cpu_to_le16(sp->fcport->d_id.b.area << 8 | sp->fcport->d_id.b.al_pa); - mbx->mb9 = cpu_to_le16(sp->fcport->vha->vp_idx); + mbx->mb9 = cpu_to_le16(sp->fcport->vp_idx); /* Implicit: mbx->mbx10 = 0. */ } @@ -1983,7 +1962,7 @@ qla24xx_adisc_iocb(srb_t *sp, struct logio_entry_24xx *logio) logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; logio->control_flags = cpu_to_le16(LCF_COMMAND_ADISC); logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); - logio->vp_index = sp->fcport->vha->vp_idx; + logio->vp_index = sp->fcport->vp_idx; } static void @@ -2004,7 +1983,7 @@ qla2x00_adisc_iocb(srb_t *sp, struct mbx_entry *mbx) mbx->mb3 = cpu_to_le16(LSW(ha->async_pd_dma)); mbx->mb6 = cpu_to_le16(MSW(MSD(ha->async_pd_dma))); mbx->mb7 = cpu_to_le16(LSW(MSD(ha->async_pd_dma))); - mbx->mb9 = cpu_to_le16(sp->fcport->vha->vp_idx); + mbx->mb9 = cpu_to_le16(sp->fcport->vp_idx); } static void @@ -2030,7 +2009,7 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk) tsk->port_id[0] = fcport->d_id.b.al_pa; tsk->port_id[1] = fcport->d_id.b.area; tsk->port_id[2] = fcport->d_id.b.domain; - tsk->vp_index = fcport->vha->vp_idx; + tsk->vp_index = fcport->vp_idx; if (flags == TCF_LUN_RESET) { int_to_scsilun(lun, &tsk->lun); @@ -2051,7 +2030,7 @@ qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) els_iocb->handle = sp->handle; els_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); els_iocb->tx_dsd_count = __constant_cpu_to_le16(bsg_job->request_payload.sg_cnt); - els_iocb->vp_index = sp->fcport->vha->vp_idx; + els_iocb->vp_index = sp->fcport->vp_idx; els_iocb->sof_type = EST_SOFI3; els_iocb->rx_dsd_count = __constant_cpu_to_le16(bsg_job->reply_payload.sg_cnt); @@ -2181,7 +2160,7 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) ct_iocb->handle = sp->handle; ct_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); - ct_iocb->vp_index = sp->fcport->vha->vp_idx; + ct_iocb->vp_index = sp->fcport->vp_idx; ct_iocb->comp_status = __constant_cpu_to_le16(0); ct_iocb->cmd_dsd_count = @@ -2364,10 +2343,11 @@ qla82xx_start_scsi(srb_t *sp) else req->cnt = req->length - (req->ring_index - cnt); - if (req->cnt < (req_cnt + 2)) - goto queuing_error; } + if (req->cnt < (req_cnt + 2)) + goto queuing_error; + ctx = sp->u.scmd.ctx = mempool_alloc(ha->ctx_mempool, GFP_ATOMIC); if (!ctx) { @@ -2382,7 +2362,7 @@ qla82xx_start_scsi(srb_t *sp) if (!ctx->fcp_cmnd) { ql_log(ql_log_fatal, vha, 0x3011, "Failed to allocate fcp_cmnd for cmd=%p.\n", cmd); - goto queuing_error; + goto queuing_error_fcp_cmnd; } /* Initialize the DSD list and dma handle */ @@ -2420,7 +2400,7 @@ qla82xx_start_scsi(srb_t *sp) cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; - cmd_pkt->vp_index = sp->fcport->vha->vp_idx; + cmd_pkt->vp_index = sp->fcport->vp_idx; /* Build IOCB segments */ if (qla24xx_build_scsi_type_6_iocbs(sp, cmd_pkt, tot_dsds)) @@ -2509,7 +2489,7 @@ qla82xx_start_scsi(srb_t *sp) cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; - cmd_pkt->vp_index = sp->fcport->vha->vp_idx; + cmd_pkt->vp_index = sp->fcport->vp_idx; int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, diff --git a/trunk/drivers/scsi/qla2xxx/qla_isr.c b/trunk/drivers/scsi/qla2xxx/qla_isr.c index 6f67a9d4998b..ce42288049b5 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_isr.c +++ b/trunk/drivers/scsi/qla2xxx/qla_isr.c @@ -5,7 +5,6 @@ * See LICENSE.qla2xxx for copyright and licensing details. */ #include "qla_def.h" -#include "qla_target.h" #include #include @@ -310,28 +309,6 @@ qla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr) "IDC failed to post ACK.\n"); } -#define LS_UNKNOWN 2 -char * -qla2x00_get_link_speed_str(struct qla_hw_data *ha) -{ - static char *link_speeds[] = {"1", "2", "?", "4", "8", "16", "10"}; - char *link_speed; - int fw_speed = ha->link_data_rate; - - if (IS_QLA2100(ha) || IS_QLA2200(ha)) - link_speed = link_speeds[0]; - else if (fw_speed == 0x13) - link_speed = link_speeds[6]; - else { - link_speed = link_speeds[LS_UNKNOWN]; - if (fw_speed < 6) - link_speed = - link_speeds[fw_speed]; - } - - return link_speed; -} - /** * qla2x00_async_event() - Process aynchronous events. * @ha: SCSI driver HA context @@ -340,6 +317,9 @@ qla2x00_get_link_speed_str(struct qla_hw_data *ha) void qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) { +#define LS_UNKNOWN 2 + static char *link_speeds[] = { "1", "2", "?", "4", "8", "16", "10" }; + char *link_speed; uint16_t handle_cnt; uint16_t cnt, mbx; uint32_t handles[5]; @@ -474,8 +454,8 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) case MBA_WAKEUP_THRES: /* Request Queue Wake-up */ ql_dbg(ql_dbg_async, vha, 0x5008, "Asynchronous WAKEUP_THRES.\n"); - break; + case MBA_LIP_OCCURRED: /* Loop Initialization Procedure */ ql_dbg(ql_dbg_async, vha, 0x5009, "LIP occurred (%x).\n", mb[1]); @@ -499,14 +479,20 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) break; case MBA_LOOP_UP: /* Loop Up Event */ - if (IS_QLA2100(ha) || IS_QLA2200(ha)) + if (IS_QLA2100(ha) || IS_QLA2200(ha)) { + link_speed = link_speeds[0]; ha->link_data_rate = PORT_SPEED_1GB; - else + } else { + link_speed = link_speeds[LS_UNKNOWN]; + if (mb[1] < 6) + link_speed = link_speeds[mb[1]]; + else if (mb[1] == 0x13) + link_speed = link_speeds[6]; ha->link_data_rate = mb[1]; + } ql_dbg(ql_dbg_async, vha, 0x500a, - "LOOP UP detected (%s Gbps).\n", - qla2x00_get_link_speed_str(ha)); + "LOOP UP detected (%s Gbps).\n", link_speed); vha->flags.management_server_logged_in = 0; qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate); @@ -652,8 +638,6 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) ql_dbg(ql_dbg_async, vha, 0x5010, "Port unavailable %04x %04x %04x.\n", mb[1], mb[2], mb[3]); - ql_log(ql_log_warn, vha, 0x505e, - "Link is offline.\n"); if (atomic_read(&vha->loop_state) != LOOP_DOWN) { atomic_set(&vha->loop_state, LOOP_DOWN); @@ -686,17 +670,12 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) ql_dbg(ql_dbg_async, vha, 0x5011, "Asynchronous PORT UPDATE ignored %04x/%04x/%04x.\n", mb[1], mb[2], mb[3]); - - qlt_async_event(mb[0], vha, mb); break; } ql_dbg(ql_dbg_async, vha, 0x5012, "Port database changed %04x %04x %04x.\n", mb[1], mb[2], mb[3]); - ql_log(ql_log_warn, vha, 0x505f, - "Link is operational (%s Gbps).\n", - qla2x00_get_link_speed_str(ha)); /* * Mark all devices as missing so we will login again. @@ -705,13 +684,8 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) qla2x00_mark_all_devices_lost(vha, 1); - if (vha->vp_idx == 0 && !qla_ini_mode_enabled(vha)) - set_bit(SCR_PENDING, &vha->dpc_flags); - set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); - - qlt_async_event(mb[0], vha, mb); break; case MBA_RSCN_UPDATE: /* State Change Registration */ @@ -833,8 +807,6 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) mb[0], mb[1], mb[2], mb[3]); } - qlt_async_event(mb[0], vha, mb); - if (!vha->vp_idx && ha->num_vhosts) qla2x00_alert_all_vps(rsp, mb); } @@ -1200,9 +1172,6 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, } else if (iop[0] & BIT_5) fcport->port_type = FCT_INITIATOR; - if (iop[0] & BIT_7) - fcport->flags |= FCF_CONF_COMP_SUPPORTED; - if (logio->io_parameter[7] || logio->io_parameter[8]) fcport->supported_classes |= FC_COS_CLASS2; if (logio->io_parameter[9] || logio->io_parameter[10]) @@ -2017,9 +1986,6 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, if (pkt->entry_status != 0) { qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt); - - (void)qlt_24xx_process_response_error(vha, pkt); - ((response_t *)pkt)->signature = RESPONSE_PROCESSED; wmb(); continue; @@ -2050,14 +2016,6 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, case ELS_IOCB_TYPE: qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE); break; - case ABTS_RECV_24XX: - /* ensure that the ATIO queue is empty */ - qlt_24xx_process_atio_queue(vha); - case ABTS_RESP_24XX: - case CTIO_TYPE7: - case NOTIFY_ACK_TYPE: - qlt_response_pkt_all_vps(vha, (response_t *)pkt); - break; case MARKER_TYPE: /* Do nothing in this case, this check is to prevent it * from falling into default case @@ -2210,13 +2168,6 @@ qla24xx_intr_handler(int irq, void *dev_id) case 0x14: qla24xx_process_response_queue(vha, rsp); break; - case 0x1C: /* ATIO queue updated */ - qlt_24xx_process_atio_queue(vha); - break; - case 0x1D: /* ATIO and response queues updated */ - qlt_24xx_process_atio_queue(vha); - qla24xx_process_response_queue(vha, rsp); - break; default: ql_dbg(ql_dbg_async, vha, 0x504f, "Unrecognized interrupt type (%d).\n", stat * 0xff); @@ -2361,13 +2312,6 @@ qla24xx_msix_default(int irq, void *dev_id) case 0x14: qla24xx_process_response_queue(vha, rsp); break; - case 0x1C: /* ATIO queue updated */ - qlt_24xx_process_atio_queue(vha); - break; - case 0x1D: /* ATIO and response queues updated */ - qlt_24xx_process_atio_queue(vha); - qla24xx_process_response_queue(vha, rsp); - break; default: ql_dbg(ql_dbg_async, vha, 0x5051, "Unrecognized interrupt type (%d).\n", stat & 0xff); @@ -2620,15 +2564,7 @@ void qla2x00_free_irqs(scsi_qla_host_t *vha) { struct qla_hw_data *ha = vha->hw; - struct rsp_que *rsp; - - /* - * We need to check that ha->rsp_q_map is valid in case we are called - * from a probe failure context. - */ - if (!ha->rsp_q_map || !ha->rsp_q_map[0]) - return; - rsp = ha->rsp_q_map[0]; + struct rsp_que *rsp = ha->rsp_q_map[0]; if (ha->flags.msix_enabled) qla24xx_disable_msix(ha); diff --git a/trunk/drivers/scsi/qla2xxx/qla_mbx.c b/trunk/drivers/scsi/qla2xxx/qla_mbx.c index d5ce92c0a8fc..b4a23394a7bd 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_mbx.c +++ b/trunk/drivers/scsi/qla2xxx/qla_mbx.c @@ -5,7 +5,6 @@ * See LICENSE.qla2xxx for copyright and licensing details. */ #include "qla_def.h" -#include "qla_target.h" #include #include @@ -271,8 +270,11 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) ictrl = RD_REG_WORD(®->isp.ictrl); } ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1119, - "MBX Command timeout for cmd %x, iocontrol=%x jiffies=%lx " - "mb[0]=0x%x\n", command, ictrl, jiffies, mb0); + "MBX Command timeout for cmd %x.\n", command); + ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x111a, + "iocontrol=%x jiffies=%lx.\n", ictrl, jiffies); + ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x111b, + "mb[0] = 0x%x.\n", mb0); ql_dump_regs(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1019); /* @@ -318,7 +320,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) CRB_NIU_XG_PAUSE_CTL_P1); } ql_log(ql_log_info, base_vha, 0x101c, - "Mailbox cmd timeout occurred, cmd=0x%x, " + "Mailbox cmd timeout occured, cmd=0x%x, " "mb[0]=0x%x, eeh_busy=0x%x. Scheduling ISP " "abort.\n", command, mcp->mb[0], ha->flags.eeh_busy); @@ -343,7 +345,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) CRB_NIU_XG_PAUSE_CTL_P1); } ql_log(ql_log_info, base_vha, 0x101e, - "Mailbox cmd timeout occurred, cmd=0x%x, " + "Mailbox cmd timeout occured, cmd=0x%x, " "mb[0]=0x%x. Scheduling ISP abort ", command, mcp->mb[0]); set_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags); @@ -388,8 +390,7 @@ qla2x00_load_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t risc_addr, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1022, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1022, "Entered %s.\n", __func__); if (MSW(risc_addr) || IS_FWI2_CAPABLE(ha)) { mcp->mb[0] = MBC_LOAD_RISC_RAM_EXTENDED; @@ -423,8 +424,7 @@ qla2x00_load_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t risc_addr, ql_dbg(ql_dbg_mbx, vha, 0x1023, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1024, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1024, "Done %s.\n", __func__); } return rval; @@ -454,8 +454,7 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1025, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1025, "Entered %s.\n", __func__); mcp->mb[0] = MBC_EXECUTE_FIRMWARE; mcp->out_mb = MBX_0; @@ -490,11 +489,10 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); } else { if (IS_FWI2_CAPABLE(ha)) { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1027, + ql_dbg(ql_dbg_mbx, vha, 0x1027, "Done exchanges=%x.\n", mcp->mb[1]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1028, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1028, "Done %s.\n", __func__); } } @@ -525,8 +523,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha) mbx_cmd_t *mcp = &mc; struct qla_hw_data *ha = vha->hw; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1029, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1029, "Entered %s.\n", __func__); mcp->mb[0] = MBC_GET_FIRMWARE_VERSION; mcp->out_mb = MBX_0; @@ -564,11 +561,11 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha) ha->fw_attributes_h = mcp->mb[15]; ha->fw_attributes_ext[0] = mcp->mb[16]; ha->fw_attributes_ext[1] = mcp->mb[17]; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1139, + ql_dbg(ql_dbg_mbx, vha, 0x1139, "%s: FW_attributes Upper: 0x%x, Lower: 0x%x.\n", __func__, mcp->mb[15], mcp->mb[6]); } else - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x112f, + ql_dbg(ql_dbg_mbx, vha, 0x112f, "%s: FwAttributes [Upper] invalid, MB6:%04x\n", __func__, mcp->mb[6]); } @@ -579,8 +576,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha) ql_dbg(ql_dbg_mbx, vha, 0x102a, "Failed=%x.\n", rval); } else { /*EMPTY*/ - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x102b, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x102b, "Done %s.\n", __func__); } return rval; } @@ -606,8 +602,7 @@ qla2x00_get_fw_options(scsi_qla_host_t *vha, uint16_t *fwopts) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x102c, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x102c, "Entered %s.\n", __func__); mcp->mb[0] = MBC_GET_FIRMWARE_OPTION; mcp->out_mb = MBX_0; @@ -625,8 +620,7 @@ qla2x00_get_fw_options(scsi_qla_host_t *vha, uint16_t *fwopts) fwopts[2] = mcp->mb[2]; fwopts[3] = mcp->mb[3]; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x102e, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x102e, "Done %s.\n", __func__); } return rval; @@ -654,8 +648,7 @@ qla2x00_set_fw_options(scsi_qla_host_t *vha, uint16_t *fwopts) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x102f, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x102f, "Entered %s.\n", __func__); mcp->mb[0] = MBC_SET_FIRMWARE_OPTION; mcp->mb[1] = fwopts[1]; @@ -683,8 +676,7 @@ qla2x00_set_fw_options(scsi_qla_host_t *vha, uint16_t *fwopts) "Failed=%x (%x/%x).\n", rval, mcp->mb[0], mcp->mb[1]); } else { /*EMPTY*/ - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1031, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1031, "Done %s.\n", __func__); } return rval; @@ -712,8 +704,7 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *vha) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1032, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1032, "Entered %s.\n", __func__); mcp->mb[0] = MBC_MAILBOX_REGISTER_TEST; mcp->mb[1] = 0xAAAA; @@ -743,8 +734,7 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *vha) ql_dbg(ql_dbg_mbx, vha, 0x1033, "Failed=%x.\n", rval); } else { /*EMPTY*/ - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1034, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1034, "Done %s.\n", __func__); } return rval; @@ -772,8 +762,7 @@ qla2x00_verify_checksum(scsi_qla_host_t *vha, uint32_t risc_addr) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1035, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1035, "Entered %s.\n", __func__); mcp->mb[0] = MBC_VERIFY_CHECKSUM; mcp->out_mb = MBX_0; @@ -798,8 +787,7 @@ qla2x00_verify_checksum(scsi_qla_host_t *vha, uint32_t risc_addr) "Failed=%x chm sum=%x.\n", rval, IS_FWI2_CAPABLE(vha->hw) ? (mcp->mb[2] << 16) | mcp->mb[1] : mcp->mb[1]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1037, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1037, "Done %s.\n", __func__); } return rval; @@ -831,8 +819,7 @@ qla2x00_issue_iocb_timeout(scsi_qla_host_t *vha, void *buffer, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1038, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1038, "Entered %s.\n", __func__); mcp->mb[0] = MBC_IOCB_COMMAND_A64; mcp->mb[1] = 0; @@ -855,8 +842,7 @@ qla2x00_issue_iocb_timeout(scsi_qla_host_t *vha, void *buffer, /* Mask reserved bits. */ sts_entry->entry_status &= IS_FWI2_CAPABLE(vha->hw) ? RF_MASK_24XX : RF_MASK; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x103a, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x103a, "Done %s.\n", __func__); } return rval; @@ -898,8 +884,7 @@ qla2x00_abort_command(srb_t *sp) struct req_que *req = vha->req; struct scsi_cmnd *cmd = GET_CMD_SP(sp); - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x103b, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x103b, "Entered %s.\n", __func__); spin_lock_irqsave(&ha->hardware_lock, flags); for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) { @@ -930,8 +915,7 @@ qla2x00_abort_command(srb_t *sp) if (rval != QLA_SUCCESS) { ql_dbg(ql_dbg_mbx, vha, 0x103c, "Failed=%x.\n", rval); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x103d, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x103d, "Done %s.\n", __func__); } return rval; @@ -950,8 +934,7 @@ qla2x00_abort_target(struct fc_port *fcport, unsigned int l, int tag) l = l; vha = fcport->vha; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x103e, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x103e, "Entered %s.\n", __func__); req = vha->hw->req_q_map[0]; rsp = req->rsp; @@ -972,8 +955,7 @@ qla2x00_abort_target(struct fc_port *fcport, unsigned int l, int tag) mcp->flags = 0; rval = qla2x00_mailbox_command(vha, mcp); if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x103f, - "Failed=%x.\n", rval); + ql_dbg(ql_dbg_mbx, vha, 0x103f, "Failed=%x.\n", rval); } /* Issue marker IOCB. */ @@ -983,8 +965,7 @@ qla2x00_abort_target(struct fc_port *fcport, unsigned int l, int tag) ql_dbg(ql_dbg_mbx, vha, 0x1040, "Failed to issue marker IOCB (%x).\n", rval2); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1041, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1041, "Done %s.\n", __func__); } return rval; @@ -1002,8 +983,7 @@ qla2x00_lun_reset(struct fc_port *fcport, unsigned int l, int tag) vha = fcport->vha; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1042, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1042, "Entered %s.\n", __func__); req = vha->hw->req_q_map[0]; rsp = req->rsp; @@ -1032,8 +1012,7 @@ qla2x00_lun_reset(struct fc_port *fcport, unsigned int l, int tag) ql_dbg(ql_dbg_mbx, vha, 0x1044, "Failed to issue marker IOCB (%x).\n", rval2); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1045, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1045, "Done %s.\n", __func__); } return rval; @@ -1067,8 +1046,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1046, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1046, "Entered %s.\n", __func__); mcp->mb[0] = MBC_GET_ADAPTER_LOOP_ID; mcp->mb[9] = vha->vp_idx; @@ -1096,8 +1074,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa, /*EMPTY*/ ql_dbg(ql_dbg_mbx, vha, 0x1047, "Failed=%x.\n", rval); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1048, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1048, "Done %s.\n", __func__); if (IS_CNA_CAPABLE(vha->hw)) { vha->fcoe_vlan_id = mcp->mb[9] & 0xfff; @@ -1138,8 +1115,7 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *vha, uint8_t *retry_cnt, uint8_t *tov, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1049, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1049, "Entered %s.\n", __func__); mcp->mb[0] = MBC_GET_RETRY_COUNT; mcp->out_mb = MBX_0; @@ -1162,7 +1138,7 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *vha, uint8_t *retry_cnt, uint8_t *tov, *tov = ratov; } - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x104b, + ql_dbg(ql_dbg_mbx, vha, 0x104b, "Done %s mb3=%d ratov=%d.\n", __func__, mcp->mb[3], ratov); } @@ -1194,8 +1170,7 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size) mbx_cmd_t *mcp = &mc; struct qla_hw_data *ha = vha->hw; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x104c, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x104c, "Entered %s.\n", __func__); if (IS_QLA82XX(ha) && ql2xdbwr) qla82xx_wr_32(ha, ha->nxdb_wr_ptr, @@ -1238,100 +1213,9 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size) rval, mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3]); } else { /*EMPTY*/ - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x104e, - "Done %s.\n", __func__); - } - - return rval; -} - -/* - * qla2x00_get_node_name_list - * Issue get node name list mailbox command, kmalloc() - * and return the resulting list. Caller must kfree() it! - * - * Input: - * ha = adapter state pointer. - * out_data = resulting list - * out_len = length of the resulting list - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_get_node_name_list(scsi_qla_host_t *vha, void **out_data, int *out_len) -{ - struct qla_hw_data *ha = vha->hw; - struct qla_port_24xx_data *list = NULL; - void *pmap; - mbx_cmd_t mc; - dma_addr_t pmap_dma; - ulong dma_size; - int rval, left; - - left = 1; - while (left > 0) { - dma_size = left * sizeof(*list); - pmap = dma_alloc_coherent(&ha->pdev->dev, dma_size, - &pmap_dma, GFP_KERNEL); - if (!pmap) { - ql_log(ql_log_warn, vha, 0x113f, - "%s(%ld): DMA Alloc failed of %ld\n", - __func__, vha->host_no, dma_size); - rval = QLA_MEMORY_ALLOC_FAILED; - goto out; - } - - mc.mb[0] = MBC_PORT_NODE_NAME_LIST; - mc.mb[1] = BIT_1 | BIT_3; - mc.mb[2] = MSW(pmap_dma); - mc.mb[3] = LSW(pmap_dma); - mc.mb[6] = MSW(MSD(pmap_dma)); - mc.mb[7] = LSW(MSD(pmap_dma)); - mc.mb[8] = dma_size; - mc.out_mb = MBX_0|MBX_1|MBX_2|MBX_3|MBX_6|MBX_7|MBX_8; - mc.in_mb = MBX_0|MBX_1; - mc.tov = 30; - mc.flags = MBX_DMA_IN; - - rval = qla2x00_mailbox_command(vha, &mc); - if (rval != QLA_SUCCESS) { - if ((mc.mb[0] == MBS_COMMAND_ERROR) && - (mc.mb[1] == 0xA)) { - left += le16_to_cpu(mc.mb[2]) / - sizeof(struct qla_port_24xx_data); - goto restart; - } - goto out_free; - } - - left = 0; - - list = kzalloc(dma_size, GFP_KERNEL); - if (!list) { - ql_log(ql_log_warn, vha, 0x1140, - "%s(%ld): failed to allocate node names list " - "structure.\n", __func__, vha->host_no); - rval = QLA_MEMORY_ALLOC_FAILED; - goto out_free; - } - - memcpy(list, pmap, dma_size); -restart: - dma_free_coherent(&ha->pdev->dev, dma_size, pmap, pmap_dma); + ql_dbg(ql_dbg_mbx, vha, 0x104e, "Done %s.\n", __func__); } - *out_data = list; - *out_len = dma_size; - -out: - return rval; - -out_free: - dma_free_coherent(&ha->pdev->dev, dma_size, pmap, pmap_dma); return rval; } @@ -1362,8 +1246,7 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt) dma_addr_t pd_dma; struct qla_hw_data *ha = vha->hw; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x104f, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x104f, "Entered %s.\n", __func__); pd24 = NULL; pd = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &pd_dma); @@ -1443,13 +1326,6 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt) fcport->port_type = FCT_INITIATOR; else fcport->port_type = FCT_TARGET; - - /* Passback COS information. */ - fcport->supported_classes = (pd24->flags & PDF_CLASS_2) ? - FC_COS_CLASS2 : FC_COS_CLASS3; - - if (pd24->prli_svc_param_word_3[0] & BIT_7) - fcport->flags |= FCF_CONF_COMP_SUPPORTED; } else { uint64_t zero = 0; @@ -1502,8 +1378,7 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt) "Failed=%x mb[0]=%x mb[1]=%x.\n", rval, mcp->mb[0], mcp->mb[1]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1053, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1053, "Done %s.\n", __func__); } return rval; @@ -1532,8 +1407,7 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1054, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1054, "Entered %s.\n", __func__); mcp->mb[0] = MBC_GET_FIRMWARE_STATE; mcp->out_mb = MBX_0; @@ -1559,8 +1433,7 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states) ql_dbg(ql_dbg_mbx, vha, 0x1055, "Failed=%x.\n", rval); } else { /*EMPTY*/ - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1056, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1056, "Done %s.\n", __func__); } return rval; @@ -1592,8 +1465,7 @@ qla2x00_get_port_name(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t *name, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1057, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1057, "Entered %s.\n", __func__); mcp->mb[0] = MBC_GET_PORT_NAME; mcp->mb[9] = vha->vp_idx; @@ -1627,8 +1499,7 @@ qla2x00_get_port_name(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t *name, name[7] = LSB(mcp->mb[7]); } - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1059, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1059, "Done %s.\n", __func__); } return rval; @@ -1656,8 +1527,7 @@ qla2x00_lip_reset(scsi_qla_host_t *vha) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x105a, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x105a, "Entered %s.\n", __func__); if (IS_CNA_CAPABLE(vha->hw)) { /* Logout across all FCFs. */ @@ -1694,8 +1564,7 @@ qla2x00_lip_reset(scsi_qla_host_t *vha) ql_dbg(ql_dbg_mbx, vha, 0x105b, "Failed=%x.\n", rval); } else { /*EMPTY*/ - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x105c, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x105c, "Done %s.\n", __func__); } return rval; @@ -1727,10 +1596,9 @@ qla2x00_send_sns(scsi_qla_host_t *vha, dma_addr_t sns_phys_address, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x105d, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x105d, "Entered %s.\n", __func__); - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x105e, + ql_dbg(ql_dbg_mbx, vha, 0x105e, "Retry cnt=%d ratov=%d total tov=%d.\n", vha->hw->retry_count, vha->hw->login_timeout, mcp->tov); @@ -1754,8 +1622,7 @@ qla2x00_send_sns(scsi_qla_host_t *vha, dma_addr_t sns_phys_address, rval, mcp->mb[0], mcp->mb[1]); } else { /*EMPTY*/ - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1060, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1060, "Done %s.\n", __func__); } return rval; @@ -1774,8 +1641,7 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, struct req_que *req; struct rsp_que *rsp; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1061, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1061, "Entered %s.\n", __func__); if (ha->flags.cpu_affinity_enabled) req = ha->req_q_map[0]; @@ -1849,8 +1715,7 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, break; } } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1066, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1066, "Done %s.\n", __func__); iop[0] = le32_to_cpu(lg->io_parameter[0]); @@ -1868,10 +1733,6 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, mb[10] |= BIT_0; /* Class 2. */ if (lg->io_parameter[9] || lg->io_parameter[10]) mb[10] |= BIT_1; /* Class 3. */ - if (lg->io_parameter[0] & __constant_cpu_to_le32(BIT_7)) - mb[10] |= BIT_7; /* Confirmed Completion - * Allowed - */ } dma_pool_free(ha->s_dma_pool, lg, lg_dma); @@ -1909,8 +1770,7 @@ qla2x00_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, mbx_cmd_t *mcp = &mc; struct qla_hw_data *ha = vha->hw; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1067, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1067, "Entered %s.\n", __func__); mcp->mb[0] = MBC_LOGIN_FABRIC_PORT; mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0; @@ -1958,8 +1818,7 @@ qla2x00_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, rval, mcp->mb[0], mcp->mb[1], mcp->mb[2]); } else { /*EMPTY*/ - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1069, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1069, "Done %s.\n", __func__); } return rval; @@ -1990,8 +1849,7 @@ qla2x00_login_local_device(scsi_qla_host_t *vha, fc_port_t *fcport, mbx_cmd_t *mcp = &mc; struct qla_hw_data *ha = vha->hw; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x106a, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x106a, "Entered %s.\n", __func__); if (IS_FWI2_CAPABLE(ha)) return qla24xx_login_fabric(vha, fcport->loop_id, @@ -2033,8 +1891,7 @@ qla2x00_login_local_device(scsi_qla_host_t *vha, fc_port_t *fcport, rval, mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]); } else { /*EMPTY*/ - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x106c, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x106c, "Done %s.\n", __func__); } return (rval); @@ -2051,8 +1908,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, struct req_que *req; struct rsp_que *rsp; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x106d, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x106d, "Entered %s.\n", __func__); lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma); if (lg == NULL) { @@ -2096,8 +1952,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, le32_to_cpu(lg->io_parameter[1])); } else { /*EMPTY*/ - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1072, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1072, "Done %s.\n", __func__); } dma_pool_free(ha->s_dma_pool, lg, lg_dma); @@ -2129,8 +1984,7 @@ qla2x00_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1073, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1073, "Entered %s.\n", __func__); mcp->mb[0] = MBC_LOGOUT_FABRIC_PORT; mcp->out_mb = MBX_1|MBX_0; @@ -2153,8 +2007,7 @@ qla2x00_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, "Failed=%x mb[1]=%x.\n", rval, mcp->mb[1]); } else { /*EMPTY*/ - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1075, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1075, "Done %s.\n", __func__); } return rval; @@ -2182,8 +2035,7 @@ qla2x00_full_login_lip(scsi_qla_host_t *vha) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1076, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1076, "Entered %s.\n", __func__); mcp->mb[0] = MBC_LIP_FULL_LOGIN; mcp->mb[1] = IS_FWI2_CAPABLE(vha->hw) ? BIT_3 : 0; @@ -2200,8 +2052,7 @@ qla2x00_full_login_lip(scsi_qla_host_t *vha) ql_dbg(ql_dbg_mbx, vha, 0x1077, "Failed=%x.\n", rval); } else { /*EMPTY*/ - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1078, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1078, "Done %s.\n", __func__); } return rval; @@ -2227,8 +2078,7 @@ qla2x00_get_id_list(scsi_qla_host_t *vha, void *id_list, dma_addr_t id_list_dma, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1079, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1079, "Entered %s.\n", __func__); if (id_list == NULL) return QLA_FUNCTION_FAILED; @@ -2260,8 +2110,7 @@ qla2x00_get_id_list(scsi_qla_host_t *vha, void *id_list, dma_addr_t id_list_dma, ql_dbg(ql_dbg_mbx, vha, 0x107a, "Failed=%x.\n", rval); } else { *entries = mcp->mb[1]; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x107b, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x107b, "Done %s.\n", __func__); } return rval; @@ -2289,8 +2138,7 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x107c, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x107c, "Entered %s.\n", __func__); mcp->mb[0] = MBC_GET_RESOURCE_COUNTS; mcp->out_mb = MBX_0; @@ -2306,7 +2154,7 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt, ql_dbg(ql_dbg_mbx, vha, 0x107d, "Failed mb[0]=%x.\n", mcp->mb[0]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x107e, + ql_dbg(ql_dbg_mbx, vha, 0x107e, "Done %s mb1=%x mb2=%x mb3=%x mb6=%x mb7=%x mb10=%x " "mb11=%x mb12=%x.\n", __func__, mcp->mb[1], mcp->mb[2], mcp->mb[3], mcp->mb[6], mcp->mb[7], mcp->mb[10], @@ -2353,8 +2201,7 @@ qla2x00_get_fcal_position_map(scsi_qla_host_t *vha, char *pos_map) dma_addr_t pmap_dma; struct qla_hw_data *ha = vha->hw; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x107f, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x107f, "Entered %s.\n", __func__); pmap = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &pmap_dma); if (pmap == NULL) { @@ -2377,7 +2224,7 @@ qla2x00_get_fcal_position_map(scsi_qla_host_t *vha, char *pos_map) rval = qla2x00_mailbox_command(vha, mcp); if (rval == QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1081, + ql_dbg(ql_dbg_mbx, vha, 0x1081, "mb0/mb1=%x/%X FC/AL position map size (%x).\n", mcp->mb[0], mcp->mb[1], (unsigned)pmap[0]); ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x111d, @@ -2391,8 +2238,7 @@ qla2x00_get_fcal_position_map(scsi_qla_host_t *vha, char *pos_map) if (rval != QLA_SUCCESS) { ql_dbg(ql_dbg_mbx, vha, 0x1082, "Failed=%x.\n", rval); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1083, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1083, "Done %s.\n", __func__); } return rval; @@ -2421,8 +2267,7 @@ qla2x00_get_link_status(scsi_qla_host_t *vha, uint16_t loop_id, uint32_t *siter, *diter, dwords; struct qla_hw_data *ha = vha->hw; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1084, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1084, "Entered %s.\n", __func__); mcp->mb[0] = MBC_GET_LINK_STATUS; mcp->mb[2] = MSW(stats_dma); @@ -2456,8 +2301,7 @@ qla2x00_get_link_status(scsi_qla_host_t *vha, uint16_t loop_id, rval = QLA_FUNCTION_FAILED; } else { /* Copy over data -- firmware data is LE. */ - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1086, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1086, "Done %s.\n", __func__); dwords = offsetof(struct link_statistics, unused1) / 4; siter = diter = &stats->link_fail_cnt; while (dwords--) @@ -2480,8 +2324,7 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats, mbx_cmd_t *mcp = &mc; uint32_t *siter, *diter, dwords; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1088, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1088, "Entered %s.\n", __func__); mcp->mb[0] = MBC_GET_LINK_PRIV_STATS; mcp->mb[2] = MSW(stats_dma); @@ -2503,8 +2346,7 @@ qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats, "Failed mb[0]=%x.\n", mcp->mb[0]); rval = QLA_FUNCTION_FAILED; } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x108a, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x108a, "Done %s.\n", __func__); /* Copy over data -- firmware data is LE. */ dwords = sizeof(struct link_statistics) / 4; siter = diter = &stats->link_fail_cnt; @@ -2533,8 +2375,7 @@ qla24xx_abort_command(srb_t *sp) struct qla_hw_data *ha = vha->hw; struct req_que *req = vha->req; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x108c, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x108c, "Entered %s.\n", __func__); spin_lock_irqsave(&ha->hardware_lock, flags); for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) { @@ -2563,7 +2404,7 @@ qla24xx_abort_command(srb_t *sp) abt->port_id[0] = fcport->d_id.b.al_pa; abt->port_id[1] = fcport->d_id.b.area; abt->port_id[2] = fcport->d_id.b.domain; - abt->vp_index = fcport->vha->vp_idx; + abt->vp_index = fcport->vp_idx; abt->req_que_no = cpu_to_le16(req->id); @@ -2582,8 +2423,7 @@ qla24xx_abort_command(srb_t *sp) le16_to_cpu(abt->nport_handle)); rval = QLA_FUNCTION_FAILED; } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1091, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1091, "Done %s.\n", __func__); } dma_pool_free(ha->s_dma_pool, abt, abt_dma); @@ -2615,8 +2455,7 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, ha = vha->hw; req = vha->req; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1092, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1092, "Entered %s.\n", __func__); if (ha->flags.cpu_affinity_enabled) rsp = ha->rsp_q_map[tag + 1]; @@ -2639,7 +2478,7 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, tsk->p.tsk.port_id[0] = fcport->d_id.b.al_pa; tsk->p.tsk.port_id[1] = fcport->d_id.b.area; tsk->p.tsk.port_id[2] = fcport->d_id.b.domain; - tsk->p.tsk.vp_index = fcport->vha->vp_idx; + tsk->p.tsk.vp_index = fcport->vp_idx; if (type == TCF_LUN_RESET) { int_to_scsilun(l, &tsk->p.tsk.lun); host_to_fcp_swap((uint8_t *)&tsk->p.tsk.lun, @@ -2665,7 +2504,7 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, } else if (le16_to_cpu(sts->scsi_status) & SS_RESPONSE_INFO_LEN_VALID) { if (le32_to_cpu(sts->rsp_data_len) < 4) { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1097, + ql_dbg(ql_dbg_mbx, vha, 0x1097, "Ignoring inconsistent data length -- not enough " "response info (%d).\n", le32_to_cpu(sts->rsp_data_len)); @@ -2684,8 +2523,7 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, ql_dbg(ql_dbg_mbx, vha, 0x1099, "Failed to issue marker IOCB (%x).\n", rval2); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x109a, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x109a, "Done %s.\n", __func__); } dma_pool_free(ha->s_dma_pool, tsk, tsk_dma); @@ -2726,8 +2564,7 @@ qla2x00_system_error(scsi_qla_host_t *vha) if (!IS_QLA23XX(ha) && !IS_FWI2_CAPABLE(ha)) return QLA_FUNCTION_FAILED; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x109b, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x109b, "Entered %s.\n", __func__); mcp->mb[0] = MBC_GEN_SYSTEM_ERROR; mcp->out_mb = MBX_0; @@ -2739,8 +2576,7 @@ qla2x00_system_error(scsi_qla_host_t *vha) if (rval != QLA_SUCCESS) { ql_dbg(ql_dbg_mbx, vha, 0x109c, "Failed=%x.\n", rval); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x109d, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x109d, "Done %s.\n", __func__); } return rval; @@ -2760,8 +2596,7 @@ qla2x00_set_serdes_params(scsi_qla_host_t *vha, uint16_t sw_em_1g, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x109e, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x109e, "Entered %s.\n", __func__); mcp->mb[0] = MBC_SERDES_PARAMS; mcp->mb[1] = BIT_0; @@ -2780,8 +2615,7 @@ qla2x00_set_serdes_params(scsi_qla_host_t *vha, uint16_t sw_em_1g, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); } else { /*EMPTY*/ - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10a0, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10a0, "Done %s.\n", __func__); } return rval; @@ -2797,8 +2631,7 @@ qla2x00_stop_firmware(scsi_qla_host_t *vha) if (!IS_FWI2_CAPABLE(vha->hw)) return QLA_FUNCTION_FAILED; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10a1, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10a1, "Entered %s.\n", __func__); mcp->mb[0] = MBC_STOP_FIRMWARE; mcp->mb[1] = 0; @@ -2813,8 +2646,7 @@ qla2x00_stop_firmware(scsi_qla_host_t *vha) if (mcp->mb[0] == MBS_INVALID_COMMAND) rval = QLA_INVALID_COMMAND; } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10a3, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10a3, "Done %s.\n", __func__); } return rval; @@ -2828,8 +2660,7 @@ qla2x00_enable_eft_trace(scsi_qla_host_t *vha, dma_addr_t eft_dma, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10a4, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10a4, "Entered %s.\n", __func__); if (!IS_FWI2_CAPABLE(vha->hw)) return QLA_FUNCTION_FAILED; @@ -2855,8 +2686,7 @@ qla2x00_enable_eft_trace(scsi_qla_host_t *vha, dma_addr_t eft_dma, "Failed=%x mb[0]=%x mb[1]=%x.\n", rval, mcp->mb[0], mcp->mb[1]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10a6, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10a6, "Done %s.\n", __func__); } return rval; @@ -2869,8 +2699,7 @@ qla2x00_disable_eft_trace(scsi_qla_host_t *vha) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10a7, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10a7, "Entered %s.\n", __func__); if (!IS_FWI2_CAPABLE(vha->hw)) return QLA_FUNCTION_FAILED; @@ -2890,8 +2719,7 @@ qla2x00_disable_eft_trace(scsi_qla_host_t *vha) "Failed=%x mb[0]=%x mb[1]=%x.\n", rval, mcp->mb[0], mcp->mb[1]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10a9, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10a9, "Done %s.\n", __func__); } return rval; @@ -2905,8 +2733,7 @@ qla2x00_enable_fce_trace(scsi_qla_host_t *vha, dma_addr_t fce_dma, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10aa, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10aa, "Entered %s.\n", __func__); if (!IS_QLA25XX(vha->hw) && !IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw)) @@ -2937,8 +2764,7 @@ qla2x00_enable_fce_trace(scsi_qla_host_t *vha, dma_addr_t fce_dma, "Failed=%x mb[0]=%x mb[1]=%x.\n", rval, mcp->mb[0], mcp->mb[1]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10ac, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10ac, "Done %s.\n", __func__); if (mb) memcpy(mb, mcp->mb, 8 * sizeof(*mb)); @@ -2956,8 +2782,7 @@ qla2x00_disable_fce_trace(scsi_qla_host_t *vha, uint64_t *wr, uint64_t *rd) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10ad, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10ad, "Entered %s.\n", __func__); if (!IS_FWI2_CAPABLE(vha->hw)) return QLA_FUNCTION_FAILED; @@ -2979,8 +2804,7 @@ qla2x00_disable_fce_trace(scsi_qla_host_t *vha, uint64_t *wr, uint64_t *rd) "Failed=%x mb[0]=%x mb[1]=%x.\n", rval, mcp->mb[0], mcp->mb[1]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10af, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10af, "Done %s.\n", __func__); if (wr) *wr = (uint64_t) mcp->mb[5] << 48 | @@ -3005,8 +2829,7 @@ qla2x00_get_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10b0, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10b0, "Entered %s.\n", __func__); if (!IS_IIDMA_CAPABLE(vha->hw)) return QLA_FUNCTION_FAILED; @@ -3031,8 +2854,7 @@ qla2x00_get_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id, if (rval != QLA_SUCCESS) { ql_dbg(ql_dbg_mbx, vha, 0x10b1, "Failed=%x.\n", rval); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10b2, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10b2, "Done %s.\n", __func__); if (port_speed) *port_speed = mcp->mb[3]; } @@ -3048,8 +2870,7 @@ qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10b3, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10b3, "Entered %s.\n", __func__); if (!IS_IIDMA_CAPABLE(vha->hw)) return QLA_FUNCTION_FAILED; @@ -3076,11 +2897,9 @@ qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id, } if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10b4, - "Failed=%x.\n", rval); + ql_dbg(ql_dbg_mbx, vha, 0x10b4, "Failed=%x.\n", rval); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10b5, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10b5, "Done %s.\n", __func__); } return rval; @@ -3096,25 +2915,24 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, scsi_qla_host_t *vp; unsigned long flags; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10b6, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10b6, "Entered %s.\n", __func__); if (rptid_entry->entry_status != 0) return; if (rptid_entry->format == 0) { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10b7, + ql_dbg(ql_dbg_mbx, vha, 0x10b7, "Format 0 : Number of VPs setup %d, number of " "VPs acquired %d.\n", MSB(le16_to_cpu(rptid_entry->vp_count)), LSB(le16_to_cpu(rptid_entry->vp_count))); - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10b8, + ql_dbg(ql_dbg_mbx, vha, 0x10b8, "Primary port id %02x%02x%02x.\n", rptid_entry->port_id[2], rptid_entry->port_id[1], rptid_entry->port_id[0]); } else if (rptid_entry->format == 1) { vp_idx = LSB(stat); - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10b9, + ql_dbg(ql_dbg_mbx, vha, 0x10b9, "Format 1: VP[%d] enabled - status %d - with " "port id %02x%02x%02x.\n", vp_idx, MSB(stat), rptid_entry->port_id[2], rptid_entry->port_id[1], @@ -3181,8 +2999,7 @@ qla24xx_modify_vp_config(scsi_qla_host_t *vha) /* This can be called by the parent */ - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10bb, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10bb, "Entered %s.\n", __func__); vpmod = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &vpmod_dma); if (!vpmod) { @@ -3198,9 +3015,6 @@ qla24xx_modify_vp_config(scsi_qla_host_t *vha) vpmod->vp_count = 1; vpmod->vp_index1 = vha->vp_idx; vpmod->options_idx1 = BIT_3|BIT_4|BIT_5; - - qlt_modify_vp_config(vha, vpmod); - memcpy(vpmod->node_name_idx1, vha->node_name, WWN_SIZE); memcpy(vpmod->port_name_idx1, vha->port_name, WWN_SIZE); vpmod->entry_count = 1; @@ -3221,8 +3035,7 @@ qla24xx_modify_vp_config(scsi_qla_host_t *vha) rval = QLA_FUNCTION_FAILED; } else { /* EMPTY */ - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10c0, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10c0, "Done %s.\n", __func__); fc_vport_set_state(vha->fc_vport, FC_VPORT_INITIALIZING); } dma_pool_free(ha->s_dma_pool, vpmod, vpmod_dma); @@ -3256,7 +3069,7 @@ qla24xx_control_vp(scsi_qla_host_t *vha, int cmd) int vp_index = vha->vp_idx; struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10c1, + ql_dbg(ql_dbg_mbx, vha, 0x10c1, "Entered %s enabling index %d.\n", __func__, vp_index); if (vp_index == 0 || vp_index >= ha->max_npiv_vports) @@ -3299,8 +3112,7 @@ qla24xx_control_vp(scsi_qla_host_t *vha, int cmd) le16_to_cpu(vce->comp_status)); rval = QLA_FUNCTION_FAILED; } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10c6, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10c6, "Done %s.\n", __func__); } dma_pool_free(ha->s_dma_pool, vce, vce_dma); @@ -3337,8 +3149,14 @@ qla2x00_send_change_request(scsi_qla_host_t *vha, uint16_t format, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10c7, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10c7, "Entered %s.\n", __func__); + + /* + * This command is implicitly executed by firmware during login for the + * physical hosts + */ + if (vp_idx == 0) + return QLA_FUNCTION_FAILED; mcp->mb[0] = MBC_SEND_CHANGE_REQUEST; mcp->mb[1] = format; @@ -3367,8 +3185,7 @@ qla2x00_dump_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t addr, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1009, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1009, "Entered %s.\n", __func__); if (MSW(addr) || IS_FWI2_CAPABLE(vha->hw)) { mcp->mb[0] = MBC_DUMP_RISC_RAM_EXTENDED; @@ -3402,8 +3219,7 @@ qla2x00_dump_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t addr, ql_dbg(ql_dbg_mbx, vha, 0x1008, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1007, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1007, "Done %s.\n", __func__); } return rval; @@ -3428,8 +3244,7 @@ qla84xx_verify_chip(struct scsi_qla_host *vha, uint16_t *status) unsigned long flags; struct qla_hw_data *ha = vha->hw; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10c8, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10c8, "Entered %s.\n", __func__); mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma); if (mn == NULL) { @@ -3470,7 +3285,7 @@ qla84xx_verify_chip(struct scsi_qla_host *vha, uint16_t *status) status[0] = le16_to_cpu(mn->p.rsp.comp_status); status[1] = status[0] == CS_VCS_CHIP_FAILURE ? le16_to_cpu(mn->p.rsp.failure_code) : 0; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10ce, + ql_dbg(ql_dbg_mbx, vha, 0x10ce, "cs=%x fc=%x.\n", status[0], status[1]); if (status[0] != CS_COMPLETE) { @@ -3484,7 +3299,7 @@ qla84xx_verify_chip(struct scsi_qla_host *vha, uint16_t *status) retry = 1; } } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10d0, + ql_dbg(ql_dbg_mbx, vha, 0x10d0, "Firmware updated to %x.\n", le32_to_cpu(mn->p.rsp.fw_ver)); @@ -3501,11 +3316,9 @@ qla84xx_verify_chip(struct scsi_qla_host *vha, uint16_t *status) dma_pool_free(ha->s_dma_pool, mn, mn_dma); if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10d1, - "Failed=%x.\n", rval); + ql_dbg(ql_dbg_mbx, vha, 0x10d1, "Failed=%x.\n", rval); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10d2, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10d2, "Done %s.\n", __func__); } return rval; @@ -3521,8 +3334,7 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req) struct device_reg_25xxmq __iomem *reg; struct qla_hw_data *ha = vha->hw; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10d3, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10d3, "Entered %s.\n", __func__); mcp->mb[0] = MBC_INITIALIZE_MULTIQ; mcp->mb[1] = req->options; @@ -3576,8 +3388,7 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req) ql_dbg(ql_dbg_mbx, vha, 0x10d4, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10d5, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10d5, "Done %s.\n", __func__); } return rval; @@ -3593,8 +3404,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp) struct device_reg_25xxmq __iomem *reg; struct qla_hw_data *ha = vha->hw; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10d6, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10d6, "Entered %s.\n", __func__); mcp->mb[0] = MBC_INITIALIZE_MULTIQ; mcp->mb[1] = rsp->options; @@ -3646,8 +3456,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp) ql_dbg(ql_dbg_mbx, vha, 0x10d7, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10d8, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10d8, "Done %s.\n", __func__); } return rval; @@ -3660,8 +3469,7 @@ qla81xx_idc_ack(scsi_qla_host_t *vha, uint16_t *mb) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10d9, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10d9, "Entered %s.\n", __func__); mcp->mb[0] = MBC_IDC_ACK; memcpy(&mcp->mb[1], mb, QLA_IDC_ACK_REGS * sizeof(uint16_t)); @@ -3675,8 +3483,7 @@ qla81xx_idc_ack(scsi_qla_host_t *vha, uint16_t *mb) ql_dbg(ql_dbg_mbx, vha, 0x10da, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10db, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10db, "Done %s.\n", __func__); } return rval; @@ -3689,8 +3496,7 @@ qla81xx_fac_get_sector_size(scsi_qla_host_t *vha, uint32_t *sector_size) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10dc, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10dc, "Entered %s.\n", __func__); if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw)) return QLA_FUNCTION_FAILED; @@ -3708,8 +3514,7 @@ qla81xx_fac_get_sector_size(scsi_qla_host_t *vha, uint32_t *sector_size) "Failed=%x mb[0]=%x mb[1]=%x.\n", rval, mcp->mb[0], mcp->mb[1]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10de, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10de, "Done %s.\n", __func__); *sector_size = mcp->mb[1]; } @@ -3726,8 +3531,7 @@ qla81xx_fac_do_write_enable(scsi_qla_host_t *vha, int enable) if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw)) return QLA_FUNCTION_FAILED; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10df, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10df, "Entered %s.\n", __func__); mcp->mb[0] = MBC_FLASH_ACCESS_CTRL; mcp->mb[1] = enable ? FAC_OPT_CMD_WRITE_ENABLE : @@ -3743,8 +3547,7 @@ qla81xx_fac_do_write_enable(scsi_qla_host_t *vha, int enable) "Failed=%x mb[0]=%x mb[1]=%x.\n", rval, mcp->mb[0], mcp->mb[1]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e1, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10e1, "Done %s.\n", __func__); } return rval; @@ -3760,8 +3563,7 @@ qla81xx_fac_erase_sector(scsi_qla_host_t *vha, uint32_t start, uint32_t finish) if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw)) return QLA_FUNCTION_FAILED; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e2, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10e2, "Entered %s.\n", __func__); mcp->mb[0] = MBC_FLASH_ACCESS_CTRL; mcp->mb[1] = FAC_OPT_CMD_ERASE_SECTOR; @@ -3780,8 +3582,7 @@ qla81xx_fac_erase_sector(scsi_qla_host_t *vha, uint32_t start, uint32_t finish) "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x.\n", rval, mcp->mb[0], mcp->mb[1], mcp->mb[2]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e4, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10e4, "Done %s.\n", __func__); } return rval; @@ -3794,8 +3595,7 @@ qla81xx_restart_mpi_firmware(scsi_qla_host_t *vha) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e5, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10e5, "Entered %s.\n", __func__); mcp->mb[0] = MBC_RESTART_MPI_FW; mcp->out_mb = MBX_0; @@ -3809,8 +3609,7 @@ qla81xx_restart_mpi_firmware(scsi_qla_host_t *vha) "Failed=%x mb[0]=%x mb[1]=%x.\n", rval, mcp->mb[0], mcp->mb[1]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e7, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10e7, "Done %s.\n", __func__); } return rval; @@ -3825,8 +3624,7 @@ qla2x00_read_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp, mbx_cmd_t *mcp = &mc; struct qla_hw_data *ha = vha->hw; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10e8, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10e8, "Entered %s.\n", __func__); if (!IS_FWI2_CAPABLE(ha)) return QLA_FUNCTION_FAILED; @@ -3856,8 +3654,7 @@ qla2x00_read_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp, ql_dbg(ql_dbg_mbx, vha, 0x10e9, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10ea, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10ea, "Done %s.\n", __func__); } return rval; @@ -3872,8 +3669,7 @@ qla2x00_write_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp, mbx_cmd_t *mcp = &mc; struct qla_hw_data *ha = vha->hw; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10eb, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10eb, "Entered %s.\n", __func__); if (!IS_FWI2_CAPABLE(ha)) return QLA_FUNCTION_FAILED; @@ -3903,8 +3699,7 @@ qla2x00_write_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp, ql_dbg(ql_dbg_mbx, vha, 0x10ec, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10ed, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10ed, "Done %s.\n", __func__); } return rval; @@ -3918,8 +3713,7 @@ qla2x00_get_xgmac_stats(scsi_qla_host_t *vha, dma_addr_t stats_dma, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10ee, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10ee, "Entered %s.\n", __func__); if (!IS_CNA_CAPABLE(vha->hw)) return QLA_FUNCTION_FAILED; @@ -3941,8 +3735,7 @@ qla2x00_get_xgmac_stats(scsi_qla_host_t *vha, dma_addr_t stats_dma, "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x.\n", rval, mcp->mb[0], mcp->mb[1], mcp->mb[2]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10f0, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10f0, "Done %s.\n", __func__); *actual_size = mcp->mb[2] << 2; @@ -3959,8 +3752,7 @@ qla2x00_get_dcbx_params(scsi_qla_host_t *vha, dma_addr_t tlv_dma, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10f1, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10f1, "Entered %s.\n", __func__); if (!IS_CNA_CAPABLE(vha->hw)) return QLA_FUNCTION_FAILED; @@ -3983,8 +3775,7 @@ qla2x00_get_dcbx_params(scsi_qla_host_t *vha, dma_addr_t tlv_dma, "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x.\n", rval, mcp->mb[0], mcp->mb[1], mcp->mb[2]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10f3, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10f3, "Done %s.\n", __func__); } return rval; @@ -3997,8 +3788,7 @@ qla2x00_read_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t *data) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10f4, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10f4, "Entered %s.\n", __func__); if (!IS_FWI2_CAPABLE(vha->hw)) return QLA_FUNCTION_FAILED; @@ -4015,8 +3805,7 @@ qla2x00_read_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t *data) ql_dbg(ql_dbg_mbx, vha, 0x10f5, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10f6, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10f6, "Done %s.\n", __func__); *data = mcp->mb[3] << 16 | mcp->mb[2]; } @@ -4032,8 +3821,7 @@ qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, mbx_cmd_t *mcp = &mc; uint32_t iter_cnt = 0x1; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10f7, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10f7, "Entered %s.\n", __func__); memset(mcp->mb, 0 , sizeof(mcp->mb)); mcp->mb[0] = MBC_DIAGNOSTIC_LOOP_BACK; @@ -4077,8 +3865,7 @@ qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, "mb[19]=%x.\n", rval, mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3], mcp->mb[18], mcp->mb[19]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10f9, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10f9, "Done %s.\n", __func__); } /* Copy mailbox information */ @@ -4095,8 +3882,7 @@ qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, mbx_cmd_t *mcp = &mc; struct qla_hw_data *ha = vha->hw; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10fa, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10fa, "Entered %s.\n", __func__); memset(mcp->mb, 0 , sizeof(mcp->mb)); mcp->mb[0] = MBC_DIAGNOSTIC_ECHO; @@ -4140,8 +3926,7 @@ qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, "Failed=%x mb[0]=%x mb[1]=%x.\n", rval, mcp->mb[0], mcp->mb[1]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10fc, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10fc, "Done %s.\n", __func__); } /* Copy mailbox information */ @@ -4156,7 +3941,7 @@ qla84xx_reset_chip(scsi_qla_host_t *vha, uint16_t enable_diagnostic) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10fd, + ql_dbg(ql_dbg_mbx, vha, 0x10fd, "Entered %s enable_diag=%d.\n", __func__, enable_diagnostic); mcp->mb[0] = MBC_ISP84XX_RESET; @@ -4170,8 +3955,7 @@ qla84xx_reset_chip(scsi_qla_host_t *vha, uint16_t enable_diagnostic) if (rval != QLA_SUCCESS) ql_dbg(ql_dbg_mbx, vha, 0x10fe, "Failed=%x.\n", rval); else - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10ff, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10ff, "Done %s.\n", __func__); return rval; } @@ -4183,8 +3967,7 @@ qla2x00_write_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t data) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1100, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1100, "Entered %s.\n", __func__); if (!IS_FWI2_CAPABLE(vha->hw)) return QLA_FUNCTION_FAILED; @@ -4203,8 +3986,7 @@ qla2x00_write_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t data) ql_dbg(ql_dbg_mbx, vha, 0x1101, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1102, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1102, "Done %s.\n", __func__); } return rval; @@ -4221,8 +4003,7 @@ qla81xx_write_mpi_register(scsi_qla_host_t *vha, uint16_t *mb) rval = QLA_SUCCESS; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1103, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1103, "Entered %s.\n", __func__); clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); @@ -4265,8 +4046,7 @@ qla81xx_write_mpi_register(scsi_qla_host_t *vha, uint16_t *mb) ql_dbg(ql_dbg_mbx, vha, 0x1104, "Failed=%x mb[0]=%x.\n", rval, mb[0]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1105, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1105, "Done %s.\n", __func__); } return rval; @@ -4280,8 +4060,7 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha) mbx_cmd_t *mcp = &mc; struct qla_hw_data *ha = vha->hw; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1106, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1106, "Entered %s.\n", __func__); if (!IS_FWI2_CAPABLE(ha)) return QLA_FUNCTION_FAILED; @@ -4299,8 +4078,7 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha) ql_dbg(ql_dbg_mbx, vha, 0x1107, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1108, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1108, "Done %s.\n", __func__); if (mcp->mb[1] != 0x7) ha->link_data_rate = mcp->mb[1]; } @@ -4316,8 +4094,7 @@ qla81xx_get_port_config(scsi_qla_host_t *vha, uint16_t *mb) mbx_cmd_t *mcp = &mc; struct qla_hw_data *ha = vha->hw; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1109, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1109, "Entered %s.\n", __func__); if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha)) return QLA_FUNCTION_FAILED; @@ -4336,8 +4113,7 @@ qla81xx_get_port_config(scsi_qla_host_t *vha, uint16_t *mb) /* Copy all bits to preserve original value */ memcpy(mb, &mcp->mb[1], sizeof(uint16_t) * 4); - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x110b, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x110b, "Done %s.\n", __func__); } return rval; } @@ -4349,8 +4125,7 @@ qla81xx_set_port_config(scsi_qla_host_t *vha, uint16_t *mb) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x110c, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x110c, "Entered %s.\n", __func__); mcp->mb[0] = MBC_SET_PORT_CONFIG; /* Copy all bits to preserve original setting */ @@ -4365,8 +4140,7 @@ qla81xx_set_port_config(scsi_qla_host_t *vha, uint16_t *mb) ql_dbg(ql_dbg_mbx, vha, 0x110d, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); } else - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x110e, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x110e, "Done %s.\n", __func__); return rval; } @@ -4381,8 +4155,7 @@ qla24xx_set_fcp_prio(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t priority, mbx_cmd_t *mcp = &mc; struct qla_hw_data *ha = vha->hw; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x110f, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x110f, "Entered %s.\n", __func__); if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha)) return QLA_FUNCTION_FAILED; @@ -4410,8 +4183,7 @@ qla24xx_set_fcp_prio(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t priority, if (rval != QLA_SUCCESS) { ql_dbg(ql_dbg_mbx, vha, 0x10cd, "Failed=%x.\n", rval); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10cc, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10cc, "Done %s.\n", __func__); } return rval; @@ -4424,8 +4196,7 @@ qla2x00_get_thermal_temp(scsi_qla_host_t *vha, uint16_t *temp, uint16_t *frac) uint8_t byte; struct qla_hw_data *ha = vha->hw; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10ca, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x10ca, "Entered %s.\n", __func__); /* Integer part */ rval = qla2x00_read_sfp(vha, 0, &byte, 0x98, 0x01, 1, BIT_13|BIT_0); @@ -4445,8 +4216,7 @@ qla2x00_get_thermal_temp(scsi_qla_host_t *vha, uint16_t *temp, uint16_t *frac) } *frac = (byte >> 6) * 25; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1018, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1018, "Done %s.\n", __func__); fail: return rval; } @@ -4459,8 +4229,7 @@ qla82xx_mbx_intr_enable(scsi_qla_host_t *vha) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1017, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1017, "Entered %s.\n", __func__); if (!IS_FWI2_CAPABLE(ha)) return QLA_FUNCTION_FAILED; @@ -4479,8 +4248,7 @@ qla82xx_mbx_intr_enable(scsi_qla_host_t *vha) ql_dbg(ql_dbg_mbx, vha, 0x1016, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x100e, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x100e, "Done %s.\n", __func__); } return rval; @@ -4494,8 +4262,7 @@ qla82xx_mbx_intr_disable(scsi_qla_host_t *vha) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x100d, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x100d, "Entered %s.\n", __func__); if (!IS_QLA82XX(ha)) return QLA_FUNCTION_FAILED; @@ -4514,8 +4281,7 @@ qla82xx_mbx_intr_disable(scsi_qla_host_t *vha) ql_dbg(ql_dbg_mbx, vha, 0x100c, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x100b, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x100b, "Done %s.\n", __func__); } return rval; @@ -4529,8 +4295,7 @@ qla82xx_md_get_template_size(scsi_qla_host_t *vha) mbx_cmd_t *mcp = &mc; int rval = QLA_FUNCTION_FAILED; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x111f, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x111f, "Entered %s.\n", __func__); memset(mcp->mb, 0 , sizeof(mcp->mb)); mcp->mb[0] = LSW(MBC_DIAGNOSTIC_MINIDUMP_TEMPLATE); @@ -4553,8 +4318,7 @@ qla82xx_md_get_template_size(scsi_qla_host_t *vha) (mcp->mb[1] << 16) | mcp->mb[0], (mcp->mb[3] << 16) | mcp->mb[2]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1121, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1121, "Done %s.\n", __func__); ha->md_template_size = ((mcp->mb[3] << 16) | mcp->mb[2]); if (!ha->md_template_size) { ql_dbg(ql_dbg_mbx, vha, 0x1122, @@ -4573,8 +4337,7 @@ qla82xx_md_get_template(scsi_qla_host_t *vha) mbx_cmd_t *mcp = &mc; int rval = QLA_FUNCTION_FAILED; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1123, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1123, "Entered %s.\n", __func__); ha->md_tmplt_hdr = dma_alloc_coherent(&ha->pdev->dev, ha->md_template_size, &ha->md_tmplt_hdr_dma, GFP_KERNEL); @@ -4609,8 +4372,7 @@ qla82xx_md_get_template(scsi_qla_host_t *vha) ((mcp->mb[1] << 16) | mcp->mb[0]), ((mcp->mb[3] << 16) | mcp->mb[2])); } else - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1126, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1126, "Done %s.\n", __func__); return rval; } @@ -4625,8 +4387,7 @@ qla81xx_set_led_config(scsi_qla_host_t *vha, uint16_t *led_cfg) if (!IS_QLA81XX(ha) && !IS_QLA8031(ha)) return QLA_FUNCTION_FAILED; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1133, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1133, "Entered %s.\n", __func__); memset(mcp, 0, sizeof(mbx_cmd_t)); mcp->mb[0] = MBC_SET_LED_CONFIG; @@ -4651,8 +4412,7 @@ qla81xx_set_led_config(scsi_qla_host_t *vha, uint16_t *led_cfg) ql_dbg(ql_dbg_mbx, vha, 0x1134, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1135, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1135, "Done %s.\n", __func__); } return rval; @@ -4669,8 +4429,7 @@ qla81xx_get_led_config(scsi_qla_host_t *vha, uint16_t *led_cfg) if (!IS_QLA81XX(ha) && !IS_QLA8031(ha)) return QLA_FUNCTION_FAILED; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1136, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1136, "Entered %s.\n", __func__); memset(mcp, 0, sizeof(mbx_cmd_t)); mcp->mb[0] = MBC_GET_LED_CONFIG; @@ -4695,8 +4454,7 @@ qla81xx_get_led_config(scsi_qla_host_t *vha, uint16_t *led_cfg) led_cfg[4] = mcp->mb[5]; led_cfg[5] = mcp->mb[6]; } - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1138, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1138, "Done %s.\n", __func__); } return rval; @@ -4713,7 +4471,7 @@ qla82xx_mbx_beacon_ctl(scsi_qla_host_t *vha, int enable) if (!IS_QLA82XX(ha)) return QLA_FUNCTION_FAILED; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1127, + ql_dbg(ql_dbg_mbx, vha, 0x1127, "Entered %s.\n", __func__); memset(mcp, 0, sizeof(mbx_cmd_t)); @@ -4733,7 +4491,7 @@ qla82xx_mbx_beacon_ctl(scsi_qla_host_t *vha, int enable) ql_dbg(ql_dbg_mbx, vha, 0x1128, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1129, + ql_dbg(ql_dbg_mbx, vha, 0x1129, "Done %s.\n", __func__); } @@ -4751,8 +4509,7 @@ qla83xx_write_remote_reg(scsi_qla_host_t *vha, uint32_t reg, uint32_t data) if (!IS_QLA83XX(ha)) return QLA_FUNCTION_FAILED; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1130, - "Entered %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x1130, "Entered %s.\n", __func__); mcp->mb[0] = MBC_WRITE_REMOTE_REG; mcp->mb[1] = LSW(reg); @@ -4770,7 +4527,7 @@ qla83xx_write_remote_reg(scsi_qla_host_t *vha, uint32_t reg, uint32_t data) ql_dbg(ql_dbg_mbx, vha, 0x1131, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); } else { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1132, + ql_dbg(ql_dbg_mbx, vha, 0x1132, "Done %s.\n", __func__); } @@ -4786,14 +4543,13 @@ qla2x00_port_logout(scsi_qla_host_t *vha, struct fc_port *fcport) mbx_cmd_t *mcp = &mc; if (IS_QLA2100(ha) || IS_QLA2200(ha)) { - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x113b, + ql_dbg(ql_dbg_mbx, vha, 0x113b, "Implicit LOGO Unsupported.\n"); return QLA_FUNCTION_FAILED; } - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x113c, - "Entering %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x113c, "Done %s.\n", __func__); /* Perform Implicit LOGO. */ mcp->mb[0] = MBC_PORT_LOGOUT; @@ -4808,8 +4564,7 @@ qla2x00_port_logout(scsi_qla_host_t *vha, struct fc_port *fcport) ql_dbg(ql_dbg_mbx, vha, 0x113d, "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); else - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x113e, - "Done %s.\n", __func__); + ql_dbg(ql_dbg_mbx, vha, 0x113e, "Done %s.\n", __func__); return rval; } diff --git a/trunk/drivers/scsi/qla2xxx/qla_mid.c b/trunk/drivers/scsi/qla2xxx/qla_mid.c index 3e8b32419e68..aa062a1b0ca4 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_mid.c +++ b/trunk/drivers/scsi/qla2xxx/qla_mid.c @@ -6,7 +6,6 @@ */ #include "qla_def.h" #include "qla_gbl.h" -#include "qla_target.h" #include #include @@ -50,9 +49,6 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha) spin_lock_irqsave(&ha->vport_slock, flags); list_add_tail(&vha->list, &ha->vp_list); - - qlt_update_vp_map(vha, SET_VP_IDX); - spin_unlock_irqrestore(&ha->vport_slock, flags); mutex_unlock(&ha->vport_lock); @@ -83,7 +79,6 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha) spin_lock_irqsave(&ha->vport_slock, flags); } list_del(&vha->list); - qlt_update_vp_map(vha, RESET_VP_IDX); spin_unlock_irqrestore(&ha->vport_slock, flags); vp_id = vha->vp_idx; @@ -139,7 +134,7 @@ qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha) list_for_each_entry(fcport, &vha->vp_fcports, list) { ql_dbg(ql_dbg_vport, vha, 0xa001, "Marking port dead, loop_id=0x%04x : %x.\n", - fcport->loop_id, fcport->vha->vp_idx); + fcport->loop_id, fcport->vp_idx); qla2x00_mark_device_lost(vha, fcport, 0, 0); qla2x00_set_fcport_state(fcport, FCS_UNCONFIGURED); @@ -155,9 +150,6 @@ qla24xx_disable_vp(scsi_qla_host_t *vha) atomic_set(&vha->loop_state, LOOP_DOWN); atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); - /* Remove port id from vp target map */ - qlt_update_vp_map(vha, RESET_AL_PA); - qla2x00_mark_vp_devices_dead(vha); atomic_set(&vha->vp_state, VP_FAILED); vha->flags.management_server_logged_in = 0; @@ -303,8 +295,10 @@ qla2x00_vp_abort_isp(scsi_qla_host_t *vha) static int qla2x00_do_dpc_vp(scsi_qla_host_t *vha) { - ql_dbg(ql_dbg_dpc + ql_dbg_verbose, vha, 0x4012, - "Entering %s vp_flags: 0x%lx.\n", __func__, vha->vp_flags); + ql_dbg(ql_dbg_dpc, vha, 0x4012, + "Entering %s.\n", __func__); + ql_dbg(ql_dbg_dpc, vha, 0x4013, + "vp_flags: 0x%lx.\n", vha->vp_flags); qla2x00_do_work(vha); @@ -354,7 +348,7 @@ qla2x00_do_dpc_vp(scsi_qla_host_t *vha) } } - ql_dbg(ql_dbg_dpc + ql_dbg_verbose, vha, 0x401c, + ql_dbg(ql_dbg_dpc, vha, 0x401c, "Exiting %s.\n", __func__); return 0; } diff --git a/trunk/drivers/scsi/qla2xxx/qla_nx.c b/trunk/drivers/scsi/qla2xxx/qla_nx.c index caf627ba7fa8..de722a933438 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_nx.c +++ b/trunk/drivers/scsi/qla2xxx/qla_nx.c @@ -1190,12 +1190,12 @@ qla82xx_pinit_from_rom(scsi_qla_host_t *vha) } /* Offset in flash = lower 16 bits - * Number of entries = upper 16 bits + * Number of enteries = upper 16 bits */ offset = n & 0xffffU; n = (n >> 16) & 0xffffU; - /* number of addr/value pair should not exceed 1024 entries */ + /* number of addr/value pair should not exceed 1024 enteries */ if (n >= 1024) { ql_log(ql_log_fatal, vha, 0x0071, "Card flash not initialized:n=0x%x.\n", n); @@ -2050,7 +2050,7 @@ qla82xx_intr_handler(int irq, void *dev_id) rsp = (struct rsp_que *) dev_id; if (!rsp) { - ql_log(ql_log_info, NULL, 0xb053, + ql_log(ql_log_info, NULL, 0xb054, "%s: NULL response queue pointer.\n", __func__); return IRQ_NONE; } @@ -2446,7 +2446,7 @@ qla82xx_load_fw(scsi_qla_host_t *vha) if (qla82xx_fw_load_from_flash(ha) == QLA_SUCCESS) { ql_log(ql_log_info, vha, 0x00a1, - "Firmware loaded successfully from flash.\n"); + "Firmware loaded successully from flash.\n"); return QLA_SUCCESS; } else { ql_log(ql_log_warn, vha, 0x0108, @@ -2461,7 +2461,7 @@ qla82xx_load_fw(scsi_qla_host_t *vha) blob = ha->hablob = qla2x00_request_firmware(vha); if (!blob) { ql_log(ql_log_fatal, vha, 0x00a3, - "Firmware image not present.\n"); + "Firmware image not preset.\n"); goto fw_load_failed; } @@ -2689,7 +2689,7 @@ qla82xx_write_flash_data(struct scsi_qla_host *vha, uint32_t *dwptr, if (!optrom) { ql_log(ql_log_warn, vha, 0xb01b, "Unable to allocate memory " - "for optrom burst write (%x KB).\n", + "for optron burst write (%x KB).\n", OPTROM_BURST_SIZE / 1024); } } @@ -2960,8 +2960,9 @@ qla82xx_need_qsnt_handler(scsi_qla_host_t *vha) * changing the state to DEV_READY */ ql_log(ql_log_info, vha, 0xb023, - "%s : QUIESCENT TIMEOUT DRV_ACTIVE:%d " - "DRV_STATE:%d.\n", QLA2XXX_DRIVER_NAME, + "%s : QUIESCENT TIMEOUT.\n", QLA2XXX_DRIVER_NAME); + ql_log(ql_log_info, vha, 0xb024, + "DRV_ACTIVE:%d DRV_STATE:%d.\n", drv_active, drv_state); qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_READY); @@ -3128,7 +3129,7 @@ qla82xx_need_reset_handler(scsi_qla_host_t *vha) if (ql2xmdenable) { if (qla82xx_md_collect(vha)) ql_log(ql_log_warn, vha, 0xb02c, - "Minidump not collected.\n"); + "Not able to collect minidump.\n"); } else ql_log(ql_log_warn, vha, 0xb04f, "Minidump disabled.\n"); @@ -3159,11 +3160,11 @@ qla82xx_check_md_needed(scsi_qla_host_t *vha) "Firmware version differs " "Previous version: %d:%d:%d - " "New version: %d:%d:%d\n", - fw_major_version, fw_minor_version, - fw_subminor_version, ha->fw_major_version, ha->fw_minor_version, - ha->fw_subminor_version); + ha->fw_subminor_version, + fw_major_version, fw_minor_version, + fw_subminor_version); /* Release MiniDump resources */ qla82xx_md_free(vha); /* ALlocate MiniDump resources */ @@ -3324,30 +3325,6 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha) return rval; } -static int qla82xx_check_temp(scsi_qla_host_t *vha) -{ - uint32_t temp, temp_state, temp_val; - struct qla_hw_data *ha = vha->hw; - - temp = qla82xx_rd_32(ha, CRB_TEMP_STATE); - temp_state = qla82xx_get_temp_state(temp); - temp_val = qla82xx_get_temp_val(temp); - - if (temp_state == QLA82XX_TEMP_PANIC) { - ql_log(ql_log_warn, vha, 0x600e, - "Device temperature %d degrees C exceeds " - " maximum allowed. Hardware has been shut down.\n", - temp_val); - return 1; - } else if (temp_state == QLA82XX_TEMP_WARN) { - ql_log(ql_log_warn, vha, 0x600f, - "Device temperature %d degrees C exceeds " - "operating range. Immediate action needed.\n", - temp_val); - } - return 0; -} - void qla82xx_clear_pending_mbx(scsi_qla_host_t *vha) { struct qla_hw_data *ha = vha->hw; @@ -3370,20 +3347,18 @@ void qla82xx_watchdog(scsi_qla_host_t *vha) /* don't poll if reset is going on */ if (!ha->flags.isp82xx_reset_hdlr_active) { dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - if (qla82xx_check_temp(vha)) { - set_bit(ISP_UNRECOVERABLE, &vha->dpc_flags); - ha->flags.isp82xx_fw_hung = 1; - qla82xx_clear_pending_mbx(vha); - } else if (dev_state == QLA82XX_DEV_NEED_RESET && + if (dev_state == QLA82XX_DEV_NEED_RESET && !test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) { ql_log(ql_log_warn, vha, 0x6001, "Adapter reset needed.\n"); set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT && !test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags)) { ql_log(ql_log_warn, vha, 0x6002, "Quiescent needed.\n"); set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); } else { if (qla82xx_check_fw_alive(vha)) { ql_dbg(ql_dbg_timer, vha, 0x6011, @@ -3423,6 +3398,7 @@ void qla82xx_watchdog(scsi_qla_host_t *vha) set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); } + qla2xxx_wake_dpc(vha); ha->flags.isp82xx_fw_hung = 1; ql_log(ql_log_warn, vha, 0x6007, "Firmware hung.\n"); qla82xx_clear_pending_mbx(vha); @@ -4137,14 +4113,6 @@ qla82xx_md_collect(scsi_qla_host_t *vha) goto md_failed; } - if (ha->flags.isp82xx_no_md_cap) { - ql_log(ql_log_warn, vha, 0xb054, - "Forced reset from application, " - "ignore minidump capture\n"); - ha->flags.isp82xx_no_md_cap = 0; - goto md_failed; - } - if (qla82xx_validate_template_chksum(vha)) { ql_log(ql_log_info, vha, 0xb039, "Template checksum validation error\n"); diff --git a/trunk/drivers/scsi/qla2xxx/qla_nx.h b/trunk/drivers/scsi/qla2xxx/qla_nx.h index 6eb210e3cc63..4ac50e274661 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_nx.h +++ b/trunk/drivers/scsi/qla2xxx/qla_nx.h @@ -26,7 +26,6 @@ #define CRB_RCVPEG_STATE QLA82XX_REG(0x13c) #define BOOT_LOADER_DIMM_STATUS QLA82XX_REG(0x54) #define CRB_DMA_SHIFT QLA82XX_REG(0xcc) -#define CRB_TEMP_STATE QLA82XX_REG(0x1b4) #define QLA82XX_DMA_SHIFT_VALUE 0x55555555 #define QLA82XX_HW_H0_CH_HUB_ADR 0x05 @@ -562,6 +561,7 @@ #define QLA82XX_FW_VERSION_SUB (QLA82XX_CAM_RAM(0x158)) #define QLA82XX_PCIE_REG(reg) (QLA82XX_CRB_PCIE + (reg)) +#define PCIE_CHICKEN3 (0x120c8) #define PCIE_SETUP_FUNCTION (0x12040) #define PCIE_SETUP_FUNCTION2 (0x12048) @@ -1178,16 +1178,4 @@ static const int MD_MIU_TEST_AGT_RDDATA[] = { 0x410000A8, 0x410000AC, #define CRB_NIU_XG_PAUSE_CTL_P0 0x1 #define CRB_NIU_XG_PAUSE_CTL_P1 0x8 -#define qla82xx_get_temp_val(x) ((x) >> 16) -#define qla82xx_get_temp_state(x) ((x) & 0xffff) -#define qla82xx_encode_temp(val, state) (((val) << 16) | (state)) - -/* - * Temperature control. - */ -enum { - QLA82XX_TEMP_NORMAL = 0x1, /* Normal operating range */ - QLA82XX_TEMP_WARN, /* Sound alert, temperature getting high */ - QLA82XX_TEMP_PANIC /* Fatal error, hardware has shut down. */ -}; #endif diff --git a/trunk/drivers/scsi/qla2xxx/qla_os.c b/trunk/drivers/scsi/qla2xxx/qla_os.c index 6d1d873a20e2..c9c56a8427f3 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_os.c +++ b/trunk/drivers/scsi/qla2xxx/qla_os.c @@ -13,13 +13,12 @@ #include #include #include + #include #include #include #include -#include "qla_target.h" - /* * Driver version */ @@ -41,12 +40,6 @@ static struct kmem_cache *ctx_cachep; */ int ql_errlev = ql_log_all; -int ql2xenableclass2; -module_param(ql2xenableclass2, int, S_IRUGO|S_IRUSR); -MODULE_PARM_DESC(ql2xenableclass2, - "Specify if Class 2 operations are supported from the very " - "beginning. Default is 0 - class 2 not supported."); - int ql2xlogintimeout = 20; module_param(ql2xlogintimeout, int, S_IRUGO); MODULE_PARM_DESC(ql2xlogintimeout, @@ -262,8 +255,6 @@ struct scsi_host_template qla2xxx_driver_template = { .max_sectors = 0xFFFF, .shost_attrs = qla2x00_host_attrs, - - .supported_mode = MODE_INITIATOR, }; static struct scsi_transport_template *qla2xxx_transport_template = NULL; @@ -315,8 +306,7 @@ static void qla2x00_free_fw_dump(struct qla_hw_data *); static void qla2x00_mem_free(struct qla_hw_data *); /* -------------------------------------------------------------------------- */ -static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req, - struct rsp_que *rsp) +static int qla2x00_alloc_queues(struct qla_hw_data *ha) { scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); ha->req_q_map = kzalloc(sizeof(struct req_que *) * ha->max_req_queues, @@ -334,12 +324,6 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req, "Unable to allocate memory for response queue ptrs.\n"); goto fail_rsp_map; } - /* - * Make sure we record at least the request and response queue zero in - * case we need to free them if part of the probe fails. - */ - ha->rsp_q_map[0] = rsp; - ha->req_q_map[0] = req; set_bit(0, ha->rsp_qid_map); set_bit(0, ha->req_qid_map); return 1; @@ -658,12 +642,12 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) if (ha->flags.eeh_busy) { if (ha->flags.pci_channel_io_perm_failure) { - ql_dbg(ql_dbg_aer, vha, 0x9010, + ql_dbg(ql_dbg_io, vha, 0x3001, "PCI Channel IO permanent failure, exiting " "cmd=%p.\n", cmd); cmd->result = DID_NO_CONNECT << 16; } else { - ql_dbg(ql_dbg_aer, vha, 0x9011, + ql_dbg(ql_dbg_io, vha, 0x3002, "EEH_Busy, Requeuing the cmd=%p.\n", cmd); cmd->result = DID_REQUEUE << 16; } @@ -673,7 +657,7 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) rval = fc_remote_port_chkready(rport); if (rval) { cmd->result = rval; - ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x3003, + ql_dbg(ql_dbg_io, vha, 0x3003, "fc_remote_port_chkready failed for cmd=%p, rval=0x%x.\n", cmd, rval); goto qc24_fail_command; @@ -1152,7 +1136,7 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) ret = FAILED; ql_log(ql_log_info, vha, 0x8012, - "BUS RESET ISSUED nexus=%ld:%d:%d.\n", vha->host_no, id, lun); + "BUS RESET ISSUED nexus=%ld:%d%d.\n", vha->host_no, id, lun); if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) { ql_log(ql_log_fatal, vha, 0x8013, @@ -2196,7 +2180,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ql_dbg_pci(ql_dbg_init, pdev, 0x000a, "Memory allocated for ha=%p.\n", ha); ha->pdev = pdev; - ha->tgt.enable_class_2 = ql2xenableclass2; /* Clear our data area */ ha->bars = bars; @@ -2260,7 +2243,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->mbx_count = MAILBOX_REGISTER_COUNT; req_length = REQUEST_ENTRY_CNT_24XX; rsp_length = RESPONSE_ENTRY_CNT_2300; - ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX; ha->max_loop_id = SNS_LAST_LOOP_ID_2300; ha->init_cb_size = sizeof(struct mid_init_cb_24xx); ha->gid_list_info_size = 8; @@ -2276,7 +2258,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->mbx_count = MAILBOX_REGISTER_COUNT; req_length = REQUEST_ENTRY_CNT_24XX; rsp_length = RESPONSE_ENTRY_CNT_2300; - ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX; ha->max_loop_id = SNS_LAST_LOOP_ID_2300; ha->init_cb_size = sizeof(struct mid_init_cb_24xx); ha->gid_list_info_size = 8; @@ -2436,17 +2417,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) host->max_cmd_len, host->max_channel, host->max_lun, host->transportt, sht->vendor_id); -que_init: - /* Alloc arrays of request and response ring ptrs */ - if (!qla2x00_alloc_queues(ha, req, rsp)) { - ql_log(ql_log_fatal, base_vha, 0x003d, - "Failed to allocate memory for queue pointers..." - "aborting.\n"); - goto probe_init_failed; - } - - qlt_probe_one_stage1(base_vha, ha); - /* Set up the irqs */ ret = qla2x00_request_irqs(ha, rsp); if (ret) @@ -2454,10 +2424,20 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) pci_save_state(pdev); - /* Assign back pointers */ + /* Alloc arrays of request and response ring ptrs */ +que_init: + if (!qla2x00_alloc_queues(ha)) { + ql_log(ql_log_fatal, base_vha, 0x003d, + "Failed to allocate memory for queue pointers.. aborting.\n"); + goto probe_init_failed; + } + + ha->rsp_q_map[0] = rsp; + ha->req_q_map[0] = req; rsp->req = req; req->rsp = rsp; - + set_bit(0, ha->req_qid_map); + set_bit(0, ha->rsp_qid_map); /* FWI2-capable only. */ req->req_q_in = &ha->iobase->isp24.req_q_in; req->req_q_out = &ha->iobase->isp24.req_q_out; @@ -2534,14 +2514,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ql_dbg(ql_dbg_init, base_vha, 0x00ee, "DPC thread started successfully.\n"); - /* - * If we're not coming up in initiator mode, we might sit for - * a while without waking up the dpc thread, which leads to a - * stuck process warning. So just kick the dpc once here and - * let the kthread start (and go back to sleep in qla2x00_do_dpc). - */ - qla2xxx_wake_dpc(base_vha); - skip_dpc: list_add_tail(&base_vha->list, &ha->vp_list); base_vha->host->irq = ha->pdev->irq; @@ -2587,11 +2559,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ql_dbg(ql_dbg_init, base_vha, 0x00f2, "Init done and hba is online.\n"); - if (qla_ini_mode_enabled(base_vha)) - scsi_scan_host(host); - else - ql_dbg(ql_dbg_init, base_vha, 0x0122, - "skipping scsi_scan_host() for non-initiator port\n"); + scsi_scan_host(host); qla2x00_alloc_sysfs_attr(base_vha); @@ -2609,17 +2577,11 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) base_vha->host_no, ha->isp_ops->fw_version_str(base_vha, fw_str)); - qlt_add_target(ha, base_vha); - return 0; probe_init_failed: qla2x00_free_req_que(ha, req); - ha->req_q_map[0] = NULL; - clear_bit(0, ha->req_qid_map); qla2x00_free_rsp_que(ha, rsp); - ha->rsp_q_map[0] = NULL; - clear_bit(0, ha->rsp_qid_map); ha->max_req_queues = ha->max_rsp_queues = 0; probe_failed: @@ -2658,22 +2620,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) return ret; } -static void -qla2x00_stop_dpc_thread(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - struct task_struct *t = ha->dpc_thread; - - if (ha->dpc_thread == NULL) - return; - /* - * qla2xxx_wake_dpc checks for ->dpc_thread - * so we need to zero it out. - */ - ha->dpc_thread = NULL; - kthread_stop(t); -} - static void qla2x00_shutdown(struct pci_dev *pdev) { @@ -2717,18 +2663,9 @@ qla2x00_remove_one(struct pci_dev *pdev) struct qla_hw_data *ha; unsigned long flags; - /* - * If the PCI device is disabled that means that probe failed and any - * resources should be have cleaned up on probe exit. - */ - if (!atomic_read(&pdev->enable_cnt)) - return; - base_vha = pci_get_drvdata(pdev); ha = base_vha->hw; - ha->flags.host_shutting_down = 1; - mutex_lock(&ha->vport_lock); while (ha->cur_vport_count) { struct Scsi_Host *scsi_host; @@ -2782,7 +2719,6 @@ qla2x00_remove_one(struct pci_dev *pdev) ha->dpc_thread = NULL; kthread_stop(t); } - qlt_remove_target(ha, base_vha); qla2x00_free_sysfs_attr(base_vha); @@ -2834,7 +2770,17 @@ qla2x00_free_device(scsi_qla_host_t *vha) if (vha->timer_active) qla2x00_stop_timer(vha); - qla2x00_stop_dpc_thread(vha); + /* Kill the kernel thread for this host */ + if (ha->dpc_thread) { + struct task_struct *t = ha->dpc_thread; + + /* + * qla2xxx_wake_dpc checks for ->dpc_thread + * so we need to zero it out. + */ + ha->dpc_thread = NULL; + kthread_stop(t); + } qla25xx_delete_queues(vha); @@ -2896,10 +2842,8 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport, spin_unlock_irqrestore(vha->host->host_lock, flags); set_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags); qla2xxx_wake_dpc(base_vha); - } else { + } else fc_remote_port_delete(rport); - qlt_fc_port_deleted(vha, fcport); - } } /* @@ -2915,7 +2859,7 @@ void qla2x00_mark_device_lost(scsi_qla_host_t *vha, fc_port_t *fcport, int do_login, int defer) { if (atomic_read(&fcport->state) == FCS_ONLINE && - vha->vp_idx == fcport->vha->vp_idx) { + vha->vp_idx == fcport->vp_idx) { qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST); qla2x00_schedule_rport_del(vha, fcport, defer); } @@ -2964,7 +2908,7 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha, int defer) fc_port_t *fcport; list_for_each_entry(fcport, &vha->vp_fcports, list) { - if (vha->vp_idx != 0 && vha->vp_idx != fcport->vha->vp_idx) + if (vha->vp_idx != 0 && vha->vp_idx != fcport->vp_idx) continue; /* @@ -2977,7 +2921,7 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha, int defer) qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST); if (defer) qla2x00_schedule_rport_del(vha, fcport, defer); - else if (vha->vp_idx == fcport->vha->vp_idx) + else if (vha->vp_idx == fcport->vp_idx) qla2x00_schedule_rport_del(vha, fcport, defer); } } @@ -3002,13 +2946,10 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, if (!ha->init_cb) goto fail; - if (qlt_mem_alloc(ha) < 0) - goto fail_free_init_cb; - ha->gid_list = dma_alloc_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha), &ha->gid_list_dma, GFP_KERNEL); if (!ha->gid_list) - goto fail_free_tgt_mem; + goto fail_free_init_cb; ha->srb_mempool = mempool_create_slab_pool(SRB_MIN_REQ, srb_cachep); if (!ha->srb_mempool) @@ -3226,8 +3167,6 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, ha->gid_list_dma); ha->gid_list = NULL; ha->gid_list_dma = 0; -fail_free_tgt_mem: - qlt_mem_free(ha); fail_free_init_cb: dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, ha->init_cb, ha->init_cb_dma); @@ -3343,8 +3282,6 @@ qla2x00_mem_free(struct qla_hw_data *ha) if (ha->ctx_mempool) mempool_destroy(ha->ctx_mempool); - qlt_mem_free(ha); - if (ha->init_cb) dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, ha->init_cb, ha->init_cb_dma); @@ -3374,10 +3311,6 @@ qla2x00_mem_free(struct qla_hw_data *ha) ha->gid_list = NULL; ha->gid_list_dma = 0; - - ha->tgt.atio_ring = NULL; - ha->tgt.atio_dma = 0; - ha->tgt.tgt_vp_map = NULL; } struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, @@ -3738,9 +3671,10 @@ qla2x00_do_dpc(void *data) ha->dpc_active = 1; - ql_dbg(ql_dbg_dpc + ql_dbg_verbose, base_vha, 0x4001, - "DPC handler waking up, dpc_flags=0x%lx.\n", - base_vha->dpc_flags); + ql_dbg(ql_dbg_dpc, base_vha, 0x4001, + "DPC handler waking up.\n"); + ql_dbg(ql_dbg_dpc, base_vha, 0x4002, + "dpc_flags=0x%lx.\n", base_vha->dpc_flags); qla2x00_do_work(base_vha); @@ -3806,16 +3740,6 @@ qla2x00_do_dpc(void *data) clear_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags); } - if (test_bit(SCR_PENDING, &base_vha->dpc_flags)) { - int ret; - ret = qla2x00_send_change_request(base_vha, 0x3, 0); - if (ret != QLA_SUCCESS) - ql_log(ql_log_warn, base_vha, 0x121, - "Failed to enable receiving of RSCN " - "requests: 0x%x.\n", ret); - clear_bit(SCR_PENDING, &base_vha->dpc_flags); - } - if (test_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags)) { ql_dbg(ql_dbg_dpc, base_vha, 0x4009, "Quiescence mode scheduled.\n"); @@ -4533,21 +4457,6 @@ qla2x00_module_init(void) return -ENOMEM; } - /* Initialize target kmem_cache and mem_pools */ - ret = qlt_init(); - if (ret < 0) { - kmem_cache_destroy(srb_cachep); - return ret; - } else if (ret > 0) { - /* - * If initiator mode is explictly disabled by qlt_init(), - * prevent scsi_transport_fc.c:fc_scsi_scan_rport() from - * performing scsi_scan_target() during LOOP UP event. - */ - qla2xxx_transport_functions.disable_target_scan = 1; - qla2xxx_transport_vport_functions.disable_target_scan = 1; - } - /* Derive version string. */ strcpy(qla2x00_version_str, QLA2XXX_VERSION); if (ql2xextended_error_logging) @@ -4559,7 +4468,6 @@ qla2x00_module_init(void) kmem_cache_destroy(srb_cachep); ql_log(ql_log_fatal, NULL, 0x0002, "fc_attach_transport failed...Failing load!.\n"); - qlt_exit(); return -ENODEV; } @@ -4573,7 +4481,6 @@ qla2x00_module_init(void) fc_attach_transport(&qla2xxx_transport_vport_functions); if (!qla2xxx_transport_vport_template) { kmem_cache_destroy(srb_cachep); - qlt_exit(); fc_release_transport(qla2xxx_transport_template); ql_log(ql_log_fatal, NULL, 0x0004, "fc_attach_transport vport failed...Failing load!.\n"); @@ -4585,7 +4492,6 @@ qla2x00_module_init(void) ret = pci_register_driver(&qla2xxx_pci_driver); if (ret) { kmem_cache_destroy(srb_cachep); - qlt_exit(); fc_release_transport(qla2xxx_transport_template); fc_release_transport(qla2xxx_transport_vport_template); ql_log(ql_log_fatal, NULL, 0x0006, @@ -4605,7 +4511,6 @@ qla2x00_module_exit(void) pci_unregister_driver(&qla2xxx_pci_driver); qla2x00_release_firmware(); kmem_cache_destroy(srb_cachep); - qlt_exit(); if (ctx_cachep) kmem_cache_destroy(ctx_cachep); fc_release_transport(qla2xxx_transport_template); diff --git a/trunk/drivers/scsi/qla2xxx/qla_target.c b/trunk/drivers/scsi/qla2xxx/qla_target.c deleted file mode 100644 index 04f80ebf09eb..000000000000 --- a/trunk/drivers/scsi/qla2xxx/qla_target.c +++ /dev/null @@ -1,4973 +0,0 @@ -/* - * qla_target.c SCSI LLD infrastructure for QLogic 22xx/23xx/24xx/25xx - * - * based on qla2x00t.c code: - * - * Copyright (C) 2004 - 2010 Vladislav Bolkhovitin - * Copyright (C) 2004 - 2005 Leonid Stoljar - * Copyright (C) 2006 Nathaniel Clark - * Copyright (C) 2006 - 2010 ID7 Ltd. - * - * Forward port and refactoring to modern qla2xxx and target/configfs - * - * Copyright (C) 2010-2011 Nicholas A. Bellinger - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2 - * of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "qla_def.h" -#include "qla_target.h" - -static char *qlini_mode = QLA2XXX_INI_MODE_STR_ENABLED; -module_param(qlini_mode, charp, S_IRUGO); -MODULE_PARM_DESC(qlini_mode, - "Determines when initiator mode will be enabled. Possible values: " - "\"exclusive\" - initiator mode will be enabled on load, " - "disabled on enabling target mode and then on disabling target mode " - "enabled back; " - "\"disabled\" - initiator mode will never be enabled; " - "\"enabled\" (default) - initiator mode will always stay enabled."); - -static int ql2x_ini_mode = QLA2XXX_INI_MODE_EXCLUSIVE; - -/* - * From scsi/fc/fc_fcp.h - */ -enum fcp_resp_rsp_codes { - FCP_TMF_CMPL = 0, - FCP_DATA_LEN_INVALID = 1, - FCP_CMND_FIELDS_INVALID = 2, - FCP_DATA_PARAM_MISMATCH = 3, - FCP_TMF_REJECTED = 4, - FCP_TMF_FAILED = 5, - FCP_TMF_INVALID_LUN = 9, -}; - -/* - * fc_pri_ta from scsi/fc/fc_fcp.h - */ -#define FCP_PTA_SIMPLE 0 /* simple task attribute */ -#define FCP_PTA_HEADQ 1 /* head of queue task attribute */ -#define FCP_PTA_ORDERED 2 /* ordered task attribute */ -#define FCP_PTA_ACA 4 /* auto. contigent allegiance */ -#define FCP_PTA_MASK 7 /* mask for task attribute field */ -#define FCP_PRI_SHIFT 3 /* priority field starts in bit 3 */ -#define FCP_PRI_RESVD_MASK 0x80 /* reserved bits in priority field */ - -/* - * This driver calls qla2x00_alloc_iocbs() and qla2x00_issue_marker(), which - * must be called under HW lock and could unlock/lock it inside. - * It isn't an issue, since in the current implementation on the time when - * those functions are called: - * - * - Either context is IRQ and only IRQ handler can modify HW data, - * including rings related fields, - * - * - Or access to target mode variables from struct qla_tgt doesn't - * cross those functions boundaries, except tgt_stop, which - * additionally protected by irq_cmd_count. - */ -/* Predefs for callbacks handed to qla2xxx LLD */ -static void qlt_24xx_atio_pkt(struct scsi_qla_host *ha, - struct atio_from_isp *pkt); -static void qlt_response_pkt(struct scsi_qla_host *ha, response_t *pkt); -static int qlt_issue_task_mgmt(struct qla_tgt_sess *sess, uint32_t lun, - int fn, void *iocb, int flags); -static void qlt_send_term_exchange(struct scsi_qla_host *ha, struct qla_tgt_cmd - *cmd, struct atio_from_isp *atio, int ha_locked); -static void qlt_reject_free_srr_imm(struct scsi_qla_host *ha, - struct qla_tgt_srr_imm *imm, int ha_lock); -/* - * Global Variables - */ -static struct kmem_cache *qla_tgt_cmd_cachep; -static struct kmem_cache *qla_tgt_mgmt_cmd_cachep; -static mempool_t *qla_tgt_mgmt_cmd_mempool; -static struct workqueue_struct *qla_tgt_wq; -static DEFINE_MUTEX(qla_tgt_mutex); -static LIST_HEAD(qla_tgt_glist); - -/* ha->hardware_lock supposed to be held on entry (to protect tgt->sess_list) */ -static struct qla_tgt_sess *qlt_find_sess_by_port_name( - struct qla_tgt *tgt, - const uint8_t *port_name) -{ - struct qla_tgt_sess *sess; - - list_for_each_entry(sess, &tgt->sess_list, sess_list_entry) { - if (!memcmp(sess->port_name, port_name, WWN_SIZE)) - return sess; - } - - return NULL; -} - -/* Might release hw lock, then reaquire!! */ -static inline int qlt_issue_marker(struct scsi_qla_host *vha, int vha_locked) -{ - /* Send marker if required */ - if (unlikely(vha->marker_needed != 0)) { - int rc = qla2x00_issue_marker(vha, vha_locked); - if (rc != QLA_SUCCESS) { - ql_dbg(ql_dbg_tgt, vha, 0xe03d, - "qla_target(%d): issue_marker() failed\n", - vha->vp_idx); - } - return rc; - } - return QLA_SUCCESS; -} - -static inline -struct scsi_qla_host *qlt_find_host_by_d_id(struct scsi_qla_host *vha, - uint8_t *d_id) -{ - struct qla_hw_data *ha = vha->hw; - uint8_t vp_idx; - - if ((vha->d_id.b.area != d_id[1]) || (vha->d_id.b.domain != d_id[0])) - return NULL; - - if (vha->d_id.b.al_pa == d_id[2]) - return vha; - - BUG_ON(ha->tgt.tgt_vp_map == NULL); - vp_idx = ha->tgt.tgt_vp_map[d_id[2]].idx; - if (likely(test_bit(vp_idx, ha->vp_idx_map))) - return ha->tgt.tgt_vp_map[vp_idx].vha; - - return NULL; -} - -static inline -struct scsi_qla_host *qlt_find_host_by_vp_idx(struct scsi_qla_host *vha, - uint16_t vp_idx) -{ - struct qla_hw_data *ha = vha->hw; - - if (vha->vp_idx == vp_idx) - return vha; - - BUG_ON(ha->tgt.tgt_vp_map == NULL); - if (likely(test_bit(vp_idx, ha->vp_idx_map))) - return ha->tgt.tgt_vp_map[vp_idx].vha; - - return NULL; -} - -void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha, - struct atio_from_isp *atio) -{ - switch (atio->u.raw.entry_type) { - case ATIO_TYPE7: - { - struct scsi_qla_host *host = qlt_find_host_by_d_id(vha, - atio->u.isp24.fcp_hdr.d_id); - if (unlikely(NULL == host)) { - ql_dbg(ql_dbg_tgt, vha, 0xe03e, - "qla_target(%d): Received ATIO_TYPE7 " - "with unknown d_id %x:%x:%x\n", vha->vp_idx, - atio->u.isp24.fcp_hdr.d_id[0], - atio->u.isp24.fcp_hdr.d_id[1], - atio->u.isp24.fcp_hdr.d_id[2]); - break; - } - qlt_24xx_atio_pkt(host, atio); - break; - } - - case IMMED_NOTIFY_TYPE: - { - struct scsi_qla_host *host = vha; - struct imm_ntfy_from_isp *entry = - (struct imm_ntfy_from_isp *)atio; - - if ((entry->u.isp24.vp_index != 0xFF) && - (entry->u.isp24.nport_handle != 0xFFFF)) { - host = qlt_find_host_by_vp_idx(vha, - entry->u.isp24.vp_index); - if (unlikely(!host)) { - ql_dbg(ql_dbg_tgt, vha, 0xe03f, - "qla_target(%d): Received " - "ATIO (IMMED_NOTIFY_TYPE) " - "with unknown vp_index %d\n", - vha->vp_idx, entry->u.isp24.vp_index); - break; - } - } - qlt_24xx_atio_pkt(host, atio); - break; - } - - default: - ql_dbg(ql_dbg_tgt, vha, 0xe040, - "qla_target(%d): Received unknown ATIO atio " - "type %x\n", vha->vp_idx, atio->u.raw.entry_type); - break; - } - - return; -} - -void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, response_t *pkt) -{ - switch (pkt->entry_type) { - case CTIO_TYPE7: - { - struct ctio7_from_24xx *entry = (struct ctio7_from_24xx *)pkt; - struct scsi_qla_host *host = qlt_find_host_by_vp_idx(vha, - entry->vp_index); - if (unlikely(!host)) { - ql_dbg(ql_dbg_tgt, vha, 0xe041, - "qla_target(%d): Response pkt (CTIO_TYPE7) " - "received, with unknown vp_index %d\n", - vha->vp_idx, entry->vp_index); - break; - } - qlt_response_pkt(host, pkt); - break; - } - - case IMMED_NOTIFY_TYPE: - { - struct scsi_qla_host *host = vha; - struct imm_ntfy_from_isp *entry = - (struct imm_ntfy_from_isp *)pkt; - - host = qlt_find_host_by_vp_idx(vha, entry->u.isp24.vp_index); - if (unlikely(!host)) { - ql_dbg(ql_dbg_tgt, vha, 0xe042, - "qla_target(%d): Response pkt (IMMED_NOTIFY_TYPE) " - "received, with unknown vp_index %d\n", - vha->vp_idx, entry->u.isp24.vp_index); - break; - } - qlt_response_pkt(host, pkt); - break; - } - - case NOTIFY_ACK_TYPE: - { - struct scsi_qla_host *host = vha; - struct nack_to_isp *entry = (struct nack_to_isp *)pkt; - - if (0xFF != entry->u.isp24.vp_index) { - host = qlt_find_host_by_vp_idx(vha, - entry->u.isp24.vp_index); - if (unlikely(!host)) { - ql_dbg(ql_dbg_tgt, vha, 0xe043, - "qla_target(%d): Response " - "pkt (NOTIFY_ACK_TYPE) " - "received, with unknown " - "vp_index %d\n", vha->vp_idx, - entry->u.isp24.vp_index); - break; - } - } - qlt_response_pkt(host, pkt); - break; - } - - case ABTS_RECV_24XX: - { - struct abts_recv_from_24xx *entry = - (struct abts_recv_from_24xx *)pkt; - struct scsi_qla_host *host = qlt_find_host_by_vp_idx(vha, - entry->vp_index); - if (unlikely(!host)) { - ql_dbg(ql_dbg_tgt, vha, 0xe044, - "qla_target(%d): Response pkt " - "(ABTS_RECV_24XX) received, with unknown " - "vp_index %d\n", vha->vp_idx, entry->vp_index); - break; - } - qlt_response_pkt(host, pkt); - break; - } - - case ABTS_RESP_24XX: - { - struct abts_resp_to_24xx *entry = - (struct abts_resp_to_24xx *)pkt; - struct scsi_qla_host *host = qlt_find_host_by_vp_idx(vha, - entry->vp_index); - if (unlikely(!host)) { - ql_dbg(ql_dbg_tgt, vha, 0xe045, - "qla_target(%d): Response pkt " - "(ABTS_RECV_24XX) received, with unknown " - "vp_index %d\n", vha->vp_idx, entry->vp_index); - break; - } - qlt_response_pkt(host, pkt); - break; - } - - default: - qlt_response_pkt(vha, pkt); - break; - } - -} - -static void qlt_free_session_done(struct work_struct *work) -{ - struct qla_tgt_sess *sess = container_of(work, struct qla_tgt_sess, - free_work); - struct qla_tgt *tgt = sess->tgt; - struct scsi_qla_host *vha = sess->vha; - struct qla_hw_data *ha = vha->hw; - - BUG_ON(!tgt); - /* - * Release the target session for FC Nexus from fabric module code. - */ - if (sess->se_sess != NULL) - ha->tgt.tgt_ops->free_session(sess); - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf001, - "Unregistration of sess %p finished\n", sess); - - kfree(sess); - /* - * We need to protect against race, when tgt is freed before or - * inside wake_up() - */ - tgt->sess_count--; - if (tgt->sess_count == 0) - wake_up_all(&tgt->waitQ); -} - -/* ha->hardware_lock supposed to be held on entry */ -void qlt_unreg_sess(struct qla_tgt_sess *sess) -{ - struct scsi_qla_host *vha = sess->vha; - - vha->hw->tgt.tgt_ops->clear_nacl_from_fcport_map(sess); - - list_del(&sess->sess_list_entry); - if (sess->deleted) - list_del(&sess->del_list_entry); - - INIT_WORK(&sess->free_work, qlt_free_session_done); - schedule_work(&sess->free_work); -} -EXPORT_SYMBOL(qlt_unreg_sess); - -/* ha->hardware_lock supposed to be held on entry */ -static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd) -{ - struct qla_hw_data *ha = vha->hw; - struct qla_tgt_sess *sess = NULL; - uint32_t unpacked_lun, lun = 0; - uint16_t loop_id; - int res = 0; - struct imm_ntfy_from_isp *n = (struct imm_ntfy_from_isp *)iocb; - struct atio_from_isp *a = (struct atio_from_isp *)iocb; - - loop_id = le16_to_cpu(n->u.isp24.nport_handle); - if (loop_id == 0xFFFF) { -#if 0 /* FIXME: Re-enable Global event handling.. */ - /* Global event */ - atomic_inc(&ha->tgt.qla_tgt->tgt_global_resets_count); - qlt_clear_tgt_db(ha->tgt.qla_tgt, 1); - if (!list_empty(&ha->tgt.qla_tgt->sess_list)) { - sess = list_entry(ha->tgt.qla_tgt->sess_list.next, - typeof(*sess), sess_list_entry); - switch (mcmd) { - case QLA_TGT_NEXUS_LOSS_SESS: - mcmd = QLA_TGT_NEXUS_LOSS; - break; - case QLA_TGT_ABORT_ALL_SESS: - mcmd = QLA_TGT_ABORT_ALL; - break; - case QLA_TGT_NEXUS_LOSS: - case QLA_TGT_ABORT_ALL: - break; - default: - ql_dbg(ql_dbg_tgt, vha, 0xe046, - "qla_target(%d): Not allowed " - "command %x in %s", vha->vp_idx, - mcmd, __func__); - sess = NULL; - break; - } - } else - sess = NULL; -#endif - } else { - sess = ha->tgt.tgt_ops->find_sess_by_loop_id(vha, loop_id); - } - - ql_dbg(ql_dbg_tgt, vha, 0xe000, - "Using sess for qla_tgt_reset: %p\n", sess); - if (!sess) { - res = -ESRCH; - return res; - } - - ql_dbg(ql_dbg_tgt, vha, 0xe047, - "scsi(%ld): resetting (session %p from port " - "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, " - "mcmd %x, loop_id %d)\n", vha->host_no, sess, - sess->port_name[0], sess->port_name[1], - sess->port_name[2], sess->port_name[3], - sess->port_name[4], sess->port_name[5], - sess->port_name[6], sess->port_name[7], - mcmd, loop_id); - - lun = a->u.isp24.fcp_cmnd.lun; - unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun); - - return qlt_issue_task_mgmt(sess, unpacked_lun, mcmd, - iocb, QLA24XX_MGMT_SEND_NACK); -} - -/* ha->hardware_lock supposed to be held on entry */ -static void qlt_schedule_sess_for_deletion(struct qla_tgt_sess *sess, - bool immediate) -{ - struct qla_tgt *tgt = sess->tgt; - uint32_t dev_loss_tmo = tgt->ha->port_down_retry_count + 5; - - if (sess->deleted) - return; - - ql_dbg(ql_dbg_tgt, sess->vha, 0xe001, - "Scheduling sess %p for deletion\n", sess); - list_add_tail(&sess->del_list_entry, &tgt->del_sess_list); - sess->deleted = 1; - - if (immediate) - dev_loss_tmo = 0; - - sess->expires = jiffies + dev_loss_tmo * HZ; - - ql_dbg(ql_dbg_tgt, sess->vha, 0xe048, - "qla_target(%d): session for port %02x:%02x:%02x:" - "%02x:%02x:%02x:%02x:%02x (loop ID %d) scheduled for " - "deletion in %u secs (expires: %lu) immed: %d\n", - sess->vha->vp_idx, - sess->port_name[0], sess->port_name[1], - sess->port_name[2], sess->port_name[3], - sess->port_name[4], sess->port_name[5], - sess->port_name[6], sess->port_name[7], - sess->loop_id, dev_loss_tmo, sess->expires, immediate); - - if (immediate) - schedule_delayed_work(&tgt->sess_del_work, 0); - else - schedule_delayed_work(&tgt->sess_del_work, - jiffies - sess->expires); -} - -/* ha->hardware_lock supposed to be held on entry */ -static void qlt_clear_tgt_db(struct qla_tgt *tgt, bool local_only) -{ - struct qla_tgt_sess *sess; - - list_for_each_entry(sess, &tgt->sess_list, sess_list_entry) - qlt_schedule_sess_for_deletion(sess, true); - - /* At this point tgt could be already dead */ -} - -static int qla24xx_get_loop_id(struct scsi_qla_host *vha, const uint8_t *s_id, - uint16_t *loop_id) -{ - struct qla_hw_data *ha = vha->hw; - dma_addr_t gid_list_dma; - struct gid_list_info *gid_list; - char *id_iter; - int res, rc, i; - uint16_t entries; - - gid_list = dma_alloc_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha), - &gid_list_dma, GFP_KERNEL); - if (!gid_list) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf044, - "qla_target(%d): DMA Alloc failed of %u\n", - vha->vp_idx, qla2x00_gid_list_size(ha)); - return -ENOMEM; - } - - /* Get list of logged in devices */ - rc = qla2x00_get_id_list(vha, gid_list, gid_list_dma, &entries); - if (rc != QLA_SUCCESS) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf045, - "qla_target(%d): get_id_list() failed: %x\n", - vha->vp_idx, rc); - res = -1; - goto out_free_id_list; - } - - id_iter = (char *)gid_list; - res = -1; - for (i = 0; i < entries; i++) { - struct gid_list_info *gid = (struct gid_list_info *)id_iter; - if ((gid->al_pa == s_id[2]) && - (gid->area == s_id[1]) && - (gid->domain == s_id[0])) { - *loop_id = le16_to_cpu(gid->loop_id); - res = 0; - break; - } - id_iter += ha->gid_list_info_size; - } - -out_free_id_list: - dma_free_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha), - gid_list, gid_list_dma); - return res; -} - -static bool qlt_check_fcport_exist(struct scsi_qla_host *vha, - struct qla_tgt_sess *sess) -{ - struct qla_hw_data *ha = vha->hw; - struct qla_port_24xx_data *pmap24; - bool res, found = false; - int rc, i; - uint16_t loop_id = 0xFFFF; /* to eliminate compiler's warning */ - uint16_t entries; - void *pmap; - int pmap_len; - fc_port_t *fcport; - int global_resets; - -retry: - global_resets = atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count); - - rc = qla2x00_get_node_name_list(vha, &pmap, &pmap_len); - if (rc != QLA_SUCCESS) { - res = false; - goto out; - } - - pmap24 = pmap; - entries = pmap_len/sizeof(*pmap24); - - for (i = 0; i < entries; ++i) { - if (!memcmp(sess->port_name, pmap24[i].port_name, WWN_SIZE)) { - loop_id = le16_to_cpu(pmap24[i].loop_id); - found = true; - break; - } - } - - kfree(pmap); - - if (!found) { - res = false; - goto out; - } - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf046, - "qlt_check_fcport_exist(): loop_id %d", loop_id); - - fcport = kzalloc(sizeof(*fcport), GFP_KERNEL); - if (fcport == NULL) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf047, - "qla_target(%d): Allocation of tmp FC port failed", - vha->vp_idx); - res = false; - goto out; - } - - fcport->loop_id = loop_id; - - rc = qla2x00_get_port_database(vha, fcport, 0); - if (rc != QLA_SUCCESS) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf048, - "qla_target(%d): Failed to retrieve fcport " - "information -- get_port_database() returned %x " - "(loop_id=0x%04x)", vha->vp_idx, rc, loop_id); - res = false; - goto out_free_fcport; - } - - if (global_resets != - atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count)) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf002, - "qla_target(%d): global reset during session discovery" - " (counter was %d, new %d), retrying", - vha->vp_idx, global_resets, - atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count)); - goto retry; - } - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf003, - "Updating sess %p s_id %x:%x:%x, loop_id %d) to d_id %x:%x:%x, " - "loop_id %d", sess, sess->s_id.b.domain, sess->s_id.b.al_pa, - sess->s_id.b.area, sess->loop_id, fcport->d_id.b.domain, - fcport->d_id.b.al_pa, fcport->d_id.b.area, fcport->loop_id); - - sess->s_id = fcport->d_id; - sess->loop_id = fcport->loop_id; - sess->conf_compl_supported = !!(fcport->flags & - FCF_CONF_COMP_SUPPORTED); - - res = true; - -out_free_fcport: - kfree(fcport); - -out: - return res; -} - -/* ha->hardware_lock supposed to be held on entry */ -static void qlt_undelete_sess(struct qla_tgt_sess *sess) -{ - BUG_ON(!sess->deleted); - - list_del(&sess->del_list_entry); - sess->deleted = 0; -} - -static void qlt_del_sess_work_fn(struct delayed_work *work) -{ - struct qla_tgt *tgt = container_of(work, struct qla_tgt, - sess_del_work); - struct scsi_qla_host *vha = tgt->vha; - struct qla_hw_data *ha = vha->hw; - struct qla_tgt_sess *sess; - unsigned long flags; - - spin_lock_irqsave(&ha->hardware_lock, flags); - while (!list_empty(&tgt->del_sess_list)) { - sess = list_entry(tgt->del_sess_list.next, typeof(*sess), - del_list_entry); - if (time_after_eq(jiffies, sess->expires)) { - bool cancel; - - qlt_undelete_sess(sess); - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - cancel = qlt_check_fcport_exist(vha, sess); - - if (cancel) { - if (sess->deleted) { - /* - * sess was again deleted while we were - * discovering it - */ - spin_lock_irqsave(&ha->hardware_lock, - flags); - continue; - } - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf049, - "qla_target(%d): cancel deletion of " - "session for port %02x:%02x:%02x:%02x:%02x:" - "%02x:%02x:%02x (loop ID %d), because " - " it isn't deleted by firmware", - vha->vp_idx, sess->port_name[0], - sess->port_name[1], sess->port_name[2], - sess->port_name[3], sess->port_name[4], - sess->port_name[5], sess->port_name[6], - sess->port_name[7], sess->loop_id); - } else { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf004, - "Timeout: sess %p about to be deleted\n", - sess); - ha->tgt.tgt_ops->shutdown_sess(sess); - ha->tgt.tgt_ops->put_sess(sess); - } - - spin_lock_irqsave(&ha->hardware_lock, flags); - } else { - schedule_delayed_work(&tgt->sess_del_work, - jiffies - sess->expires); - break; - } - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -/* - * Adds an extra ref to allow to drop hw lock after adding sess to the list. - * Caller must put it. - */ -static struct qla_tgt_sess *qlt_create_sess( - struct scsi_qla_host *vha, - fc_port_t *fcport, - bool local) -{ - struct qla_hw_data *ha = vha->hw; - struct qla_tgt_sess *sess; - unsigned long flags; - unsigned char be_sid[3]; - - /* Check to avoid double sessions */ - spin_lock_irqsave(&ha->hardware_lock, flags); - list_for_each_entry(sess, &ha->tgt.qla_tgt->sess_list, - sess_list_entry) { - if (!memcmp(sess->port_name, fcport->port_name, WWN_SIZE)) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf005, - "Double sess %p found (s_id %x:%x:%x, " - "loop_id %d), updating to d_id %x:%x:%x, " - "loop_id %d", sess, sess->s_id.b.domain, - sess->s_id.b.al_pa, sess->s_id.b.area, - sess->loop_id, fcport->d_id.b.domain, - fcport->d_id.b.al_pa, fcport->d_id.b.area, - fcport->loop_id); - - if (sess->deleted) - qlt_undelete_sess(sess); - - kref_get(&sess->se_sess->sess_kref); - sess->s_id = fcport->d_id; - sess->loop_id = fcport->loop_id; - sess->conf_compl_supported = !!(fcport->flags & - FCF_CONF_COMP_SUPPORTED); - if (sess->local && !local) - sess->local = 0; - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - return sess; - } - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - sess = kzalloc(sizeof(*sess), GFP_KERNEL); - if (!sess) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04a, - "qla_target(%u): session allocation failed, " - "all commands from port %02x:%02x:%02x:%02x:" - "%02x:%02x:%02x:%02x will be refused", vha->vp_idx, - fcport->port_name[0], fcport->port_name[1], - fcport->port_name[2], fcport->port_name[3], - fcport->port_name[4], fcport->port_name[5], - fcport->port_name[6], fcport->port_name[7]); - - return NULL; - } - sess->tgt = ha->tgt.qla_tgt; - sess->vha = vha; - sess->s_id = fcport->d_id; - sess->loop_id = fcport->loop_id; - sess->local = local; - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf006, - "Adding sess %p to tgt %p via ->check_initiator_node_acl()\n", - sess, ha->tgt.qla_tgt); - - be_sid[0] = sess->s_id.b.domain; - be_sid[1] = sess->s_id.b.area; - be_sid[2] = sess->s_id.b.al_pa; - /* - * Determine if this fc_port->port_name is allowed to access - * target mode using explict NodeACLs+MappedLUNs, or using - * TPG demo mode. If this is successful a target mode FC nexus - * is created. - */ - if (ha->tgt.tgt_ops->check_initiator_node_acl(vha, - &fcport->port_name[0], sess, &be_sid[0], fcport->loop_id) < 0) { - kfree(sess); - return NULL; - } - /* - * Take an extra reference to ->sess_kref here to handle qla_tgt_sess - * access across ->hardware_lock reaquire. - */ - kref_get(&sess->se_sess->sess_kref); - - sess->conf_compl_supported = !!(fcport->flags & - FCF_CONF_COMP_SUPPORTED); - BUILD_BUG_ON(sizeof(sess->port_name) != sizeof(fcport->port_name)); - memcpy(sess->port_name, fcport->port_name, sizeof(sess->port_name)); - - spin_lock_irqsave(&ha->hardware_lock, flags); - list_add_tail(&sess->sess_list_entry, &ha->tgt.qla_tgt->sess_list); - ha->tgt.qla_tgt->sess_count++; - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04b, - "qla_target(%d): %ssession for wwn %02x:%02x:%02x:%02x:" - "%02x:%02x:%02x:%02x (loop_id %d, s_id %x:%x:%x, confirmed" - " completion %ssupported) added\n", - vha->vp_idx, local ? "local " : "", fcport->port_name[0], - fcport->port_name[1], fcport->port_name[2], fcport->port_name[3], - fcport->port_name[4], fcport->port_name[5], fcport->port_name[6], - fcport->port_name[7], fcport->loop_id, sess->s_id.b.domain, - sess->s_id.b.area, sess->s_id.b.al_pa, sess->conf_compl_supported ? - "" : "not "); - - return sess; -} - -/* - * Called from drivers/scsi/qla2xxx/qla_init.c:qla2x00_reg_remote_port() - */ -void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport) -{ - struct qla_hw_data *ha = vha->hw; - struct qla_tgt *tgt = ha->tgt.qla_tgt; - struct qla_tgt_sess *sess; - unsigned long flags; - - if (!vha->hw->tgt.tgt_ops) - return; - - if (!tgt || (fcport->port_type != FCT_INITIATOR)) - return; - - spin_lock_irqsave(&ha->hardware_lock, flags); - if (tgt->tgt_stop) { - spin_unlock_irqrestore(&ha->hardware_lock, flags); - return; - } - sess = qlt_find_sess_by_port_name(tgt, fcport->port_name); - if (!sess) { - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - mutex_lock(&ha->tgt.tgt_mutex); - sess = qlt_create_sess(vha, fcport, false); - mutex_unlock(&ha->tgt.tgt_mutex); - - spin_lock_irqsave(&ha->hardware_lock, flags); - } else { - kref_get(&sess->se_sess->sess_kref); - - if (sess->deleted) { - qlt_undelete_sess(sess); - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04c, - "qla_target(%u): %ssession for port %02x:" - "%02x:%02x:%02x:%02x:%02x:%02x:%02x (loop ID %d) " - "reappeared\n", vha->vp_idx, sess->local ? "local " - : "", sess->port_name[0], sess->port_name[1], - sess->port_name[2], sess->port_name[3], - sess->port_name[4], sess->port_name[5], - sess->port_name[6], sess->port_name[7], - sess->loop_id); - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf007, - "Reappeared sess %p\n", sess); - } - sess->s_id = fcport->d_id; - sess->loop_id = fcport->loop_id; - sess->conf_compl_supported = !!(fcport->flags & - FCF_CONF_COMP_SUPPORTED); - } - - if (sess && sess->local) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04d, - "qla_target(%u): local session for " - "port %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x " - "(loop ID %d) became global\n", vha->vp_idx, - fcport->port_name[0], fcport->port_name[1], - fcport->port_name[2], fcport->port_name[3], - fcport->port_name[4], fcport->port_name[5], - fcport->port_name[6], fcport->port_name[7], - sess->loop_id); - sess->local = 0; - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - ha->tgt.tgt_ops->put_sess(sess); -} - -void qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport) -{ - struct qla_hw_data *ha = vha->hw; - struct qla_tgt *tgt = ha->tgt.qla_tgt; - struct qla_tgt_sess *sess; - unsigned long flags; - - if (!vha->hw->tgt.tgt_ops) - return; - - if (!tgt || (fcport->port_type != FCT_INITIATOR)) - return; - - spin_lock_irqsave(&ha->hardware_lock, flags); - if (tgt->tgt_stop) { - spin_unlock_irqrestore(&ha->hardware_lock, flags); - return; - } - sess = qlt_find_sess_by_port_name(tgt, fcport->port_name); - if (!sess) { - spin_unlock_irqrestore(&ha->hardware_lock, flags); - return; - } - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf008, "qla_tgt_fc_port_deleted %p", sess); - - sess->local = 1; - qlt_schedule_sess_for_deletion(sess, false); - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -static inline int test_tgt_sess_count(struct qla_tgt *tgt) -{ - struct qla_hw_data *ha = tgt->ha; - unsigned long flags; - int res; - /* - * We need to protect against race, when tgt is freed before or - * inside wake_up() - */ - spin_lock_irqsave(&ha->hardware_lock, flags); - ql_dbg(ql_dbg_tgt, tgt->vha, 0xe002, - "tgt %p, empty(sess_list)=%d sess_count=%d\n", - tgt, list_empty(&tgt->sess_list), tgt->sess_count); - res = (tgt->sess_count == 0); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - return res; -} - -/* Called by tcm_qla2xxx configfs code */ -void qlt_stop_phase1(struct qla_tgt *tgt) -{ - struct scsi_qla_host *vha = tgt->vha; - struct qla_hw_data *ha = tgt->ha; - unsigned long flags; - - if (tgt->tgt_stop || tgt->tgt_stopped) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04e, - "Already in tgt->tgt_stop or tgt_stopped state\n"); - dump_stack(); - return; - } - - ql_dbg(ql_dbg_tgt, vha, 0xe003, "Stopping target for host %ld(%p)\n", - vha->host_no, vha); - /* - * Mutex needed to sync with qla_tgt_fc_port_[added,deleted]. - * Lock is needed, because we still can get an incoming packet. - */ - mutex_lock(&ha->tgt.tgt_mutex); - spin_lock_irqsave(&ha->hardware_lock, flags); - tgt->tgt_stop = 1; - qlt_clear_tgt_db(tgt, true); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - mutex_unlock(&ha->tgt.tgt_mutex); - - flush_delayed_work_sync(&tgt->sess_del_work); - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf009, - "Waiting for sess works (tgt %p)", tgt); - spin_lock_irqsave(&tgt->sess_work_lock, flags); - while (!list_empty(&tgt->sess_works_list)) { - spin_unlock_irqrestore(&tgt->sess_work_lock, flags); - flush_scheduled_work(); - spin_lock_irqsave(&tgt->sess_work_lock, flags); - } - spin_unlock_irqrestore(&tgt->sess_work_lock, flags); - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00a, - "Waiting for tgt %p: list_empty(sess_list)=%d " - "sess_count=%d\n", tgt, list_empty(&tgt->sess_list), - tgt->sess_count); - - wait_event(tgt->waitQ, test_tgt_sess_count(tgt)); - - /* Big hammer */ - if (!ha->flags.host_shutting_down && qla_tgt_mode_enabled(vha)) - qlt_disable_vha(vha); - - /* Wait for sessions to clear out (just in case) */ - wait_event(tgt->waitQ, test_tgt_sess_count(tgt)); -} -EXPORT_SYMBOL(qlt_stop_phase1); - -/* Called by tcm_qla2xxx configfs code */ -void qlt_stop_phase2(struct qla_tgt *tgt) -{ - struct qla_hw_data *ha = tgt->ha; - unsigned long flags; - - if (tgt->tgt_stopped) { - ql_dbg(ql_dbg_tgt_mgt, tgt->vha, 0xf04f, - "Already in tgt->tgt_stopped state\n"); - dump_stack(); - return; - } - - ql_dbg(ql_dbg_tgt_mgt, tgt->vha, 0xf00b, - "Waiting for %d IRQ commands to complete (tgt %p)", - tgt->irq_cmd_count, tgt); - - mutex_lock(&ha->tgt.tgt_mutex); - spin_lock_irqsave(&ha->hardware_lock, flags); - while (tgt->irq_cmd_count != 0) { - spin_unlock_irqrestore(&ha->hardware_lock, flags); - udelay(2); - spin_lock_irqsave(&ha->hardware_lock, flags); - } - tgt->tgt_stop = 0; - tgt->tgt_stopped = 1; - spin_unlock_irqrestore(&ha->hardware_lock, flags); - mutex_unlock(&ha->tgt.tgt_mutex); - - ql_dbg(ql_dbg_tgt_mgt, tgt->vha, 0xf00c, "Stop of tgt %p finished", - tgt); -} -EXPORT_SYMBOL(qlt_stop_phase2); - -/* Called from qlt_remove_target() -> qla2x00_remove_one() */ -void qlt_release(struct qla_tgt *tgt) -{ - struct qla_hw_data *ha = tgt->ha; - - if ((ha->tgt.qla_tgt != NULL) && !tgt->tgt_stopped) - qlt_stop_phase2(tgt); - - ha->tgt.qla_tgt = NULL; - - ql_dbg(ql_dbg_tgt_mgt, tgt->vha, 0xf00d, - "Release of tgt %p finished\n", tgt); - - kfree(tgt); -} - -/* ha->hardware_lock supposed to be held on entry */ -static int qlt_sched_sess_work(struct qla_tgt *tgt, int type, - const void *param, unsigned int param_size) -{ - struct qla_tgt_sess_work_param *prm; - unsigned long flags; - - prm = kzalloc(sizeof(*prm), GFP_ATOMIC); - if (!prm) { - ql_dbg(ql_dbg_tgt_mgt, tgt->vha, 0xf050, - "qla_target(%d): Unable to create session " - "work, command will be refused", 0); - return -ENOMEM; - } - - ql_dbg(ql_dbg_tgt_mgt, tgt->vha, 0xf00e, - "Scheduling work (type %d, prm %p)" - " to find session for param %p (size %d, tgt %p)\n", - type, prm, param, param_size, tgt); - - prm->type = type; - memcpy(&prm->tm_iocb, param, param_size); - - spin_lock_irqsave(&tgt->sess_work_lock, flags); - list_add_tail(&prm->sess_works_list_entry, &tgt->sess_works_list); - spin_unlock_irqrestore(&tgt->sess_work_lock, flags); - - schedule_work(&tgt->sess_work); - - return 0; -} - -/* - * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire - */ -static void qlt_send_notify_ack(struct scsi_qla_host *vha, - struct imm_ntfy_from_isp *ntfy, - uint32_t add_flags, uint16_t resp_code, int resp_code_valid, - uint16_t srr_flags, uint16_t srr_reject_code, uint8_t srr_explan) -{ - struct qla_hw_data *ha = vha->hw; - request_t *pkt; - struct nack_to_isp *nack; - - ql_dbg(ql_dbg_tgt, vha, 0xe004, "Sending NOTIFY_ACK (ha=%p)\n", ha); - - /* Send marker if required */ - if (qlt_issue_marker(vha, 1) != QLA_SUCCESS) - return; - - pkt = (request_t *)qla2x00_alloc_iocbs(vha, NULL); - if (!pkt) { - ql_dbg(ql_dbg_tgt, vha, 0xe049, - "qla_target(%d): %s failed: unable to allocate " - "request packet\n", vha->vp_idx, __func__); - return; - } - - if (ha->tgt.qla_tgt != NULL) - ha->tgt.qla_tgt->notify_ack_expected++; - - pkt->entry_type = NOTIFY_ACK_TYPE; - pkt->entry_count = 1; - - nack = (struct nack_to_isp *)pkt; - nack->ox_id = ntfy->ox_id; - - nack->u.isp24.nport_handle = ntfy->u.isp24.nport_handle; - if (le16_to_cpu(ntfy->u.isp24.status) == IMM_NTFY_ELS) { - nack->u.isp24.flags = ntfy->u.isp24.flags & - __constant_cpu_to_le32(NOTIFY24XX_FLAGS_PUREX_IOCB); - } - nack->u.isp24.srr_rx_id = ntfy->u.isp24.srr_rx_id; - nack->u.isp24.status = ntfy->u.isp24.status; - nack->u.isp24.status_subcode = ntfy->u.isp24.status_subcode; - nack->u.isp24.exchange_address = ntfy->u.isp24.exchange_address; - nack->u.isp24.srr_rel_offs = ntfy->u.isp24.srr_rel_offs; - nack->u.isp24.srr_ui = ntfy->u.isp24.srr_ui; - nack->u.isp24.srr_flags = cpu_to_le16(srr_flags); - nack->u.isp24.srr_reject_code = srr_reject_code; - nack->u.isp24.srr_reject_code_expl = srr_explan; - nack->u.isp24.vp_index = ntfy->u.isp24.vp_index; - - ql_dbg(ql_dbg_tgt, vha, 0xe005, - "qla_target(%d): Sending 24xx Notify Ack %d\n", - vha->vp_idx, nack->u.isp24.status); - - qla2x00_start_iocbs(vha, vha->req); -} - -/* - * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire - */ -static void qlt_24xx_send_abts_resp(struct scsi_qla_host *vha, - struct abts_recv_from_24xx *abts, uint32_t status, - bool ids_reversed) -{ - struct qla_hw_data *ha = vha->hw; - struct abts_resp_to_24xx *resp; - uint32_t f_ctl; - uint8_t *p; - - ql_dbg(ql_dbg_tgt, vha, 0xe006, - "Sending task mgmt ABTS response (ha=%p, atio=%p, status=%x\n", - ha, abts, status); - - /* Send marker if required */ - if (qlt_issue_marker(vha, 1) != QLA_SUCCESS) - return; - - resp = (struct abts_resp_to_24xx *)qla2x00_alloc_iocbs(vha, NULL); - if (!resp) { - ql_dbg(ql_dbg_tgt, vha, 0xe04a, - "qla_target(%d): %s failed: unable to allocate " - "request packet", vha->vp_idx, __func__); - return; - } - - resp->entry_type = ABTS_RESP_24XX; - resp->entry_count = 1; - resp->nport_handle = abts->nport_handle; - resp->vp_index = vha->vp_idx; - resp->sof_type = abts->sof_type; - resp->exchange_address = abts->exchange_address; - resp->fcp_hdr_le = abts->fcp_hdr_le; - f_ctl = __constant_cpu_to_le32(F_CTL_EXCH_CONTEXT_RESP | - F_CTL_LAST_SEQ | F_CTL_END_SEQ | - F_CTL_SEQ_INITIATIVE); - p = (uint8_t *)&f_ctl; - resp->fcp_hdr_le.f_ctl[0] = *p++; - resp->fcp_hdr_le.f_ctl[1] = *p++; - resp->fcp_hdr_le.f_ctl[2] = *p; - if (ids_reversed) { - resp->fcp_hdr_le.d_id[0] = abts->fcp_hdr_le.d_id[0]; - resp->fcp_hdr_le.d_id[1] = abts->fcp_hdr_le.d_id[1]; - resp->fcp_hdr_le.d_id[2] = abts->fcp_hdr_le.d_id[2]; - resp->fcp_hdr_le.s_id[0] = abts->fcp_hdr_le.s_id[0]; - resp->fcp_hdr_le.s_id[1] = abts->fcp_hdr_le.s_id[1]; - resp->fcp_hdr_le.s_id[2] = abts->fcp_hdr_le.s_id[2]; - } else { - resp->fcp_hdr_le.d_id[0] = abts->fcp_hdr_le.s_id[0]; - resp->fcp_hdr_le.d_id[1] = abts->fcp_hdr_le.s_id[1]; - resp->fcp_hdr_le.d_id[2] = abts->fcp_hdr_le.s_id[2]; - resp->fcp_hdr_le.s_id[0] = abts->fcp_hdr_le.d_id[0]; - resp->fcp_hdr_le.s_id[1] = abts->fcp_hdr_le.d_id[1]; - resp->fcp_hdr_le.s_id[2] = abts->fcp_hdr_le.d_id[2]; - } - resp->exchange_addr_to_abort = abts->exchange_addr_to_abort; - if (status == FCP_TMF_CMPL) { - resp->fcp_hdr_le.r_ctl = R_CTL_BASIC_LINK_SERV | R_CTL_B_ACC; - resp->payload.ba_acct.seq_id_valid = SEQ_ID_INVALID; - resp->payload.ba_acct.low_seq_cnt = 0x0000; - resp->payload.ba_acct.high_seq_cnt = 0xFFFF; - resp->payload.ba_acct.ox_id = abts->fcp_hdr_le.ox_id; - resp->payload.ba_acct.rx_id = abts->fcp_hdr_le.rx_id; - } else { - resp->fcp_hdr_le.r_ctl = R_CTL_BASIC_LINK_SERV | R_CTL_B_RJT; - resp->payload.ba_rjt.reason_code = - BA_RJT_REASON_CODE_UNABLE_TO_PERFORM; - /* Other bytes are zero */ - } - - ha->tgt.qla_tgt->abts_resp_expected++; - - qla2x00_start_iocbs(vha, vha->req); -} - -/* - * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire - */ -static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha, - struct abts_resp_from_24xx_fw *entry) -{ - struct ctio7_to_24xx *ctio; - - ql_dbg(ql_dbg_tgt, vha, 0xe007, - "Sending retry TERM EXCH CTIO7 (ha=%p)\n", vha->hw); - /* Send marker if required */ - if (qlt_issue_marker(vha, 1) != QLA_SUCCESS) - return; - - ctio = (struct ctio7_to_24xx *)qla2x00_alloc_iocbs(vha, NULL); - if (ctio == NULL) { - ql_dbg(ql_dbg_tgt, vha, 0xe04b, - "qla_target(%d): %s failed: unable to allocate " - "request packet\n", vha->vp_idx, __func__); - return; - } - - /* - * We've got on entrance firmware's response on by us generated - * ABTS response. So, in it ID fields are reversed. - */ - - ctio->entry_type = CTIO_TYPE7; - ctio->entry_count = 1; - ctio->nport_handle = entry->nport_handle; - ctio->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK; - ctio->timeout = __constant_cpu_to_le16(QLA_TGT_TIMEOUT); - ctio->vp_index = vha->vp_idx; - ctio->initiator_id[0] = entry->fcp_hdr_le.d_id[0]; - ctio->initiator_id[1] = entry->fcp_hdr_le.d_id[1]; - ctio->initiator_id[2] = entry->fcp_hdr_le.d_id[2]; - ctio->exchange_addr = entry->exchange_addr_to_abort; - ctio->u.status1.flags = - __constant_cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1 | - CTIO7_FLAGS_TERMINATE); - ctio->u.status1.ox_id = entry->fcp_hdr_le.ox_id; - - qla2x00_start_iocbs(vha, vha->req); - - qlt_24xx_send_abts_resp(vha, (struct abts_recv_from_24xx *)entry, - FCP_TMF_CMPL, true); -} - -/* ha->hardware_lock supposed to be held on entry */ -static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha, - struct abts_recv_from_24xx *abts, struct qla_tgt_sess *sess) -{ - struct qla_hw_data *ha = vha->hw; - struct qla_tgt_mgmt_cmd *mcmd; - int rc; - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00f, - "qla_target(%d): task abort (tag=%d)\n", - vha->vp_idx, abts->exchange_addr_to_abort); - - mcmd = mempool_alloc(qla_tgt_mgmt_cmd_mempool, GFP_ATOMIC); - if (mcmd == NULL) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf051, - "qla_target(%d): %s: Allocation of ABORT cmd failed", - vha->vp_idx, __func__); - return -ENOMEM; - } - memset(mcmd, 0, sizeof(*mcmd)); - - mcmd->sess = sess; - memcpy(&mcmd->orig_iocb.abts, abts, sizeof(mcmd->orig_iocb.abts)); - - rc = ha->tgt.tgt_ops->handle_tmr(mcmd, 0, TMR_ABORT_TASK, - abts->exchange_addr_to_abort); - if (rc != 0) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf052, - "qla_target(%d): tgt_ops->handle_tmr()" - " failed: %d", vha->vp_idx, rc); - mempool_free(mcmd, qla_tgt_mgmt_cmd_mempool); - return -EFAULT; - } - - return 0; -} - -/* - * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire - */ -static void qlt_24xx_handle_abts(struct scsi_qla_host *vha, - struct abts_recv_from_24xx *abts) -{ - struct qla_hw_data *ha = vha->hw; - struct qla_tgt_sess *sess; - uint32_t tag = abts->exchange_addr_to_abort; - uint8_t s_id[3]; - int rc; - - if (le32_to_cpu(abts->fcp_hdr_le.parameter) & ABTS_PARAM_ABORT_SEQ) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf053, - "qla_target(%d): ABTS: Abort Sequence not " - "supported\n", vha->vp_idx); - qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED, false); - return; - } - - if (tag == ATIO_EXCHANGE_ADDRESS_UNKNOWN) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf010, - "qla_target(%d): ABTS: Unknown Exchange " - "Address received\n", vha->vp_idx); - qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED, false); - return; - } - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf011, - "qla_target(%d): task abort (s_id=%x:%x:%x, " - "tag=%d, param=%x)\n", vha->vp_idx, abts->fcp_hdr_le.s_id[2], - abts->fcp_hdr_le.s_id[1], abts->fcp_hdr_le.s_id[0], tag, - le32_to_cpu(abts->fcp_hdr_le.parameter)); - - s_id[0] = abts->fcp_hdr_le.s_id[2]; - s_id[1] = abts->fcp_hdr_le.s_id[1]; - s_id[2] = abts->fcp_hdr_le.s_id[0]; - - sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id); - if (!sess) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf012, - "qla_target(%d): task abort for non-existant session\n", - vha->vp_idx); - rc = qlt_sched_sess_work(ha->tgt.qla_tgt, - QLA_TGT_SESS_WORK_ABORT, abts, sizeof(*abts)); - if (rc != 0) { - qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED, - false); - } - return; - } - - rc = __qlt_24xx_handle_abts(vha, abts, sess); - if (rc != 0) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf054, - "qla_target(%d): __qlt_24xx_handle_abts() failed: %d\n", - vha->vp_idx, rc); - qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED, false); - return; - } -} - -/* - * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire - */ -static void qlt_24xx_send_task_mgmt_ctio(struct scsi_qla_host *ha, - struct qla_tgt_mgmt_cmd *mcmd, uint32_t resp_code) -{ - struct atio_from_isp *atio = &mcmd->orig_iocb.atio; - struct ctio7_to_24xx *ctio; - - ql_dbg(ql_dbg_tgt, ha, 0xe008, - "Sending task mgmt CTIO7 (ha=%p, atio=%p, resp_code=%x\n", - ha, atio, resp_code); - - /* Send marker if required */ - if (qlt_issue_marker(ha, 1) != QLA_SUCCESS) - return; - - ctio = (struct ctio7_to_24xx *)qla2x00_alloc_iocbs(ha, NULL); - if (ctio == NULL) { - ql_dbg(ql_dbg_tgt, ha, 0xe04c, - "qla_target(%d): %s failed: unable to allocate " - "request packet\n", ha->vp_idx, __func__); - return; - } - - ctio->entry_type = CTIO_TYPE7; - ctio->entry_count = 1; - ctio->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK; - ctio->nport_handle = mcmd->sess->loop_id; - ctio->timeout = __constant_cpu_to_le16(QLA_TGT_TIMEOUT); - ctio->vp_index = ha->vp_idx; - ctio->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2]; - ctio->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1]; - ctio->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0]; - ctio->exchange_addr = atio->u.isp24.exchange_addr; - ctio->u.status1.flags = (atio->u.isp24.attr << 9) | - __constant_cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1 | - CTIO7_FLAGS_SEND_STATUS); - ctio->u.status1.ox_id = swab16(atio->u.isp24.fcp_hdr.ox_id); - ctio->u.status1.scsi_status = - __constant_cpu_to_le16(SS_RESPONSE_INFO_LEN_VALID); - ctio->u.status1.response_len = __constant_cpu_to_le16(8); - ((uint32_t *)ctio->u.status1.sense_data)[0] = cpu_to_be32(resp_code); - - qla2x00_start_iocbs(ha, ha->req); -} - -void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *mcmd) -{ - mempool_free(mcmd, qla_tgt_mgmt_cmd_mempool); -} -EXPORT_SYMBOL(qlt_free_mcmd); - -/* callback from target fabric module code */ -void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd) -{ - struct scsi_qla_host *vha = mcmd->sess->vha; - struct qla_hw_data *ha = vha->hw; - unsigned long flags; - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf013, - "TM response mcmd (%p) status %#x state %#x", - mcmd, mcmd->fc_tm_rsp, mcmd->flags); - - spin_lock_irqsave(&ha->hardware_lock, flags); - if (mcmd->flags == QLA24XX_MGMT_SEND_NACK) - qlt_send_notify_ack(vha, &mcmd->orig_iocb.imm_ntfy, - 0, 0, 0, 0, 0, 0); - else { - if (mcmd->se_cmd.se_tmr_req->function == TMR_ABORT_TASK) - qlt_24xx_send_abts_resp(vha, &mcmd->orig_iocb.abts, - mcmd->fc_tm_rsp, false); - else - qlt_24xx_send_task_mgmt_ctio(vha, mcmd, - mcmd->fc_tm_rsp); - } - /* - * Make the callback for ->free_mcmd() to queue_work() and invoke - * target_put_sess_cmd() to drop cmd_kref to 1. The final - * target_put_sess_cmd() call will be made from TFO->check_stop_free() - * -> tcm_qla2xxx_check_stop_free() to release the TMR associated se_cmd - * descriptor after TFO->queue_tm_rsp() -> tcm_qla2xxx_queue_tm_rsp() -> - * qlt_xmit_tm_rsp() returns here.. - */ - ha->tgt.tgt_ops->free_mcmd(mcmd); - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} -EXPORT_SYMBOL(qlt_xmit_tm_rsp); - -/* No locks */ -static int qlt_pci_map_calc_cnt(struct qla_tgt_prm *prm) -{ - struct qla_tgt_cmd *cmd = prm->cmd; - - BUG_ON(cmd->sg_cnt == 0); - - prm->sg = (struct scatterlist *)cmd->sg; - prm->seg_cnt = pci_map_sg(prm->tgt->ha->pdev, cmd->sg, - cmd->sg_cnt, cmd->dma_data_direction); - if (unlikely(prm->seg_cnt == 0)) - goto out_err; - - prm->cmd->sg_mapped = 1; - - /* - * If greater than four sg entries then we need to allocate - * the continuation entries - */ - if (prm->seg_cnt > prm->tgt->datasegs_per_cmd) - prm->req_cnt += DIV_ROUND_UP(prm->seg_cnt - - prm->tgt->datasegs_per_cmd, prm->tgt->datasegs_per_cont); - - ql_dbg(ql_dbg_tgt, prm->cmd->vha, 0xe009, "seg_cnt=%d, req_cnt=%d\n", - prm->seg_cnt, prm->req_cnt); - return 0; - -out_err: - ql_dbg(ql_dbg_tgt, prm->cmd->vha, 0xe04d, - "qla_target(%d): PCI mapping failed: sg_cnt=%d", - 0, prm->cmd->sg_cnt); - return -1; -} - -static inline void qlt_unmap_sg(struct scsi_qla_host *vha, - struct qla_tgt_cmd *cmd) -{ - struct qla_hw_data *ha = vha->hw; - - BUG_ON(!cmd->sg_mapped); - pci_unmap_sg(ha->pdev, cmd->sg, cmd->sg_cnt, cmd->dma_data_direction); - cmd->sg_mapped = 0; -} - -static int qlt_check_reserve_free_req(struct scsi_qla_host *vha, - uint32_t req_cnt) -{ - struct qla_hw_data *ha = vha->hw; - device_reg_t __iomem *reg = ha->iobase; - uint32_t cnt; - - if (vha->req->cnt < (req_cnt + 2)) { - cnt = (uint16_t)RD_REG_DWORD(®->isp24.req_q_out); - - ql_dbg(ql_dbg_tgt, vha, 0xe00a, - "Request ring circled: cnt=%d, vha->->ring_index=%d, " - "vha->req->cnt=%d, req_cnt=%d\n", cnt, - vha->req->ring_index, vha->req->cnt, req_cnt); - if (vha->req->ring_index < cnt) - vha->req->cnt = cnt - vha->req->ring_index; - else - vha->req->cnt = vha->req->length - - (vha->req->ring_index - cnt); - } - - if (unlikely(vha->req->cnt < (req_cnt + 2))) { - ql_dbg(ql_dbg_tgt, vha, 0xe00b, - "qla_target(%d): There is no room in the " - "request ring: vha->req->ring_index=%d, vha->req->cnt=%d, " - "req_cnt=%d\n", vha->vp_idx, vha->req->ring_index, - vha->req->cnt, req_cnt); - return -EAGAIN; - } - vha->req->cnt -= req_cnt; - - return 0; -} - -/* - * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire - */ -static inline void *qlt_get_req_pkt(struct scsi_qla_host *vha) -{ - /* Adjust ring index. */ - vha->req->ring_index++; - if (vha->req->ring_index == vha->req->length) { - vha->req->ring_index = 0; - vha->req->ring_ptr = vha->req->ring; - } else { - vha->req->ring_ptr++; - } - return (cont_entry_t *)vha->req->ring_ptr; -} - -/* ha->hardware_lock supposed to be held on entry */ -static inline uint32_t qlt_make_handle(struct scsi_qla_host *vha) -{ - struct qla_hw_data *ha = vha->hw; - uint32_t h; - - h = ha->tgt.current_handle; - /* always increment cmd handle */ - do { - ++h; - if (h > MAX_OUTSTANDING_COMMANDS) - h = 1; /* 0 is QLA_TGT_NULL_HANDLE */ - if (h == ha->tgt.current_handle) { - ql_dbg(ql_dbg_tgt, vha, 0xe04e, - "qla_target(%d): Ran out of " - "empty cmd slots in ha %p\n", vha->vp_idx, ha); - h = QLA_TGT_NULL_HANDLE; - break; - } - } while ((h == QLA_TGT_NULL_HANDLE) || - (h == QLA_TGT_SKIP_HANDLE) || - (ha->tgt.cmds[h-1] != NULL)); - - if (h != QLA_TGT_NULL_HANDLE) - ha->tgt.current_handle = h; - - return h; -} - -/* ha->hardware_lock supposed to be held on entry */ -static int qlt_24xx_build_ctio_pkt(struct qla_tgt_prm *prm, - struct scsi_qla_host *vha) -{ - uint32_t h; - struct ctio7_to_24xx *pkt; - struct qla_hw_data *ha = vha->hw; - struct atio_from_isp *atio = &prm->cmd->atio; - - pkt = (struct ctio7_to_24xx *)vha->req->ring_ptr; - prm->pkt = pkt; - memset(pkt, 0, sizeof(*pkt)); - - pkt->entry_type = CTIO_TYPE7; - pkt->entry_count = (uint8_t)prm->req_cnt; - pkt->vp_index = vha->vp_idx; - - h = qlt_make_handle(vha); - if (unlikely(h == QLA_TGT_NULL_HANDLE)) { - /* - * CTIO type 7 from the firmware doesn't provide a way to - * know the initiator's LOOP ID, hence we can't find - * the session and, so, the command. - */ - return -EAGAIN; - } else - ha->tgt.cmds[h-1] = prm->cmd; - - pkt->handle = h | CTIO_COMPLETION_HANDLE_MARK; - pkt->nport_handle = prm->cmd->loop_id; - pkt->timeout = __constant_cpu_to_le16(QLA_TGT_TIMEOUT); - pkt->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2]; - pkt->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1]; - pkt->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0]; - pkt->exchange_addr = atio->u.isp24.exchange_addr; - pkt->u.status0.flags |= (atio->u.isp24.attr << 9); - pkt->u.status0.ox_id = swab16(atio->u.isp24.fcp_hdr.ox_id); - pkt->u.status0.relative_offset = cpu_to_le32(prm->cmd->offset); - - ql_dbg(ql_dbg_tgt, vha, 0xe00c, - "qla_target(%d): handle(cmd) -> %08x, timeout %d, ox_id %#x\n", - vha->vp_idx, pkt->handle, QLA_TGT_TIMEOUT, - le16_to_cpu(pkt->u.status0.ox_id)); - return 0; -} - -/* - * ha->hardware_lock supposed to be held on entry. We have already made sure - * that there is sufficient amount of request entries to not drop it. - */ -static void qlt_load_cont_data_segments(struct qla_tgt_prm *prm, - struct scsi_qla_host *vha) -{ - int cnt; - uint32_t *dword_ptr; - int enable_64bit_addressing = prm->tgt->tgt_enable_64bit_addr; - - /* Build continuation packets */ - while (prm->seg_cnt > 0) { - cont_a64_entry_t *cont_pkt64 = - (cont_a64_entry_t *)qlt_get_req_pkt(vha); - - /* - * Make sure that from cont_pkt64 none of - * 64-bit specific fields used for 32-bit - * addressing. Cast to (cont_entry_t *) for - * that. - */ - - memset(cont_pkt64, 0, sizeof(*cont_pkt64)); - - cont_pkt64->entry_count = 1; - cont_pkt64->sys_define = 0; - - if (enable_64bit_addressing) { - cont_pkt64->entry_type = CONTINUE_A64_TYPE; - dword_ptr = - (uint32_t *)&cont_pkt64->dseg_0_address; - } else { - cont_pkt64->entry_type = CONTINUE_TYPE; - dword_ptr = - (uint32_t *)&((cont_entry_t *) - cont_pkt64)->dseg_0_address; - } - - /* Load continuation entry data segments */ - for (cnt = 0; - cnt < prm->tgt->datasegs_per_cont && prm->seg_cnt; - cnt++, prm->seg_cnt--) { - *dword_ptr++ = - cpu_to_le32(pci_dma_lo32 - (sg_dma_address(prm->sg))); - if (enable_64bit_addressing) { - *dword_ptr++ = - cpu_to_le32(pci_dma_hi32 - (sg_dma_address - (prm->sg))); - } - *dword_ptr++ = cpu_to_le32(sg_dma_len(prm->sg)); - - ql_dbg(ql_dbg_tgt, vha, 0xe00d, - "S/G Segment Cont. phys_addr=%llx:%llx, len=%d\n", - (long long unsigned int) - pci_dma_hi32(sg_dma_address(prm->sg)), - (long long unsigned int) - pci_dma_lo32(sg_dma_address(prm->sg)), - (int)sg_dma_len(prm->sg)); - - prm->sg = sg_next(prm->sg); - } - } -} - -/* - * ha->hardware_lock supposed to be held on entry. We have already made sure - * that there is sufficient amount of request entries to not drop it. - */ -static void qlt_load_data_segments(struct qla_tgt_prm *prm, - struct scsi_qla_host *vha) -{ - int cnt; - uint32_t *dword_ptr; - int enable_64bit_addressing = prm->tgt->tgt_enable_64bit_addr; - struct ctio7_to_24xx *pkt24 = (struct ctio7_to_24xx *)prm->pkt; - - ql_dbg(ql_dbg_tgt, vha, 0xe00e, - "iocb->scsi_status=%x, iocb->flags=%x\n", - le16_to_cpu(pkt24->u.status0.scsi_status), - le16_to_cpu(pkt24->u.status0.flags)); - - pkt24->u.status0.transfer_length = cpu_to_le32(prm->cmd->bufflen); - - /* Setup packet address segment pointer */ - dword_ptr = pkt24->u.status0.dseg_0_address; - - /* Set total data segment count */ - if (prm->seg_cnt) - pkt24->dseg_count = cpu_to_le16(prm->seg_cnt); - - if (prm->seg_cnt == 0) { - /* No data transfer */ - *dword_ptr++ = 0; - *dword_ptr = 0; - return; - } - - /* If scatter gather */ - ql_dbg(ql_dbg_tgt, vha, 0xe00f, "%s", "Building S/G data segments..."); - - /* Load command entry data segments */ - for (cnt = 0; - (cnt < prm->tgt->datasegs_per_cmd) && prm->seg_cnt; - cnt++, prm->seg_cnt--) { - *dword_ptr++ = - cpu_to_le32(pci_dma_lo32(sg_dma_address(prm->sg))); - if (enable_64bit_addressing) { - *dword_ptr++ = - cpu_to_le32(pci_dma_hi32( - sg_dma_address(prm->sg))); - } - *dword_ptr++ = cpu_to_le32(sg_dma_len(prm->sg)); - - ql_dbg(ql_dbg_tgt, vha, 0xe010, - "S/G Segment phys_addr=%llx:%llx, len=%d\n", - (long long unsigned int)pci_dma_hi32(sg_dma_address( - prm->sg)), - (long long unsigned int)pci_dma_lo32(sg_dma_address( - prm->sg)), - (int)sg_dma_len(prm->sg)); - - prm->sg = sg_next(prm->sg); - } - - qlt_load_cont_data_segments(prm, vha); -} - -static inline int qlt_has_data(struct qla_tgt_cmd *cmd) -{ - return cmd->bufflen > 0; -} - -/* - * Called without ha->hardware_lock held - */ -static int qlt_pre_xmit_response(struct qla_tgt_cmd *cmd, - struct qla_tgt_prm *prm, int xmit_type, uint8_t scsi_status, - uint32_t *full_req_cnt) -{ - struct qla_tgt *tgt = cmd->tgt; - struct scsi_qla_host *vha = tgt->vha; - struct qla_hw_data *ha = vha->hw; - struct se_cmd *se_cmd = &cmd->se_cmd; - - if (unlikely(cmd->aborted)) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014, - "qla_target(%d): terminating exchange " - "for aborted cmd=%p (se_cmd=%p, tag=%d)", vha->vp_idx, cmd, - se_cmd, cmd->tag); - - cmd->state = QLA_TGT_STATE_ABORTED; - - qlt_send_term_exchange(vha, cmd, &cmd->atio, 0); - - /* !! At this point cmd could be already freed !! */ - return QLA_TGT_PRE_XMIT_RESP_CMD_ABORTED; - } - - ql_dbg(ql_dbg_tgt, vha, 0xe011, "qla_target(%d): tag=%u\n", - vha->vp_idx, cmd->tag); - - prm->cmd = cmd; - prm->tgt = tgt; - prm->rq_result = scsi_status; - prm->sense_buffer = &cmd->sense_buffer[0]; - prm->sense_buffer_len = TRANSPORT_SENSE_BUFFER; - prm->sg = NULL; - prm->seg_cnt = -1; - prm->req_cnt = 1; - prm->add_status_pkt = 0; - - ql_dbg(ql_dbg_tgt, vha, 0xe012, "rq_result=%x, xmit_type=%x\n", - prm->rq_result, xmit_type); - - /* Send marker if required */ - if (qlt_issue_marker(vha, 0) != QLA_SUCCESS) - return -EFAULT; - - ql_dbg(ql_dbg_tgt, vha, 0xe013, "CTIO start: vha(%d)\n", vha->vp_idx); - - if ((xmit_type & QLA_TGT_XMIT_DATA) && qlt_has_data(cmd)) { - if (qlt_pci_map_calc_cnt(prm) != 0) - return -EAGAIN; - } - - *full_req_cnt = prm->req_cnt; - - if (se_cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) { - prm->residual = se_cmd->residual_count; - ql_dbg(ql_dbg_tgt, vha, 0xe014, - "Residual underflow: %d (tag %d, " - "op %x, bufflen %d, rq_result %x)\n", prm->residual, - cmd->tag, se_cmd->t_task_cdb ? se_cmd->t_task_cdb[0] : 0, - cmd->bufflen, prm->rq_result); - prm->rq_result |= SS_RESIDUAL_UNDER; - } else if (se_cmd->se_cmd_flags & SCF_OVERFLOW_BIT) { - prm->residual = se_cmd->residual_count; - ql_dbg(ql_dbg_tgt, vha, 0xe015, - "Residual overflow: %d (tag %d, " - "op %x, bufflen %d, rq_result %x)\n", prm->residual, - cmd->tag, se_cmd->t_task_cdb ? se_cmd->t_task_cdb[0] : 0, - cmd->bufflen, prm->rq_result); - prm->rq_result |= SS_RESIDUAL_OVER; - } - - if (xmit_type & QLA_TGT_XMIT_STATUS) { - /* - * If QLA_TGT_XMIT_DATA is not set, add_status_pkt will be - * ignored in *xmit_response() below - */ - if (qlt_has_data(cmd)) { - if (QLA_TGT_SENSE_VALID(prm->sense_buffer) || - (IS_FWI2_CAPABLE(ha) && - (prm->rq_result != 0))) { - prm->add_status_pkt = 1; - (*full_req_cnt)++; - } - } - } - - ql_dbg(ql_dbg_tgt, vha, 0xe016, - "req_cnt=%d, full_req_cnt=%d, add_status_pkt=%d\n", - prm->req_cnt, *full_req_cnt, prm->add_status_pkt); - - return 0; -} - -static inline int qlt_need_explicit_conf(struct qla_hw_data *ha, - struct qla_tgt_cmd *cmd, int sending_sense) -{ - if (ha->tgt.enable_class_2) - return 0; - - if (sending_sense) - return cmd->conf_compl_supported; - else - return ha->tgt.enable_explicit_conf && - cmd->conf_compl_supported; -} - -#ifdef CONFIG_QLA_TGT_DEBUG_SRR -/* - * Original taken from the XFS code - */ -static unsigned long qlt_srr_random(void) -{ - static int Inited; - static unsigned long RandomValue; - static DEFINE_SPINLOCK(lock); - /* cycles pseudo-randomly through all values between 1 and 2^31 - 2 */ - register long rv; - register long lo; - register long hi; - unsigned long flags; - - spin_lock_irqsave(&lock, flags); - if (!Inited) { - RandomValue = jiffies; - Inited = 1; - } - rv = RandomValue; - hi = rv / 127773; - lo = rv % 127773; - rv = 16807 * lo - 2836 * hi; - if (rv <= 0) - rv += 2147483647; - RandomValue = rv; - spin_unlock_irqrestore(&lock, flags); - return rv; -} - -static void qlt_check_srr_debug(struct qla_tgt_cmd *cmd, int *xmit_type) -{ -#if 0 /* This is not a real status packets lost, so it won't lead to SRR */ - if ((*xmit_type & QLA_TGT_XMIT_STATUS) && (qlt_srr_random() % 200) - == 50) { - *xmit_type &= ~QLA_TGT_XMIT_STATUS; - ql_dbg(ql_dbg_tgt_mgt, cmd->vha, 0xf015, - "Dropping cmd %p (tag %d) status", cmd, cmd->tag); - } -#endif - /* - * It's currently not possible to simulate SRRs for FCP_WRITE without - * a physical link layer failure, so don't even try here.. - */ - if (cmd->dma_data_direction != DMA_FROM_DEVICE) - return; - - if (qlt_has_data(cmd) && (cmd->sg_cnt > 1) && - ((qlt_srr_random() % 100) == 20)) { - int i, leave = 0; - unsigned int tot_len = 0; - - while (leave == 0) - leave = qlt_srr_random() % cmd->sg_cnt; - - for (i = 0; i < leave; i++) - tot_len += cmd->sg[i].length; - - ql_dbg(ql_dbg_tgt_mgt, cmd->vha, 0xf016, - "Cutting cmd %p (tag %d) buffer" - " tail to len %d, sg_cnt %d (cmd->bufflen %d," - " cmd->sg_cnt %d)", cmd, cmd->tag, tot_len, leave, - cmd->bufflen, cmd->sg_cnt); - - cmd->bufflen = tot_len; - cmd->sg_cnt = leave; - } - - if (qlt_has_data(cmd) && ((qlt_srr_random() % 100) == 70)) { - unsigned int offset = qlt_srr_random() % cmd->bufflen; - - ql_dbg(ql_dbg_tgt_mgt, cmd->vha, 0xf017, - "Cutting cmd %p (tag %d) buffer head " - "to offset %d (cmd->bufflen %d)", cmd, cmd->tag, offset, - cmd->bufflen); - if (offset == 0) - *xmit_type &= ~QLA_TGT_XMIT_DATA; - else if (qlt_set_data_offset(cmd, offset)) { - ql_dbg(ql_dbg_tgt_mgt, cmd->vha, 0xf018, - "qlt_set_data_offset() failed (tag %d)", cmd->tag); - } - } -} -#else -static inline void qlt_check_srr_debug(struct qla_tgt_cmd *cmd, int *xmit_type) -{} -#endif - -static void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio, - struct qla_tgt_prm *prm) -{ - prm->sense_buffer_len = min_t(uint32_t, prm->sense_buffer_len, - (uint32_t)sizeof(ctio->u.status1.sense_data)); - ctio->u.status0.flags |= - __constant_cpu_to_le16(CTIO7_FLAGS_SEND_STATUS); - if (qlt_need_explicit_conf(prm->tgt->ha, prm->cmd, 0)) { - ctio->u.status0.flags |= __constant_cpu_to_le16( - CTIO7_FLAGS_EXPLICIT_CONFORM | - CTIO7_FLAGS_CONFORM_REQ); - } - ctio->u.status0.residual = cpu_to_le32(prm->residual); - ctio->u.status0.scsi_status = cpu_to_le16(prm->rq_result); - if (QLA_TGT_SENSE_VALID(prm->sense_buffer)) { - int i; - - if (qlt_need_explicit_conf(prm->tgt->ha, prm->cmd, 1)) { - if (prm->cmd->se_cmd.scsi_status != 0) { - ql_dbg(ql_dbg_tgt, prm->cmd->vha, 0xe017, - "Skipping EXPLICIT_CONFORM and " - "CTIO7_FLAGS_CONFORM_REQ for FCP READ w/ " - "non GOOD status\n"); - goto skip_explict_conf; - } - ctio->u.status1.flags |= __constant_cpu_to_le16( - CTIO7_FLAGS_EXPLICIT_CONFORM | - CTIO7_FLAGS_CONFORM_REQ); - } -skip_explict_conf: - ctio->u.status1.flags &= - ~__constant_cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_0); - ctio->u.status1.flags |= - __constant_cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1); - ctio->u.status1.scsi_status |= - __constant_cpu_to_le16(SS_SENSE_LEN_VALID); - ctio->u.status1.sense_length = - cpu_to_le16(prm->sense_buffer_len); - for (i = 0; i < prm->sense_buffer_len/4; i++) - ((uint32_t *)ctio->u.status1.sense_data)[i] = - cpu_to_be32(((uint32_t *)prm->sense_buffer)[i]); -#if 0 - if (unlikely((prm->sense_buffer_len % 4) != 0)) { - static int q; - if (q < 10) { - ql_dbg(ql_dbg_tgt, vha, 0xe04f, - "qla_target(%d): %d bytes of sense " - "lost", prm->tgt->ha->vp_idx, - prm->sense_buffer_len % 4); - q++; - } - } -#endif - } else { - ctio->u.status1.flags &= - ~__constant_cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_0); - ctio->u.status1.flags |= - __constant_cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1); - ctio->u.status1.sense_length = 0; - memset(ctio->u.status1.sense_data, 0, - sizeof(ctio->u.status1.sense_data)); - } - - /* Sense with len > 24, is it possible ??? */ -} - -/* - * Callback to setup response of xmit_type of QLA_TGT_XMIT_DATA and * - * QLA_TGT_XMIT_STATUS for >= 24xx silicon - */ -int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, - uint8_t scsi_status) -{ - struct scsi_qla_host *vha = cmd->vha; - struct qla_hw_data *ha = vha->hw; - struct ctio7_to_24xx *pkt; - struct qla_tgt_prm prm; - uint32_t full_req_cnt = 0; - unsigned long flags = 0; - int res; - - memset(&prm, 0, sizeof(prm)); - qlt_check_srr_debug(cmd, &xmit_type); - - ql_dbg(ql_dbg_tgt, cmd->vha, 0xe018, - "is_send_status=%d, cmd->bufflen=%d, cmd->sg_cnt=%d, " - "cmd->dma_data_direction=%d\n", (xmit_type & QLA_TGT_XMIT_STATUS) ? - 1 : 0, cmd->bufflen, cmd->sg_cnt, cmd->dma_data_direction); - - res = qlt_pre_xmit_response(cmd, &prm, xmit_type, scsi_status, - &full_req_cnt); - if (unlikely(res != 0)) { - if (res == QLA_TGT_PRE_XMIT_RESP_CMD_ABORTED) - return 0; - - return res; - } - - spin_lock_irqsave(&ha->hardware_lock, flags); - - /* Does F/W have an IOCBs for this request */ - res = qlt_check_reserve_free_req(vha, full_req_cnt); - if (unlikely(res)) - goto out_unmap_unlock; - - res = qlt_24xx_build_ctio_pkt(&prm, vha); - if (unlikely(res != 0)) - goto out_unmap_unlock; - - - pkt = (struct ctio7_to_24xx *)prm.pkt; - - if (qlt_has_data(cmd) && (xmit_type & QLA_TGT_XMIT_DATA)) { - pkt->u.status0.flags |= - __constant_cpu_to_le16(CTIO7_FLAGS_DATA_IN | - CTIO7_FLAGS_STATUS_MODE_0); - - qlt_load_data_segments(&prm, vha); - - if (prm.add_status_pkt == 0) { - if (xmit_type & QLA_TGT_XMIT_STATUS) { - pkt->u.status0.scsi_status = - cpu_to_le16(prm.rq_result); - pkt->u.status0.residual = - cpu_to_le32(prm.residual); - pkt->u.status0.flags |= __constant_cpu_to_le16( - CTIO7_FLAGS_SEND_STATUS); - if (qlt_need_explicit_conf(ha, cmd, 0)) { - pkt->u.status0.flags |= - __constant_cpu_to_le16( - CTIO7_FLAGS_EXPLICIT_CONFORM | - CTIO7_FLAGS_CONFORM_REQ); - } - } - - } else { - /* - * We have already made sure that there is sufficient - * amount of request entries to not drop HW lock in - * req_pkt(). - */ - struct ctio7_to_24xx *ctio = - (struct ctio7_to_24xx *)qlt_get_req_pkt(vha); - - ql_dbg(ql_dbg_tgt, vha, 0xe019, - "Building additional status packet\n"); - - memcpy(ctio, pkt, sizeof(*ctio)); - ctio->entry_count = 1; - ctio->dseg_count = 0; - ctio->u.status1.flags &= ~__constant_cpu_to_le16( - CTIO7_FLAGS_DATA_IN); - - /* Real finish is ctio_m1's finish */ - pkt->handle |= CTIO_INTERMEDIATE_HANDLE_MARK; - pkt->u.status0.flags |= __constant_cpu_to_le16( - CTIO7_FLAGS_DONT_RET_CTIO); - qlt_24xx_init_ctio_to_isp((struct ctio7_to_24xx *)ctio, - &prm); - pr_debug("Status CTIO7: %p\n", ctio); - } - } else - qlt_24xx_init_ctio_to_isp(pkt, &prm); - - - cmd->state = QLA_TGT_STATE_PROCESSED; /* Mid-level is done processing */ - - ql_dbg(ql_dbg_tgt, vha, 0xe01a, - "Xmitting CTIO7 response pkt for 24xx: %p scsi_status: 0x%02x\n", - pkt, scsi_status); - - qla2x00_start_iocbs(vha, vha->req); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - return 0; - -out_unmap_unlock: - if (cmd->sg_mapped) - qlt_unmap_sg(vha, cmd); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - return res; -} -EXPORT_SYMBOL(qlt_xmit_response); - -int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) -{ - struct ctio7_to_24xx *pkt; - struct scsi_qla_host *vha = cmd->vha; - struct qla_hw_data *ha = vha->hw; - struct qla_tgt *tgt = cmd->tgt; - struct qla_tgt_prm prm; - unsigned long flags; - int res = 0; - - memset(&prm, 0, sizeof(prm)); - prm.cmd = cmd; - prm.tgt = tgt; - prm.sg = NULL; - prm.req_cnt = 1; - - /* Send marker if required */ - if (qlt_issue_marker(vha, 0) != QLA_SUCCESS) - return -EIO; - - ql_dbg(ql_dbg_tgt, vha, 0xe01b, "CTIO_start: vha(%d)", - (int)vha->vp_idx); - - /* Calculate number of entries and segments required */ - if (qlt_pci_map_calc_cnt(&prm) != 0) - return -EAGAIN; - - spin_lock_irqsave(&ha->hardware_lock, flags); - - /* Does F/W have an IOCBs for this request */ - res = qlt_check_reserve_free_req(vha, prm.req_cnt); - if (res != 0) - goto out_unlock_free_unmap; - - res = qlt_24xx_build_ctio_pkt(&prm, vha); - if (unlikely(res != 0)) - goto out_unlock_free_unmap; - pkt = (struct ctio7_to_24xx *)prm.pkt; - pkt->u.status0.flags |= __constant_cpu_to_le16(CTIO7_FLAGS_DATA_OUT | - CTIO7_FLAGS_STATUS_MODE_0); - qlt_load_data_segments(&prm, vha); - - cmd->state = QLA_TGT_STATE_NEED_DATA; - - qla2x00_start_iocbs(vha, vha->req); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - return res; - -out_unlock_free_unmap: - if (cmd->sg_mapped) - qlt_unmap_sg(vha, cmd); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - return res; -} -EXPORT_SYMBOL(qlt_rdy_to_xfer); - -/* If hardware_lock held on entry, might drop it, then reaquire */ -/* This function sends the appropriate CTIO to ISP 2xxx or 24xx */ -static int __qlt_send_term_exchange(struct scsi_qla_host *vha, - struct qla_tgt_cmd *cmd, - struct atio_from_isp *atio) -{ - struct ctio7_to_24xx *ctio24; - struct qla_hw_data *ha = vha->hw; - request_t *pkt; - int ret = 0; - - ql_dbg(ql_dbg_tgt, vha, 0xe01c, "Sending TERM EXCH CTIO (ha=%p)\n", ha); - - pkt = (request_t *)qla2x00_alloc_iocbs(vha, NULL); - if (pkt == NULL) { - ql_dbg(ql_dbg_tgt, vha, 0xe050, - "qla_target(%d): %s failed: unable to allocate " - "request packet\n", vha->vp_idx, __func__); - return -ENOMEM; - } - - if (cmd != NULL) { - if (cmd->state < QLA_TGT_STATE_PROCESSED) { - ql_dbg(ql_dbg_tgt, vha, 0xe051, - "qla_target(%d): Terminating cmd %p with " - "incorrect state %d\n", vha->vp_idx, cmd, - cmd->state); - } else - ret = 1; - } - - pkt->entry_count = 1; - pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK; - - ctio24 = (struct ctio7_to_24xx *)pkt; - ctio24->entry_type = CTIO_TYPE7; - ctio24->nport_handle = cmd ? cmd->loop_id : CTIO7_NHANDLE_UNRECOGNIZED; - ctio24->timeout = __constant_cpu_to_le16(QLA_TGT_TIMEOUT); - ctio24->vp_index = vha->vp_idx; - ctio24->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2]; - ctio24->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1]; - ctio24->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0]; - ctio24->exchange_addr = atio->u.isp24.exchange_addr; - ctio24->u.status1.flags = (atio->u.isp24.attr << 9) | - __constant_cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1 | - CTIO7_FLAGS_TERMINATE); - ctio24->u.status1.ox_id = swab16(atio->u.isp24.fcp_hdr.ox_id); - - /* Most likely, it isn't needed */ - ctio24->u.status1.residual = get_unaligned((uint32_t *) - &atio->u.isp24.fcp_cmnd.add_cdb[ - atio->u.isp24.fcp_cmnd.add_cdb_len]); - if (ctio24->u.status1.residual != 0) - ctio24->u.status1.scsi_status |= SS_RESIDUAL_UNDER; - - qla2x00_start_iocbs(vha, vha->req); - return ret; -} - -static void qlt_send_term_exchange(struct scsi_qla_host *vha, - struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked) -{ - unsigned long flags; - int rc; - - if (qlt_issue_marker(vha, ha_locked) < 0) - return; - - if (ha_locked) { - rc = __qlt_send_term_exchange(vha, cmd, atio); - goto done; - } - spin_lock_irqsave(&vha->hw->hardware_lock, flags); - rc = __qlt_send_term_exchange(vha, cmd, atio); - spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); -done: - if (rc == 1) { - if (!ha_locked && !in_interrupt()) - msleep(250); /* just in case */ - - vha->hw->tgt.tgt_ops->free_cmd(cmd); - } -} - -void qlt_free_cmd(struct qla_tgt_cmd *cmd) -{ - BUG_ON(cmd->sg_mapped); - - if (unlikely(cmd->free_sg)) - kfree(cmd->sg); - kmem_cache_free(qla_tgt_cmd_cachep, cmd); -} -EXPORT_SYMBOL(qlt_free_cmd); - -/* ha->hardware_lock supposed to be held on entry */ -static int qlt_prepare_srr_ctio(struct scsi_qla_host *vha, - struct qla_tgt_cmd *cmd, void *ctio) -{ - struct qla_tgt_srr_ctio *sc; - struct qla_hw_data *ha = vha->hw; - struct qla_tgt *tgt = ha->tgt.qla_tgt; - struct qla_tgt_srr_imm *imm; - - tgt->ctio_srr_id++; - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf019, - "qla_target(%d): CTIO with SRR status received\n", vha->vp_idx); - - if (!ctio) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf055, - "qla_target(%d): SRR CTIO, but ctio is NULL\n", - vha->vp_idx); - return -EINVAL; - } - - sc = kzalloc(sizeof(*sc), GFP_ATOMIC); - if (sc != NULL) { - sc->cmd = cmd; - /* IRQ is already OFF */ - spin_lock(&tgt->srr_lock); - sc->srr_id = tgt->ctio_srr_id; - list_add_tail(&sc->srr_list_entry, - &tgt->srr_ctio_list); - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01a, - "CTIO SRR %p added (id %d)\n", sc, sc->srr_id); - if (tgt->imm_srr_id == tgt->ctio_srr_id) { - int found = 0; - list_for_each_entry(imm, &tgt->srr_imm_list, - srr_list_entry) { - if (imm->srr_id == sc->srr_id) { - found = 1; - break; - } - } - if (found) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01b, - "Scheduling srr work\n"); - schedule_work(&tgt->srr_work); - } else { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf056, - "qla_target(%d): imm_srr_id " - "== ctio_srr_id (%d), but there is no " - "corresponding SRR IMM, deleting CTIO " - "SRR %p\n", vha->vp_idx, - tgt->ctio_srr_id, sc); - list_del(&sc->srr_list_entry); - spin_unlock(&tgt->srr_lock); - - kfree(sc); - return -EINVAL; - } - } - spin_unlock(&tgt->srr_lock); - } else { - struct qla_tgt_srr_imm *ti; - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf057, - "qla_target(%d): Unable to allocate SRR CTIO entry\n", - vha->vp_idx); - spin_lock(&tgt->srr_lock); - list_for_each_entry_safe(imm, ti, &tgt->srr_imm_list, - srr_list_entry) { - if (imm->srr_id == tgt->ctio_srr_id) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01c, - "IMM SRR %p deleted (id %d)\n", - imm, imm->srr_id); - list_del(&imm->srr_list_entry); - qlt_reject_free_srr_imm(vha, imm, 1); - } - } - spin_unlock(&tgt->srr_lock); - - return -ENOMEM; - } - - return 0; -} - -/* - * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire - */ -static int qlt_term_ctio_exchange(struct scsi_qla_host *vha, void *ctio, - struct qla_tgt_cmd *cmd, uint32_t status) -{ - int term = 0; - - if (ctio != NULL) { - struct ctio7_from_24xx *c = (struct ctio7_from_24xx *)ctio; - term = !(c->flags & - __constant_cpu_to_le16(OF_TERM_EXCH)); - } else - term = 1; - - if (term) - qlt_send_term_exchange(vha, cmd, &cmd->atio, 1); - - return term; -} - -/* ha->hardware_lock supposed to be held on entry */ -static inline struct qla_tgt_cmd *qlt_get_cmd(struct scsi_qla_host *vha, - uint32_t handle) -{ - struct qla_hw_data *ha = vha->hw; - - handle--; - if (ha->tgt.cmds[handle] != NULL) { - struct qla_tgt_cmd *cmd = ha->tgt.cmds[handle]; - ha->tgt.cmds[handle] = NULL; - return cmd; - } else - return NULL; -} - -/* ha->hardware_lock supposed to be held on entry */ -static struct qla_tgt_cmd *qlt_ctio_to_cmd(struct scsi_qla_host *vha, - uint32_t handle, void *ctio) -{ - struct qla_tgt_cmd *cmd = NULL; - - /* Clear out internal marks */ - handle &= ~(CTIO_COMPLETION_HANDLE_MARK | - CTIO_INTERMEDIATE_HANDLE_MARK); - - if (handle != QLA_TGT_NULL_HANDLE) { - if (unlikely(handle == QLA_TGT_SKIP_HANDLE)) { - ql_dbg(ql_dbg_tgt, vha, 0xe01d, "%s", - "SKIP_HANDLE CTIO\n"); - return NULL; - } - /* handle-1 is actually used */ - if (unlikely(handle > MAX_OUTSTANDING_COMMANDS)) { - ql_dbg(ql_dbg_tgt, vha, 0xe052, - "qla_target(%d): Wrong handle %x received\n", - vha->vp_idx, handle); - return NULL; - } - cmd = qlt_get_cmd(vha, handle); - if (unlikely(cmd == NULL)) { - ql_dbg(ql_dbg_tgt, vha, 0xe053, - "qla_target(%d): Suspicious: unable to " - "find the command with handle %x\n", vha->vp_idx, - handle); - return NULL; - } - } else if (ctio != NULL) { - /* We can't get loop ID from CTIO7 */ - ql_dbg(ql_dbg_tgt, vha, 0xe054, - "qla_target(%d): Wrong CTIO received: QLA24xx doesn't " - "support NULL handles\n", vha->vp_idx); - return NULL; - } - - return cmd; -} - -/* - * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire - */ -static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle, - uint32_t status, void *ctio) -{ - struct qla_hw_data *ha = vha->hw; - struct se_cmd *se_cmd; - struct target_core_fabric_ops *tfo; - struct qla_tgt_cmd *cmd; - - ql_dbg(ql_dbg_tgt, vha, 0xe01e, - "qla_target(%d): handle(ctio %p status %#x) <- %08x\n", - vha->vp_idx, ctio, status, handle); - - if (handle & CTIO_INTERMEDIATE_HANDLE_MARK) { - /* That could happen only in case of an error/reset/abort */ - if (status != CTIO_SUCCESS) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01d, - "Intermediate CTIO received" - " (status %x)\n", status); - } - return; - } - - cmd = qlt_ctio_to_cmd(vha, handle, ctio); - if (cmd == NULL) { - if (status != CTIO_SUCCESS) - qlt_term_ctio_exchange(vha, ctio, NULL, status); - return; - } - se_cmd = &cmd->se_cmd; - tfo = se_cmd->se_tfo; - - if (cmd->sg_mapped) - qlt_unmap_sg(vha, cmd); - - if (unlikely(status != CTIO_SUCCESS)) { - switch (status & 0xFFFF) { - case CTIO_LIP_RESET: - case CTIO_TARGET_RESET: - case CTIO_ABORTED: - case CTIO_TIMEOUT: - case CTIO_INVALID_RX_ID: - /* They are OK */ - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf058, - "qla_target(%d): CTIO with " - "status %#x received, state %x, se_cmd %p, " - "(LIP_RESET=e, ABORTED=2, TARGET_RESET=17, " - "TIMEOUT=b, INVALID_RX_ID=8)\n", vha->vp_idx, - status, cmd->state, se_cmd); - break; - - case CTIO_PORT_LOGGED_OUT: - case CTIO_PORT_UNAVAILABLE: - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf059, - "qla_target(%d): CTIO with PORT LOGGED " - "OUT (29) or PORT UNAVAILABLE (28) status %x " - "received (state %x, se_cmd %p)\n", vha->vp_idx, - status, cmd->state, se_cmd); - break; - - case CTIO_SRR_RECEIVED: - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05a, - "qla_target(%d): CTIO with SRR_RECEIVED" - " status %x received (state %x, se_cmd %p)\n", - vha->vp_idx, status, cmd->state, se_cmd); - if (qlt_prepare_srr_ctio(vha, cmd, ctio) != 0) - break; - else - return; - - default: - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05b, - "qla_target(%d): CTIO with error status " - "0x%x received (state %x, se_cmd %p\n", - vha->vp_idx, status, cmd->state, se_cmd); - break; - } - - if (cmd->state != QLA_TGT_STATE_NEED_DATA) - if (qlt_term_ctio_exchange(vha, ctio, cmd, status)) - return; - } - - if (cmd->state == QLA_TGT_STATE_PROCESSED) { - ql_dbg(ql_dbg_tgt, vha, 0xe01f, "Command %p finished\n", cmd); - } else if (cmd->state == QLA_TGT_STATE_NEED_DATA) { - int rx_status = 0; - - cmd->state = QLA_TGT_STATE_DATA_IN; - - if (unlikely(status != CTIO_SUCCESS)) - rx_status = -EIO; - else - cmd->write_data_transferred = 1; - - ql_dbg(ql_dbg_tgt, vha, 0xe020, - "Data received, context %x, rx_status %d\n", - 0x0, rx_status); - - ha->tgt.tgt_ops->handle_data(cmd); - return; - } else if (cmd->state == QLA_TGT_STATE_ABORTED) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01e, - "Aborted command %p (tag %d) finished\n", cmd, cmd->tag); - } else { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05c, - "qla_target(%d): A command in state (%d) should " - "not return a CTIO complete\n", vha->vp_idx, cmd->state); - } - - if (unlikely(status != CTIO_SUCCESS)) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf01f, "Finishing failed CTIO\n"); - dump_stack(); - } - - ha->tgt.tgt_ops->free_cmd(cmd); -} - -/* ha->hardware_lock supposed to be held on entry */ -/* called via callback from qla2xxx */ -void qlt_ctio_completion(struct scsi_qla_host *vha, uint32_t handle) -{ - struct qla_hw_data *ha = vha->hw; - struct qla_tgt *tgt = ha->tgt.qla_tgt; - - if (likely(tgt == NULL)) { - ql_dbg(ql_dbg_tgt, vha, 0xe021, - "CTIO, but target mode not enabled" - " (ha %d %p handle %#x)", vha->vp_idx, ha, handle); - return; - } - - tgt->irq_cmd_count++; - qlt_do_ctio_completion(vha, handle, CTIO_SUCCESS, NULL); - tgt->irq_cmd_count--; -} - -static inline int qlt_get_fcp_task_attr(struct scsi_qla_host *vha, - uint8_t task_codes) -{ - int fcp_task_attr; - - switch (task_codes) { - case ATIO_SIMPLE_QUEUE: - fcp_task_attr = MSG_SIMPLE_TAG; - break; - case ATIO_HEAD_OF_QUEUE: - fcp_task_attr = MSG_HEAD_TAG; - break; - case ATIO_ORDERED_QUEUE: - fcp_task_attr = MSG_ORDERED_TAG; - break; - case ATIO_ACA_QUEUE: - fcp_task_attr = MSG_ACA_TAG; - break; - case ATIO_UNTAGGED: - fcp_task_attr = MSG_SIMPLE_TAG; - break; - default: - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05d, - "qla_target: unknown task code %x, use ORDERED instead\n", - task_codes); - fcp_task_attr = MSG_ORDERED_TAG; - break; - } - - return fcp_task_attr; -} - -static struct qla_tgt_sess *qlt_make_local_sess(struct scsi_qla_host *, - uint8_t *); -/* - * Process context for I/O path into tcm_qla2xxx code - */ -static void qlt_do_work(struct work_struct *work) -{ - struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work); - scsi_qla_host_t *vha = cmd->vha; - struct qla_hw_data *ha = vha->hw; - struct qla_tgt *tgt = ha->tgt.qla_tgt; - struct qla_tgt_sess *sess = NULL; - struct atio_from_isp *atio = &cmd->atio; - unsigned char *cdb; - unsigned long flags; - uint32_t data_length; - int ret, fcp_task_attr, data_dir, bidi = 0; - - if (tgt->tgt_stop) - goto out_term; - - spin_lock_irqsave(&ha->hardware_lock, flags); - sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, - atio->u.isp24.fcp_hdr.s_id); - if (sess) { - if (unlikely(sess->tearing_down)) { - sess = NULL; - spin_unlock_irqrestore(&ha->hardware_lock, flags); - goto out_term; - } else { - /* - * Do the extra kref_get() before dropping - * qla_hw_data->hardware_lock. - */ - kref_get(&sess->se_sess->sess_kref); - } - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - if (unlikely(!sess)) { - uint8_t *s_id = atio->u.isp24.fcp_hdr.s_id; - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf022, - "qla_target(%d): Unable to find wwn login" - " (s_id %x:%x:%x), trying to create it manually\n", - vha->vp_idx, s_id[0], s_id[1], s_id[2]); - - if (atio->u.raw.entry_count > 1) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf023, - "Dropping multy entry cmd %p\n", cmd); - goto out_term; - } - - mutex_lock(&ha->tgt.tgt_mutex); - sess = qlt_make_local_sess(vha, s_id); - /* sess has an extra creation ref. */ - mutex_unlock(&ha->tgt.tgt_mutex); - - if (!sess) - goto out_term; - } - - cmd->sess = sess; - cmd->loop_id = sess->loop_id; - cmd->conf_compl_supported = sess->conf_compl_supported; - - cdb = &atio->u.isp24.fcp_cmnd.cdb[0]; - cmd->tag = atio->u.isp24.exchange_addr; - cmd->unpacked_lun = scsilun_to_int( - (struct scsi_lun *)&atio->u.isp24.fcp_cmnd.lun); - - if (atio->u.isp24.fcp_cmnd.rddata && - atio->u.isp24.fcp_cmnd.wrdata) { - bidi = 1; - data_dir = DMA_TO_DEVICE; - } else if (atio->u.isp24.fcp_cmnd.rddata) - data_dir = DMA_FROM_DEVICE; - else if (atio->u.isp24.fcp_cmnd.wrdata) - data_dir = DMA_TO_DEVICE; - else - data_dir = DMA_NONE; - - fcp_task_attr = qlt_get_fcp_task_attr(vha, - atio->u.isp24.fcp_cmnd.task_attr); - data_length = be32_to_cpu(get_unaligned((uint32_t *) - &atio->u.isp24.fcp_cmnd.add_cdb[ - atio->u.isp24.fcp_cmnd.add_cdb_len])); - - ql_dbg(ql_dbg_tgt, vha, 0xe022, - "qla_target: START qla command: %p lun: 0x%04x (tag %d)\n", - cmd, cmd->unpacked_lun, cmd->tag); - - ret = vha->hw->tgt.tgt_ops->handle_cmd(vha, cmd, cdb, data_length, - fcp_task_attr, data_dir, bidi); - if (ret != 0) - goto out_term; - /* - * Drop extra session reference from qla_tgt_handle_cmd_for_atio*( - */ - ha->tgt.tgt_ops->put_sess(sess); - return; - -out_term: - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf020, "Terminating work cmd %p", cmd); - /* - * cmd has not sent to target yet, so pass NULL as the second argument - */ - spin_lock_irqsave(&ha->hardware_lock, flags); - qlt_send_term_exchange(vha, NULL, &cmd->atio, 1); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - if (sess) - ha->tgt.tgt_ops->put_sess(sess); -} - -/* ha->hardware_lock supposed to be held on entry */ -static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, - struct atio_from_isp *atio) -{ - struct qla_hw_data *ha = vha->hw; - struct qla_tgt *tgt = ha->tgt.qla_tgt; - struct qla_tgt_cmd *cmd; - - if (unlikely(tgt->tgt_stop)) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf021, - "New command while device %p is shutting down\n", tgt); - return -EFAULT; - } - - cmd = kmem_cache_zalloc(qla_tgt_cmd_cachep, GFP_ATOMIC); - if (!cmd) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05e, - "qla_target(%d): Allocation of cmd failed\n", vha->vp_idx); - return -ENOMEM; - } - - INIT_LIST_HEAD(&cmd->cmd_list); - - memcpy(&cmd->atio, atio, sizeof(*atio)); - cmd->state = QLA_TGT_STATE_NEW; - cmd->tgt = ha->tgt.qla_tgt; - cmd->vha = vha; - - INIT_WORK(&cmd->work, qlt_do_work); - queue_work(qla_tgt_wq, &cmd->work); - return 0; - -} - -/* ha->hardware_lock supposed to be held on entry */ -static int qlt_issue_task_mgmt(struct qla_tgt_sess *sess, uint32_t lun, - int fn, void *iocb, int flags) -{ - struct scsi_qla_host *vha = sess->vha; - struct qla_hw_data *ha = vha->hw; - struct qla_tgt_mgmt_cmd *mcmd; - int res; - uint8_t tmr_func; - - mcmd = mempool_alloc(qla_tgt_mgmt_cmd_mempool, GFP_ATOMIC); - if (!mcmd) { - ql_dbg(ql_dbg_tgt_tmr, vha, 0x10009, - "qla_target(%d): Allocation of management " - "command failed, some commands and their data could " - "leak\n", vha->vp_idx); - return -ENOMEM; - } - memset(mcmd, 0, sizeof(*mcmd)); - mcmd->sess = sess; - - if (iocb) { - memcpy(&mcmd->orig_iocb.imm_ntfy, iocb, - sizeof(mcmd->orig_iocb.imm_ntfy)); - } - mcmd->tmr_func = fn; - mcmd->flags = flags; - - switch (fn) { - case QLA_TGT_CLEAR_ACA: - ql_dbg(ql_dbg_tgt_tmr, vha, 0x10000, - "qla_target(%d): CLEAR_ACA received\n", sess->vha->vp_idx); - tmr_func = TMR_CLEAR_ACA; - break; - - case QLA_TGT_TARGET_RESET: - ql_dbg(ql_dbg_tgt_tmr, vha, 0x10001, - "qla_target(%d): TARGET_RESET received\n", - sess->vha->vp_idx); - tmr_func = TMR_TARGET_WARM_RESET; - break; - - case QLA_TGT_LUN_RESET: - ql_dbg(ql_dbg_tgt_tmr, vha, 0x10002, - "qla_target(%d): LUN_RESET received\n", sess->vha->vp_idx); - tmr_func = TMR_LUN_RESET; - break; - - case QLA_TGT_CLEAR_TS: - ql_dbg(ql_dbg_tgt_tmr, vha, 0x10003, - "qla_target(%d): CLEAR_TS received\n", sess->vha->vp_idx); - tmr_func = TMR_CLEAR_TASK_SET; - break; - - case QLA_TGT_ABORT_TS: - ql_dbg(ql_dbg_tgt_tmr, vha, 0x10004, - "qla_target(%d): ABORT_TS received\n", sess->vha->vp_idx); - tmr_func = TMR_ABORT_TASK_SET; - break; -#if 0 - case QLA_TGT_ABORT_ALL: - ql_dbg(ql_dbg_tgt_tmr, vha, 0x10005, - "qla_target(%d): Doing ABORT_ALL_TASKS\n", - sess->vha->vp_idx); - tmr_func = 0; - break; - - case QLA_TGT_ABORT_ALL_SESS: - ql_dbg(ql_dbg_tgt_tmr, vha, 0x10006, - "qla_target(%d): Doing ABORT_ALL_TASKS_SESS\n", - sess->vha->vp_idx); - tmr_func = 0; - break; - - case QLA_TGT_NEXUS_LOSS_SESS: - ql_dbg(ql_dbg_tgt_tmr, vha, 0x10007, - "qla_target(%d): Doing NEXUS_LOSS_SESS\n", - sess->vha->vp_idx); - tmr_func = 0; - break; - - case QLA_TGT_NEXUS_LOSS: - ql_dbg(ql_dbg_tgt_tmr, vha, 0x10008, - "qla_target(%d): Doing NEXUS_LOSS\n", sess->vha->vp_idx); - tmr_func = 0; - break; -#endif - default: - ql_dbg(ql_dbg_tgt_tmr, vha, 0x1000a, - "qla_target(%d): Unknown task mgmt fn 0x%x\n", - sess->vha->vp_idx, fn); - mempool_free(mcmd, qla_tgt_mgmt_cmd_mempool); - return -ENOSYS; - } - - res = ha->tgt.tgt_ops->handle_tmr(mcmd, lun, tmr_func, 0); - if (res != 0) { - ql_dbg(ql_dbg_tgt_tmr, vha, 0x1000b, - "qla_target(%d): tgt.tgt_ops->handle_tmr() failed: %d\n", - sess->vha->vp_idx, res); - mempool_free(mcmd, qla_tgt_mgmt_cmd_mempool); - return -EFAULT; - } - - return 0; -} - -/* ha->hardware_lock supposed to be held on entry */ -static int qlt_handle_task_mgmt(struct scsi_qla_host *vha, void *iocb) -{ - struct atio_from_isp *a = (struct atio_from_isp *)iocb; - struct qla_hw_data *ha = vha->hw; - struct qla_tgt *tgt; - struct qla_tgt_sess *sess; - uint32_t lun, unpacked_lun; - int lun_size, fn; - - tgt = ha->tgt.qla_tgt; - - lun = a->u.isp24.fcp_cmnd.lun; - lun_size = sizeof(a->u.isp24.fcp_cmnd.lun); - fn = a->u.isp24.fcp_cmnd.task_mgmt_flags; - sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, - a->u.isp24.fcp_hdr.s_id); - unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun); - - if (!sess) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf024, - "qla_target(%d): task mgmt fn 0x%x for " - "non-existant session\n", vha->vp_idx, fn); - return qlt_sched_sess_work(tgt, QLA_TGT_SESS_WORK_TM, iocb, - sizeof(struct atio_from_isp)); - } - - return qlt_issue_task_mgmt(sess, unpacked_lun, fn, iocb, 0); -} - -/* ha->hardware_lock supposed to be held on entry */ -static int __qlt_abort_task(struct scsi_qla_host *vha, - struct imm_ntfy_from_isp *iocb, struct qla_tgt_sess *sess) -{ - struct atio_from_isp *a = (struct atio_from_isp *)iocb; - struct qla_hw_data *ha = vha->hw; - struct qla_tgt_mgmt_cmd *mcmd; - uint32_t lun, unpacked_lun; - int rc; - - mcmd = mempool_alloc(qla_tgt_mgmt_cmd_mempool, GFP_ATOMIC); - if (mcmd == NULL) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf05f, - "qla_target(%d): %s: Allocation of ABORT cmd failed\n", - vha->vp_idx, __func__); - return -ENOMEM; - } - memset(mcmd, 0, sizeof(*mcmd)); - - mcmd->sess = sess; - memcpy(&mcmd->orig_iocb.imm_ntfy, iocb, - sizeof(mcmd->orig_iocb.imm_ntfy)); - - lun = a->u.isp24.fcp_cmnd.lun; - unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun); - - rc = ha->tgt.tgt_ops->handle_tmr(mcmd, unpacked_lun, TMR_ABORT_TASK, - le16_to_cpu(iocb->u.isp2x.seq_id)); - if (rc != 0) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf060, - "qla_target(%d): tgt_ops->handle_tmr() failed: %d\n", - vha->vp_idx, rc); - mempool_free(mcmd, qla_tgt_mgmt_cmd_mempool); - return -EFAULT; - } - - return 0; -} - -/* ha->hardware_lock supposed to be held on entry */ -static int qlt_abort_task(struct scsi_qla_host *vha, - struct imm_ntfy_from_isp *iocb) -{ - struct qla_hw_data *ha = vha->hw; - struct qla_tgt_sess *sess; - int loop_id; - - loop_id = GET_TARGET_ID(ha, (struct atio_from_isp *)iocb); - - sess = ha->tgt.tgt_ops->find_sess_by_loop_id(vha, loop_id); - if (sess == NULL) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf025, - "qla_target(%d): task abort for unexisting " - "session\n", vha->vp_idx); - return qlt_sched_sess_work(ha->tgt.qla_tgt, - QLA_TGT_SESS_WORK_ABORT, iocb, sizeof(*iocb)); - } - - return __qlt_abort_task(vha, iocb, sess); -} - -/* - * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire - */ -static int qlt_24xx_handle_els(struct scsi_qla_host *vha, - struct imm_ntfy_from_isp *iocb) -{ - struct qla_hw_data *ha = vha->hw; - int res = 0; - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf026, - "qla_target(%d): Port ID: 0x%02x:%02x:%02x" - " ELS opcode: 0x%02x\n", vha->vp_idx, iocb->u.isp24.port_id[0], - iocb->u.isp24.port_id[1], iocb->u.isp24.port_id[2], - iocb->u.isp24.status_subcode); - - switch (iocb->u.isp24.status_subcode) { - case ELS_PLOGI: - case ELS_FLOGI: - case ELS_PRLI: - case ELS_LOGO: - case ELS_PRLO: - res = qlt_reset(vha, iocb, QLA_TGT_NEXUS_LOSS_SESS); - break; - case ELS_PDISC: - case ELS_ADISC: - { - struct qla_tgt *tgt = ha->tgt.qla_tgt; - if (tgt->link_reinit_iocb_pending) { - qlt_send_notify_ack(vha, &tgt->link_reinit_iocb, - 0, 0, 0, 0, 0, 0); - tgt->link_reinit_iocb_pending = 0; - } - res = 1; /* send notify ack */ - break; - } - - default: - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf061, - "qla_target(%d): Unsupported ELS command %x " - "received\n", vha->vp_idx, iocb->u.isp24.status_subcode); - res = qlt_reset(vha, iocb, QLA_TGT_NEXUS_LOSS_SESS); - break; - } - - return res; -} - -static int qlt_set_data_offset(struct qla_tgt_cmd *cmd, uint32_t offset) -{ - struct scatterlist *sg, *sgp, *sg_srr, *sg_srr_start = NULL; - size_t first_offset = 0, rem_offset = offset, tmp = 0; - int i, sg_srr_cnt, bufflen = 0; - - ql_dbg(ql_dbg_tgt, cmd->vha, 0xe023, - "Entering qla_tgt_set_data_offset: cmd: %p, cmd->sg: %p, " - "cmd->sg_cnt: %u, direction: %d\n", - cmd, cmd->sg, cmd->sg_cnt, cmd->dma_data_direction); - - /* - * FIXME: Reject non zero SRR relative offset until we can test - * this code properly. - */ - pr_debug("Rejecting non zero SRR rel_offs: %u\n", offset); - return -1; - - if (!cmd->sg || !cmd->sg_cnt) { - ql_dbg(ql_dbg_tgt, cmd->vha, 0xe055, - "Missing cmd->sg or zero cmd->sg_cnt in" - " qla_tgt_set_data_offset\n"); - return -EINVAL; - } - /* - * Walk the current cmd->sg list until we locate the new sg_srr_start - */ - for_each_sg(cmd->sg, sg, cmd->sg_cnt, i) { - ql_dbg(ql_dbg_tgt, cmd->vha, 0xe024, - "sg[%d]: %p page: %p, length: %d, offset: %d\n", - i, sg, sg_page(sg), sg->length, sg->offset); - - if ((sg->length + tmp) > offset) { - first_offset = rem_offset; - sg_srr_start = sg; - ql_dbg(ql_dbg_tgt, cmd->vha, 0xe025, - "Found matching sg[%d], using %p as sg_srr_start, " - "and using first_offset: %zu\n", i, sg, - first_offset); - break; - } - tmp += sg->length; - rem_offset -= sg->length; - } - - if (!sg_srr_start) { - ql_dbg(ql_dbg_tgt, cmd->vha, 0xe056, - "Unable to locate sg_srr_start for offset: %u\n", offset); - return -EINVAL; - } - sg_srr_cnt = (cmd->sg_cnt - i); - - sg_srr = kzalloc(sizeof(struct scatterlist) * sg_srr_cnt, GFP_KERNEL); - if (!sg_srr) { - ql_dbg(ql_dbg_tgt, cmd->vha, 0xe057, - "Unable to allocate sgp\n"); - return -ENOMEM; - } - sg_init_table(sg_srr, sg_srr_cnt); - sgp = &sg_srr[0]; - /* - * Walk the remaining list for sg_srr_start, mapping to the newly - * allocated sg_srr taking first_offset into account. - */ - for_each_sg(sg_srr_start, sg, sg_srr_cnt, i) { - if (first_offset) { - sg_set_page(sgp, sg_page(sg), - (sg->length - first_offset), first_offset); - first_offset = 0; - } else { - sg_set_page(sgp, sg_page(sg), sg->length, 0); - } - bufflen += sgp->length; - - sgp = sg_next(sgp); - if (!sgp) - break; - } - - cmd->sg = sg_srr; - cmd->sg_cnt = sg_srr_cnt; - cmd->bufflen = bufflen; - cmd->offset += offset; - cmd->free_sg = 1; - - ql_dbg(ql_dbg_tgt, cmd->vha, 0xe026, "New cmd->sg: %p\n", cmd->sg); - ql_dbg(ql_dbg_tgt, cmd->vha, 0xe027, "New cmd->sg_cnt: %u\n", - cmd->sg_cnt); - ql_dbg(ql_dbg_tgt, cmd->vha, 0xe028, "New cmd->bufflen: %u\n", - cmd->bufflen); - ql_dbg(ql_dbg_tgt, cmd->vha, 0xe029, "New cmd->offset: %u\n", - cmd->offset); - - if (cmd->sg_cnt < 0) - BUG(); - - if (cmd->bufflen < 0) - BUG(); - - return 0; -} - -static inline int qlt_srr_adjust_data(struct qla_tgt_cmd *cmd, - uint32_t srr_rel_offs, int *xmit_type) -{ - int res = 0, rel_offs; - - rel_offs = srr_rel_offs - cmd->offset; - ql_dbg(ql_dbg_tgt_mgt, cmd->vha, 0xf027, "srr_rel_offs=%d, rel_offs=%d", - srr_rel_offs, rel_offs); - - *xmit_type = QLA_TGT_XMIT_ALL; - - if (rel_offs < 0) { - ql_dbg(ql_dbg_tgt_mgt, cmd->vha, 0xf062, - "qla_target(%d): SRR rel_offs (%d) < 0", - cmd->vha->vp_idx, rel_offs); - res = -1; - } else if (rel_offs == cmd->bufflen) - *xmit_type = QLA_TGT_XMIT_STATUS; - else if (rel_offs > 0) - res = qlt_set_data_offset(cmd, rel_offs); - - return res; -} - -/* No locks, thread context */ -static void qlt_handle_srr(struct scsi_qla_host *vha, - struct qla_tgt_srr_ctio *sctio, struct qla_tgt_srr_imm *imm) -{ - struct imm_ntfy_from_isp *ntfy = - (struct imm_ntfy_from_isp *)&imm->imm_ntfy; - struct qla_hw_data *ha = vha->hw; - struct qla_tgt_cmd *cmd = sctio->cmd; - struct se_cmd *se_cmd = &cmd->se_cmd; - unsigned long flags; - int xmit_type = 0, resp = 0; - uint32_t offset; - uint16_t srr_ui; - - offset = le32_to_cpu(ntfy->u.isp24.srr_rel_offs); - srr_ui = ntfy->u.isp24.srr_ui; - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf028, "SRR cmd %p, srr_ui %x\n", - cmd, srr_ui); - - switch (srr_ui) { - case SRR_IU_STATUS: - spin_lock_irqsave(&ha->hardware_lock, flags); - qlt_send_notify_ack(vha, ntfy, - 0, 0, 0, NOTIFY_ACK_SRR_FLAGS_ACCEPT, 0, 0); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - xmit_type = QLA_TGT_XMIT_STATUS; - resp = 1; - break; - case SRR_IU_DATA_IN: - if (!cmd->sg || !cmd->sg_cnt) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf063, - "Unable to process SRR_IU_DATA_IN due to" - " missing cmd->sg, state: %d\n", cmd->state); - dump_stack(); - goto out_reject; - } - if (se_cmd->scsi_status != 0) { - ql_dbg(ql_dbg_tgt, vha, 0xe02a, - "Rejecting SRR_IU_DATA_IN with non GOOD " - "scsi_status\n"); - goto out_reject; - } - cmd->bufflen = se_cmd->data_length; - - if (qlt_has_data(cmd)) { - if (qlt_srr_adjust_data(cmd, offset, &xmit_type) != 0) - goto out_reject; - spin_lock_irqsave(&ha->hardware_lock, flags); - qlt_send_notify_ack(vha, ntfy, - 0, 0, 0, NOTIFY_ACK_SRR_FLAGS_ACCEPT, 0, 0); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - resp = 1; - } else { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf064, - "qla_target(%d): SRR for in data for cmd " - "without them (tag %d, SCSI status %d), " - "reject", vha->vp_idx, cmd->tag, - cmd->se_cmd.scsi_status); - goto out_reject; - } - break; - case SRR_IU_DATA_OUT: - if (!cmd->sg || !cmd->sg_cnt) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf065, - "Unable to process SRR_IU_DATA_OUT due to" - " missing cmd->sg\n"); - dump_stack(); - goto out_reject; - } - if (se_cmd->scsi_status != 0) { - ql_dbg(ql_dbg_tgt, vha, 0xe02b, - "Rejecting SRR_IU_DATA_OUT" - " with non GOOD scsi_status\n"); - goto out_reject; - } - cmd->bufflen = se_cmd->data_length; - - if (qlt_has_data(cmd)) { - if (qlt_srr_adjust_data(cmd, offset, &xmit_type) != 0) - goto out_reject; - spin_lock_irqsave(&ha->hardware_lock, flags); - qlt_send_notify_ack(vha, ntfy, - 0, 0, 0, NOTIFY_ACK_SRR_FLAGS_ACCEPT, 0, 0); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - if (xmit_type & QLA_TGT_XMIT_DATA) - qlt_rdy_to_xfer(cmd); - } else { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf066, - "qla_target(%d): SRR for out data for cmd " - "without them (tag %d, SCSI status %d), " - "reject", vha->vp_idx, cmd->tag, - cmd->se_cmd.scsi_status); - goto out_reject; - } - break; - default: - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf067, - "qla_target(%d): Unknown srr_ui value %x", - vha->vp_idx, srr_ui); - goto out_reject; - } - - /* Transmit response in case of status and data-in cases */ - if (resp) - qlt_xmit_response(cmd, xmit_type, se_cmd->scsi_status); - - return; - -out_reject: - spin_lock_irqsave(&ha->hardware_lock, flags); - qlt_send_notify_ack(vha, ntfy, 0, 0, 0, - NOTIFY_ACK_SRR_FLAGS_REJECT, - NOTIFY_ACK_SRR_REJECT_REASON_UNABLE_TO_PERFORM, - NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_NO_EXPL); - if (cmd->state == QLA_TGT_STATE_NEED_DATA) { - cmd->state = QLA_TGT_STATE_DATA_IN; - dump_stack(); - } else - qlt_send_term_exchange(vha, cmd, &cmd->atio, 1); - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -static void qlt_reject_free_srr_imm(struct scsi_qla_host *vha, - struct qla_tgt_srr_imm *imm, int ha_locked) -{ - struct qla_hw_data *ha = vha->hw; - unsigned long flags = 0; - - if (!ha_locked) - spin_lock_irqsave(&ha->hardware_lock, flags); - - qlt_send_notify_ack(vha, (void *)&imm->imm_ntfy, 0, 0, 0, - NOTIFY_ACK_SRR_FLAGS_REJECT, - NOTIFY_ACK_SRR_REJECT_REASON_UNABLE_TO_PERFORM, - NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_NO_EXPL); - - if (!ha_locked) - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - kfree(imm); -} - -static void qlt_handle_srr_work(struct work_struct *work) -{ - struct qla_tgt *tgt = container_of(work, struct qla_tgt, srr_work); - struct scsi_qla_host *vha = tgt->vha; - struct qla_tgt_srr_ctio *sctio; - unsigned long flags; - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf029, "Entering SRR work (tgt %p)\n", - tgt); - -restart: - spin_lock_irqsave(&tgt->srr_lock, flags); - list_for_each_entry(sctio, &tgt->srr_ctio_list, srr_list_entry) { - struct qla_tgt_srr_imm *imm, *i, *ti; - struct qla_tgt_cmd *cmd; - struct se_cmd *se_cmd; - - imm = NULL; - list_for_each_entry_safe(i, ti, &tgt->srr_imm_list, - srr_list_entry) { - if (i->srr_id == sctio->srr_id) { - list_del(&i->srr_list_entry); - if (imm) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf068, - "qla_target(%d): There must be " - "only one IMM SRR per CTIO SRR " - "(IMM SRR %p, id %d, CTIO %p\n", - vha->vp_idx, i, i->srr_id, sctio); - qlt_reject_free_srr_imm(tgt->vha, i, 0); - } else - imm = i; - } - } - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf02a, - "IMM SRR %p, CTIO SRR %p (id %d)\n", imm, sctio, - sctio->srr_id); - - if (imm == NULL) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf02b, - "Not found matching IMM for SRR CTIO (id %d)\n", - sctio->srr_id); - continue; - } else - list_del(&sctio->srr_list_entry); - - spin_unlock_irqrestore(&tgt->srr_lock, flags); - - cmd = sctio->cmd; - /* - * Reset qla_tgt_cmd SRR values and SGL pointer+count to follow - * tcm_qla2xxx_write_pending() and tcm_qla2xxx_queue_data_in() - * logic.. - */ - cmd->offset = 0; - if (cmd->free_sg) { - kfree(cmd->sg); - cmd->sg = NULL; - cmd->free_sg = 0; - } - se_cmd = &cmd->se_cmd; - - cmd->sg_cnt = se_cmd->t_data_nents; - cmd->sg = se_cmd->t_data_sg; - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf02c, - "SRR cmd %p (se_cmd %p, tag %d, op %x), " - "sg_cnt=%d, offset=%d", cmd, &cmd->se_cmd, cmd->tag, - se_cmd->t_task_cdb[0], cmd->sg_cnt, cmd->offset); - - qlt_handle_srr(vha, sctio, imm); - - kfree(imm); - kfree(sctio); - goto restart; - } - spin_unlock_irqrestore(&tgt->srr_lock, flags); -} - -/* ha->hardware_lock supposed to be held on entry */ -static void qlt_prepare_srr_imm(struct scsi_qla_host *vha, - struct imm_ntfy_from_isp *iocb) -{ - struct qla_tgt_srr_imm *imm; - struct qla_hw_data *ha = vha->hw; - struct qla_tgt *tgt = ha->tgt.qla_tgt; - struct qla_tgt_srr_ctio *sctio; - - tgt->imm_srr_id++; - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf02d, "qla_target(%d): SRR received\n", - vha->vp_idx); - - imm = kzalloc(sizeof(*imm), GFP_ATOMIC); - if (imm != NULL) { - memcpy(&imm->imm_ntfy, iocb, sizeof(imm->imm_ntfy)); - - /* IRQ is already OFF */ - spin_lock(&tgt->srr_lock); - imm->srr_id = tgt->imm_srr_id; - list_add_tail(&imm->srr_list_entry, - &tgt->srr_imm_list); - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf02e, - "IMM NTFY SRR %p added (id %d, ui %x)\n", - imm, imm->srr_id, iocb->u.isp24.srr_ui); - if (tgt->imm_srr_id == tgt->ctio_srr_id) { - int found = 0; - list_for_each_entry(sctio, &tgt->srr_ctio_list, - srr_list_entry) { - if (sctio->srr_id == imm->srr_id) { - found = 1; - break; - } - } - if (found) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf02f, "%s", - "Scheduling srr work\n"); - schedule_work(&tgt->srr_work); - } else { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf030, - "qla_target(%d): imm_srr_id " - "== ctio_srr_id (%d), but there is no " - "corresponding SRR CTIO, deleting IMM " - "SRR %p\n", vha->vp_idx, tgt->ctio_srr_id, - imm); - list_del(&imm->srr_list_entry); - - kfree(imm); - - spin_unlock(&tgt->srr_lock); - goto out_reject; - } - } - spin_unlock(&tgt->srr_lock); - } else { - struct qla_tgt_srr_ctio *ts; - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf069, - "qla_target(%d): Unable to allocate SRR IMM " - "entry, SRR request will be rejected\n", vha->vp_idx); - - /* IRQ is already OFF */ - spin_lock(&tgt->srr_lock); - list_for_each_entry_safe(sctio, ts, &tgt->srr_ctio_list, - srr_list_entry) { - if (sctio->srr_id == tgt->imm_srr_id) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf031, - "CTIO SRR %p deleted (id %d)\n", - sctio, sctio->srr_id); - list_del(&sctio->srr_list_entry); - qlt_send_term_exchange(vha, sctio->cmd, - &sctio->cmd->atio, 1); - kfree(sctio); - } - } - spin_unlock(&tgt->srr_lock); - goto out_reject; - } - - return; - -out_reject: - qlt_send_notify_ack(vha, iocb, 0, 0, 0, - NOTIFY_ACK_SRR_FLAGS_REJECT, - NOTIFY_ACK_SRR_REJECT_REASON_UNABLE_TO_PERFORM, - NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_NO_EXPL); -} - -/* - * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire - */ -static void qlt_handle_imm_notify(struct scsi_qla_host *vha, - struct imm_ntfy_from_isp *iocb) -{ - struct qla_hw_data *ha = vha->hw; - uint32_t add_flags = 0; - int send_notify_ack = 1; - uint16_t status; - - status = le16_to_cpu(iocb->u.isp2x.status); - switch (status) { - case IMM_NTFY_LIP_RESET: - { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf032, - "qla_target(%d): LIP reset (loop %#x), subcode %x\n", - vha->vp_idx, le16_to_cpu(iocb->u.isp24.nport_handle), - iocb->u.isp24.status_subcode); - - if (qlt_reset(vha, iocb, QLA_TGT_ABORT_ALL) == 0) - send_notify_ack = 0; - break; - } - - case IMM_NTFY_LIP_LINK_REINIT: - { - struct qla_tgt *tgt = ha->tgt.qla_tgt; - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf033, - "qla_target(%d): LINK REINIT (loop %#x, " - "subcode %x)\n", vha->vp_idx, - le16_to_cpu(iocb->u.isp24.nport_handle), - iocb->u.isp24.status_subcode); - if (tgt->link_reinit_iocb_pending) { - qlt_send_notify_ack(vha, &tgt->link_reinit_iocb, - 0, 0, 0, 0, 0, 0); - } - memcpy(&tgt->link_reinit_iocb, iocb, sizeof(*iocb)); - tgt->link_reinit_iocb_pending = 1; - /* - * QLogic requires to wait after LINK REINIT for possible - * PDISC or ADISC ELS commands - */ - send_notify_ack = 0; - break; - } - - case IMM_NTFY_PORT_LOGOUT: - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf034, - "qla_target(%d): Port logout (loop " - "%#x, subcode %x)\n", vha->vp_idx, - le16_to_cpu(iocb->u.isp24.nport_handle), - iocb->u.isp24.status_subcode); - - if (qlt_reset(vha, iocb, QLA_TGT_NEXUS_LOSS_SESS) == 0) - send_notify_ack = 0; - /* The sessions will be cleared in the callback, if needed */ - break; - - case IMM_NTFY_GLBL_TPRLO: - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf035, - "qla_target(%d): Global TPRLO (%x)\n", vha->vp_idx, status); - if (qlt_reset(vha, iocb, QLA_TGT_NEXUS_LOSS) == 0) - send_notify_ack = 0; - /* The sessions will be cleared in the callback, if needed */ - break; - - case IMM_NTFY_PORT_CONFIG: - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf036, - "qla_target(%d): Port config changed (%x)\n", vha->vp_idx, - status); - if (qlt_reset(vha, iocb, QLA_TGT_ABORT_ALL) == 0) - send_notify_ack = 0; - /* The sessions will be cleared in the callback, if needed */ - break; - - case IMM_NTFY_GLBL_LOGO: - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf06a, - "qla_target(%d): Link failure detected\n", - vha->vp_idx); - /* I_T nexus loss */ - if (qlt_reset(vha, iocb, QLA_TGT_NEXUS_LOSS) == 0) - send_notify_ack = 0; - break; - - case IMM_NTFY_IOCB_OVERFLOW: - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf06b, - "qla_target(%d): Cannot provide requested " - "capability (IOCB overflowed the immediate notify " - "resource count)\n", vha->vp_idx); - break; - - case IMM_NTFY_ABORT_TASK: - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf037, - "qla_target(%d): Abort Task (S %08x I %#x -> " - "L %#x)\n", vha->vp_idx, - le16_to_cpu(iocb->u.isp2x.seq_id), - GET_TARGET_ID(ha, (struct atio_from_isp *)iocb), - le16_to_cpu(iocb->u.isp2x.lun)); - if (qlt_abort_task(vha, iocb) == 0) - send_notify_ack = 0; - break; - - case IMM_NTFY_RESOURCE: - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf06c, - "qla_target(%d): Out of resources, host %ld\n", - vha->vp_idx, vha->host_no); - break; - - case IMM_NTFY_MSG_RX: - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf038, - "qla_target(%d): Immediate notify task %x\n", - vha->vp_idx, iocb->u.isp2x.task_flags); - if (qlt_handle_task_mgmt(vha, iocb) == 0) - send_notify_ack = 0; - break; - - case IMM_NTFY_ELS: - if (qlt_24xx_handle_els(vha, iocb) == 0) - send_notify_ack = 0; - break; - - case IMM_NTFY_SRR: - qlt_prepare_srr_imm(vha, iocb); - send_notify_ack = 0; - break; - - default: - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf06d, - "qla_target(%d): Received unknown immediate " - "notify status %x\n", vha->vp_idx, status); - break; - } - - if (send_notify_ack) - qlt_send_notify_ack(vha, iocb, add_flags, 0, 0, 0, 0, 0); -} - -/* - * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire - * This function sends busy to ISP 2xxx or 24xx. - */ -static void qlt_send_busy(struct scsi_qla_host *vha, - struct atio_from_isp *atio, uint16_t status) -{ - struct ctio7_to_24xx *ctio24; - struct qla_hw_data *ha = vha->hw; - request_t *pkt; - struct qla_tgt_sess *sess = NULL; - - sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, - atio->u.isp24.fcp_hdr.s_id); - if (!sess) { - qlt_send_term_exchange(vha, NULL, atio, 1); - return; - } - /* Sending marker isn't necessary, since we called from ISR */ - - pkt = (request_t *)qla2x00_alloc_iocbs(vha, NULL); - if (!pkt) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf06e, - "qla_target(%d): %s failed: unable to allocate " - "request packet", vha->vp_idx, __func__); - return; - } - - pkt->entry_count = 1; - pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK; - - ctio24 = (struct ctio7_to_24xx *)pkt; - ctio24->entry_type = CTIO_TYPE7; - ctio24->nport_handle = sess->loop_id; - ctio24->timeout = __constant_cpu_to_le16(QLA_TGT_TIMEOUT); - ctio24->vp_index = vha->vp_idx; - ctio24->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2]; - ctio24->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1]; - ctio24->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0]; - ctio24->exchange_addr = atio->u.isp24.exchange_addr; - ctio24->u.status1.flags = (atio->u.isp24.attr << 9) | - __constant_cpu_to_le16( - CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_SEND_STATUS | - CTIO7_FLAGS_DONT_RET_CTIO); - /* - * CTIO from fw w/o se_cmd doesn't provide enough info to retry it, - * if the explicit conformation is used. - */ - ctio24->u.status1.ox_id = swab16(atio->u.isp24.fcp_hdr.ox_id); - ctio24->u.status1.scsi_status = cpu_to_le16(status); - ctio24->u.status1.residual = get_unaligned((uint32_t *) - &atio->u.isp24.fcp_cmnd.add_cdb[ - atio->u.isp24.fcp_cmnd.add_cdb_len]); - if (ctio24->u.status1.residual != 0) - ctio24->u.status1.scsi_status |= SS_RESIDUAL_UNDER; - - qla2x00_start_iocbs(vha, vha->req); -} - -/* ha->hardware_lock supposed to be held on entry */ -/* called via callback from qla2xxx */ -static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha, - struct atio_from_isp *atio) -{ - struct qla_hw_data *ha = vha->hw; - struct qla_tgt *tgt = ha->tgt.qla_tgt; - int rc; - - if (unlikely(tgt == NULL)) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf039, - "ATIO pkt, but no tgt (ha %p)", ha); - return; - } - ql_dbg(ql_dbg_tgt, vha, 0xe02c, - "qla_target(%d): ATIO pkt %p: type %02x count %02x", - vha->vp_idx, atio, atio->u.raw.entry_type, - atio->u.raw.entry_count); - /* - * In tgt_stop mode we also should allow all requests to pass. - * Otherwise, some commands can stuck. - */ - - tgt->irq_cmd_count++; - - switch (atio->u.raw.entry_type) { - case ATIO_TYPE7: - ql_dbg(ql_dbg_tgt, vha, 0xe02d, - "ATIO_TYPE7 instance %d, lun %Lx, read/write %d/%d, " - "add_cdb_len %d, data_length %04x, s_id %x:%x:%x\n", - vha->vp_idx, atio->u.isp24.fcp_cmnd.lun, - atio->u.isp24.fcp_cmnd.rddata, - atio->u.isp24.fcp_cmnd.wrdata, - atio->u.isp24.fcp_cmnd.add_cdb_len, - be32_to_cpu(get_unaligned((uint32_t *) - &atio->u.isp24.fcp_cmnd.add_cdb[ - atio->u.isp24.fcp_cmnd.add_cdb_len])), - atio->u.isp24.fcp_hdr.s_id[0], - atio->u.isp24.fcp_hdr.s_id[1], - atio->u.isp24.fcp_hdr.s_id[2]); - - if (unlikely(atio->u.isp24.exchange_addr == - ATIO_EXCHANGE_ADDRESS_UNKNOWN)) { - ql_dbg(ql_dbg_tgt, vha, 0xe058, - "qla_target(%d): ATIO_TYPE7 " - "received with UNKNOWN exchange address, " - "sending QUEUE_FULL\n", vha->vp_idx); - qlt_send_busy(vha, atio, SAM_STAT_TASK_SET_FULL); - break; - } - if (likely(atio->u.isp24.fcp_cmnd.task_mgmt_flags == 0)) - rc = qlt_handle_cmd_for_atio(vha, atio); - else - rc = qlt_handle_task_mgmt(vha, atio); - if (unlikely(rc != 0)) { - if (rc == -ESRCH) { -#if 1 /* With TERM EXCHANGE some FC cards refuse to boot */ - qlt_send_busy(vha, atio, SAM_STAT_BUSY); -#else - qlt_send_term_exchange(vha, NULL, atio, 1); -#endif - } else { - if (tgt->tgt_stop) { - ql_dbg(ql_dbg_tgt, vha, 0xe059, - "qla_target: Unable to send " - "command to target for req, " - "ignoring.\n"); - } else { - ql_dbg(ql_dbg_tgt, vha, 0xe05a, - "qla_target(%d): Unable to send " - "command to target, sending BUSY " - "status.\n", vha->vp_idx); - qlt_send_busy(vha, atio, SAM_STAT_BUSY); - } - } - } - break; - - case IMMED_NOTIFY_TYPE: - { - if (unlikely(atio->u.isp2x.entry_status != 0)) { - ql_dbg(ql_dbg_tgt, vha, 0xe05b, - "qla_target(%d): Received ATIO packet %x " - "with error status %x\n", vha->vp_idx, - atio->u.raw.entry_type, - atio->u.isp2x.entry_status); - break; - } - ql_dbg(ql_dbg_tgt, vha, 0xe02e, "%s", "IMMED_NOTIFY ATIO"); - qlt_handle_imm_notify(vha, (struct imm_ntfy_from_isp *)atio); - break; - } - - default: - ql_dbg(ql_dbg_tgt, vha, 0xe05c, - "qla_target(%d): Received unknown ATIO atio " - "type %x\n", vha->vp_idx, atio->u.raw.entry_type); - break; - } - - tgt->irq_cmd_count--; -} - -/* ha->hardware_lock supposed to be held on entry */ -/* called via callback from qla2xxx */ -static void qlt_response_pkt(struct scsi_qla_host *vha, response_t *pkt) -{ - struct qla_hw_data *ha = vha->hw; - struct qla_tgt *tgt = ha->tgt.qla_tgt; - - if (unlikely(tgt == NULL)) { - ql_dbg(ql_dbg_tgt, vha, 0xe05d, - "qla_target(%d): Response pkt %x received, but no " - "tgt (ha %p)\n", vha->vp_idx, pkt->entry_type, ha); - return; - } - - ql_dbg(ql_dbg_tgt, vha, 0xe02f, - "qla_target(%d): response pkt %p: T %02x C %02x S %02x " - "handle %#x\n", vha->vp_idx, pkt, pkt->entry_type, - pkt->entry_count, pkt->entry_status, pkt->handle); - - /* - * In tgt_stop mode we also should allow all requests to pass. - * Otherwise, some commands can stuck. - */ - - tgt->irq_cmd_count++; - - switch (pkt->entry_type) { - case CTIO_TYPE7: - { - struct ctio7_from_24xx *entry = (struct ctio7_from_24xx *)pkt; - ql_dbg(ql_dbg_tgt, vha, 0xe030, "CTIO_TYPE7: instance %d\n", - vha->vp_idx); - qlt_do_ctio_completion(vha, entry->handle, - le16_to_cpu(entry->status)|(pkt->entry_status << 16), - entry); - break; - } - - case ACCEPT_TGT_IO_TYPE: - { - struct atio_from_isp *atio = (struct atio_from_isp *)pkt; - int rc; - ql_dbg(ql_dbg_tgt, vha, 0xe031, - "ACCEPT_TGT_IO instance %d status %04x " - "lun %04x read/write %d data_length %04x " - "target_id %02x rx_id %04x\n ", vha->vp_idx, - le16_to_cpu(atio->u.isp2x.status), - le16_to_cpu(atio->u.isp2x.lun), - atio->u.isp2x.execution_codes, - le32_to_cpu(atio->u.isp2x.data_length), GET_TARGET_ID(ha, - atio), atio->u.isp2x.rx_id); - if (atio->u.isp2x.status != - __constant_cpu_to_le16(ATIO_CDB_VALID)) { - ql_dbg(ql_dbg_tgt, vha, 0xe05e, - "qla_target(%d): ATIO with error " - "status %x received\n", vha->vp_idx, - le16_to_cpu(atio->u.isp2x.status)); - break; - } - ql_dbg(ql_dbg_tgt, vha, 0xe032, - "FCP CDB: 0x%02x, sizeof(cdb): %lu", - atio->u.isp2x.cdb[0], (unsigned long - int)sizeof(atio->u.isp2x.cdb)); - - rc = qlt_handle_cmd_for_atio(vha, atio); - if (unlikely(rc != 0)) { - if (rc == -ESRCH) { -#if 1 /* With TERM EXCHANGE some FC cards refuse to boot */ - qlt_send_busy(vha, atio, 0); -#else - qlt_send_term_exchange(vha, NULL, atio, 1); -#endif - } else { - if (tgt->tgt_stop) { - ql_dbg(ql_dbg_tgt, vha, 0xe05f, - "qla_target: Unable to send " - "command to target, sending TERM " - "EXCHANGE for rsp\n"); - qlt_send_term_exchange(vha, NULL, - atio, 1); - } else { - ql_dbg(ql_dbg_tgt, vha, 0xe060, - "qla_target(%d): Unable to send " - "command to target, sending BUSY " - "status\n", vha->vp_idx); - qlt_send_busy(vha, atio, 0); - } - } - } - } - break; - - case CONTINUE_TGT_IO_TYPE: - { - struct ctio_to_2xxx *entry = (struct ctio_to_2xxx *)pkt; - ql_dbg(ql_dbg_tgt, vha, 0xe033, - "CONTINUE_TGT_IO: instance %d\n", vha->vp_idx); - qlt_do_ctio_completion(vha, entry->handle, - le16_to_cpu(entry->status)|(pkt->entry_status << 16), - entry); - break; - } - - case CTIO_A64_TYPE: - { - struct ctio_to_2xxx *entry = (struct ctio_to_2xxx *)pkt; - ql_dbg(ql_dbg_tgt, vha, 0xe034, "CTIO_A64: instance %d\n", - vha->vp_idx); - qlt_do_ctio_completion(vha, entry->handle, - le16_to_cpu(entry->status)|(pkt->entry_status << 16), - entry); - break; - } - - case IMMED_NOTIFY_TYPE: - ql_dbg(ql_dbg_tgt, vha, 0xe035, "%s", "IMMED_NOTIFY\n"); - qlt_handle_imm_notify(vha, (struct imm_ntfy_from_isp *)pkt); - break; - - case NOTIFY_ACK_TYPE: - if (tgt->notify_ack_expected > 0) { - struct nack_to_isp *entry = (struct nack_to_isp *)pkt; - ql_dbg(ql_dbg_tgt, vha, 0xe036, - "NOTIFY_ACK seq %08x status %x\n", - le16_to_cpu(entry->u.isp2x.seq_id), - le16_to_cpu(entry->u.isp2x.status)); - tgt->notify_ack_expected--; - if (entry->u.isp2x.status != - __constant_cpu_to_le16(NOTIFY_ACK_SUCCESS)) { - ql_dbg(ql_dbg_tgt, vha, 0xe061, - "qla_target(%d): NOTIFY_ACK " - "failed %x\n", vha->vp_idx, - le16_to_cpu(entry->u.isp2x.status)); - } - } else { - ql_dbg(ql_dbg_tgt, vha, 0xe062, - "qla_target(%d): Unexpected NOTIFY_ACK received\n", - vha->vp_idx); - } - break; - - case ABTS_RECV_24XX: - ql_dbg(ql_dbg_tgt, vha, 0xe037, - "ABTS_RECV_24XX: instance %d\n", vha->vp_idx); - qlt_24xx_handle_abts(vha, (struct abts_recv_from_24xx *)pkt); - break; - - case ABTS_RESP_24XX: - if (tgt->abts_resp_expected > 0) { - struct abts_resp_from_24xx_fw *entry = - (struct abts_resp_from_24xx_fw *)pkt; - ql_dbg(ql_dbg_tgt, vha, 0xe038, - "ABTS_RESP_24XX: compl_status %x\n", - entry->compl_status); - tgt->abts_resp_expected--; - if (le16_to_cpu(entry->compl_status) != - ABTS_RESP_COMPL_SUCCESS) { - if ((entry->error_subcode1 == 0x1E) && - (entry->error_subcode2 == 0)) { - /* - * We've got a race here: aborted - * exchange not terminated, i.e. - * response for the aborted command was - * sent between the abort request was - * received and processed. - * Unfortunately, the firmware has a - * silly requirement that all aborted - * exchanges must be explicitely - * terminated, otherwise it refuses to - * send responses for the abort - * requests. So, we have to - * (re)terminate the exchange and retry - * the abort response. - */ - qlt_24xx_retry_term_exchange(vha, - entry); - } else - ql_dbg(ql_dbg_tgt, vha, 0xe063, - "qla_target(%d): ABTS_RESP_24XX " - "failed %x (subcode %x:%x)", - vha->vp_idx, entry->compl_status, - entry->error_subcode1, - entry->error_subcode2); - } - } else { - ql_dbg(ql_dbg_tgt, vha, 0xe064, - "qla_target(%d): Unexpected ABTS_RESP_24XX " - "received\n", vha->vp_idx); - } - break; - - default: - ql_dbg(ql_dbg_tgt, vha, 0xe065, - "qla_target(%d): Received unknown response pkt " - "type %x\n", vha->vp_idx, pkt->entry_type); - break; - } - - tgt->irq_cmd_count--; -} - -/* - * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire - */ -void qlt_async_event(uint16_t code, struct scsi_qla_host *vha, - uint16_t *mailbox) -{ - struct qla_hw_data *ha = vha->hw; - struct qla_tgt *tgt = ha->tgt.qla_tgt; - int reason_code; - - ql_dbg(ql_dbg_tgt, vha, 0xe039, - "scsi(%ld): ha state %d init_done %d oper_mode %d topo %d\n", - vha->host_no, atomic_read(&vha->loop_state), vha->flags.init_done, - ha->operating_mode, ha->current_topology); - - if (!ha->tgt.tgt_ops) - return; - - if (unlikely(tgt == NULL)) { - ql_dbg(ql_dbg_tgt, vha, 0xe03a, - "ASYNC EVENT %#x, but no tgt (ha %p)\n", code, ha); - return; - } - - if (((code == MBA_POINT_TO_POINT) || (code == MBA_CHG_IN_CONNECTION)) && - IS_QLA2100(ha)) - return; - /* - * In tgt_stop mode we also should allow all requests to pass. - * Otherwise, some commands can stuck. - */ - - tgt->irq_cmd_count++; - - switch (code) { - case MBA_RESET: /* Reset */ - case MBA_SYSTEM_ERR: /* System Error */ - case MBA_REQ_TRANSFER_ERR: /* Request Transfer Error */ - case MBA_RSP_TRANSFER_ERR: /* Response Transfer Error */ - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf03a, - "qla_target(%d): System error async event %#x " - "occured", vha->vp_idx, code); - break; - case MBA_WAKEUP_THRES: /* Request Queue Wake-up. */ - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - break; - - case MBA_LOOP_UP: - { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf03b, - "qla_target(%d): Async LOOP_UP occured " - "(m[1]=%x, m[2]=%x, m[3]=%x, m[4]=%x)", vha->vp_idx, - le16_to_cpu(mailbox[1]), le16_to_cpu(mailbox[2]), - le16_to_cpu(mailbox[3]), le16_to_cpu(mailbox[4])); - if (tgt->link_reinit_iocb_pending) { - qlt_send_notify_ack(vha, (void *)&tgt->link_reinit_iocb, - 0, 0, 0, 0, 0, 0); - tgt->link_reinit_iocb_pending = 0; - } - break; - } - - case MBA_LIP_OCCURRED: - case MBA_LOOP_DOWN: - case MBA_LIP_RESET: - case MBA_RSCN_UPDATE: - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf03c, - "qla_target(%d): Async event %#x occured " - "(m[1]=%x, m[2]=%x, m[3]=%x, m[4]=%x)", vha->vp_idx, code, - le16_to_cpu(mailbox[1]), le16_to_cpu(mailbox[2]), - le16_to_cpu(mailbox[3]), le16_to_cpu(mailbox[4])); - break; - - case MBA_PORT_UPDATE: - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf03d, - "qla_target(%d): Port update async event %#x " - "occured: updating the ports database (m[1]=%x, m[2]=%x, " - "m[3]=%x, m[4]=%x)", vha->vp_idx, code, - le16_to_cpu(mailbox[1]), le16_to_cpu(mailbox[2]), - le16_to_cpu(mailbox[3]), le16_to_cpu(mailbox[4])); - reason_code = le16_to_cpu(mailbox[2]); - if (reason_code == 0x4) - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf03e, - "Async MB 2: Got PLOGI Complete\n"); - else if (reason_code == 0x7) - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf03f, - "Async MB 2: Port Logged Out\n"); - break; - - default: - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf040, - "qla_target(%d): Async event %#x occured: " - "ignore (m[1]=%x, m[2]=%x, m[3]=%x, m[4]=%x)", vha->vp_idx, - code, le16_to_cpu(mailbox[1]), le16_to_cpu(mailbox[2]), - le16_to_cpu(mailbox[3]), le16_to_cpu(mailbox[4])); - break; - } - - tgt->irq_cmd_count--; -} - -static fc_port_t *qlt_get_port_database(struct scsi_qla_host *vha, - uint16_t loop_id) -{ - fc_port_t *fcport; - int rc; - - fcport = kzalloc(sizeof(*fcport), GFP_KERNEL); - if (!fcport) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf06f, - "qla_target(%d): Allocation of tmp FC port failed", - vha->vp_idx); - return NULL; - } - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf041, "loop_id %d", loop_id); - - fcport->loop_id = loop_id; - - rc = qla2x00_get_port_database(vha, fcport, 0); - if (rc != QLA_SUCCESS) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf070, - "qla_target(%d): Failed to retrieve fcport " - "information -- get_port_database() returned %x " - "(loop_id=0x%04x)", vha->vp_idx, rc, loop_id); - kfree(fcport); - return NULL; - } - - return fcport; -} - -/* Must be called under tgt_mutex */ -static struct qla_tgt_sess *qlt_make_local_sess(struct scsi_qla_host *vha, - uint8_t *s_id) -{ - struct qla_hw_data *ha = vha->hw; - struct qla_tgt_sess *sess = NULL; - fc_port_t *fcport = NULL; - int rc, global_resets; - uint16_t loop_id = 0; - -retry: - global_resets = atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count); - - rc = qla24xx_get_loop_id(vha, s_id, &loop_id); - if (rc != 0) { - if ((s_id[0] == 0xFF) && - (s_id[1] == 0xFC)) { - /* - * This is Domain Controller, so it should be - * OK to drop SCSI commands from it. - */ - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf042, - "Unable to find initiator with S_ID %x:%x:%x", - s_id[0], s_id[1], s_id[2]); - } else - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf071, - "qla_target(%d): Unable to find " - "initiator with S_ID %x:%x:%x", - vha->vp_idx, s_id[0], s_id[1], - s_id[2]); - return NULL; - } - - fcport = qlt_get_port_database(vha, loop_id); - if (!fcport) - return NULL; - - if (global_resets != - atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count)) { - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf043, - "qla_target(%d): global reset during session discovery " - "(counter was %d, new %d), retrying", vha->vp_idx, - global_resets, - atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count)); - goto retry; - } - - sess = qlt_create_sess(vha, fcport, true); - - kfree(fcport); - return sess; -} - -static void qlt_abort_work(struct qla_tgt *tgt, - struct qla_tgt_sess_work_param *prm) -{ - struct scsi_qla_host *vha = tgt->vha; - struct qla_hw_data *ha = vha->hw; - struct qla_tgt_sess *sess = NULL; - unsigned long flags; - uint32_t be_s_id; - uint8_t s_id[3]; - int rc; - - spin_lock_irqsave(&ha->hardware_lock, flags); - - if (tgt->tgt_stop) - goto out_term; - - s_id[0] = prm->abts.fcp_hdr_le.s_id[2]; - s_id[1] = prm->abts.fcp_hdr_le.s_id[1]; - s_id[2] = prm->abts.fcp_hdr_le.s_id[0]; - - sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, - (unsigned char *)&be_s_id); - if (!sess) { - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - mutex_lock(&ha->tgt.tgt_mutex); - sess = qlt_make_local_sess(vha, s_id); - /* sess has got an extra creation ref */ - mutex_unlock(&ha->tgt.tgt_mutex); - - spin_lock_irqsave(&ha->hardware_lock, flags); - if (!sess) - goto out_term; - } else { - kref_get(&sess->se_sess->sess_kref); - } - - if (tgt->tgt_stop) - goto out_term; - - rc = __qlt_24xx_handle_abts(vha, &prm->abts, sess); - if (rc != 0) - goto out_term; - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - ha->tgt.tgt_ops->put_sess(sess); - return; - -out_term: - qlt_24xx_send_abts_resp(vha, &prm->abts, FCP_TMF_REJECTED, false); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - if (sess) - ha->tgt.tgt_ops->put_sess(sess); -} - -static void qlt_tmr_work(struct qla_tgt *tgt, - struct qla_tgt_sess_work_param *prm) -{ - struct atio_from_isp *a = &prm->tm_iocb2; - struct scsi_qla_host *vha = tgt->vha; - struct qla_hw_data *ha = vha->hw; - struct qla_tgt_sess *sess = NULL; - unsigned long flags; - uint8_t *s_id = NULL; /* to hide compiler warnings */ - int rc; - uint32_t lun, unpacked_lun; - int lun_size, fn; - void *iocb; - - spin_lock_irqsave(&ha->hardware_lock, flags); - - if (tgt->tgt_stop) - goto out_term; - - s_id = prm->tm_iocb2.u.isp24.fcp_hdr.s_id; - sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id); - if (!sess) { - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - mutex_lock(&ha->tgt.tgt_mutex); - sess = qlt_make_local_sess(vha, s_id); - /* sess has got an extra creation ref */ - mutex_unlock(&ha->tgt.tgt_mutex); - - spin_lock_irqsave(&ha->hardware_lock, flags); - if (!sess) - goto out_term; - } else { - kref_get(&sess->se_sess->sess_kref); - } - - iocb = a; - lun = a->u.isp24.fcp_cmnd.lun; - lun_size = sizeof(lun); - fn = a->u.isp24.fcp_cmnd.task_mgmt_flags; - unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun); - - rc = qlt_issue_task_mgmt(sess, unpacked_lun, fn, iocb, 0); - if (rc != 0) - goto out_term; - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - ha->tgt.tgt_ops->put_sess(sess); - return; - -out_term: - qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - if (sess) - ha->tgt.tgt_ops->put_sess(sess); -} - -static void qlt_sess_work_fn(struct work_struct *work) -{ - struct qla_tgt *tgt = container_of(work, struct qla_tgt, sess_work); - struct scsi_qla_host *vha = tgt->vha; - unsigned long flags; - - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf000, "Sess work (tgt %p)", tgt); - - spin_lock_irqsave(&tgt->sess_work_lock, flags); - while (!list_empty(&tgt->sess_works_list)) { - struct qla_tgt_sess_work_param *prm = list_entry( - tgt->sess_works_list.next, typeof(*prm), - sess_works_list_entry); - - /* - * This work can be scheduled on several CPUs at time, so we - * must delete the entry to eliminate double processing - */ - list_del(&prm->sess_works_list_entry); - - spin_unlock_irqrestore(&tgt->sess_work_lock, flags); - - switch (prm->type) { - case QLA_TGT_SESS_WORK_ABORT: - qlt_abort_work(tgt, prm); - break; - case QLA_TGT_SESS_WORK_TM: - qlt_tmr_work(tgt, prm); - break; - default: - BUG_ON(1); - break; - } - - spin_lock_irqsave(&tgt->sess_work_lock, flags); - - kfree(prm); - } - spin_unlock_irqrestore(&tgt->sess_work_lock, flags); -} - -/* Must be called under tgt_host_action_mutex */ -int qlt_add_target(struct qla_hw_data *ha, struct scsi_qla_host *base_vha) -{ - struct qla_tgt *tgt; - - if (!QLA_TGT_MODE_ENABLED()) - return 0; - - ql_dbg(ql_dbg_tgt, base_vha, 0xe03b, - "Registering target for host %ld(%p)", base_vha->host_no, ha); - - BUG_ON((ha->tgt.qla_tgt != NULL) || (ha->tgt.tgt_ops != NULL)); - - tgt = kzalloc(sizeof(struct qla_tgt), GFP_KERNEL); - if (!tgt) { - ql_dbg(ql_dbg_tgt, base_vha, 0xe066, - "Unable to allocate struct qla_tgt\n"); - return -ENOMEM; - } - - if (!(base_vha->host->hostt->supported_mode & MODE_TARGET)) - base_vha->host->hostt->supported_mode |= MODE_TARGET; - - tgt->ha = ha; - tgt->vha = base_vha; - init_waitqueue_head(&tgt->waitQ); - INIT_LIST_HEAD(&tgt->sess_list); - INIT_LIST_HEAD(&tgt->del_sess_list); - INIT_DELAYED_WORK(&tgt->sess_del_work, - (void (*)(struct work_struct *))qlt_del_sess_work_fn); - spin_lock_init(&tgt->sess_work_lock); - INIT_WORK(&tgt->sess_work, qlt_sess_work_fn); - INIT_LIST_HEAD(&tgt->sess_works_list); - spin_lock_init(&tgt->srr_lock); - INIT_LIST_HEAD(&tgt->srr_ctio_list); - INIT_LIST_HEAD(&tgt->srr_imm_list); - INIT_WORK(&tgt->srr_work, qlt_handle_srr_work); - atomic_set(&tgt->tgt_global_resets_count, 0); - - ha->tgt.qla_tgt = tgt; - - ql_dbg(ql_dbg_tgt, base_vha, 0xe067, - "qla_target(%d): using 64 Bit PCI addressing", - base_vha->vp_idx); - tgt->tgt_enable_64bit_addr = 1; - /* 3 is reserved */ - tgt->sg_tablesize = QLA_TGT_MAX_SG_24XX(base_vha->req->length - 3); - tgt->datasegs_per_cmd = QLA_TGT_DATASEGS_PER_CMD_24XX; - tgt->datasegs_per_cont = QLA_TGT_DATASEGS_PER_CONT_24XX; - - mutex_lock(&qla_tgt_mutex); - list_add_tail(&tgt->tgt_list_entry, &qla_tgt_glist); - mutex_unlock(&qla_tgt_mutex); - - return 0; -} - -/* Must be called under tgt_host_action_mutex */ -int qlt_remove_target(struct qla_hw_data *ha, struct scsi_qla_host *vha) -{ - if (!ha->tgt.qla_tgt) - return 0; - - mutex_lock(&qla_tgt_mutex); - list_del(&ha->tgt.qla_tgt->tgt_list_entry); - mutex_unlock(&qla_tgt_mutex); - - ql_dbg(ql_dbg_tgt, vha, 0xe03c, "Unregistering target for host %ld(%p)", - vha->host_no, ha); - qlt_release(ha->tgt.qla_tgt); - - return 0; -} - -static void qlt_lport_dump(struct scsi_qla_host *vha, u64 wwpn, - unsigned char *b) -{ - int i; - - pr_debug("qla2xxx HW vha->node_name: "); - for (i = 0; i < WWN_SIZE; i++) - pr_debug("%02x ", vha->node_name[i]); - pr_debug("\n"); - pr_debug("qla2xxx HW vha->port_name: "); - for (i = 0; i < WWN_SIZE; i++) - pr_debug("%02x ", vha->port_name[i]); - pr_debug("\n"); - - pr_debug("qla2xxx passed configfs WWPN: "); - put_unaligned_be64(wwpn, b); - for (i = 0; i < WWN_SIZE; i++) - pr_debug("%02x ", b[i]); - pr_debug("\n"); -} - -/** - * qla_tgt_lport_register - register lport with external module - * - * @qla_tgt_ops: Pointer for tcm_qla2xxx qla_tgt_ops - * @wwpn: Passwd FC target WWPN - * @callback: lport initialization callback for tcm_qla2xxx code - * @target_lport_ptr: pointer for tcm_qla2xxx specific lport data - */ -int qlt_lport_register(struct qla_tgt_func_tmpl *qla_tgt_ops, u64 wwpn, - int (*callback)(struct scsi_qla_host *), void *target_lport_ptr) -{ - struct qla_tgt *tgt; - struct scsi_qla_host *vha; - struct qla_hw_data *ha; - struct Scsi_Host *host; - unsigned long flags; - int rc; - u8 b[WWN_SIZE]; - - mutex_lock(&qla_tgt_mutex); - list_for_each_entry(tgt, &qla_tgt_glist, tgt_list_entry) { - vha = tgt->vha; - ha = vha->hw; - - host = vha->host; - if (!host) - continue; - - if (ha->tgt.tgt_ops != NULL) - continue; - - if (!(host->hostt->supported_mode & MODE_TARGET)) - continue; - - spin_lock_irqsave(&ha->hardware_lock, flags); - if (host->active_mode & MODE_TARGET) { - pr_debug("MODE_TARGET already active on qla2xxx(%d)\n", - host->host_no); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - continue; - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - if (!scsi_host_get(host)) { - ql_dbg(ql_dbg_tgt, vha, 0xe068, - "Unable to scsi_host_get() for" - " qla2xxx scsi_host\n"); - continue; - } - qlt_lport_dump(vha, wwpn, b); - - if (memcmp(vha->port_name, b, WWN_SIZE)) { - scsi_host_put(host); - continue; - } - /* - * Setup passed parameters ahead of invoking callback - */ - ha->tgt.tgt_ops = qla_tgt_ops; - ha->tgt.target_lport_ptr = target_lport_ptr; - rc = (*callback)(vha); - if (rc != 0) { - ha->tgt.tgt_ops = NULL; - ha->tgt.target_lport_ptr = NULL; - } - mutex_unlock(&qla_tgt_mutex); - return rc; - } - mutex_unlock(&qla_tgt_mutex); - - return -ENODEV; -} -EXPORT_SYMBOL(qlt_lport_register); - -/** - * qla_tgt_lport_deregister - Degister lport - * - * @vha: Registered scsi_qla_host pointer - */ -void qlt_lport_deregister(struct scsi_qla_host *vha) -{ - struct qla_hw_data *ha = vha->hw; - struct Scsi_Host *sh = vha->host; - /* - * Clear the target_lport_ptr qla_target_template pointer in qla_hw_data - */ - ha->tgt.target_lport_ptr = NULL; - ha->tgt.tgt_ops = NULL; - /* - * Release the Scsi_Host reference for the underlying qla2xxx host - */ - scsi_host_put(sh); -} -EXPORT_SYMBOL(qlt_lport_deregister); - -/* Must be called under HW lock */ -void qlt_set_mode(struct scsi_qla_host *vha) -{ - struct qla_hw_data *ha = vha->hw; - - switch (ql2x_ini_mode) { - case QLA2XXX_INI_MODE_DISABLED: - case QLA2XXX_INI_MODE_EXCLUSIVE: - vha->host->active_mode = MODE_TARGET; - break; - case QLA2XXX_INI_MODE_ENABLED: - vha->host->active_mode |= MODE_TARGET; - break; - default: - break; - } - - if (ha->tgt.ini_mode_force_reverse) - qla_reverse_ini_mode(vha); -} - -/* Must be called under HW lock */ -void qlt_clear_mode(struct scsi_qla_host *vha) -{ - struct qla_hw_data *ha = vha->hw; - - switch (ql2x_ini_mode) { - case QLA2XXX_INI_MODE_DISABLED: - vha->host->active_mode = MODE_UNKNOWN; - break; - case QLA2XXX_INI_MODE_EXCLUSIVE: - vha->host->active_mode = MODE_INITIATOR; - break; - case QLA2XXX_INI_MODE_ENABLED: - vha->host->active_mode &= ~MODE_TARGET; - break; - default: - break; - } - - if (ha->tgt.ini_mode_force_reverse) - qla_reverse_ini_mode(vha); -} - -/* - * qla_tgt_enable_vha - NO LOCK HELD - * - * host_reset, bring up w/ Target Mode Enabled - */ -void -qlt_enable_vha(struct scsi_qla_host *vha) -{ - struct qla_hw_data *ha = vha->hw; - struct qla_tgt *tgt = ha->tgt.qla_tgt; - unsigned long flags; - - if (!tgt) { - ql_dbg(ql_dbg_tgt, vha, 0xe069, - "Unable to locate qla_tgt pointer from" - " struct qla_hw_data\n"); - dump_stack(); - return; - } - - spin_lock_irqsave(&ha->hardware_lock, flags); - tgt->tgt_stopped = 0; - qlt_set_mode(vha); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); - qla2x00_wait_for_hba_online(vha); -} -EXPORT_SYMBOL(qlt_enable_vha); - -/* - * qla_tgt_disable_vha - NO LOCK HELD - * - * Disable Target Mode and reset the adapter - */ -void -qlt_disable_vha(struct scsi_qla_host *vha) -{ - struct qla_hw_data *ha = vha->hw; - struct qla_tgt *tgt = ha->tgt.qla_tgt; - unsigned long flags; - - if (!tgt) { - ql_dbg(ql_dbg_tgt, vha, 0xe06a, - "Unable to locate qla_tgt pointer from" - " struct qla_hw_data\n"); - dump_stack(); - return; - } - - spin_lock_irqsave(&ha->hardware_lock, flags); - qlt_clear_mode(vha); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); - qla2x00_wait_for_hba_online(vha); -} - -/* - * Called from qla_init.c:qla24xx_vport_create() contex to setup - * the target mode specific struct scsi_qla_host and struct qla_hw_data - * members. - */ -void -qlt_vport_create(struct scsi_qla_host *vha, struct qla_hw_data *ha) -{ - if (!qla_tgt_mode_enabled(vha)) - return; - - mutex_init(&ha->tgt.tgt_mutex); - mutex_init(&ha->tgt.tgt_host_action_mutex); - - qlt_clear_mode(vha); - - /* - * NOTE: Currently the value is kept the same for <24xx and - * >=24xx ISPs. If it is necessary to change it, - * the check should be added for specific ISPs, - * assigning the value appropriately. - */ - ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX; -} - -void -qlt_rff_id(struct scsi_qla_host *vha, struct ct_sns_req *ct_req) -{ - /* - * FC-4 Feature bit 0 indicates target functionality to the name server. - */ - if (qla_tgt_mode_enabled(vha)) { - if (qla_ini_mode_enabled(vha)) - ct_req->req.rff_id.fc4_feature = BIT_0 | BIT_1; - else - ct_req->req.rff_id.fc4_feature = BIT_0; - } else if (qla_ini_mode_enabled(vha)) { - ct_req->req.rff_id.fc4_feature = BIT_1; - } -} - -/* - * qlt_init_atio_q_entries() - Initializes ATIO queue entries. - * @ha: HA context - * - * Beginning of ATIO ring has initialization control block already built - * by nvram config routine. - * - * Returns 0 on success. - */ -void -qlt_init_atio_q_entries(struct scsi_qla_host *vha) -{ - struct qla_hw_data *ha = vha->hw; - uint16_t cnt; - struct atio_from_isp *pkt = (struct atio_from_isp *)ha->tgt.atio_ring; - - if (!qla_tgt_mode_enabled(vha)) - return; - - for (cnt = 0; cnt < ha->tgt.atio_q_length; cnt++) { - pkt->u.raw.signature = ATIO_PROCESSED; - pkt++; - } - -} - -/* - * qlt_24xx_process_atio_queue() - Process ATIO queue entries. - * @ha: SCSI driver HA context - */ -void -qlt_24xx_process_atio_queue(struct scsi_qla_host *vha) -{ - struct qla_hw_data *ha = vha->hw; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - struct atio_from_isp *pkt; - int cnt, i; - - if (!vha->flags.online) - return; - - while (ha->tgt.atio_ring_ptr->signature != ATIO_PROCESSED) { - pkt = (struct atio_from_isp *)ha->tgt.atio_ring_ptr; - cnt = pkt->u.raw.entry_count; - - qlt_24xx_atio_pkt_all_vps(vha, (struct atio_from_isp *)pkt); - - for (i = 0; i < cnt; i++) { - ha->tgt.atio_ring_index++; - if (ha->tgt.atio_ring_index == ha->tgt.atio_q_length) { - ha->tgt.atio_ring_index = 0; - ha->tgt.atio_ring_ptr = ha->tgt.atio_ring; - } else - ha->tgt.atio_ring_ptr++; - - pkt->u.raw.signature = ATIO_PROCESSED; - pkt = (struct atio_from_isp *)ha->tgt.atio_ring_ptr; - } - wmb(); - } - - /* Adjust ring index */ - WRT_REG_DWORD(®->atio_q_out, ha->tgt.atio_ring_index); -} - -void -qlt_24xx_config_rings(struct scsi_qla_host *vha, device_reg_t __iomem *reg) -{ - struct qla_hw_data *ha = vha->hw; - -/* FIXME: atio_q in/out for ha->mqenable=1..? */ - if (ha->mqenable) { -#if 0 - WRT_REG_DWORD(®->isp25mq.atio_q_in, 0); - WRT_REG_DWORD(®->isp25mq.atio_q_out, 0); - RD_REG_DWORD(®->isp25mq.atio_q_out); -#endif - } else { - /* Setup APTIO registers for target mode */ - WRT_REG_DWORD(®->isp24.atio_q_in, 0); - WRT_REG_DWORD(®->isp24.atio_q_out, 0); - RD_REG_DWORD(®->isp24.atio_q_out); - } -} - -void -qlt_24xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_24xx *nv) -{ - struct qla_hw_data *ha = vha->hw; - - if (qla_tgt_mode_enabled(vha)) { - if (!ha->tgt.saved_set) { - /* We save only once */ - ha->tgt.saved_exchange_count = nv->exchange_count; - ha->tgt.saved_firmware_options_1 = - nv->firmware_options_1; - ha->tgt.saved_firmware_options_2 = - nv->firmware_options_2; - ha->tgt.saved_firmware_options_3 = - nv->firmware_options_3; - ha->tgt.saved_set = 1; - } - - nv->exchange_count = __constant_cpu_to_le16(0xFFFF); - - /* Enable target mode */ - nv->firmware_options_1 |= __constant_cpu_to_le32(BIT_4); - - /* Disable ini mode, if requested */ - if (!qla_ini_mode_enabled(vha)) - nv->firmware_options_1 |= __constant_cpu_to_le32(BIT_5); - - /* Disable Full Login after LIP */ - nv->firmware_options_1 &= __constant_cpu_to_le32(~BIT_13); - /* Enable initial LIP */ - nv->firmware_options_1 &= __constant_cpu_to_le32(~BIT_9); - /* Enable FC tapes support */ - nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12); - /* Disable Full Login after LIP */ - nv->host_p &= __constant_cpu_to_le32(~BIT_10); - /* Enable target PRLI control */ - nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_14); - } else { - if (ha->tgt.saved_set) { - nv->exchange_count = ha->tgt.saved_exchange_count; - nv->firmware_options_1 = - ha->tgt.saved_firmware_options_1; - nv->firmware_options_2 = - ha->tgt.saved_firmware_options_2; - nv->firmware_options_3 = - ha->tgt.saved_firmware_options_3; - } - return; - } - - /* out-of-order frames reassembly */ - nv->firmware_options_3 |= BIT_6|BIT_9; - - if (ha->tgt.enable_class_2) { - if (vha->flags.init_done) - fc_host_supported_classes(vha->host) = - FC_COS_CLASS2 | FC_COS_CLASS3; - - nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_8); - } else { - if (vha->flags.init_done) - fc_host_supported_classes(vha->host) = FC_COS_CLASS3; - - nv->firmware_options_2 &= ~__constant_cpu_to_le32(BIT_8); - } -} - -void -qlt_24xx_config_nvram_stage2(struct scsi_qla_host *vha, - struct init_cb_24xx *icb) -{ - struct qla_hw_data *ha = vha->hw; - - if (ha->tgt.node_name_set) { - memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE); - icb->firmware_options_1 |= __constant_cpu_to_le32(BIT_14); - } -} - -int -qlt_24xx_process_response_error(struct scsi_qla_host *vha, - struct sts_entry_24xx *pkt) -{ - switch (pkt->entry_type) { - case ABTS_RECV_24XX: - case ABTS_RESP_24XX: - case CTIO_TYPE7: - case NOTIFY_ACK_TYPE: - return 1; - default: - return 0; - } -} - -void -qlt_modify_vp_config(struct scsi_qla_host *vha, - struct vp_config_entry_24xx *vpmod) -{ - if (qla_tgt_mode_enabled(vha)) - vpmod->options_idx1 &= ~BIT_5; - /* Disable ini mode, if requested */ - if (!qla_ini_mode_enabled(vha)) - vpmod->options_idx1 &= ~BIT_4; -} - -void -qlt_probe_one_stage1(struct scsi_qla_host *base_vha, struct qla_hw_data *ha) -{ - if (!QLA_TGT_MODE_ENABLED()) - return; - - mutex_init(&ha->tgt.tgt_mutex); - mutex_init(&ha->tgt.tgt_host_action_mutex); - qlt_clear_mode(base_vha); -} - -int -qlt_mem_alloc(struct qla_hw_data *ha) -{ - if (!QLA_TGT_MODE_ENABLED()) - return 0; - - ha->tgt.tgt_vp_map = kzalloc(sizeof(struct qla_tgt_vp_map) * - MAX_MULTI_ID_FABRIC, GFP_KERNEL); - if (!ha->tgt.tgt_vp_map) - return -ENOMEM; - - ha->tgt.atio_ring = dma_alloc_coherent(&ha->pdev->dev, - (ha->tgt.atio_q_length + 1) * sizeof(struct atio_from_isp), - &ha->tgt.atio_dma, GFP_KERNEL); - if (!ha->tgt.atio_ring) { - kfree(ha->tgt.tgt_vp_map); - return -ENOMEM; - } - return 0; -} - -void -qlt_mem_free(struct qla_hw_data *ha) -{ - if (!QLA_TGT_MODE_ENABLED()) - return; - - if (ha->tgt.atio_ring) { - dma_free_coherent(&ha->pdev->dev, (ha->tgt.atio_q_length + 1) * - sizeof(struct atio_from_isp), ha->tgt.atio_ring, - ha->tgt.atio_dma); - } - kfree(ha->tgt.tgt_vp_map); -} - -/* vport_slock to be held by the caller */ -void -qlt_update_vp_map(struct scsi_qla_host *vha, int cmd) -{ - if (!QLA_TGT_MODE_ENABLED()) - return; - - switch (cmd) { - case SET_VP_IDX: - vha->hw->tgt.tgt_vp_map[vha->vp_idx].vha = vha; - break; - case SET_AL_PA: - vha->hw->tgt.tgt_vp_map[vha->d_id.b.al_pa].idx = vha->vp_idx; - break; - case RESET_VP_IDX: - vha->hw->tgt.tgt_vp_map[vha->vp_idx].vha = NULL; - break; - case RESET_AL_PA: - vha->hw->tgt.tgt_vp_map[vha->d_id.b.al_pa].idx = 0; - break; - } -} - -static int __init qlt_parse_ini_mode(void) -{ - if (strcasecmp(qlini_mode, QLA2XXX_INI_MODE_STR_EXCLUSIVE) == 0) - ql2x_ini_mode = QLA2XXX_INI_MODE_EXCLUSIVE; - else if (strcasecmp(qlini_mode, QLA2XXX_INI_MODE_STR_DISABLED) == 0) - ql2x_ini_mode = QLA2XXX_INI_MODE_DISABLED; - else if (strcasecmp(qlini_mode, QLA2XXX_INI_MODE_STR_ENABLED) == 0) - ql2x_ini_mode = QLA2XXX_INI_MODE_ENABLED; - else - return false; - - return true; -} - -int __init qlt_init(void) -{ - int ret; - - if (!qlt_parse_ini_mode()) { - ql_log(ql_log_fatal, NULL, 0xe06b, - "qlt_parse_ini_mode() failed\n"); - return -EINVAL; - } - - if (!QLA_TGT_MODE_ENABLED()) - return 0; - - qla_tgt_cmd_cachep = kmem_cache_create("qla_tgt_cmd_cachep", - sizeof(struct qla_tgt_cmd), __alignof__(struct qla_tgt_cmd), 0, - NULL); - if (!qla_tgt_cmd_cachep) { - ql_log(ql_log_fatal, NULL, 0xe06c, - "kmem_cache_create for qla_tgt_cmd_cachep failed\n"); - return -ENOMEM; - } - - qla_tgt_mgmt_cmd_cachep = kmem_cache_create("qla_tgt_mgmt_cmd_cachep", - sizeof(struct qla_tgt_mgmt_cmd), __alignof__(struct - qla_tgt_mgmt_cmd), 0, NULL); - if (!qla_tgt_mgmt_cmd_cachep) { - ql_log(ql_log_fatal, NULL, 0xe06d, - "kmem_cache_create for qla_tgt_mgmt_cmd_cachep failed\n"); - ret = -ENOMEM; - goto out; - } - - qla_tgt_mgmt_cmd_mempool = mempool_create(25, mempool_alloc_slab, - mempool_free_slab, qla_tgt_mgmt_cmd_cachep); - if (!qla_tgt_mgmt_cmd_mempool) { - ql_log(ql_log_fatal, NULL, 0xe06e, - "mempool_create for qla_tgt_mgmt_cmd_mempool failed\n"); - ret = -ENOMEM; - goto out_mgmt_cmd_cachep; - } - - qla_tgt_wq = alloc_workqueue("qla_tgt_wq", 0, 0); - if (!qla_tgt_wq) { - ql_log(ql_log_fatal, NULL, 0xe06f, - "alloc_workqueue for qla_tgt_wq failed\n"); - ret = -ENOMEM; - goto out_cmd_mempool; - } - /* - * Return 1 to signal that initiator-mode is being disabled - */ - return (ql2x_ini_mode == QLA2XXX_INI_MODE_DISABLED) ? 1 : 0; - -out_cmd_mempool: - mempool_destroy(qla_tgt_mgmt_cmd_mempool); -out_mgmt_cmd_cachep: - kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep); -out: - kmem_cache_destroy(qla_tgt_cmd_cachep); - return ret; -} - -void qlt_exit(void) -{ - if (!QLA_TGT_MODE_ENABLED()) - return; - - destroy_workqueue(qla_tgt_wq); - mempool_destroy(qla_tgt_mgmt_cmd_mempool); - kmem_cache_destroy(qla_tgt_mgmt_cmd_cachep); - kmem_cache_destroy(qla_tgt_cmd_cachep); -} diff --git a/trunk/drivers/scsi/qla2xxx/qla_target.h b/trunk/drivers/scsi/qla2xxx/qla_target.h deleted file mode 100644 index 9ec19bc2f0fe..000000000000 --- a/trunk/drivers/scsi/qla2xxx/qla_target.h +++ /dev/null @@ -1,1005 +0,0 @@ -/* - * Copyright (C) 2004 - 2010 Vladislav Bolkhovitin - * Copyright (C) 2004 - 2005 Leonid Stoljar - * Copyright (C) 2006 Nathaniel Clark - * Copyright (C) 2007 - 2010 ID7 Ltd. - * - * Forward port and refactoring to modern qla2xxx and target/configfs - * - * Copyright (C) 2010-2011 Nicholas A. Bellinger - * - * Additional file for the target driver support. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -/* - * This is the global def file that is useful for including from the - * target portion. - */ - -#ifndef __QLA_TARGET_H -#define __QLA_TARGET_H - -#include "qla_def.h" - -/* - * Must be changed on any change in any initiator visible interfaces or - * data in the target add-on - */ -#define QLA2XXX_TARGET_MAGIC 269 - -/* - * Must be changed on any change in any target visible interfaces or - * data in the initiator - */ -#define QLA2XXX_INITIATOR_MAGIC 57222 - -#define QLA2XXX_INI_MODE_STR_EXCLUSIVE "exclusive" -#define QLA2XXX_INI_MODE_STR_DISABLED "disabled" -#define QLA2XXX_INI_MODE_STR_ENABLED "enabled" - -#define QLA2XXX_INI_MODE_EXCLUSIVE 0 -#define QLA2XXX_INI_MODE_DISABLED 1 -#define QLA2XXX_INI_MODE_ENABLED 2 - -#define QLA2XXX_COMMAND_COUNT_INIT 250 -#define QLA2XXX_IMMED_NOTIFY_COUNT_INIT 250 - -/* - * Used to mark which completion handles (for RIO Status's) are for CTIO's - * vs. regular (non-target) info. This is checked for in - * qla2x00_process_response_queue() to see if a handle coming back in a - * multi-complete should come to the tgt driver or be handled there by qla2xxx - */ -#define CTIO_COMPLETION_HANDLE_MARK BIT_29 -#if (CTIO_COMPLETION_HANDLE_MARK <= MAX_OUTSTANDING_COMMANDS) -#error "CTIO_COMPLETION_HANDLE_MARK not larger than MAX_OUTSTANDING_COMMANDS" -#endif -#define HANDLE_IS_CTIO_COMP(h) (h & CTIO_COMPLETION_HANDLE_MARK) - -/* Used to mark CTIO as intermediate */ -#define CTIO_INTERMEDIATE_HANDLE_MARK BIT_30 - -#ifndef OF_SS_MODE_0 -/* - * ISP target entries - Flags bit definitions. - */ -#define OF_SS_MODE_0 0 -#define OF_SS_MODE_1 1 -#define OF_SS_MODE_2 2 -#define OF_SS_MODE_3 3 - -#define OF_EXPL_CONF BIT_5 /* Explicit Confirmation Requested */ -#define OF_DATA_IN BIT_6 /* Data in to initiator */ - /* (data from target to initiator) */ -#define OF_DATA_OUT BIT_7 /* Data out from initiator */ - /* (data from initiator to target) */ -#define OF_NO_DATA (BIT_7 | BIT_6) -#define OF_INC_RC BIT_8 /* Increment command resource count */ -#define OF_FAST_POST BIT_9 /* Enable mailbox fast posting. */ -#define OF_CONF_REQ BIT_13 /* Confirmation Requested */ -#define OF_TERM_EXCH BIT_14 /* Terminate exchange */ -#define OF_SSTS BIT_15 /* Send SCSI status */ -#endif - -#ifndef QLA_TGT_DATASEGS_PER_CMD32 -#define QLA_TGT_DATASEGS_PER_CMD32 3 -#define QLA_TGT_DATASEGS_PER_CONT32 7 -#define QLA_TGT_MAX_SG32(ql) \ - (((ql) > 0) ? (QLA_TGT_DATASEGS_PER_CMD32 + \ - QLA_TGT_DATASEGS_PER_CONT32*((ql) - 1)) : 0) - -#define QLA_TGT_DATASEGS_PER_CMD64 2 -#define QLA_TGT_DATASEGS_PER_CONT64 5 -#define QLA_TGT_MAX_SG64(ql) \ - (((ql) > 0) ? (QLA_TGT_DATASEGS_PER_CMD64 + \ - QLA_TGT_DATASEGS_PER_CONT64*((ql) - 1)) : 0) -#endif - -#ifndef QLA_TGT_DATASEGS_PER_CMD_24XX -#define QLA_TGT_DATASEGS_PER_CMD_24XX 1 -#define QLA_TGT_DATASEGS_PER_CONT_24XX 5 -#define QLA_TGT_MAX_SG_24XX(ql) \ - (min(1270, ((ql) > 0) ? (QLA_TGT_DATASEGS_PER_CMD_24XX + \ - QLA_TGT_DATASEGS_PER_CONT_24XX*((ql) - 1)) : 0)) -#endif -#endif - -#define GET_TARGET_ID(ha, iocb) ((HAS_EXTENDED_IDS(ha)) \ - ? le16_to_cpu((iocb)->u.isp2x.target.extended) \ - : (uint16_t)(iocb)->u.isp2x.target.id.standard) - -#ifndef IMMED_NOTIFY_TYPE -#define IMMED_NOTIFY_TYPE 0x0D /* Immediate notify entry. */ -/* - * ISP queue - immediate notify entry structure definition. - * This is sent by the ISP to the Target driver. - * This IOCB would have report of events sent by the - * initiator, that needs to be handled by the target - * driver immediately. - */ -struct imm_ntfy_from_isp { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - union { - struct { - uint32_t sys_define_2; /* System defined. */ - target_id_t target; - uint16_t lun; - uint8_t target_id; - uint8_t reserved_1; - uint16_t status_modifier; - uint16_t status; - uint16_t task_flags; - uint16_t seq_id; - uint16_t srr_rx_id; - uint32_t srr_rel_offs; - uint16_t srr_ui; -#define SRR_IU_DATA_IN 0x1 -#define SRR_IU_DATA_OUT 0x5 -#define SRR_IU_STATUS 0x7 - uint16_t srr_ox_id; - uint8_t reserved_2[28]; - } isp2x; - struct { - uint32_t reserved; - uint16_t nport_handle; - uint16_t reserved_2; - uint16_t flags; -#define NOTIFY24XX_FLAGS_GLOBAL_TPRLO BIT_1 -#define NOTIFY24XX_FLAGS_PUREX_IOCB BIT_0 - uint16_t srr_rx_id; - uint16_t status; - uint8_t status_subcode; - uint8_t reserved_3; - uint32_t exchange_address; - uint32_t srr_rel_offs; - uint16_t srr_ui; - uint16_t srr_ox_id; - uint8_t reserved_4[19]; - uint8_t vp_index; - uint32_t reserved_5; - uint8_t port_id[3]; - uint8_t reserved_6; - } isp24; - } u; - uint16_t reserved_7; - uint16_t ox_id; -} __packed; -#endif - -#ifndef NOTIFY_ACK_TYPE -#define NOTIFY_ACK_TYPE 0x0E /* Notify acknowledge entry. */ -/* - * ISP queue - notify acknowledge entry structure definition. - * This is sent to the ISP from the target driver. - */ -struct nack_to_isp { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - union { - struct { - uint32_t sys_define_2; /* System defined. */ - target_id_t target; - uint8_t target_id; - uint8_t reserved_1; - uint16_t flags; - uint16_t resp_code; - uint16_t status; - uint16_t task_flags; - uint16_t seq_id; - uint16_t srr_rx_id; - uint32_t srr_rel_offs; - uint16_t srr_ui; - uint16_t srr_flags; - uint16_t srr_reject_code; - uint8_t srr_reject_vendor_uniq; - uint8_t srr_reject_code_expl; - uint8_t reserved_2[24]; - } isp2x; - struct { - uint32_t handle; - uint16_t nport_handle; - uint16_t reserved_1; - uint16_t flags; - uint16_t srr_rx_id; - uint16_t status; - uint8_t status_subcode; - uint8_t reserved_3; - uint32_t exchange_address; - uint32_t srr_rel_offs; - uint16_t srr_ui; - uint16_t srr_flags; - uint8_t reserved_4[19]; - uint8_t vp_index; - uint8_t srr_reject_vendor_uniq; - uint8_t srr_reject_code_expl; - uint8_t srr_reject_code; - uint8_t reserved_5[5]; - } isp24; - } u; - uint8_t reserved[2]; - uint16_t ox_id; -} __packed; -#define NOTIFY_ACK_SRR_FLAGS_ACCEPT 0 -#define NOTIFY_ACK_SRR_FLAGS_REJECT 1 - -#define NOTIFY_ACK_SRR_REJECT_REASON_UNABLE_TO_PERFORM 0x9 - -#define NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_NO_EXPL 0 -#define NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_UNABLE_TO_SUPPLY_DATA 0x2a - -#define NOTIFY_ACK_SUCCESS 0x01 -#endif - -#ifndef ACCEPT_TGT_IO_TYPE -#define ACCEPT_TGT_IO_TYPE 0x16 /* Accept target I/O entry. */ -#endif - -#ifndef CONTINUE_TGT_IO_TYPE -#define CONTINUE_TGT_IO_TYPE 0x17 -/* - * ISP queue - Continue Target I/O (CTIO) entry for status mode 0 structure. - * This structure is sent to the ISP 2xxx from target driver. - */ -struct ctio_to_2xxx { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - uint32_t handle; /* System defined handle */ - target_id_t target; - uint16_t rx_id; - uint16_t flags; - uint16_t status; - uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ - uint16_t dseg_count; /* Data segment count. */ - uint32_t relative_offset; - uint32_t residual; - uint16_t reserved_1[3]; - uint16_t scsi_status; - uint32_t transfer_length; - uint32_t dseg_0_address; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address; /* Data segment 1 address. */ - uint32_t dseg_1_length; /* Data segment 1 length. */ - uint32_t dseg_2_address; /* Data segment 2 address. */ - uint32_t dseg_2_length; /* Data segment 2 length. */ -} __packed; -#define ATIO_PATH_INVALID 0x07 -#define ATIO_CANT_PROV_CAP 0x16 -#define ATIO_CDB_VALID 0x3D - -#define ATIO_EXEC_READ BIT_1 -#define ATIO_EXEC_WRITE BIT_0 -#endif - -#ifndef CTIO_A64_TYPE -#define CTIO_A64_TYPE 0x1F -#define CTIO_SUCCESS 0x01 -#define CTIO_ABORTED 0x02 -#define CTIO_INVALID_RX_ID 0x08 -#define CTIO_TIMEOUT 0x0B -#define CTIO_LIP_RESET 0x0E -#define CTIO_TARGET_RESET 0x17 -#define CTIO_PORT_UNAVAILABLE 0x28 -#define CTIO_PORT_LOGGED_OUT 0x29 -#define CTIO_PORT_CONF_CHANGED 0x2A -#define CTIO_SRR_RECEIVED 0x45 -#endif - -#ifndef CTIO_RET_TYPE -#define CTIO_RET_TYPE 0x17 /* CTIO return entry */ -#define ATIO_TYPE7 0x06 /* Accept target I/O entry for 24xx */ - -struct fcp_hdr { - uint8_t r_ctl; - uint8_t d_id[3]; - uint8_t cs_ctl; - uint8_t s_id[3]; - uint8_t type; - uint8_t f_ctl[3]; - uint8_t seq_id; - uint8_t df_ctl; - uint16_t seq_cnt; - uint16_t ox_id; - uint16_t rx_id; - uint32_t parameter; -} __packed; - -struct fcp_hdr_le { - uint8_t d_id[3]; - uint8_t r_ctl; - uint8_t s_id[3]; - uint8_t cs_ctl; - uint8_t f_ctl[3]; - uint8_t type; - uint16_t seq_cnt; - uint8_t df_ctl; - uint8_t seq_id; - uint16_t rx_id; - uint16_t ox_id; - uint32_t parameter; -} __packed; - -#define F_CTL_EXCH_CONTEXT_RESP BIT_23 -#define F_CTL_SEQ_CONTEXT_RESIP BIT_22 -#define F_CTL_LAST_SEQ BIT_20 -#define F_CTL_END_SEQ BIT_19 -#define F_CTL_SEQ_INITIATIVE BIT_16 - -#define R_CTL_BASIC_LINK_SERV 0x80 -#define R_CTL_B_ACC 0x4 -#define R_CTL_B_RJT 0x5 - -struct atio7_fcp_cmnd { - uint64_t lun; - uint8_t cmnd_ref; - uint8_t task_attr:3; - uint8_t reserved:5; - uint8_t task_mgmt_flags; -#define FCP_CMND_TASK_MGMT_CLEAR_ACA 6 -#define FCP_CMND_TASK_MGMT_TARGET_RESET 5 -#define FCP_CMND_TASK_MGMT_LU_RESET 4 -#define FCP_CMND_TASK_MGMT_CLEAR_TASK_SET 2 -#define FCP_CMND_TASK_MGMT_ABORT_TASK_SET 1 - uint8_t wrdata:1; - uint8_t rddata:1; - uint8_t add_cdb_len:6; - uint8_t cdb[16]; - /* - * add_cdb is optional and can absent from struct atio7_fcp_cmnd. Size 4 - * only to make sizeof(struct atio7_fcp_cmnd) be as expected by - * BUILD_BUG_ON in qlt_init(). - */ - uint8_t add_cdb[4]; - /* uint32_t data_length; */ -} __packed; - -/* - * ISP queue - Accept Target I/O (ATIO) type entry IOCB structure. - * This is sent from the ISP to the target driver. - */ -struct atio_from_isp { - union { - struct { - uint16_t entry_hdr; - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - uint32_t sys_define_2; /* System defined. */ - target_id_t target; - uint16_t rx_id; - uint16_t flags; - uint16_t status; - uint8_t command_ref; - uint8_t task_codes; - uint8_t task_flags; - uint8_t execution_codes; - uint8_t cdb[MAX_CMDSZ]; - uint32_t data_length; - uint16_t lun; - uint8_t initiator_port_name[WWN_SIZE]; /* on qla23xx */ - uint16_t reserved_32[6]; - uint16_t ox_id; - } isp2x; - struct { - uint16_t entry_hdr; - uint8_t fcp_cmnd_len_low; - uint8_t fcp_cmnd_len_high:4; - uint8_t attr:4; - uint32_t exchange_addr; -#define ATIO_EXCHANGE_ADDRESS_UNKNOWN 0xFFFFFFFF - struct fcp_hdr fcp_hdr; - struct atio7_fcp_cmnd fcp_cmnd; - } isp24; - struct { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t data[58]; - uint32_t signature; -#define ATIO_PROCESSED 0xDEADDEAD /* Signature */ - } raw; - } u; -} __packed; - -#define CTIO_TYPE7 0x12 /* Continue target I/O entry (for 24xx) */ - -/* - * ISP queue - Continue Target I/O (ATIO) type 7 entry (for 24xx) structure. - * This structure is sent to the ISP 24xx from the target driver. - */ - -struct ctio7_to_24xx { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - uint32_t handle; /* System defined handle */ - uint16_t nport_handle; -#define CTIO7_NHANDLE_UNRECOGNIZED 0xFFFF - uint16_t timeout; - uint16_t dseg_count; /* Data segment count. */ - uint8_t vp_index; - uint8_t add_flags; - uint8_t initiator_id[3]; - uint8_t reserved; - uint32_t exchange_addr; - union { - struct { - uint16_t reserved1; - uint16_t flags; - uint32_t residual; - uint16_t ox_id; - uint16_t scsi_status; - uint32_t relative_offset; - uint32_t reserved2; - uint32_t transfer_length; - uint32_t reserved3; - /* Data segment 0 address. */ - uint32_t dseg_0_address[2]; - /* Data segment 0 length. */ - uint32_t dseg_0_length; - } status0; - struct { - uint16_t sense_length; - uint16_t flags; - uint32_t residual; - uint16_t ox_id; - uint16_t scsi_status; - uint16_t response_len; - uint16_t reserved; - uint8_t sense_data[24]; - } status1; - } u; -} __packed; - -/* - * ISP queue - CTIO type 7 from ISP 24xx to target driver - * returned entry structure. - */ -struct ctio7_from_24xx { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - uint32_t handle; /* System defined handle */ - uint16_t status; - uint16_t timeout; - uint16_t dseg_count; /* Data segment count. */ - uint8_t vp_index; - uint8_t reserved1[5]; - uint32_t exchange_address; - uint16_t reserved2; - uint16_t flags; - uint32_t residual; - uint16_t ox_id; - uint16_t reserved3; - uint32_t relative_offset; - uint8_t reserved4[24]; -} __packed; - -/* CTIO7 flags values */ -#define CTIO7_FLAGS_SEND_STATUS BIT_15 -#define CTIO7_FLAGS_TERMINATE BIT_14 -#define CTIO7_FLAGS_CONFORM_REQ BIT_13 -#define CTIO7_FLAGS_DONT_RET_CTIO BIT_8 -#define CTIO7_FLAGS_STATUS_MODE_0 0 -#define CTIO7_FLAGS_STATUS_MODE_1 BIT_6 -#define CTIO7_FLAGS_EXPLICIT_CONFORM BIT_5 -#define CTIO7_FLAGS_CONFIRM_SATISF BIT_4 -#define CTIO7_FLAGS_DSD_PTR BIT_2 -#define CTIO7_FLAGS_DATA_IN BIT_1 -#define CTIO7_FLAGS_DATA_OUT BIT_0 - -#define ELS_PLOGI 0x3 -#define ELS_FLOGI 0x4 -#define ELS_LOGO 0x5 -#define ELS_PRLI 0x20 -#define ELS_PRLO 0x21 -#define ELS_TPRLO 0x24 -#define ELS_PDISC 0x50 -#define ELS_ADISC 0x52 - -/* - * ISP queue - ABTS received/response entries structure definition for 24xx. - */ -#define ABTS_RECV_24XX 0x54 /* ABTS received (for 24xx) */ -#define ABTS_RESP_24XX 0x55 /* ABTS responce (for 24xx) */ - -/* - * ISP queue - ABTS received IOCB entry structure definition for 24xx. - * The ABTS BLS received from the wire is sent to the - * target driver by the ISP 24xx. - * The IOCB is placed on the response queue. - */ -struct abts_recv_from_24xx { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - uint8_t reserved_1[6]; - uint16_t nport_handle; - uint8_t reserved_2[2]; - uint8_t vp_index; - uint8_t reserved_3:4; - uint8_t sof_type:4; - uint32_t exchange_address; - struct fcp_hdr_le fcp_hdr_le; - uint8_t reserved_4[16]; - uint32_t exchange_addr_to_abort; -} __packed; - -#define ABTS_PARAM_ABORT_SEQ BIT_0 - -struct ba_acc_le { - uint16_t reserved; - uint8_t seq_id_last; - uint8_t seq_id_valid; -#define SEQ_ID_VALID 0x80 -#define SEQ_ID_INVALID 0x00 - uint16_t rx_id; - uint16_t ox_id; - uint16_t high_seq_cnt; - uint16_t low_seq_cnt; -} __packed; - -struct ba_rjt_le { - uint8_t vendor_uniq; - uint8_t reason_expl; - uint8_t reason_code; -#define BA_RJT_REASON_CODE_INVALID_COMMAND 0x1 -#define BA_RJT_REASON_CODE_UNABLE_TO_PERFORM 0x9 - uint8_t reserved; -} __packed; - -/* - * ISP queue - ABTS Response IOCB entry structure definition for 24xx. - * The ABTS response to the ABTS received is sent by the - * target driver to the ISP 24xx. - * The IOCB is placed on the request queue. - */ -struct abts_resp_to_24xx { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - uint32_t handle; - uint16_t reserved_1; - uint16_t nport_handle; - uint16_t control_flags; -#define ABTS_CONTR_FLG_TERM_EXCHG BIT_0 - uint8_t vp_index; - uint8_t reserved_3:4; - uint8_t sof_type:4; - uint32_t exchange_address; - struct fcp_hdr_le fcp_hdr_le; - union { - struct ba_acc_le ba_acct; - struct ba_rjt_le ba_rjt; - } __packed payload; - uint32_t reserved_4; - uint32_t exchange_addr_to_abort; -} __packed; - -/* - * ISP queue - ABTS Response IOCB from ISP24xx Firmware entry structure. - * The ABTS response with completion status to the ABTS response - * (sent by the target driver to the ISP 24xx) is sent by the - * ISP24xx firmware to the target driver. - * The IOCB is placed on the response queue. - */ -struct abts_resp_from_24xx_fw { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - uint32_t handle; - uint16_t compl_status; -#define ABTS_RESP_COMPL_SUCCESS 0 -#define ABTS_RESP_COMPL_SUBCODE_ERROR 0x31 - uint16_t nport_handle; - uint16_t reserved_1; - uint8_t reserved_2; - uint8_t reserved_3:4; - uint8_t sof_type:4; - uint32_t exchange_address; - struct fcp_hdr_le fcp_hdr_le; - uint8_t reserved_4[8]; - uint32_t error_subcode1; -#define ABTS_RESP_SUBCODE_ERR_ABORTED_EXCH_NOT_TERM 0x1E - uint32_t error_subcode2; - uint32_t exchange_addr_to_abort; -} __packed; - -/********************************************************************\ - * Type Definitions used by initiator & target halves -\********************************************************************/ - -struct qla_tgt_mgmt_cmd; -struct qla_tgt_sess; - -/* - * This structure provides a template of function calls that the - * target driver (from within qla_target.c) can issue to the - * target module (tcm_qla2xxx). - */ -struct qla_tgt_func_tmpl { - - int (*handle_cmd)(struct scsi_qla_host *, struct qla_tgt_cmd *, - unsigned char *, uint32_t, int, int, int); - int (*handle_data)(struct qla_tgt_cmd *); - int (*handle_tmr)(struct qla_tgt_mgmt_cmd *, uint32_t, uint8_t, - uint32_t); - void (*free_cmd)(struct qla_tgt_cmd *); - void (*free_mcmd)(struct qla_tgt_mgmt_cmd *); - void (*free_session)(struct qla_tgt_sess *); - - int (*check_initiator_node_acl)(struct scsi_qla_host *, unsigned char *, - void *, uint8_t *, uint16_t); - struct qla_tgt_sess *(*find_sess_by_loop_id)(struct scsi_qla_host *, - const uint16_t); - struct qla_tgt_sess *(*find_sess_by_s_id)(struct scsi_qla_host *, - const uint8_t *); - void (*clear_nacl_from_fcport_map)(struct qla_tgt_sess *); - void (*put_sess)(struct qla_tgt_sess *); - void (*shutdown_sess)(struct qla_tgt_sess *); -}; - -int qla2x00_wait_for_hba_online(struct scsi_qla_host *); - -#include - -#define QLA_TGT_TIMEOUT 10 /* in seconds */ - -#define QLA_TGT_MAX_HW_PENDING_TIME 60 /* in seconds */ - -/* Immediate notify status constants */ -#define IMM_NTFY_LIP_RESET 0x000E -#define IMM_NTFY_LIP_LINK_REINIT 0x000F -#define IMM_NTFY_IOCB_OVERFLOW 0x0016 -#define IMM_NTFY_ABORT_TASK 0x0020 -#define IMM_NTFY_PORT_LOGOUT 0x0029 -#define IMM_NTFY_PORT_CONFIG 0x002A -#define IMM_NTFY_GLBL_TPRLO 0x002D -#define IMM_NTFY_GLBL_LOGO 0x002E -#define IMM_NTFY_RESOURCE 0x0034 -#define IMM_NTFY_MSG_RX 0x0036 -#define IMM_NTFY_SRR 0x0045 -#define IMM_NTFY_ELS 0x0046 - -/* Immediate notify task flags */ -#define IMM_NTFY_TASK_MGMT_SHIFT 8 - -#define QLA_TGT_CLEAR_ACA 0x40 -#define QLA_TGT_TARGET_RESET 0x20 -#define QLA_TGT_LUN_RESET 0x10 -#define QLA_TGT_CLEAR_TS 0x04 -#define QLA_TGT_ABORT_TS 0x02 -#define QLA_TGT_ABORT_ALL_SESS 0xFFFF -#define QLA_TGT_ABORT_ALL 0xFFFE -#define QLA_TGT_NEXUS_LOSS_SESS 0xFFFD -#define QLA_TGT_NEXUS_LOSS 0xFFFC - -/* Notify Acknowledge flags */ -#define NOTIFY_ACK_RES_COUNT BIT_8 -#define NOTIFY_ACK_CLEAR_LIP_RESET BIT_5 -#define NOTIFY_ACK_TM_RESP_CODE_VALID BIT_4 - -/* Command's states */ -#define QLA_TGT_STATE_NEW 0 /* New command + target processing */ -#define QLA_TGT_STATE_NEED_DATA 1 /* target needs data to continue */ -#define QLA_TGT_STATE_DATA_IN 2 /* Data arrived + target processing */ -#define QLA_TGT_STATE_PROCESSED 3 /* target done processing */ -#define QLA_TGT_STATE_ABORTED 4 /* Command aborted */ - -/* Special handles */ -#define QLA_TGT_NULL_HANDLE 0 -#define QLA_TGT_SKIP_HANDLE (0xFFFFFFFF & ~CTIO_COMPLETION_HANDLE_MARK) - -/* ATIO task_codes field */ -#define ATIO_SIMPLE_QUEUE 0 -#define ATIO_HEAD_OF_QUEUE 1 -#define ATIO_ORDERED_QUEUE 2 -#define ATIO_ACA_QUEUE 4 -#define ATIO_UNTAGGED 5 - -/* TM failed response codes, see FCP (9.4.11 FCP_RSP_INFO) */ -#define FC_TM_SUCCESS 0 -#define FC_TM_BAD_FCP_DATA 1 -#define FC_TM_BAD_CMD 2 -#define FC_TM_FCP_DATA_MISMATCH 3 -#define FC_TM_REJECT 4 -#define FC_TM_FAILED 5 - -/* - * Error code of qlt_pre_xmit_response() meaning that cmd's exchange was - * terminated, so no more actions is needed and success should be returned - * to target. - */ -#define QLA_TGT_PRE_XMIT_RESP_CMD_ABORTED 0x1717 - -#if (BITS_PER_LONG > 32) || defined(CONFIG_HIGHMEM64G) -#define pci_dma_lo32(a) (a & 0xffffffff) -#define pci_dma_hi32(a) ((((a) >> 16)>>16) & 0xffffffff) -#else -#define pci_dma_lo32(a) (a & 0xffffffff) -#define pci_dma_hi32(a) 0 -#endif - -#define QLA_TGT_SENSE_VALID(sense) ((sense != NULL) && \ - (((const uint8_t *)(sense))[0] & 0x70) == 0x70) - -struct qla_port_24xx_data { - uint8_t port_name[WWN_SIZE]; - uint16_t loop_id; - uint16_t reserved; -}; - -struct qla_tgt { - struct scsi_qla_host *vha; - struct qla_hw_data *ha; - - /* - * To sync between IRQ handlers and qlt_target_release(). Needed, - * because req_pkt() can drop/reaquire HW lock inside. Protected by - * HW lock. - */ - int irq_cmd_count; - - int datasegs_per_cmd, datasegs_per_cont, sg_tablesize; - - /* Target's flags, serialized by pha->hardware_lock */ - unsigned int tgt_enable_64bit_addr:1; /* 64-bits PCI addr enabled */ - unsigned int link_reinit_iocb_pending:1; - - /* - * Protected by tgt_mutex AND hardware_lock for writing and tgt_mutex - * OR hardware_lock for reading. - */ - int tgt_stop; /* the target mode driver is being stopped */ - int tgt_stopped; /* the target mode driver has been stopped */ - - /* Count of sessions refering qla_tgt. Protected by hardware_lock. */ - int sess_count; - - /* Protected by hardware_lock. Addition also protected by tgt_mutex. */ - struct list_head sess_list; - - /* Protected by hardware_lock */ - struct list_head del_sess_list; - struct delayed_work sess_del_work; - - spinlock_t sess_work_lock; - struct list_head sess_works_list; - struct work_struct sess_work; - - struct imm_ntfy_from_isp link_reinit_iocb; - wait_queue_head_t waitQ; - int notify_ack_expected; - int abts_resp_expected; - int modify_lun_expected; - - int ctio_srr_id; - int imm_srr_id; - spinlock_t srr_lock; - struct list_head srr_ctio_list; - struct list_head srr_imm_list; - struct work_struct srr_work; - - atomic_t tgt_global_resets_count; - - struct list_head tgt_list_entry; -}; - -/* - * Equivilant to IT Nexus (Initiator-Target) - */ -struct qla_tgt_sess { - uint16_t loop_id; - port_id_t s_id; - - unsigned int conf_compl_supported:1; - unsigned int deleted:1; - unsigned int local:1; - unsigned int tearing_down:1; - - struct se_session *se_sess; - struct scsi_qla_host *vha; - struct qla_tgt *tgt; - - struct list_head sess_list_entry; - unsigned long expires; - struct list_head del_list_entry; - - uint8_t port_name[WWN_SIZE]; - struct work_struct free_work; -}; - -struct qla_tgt_cmd { - struct qla_tgt_sess *sess; - int state; - struct se_cmd se_cmd; - struct work_struct free_work; - struct work_struct work; - /* Sense buffer that will be mapped into outgoing status */ - unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER]; - - /* to save extra sess dereferences */ - unsigned int conf_compl_supported:1; - unsigned int sg_mapped:1; - unsigned int free_sg:1; - unsigned int aborted:1; /* Needed in case of SRR */ - unsigned int write_data_transferred:1; - - struct scatterlist *sg; /* cmd data buffer SG vector */ - int sg_cnt; /* SG segments count */ - int bufflen; /* cmd buffer length */ - int offset; - uint32_t tag; - uint32_t unpacked_lun; - enum dma_data_direction dma_data_direction; - - uint16_t loop_id; /* to save extra sess dereferences */ - struct qla_tgt *tgt; /* to save extra sess dereferences */ - struct scsi_qla_host *vha; - struct list_head cmd_list; - - struct atio_from_isp atio; -}; - -struct qla_tgt_sess_work_param { - struct list_head sess_works_list_entry; - -#define QLA_TGT_SESS_WORK_ABORT 1 -#define QLA_TGT_SESS_WORK_TM 2 - int type; - - union { - struct abts_recv_from_24xx abts; - struct imm_ntfy_from_isp tm_iocb; - struct atio_from_isp tm_iocb2; - }; -}; - -struct qla_tgt_mgmt_cmd { - uint8_t tmr_func; - uint8_t fc_tm_rsp; - struct qla_tgt_sess *sess; - struct se_cmd se_cmd; - struct work_struct free_work; - unsigned int flags; -#define QLA24XX_MGMT_SEND_NACK 1 - union { - struct atio_from_isp atio; - struct imm_ntfy_from_isp imm_ntfy; - struct abts_recv_from_24xx abts; - } __packed orig_iocb; -}; - -struct qla_tgt_prm { - struct qla_tgt_cmd *cmd; - struct qla_tgt *tgt; - void *pkt; - struct scatterlist *sg; /* cmd data buffer SG vector */ - int seg_cnt; - int req_cnt; - uint16_t rq_result; - uint16_t scsi_status; - unsigned char *sense_buffer; - int sense_buffer_len; - int residual; - int add_status_pkt; -}; - -struct qla_tgt_srr_imm { - struct list_head srr_list_entry; - int srr_id; - struct imm_ntfy_from_isp imm_ntfy; -}; - -struct qla_tgt_srr_ctio { - struct list_head srr_list_entry; - int srr_id; - struct qla_tgt_cmd *cmd; -}; - -#define QLA_TGT_XMIT_DATA 1 -#define QLA_TGT_XMIT_STATUS 2 -#define QLA_TGT_XMIT_ALL (QLA_TGT_XMIT_STATUS|QLA_TGT_XMIT_DATA) - -#include - -extern struct qla_tgt_data qla_target; -/* - * Internal function prototypes - */ -void qlt_disable_vha(struct scsi_qla_host *); - -/* - * Function prototypes for qla_target.c logic used by qla2xxx LLD code. - */ -extern int qlt_add_target(struct qla_hw_data *, struct scsi_qla_host *); -extern int qlt_remove_target(struct qla_hw_data *, struct scsi_qla_host *); -extern int qlt_lport_register(struct qla_tgt_func_tmpl *, u64, - int (*callback)(struct scsi_qla_host *), void *); -extern void qlt_lport_deregister(struct scsi_qla_host *); -extern void qlt_unreg_sess(struct qla_tgt_sess *); -extern void qlt_fc_port_added(struct scsi_qla_host *, fc_port_t *); -extern void qlt_fc_port_deleted(struct scsi_qla_host *, fc_port_t *); -extern void qlt_set_mode(struct scsi_qla_host *ha); -extern void qlt_clear_mode(struct scsi_qla_host *ha); -extern int __init qlt_init(void); -extern void qlt_exit(void); -extern void qlt_update_vp_map(struct scsi_qla_host *, int); - -/* - * This macro is used during early initializations when host->active_mode - * is not set. Right now, ha value is ignored. - */ -#define QLA_TGT_MODE_ENABLED() (ql2x_ini_mode != QLA2XXX_INI_MODE_ENABLED) - -static inline bool qla_tgt_mode_enabled(struct scsi_qla_host *ha) -{ - return ha->host->active_mode & MODE_TARGET; -} - -static inline bool qla_ini_mode_enabled(struct scsi_qla_host *ha) -{ - return ha->host->active_mode & MODE_INITIATOR; -} - -static inline void qla_reverse_ini_mode(struct scsi_qla_host *ha) -{ - if (ha->host->active_mode & MODE_INITIATOR) - ha->host->active_mode &= ~MODE_INITIATOR; - else - ha->host->active_mode |= MODE_INITIATOR; -} - -/* - * Exported symbols from qla_target.c LLD logic used by qla2xxx code.. - */ -extern void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *, - struct atio_from_isp *); -extern void qlt_response_pkt_all_vps(struct scsi_qla_host *, response_t *); -extern int qlt_rdy_to_xfer(struct qla_tgt_cmd *); -extern int qlt_xmit_response(struct qla_tgt_cmd *, int, uint8_t); -extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *); -extern void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *); -extern void qlt_free_cmd(struct qla_tgt_cmd *cmd); -extern void qlt_ctio_completion(struct scsi_qla_host *, uint32_t); -extern void qlt_async_event(uint16_t, struct scsi_qla_host *, uint16_t *); -extern void qlt_enable_vha(struct scsi_qla_host *); -extern void qlt_vport_create(struct scsi_qla_host *, struct qla_hw_data *); -extern void qlt_rff_id(struct scsi_qla_host *, struct ct_sns_req *); -extern void qlt_init_atio_q_entries(struct scsi_qla_host *); -extern void qlt_24xx_process_atio_queue(struct scsi_qla_host *); -extern void qlt_24xx_config_rings(struct scsi_qla_host *, - device_reg_t __iomem *); -extern void qlt_24xx_config_nvram_stage1(struct scsi_qla_host *, - struct nvram_24xx *); -extern void qlt_24xx_config_nvram_stage2(struct scsi_qla_host *, - struct init_cb_24xx *); -extern int qlt_24xx_process_response_error(struct scsi_qla_host *, - struct sts_entry_24xx *); -extern void qlt_modify_vp_config(struct scsi_qla_host *, - struct vp_config_entry_24xx *); -extern void qlt_probe_one_stage1(struct scsi_qla_host *, struct qla_hw_data *); -extern int qlt_mem_alloc(struct qla_hw_data *); -extern void qlt_mem_free(struct qla_hw_data *); -extern void qlt_stop_phase1(struct qla_tgt *); -extern void qlt_stop_phase2(struct qla_tgt *); - -#endif /* __QLA_TARGET_H */ diff --git a/trunk/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/trunk/drivers/scsi/qla2xxx/tcm_qla2xxx.c deleted file mode 100644 index 436598f57404..000000000000 --- a/trunk/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ /dev/null @@ -1,1955 +0,0 @@ -/******************************************************************************* - * This file contains tcm implementation using v4 configfs fabric infrastructure - * for QLogic target mode HBAs - * - * ?? Copyright 2010-2011 RisingTide Systems LLC. - * - * Licensed to the Linux Foundation under the General Public License (GPL) - * version 2. - * - * Author: Nicholas A. Bellinger - * - * tcm_qla2xxx_parse_wwn() and tcm_qla2xxx_format_wwn() contains code from - * the TCM_FC / Open-FCoE.org fabric module. - * - * Copyright (c) 2010 Cisco Systems, Inc - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - ****************************************************************************/ - - -#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 "qla_def.h" -#include "qla_target.h" -#include "tcm_qla2xxx.h" - -struct workqueue_struct *tcm_qla2xxx_free_wq; -struct workqueue_struct *tcm_qla2xxx_cmd_wq; - -static int tcm_qla2xxx_check_true(struct se_portal_group *se_tpg) -{ - return 1; -} - -static int tcm_qla2xxx_check_false(struct se_portal_group *se_tpg) -{ - return 0; -} - -/* - * Parse WWN. - * If strict, we require lower-case hex and colon separators to be sure - * the name is the same as what would be generated by ft_format_wwn() - * so the name and wwn are mapped one-to-one. - */ -static ssize_t tcm_qla2xxx_parse_wwn(const char *name, u64 *wwn, int strict) -{ - const char *cp; - char c; - u32 nibble; - u32 byte = 0; - u32 pos = 0; - u32 err; - - *wwn = 0; - for (cp = name; cp < &name[TCM_QLA2XXX_NAMELEN - 1]; cp++) { - c = *cp; - if (c == '\n' && cp[1] == '\0') - continue; - if (strict && pos++ == 2 && byte++ < 7) { - pos = 0; - if (c == ':') - continue; - err = 1; - goto fail; - } - if (c == '\0') { - err = 2; - if (strict && byte != 8) - goto fail; - return cp - name; - } - err = 3; - if (isdigit(c)) - nibble = c - '0'; - else if (isxdigit(c) && (islower(c) || !strict)) - nibble = tolower(c) - 'a' + 10; - else - goto fail; - *wwn = (*wwn << 4) | nibble; - } - err = 4; -fail: - pr_debug("err %u len %zu pos %u byte %u\n", - err, cp - name, pos, byte); - return -1; -} - -static ssize_t tcm_qla2xxx_format_wwn(char *buf, size_t len, u64 wwn) -{ - u8 b[8]; - - put_unaligned_be64(wwn, b); - return snprintf(buf, len, - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", - b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); -} - -static char *tcm_qla2xxx_get_fabric_name(void) -{ - return "qla2xxx"; -} - -/* - * From drivers/scsi/scsi_transport_fc.c:fc_parse_wwn - */ -static int tcm_qla2xxx_npiv_extract_wwn(const char *ns, u64 *nm) -{ - unsigned int i, j, value; - u8 wwn[8]; - - memset(wwn, 0, sizeof(wwn)); - - /* Validate and store the new name */ - for (i = 0, j = 0; i < 16; i++) { - value = hex_to_bin(*ns++); - if (value >= 0) - j = (j << 4) | value; - else - return -EINVAL; - - if (i % 2) { - wwn[i/2] = j & 0xff; - j = 0; - } - } - - *nm = wwn_to_u64(wwn); - return 0; -} - -/* - * This parsing logic follows drivers/scsi/scsi_transport_fc.c: - * store_fc_host_vport_create() - */ -static int tcm_qla2xxx_npiv_parse_wwn( - const char *name, - size_t count, - u64 *wwpn, - u64 *wwnn) -{ - unsigned int cnt = count; - int rc; - - *wwpn = 0; - *wwnn = 0; - - /* count may include a LF at end of string */ - if (name[cnt-1] == '\n') - cnt--; - - /* validate we have enough characters for WWPN */ - if ((cnt != (16+1+16)) || (name[16] != ':')) - return -EINVAL; - - rc = tcm_qla2xxx_npiv_extract_wwn(&name[0], wwpn); - if (rc != 0) - return rc; - - rc = tcm_qla2xxx_npiv_extract_wwn(&name[17], wwnn); - if (rc != 0) - return rc; - - return 0; -} - -static ssize_t tcm_qla2xxx_npiv_format_wwn(char *buf, size_t len, - u64 wwpn, u64 wwnn) -{ - u8 b[8], b2[8]; - - put_unaligned_be64(wwpn, b); - put_unaligned_be64(wwnn, b2); - return snprintf(buf, len, - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x," - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", - b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], - b2[0], b2[1], b2[2], b2[3], b2[4], b2[5], b2[6], b2[7]); -} - -static char *tcm_qla2xxx_npiv_get_fabric_name(void) -{ - return "qla2xxx_npiv"; -} - -static u8 tcm_qla2xxx_get_fabric_proto_ident(struct se_portal_group *se_tpg) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - struct tcm_qla2xxx_lport *lport = tpg->lport; - u8 proto_id; - - switch (lport->lport_proto_id) { - case SCSI_PROTOCOL_FCP: - default: - proto_id = fc_get_fabric_proto_ident(se_tpg); - break; - } - - return proto_id; -} - -static char *tcm_qla2xxx_get_fabric_wwn(struct se_portal_group *se_tpg) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - struct tcm_qla2xxx_lport *lport = tpg->lport; - - return &lport->lport_name[0]; -} - -static char *tcm_qla2xxx_npiv_get_fabric_wwn(struct se_portal_group *se_tpg) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - struct tcm_qla2xxx_lport *lport = tpg->lport; - - return &lport->lport_npiv_name[0]; -} - -static u16 tcm_qla2xxx_get_tag(struct se_portal_group *se_tpg) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - return tpg->lport_tpgt; -} - -static u32 tcm_qla2xxx_get_default_depth(struct se_portal_group *se_tpg) -{ - return 1; -} - -static u32 tcm_qla2xxx_get_pr_transport_id( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code, - unsigned char *buf) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - struct tcm_qla2xxx_lport *lport = tpg->lport; - int ret = 0; - - switch (lport->lport_proto_id) { - case SCSI_PROTOCOL_FCP: - default: - ret = fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg, - format_code, buf); - break; - } - - return ret; -} - -static u32 tcm_qla2xxx_get_pr_transport_id_len( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct t10_pr_registration *pr_reg, - int *format_code) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - struct tcm_qla2xxx_lport *lport = tpg->lport; - int ret = 0; - - switch (lport->lport_proto_id) { - case SCSI_PROTOCOL_FCP: - default: - ret = fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, - format_code); - break; - } - - return ret; -} - -static char *tcm_qla2xxx_parse_pr_out_transport_id( - struct se_portal_group *se_tpg, - const char *buf, - u32 *out_tid_len, - char **port_nexus_ptr) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - struct tcm_qla2xxx_lport *lport = tpg->lport; - char *tid = NULL; - - switch (lport->lport_proto_id) { - case SCSI_PROTOCOL_FCP: - default: - tid = fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, - port_nexus_ptr); - break; - } - - return tid; -} - -static int tcm_qla2xxx_check_demo_mode(struct se_portal_group *se_tpg) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - - return QLA_TPG_ATTRIB(tpg)->generate_node_acls; -} - -static int tcm_qla2xxx_check_demo_mode_cache(struct se_portal_group *se_tpg) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - - return QLA_TPG_ATTRIB(tpg)->cache_dynamic_acls; -} - -static int tcm_qla2xxx_check_demo_write_protect(struct se_portal_group *se_tpg) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - - return QLA_TPG_ATTRIB(tpg)->demo_mode_write_protect; -} - -static int tcm_qla2xxx_check_prod_write_protect(struct se_portal_group *se_tpg) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - - return QLA_TPG_ATTRIB(tpg)->prod_mode_write_protect; -} - -static struct se_node_acl *tcm_qla2xxx_alloc_fabric_acl( - struct se_portal_group *se_tpg) -{ - struct tcm_qla2xxx_nacl *nacl; - - nacl = kzalloc(sizeof(struct tcm_qla2xxx_nacl), GFP_KERNEL); - if (!nacl) { - pr_err("Unable to alocate struct tcm_qla2xxx_nacl\n"); - return NULL; - } - - return &nacl->se_node_acl; -} - -static void tcm_qla2xxx_release_fabric_acl( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl) -{ - struct tcm_qla2xxx_nacl *nacl = container_of(se_nacl, - struct tcm_qla2xxx_nacl, se_node_acl); - kfree(nacl); -} - -static u32 tcm_qla2xxx_tpg_get_inst_index(struct se_portal_group *se_tpg) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - - return tpg->lport_tpgt; -} - -static void tcm_qla2xxx_complete_mcmd(struct work_struct *work) -{ - struct qla_tgt_mgmt_cmd *mcmd = container_of(work, - struct qla_tgt_mgmt_cmd, free_work); - - transport_generic_free_cmd(&mcmd->se_cmd, 0); -} - -/* - * Called from qla_target_template->free_mcmd(), and will call - * tcm_qla2xxx_release_cmd() via normal struct target_core_fabric_ops - * release callback. qla_hw_data->hardware_lock is expected to be held - */ -static void tcm_qla2xxx_free_mcmd(struct qla_tgt_mgmt_cmd *mcmd) -{ - INIT_WORK(&mcmd->free_work, tcm_qla2xxx_complete_mcmd); - queue_work(tcm_qla2xxx_free_wq, &mcmd->free_work); -} - -static void tcm_qla2xxx_complete_free(struct work_struct *work) -{ - struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work); - - transport_generic_free_cmd(&cmd->se_cmd, 0); -} - -/* - * Called from qla_target_template->free_cmd(), and will call - * tcm_qla2xxx_release_cmd via normal struct target_core_fabric_ops - * release callback. qla_hw_data->hardware_lock is expected to be held - */ -static void tcm_qla2xxx_free_cmd(struct qla_tgt_cmd *cmd) -{ - INIT_WORK(&cmd->work, tcm_qla2xxx_complete_free); - queue_work(tcm_qla2xxx_free_wq, &cmd->work); -} - -/* - * Called from struct target_core_fabric_ops->check_stop_free() context - */ -static int tcm_qla2xxx_check_stop_free(struct se_cmd *se_cmd) -{ - return target_put_sess_cmd(se_cmd->se_sess, se_cmd); -} - -/* tcm_qla2xxx_release_cmd - Callback from TCM Core to release underlying - * fabric descriptor @se_cmd command to release - */ -static void tcm_qla2xxx_release_cmd(struct se_cmd *se_cmd) -{ - struct qla_tgt_cmd *cmd; - - if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) { - struct qla_tgt_mgmt_cmd *mcmd = container_of(se_cmd, - struct qla_tgt_mgmt_cmd, se_cmd); - qlt_free_mcmd(mcmd); - return; - } - - cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd); - qlt_free_cmd(cmd); -} - -static int tcm_qla2xxx_shutdown_session(struct se_session *se_sess) -{ - struct qla_tgt_sess *sess = se_sess->fabric_sess_ptr; - struct scsi_qla_host *vha; - unsigned long flags; - - BUG_ON(!sess); - vha = sess->vha; - - spin_lock_irqsave(&vha->hw->hardware_lock, flags); - sess->tearing_down = 1; - target_splice_sess_cmd_list(se_sess); - spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); - - return 1; -} - -static void tcm_qla2xxx_close_session(struct se_session *se_sess) -{ - struct qla_tgt_sess *sess = se_sess->fabric_sess_ptr; - struct scsi_qla_host *vha; - unsigned long flags; - - BUG_ON(!sess); - vha = sess->vha; - - spin_lock_irqsave(&vha->hw->hardware_lock, flags); - qlt_unreg_sess(sess); - spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); -} - -static u32 tcm_qla2xxx_sess_get_index(struct se_session *se_sess) -{ - return 0; -} - -/* - * The LIO target core uses DMA_TO_DEVICE to mean that data is going - * to the target (eg handling a WRITE) and DMA_FROM_DEVICE to mean - * that data is coming from the target (eg handling a READ). However, - * this is just the opposite of what we have to tell the DMA mapping - * layer -- eg when handling a READ, the HBA will have to DMA the data - * out of memory so it can send it to the initiator, which means we - * need to use DMA_TO_DEVICE when we map the data. - */ -static enum dma_data_direction tcm_qla2xxx_mapping_dir(struct se_cmd *se_cmd) -{ - if (se_cmd->se_cmd_flags & SCF_BIDI) - return DMA_BIDIRECTIONAL; - - switch (se_cmd->data_direction) { - case DMA_TO_DEVICE: - return DMA_FROM_DEVICE; - case DMA_FROM_DEVICE: - return DMA_TO_DEVICE; - case DMA_NONE: - default: - return DMA_NONE; - } -} - -static int tcm_qla2xxx_write_pending(struct se_cmd *se_cmd) -{ - struct qla_tgt_cmd *cmd = container_of(se_cmd, - struct qla_tgt_cmd, se_cmd); - - cmd->bufflen = se_cmd->data_length; - cmd->dma_data_direction = tcm_qla2xxx_mapping_dir(se_cmd); - - cmd->sg_cnt = se_cmd->t_data_nents; - cmd->sg = se_cmd->t_data_sg; - - /* - * qla_target.c:qlt_rdy_to_xfer() will call pci_map_sg() to setup - * the SGL mappings into PCIe memory for incoming FCP WRITE data. - */ - return qlt_rdy_to_xfer(cmd); -} - -static int tcm_qla2xxx_write_pending_status(struct se_cmd *se_cmd) -{ - unsigned long flags; - /* - * Check for WRITE_PENDING status to determine if we need to wait for - * CTIO aborts to be posted via hardware in tcm_qla2xxx_handle_data(). - */ - spin_lock_irqsave(&se_cmd->t_state_lock, flags); - if (se_cmd->t_state == TRANSPORT_WRITE_PENDING || - se_cmd->t_state == TRANSPORT_COMPLETE_QF_WP) { - spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); - wait_for_completion_timeout(&se_cmd->t_transport_stop_comp, - 3000); - return 0; - } - spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); - - return 0; -} - -static void tcm_qla2xxx_set_default_node_attrs(struct se_node_acl *nacl) -{ - return; -} - -static u32 tcm_qla2xxx_get_task_tag(struct se_cmd *se_cmd) -{ - struct qla_tgt_cmd *cmd = container_of(se_cmd, - struct qla_tgt_cmd, se_cmd); - - return cmd->tag; -} - -static int tcm_qla2xxx_get_cmd_state(struct se_cmd *se_cmd) -{ - return 0; -} - -/* - * Called from process context in qla_target.c:qlt_do_work() code - */ -static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd, - unsigned char *cdb, uint32_t data_length, int fcp_task_attr, - int data_dir, int bidi) -{ - struct se_cmd *se_cmd = &cmd->se_cmd; - struct se_session *se_sess; - struct qla_tgt_sess *sess; - int flags = TARGET_SCF_ACK_KREF; - - if (bidi) - flags |= TARGET_SCF_BIDI_OP; - - sess = cmd->sess; - if (!sess) { - pr_err("Unable to locate struct qla_tgt_sess from qla_tgt_cmd\n"); - return -EINVAL; - } - - se_sess = sess->se_sess; - if (!se_sess) { - pr_err("Unable to locate active struct se_session\n"); - return -EINVAL; - } - - target_submit_cmd(se_cmd, se_sess, cdb, &cmd->sense_buffer[0], - cmd->unpacked_lun, data_length, fcp_task_attr, - data_dir, flags); - return 0; -} - -static void tcm_qla2xxx_do_rsp(struct work_struct *work) -{ - struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work); - /* - * Dispatch ->queue_status from workqueue process context - */ - transport_generic_request_failure(&cmd->se_cmd); -} - -/* - * Called from qla_target.c:qlt_do_ctio_completion() - */ -static int tcm_qla2xxx_handle_data(struct qla_tgt_cmd *cmd) -{ - struct se_cmd *se_cmd = &cmd->se_cmd; - unsigned long flags; - /* - * Ensure that the complete FCP WRITE payload has been received. - * Otherwise return an exception via CHECK_CONDITION status. - */ - if (!cmd->write_data_transferred) { - /* - * Check if se_cmd has already been aborted via LUN_RESET, and - * waiting upon completion in tcm_qla2xxx_write_pending_status() - */ - spin_lock_irqsave(&se_cmd->t_state_lock, flags); - if (se_cmd->transport_state & CMD_T_ABORTED) { - spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); - complete(&se_cmd->t_transport_stop_comp); - return 0; - } - spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); - - se_cmd->scsi_sense_reason = TCM_CHECK_CONDITION_ABORT_CMD; - INIT_WORK(&cmd->work, tcm_qla2xxx_do_rsp); - queue_work(tcm_qla2xxx_free_wq, &cmd->work); - return 0; - } - /* - * We now tell TCM to queue this WRITE CDB with TRANSPORT_PROCESS_WRITE - * status to the backstore processing thread. - */ - return transport_generic_handle_data(&cmd->se_cmd); -} - -/* - * Called from qla_target.c:qlt_issue_task_mgmt() - */ -int tcm_qla2xxx_handle_tmr(struct qla_tgt_mgmt_cmd *mcmd, uint32_t lun, - uint8_t tmr_func, uint32_t tag) -{ - struct qla_tgt_sess *sess = mcmd->sess; - struct se_cmd *se_cmd = &mcmd->se_cmd; - - return target_submit_tmr(se_cmd, sess->se_sess, NULL, lun, mcmd, - tmr_func, GFP_ATOMIC, tag, TARGET_SCF_ACK_KREF); -} - -static int tcm_qla2xxx_queue_data_in(struct se_cmd *se_cmd) -{ - struct qla_tgt_cmd *cmd = container_of(se_cmd, - struct qla_tgt_cmd, se_cmd); - - cmd->bufflen = se_cmd->data_length; - cmd->dma_data_direction = tcm_qla2xxx_mapping_dir(se_cmd); - cmd->aborted = (se_cmd->transport_state & CMD_T_ABORTED); - - cmd->sg_cnt = se_cmd->t_data_nents; - cmd->sg = se_cmd->t_data_sg; - cmd->offset = 0; - - /* - * Now queue completed DATA_IN the qla2xxx LLD and response ring - */ - return qlt_xmit_response(cmd, QLA_TGT_XMIT_DATA|QLA_TGT_XMIT_STATUS, - se_cmd->scsi_status); -} - -static int tcm_qla2xxx_queue_status(struct se_cmd *se_cmd) -{ - struct qla_tgt_cmd *cmd = container_of(se_cmd, - struct qla_tgt_cmd, se_cmd); - int xmit_type = QLA_TGT_XMIT_STATUS; - - cmd->bufflen = se_cmd->data_length; - cmd->sg = NULL; - cmd->sg_cnt = 0; - cmd->offset = 0; - cmd->dma_data_direction = tcm_qla2xxx_mapping_dir(se_cmd); - cmd->aborted = (se_cmd->transport_state & CMD_T_ABORTED); - - if (se_cmd->data_direction == DMA_FROM_DEVICE) { - /* - * For FCP_READ with CHECK_CONDITION status, clear cmd->bufflen - * for qla_tgt_xmit_response LLD code - */ - se_cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT; - se_cmd->residual_count = se_cmd->data_length; - - cmd->bufflen = 0; - } - /* - * Now queue status response to qla2xxx LLD code and response ring - */ - return qlt_xmit_response(cmd, xmit_type, se_cmd->scsi_status); -} - -static int tcm_qla2xxx_queue_tm_rsp(struct se_cmd *se_cmd) -{ - struct se_tmr_req *se_tmr = se_cmd->se_tmr_req; - struct qla_tgt_mgmt_cmd *mcmd = container_of(se_cmd, - struct qla_tgt_mgmt_cmd, se_cmd); - - pr_debug("queue_tm_rsp: mcmd: %p func: 0x%02x response: 0x%02x\n", - mcmd, se_tmr->function, se_tmr->response); - /* - * Do translation between TCM TM response codes and - * QLA2xxx FC TM response codes. - */ - switch (se_tmr->response) { - case TMR_FUNCTION_COMPLETE: - mcmd->fc_tm_rsp = FC_TM_SUCCESS; - break; - case TMR_TASK_DOES_NOT_EXIST: - mcmd->fc_tm_rsp = FC_TM_BAD_CMD; - break; - case TMR_FUNCTION_REJECTED: - mcmd->fc_tm_rsp = FC_TM_REJECT; - break; - case TMR_LUN_DOES_NOT_EXIST: - default: - mcmd->fc_tm_rsp = FC_TM_FAILED; - break; - } - /* - * Queue the TM response to QLA2xxx LLD to build a - * CTIO response packet. - */ - qlt_xmit_tm_rsp(mcmd); - - return 0; -} - -static u16 tcm_qla2xxx_get_fabric_sense_len(void) -{ - return 0; -} - -static u16 tcm_qla2xxx_set_fabric_sense_len(struct se_cmd *se_cmd, - u32 sense_length) -{ - return 0; -} - -/* Local pointer to allocated TCM configfs fabric module */ -struct target_fabric_configfs *tcm_qla2xxx_fabric_configfs; -struct target_fabric_configfs *tcm_qla2xxx_npiv_fabric_configfs; - -static int tcm_qla2xxx_setup_nacl_from_rport( - struct se_portal_group *se_tpg, - struct se_node_acl *se_nacl, - struct tcm_qla2xxx_lport *lport, - struct tcm_qla2xxx_nacl *nacl, - u64 rport_wwnn) -{ - struct scsi_qla_host *vha = lport->qla_vha; - struct Scsi_Host *sh = vha->host; - struct fc_host_attrs *fc_host = shost_to_fc_host(sh); - struct fc_rport *rport; - unsigned long flags; - void *node; - int rc; - - /* - * Scan the existing rports, and create a session for the - * explict NodeACL is an matching rport->node_name already - * exists. - */ - spin_lock_irqsave(sh->host_lock, flags); - list_for_each_entry(rport, &fc_host->rports, peers) { - if (rport_wwnn != rport->node_name) - continue; - - pr_debug("Located existing rport_wwpn and rport->node_name: 0x%016LX, port_id: 0x%04x\n", - rport->node_name, rport->port_id); - nacl->nport_id = rport->port_id; - - spin_unlock_irqrestore(sh->host_lock, flags); - - spin_lock_irqsave(&vha->hw->hardware_lock, flags); - node = btree_lookup32(&lport->lport_fcport_map, rport->port_id); - if (node) { - rc = btree_update32(&lport->lport_fcport_map, - rport->port_id, se_nacl); - } else { - rc = btree_insert32(&lport->lport_fcport_map, - rport->port_id, se_nacl, - GFP_ATOMIC); - } - spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); - - if (rc) { - pr_err("Unable to insert se_nacl into fcport_map"); - WARN_ON(rc > 0); - return rc; - } - - pr_debug("Inserted into fcport_map: %p for WWNN: 0x%016LX, port_id: 0x%08x\n", - se_nacl, rport_wwnn, nacl->nport_id); - - return 1; - } - spin_unlock_irqrestore(sh->host_lock, flags); - - return 0; -} - -/* - * Expected to be called with struct qla_hw_data->hardware_lock held - */ -static void tcm_qla2xxx_clear_nacl_from_fcport_map(struct qla_tgt_sess *sess) -{ - struct se_node_acl *se_nacl = sess->se_sess->se_node_acl; - struct se_portal_group *se_tpg = se_nacl->se_tpg; - struct se_wwn *se_wwn = se_tpg->se_tpg_wwn; - struct tcm_qla2xxx_lport *lport = container_of(se_wwn, - struct tcm_qla2xxx_lport, lport_wwn); - struct tcm_qla2xxx_nacl *nacl = container_of(se_nacl, - struct tcm_qla2xxx_nacl, se_node_acl); - void *node; - - pr_debug("fc_rport domain: port_id 0x%06x\n", nacl->nport_id); - - node = btree_remove32(&lport->lport_fcport_map, nacl->nport_id); - WARN_ON(node && (node != se_nacl)); - - pr_debug("Removed from fcport_map: %p for WWNN: 0x%016LX, port_id: 0x%06x\n", - se_nacl, nacl->nport_wwnn, nacl->nport_id); -} - -static void tcm_qla2xxx_put_sess(struct qla_tgt_sess *sess) -{ - target_put_session(sess->se_sess); -} - -static void tcm_qla2xxx_shutdown_sess(struct qla_tgt_sess *sess) -{ - tcm_qla2xxx_shutdown_session(sess->se_sess); -} - -static struct se_node_acl *tcm_qla2xxx_make_nodeacl( - struct se_portal_group *se_tpg, - struct config_group *group, - const char *name) -{ - struct se_wwn *se_wwn = se_tpg->se_tpg_wwn; - struct tcm_qla2xxx_lport *lport = container_of(se_wwn, - struct tcm_qla2xxx_lport, lport_wwn); - struct se_node_acl *se_nacl, *se_nacl_new; - struct tcm_qla2xxx_nacl *nacl; - u64 wwnn; - u32 qla2xxx_nexus_depth; - int rc; - - if (tcm_qla2xxx_parse_wwn(name, &wwnn, 1) < 0) - return ERR_PTR(-EINVAL); - - se_nacl_new = tcm_qla2xxx_alloc_fabric_acl(se_tpg); - if (!se_nacl_new) - return ERR_PTR(-ENOMEM); -/* #warning FIXME: Hardcoded qla2xxx_nexus depth in tcm_qla2xxx_make_nodeacl */ - qla2xxx_nexus_depth = 1; - - /* - * se_nacl_new may be released by core_tpg_add_initiator_node_acl() - * when converting a NodeACL from demo mode -> explict - */ - se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new, - name, qla2xxx_nexus_depth); - if (IS_ERR(se_nacl)) { - tcm_qla2xxx_release_fabric_acl(se_tpg, se_nacl_new); - return se_nacl; - } - /* - * Locate our struct tcm_qla2xxx_nacl and set the FC Nport WWPN - */ - nacl = container_of(se_nacl, struct tcm_qla2xxx_nacl, se_node_acl); - nacl->nport_wwnn = wwnn; - tcm_qla2xxx_format_wwn(&nacl->nport_name[0], TCM_QLA2XXX_NAMELEN, wwnn); - /* - * Setup a se_nacl handle based on an a matching struct fc_rport setup - * via drivers/scsi/qla2xxx/qla_init.c:qla2x00_reg_remote_port() - */ - rc = tcm_qla2xxx_setup_nacl_from_rport(se_tpg, se_nacl, lport, - nacl, wwnn); - if (rc < 0) { - tcm_qla2xxx_release_fabric_acl(se_tpg, se_nacl_new); - return ERR_PTR(rc); - } - - return se_nacl; -} - -static void tcm_qla2xxx_drop_nodeacl(struct se_node_acl *se_acl) -{ - struct se_portal_group *se_tpg = se_acl->se_tpg; - struct tcm_qla2xxx_nacl *nacl = container_of(se_acl, - struct tcm_qla2xxx_nacl, se_node_acl); - - core_tpg_del_initiator_node_acl(se_tpg, se_acl, 1); - kfree(nacl); -} - -/* Start items for tcm_qla2xxx_tpg_attrib_cit */ - -#define DEF_QLA_TPG_ATTRIB(name) \ - \ -static ssize_t tcm_qla2xxx_tpg_attrib_show_##name( \ - struct se_portal_group *se_tpg, \ - char *page) \ -{ \ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, \ - struct tcm_qla2xxx_tpg, se_tpg); \ - \ - return sprintf(page, "%u\n", QLA_TPG_ATTRIB(tpg)->name); \ -} \ - \ -static ssize_t tcm_qla2xxx_tpg_attrib_store_##name( \ - struct se_portal_group *se_tpg, \ - const char *page, \ - size_t count) \ -{ \ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, \ - struct tcm_qla2xxx_tpg, se_tpg); \ - unsigned long val; \ - int ret; \ - \ - ret = kstrtoul(page, 0, &val); \ - if (ret < 0) { \ - pr_err("kstrtoul() failed with" \ - " ret: %d\n", ret); \ - return -EINVAL; \ - } \ - ret = tcm_qla2xxx_set_attrib_##name(tpg, val); \ - \ - return (!ret) ? count : -EINVAL; \ -} - -#define DEF_QLA_TPG_ATTR_BOOL(_name) \ - \ -static int tcm_qla2xxx_set_attrib_##_name( \ - struct tcm_qla2xxx_tpg *tpg, \ - unsigned long val) \ -{ \ - struct tcm_qla2xxx_tpg_attrib *a = &tpg->tpg_attrib; \ - \ - if ((val != 0) && (val != 1)) { \ - pr_err("Illegal boolean value %lu\n", val); \ - return -EINVAL; \ - } \ - \ - a->_name = val; \ - return 0; \ -} - -#define QLA_TPG_ATTR(_name, _mode) \ - TF_TPG_ATTRIB_ATTR(tcm_qla2xxx, _name, _mode); - -/* - * Define tcm_qla2xxx_tpg_attrib_s_generate_node_acls - */ -DEF_QLA_TPG_ATTR_BOOL(generate_node_acls); -DEF_QLA_TPG_ATTRIB(generate_node_acls); -QLA_TPG_ATTR(generate_node_acls, S_IRUGO | S_IWUSR); - -/* - Define tcm_qla2xxx_attrib_s_cache_dynamic_acls - */ -DEF_QLA_TPG_ATTR_BOOL(cache_dynamic_acls); -DEF_QLA_TPG_ATTRIB(cache_dynamic_acls); -QLA_TPG_ATTR(cache_dynamic_acls, S_IRUGO | S_IWUSR); - -/* - * Define tcm_qla2xxx_tpg_attrib_s_demo_mode_write_protect - */ -DEF_QLA_TPG_ATTR_BOOL(demo_mode_write_protect); -DEF_QLA_TPG_ATTRIB(demo_mode_write_protect); -QLA_TPG_ATTR(demo_mode_write_protect, S_IRUGO | S_IWUSR); - -/* - * Define tcm_qla2xxx_tpg_attrib_s_prod_mode_write_protect - */ -DEF_QLA_TPG_ATTR_BOOL(prod_mode_write_protect); -DEF_QLA_TPG_ATTRIB(prod_mode_write_protect); -QLA_TPG_ATTR(prod_mode_write_protect, S_IRUGO | S_IWUSR); - -static struct configfs_attribute *tcm_qla2xxx_tpg_attrib_attrs[] = { - &tcm_qla2xxx_tpg_attrib_generate_node_acls.attr, - &tcm_qla2xxx_tpg_attrib_cache_dynamic_acls.attr, - &tcm_qla2xxx_tpg_attrib_demo_mode_write_protect.attr, - &tcm_qla2xxx_tpg_attrib_prod_mode_write_protect.attr, - NULL, -}; - -/* End items for tcm_qla2xxx_tpg_attrib_cit */ - -static ssize_t tcm_qla2xxx_tpg_show_enable( - struct se_portal_group *se_tpg, - char *page) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - - return snprintf(page, PAGE_SIZE, "%d\n", - atomic_read(&tpg->lport_tpg_enabled)); -} - -static ssize_t tcm_qla2xxx_tpg_store_enable( - struct se_portal_group *se_tpg, - const char *page, - size_t count) -{ - struct se_wwn *se_wwn = se_tpg->se_tpg_wwn; - struct tcm_qla2xxx_lport *lport = container_of(se_wwn, - struct tcm_qla2xxx_lport, lport_wwn); - struct scsi_qla_host *vha = lport->qla_vha; - struct qla_hw_data *ha = vha->hw; - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - unsigned long op; - int rc; - - rc = kstrtoul(page, 0, &op); - if (rc < 0) { - pr_err("kstrtoul() returned %d\n", rc); - return -EINVAL; - } - if ((op != 1) && (op != 0)) { - pr_err("Illegal value for tpg_enable: %lu\n", op); - return -EINVAL; - } - - if (op) { - atomic_set(&tpg->lport_tpg_enabled, 1); - qlt_enable_vha(vha); - } else { - if (!ha->tgt.qla_tgt) { - pr_err("truct qla_hw_data *ha->tgt.qla_tgt is NULL\n"); - return -ENODEV; - } - atomic_set(&tpg->lport_tpg_enabled, 0); - qlt_stop_phase1(ha->tgt.qla_tgt); - } - - return count; -} - -TF_TPG_BASE_ATTR(tcm_qla2xxx, enable, S_IRUGO | S_IWUSR); - -static struct configfs_attribute *tcm_qla2xxx_tpg_attrs[] = { - &tcm_qla2xxx_tpg_enable.attr, - NULL, -}; - -static struct se_portal_group *tcm_qla2xxx_make_tpg( - struct se_wwn *wwn, - struct config_group *group, - const char *name) -{ - struct tcm_qla2xxx_lport *lport = container_of(wwn, - struct tcm_qla2xxx_lport, lport_wwn); - struct tcm_qla2xxx_tpg *tpg; - unsigned long tpgt; - int ret; - - if (strstr(name, "tpgt_") != name) - return ERR_PTR(-EINVAL); - if (kstrtoul(name + 5, 10, &tpgt) || tpgt > USHRT_MAX) - return ERR_PTR(-EINVAL); - - if (!lport->qla_npiv_vp && (tpgt != 1)) { - pr_err("In non NPIV mode, a single TPG=1 is used for HW port mappings\n"); - return ERR_PTR(-ENOSYS); - } - - tpg = kzalloc(sizeof(struct tcm_qla2xxx_tpg), GFP_KERNEL); - if (!tpg) { - pr_err("Unable to allocate struct tcm_qla2xxx_tpg\n"); - return ERR_PTR(-ENOMEM); - } - tpg->lport = lport; - tpg->lport_tpgt = tpgt; - /* - * By default allow READ-ONLY TPG demo-mode access w/ cached dynamic - * NodeACLs - */ - QLA_TPG_ATTRIB(tpg)->generate_node_acls = 1; - QLA_TPG_ATTRIB(tpg)->demo_mode_write_protect = 1; - QLA_TPG_ATTRIB(tpg)->cache_dynamic_acls = 1; - - ret = core_tpg_register(&tcm_qla2xxx_fabric_configfs->tf_ops, wwn, - &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); - if (ret < 0) { - kfree(tpg); - return NULL; - } - /* - * Setup local TPG=1 pointer for non NPIV mode. - */ - if (lport->qla_npiv_vp == NULL) - lport->tpg_1 = tpg; - - return &tpg->se_tpg; -} - -static void tcm_qla2xxx_drop_tpg(struct se_portal_group *se_tpg) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - struct tcm_qla2xxx_lport *lport = tpg->lport; - struct scsi_qla_host *vha = lport->qla_vha; - struct qla_hw_data *ha = vha->hw; - /* - * Call into qla2x_target.c LLD logic to shutdown the active - * FC Nexuses and disable target mode operation for this qla_hw_data - */ - if (ha->tgt.qla_tgt && !ha->tgt.qla_tgt->tgt_stop) - qlt_stop_phase1(ha->tgt.qla_tgt); - - core_tpg_deregister(se_tpg); - /* - * Clear local TPG=1 pointer for non NPIV mode. - */ - if (lport->qla_npiv_vp == NULL) - lport->tpg_1 = NULL; - - kfree(tpg); -} - -static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg( - struct se_wwn *wwn, - struct config_group *group, - const char *name) -{ - struct tcm_qla2xxx_lport *lport = container_of(wwn, - struct tcm_qla2xxx_lport, lport_wwn); - struct tcm_qla2xxx_tpg *tpg; - unsigned long tpgt; - int ret; - - if (strstr(name, "tpgt_") != name) - return ERR_PTR(-EINVAL); - if (kstrtoul(name + 5, 10, &tpgt) || tpgt > USHRT_MAX) - return ERR_PTR(-EINVAL); - - tpg = kzalloc(sizeof(struct tcm_qla2xxx_tpg), GFP_KERNEL); - if (!tpg) { - pr_err("Unable to allocate struct tcm_qla2xxx_tpg\n"); - return ERR_PTR(-ENOMEM); - } - tpg->lport = lport; - tpg->lport_tpgt = tpgt; - - ret = core_tpg_register(&tcm_qla2xxx_npiv_fabric_configfs->tf_ops, wwn, - &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); - if (ret < 0) { - kfree(tpg); - return NULL; - } - return &tpg->se_tpg; -} - -/* - * Expected to be called with struct qla_hw_data->hardware_lock held - */ -static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_s_id( - scsi_qla_host_t *vha, - const uint8_t *s_id) -{ - struct qla_hw_data *ha = vha->hw; - struct tcm_qla2xxx_lport *lport; - struct se_node_acl *se_nacl; - struct tcm_qla2xxx_nacl *nacl; - u32 key; - - lport = ha->tgt.target_lport_ptr; - if (!lport) { - pr_err("Unable to locate struct tcm_qla2xxx_lport\n"); - dump_stack(); - return NULL; - } - - key = (((unsigned long)s_id[0] << 16) | - ((unsigned long)s_id[1] << 8) | - (unsigned long)s_id[2]); - pr_debug("find_sess_by_s_id: 0x%06x\n", key); - - se_nacl = btree_lookup32(&lport->lport_fcport_map, key); - if (!se_nacl) { - pr_debug("Unable to locate s_id: 0x%06x\n", key); - return NULL; - } - pr_debug("find_sess_by_s_id: located se_nacl: %p, initiatorname: %s\n", - se_nacl, se_nacl->initiatorname); - - nacl = container_of(se_nacl, struct tcm_qla2xxx_nacl, se_node_acl); - if (!nacl->qla_tgt_sess) { - pr_err("Unable to locate struct qla_tgt_sess\n"); - return NULL; - } - - return nacl->qla_tgt_sess; -} - -/* - * Expected to be called with struct qla_hw_data->hardware_lock held - */ -static void tcm_qla2xxx_set_sess_by_s_id( - struct tcm_qla2xxx_lport *lport, - struct se_node_acl *new_se_nacl, - struct tcm_qla2xxx_nacl *nacl, - struct se_session *se_sess, - struct qla_tgt_sess *qla_tgt_sess, - uint8_t *s_id) -{ - u32 key; - void *slot; - int rc; - - key = (((unsigned long)s_id[0] << 16) | - ((unsigned long)s_id[1] << 8) | - (unsigned long)s_id[2]); - pr_debug("set_sess_by_s_id: %06x\n", key); - - slot = btree_lookup32(&lport->lport_fcport_map, key); - if (!slot) { - if (new_se_nacl) { - pr_debug("Setting up new fc_port entry to new_se_nacl\n"); - nacl->nport_id = key; - rc = btree_insert32(&lport->lport_fcport_map, key, - new_se_nacl, GFP_ATOMIC); - if (rc) - printk(KERN_ERR "Unable to insert s_id into fcport_map: %06x\n", - (int)key); - } else { - pr_debug("Wiping nonexisting fc_port entry\n"); - } - - qla_tgt_sess->se_sess = se_sess; - nacl->qla_tgt_sess = qla_tgt_sess; - return; - } - - if (nacl->qla_tgt_sess) { - if (new_se_nacl == NULL) { - pr_debug("Clearing existing nacl->qla_tgt_sess and fc_port entry\n"); - btree_remove32(&lport->lport_fcport_map, key); - nacl->qla_tgt_sess = NULL; - return; - } - pr_debug("Replacing existing nacl->qla_tgt_sess and fc_port entry\n"); - btree_update32(&lport->lport_fcport_map, key, new_se_nacl); - qla_tgt_sess->se_sess = se_sess; - nacl->qla_tgt_sess = qla_tgt_sess; - return; - } - - if (new_se_nacl == NULL) { - pr_debug("Clearing existing fc_port entry\n"); - btree_remove32(&lport->lport_fcport_map, key); - return; - } - - pr_debug("Replacing existing fc_port entry w/o active nacl->qla_tgt_sess\n"); - btree_update32(&lport->lport_fcport_map, key, new_se_nacl); - qla_tgt_sess->se_sess = se_sess; - nacl->qla_tgt_sess = qla_tgt_sess; - - pr_debug("Setup nacl->qla_tgt_sess %p by s_id for se_nacl: %p, initiatorname: %s\n", - nacl->qla_tgt_sess, new_se_nacl, new_se_nacl->initiatorname); -} - -/* - * Expected to be called with struct qla_hw_data->hardware_lock held - */ -static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_loop_id( - scsi_qla_host_t *vha, - const uint16_t loop_id) -{ - struct qla_hw_data *ha = vha->hw; - struct tcm_qla2xxx_lport *lport; - struct se_node_acl *se_nacl; - struct tcm_qla2xxx_nacl *nacl; - struct tcm_qla2xxx_fc_loopid *fc_loopid; - - lport = ha->tgt.target_lport_ptr; - if (!lport) { - pr_err("Unable to locate struct tcm_qla2xxx_lport\n"); - dump_stack(); - return NULL; - } - - pr_debug("find_sess_by_loop_id: Using loop_id: 0x%04x\n", loop_id); - - fc_loopid = lport->lport_loopid_map + loop_id; - se_nacl = fc_loopid->se_nacl; - if (!se_nacl) { - pr_debug("Unable to locate se_nacl by loop_id: 0x%04x\n", - loop_id); - return NULL; - } - - nacl = container_of(se_nacl, struct tcm_qla2xxx_nacl, se_node_acl); - - if (!nacl->qla_tgt_sess) { - pr_err("Unable to locate struct qla_tgt_sess\n"); - return NULL; - } - - return nacl->qla_tgt_sess; -} - -/* - * Expected to be called with struct qla_hw_data->hardware_lock held - */ -static void tcm_qla2xxx_set_sess_by_loop_id( - struct tcm_qla2xxx_lport *lport, - struct se_node_acl *new_se_nacl, - struct tcm_qla2xxx_nacl *nacl, - struct se_session *se_sess, - struct qla_tgt_sess *qla_tgt_sess, - uint16_t loop_id) -{ - struct se_node_acl *saved_nacl; - struct tcm_qla2xxx_fc_loopid *fc_loopid; - - pr_debug("set_sess_by_loop_id: Using loop_id: 0x%04x\n", loop_id); - - fc_loopid = &((struct tcm_qla2xxx_fc_loopid *) - lport->lport_loopid_map)[loop_id]; - - saved_nacl = fc_loopid->se_nacl; - if (!saved_nacl) { - pr_debug("Setting up new fc_loopid->se_nacl to new_se_nacl\n"); - fc_loopid->se_nacl = new_se_nacl; - if (qla_tgt_sess->se_sess != se_sess) - qla_tgt_sess->se_sess = se_sess; - if (nacl->qla_tgt_sess != qla_tgt_sess) - nacl->qla_tgt_sess = qla_tgt_sess; - return; - } - - if (nacl->qla_tgt_sess) { - if (new_se_nacl == NULL) { - pr_debug("Clearing nacl->qla_tgt_sess and fc_loopid->se_nacl\n"); - fc_loopid->se_nacl = NULL; - nacl->qla_tgt_sess = NULL; - return; - } - - pr_debug("Replacing existing nacl->qla_tgt_sess and fc_loopid->se_nacl\n"); - fc_loopid->se_nacl = new_se_nacl; - if (qla_tgt_sess->se_sess != se_sess) - qla_tgt_sess->se_sess = se_sess; - if (nacl->qla_tgt_sess != qla_tgt_sess) - nacl->qla_tgt_sess = qla_tgt_sess; - return; - } - - if (new_se_nacl == NULL) { - pr_debug("Clearing fc_loopid->se_nacl\n"); - fc_loopid->se_nacl = NULL; - return; - } - - pr_debug("Replacing existing fc_loopid->se_nacl w/o active nacl->qla_tgt_sess\n"); - fc_loopid->se_nacl = new_se_nacl; - if (qla_tgt_sess->se_sess != se_sess) - qla_tgt_sess->se_sess = se_sess; - if (nacl->qla_tgt_sess != qla_tgt_sess) - nacl->qla_tgt_sess = qla_tgt_sess; - - pr_debug("Setup nacl->qla_tgt_sess %p by loop_id for se_nacl: %p, initiatorname: %s\n", - nacl->qla_tgt_sess, new_se_nacl, new_se_nacl->initiatorname); -} - -static void tcm_qla2xxx_free_session(struct qla_tgt_sess *sess) -{ - struct qla_tgt *tgt = sess->tgt; - struct qla_hw_data *ha = tgt->ha; - struct se_session *se_sess; - struct se_node_acl *se_nacl; - struct tcm_qla2xxx_lport *lport; - struct tcm_qla2xxx_nacl *nacl; - unsigned char be_sid[3]; - unsigned long flags; - - BUG_ON(in_interrupt()); - - se_sess = sess->se_sess; - if (!se_sess) { - pr_err("struct qla_tgt_sess->se_sess is NULL\n"); - dump_stack(); - return; - } - se_nacl = se_sess->se_node_acl; - nacl = container_of(se_nacl, struct tcm_qla2xxx_nacl, se_node_acl); - - lport = ha->tgt.target_lport_ptr; - if (!lport) { - pr_err("Unable to locate struct tcm_qla2xxx_lport\n"); - dump_stack(); - return; - } - target_wait_for_sess_cmds(se_sess, 0); - /* - * And now clear the se_nacl and session pointers from our HW lport - * mappings for fabric S_ID and LOOP_ID. - */ - memset(&be_sid, 0, 3); - be_sid[0] = sess->s_id.b.domain; - be_sid[1] = sess->s_id.b.area; - be_sid[2] = sess->s_id.b.al_pa; - - spin_lock_irqsave(&ha->hardware_lock, flags); - tcm_qla2xxx_set_sess_by_s_id(lport, NULL, nacl, se_sess, - sess, be_sid); - tcm_qla2xxx_set_sess_by_loop_id(lport, NULL, nacl, se_sess, - sess, sess->loop_id); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - transport_deregister_session_configfs(sess->se_sess); - transport_deregister_session(sess->se_sess); -} - -/* - * Called via qlt_create_sess():ha->qla2x_tmpl->check_initiator_node_acl() - * to locate struct se_node_acl - */ -static int tcm_qla2xxx_check_initiator_node_acl( - scsi_qla_host_t *vha, - unsigned char *fc_wwpn, - void *qla_tgt_sess, - uint8_t *s_id, - uint16_t loop_id) -{ - struct qla_hw_data *ha = vha->hw; - struct tcm_qla2xxx_lport *lport; - struct tcm_qla2xxx_tpg *tpg; - struct tcm_qla2xxx_nacl *nacl; - struct se_portal_group *se_tpg; - struct se_node_acl *se_nacl; - struct se_session *se_sess; - struct qla_tgt_sess *sess = qla_tgt_sess; - unsigned char port_name[36]; - unsigned long flags; - - lport = ha->tgt.target_lport_ptr; - if (!lport) { - pr_err("Unable to locate struct tcm_qla2xxx_lport\n"); - dump_stack(); - return -EINVAL; - } - /* - * Locate the TPG=1 reference.. - */ - tpg = lport->tpg_1; - if (!tpg) { - pr_err("Unable to lcoate struct tcm_qla2xxx_lport->tpg_1\n"); - return -EINVAL; - } - se_tpg = &tpg->se_tpg; - - se_sess = transport_init_session(); - if (IS_ERR(se_sess)) { - pr_err("Unable to initialize struct se_session\n"); - return PTR_ERR(se_sess); - } - /* - * Format the FCP Initiator port_name into colon seperated values to - * match the format by tcm_qla2xxx explict ConfigFS NodeACLs. - */ - memset(&port_name, 0, 36); - snprintf(port_name, 36, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", - fc_wwpn[0], fc_wwpn[1], fc_wwpn[2], fc_wwpn[3], fc_wwpn[4], - fc_wwpn[5], fc_wwpn[6], fc_wwpn[7]); - /* - * Locate our struct se_node_acl either from an explict NodeACL created - * via ConfigFS, or via running in TPG demo mode. - */ - se_sess->se_node_acl = core_tpg_check_initiator_node_acl(se_tpg, - port_name); - if (!se_sess->se_node_acl) { - transport_free_session(se_sess); - return -EINVAL; - } - se_nacl = se_sess->se_node_acl; - nacl = container_of(se_nacl, struct tcm_qla2xxx_nacl, se_node_acl); - /* - * And now setup the new se_nacl and session pointers into our HW lport - * mappings for fabric S_ID and LOOP_ID. - */ - spin_lock_irqsave(&ha->hardware_lock, flags); - tcm_qla2xxx_set_sess_by_s_id(lport, se_nacl, nacl, se_sess, - qla_tgt_sess, s_id); - tcm_qla2xxx_set_sess_by_loop_id(lport, se_nacl, nacl, se_sess, - qla_tgt_sess, loop_id); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - /* - * Finally register the new FC Nexus with TCM - */ - __transport_register_session(se_nacl->se_tpg, se_nacl, se_sess, sess); - - return 0; -} - -/* - * Calls into tcm_qla2xxx used by qla2xxx LLD I/O path. - */ -static struct qla_tgt_func_tmpl tcm_qla2xxx_template = { - .handle_cmd = tcm_qla2xxx_handle_cmd, - .handle_data = tcm_qla2xxx_handle_data, - .handle_tmr = tcm_qla2xxx_handle_tmr, - .free_cmd = tcm_qla2xxx_free_cmd, - .free_mcmd = tcm_qla2xxx_free_mcmd, - .free_session = tcm_qla2xxx_free_session, - .check_initiator_node_acl = tcm_qla2xxx_check_initiator_node_acl, - .find_sess_by_s_id = tcm_qla2xxx_find_sess_by_s_id, - .find_sess_by_loop_id = tcm_qla2xxx_find_sess_by_loop_id, - .clear_nacl_from_fcport_map = tcm_qla2xxx_clear_nacl_from_fcport_map, - .put_sess = tcm_qla2xxx_put_sess, - .shutdown_sess = tcm_qla2xxx_shutdown_sess, -}; - -static int tcm_qla2xxx_init_lport(struct tcm_qla2xxx_lport *lport) -{ - int rc; - - rc = btree_init32(&lport->lport_fcport_map); - if (rc) { - pr_err("Unable to initialize lport->lport_fcport_map btree\n"); - return rc; - } - - lport->lport_loopid_map = vmalloc(sizeof(struct tcm_qla2xxx_fc_loopid) * - 65536); - if (!lport->lport_loopid_map) { - pr_err("Unable to allocate lport->lport_loopid_map of %zu bytes\n", - sizeof(struct tcm_qla2xxx_fc_loopid) * 65536); - btree_destroy32(&lport->lport_fcport_map); - return -ENOMEM; - } - memset(lport->lport_loopid_map, 0, sizeof(struct tcm_qla2xxx_fc_loopid) - * 65536); - pr_debug("qla2xxx: Allocated lport_loopid_map of %zu bytes\n", - sizeof(struct tcm_qla2xxx_fc_loopid) * 65536); - return 0; -} - -static int tcm_qla2xxx_lport_register_cb(struct scsi_qla_host *vha) -{ - struct qla_hw_data *ha = vha->hw; - struct tcm_qla2xxx_lport *lport; - /* - * Setup local pointer to vha, NPIV VP pointer (if present) and - * vha->tcm_lport pointer - */ - lport = (struct tcm_qla2xxx_lport *)ha->tgt.target_lport_ptr; - lport->qla_vha = vha; - - return 0; -} - -static struct se_wwn *tcm_qla2xxx_make_lport( - struct target_fabric_configfs *tf, - struct config_group *group, - const char *name) -{ - struct tcm_qla2xxx_lport *lport; - u64 wwpn; - int ret = -ENODEV; - - if (tcm_qla2xxx_parse_wwn(name, &wwpn, 1) < 0) - return ERR_PTR(-EINVAL); - - lport = kzalloc(sizeof(struct tcm_qla2xxx_lport), GFP_KERNEL); - if (!lport) { - pr_err("Unable to allocate struct tcm_qla2xxx_lport\n"); - return ERR_PTR(-ENOMEM); - } - lport->lport_wwpn = wwpn; - tcm_qla2xxx_format_wwn(&lport->lport_name[0], TCM_QLA2XXX_NAMELEN, - wwpn); - - ret = tcm_qla2xxx_init_lport(lport); - if (ret != 0) - goto out; - - ret = qlt_lport_register(&tcm_qla2xxx_template, wwpn, - tcm_qla2xxx_lport_register_cb, lport); - if (ret != 0) - goto out_lport; - - return &lport->lport_wwn; -out_lport: - vfree(lport->lport_loopid_map); - btree_destroy32(&lport->lport_fcport_map); -out: - kfree(lport); - return ERR_PTR(ret); -} - -static void tcm_qla2xxx_drop_lport(struct se_wwn *wwn) -{ - struct tcm_qla2xxx_lport *lport = container_of(wwn, - struct tcm_qla2xxx_lport, lport_wwn); - struct scsi_qla_host *vha = lport->qla_vha; - struct qla_hw_data *ha = vha->hw; - struct se_node_acl *node; - u32 key = 0; - - /* - * Call into qla2x_target.c LLD logic to complete the - * shutdown of struct qla_tgt after the call to - * qlt_stop_phase1() from tcm_qla2xxx_drop_tpg() above.. - */ - if (ha->tgt.qla_tgt && !ha->tgt.qla_tgt->tgt_stopped) - qlt_stop_phase2(ha->tgt.qla_tgt); - - qlt_lport_deregister(vha); - - vfree(lport->lport_loopid_map); - btree_for_each_safe32(&lport->lport_fcport_map, key, node) - btree_remove32(&lport->lport_fcport_map, key); - btree_destroy32(&lport->lport_fcport_map); - kfree(lport); -} - -static struct se_wwn *tcm_qla2xxx_npiv_make_lport( - struct target_fabric_configfs *tf, - struct config_group *group, - const char *name) -{ - struct tcm_qla2xxx_lport *lport; - u64 npiv_wwpn, npiv_wwnn; - int ret; - - if (tcm_qla2xxx_npiv_parse_wwn(name, strlen(name)+1, - &npiv_wwpn, &npiv_wwnn) < 0) - return ERR_PTR(-EINVAL); - - lport = kzalloc(sizeof(struct tcm_qla2xxx_lport), GFP_KERNEL); - if (!lport) { - pr_err("Unable to allocate struct tcm_qla2xxx_lport for NPIV\n"); - return ERR_PTR(-ENOMEM); - } - lport->lport_npiv_wwpn = npiv_wwpn; - lport->lport_npiv_wwnn = npiv_wwnn; - tcm_qla2xxx_npiv_format_wwn(&lport->lport_npiv_name[0], - TCM_QLA2XXX_NAMELEN, npiv_wwpn, npiv_wwnn); - -/* FIXME: tcm_qla2xxx_npiv_make_lport */ - ret = -ENOSYS; - if (ret != 0) - goto out; - - return &lport->lport_wwn; -out: - kfree(lport); - return ERR_PTR(ret); -} - -static void tcm_qla2xxx_npiv_drop_lport(struct se_wwn *wwn) -{ - struct tcm_qla2xxx_lport *lport = container_of(wwn, - struct tcm_qla2xxx_lport, lport_wwn); - struct scsi_qla_host *vha = lport->qla_vha; - struct Scsi_Host *sh = vha->host; - /* - * Notify libfc that we want to release the lport->npiv_vport - */ - fc_vport_terminate(lport->npiv_vport); - - scsi_host_put(sh); - kfree(lport); -} - - -static ssize_t tcm_qla2xxx_wwn_show_attr_version( - struct target_fabric_configfs *tf, - char *page) -{ - return sprintf(page, - "TCM QLOGIC QLA2XXX NPIV capable fabric module %s on %s/%s on " - UTS_RELEASE"\n", TCM_QLA2XXX_VERSION, utsname()->sysname, - utsname()->machine); -} - -TF_WWN_ATTR_RO(tcm_qla2xxx, version); - -static struct configfs_attribute *tcm_qla2xxx_wwn_attrs[] = { - &tcm_qla2xxx_wwn_version.attr, - NULL, -}; - -static struct target_core_fabric_ops tcm_qla2xxx_ops = { - .get_fabric_name = tcm_qla2xxx_get_fabric_name, - .get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident, - .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, - .tpg_get_tag = tcm_qla2xxx_get_tag, - .tpg_get_default_depth = tcm_qla2xxx_get_default_depth, - .tpg_get_pr_transport_id = tcm_qla2xxx_get_pr_transport_id, - .tpg_get_pr_transport_id_len = tcm_qla2xxx_get_pr_transport_id_len, - .tpg_parse_pr_out_transport_id = tcm_qla2xxx_parse_pr_out_transport_id, - .tpg_check_demo_mode = tcm_qla2xxx_check_demo_mode, - .tpg_check_demo_mode_cache = tcm_qla2xxx_check_demo_mode_cache, - .tpg_check_demo_mode_write_protect = - tcm_qla2xxx_check_demo_write_protect, - .tpg_check_prod_mode_write_protect = - tcm_qla2xxx_check_prod_write_protect, - .tpg_check_demo_mode_login_only = tcm_qla2xxx_check_true, - .tpg_alloc_fabric_acl = tcm_qla2xxx_alloc_fabric_acl, - .tpg_release_fabric_acl = tcm_qla2xxx_release_fabric_acl, - .tpg_get_inst_index = tcm_qla2xxx_tpg_get_inst_index, - .new_cmd_map = NULL, - .check_stop_free = tcm_qla2xxx_check_stop_free, - .release_cmd = tcm_qla2xxx_release_cmd, - .shutdown_session = tcm_qla2xxx_shutdown_session, - .close_session = tcm_qla2xxx_close_session, - .sess_get_index = tcm_qla2xxx_sess_get_index, - .sess_get_initiator_sid = NULL, - .write_pending = tcm_qla2xxx_write_pending, - .write_pending_status = tcm_qla2xxx_write_pending_status, - .set_default_node_attributes = tcm_qla2xxx_set_default_node_attrs, - .get_task_tag = tcm_qla2xxx_get_task_tag, - .get_cmd_state = tcm_qla2xxx_get_cmd_state, - .queue_data_in = tcm_qla2xxx_queue_data_in, - .queue_status = tcm_qla2xxx_queue_status, - .queue_tm_rsp = tcm_qla2xxx_queue_tm_rsp, - .get_fabric_sense_len = tcm_qla2xxx_get_fabric_sense_len, - .set_fabric_sense_len = tcm_qla2xxx_set_fabric_sense_len, - /* - * Setup function pointers for generic logic in - * target_core_fabric_configfs.c - */ - .fabric_make_wwn = tcm_qla2xxx_make_lport, - .fabric_drop_wwn = tcm_qla2xxx_drop_lport, - .fabric_make_tpg = tcm_qla2xxx_make_tpg, - .fabric_drop_tpg = tcm_qla2xxx_drop_tpg, - .fabric_post_link = NULL, - .fabric_pre_unlink = NULL, - .fabric_make_np = NULL, - .fabric_drop_np = NULL, - .fabric_make_nodeacl = tcm_qla2xxx_make_nodeacl, - .fabric_drop_nodeacl = tcm_qla2xxx_drop_nodeacl, -}; - -static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { - .get_fabric_name = tcm_qla2xxx_npiv_get_fabric_name, - .get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident, - .tpg_get_wwn = tcm_qla2xxx_npiv_get_fabric_wwn, - .tpg_get_tag = tcm_qla2xxx_get_tag, - .tpg_get_default_depth = tcm_qla2xxx_get_default_depth, - .tpg_get_pr_transport_id = tcm_qla2xxx_get_pr_transport_id, - .tpg_get_pr_transport_id_len = tcm_qla2xxx_get_pr_transport_id_len, - .tpg_parse_pr_out_transport_id = tcm_qla2xxx_parse_pr_out_transport_id, - .tpg_check_demo_mode = tcm_qla2xxx_check_false, - .tpg_check_demo_mode_cache = tcm_qla2xxx_check_true, - .tpg_check_demo_mode_write_protect = tcm_qla2xxx_check_true, - .tpg_check_prod_mode_write_protect = tcm_qla2xxx_check_false, - .tpg_check_demo_mode_login_only = tcm_qla2xxx_check_true, - .tpg_alloc_fabric_acl = tcm_qla2xxx_alloc_fabric_acl, - .tpg_release_fabric_acl = tcm_qla2xxx_release_fabric_acl, - .tpg_get_inst_index = tcm_qla2xxx_tpg_get_inst_index, - .release_cmd = tcm_qla2xxx_release_cmd, - .shutdown_session = tcm_qla2xxx_shutdown_session, - .close_session = tcm_qla2xxx_close_session, - .sess_get_index = tcm_qla2xxx_sess_get_index, - .sess_get_initiator_sid = NULL, - .write_pending = tcm_qla2xxx_write_pending, - .write_pending_status = tcm_qla2xxx_write_pending_status, - .set_default_node_attributes = tcm_qla2xxx_set_default_node_attrs, - .get_task_tag = tcm_qla2xxx_get_task_tag, - .get_cmd_state = tcm_qla2xxx_get_cmd_state, - .queue_data_in = tcm_qla2xxx_queue_data_in, - .queue_status = tcm_qla2xxx_queue_status, - .queue_tm_rsp = tcm_qla2xxx_queue_tm_rsp, - .get_fabric_sense_len = tcm_qla2xxx_get_fabric_sense_len, - .set_fabric_sense_len = tcm_qla2xxx_set_fabric_sense_len, - /* - * Setup function pointers for generic logic in - * target_core_fabric_configfs.c - */ - .fabric_make_wwn = tcm_qla2xxx_npiv_make_lport, - .fabric_drop_wwn = tcm_qla2xxx_npiv_drop_lport, - .fabric_make_tpg = tcm_qla2xxx_npiv_make_tpg, - .fabric_drop_tpg = tcm_qla2xxx_drop_tpg, - .fabric_post_link = NULL, - .fabric_pre_unlink = NULL, - .fabric_make_np = NULL, - .fabric_drop_np = NULL, - .fabric_make_nodeacl = tcm_qla2xxx_make_nodeacl, - .fabric_drop_nodeacl = tcm_qla2xxx_drop_nodeacl, -}; - -static int tcm_qla2xxx_register_configfs(void) -{ - struct target_fabric_configfs *fabric, *npiv_fabric; - int ret; - - pr_debug("TCM QLOGIC QLA2XXX fabric module %s on %s/%s on " - UTS_RELEASE"\n", TCM_QLA2XXX_VERSION, utsname()->sysname, - utsname()->machine); - /* - * Register the top level struct config_item_type with TCM core - */ - fabric = target_fabric_configfs_init(THIS_MODULE, "qla2xxx"); - if (IS_ERR(fabric)) { - pr_err("target_fabric_configfs_init() failed\n"); - return PTR_ERR(fabric); - } - /* - * Setup fabric->tf_ops from our local tcm_qla2xxx_ops - */ - fabric->tf_ops = tcm_qla2xxx_ops; - /* - * Setup default attribute lists for various fabric->tf_cit_tmpl - */ - TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = tcm_qla2xxx_wwn_attrs; - TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = tcm_qla2xxx_tpg_attrs; - TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = - tcm_qla2xxx_tpg_attrib_attrs; - TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL; - TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL; - TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL; - TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; - TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL; - TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL; - /* - * Register the fabric for use within TCM - */ - ret = target_fabric_configfs_register(fabric); - if (ret < 0) { - pr_err("target_fabric_configfs_register() failed for TCM_QLA2XXX\n"); - return ret; - } - /* - * Setup our local pointer to *fabric - */ - tcm_qla2xxx_fabric_configfs = fabric; - pr_debug("TCM_QLA2XXX[0] - Set fabric -> tcm_qla2xxx_fabric_configfs\n"); - - /* - * Register the top level struct config_item_type for NPIV with TCM core - */ - npiv_fabric = target_fabric_configfs_init(THIS_MODULE, "qla2xxx_npiv"); - if (IS_ERR(npiv_fabric)) { - pr_err("target_fabric_configfs_init() failed\n"); - ret = PTR_ERR(npiv_fabric); - goto out_fabric; - } - /* - * Setup fabric->tf_ops from our local tcm_qla2xxx_npiv_ops - */ - npiv_fabric->tf_ops = tcm_qla2xxx_npiv_ops; - /* - * Setup default attribute lists for various npiv_fabric->tf_cit_tmpl - */ - TF_CIT_TMPL(npiv_fabric)->tfc_wwn_cit.ct_attrs = tcm_qla2xxx_wwn_attrs; - TF_CIT_TMPL(npiv_fabric)->tfc_tpg_base_cit.ct_attrs = NULL; - TF_CIT_TMPL(npiv_fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL; - TF_CIT_TMPL(npiv_fabric)->tfc_tpg_param_cit.ct_attrs = NULL; - TF_CIT_TMPL(npiv_fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL; - TF_CIT_TMPL(npiv_fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL; - TF_CIT_TMPL(npiv_fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; - TF_CIT_TMPL(npiv_fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL; - TF_CIT_TMPL(npiv_fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL; - /* - * Register the npiv_fabric for use within TCM - */ - ret = target_fabric_configfs_register(npiv_fabric); - if (ret < 0) { - pr_err("target_fabric_configfs_register() failed for TCM_QLA2XXX\n"); - goto out_fabric; - } - /* - * Setup our local pointer to *npiv_fabric - */ - tcm_qla2xxx_npiv_fabric_configfs = npiv_fabric; - pr_debug("TCM_QLA2XXX[0] - Set fabric -> tcm_qla2xxx_npiv_fabric_configfs\n"); - - tcm_qla2xxx_free_wq = alloc_workqueue("tcm_qla2xxx_free", - WQ_MEM_RECLAIM, 0); - if (!tcm_qla2xxx_free_wq) { - ret = -ENOMEM; - goto out_fabric_npiv; - } - - tcm_qla2xxx_cmd_wq = alloc_workqueue("tcm_qla2xxx_cmd", 0, 0); - if (!tcm_qla2xxx_cmd_wq) { - ret = -ENOMEM; - goto out_free_wq; - } - - return 0; - -out_free_wq: - destroy_workqueue(tcm_qla2xxx_free_wq); -out_fabric_npiv: - target_fabric_configfs_deregister(tcm_qla2xxx_npiv_fabric_configfs); -out_fabric: - target_fabric_configfs_deregister(tcm_qla2xxx_fabric_configfs); - return ret; -} - -static void tcm_qla2xxx_deregister_configfs(void) -{ - destroy_workqueue(tcm_qla2xxx_cmd_wq); - destroy_workqueue(tcm_qla2xxx_free_wq); - - target_fabric_configfs_deregister(tcm_qla2xxx_fabric_configfs); - tcm_qla2xxx_fabric_configfs = NULL; - pr_debug("TCM_QLA2XXX[0] - Cleared tcm_qla2xxx_fabric_configfs\n"); - - target_fabric_configfs_deregister(tcm_qla2xxx_npiv_fabric_configfs); - tcm_qla2xxx_npiv_fabric_configfs = NULL; - pr_debug("TCM_QLA2XXX[0] - Cleared tcm_qla2xxx_npiv_fabric_configfs\n"); -} - -static int __init tcm_qla2xxx_init(void) -{ - int ret; - - ret = tcm_qla2xxx_register_configfs(); - if (ret < 0) - return ret; - - return 0; -} - -static void __exit tcm_qla2xxx_exit(void) -{ - tcm_qla2xxx_deregister_configfs(); -} - -MODULE_DESCRIPTION("TCM QLA2XXX series NPIV enabled fabric driver"); -MODULE_LICENSE("GPL"); -module_init(tcm_qla2xxx_init); -module_exit(tcm_qla2xxx_exit); diff --git a/trunk/drivers/scsi/qla2xxx/tcm_qla2xxx.h b/trunk/drivers/scsi/qla2xxx/tcm_qla2xxx.h deleted file mode 100644 index 825498103352..000000000000 --- a/trunk/drivers/scsi/qla2xxx/tcm_qla2xxx.h +++ /dev/null @@ -1,82 +0,0 @@ -#include -#include - -#define TCM_QLA2XXX_VERSION "v0.1" -/* length of ASCII WWPNs including pad */ -#define TCM_QLA2XXX_NAMELEN 32 -/* lenth of ASCII NPIV 'WWPN+WWNN' including pad */ -#define TCM_QLA2XXX_NPIV_NAMELEN 66 - -#include "qla_target.h" - -struct tcm_qla2xxx_nacl { - /* From libfc struct fc_rport->port_id */ - u32 nport_id; - /* Binary World Wide unique Node Name for remote FC Initiator Nport */ - u64 nport_wwnn; - /* ASCII formatted WWPN for FC Initiator Nport */ - char nport_name[TCM_QLA2XXX_NAMELEN]; - /* Pointer to qla_tgt_sess */ - struct qla_tgt_sess *qla_tgt_sess; - /* Pointer to TCM FC nexus */ - struct se_session *nport_nexus; - /* Returned by tcm_qla2xxx_make_nodeacl() */ - struct se_node_acl se_node_acl; -}; - -struct tcm_qla2xxx_tpg_attrib { - int generate_node_acls; - int cache_dynamic_acls; - int demo_mode_write_protect; - int prod_mode_write_protect; -}; - -struct tcm_qla2xxx_tpg { - /* FC lport target portal group tag for TCM */ - u16 lport_tpgt; - /* Atomic bit to determine TPG active status */ - atomic_t lport_tpg_enabled; - /* Pointer back to tcm_qla2xxx_lport */ - struct tcm_qla2xxx_lport *lport; - /* Used by tcm_qla2xxx_tpg_attrib_cit */ - struct tcm_qla2xxx_tpg_attrib tpg_attrib; - /* Returned by tcm_qla2xxx_make_tpg() */ - struct se_portal_group se_tpg; -}; - -#define QLA_TPG_ATTRIB(tpg) (&(tpg)->tpg_attrib) - -struct tcm_qla2xxx_fc_loopid { - struct se_node_acl *se_nacl; -}; - -struct tcm_qla2xxx_lport { - /* SCSI protocol the lport is providing */ - u8 lport_proto_id; - /* Binary World Wide unique Port Name for FC Target Lport */ - u64 lport_wwpn; - /* Binary World Wide unique Port Name for FC NPIV Target Lport */ - u64 lport_npiv_wwpn; - /* Binary World Wide unique Node Name for FC NPIV Target Lport */ - u64 lport_npiv_wwnn; - /* ASCII formatted WWPN for FC Target Lport */ - char lport_name[TCM_QLA2XXX_NAMELEN]; - /* ASCII formatted WWPN+WWNN for NPIV FC Target Lport */ - char lport_npiv_name[TCM_QLA2XXX_NPIV_NAMELEN]; - /* map for fc_port pointers in 24-bit FC Port ID space */ - struct btree_head32 lport_fcport_map; - /* vmalloc-ed memory for fc_port pointers for 16-bit FC loop ID */ - struct tcm_qla2xxx_fc_loopid *lport_loopid_map; - /* Pointer to struct scsi_qla_host from qla2xxx LLD */ - struct scsi_qla_host *qla_vha; - /* Pointer to struct scsi_qla_host for NPIV VP from qla2xxx LLD */ - struct scsi_qla_host *qla_npiv_vp; - /* Pointer to struct qla_tgt pointer */ - struct qla_tgt lport_qla_tgt; - /* Pointer to struct fc_vport for NPIV vport from libfc */ - struct fc_vport *npiv_vport; - /* Pointer to TPG=1 for non NPIV mode */ - struct tcm_qla2xxx_tpg *tpg_1; - /* Returned by tcm_qla2xxx_make_lport() */ - struct se_wwn lport_wwn; -}; diff --git a/trunk/drivers/scsi/qla4xxx/ql4_attr.c b/trunk/drivers/scsi/qla4xxx/ql4_attr.c index c681b2a355e1..0b0a7d42137d 100644 --- a/trunk/drivers/scsi/qla4xxx/ql4_attr.c +++ b/trunk/drivers/scsi/qla4xxx/ql4_attr.c @@ -9,140 +9,6 @@ #include "ql4_glbl.h" #include "ql4_dbg.h" -static ssize_t -qla4_8xxx_sysfs_read_fw_dump(struct file *filep, struct kobject *kobj, - struct bin_attribute *ba, char *buf, loff_t off, - size_t count) -{ - struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, - struct device, kobj))); - - if (!is_qla8022(ha)) - return -EINVAL; - - if (!test_bit(AF_82XX_DUMP_READING, &ha->flags)) - return 0; - - return memory_read_from_buffer(buf, count, &off, ha->fw_dump, - ha->fw_dump_size); -} - -static ssize_t -qla4_8xxx_sysfs_write_fw_dump(struct file *filep, struct kobject *kobj, - struct bin_attribute *ba, char *buf, loff_t off, - size_t count) -{ - struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, - struct device, kobj))); - uint32_t dev_state; - long reading; - int ret = 0; - - if (!is_qla8022(ha)) - return -EINVAL; - - if (off != 0) - return ret; - - buf[1] = 0; - ret = kstrtol(buf, 10, &reading); - if (ret) { - ql4_printk(KERN_ERR, ha, "%s: Invalid input. Return err %d\n", - __func__, ret); - return ret; - } - - switch (reading) { - case 0: - /* clear dump collection flags */ - if (test_and_clear_bit(AF_82XX_DUMP_READING, &ha->flags)) { - clear_bit(AF_82XX_FW_DUMPED, &ha->flags); - /* Reload minidump template */ - qla4xxx_alloc_fw_dump(ha); - DEBUG2(ql4_printk(KERN_INFO, ha, - "Firmware template reloaded\n")); - } - break; - case 1: - /* Set flag to read dump */ - if (test_bit(AF_82XX_FW_DUMPED, &ha->flags) && - !test_bit(AF_82XX_DUMP_READING, &ha->flags)) { - set_bit(AF_82XX_DUMP_READING, &ha->flags); - DEBUG2(ql4_printk(KERN_INFO, ha, - "Raw firmware dump ready for read on (%ld).\n", - ha->host_no)); - } - break; - case 2: - /* Reset HBA */ - qla4_8xxx_idc_lock(ha); - dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - if (dev_state == QLA82XX_DEV_READY) { - ql4_printk(KERN_INFO, ha, - "%s: Setting Need reset, reset_owner is 0x%x.\n", - __func__, ha->func_num); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA82XX_DEV_NEED_RESET); - set_bit(AF_82XX_RST_OWNER, &ha->flags); - } else - ql4_printk(KERN_INFO, ha, - "%s: Reset not performed as device state is 0x%x\n", - __func__, dev_state); - - qla4_8xxx_idc_unlock(ha); - break; - default: - /* do nothing */ - break; - } - - return count; -} - -static struct bin_attribute sysfs_fw_dump_attr = { - .attr = { - .name = "fw_dump", - .mode = S_IRUSR | S_IWUSR, - }, - .size = 0, - .read = qla4_8xxx_sysfs_read_fw_dump, - .write = qla4_8xxx_sysfs_write_fw_dump, -}; - -static struct sysfs_entry { - char *name; - struct bin_attribute *attr; -} bin_file_entries[] = { - { "fw_dump", &sysfs_fw_dump_attr }, - { NULL }, -}; - -void qla4_8xxx_alloc_sysfs_attr(struct scsi_qla_host *ha) -{ - struct Scsi_Host *host = ha->host; - struct sysfs_entry *iter; - int ret; - - for (iter = bin_file_entries; iter->name; iter++) { - ret = sysfs_create_bin_file(&host->shost_gendev.kobj, - iter->attr); - if (ret) - ql4_printk(KERN_ERR, ha, - "Unable to create sysfs %s binary attribute (%d).\n", - iter->name, ret); - } -} - -void qla4_8xxx_free_sysfs_attr(struct scsi_qla_host *ha) -{ - struct Scsi_Host *host = ha->host; - struct sysfs_entry *iter; - - for (iter = bin_file_entries; iter->name; iter++) - sysfs_remove_bin_file(&host->shost_gendev.kobj, - iter->attr); -} - /* Scsi_Host attributes. */ static ssize_t qla4xxx_fw_version_show(struct device *dev, diff --git a/trunk/drivers/scsi/qla4xxx/ql4_def.h b/trunk/drivers/scsi/qla4xxx/ql4_def.h index 96a5616a8fda..7f2492e88be7 100644 --- a/trunk/drivers/scsi/qla4xxx/ql4_def.h +++ b/trunk/drivers/scsi/qla4xxx/ql4_def.h @@ -398,16 +398,6 @@ struct isp_operations { int (*get_sys_info) (struct scsi_qla_host *); }; -struct ql4_mdump_size_table { - uint32_t size; - uint32_t size_cmask_02; - uint32_t size_cmask_04; - uint32_t size_cmask_08; - uint32_t size_cmask_10; - uint32_t size_cmask_FF; - uint32_t version; -}; - /*qla4xxx ipaddress configuration details */ struct ipaddress_config { uint16_t ipv4_options; @@ -495,10 +485,6 @@ struct scsi_qla_host { #define AF_EEH_BUSY 20 /* 0x00100000 */ #define AF_PCI_CHANNEL_IO_PERM_FAILURE 21 /* 0x00200000 */ #define AF_BUILD_DDB_LIST 22 /* 0x00400000 */ -#define AF_82XX_FW_DUMPED 24 /* 0x01000000 */ -#define AF_82XX_RST_OWNER 25 /* 0x02000000 */ -#define AF_82XX_DUMP_READING 26 /* 0x04000000 */ - unsigned long dpc_flags; #define DPC_RESET_HA 1 /* 0x00000002 */ @@ -676,11 +662,6 @@ struct scsi_qla_host { uint32_t nx_dev_init_timeout; uint32_t nx_reset_timeout; - void *fw_dump; - uint32_t fw_dump_size; - uint32_t fw_dump_capture_mask; - void *fw_dump_tmplt_hdr; - uint32_t fw_dump_tmplt_size; struct completion mbx_intr_comp; @@ -955,7 +936,4 @@ static inline int ql4xxx_reset_active(struct scsi_qla_host *ha) #define PROCESS_ALL_AENS 0 #define FLUSH_DDB_CHANGED_AENS 1 -/* Defines for udev events */ -#define QL4_UEVENT_CODE_FW_DUMP 0 - #endif /*_QLA4XXX_H */ diff --git a/trunk/drivers/scsi/qla4xxx/ql4_fw.h b/trunk/drivers/scsi/qla4xxx/ql4_fw.h index 7240948fb929..210cd1d64475 100644 --- a/trunk/drivers/scsi/qla4xxx/ql4_fw.h +++ b/trunk/drivers/scsi/qla4xxx/ql4_fw.h @@ -385,11 +385,6 @@ struct qla_flt_region { #define MBOX_CMD_GET_IP_ADDR_STATE 0x0091 #define MBOX_CMD_SEND_IPV6_ROUTER_SOL 0x0092 #define MBOX_CMD_GET_DB_ENTRY_CURRENT_IP_ADDR 0x0093 -#define MBOX_CMD_MINIDUMP 0x0129 - -/* Minidump subcommand */ -#define MINIDUMP_GET_SIZE_SUBCOMMAND 0x00 -#define MINIDUMP_GET_TMPLT_SUBCOMMAND 0x01 /* Mailbox 1 */ #define FW_STATE_READY 0x0000 @@ -1195,27 +1190,4 @@ struct ql_iscsi_stats { uint8_t reserved2[264]; /* 0x0308 - 0x040F */ }; -#define QLA82XX_DBG_STATE_ARRAY_LEN 16 -#define QLA82XX_DBG_CAP_SIZE_ARRAY_LEN 8 -#define QLA82XX_DBG_RSVD_ARRAY_LEN 8 - -struct qla4_8xxx_minidump_template_hdr { - uint32_t entry_type; - uint32_t first_entry_offset; - uint32_t size_of_template; - uint32_t capture_debug_level; - uint32_t num_of_entries; - uint32_t version; - uint32_t driver_timestamp; - uint32_t checksum; - - uint32_t driver_capture_mask; - uint32_t driver_info_word2; - uint32_t driver_info_word3; - uint32_t driver_info_word4; - - uint32_t saved_state_array[QLA82XX_DBG_STATE_ARRAY_LEN]; - uint32_t capture_size_array[QLA82XX_DBG_CAP_SIZE_ARRAY_LEN]; -}; - #endif /* _QLA4X_FW_H */ diff --git a/trunk/drivers/scsi/qla4xxx/ql4_glbl.h b/trunk/drivers/scsi/qla4xxx/ql4_glbl.h index 20b49d019043..910536667cf5 100644 --- a/trunk/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/trunk/drivers/scsi/qla4xxx/ql4_glbl.h @@ -196,18 +196,10 @@ int qla4xxx_bsg_request(struct bsg_job *bsg_job); int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job); void qla4xxx_arm_relogin_timer(struct ddb_entry *ddb_entry); -int qla4xxx_get_minidump_template(struct scsi_qla_host *ha, - dma_addr_t phys_addr); -int qla4xxx_req_template_size(struct scsi_qla_host *ha); -void qla4_8xxx_alloc_sysfs_attr(struct scsi_qla_host *ha); -void qla4_8xxx_free_sysfs_attr(struct scsi_qla_host *ha); -void qla4xxx_alloc_fw_dump(struct scsi_qla_host *ha); extern int ql4xextended_error_logging; extern int ql4xdontresethba; extern int ql4xenablemsix; -extern int ql4xmdcapmask; -extern int ql4xenablemd; extern struct device_attribute *qla4xxx_host_attrs[]; #endif /* _QLA4x_GBL_H */ diff --git a/trunk/drivers/scsi/qla4xxx/ql4_init.c b/trunk/drivers/scsi/qla4xxx/ql4_init.c index bf36723b84e1..90ee5d8fa731 100644 --- a/trunk/drivers/scsi/qla4xxx/ql4_init.c +++ b/trunk/drivers/scsi/qla4xxx/ql4_init.c @@ -277,94 +277,6 @@ qla4xxx_wait_for_ip_config(struct scsi_qla_host *ha) return ipv4_wait|ipv6_wait; } -/** - * qla4xxx_alloc_fw_dump - Allocate memory for minidump data. - * @ha: pointer to host adapter structure. - **/ -void qla4xxx_alloc_fw_dump(struct scsi_qla_host *ha) -{ - int status; - uint32_t capture_debug_level; - int hdr_entry_bit, k; - void *md_tmp; - dma_addr_t md_tmp_dma; - struct qla4_8xxx_minidump_template_hdr *md_hdr; - - if (ha->fw_dump) { - ql4_printk(KERN_WARNING, ha, - "Firmware dump previously allocated.\n"); - return; - } - - status = qla4xxx_req_template_size(ha); - if (status != QLA_SUCCESS) { - ql4_printk(KERN_INFO, ha, - "scsi%ld: Failed to get template size\n", - ha->host_no); - return; - } - - clear_bit(AF_82XX_FW_DUMPED, &ha->flags); - - /* Allocate memory for saving the template */ - md_tmp = dma_alloc_coherent(&ha->pdev->dev, ha->fw_dump_tmplt_size, - &md_tmp_dma, GFP_KERNEL); - - /* Request template */ - status = qla4xxx_get_minidump_template(ha, md_tmp_dma); - if (status != QLA_SUCCESS) { - ql4_printk(KERN_INFO, ha, - "scsi%ld: Failed to get minidump template\n", - ha->host_no); - goto alloc_cleanup; - } - - md_hdr = (struct qla4_8xxx_minidump_template_hdr *)md_tmp; - - capture_debug_level = md_hdr->capture_debug_level; - - /* Get capture mask based on module loadtime setting. */ - if (ql4xmdcapmask >= 0x3 && ql4xmdcapmask <= 0x7F) - ha->fw_dump_capture_mask = ql4xmdcapmask; - else - ha->fw_dump_capture_mask = capture_debug_level; - - md_hdr->driver_capture_mask = ha->fw_dump_capture_mask; - - DEBUG2(ql4_printk(KERN_INFO, ha, "Minimum num of entries = %d\n", - md_hdr->num_of_entries)); - DEBUG2(ql4_printk(KERN_INFO, ha, "Dump template size = %d\n", - ha->fw_dump_tmplt_size)); - DEBUG2(ql4_printk(KERN_INFO, ha, "Selected Capture mask =0x%x\n", - ha->fw_dump_capture_mask)); - - /* Calculate fw_dump_size */ - for (hdr_entry_bit = 0x2, k = 1; (hdr_entry_bit & 0xFF); - hdr_entry_bit <<= 1, k++) { - if (hdr_entry_bit & ha->fw_dump_capture_mask) - ha->fw_dump_size += md_hdr->capture_size_array[k]; - } - - /* Total firmware dump size including command header */ - ha->fw_dump_size += ha->fw_dump_tmplt_size; - ha->fw_dump = vmalloc(ha->fw_dump_size); - if (!ha->fw_dump) - goto alloc_cleanup; - - DEBUG2(ql4_printk(KERN_INFO, ha, - "Minidump Tempalate Size = 0x%x KB\n", - ha->fw_dump_tmplt_size)); - DEBUG2(ql4_printk(KERN_INFO, ha, - "Total Minidump size = 0x%x KB\n", ha->fw_dump_size)); - - memcpy(ha->fw_dump, md_tmp, ha->fw_dump_tmplt_size); - ha->fw_dump_tmplt_hdr = ha->fw_dump; - -alloc_cleanup: - dma_free_coherent(&ha->pdev->dev, ha->fw_dump_tmplt_size, - md_tmp, md_tmp_dma); -} - static int qla4xxx_fw_ready(struct scsi_qla_host *ha) { uint32_t timeout_count; @@ -533,13 +445,9 @@ static int qla4xxx_init_firmware(struct scsi_qla_host *ha) "control block\n", ha->host_no, __func__)); return status; } - if (!qla4xxx_fw_ready(ha)) return status; - if (is_qla8022(ha) && !test_bit(AF_INIT_DONE, &ha->flags)) - qla4xxx_alloc_fw_dump(ha); - return qla4xxx_get_firmware_status(ha); } @@ -976,8 +884,8 @@ int qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, switch (state) { case DDB_DS_SESSION_ACTIVE: case DDB_DS_DISCOVERY: - qla4xxx_update_session_conn_param(ha, ddb_entry); ddb_entry->unblock_sess(ddb_entry->sess); + qla4xxx_update_session_conn_param(ha, ddb_entry); status = QLA_SUCCESS; break; case DDB_DS_SESSION_FAILED: @@ -989,7 +897,6 @@ int qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, } break; case DDB_DS_SESSION_ACTIVE: - case DDB_DS_DISCOVERY: switch (state) { case DDB_DS_SESSION_FAILED: /* diff --git a/trunk/drivers/scsi/qla4xxx/ql4_mbx.c b/trunk/drivers/scsi/qla4xxx/ql4_mbx.c index cab8f665a41f..7ac21dabbf22 100644 --- a/trunk/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/trunk/drivers/scsi/qla4xxx/ql4_mbx.c @@ -51,6 +51,25 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, } } + if (is_qla8022(ha)) { + if (test_bit(AF_FW_RECOVERY, &ha->flags)) { + DEBUG2(ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: " + "prematurely completing mbx cmd as firmware " + "recovery detected\n", ha->host_no, __func__)); + return status; + } + /* Do not send any mbx cmd if h/w is in failed state*/ + qla4_8xxx_idc_lock(ha); + dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); + qla4_8xxx_idc_unlock(ha); + if (dev_state == QLA82XX_DEV_FAILED) { + ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: H/W is in " + "failed state, do not send any mailbox commands\n", + ha->host_no, __func__); + return status; + } + } + if ((is_aer_supported(ha)) && (test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags))) { DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Perm failure on EEH, " @@ -77,25 +96,6 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, msleep(10); } - if (is_qla8022(ha)) { - if (test_bit(AF_FW_RECOVERY, &ha->flags)) { - DEBUG2(ql4_printk(KERN_WARNING, ha, - "scsi%ld: %s: prematurely completing mbx cmd as firmware recovery detected\n", - ha->host_no, __func__)); - goto mbox_exit; - } - /* Do not send any mbx cmd if h/w is in failed state*/ - qla4_8xxx_idc_lock(ha); - dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - qla4_8xxx_idc_unlock(ha); - if (dev_state == QLA82XX_DEV_FAILED) { - ql4_printk(KERN_WARNING, ha, - "scsi%ld: %s: H/W is in failed state, do not send any mailbox commands\n", - ha->host_no, __func__); - goto mbox_exit; - } - } - spin_lock_irqsave(&ha->hardware_lock, flags); ha->mbox_status_count = outCount; @@ -270,79 +270,6 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, return status; } -/** - * qla4xxx_get_minidump_template - Get the firmware template - * @ha: Pointer to host adapter structure. - * @phys_addr: dma address for template - * - * Obtain the minidump template from firmware during initialization - * as it may not be available when minidump is desired. - **/ -int qla4xxx_get_minidump_template(struct scsi_qla_host *ha, - dma_addr_t phys_addr) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - int status; - - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_MINIDUMP; - mbox_cmd[1] = MINIDUMP_GET_TMPLT_SUBCOMMAND; - mbox_cmd[2] = LSDW(phys_addr); - mbox_cmd[3] = MSDW(phys_addr); - mbox_cmd[4] = ha->fw_dump_tmplt_size; - mbox_cmd[5] = 0; - - status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, &mbox_cmd[0], - &mbox_sts[0]); - if (status != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "scsi%ld: %s: Cmd = %08X, mbx[0] = 0x%04x, mbx[1] = 0x%04x\n", - ha->host_no, __func__, mbox_cmd[0], - mbox_sts[0], mbox_sts[1])); - } - return status; -} - -/** - * qla4xxx_req_template_size - Get minidump template size from firmware. - * @ha: Pointer to host adapter structure. - **/ -int qla4xxx_req_template_size(struct scsi_qla_host *ha) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - int status; - - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_MINIDUMP; - mbox_cmd[1] = MINIDUMP_GET_SIZE_SUBCOMMAND; - - status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 8, &mbox_cmd[0], - &mbox_sts[0]); - if (status == QLA_SUCCESS) { - ha->fw_dump_tmplt_size = mbox_sts[1]; - DEBUG2(ql4_printk(KERN_INFO, ha, - "%s: sts[0]=0x%04x, template size=0x%04x, size_cm_02=0x%04x, size_cm_04=0x%04x, size_cm_08=0x%04x, size_cm_10=0x%04x, size_cm_FF=0x%04x, version=0x%04x\n", - __func__, mbox_sts[0], mbox_sts[1], - mbox_sts[2], mbox_sts[3], mbox_sts[4], - mbox_sts[5], mbox_sts[6], mbox_sts[7])); - if (ha->fw_dump_tmplt_size == 0) - status = QLA_ERROR; - } else { - ql4_printk(KERN_WARNING, ha, - "%s: Error sts[0]=0x%04x, mbx[1]=0x%04x\n", - __func__, mbox_sts[0], mbox_sts[1]); - status = QLA_ERROR; - } - - return status; -} - void qla4xxx_mailbox_premature_completion(struct scsi_qla_host *ha) { set_bit(AF_FW_RECOVERY, &ha->flags); diff --git a/trunk/drivers/scsi/qla4xxx/ql4_nx.c b/trunk/drivers/scsi/qla4xxx/ql4_nx.c index 228b67020d2c..e1e46b6dac75 100644 --- a/trunk/drivers/scsi/qla4xxx/ql4_nx.c +++ b/trunk/drivers/scsi/qla4xxx/ql4_nx.c @@ -7,7 +7,6 @@ #include #include #include -#include #include "ql4_def.h" #include "ql4_glbl.h" @@ -421,38 +420,6 @@ qla4_8xxx_rd_32(struct scsi_qla_host *ha, ulong off) return data; } -/* Minidump related functions */ -static int qla4_8xxx_md_rw_32(struct scsi_qla_host *ha, uint32_t off, - u32 data, uint8_t flag) -{ - uint32_t win_read, off_value, rval = QLA_SUCCESS; - - off_value = off & 0xFFFF0000; - writel(off_value, (void __iomem *)(CRB_WINDOW_2M + ha->nx_pcibase)); - - /* Read back value to make sure write has gone through before trying - * to use it. - */ - win_read = readl((void __iomem *)(CRB_WINDOW_2M + ha->nx_pcibase)); - if (win_read != off_value) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "%s: Written (0x%x) != Read (0x%x), off=0x%x\n", - __func__, off_value, win_read, off)); - return QLA_ERROR; - } - - off_value = off & 0x0000FFFF; - - if (flag) - writel(data, (void __iomem *)(off_value + CRB_INDIRECT_2M + - ha->nx_pcibase)); - else - rval = readl((void __iomem *)(off_value + CRB_INDIRECT_2M + - ha->nx_pcibase)); - - return rval; -} - #define CRB_WIN_LOCK_TIMEOUT 100000000 int qla4_8xxx_crb_win_lock(struct scsi_qla_host *ha) @@ -1285,9 +1252,9 @@ qla4_8xxx_pci_mem_read_2M(struct scsi_qla_host *ha, } if (j >= MAX_CTL_CHECK) { - printk_ratelimited(KERN_ERR - "%s: failed to read through agent\n", - __func__); + if (printk_ratelimit()) + ql4_printk(KERN_ERR, ha, + "failed to read through agent\n"); break; } @@ -1423,8 +1390,7 @@ qla4_8xxx_pci_mem_write_2M(struct scsi_qla_host *ha, if (j >= MAX_CTL_CHECK) { if (printk_ratelimit()) ql4_printk(KERN_ERR, ha, - "%s: failed to read through agent\n", - __func__); + "failed to write through agent\n"); ret = -1; break; } @@ -1496,8 +1462,6 @@ qla4_8xxx_set_drv_active(struct scsi_qla_host *ha) drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); drv_active |= (1 << (ha->func_num * 4)); - ql4_printk(KERN_INFO, ha, "%s(%ld): drv_active: 0x%08x\n", - __func__, ha->host_no, drv_active); qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active); } @@ -1508,8 +1472,6 @@ qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha) drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); drv_active &= ~(1 << (ha->func_num * 4)); - ql4_printk(KERN_INFO, ha, "%s(%ld): drv_active: 0x%08x\n", - __func__, ha->host_no, drv_active); qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active); } @@ -1535,8 +1497,6 @@ qla4_8xxx_set_rst_ready(struct scsi_qla_host *ha) drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE); drv_state |= (1 << (ha->func_num * 4)); - ql4_printk(KERN_INFO, ha, "%s(%ld): drv_state: 0x%08x\n", - __func__, ha->host_no, drv_state); qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state); } @@ -1547,8 +1507,6 @@ qla4_8xxx_clear_rst_ready(struct scsi_qla_host *ha) drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE); drv_state &= ~(1 << (ha->func_num * 4)); - ql4_printk(KERN_INFO, ha, "%s(%ld): drv_state: 0x%08x\n", - __func__, ha->host_no, drv_state); qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state); } @@ -1643,629 +1601,6 @@ static void qla4_8xxx_rom_lock_recovery(struct scsi_qla_host *ha) qla4_8xxx_rom_unlock(ha); } -static void qla4_8xxx_minidump_process_rdcrb(struct scsi_qla_host *ha, - struct qla82xx_minidump_entry_hdr *entry_hdr, - uint32_t **d_ptr) -{ - uint32_t r_addr, r_stride, loop_cnt, i, r_value; - struct qla82xx_minidump_entry_crb *crb_hdr; - uint32_t *data_ptr = *d_ptr; - - DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__)); - crb_hdr = (struct qla82xx_minidump_entry_crb *)entry_hdr; - r_addr = crb_hdr->addr; - r_stride = crb_hdr->crb_strd.addr_stride; - loop_cnt = crb_hdr->op_count; - - for (i = 0; i < loop_cnt; i++) { - r_value = qla4_8xxx_md_rw_32(ha, r_addr, 0, 0); - *data_ptr++ = cpu_to_le32(r_addr); - *data_ptr++ = cpu_to_le32(r_value); - r_addr += r_stride; - } - *d_ptr = data_ptr; -} - -static int qla4_8xxx_minidump_process_l2tag(struct scsi_qla_host *ha, - struct qla82xx_minidump_entry_hdr *entry_hdr, - uint32_t **d_ptr) -{ - uint32_t addr, r_addr, c_addr, t_r_addr; - uint32_t i, k, loop_count, t_value, r_cnt, r_value; - unsigned long p_wait, w_time, p_mask; - uint32_t c_value_w, c_value_r; - struct qla82xx_minidump_entry_cache *cache_hdr; - int rval = QLA_ERROR; - uint32_t *data_ptr = *d_ptr; - - DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__)); - cache_hdr = (struct qla82xx_minidump_entry_cache *)entry_hdr; - - loop_count = cache_hdr->op_count; - r_addr = cache_hdr->read_addr; - c_addr = cache_hdr->control_addr; - c_value_w = cache_hdr->cache_ctrl.write_value; - - t_r_addr = cache_hdr->tag_reg_addr; - t_value = cache_hdr->addr_ctrl.init_tag_value; - r_cnt = cache_hdr->read_ctrl.read_addr_cnt; - p_wait = cache_hdr->cache_ctrl.poll_wait; - p_mask = cache_hdr->cache_ctrl.poll_mask; - - for (i = 0; i < loop_count; i++) { - qla4_8xxx_md_rw_32(ha, t_r_addr, t_value, 1); - - if (c_value_w) - qla4_8xxx_md_rw_32(ha, c_addr, c_value_w, 1); - - if (p_mask) { - w_time = jiffies + p_wait; - do { - c_value_r = qla4_8xxx_md_rw_32(ha, c_addr, - 0, 0); - if ((c_value_r & p_mask) == 0) { - break; - } else if (time_after_eq(jiffies, w_time)) { - /* capturing dump failed */ - return rval; - } - } while (1); - } - - addr = r_addr; - for (k = 0; k < r_cnt; k++) { - r_value = qla4_8xxx_md_rw_32(ha, addr, 0, 0); - *data_ptr++ = cpu_to_le32(r_value); - addr += cache_hdr->read_ctrl.read_addr_stride; - } - - t_value += cache_hdr->addr_ctrl.tag_value_stride; - } - *d_ptr = data_ptr; - return QLA_SUCCESS; -} - -static int qla4_8xxx_minidump_process_control(struct scsi_qla_host *ha, - struct qla82xx_minidump_entry_hdr *entry_hdr) -{ - struct qla82xx_minidump_entry_crb *crb_entry; - uint32_t read_value, opcode, poll_time, addr, index, rval = QLA_SUCCESS; - uint32_t crb_addr; - unsigned long wtime; - struct qla4_8xxx_minidump_template_hdr *tmplt_hdr; - int i; - - DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__)); - tmplt_hdr = (struct qla4_8xxx_minidump_template_hdr *) - ha->fw_dump_tmplt_hdr; - crb_entry = (struct qla82xx_minidump_entry_crb *)entry_hdr; - - crb_addr = crb_entry->addr; - for (i = 0; i < crb_entry->op_count; i++) { - opcode = crb_entry->crb_ctrl.opcode; - if (opcode & QLA82XX_DBG_OPCODE_WR) { - qla4_8xxx_md_rw_32(ha, crb_addr, - crb_entry->value_1, 1); - opcode &= ~QLA82XX_DBG_OPCODE_WR; - } - if (opcode & QLA82XX_DBG_OPCODE_RW) { - read_value = qla4_8xxx_md_rw_32(ha, crb_addr, 0, 0); - qla4_8xxx_md_rw_32(ha, crb_addr, read_value, 1); - opcode &= ~QLA82XX_DBG_OPCODE_RW; - } - if (opcode & QLA82XX_DBG_OPCODE_AND) { - read_value = qla4_8xxx_md_rw_32(ha, crb_addr, 0, 0); - read_value &= crb_entry->value_2; - opcode &= ~QLA82XX_DBG_OPCODE_AND; - if (opcode & QLA82XX_DBG_OPCODE_OR) { - read_value |= crb_entry->value_3; - opcode &= ~QLA82XX_DBG_OPCODE_OR; - } - qla4_8xxx_md_rw_32(ha, crb_addr, read_value, 1); - } - if (opcode & QLA82XX_DBG_OPCODE_OR) { - read_value = qla4_8xxx_md_rw_32(ha, crb_addr, 0, 0); - read_value |= crb_entry->value_3; - qla4_8xxx_md_rw_32(ha, crb_addr, read_value, 1); - opcode &= ~QLA82XX_DBG_OPCODE_OR; - } - if (opcode & QLA82XX_DBG_OPCODE_POLL) { - poll_time = crb_entry->crb_strd.poll_timeout; - wtime = jiffies + poll_time; - read_value = qla4_8xxx_md_rw_32(ha, crb_addr, 0, 0); - - do { - if ((read_value & crb_entry->value_2) == - crb_entry->value_1) - break; - else if (time_after_eq(jiffies, wtime)) { - /* capturing dump failed */ - rval = QLA_ERROR; - break; - } else - read_value = qla4_8xxx_md_rw_32(ha, - crb_addr, 0, 0); - } while (1); - opcode &= ~QLA82XX_DBG_OPCODE_POLL; - } - - if (opcode & QLA82XX_DBG_OPCODE_RDSTATE) { - if (crb_entry->crb_strd.state_index_a) { - index = crb_entry->crb_strd.state_index_a; - addr = tmplt_hdr->saved_state_array[index]; - } else { - addr = crb_addr; - } - - read_value = qla4_8xxx_md_rw_32(ha, addr, 0, 0); - index = crb_entry->crb_ctrl.state_index_v; - tmplt_hdr->saved_state_array[index] = read_value; - opcode &= ~QLA82XX_DBG_OPCODE_RDSTATE; - } - - if (opcode & QLA82XX_DBG_OPCODE_WRSTATE) { - if (crb_entry->crb_strd.state_index_a) { - index = crb_entry->crb_strd.state_index_a; - addr = tmplt_hdr->saved_state_array[index]; - } else { - addr = crb_addr; - } - - if (crb_entry->crb_ctrl.state_index_v) { - index = crb_entry->crb_ctrl.state_index_v; - read_value = - tmplt_hdr->saved_state_array[index]; - } else { - read_value = crb_entry->value_1; - } - - qla4_8xxx_md_rw_32(ha, addr, read_value, 1); - opcode &= ~QLA82XX_DBG_OPCODE_WRSTATE; - } - - if (opcode & QLA82XX_DBG_OPCODE_MDSTATE) { - index = crb_entry->crb_ctrl.state_index_v; - read_value = tmplt_hdr->saved_state_array[index]; - read_value <<= crb_entry->crb_ctrl.shl; - read_value >>= crb_entry->crb_ctrl.shr; - if (crb_entry->value_2) - read_value &= crb_entry->value_2; - read_value |= crb_entry->value_3; - read_value += crb_entry->value_1; - tmplt_hdr->saved_state_array[index] = read_value; - opcode &= ~QLA82XX_DBG_OPCODE_MDSTATE; - } - crb_addr += crb_entry->crb_strd.addr_stride; - } - DEBUG2(ql4_printk(KERN_INFO, ha, "Leaving fn: %s\n", __func__)); - return rval; -} - -static void qla4_8xxx_minidump_process_rdocm(struct scsi_qla_host *ha, - struct qla82xx_minidump_entry_hdr *entry_hdr, - uint32_t **d_ptr) -{ - uint32_t r_addr, r_stride, loop_cnt, i, r_value; - struct qla82xx_minidump_entry_rdocm *ocm_hdr; - uint32_t *data_ptr = *d_ptr; - - DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__)); - ocm_hdr = (struct qla82xx_minidump_entry_rdocm *)entry_hdr; - r_addr = ocm_hdr->read_addr; - r_stride = ocm_hdr->read_addr_stride; - loop_cnt = ocm_hdr->op_count; - - DEBUG2(ql4_printk(KERN_INFO, ha, - "[%s]: r_addr: 0x%x, r_stride: 0x%x, loop_cnt: 0x%x\n", - __func__, r_addr, r_stride, loop_cnt)); - - for (i = 0; i < loop_cnt; i++) { - r_value = readl((void __iomem *)(r_addr + ha->nx_pcibase)); - *data_ptr++ = cpu_to_le32(r_value); - r_addr += r_stride; - } - DEBUG2(ql4_printk(KERN_INFO, ha, "Leaving fn: %s datacount: 0x%lx\n", - __func__, (loop_cnt * sizeof(uint32_t)))); - *d_ptr = data_ptr; -} - -static void qla4_8xxx_minidump_process_rdmux(struct scsi_qla_host *ha, - struct qla82xx_minidump_entry_hdr *entry_hdr, - uint32_t **d_ptr) -{ - uint32_t r_addr, s_stride, s_addr, s_value, loop_cnt, i, r_value; - struct qla82xx_minidump_entry_mux *mux_hdr; - uint32_t *data_ptr = *d_ptr; - - DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__)); - mux_hdr = (struct qla82xx_minidump_entry_mux *)entry_hdr; - r_addr = mux_hdr->read_addr; - s_addr = mux_hdr->select_addr; - s_stride = mux_hdr->select_value_stride; - s_value = mux_hdr->select_value; - loop_cnt = mux_hdr->op_count; - - for (i = 0; i < loop_cnt; i++) { - qla4_8xxx_md_rw_32(ha, s_addr, s_value, 1); - r_value = qla4_8xxx_md_rw_32(ha, r_addr, 0, 0); - *data_ptr++ = cpu_to_le32(s_value); - *data_ptr++ = cpu_to_le32(r_value); - s_value += s_stride; - } - *d_ptr = data_ptr; -} - -static void qla4_8xxx_minidump_process_l1cache(struct scsi_qla_host *ha, - struct qla82xx_minidump_entry_hdr *entry_hdr, - uint32_t **d_ptr) -{ - uint32_t addr, r_addr, c_addr, t_r_addr; - uint32_t i, k, loop_count, t_value, r_cnt, r_value; - uint32_t c_value_w; - struct qla82xx_minidump_entry_cache *cache_hdr; - uint32_t *data_ptr = *d_ptr; - - cache_hdr = (struct qla82xx_minidump_entry_cache *)entry_hdr; - loop_count = cache_hdr->op_count; - r_addr = cache_hdr->read_addr; - c_addr = cache_hdr->control_addr; - c_value_w = cache_hdr->cache_ctrl.write_value; - - t_r_addr = cache_hdr->tag_reg_addr; - t_value = cache_hdr->addr_ctrl.init_tag_value; - r_cnt = cache_hdr->read_ctrl.read_addr_cnt; - - for (i = 0; i < loop_count; i++) { - qla4_8xxx_md_rw_32(ha, t_r_addr, t_value, 1); - qla4_8xxx_md_rw_32(ha, c_addr, c_value_w, 1); - addr = r_addr; - for (k = 0; k < r_cnt; k++) { - r_value = qla4_8xxx_md_rw_32(ha, addr, 0, 0); - *data_ptr++ = cpu_to_le32(r_value); - addr += cache_hdr->read_ctrl.read_addr_stride; - } - t_value += cache_hdr->addr_ctrl.tag_value_stride; - } - *d_ptr = data_ptr; -} - -static void qla4_8xxx_minidump_process_queue(struct scsi_qla_host *ha, - struct qla82xx_minidump_entry_hdr *entry_hdr, - uint32_t **d_ptr) -{ - uint32_t s_addr, r_addr; - uint32_t r_stride, r_value, r_cnt, qid = 0; - uint32_t i, k, loop_cnt; - struct qla82xx_minidump_entry_queue *q_hdr; - uint32_t *data_ptr = *d_ptr; - - DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__)); - q_hdr = (struct qla82xx_minidump_entry_queue *)entry_hdr; - s_addr = q_hdr->select_addr; - r_cnt = q_hdr->rd_strd.read_addr_cnt; - r_stride = q_hdr->rd_strd.read_addr_stride; - loop_cnt = q_hdr->op_count; - - for (i = 0; i < loop_cnt; i++) { - qla4_8xxx_md_rw_32(ha, s_addr, qid, 1); - r_addr = q_hdr->read_addr; - for (k = 0; k < r_cnt; k++) { - r_value = qla4_8xxx_md_rw_32(ha, r_addr, 0, 0); - *data_ptr++ = cpu_to_le32(r_value); - r_addr += r_stride; - } - qid += q_hdr->q_strd.queue_id_stride; - } - *d_ptr = data_ptr; -} - -#define MD_DIRECT_ROM_WINDOW 0x42110030 -#define MD_DIRECT_ROM_READ_BASE 0x42150000 - -static void qla4_8xxx_minidump_process_rdrom(struct scsi_qla_host *ha, - struct qla82xx_minidump_entry_hdr *entry_hdr, - uint32_t **d_ptr) -{ - uint32_t r_addr, r_value; - uint32_t i, loop_cnt; - struct qla82xx_minidump_entry_rdrom *rom_hdr; - uint32_t *data_ptr = *d_ptr; - - DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__)); - rom_hdr = (struct qla82xx_minidump_entry_rdrom *)entry_hdr; - r_addr = rom_hdr->read_addr; - loop_cnt = rom_hdr->read_data_size/sizeof(uint32_t); - - DEBUG2(ql4_printk(KERN_INFO, ha, - "[%s]: flash_addr: 0x%x, read_data_size: 0x%x\n", - __func__, r_addr, loop_cnt)); - - for (i = 0; i < loop_cnt; i++) { - qla4_8xxx_md_rw_32(ha, MD_DIRECT_ROM_WINDOW, - (r_addr & 0xFFFF0000), 1); - r_value = qla4_8xxx_md_rw_32(ha, - MD_DIRECT_ROM_READ_BASE + - (r_addr & 0x0000FFFF), 0, 0); - *data_ptr++ = cpu_to_le32(r_value); - r_addr += sizeof(uint32_t); - } - *d_ptr = data_ptr; -} - -#define MD_MIU_TEST_AGT_CTRL 0x41000090 -#define MD_MIU_TEST_AGT_ADDR_LO 0x41000094 -#define MD_MIU_TEST_AGT_ADDR_HI 0x41000098 - -static int qla4_8xxx_minidump_process_rdmem(struct scsi_qla_host *ha, - struct qla82xx_minidump_entry_hdr *entry_hdr, - uint32_t **d_ptr) -{ - uint32_t r_addr, r_value, r_data; - uint32_t i, j, loop_cnt; - struct qla82xx_minidump_entry_rdmem *m_hdr; - unsigned long flags; - uint32_t *data_ptr = *d_ptr; - - DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__)); - m_hdr = (struct qla82xx_minidump_entry_rdmem *)entry_hdr; - r_addr = m_hdr->read_addr; - loop_cnt = m_hdr->read_data_size/16; - - DEBUG2(ql4_printk(KERN_INFO, ha, - "[%s]: Read addr: 0x%x, read_data_size: 0x%x\n", - __func__, r_addr, m_hdr->read_data_size)); - - if (r_addr & 0xf) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "[%s]: Read addr 0x%x not 16 bytes alligned\n", - __func__, r_addr)); - return QLA_ERROR; - } - - if (m_hdr->read_data_size % 16) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "[%s]: Read data[0x%x] not multiple of 16 bytes\n", - __func__, m_hdr->read_data_size)); - return QLA_ERROR; - } - - DEBUG2(ql4_printk(KERN_INFO, ha, - "[%s]: rdmem_addr: 0x%x, read_data_size: 0x%x, loop_cnt: 0x%x\n", - __func__, r_addr, m_hdr->read_data_size, loop_cnt)); - - write_lock_irqsave(&ha->hw_lock, flags); - for (i = 0; i < loop_cnt; i++) { - qla4_8xxx_md_rw_32(ha, MD_MIU_TEST_AGT_ADDR_LO, r_addr, 1); - r_value = 0; - qla4_8xxx_md_rw_32(ha, MD_MIU_TEST_AGT_ADDR_HI, r_value, 1); - r_value = MIU_TA_CTL_ENABLE; - qla4_8xxx_md_rw_32(ha, MD_MIU_TEST_AGT_CTRL, r_value, 1); - r_value = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE; - qla4_8xxx_md_rw_32(ha, MD_MIU_TEST_AGT_CTRL, r_value, 1); - - for (j = 0; j < MAX_CTL_CHECK; j++) { - r_value = qla4_8xxx_md_rw_32(ha, MD_MIU_TEST_AGT_CTRL, - 0, 0); - if ((r_value & MIU_TA_CTL_BUSY) == 0) - break; - } - - if (j >= MAX_CTL_CHECK) { - printk_ratelimited(KERN_ERR - "%s: failed to read through agent\n", - __func__); - write_unlock_irqrestore(&ha->hw_lock, flags); - return QLA_SUCCESS; - } - - for (j = 0; j < 4; j++) { - r_data = qla4_8xxx_md_rw_32(ha, - MD_MIU_TEST_AGT_RDDATA[j], - 0, 0); - *data_ptr++ = cpu_to_le32(r_data); - } - - r_addr += 16; - } - write_unlock_irqrestore(&ha->hw_lock, flags); - - DEBUG2(ql4_printk(KERN_INFO, ha, "Leaving fn: %s datacount: 0x%x\n", - __func__, (loop_cnt * 16))); - - *d_ptr = data_ptr; - return QLA_SUCCESS; -} - -static void ql4_8xxx_mark_entry_skipped(struct scsi_qla_host *ha, - struct qla82xx_minidump_entry_hdr *entry_hdr, - int index) -{ - entry_hdr->d_ctrl.driver_flags |= QLA82XX_DBG_SKIPPED_FLAG; - DEBUG2(ql4_printk(KERN_INFO, ha, - "scsi(%ld): Skipping entry[%d]: ETYPE[0x%x]-ELEVEL[0x%x]\n", - ha->host_no, index, entry_hdr->entry_type, - entry_hdr->d_ctrl.entry_capture_mask)); -} - -/** - * qla82xx_collect_md_data - Retrieve firmware minidump data. - * @ha: pointer to adapter structure - **/ -static int qla4_8xxx_collect_md_data(struct scsi_qla_host *ha) -{ - int num_entry_hdr = 0; - struct qla82xx_minidump_entry_hdr *entry_hdr; - struct qla4_8xxx_minidump_template_hdr *tmplt_hdr; - uint32_t *data_ptr; - uint32_t data_collected = 0; - int i, rval = QLA_ERROR; - uint64_t now; - uint32_t timestamp; - - if (!ha->fw_dump) { - ql4_printk(KERN_INFO, ha, "%s(%ld) No buffer to dump\n", - __func__, ha->host_no); - return rval; - } - - tmplt_hdr = (struct qla4_8xxx_minidump_template_hdr *) - ha->fw_dump_tmplt_hdr; - data_ptr = (uint32_t *)((uint8_t *)ha->fw_dump + - ha->fw_dump_tmplt_size); - data_collected += ha->fw_dump_tmplt_size; - - num_entry_hdr = tmplt_hdr->num_of_entries; - ql4_printk(KERN_INFO, ha, "[%s]: starting data ptr: %p\n", - __func__, data_ptr); - ql4_printk(KERN_INFO, ha, - "[%s]: no of entry headers in Template: 0x%x\n", - __func__, num_entry_hdr); - ql4_printk(KERN_INFO, ha, "[%s]: Capture Mask obtained: 0x%x\n", - __func__, ha->fw_dump_capture_mask); - ql4_printk(KERN_INFO, ha, "[%s]: Total_data_size 0x%x, %d obtained\n", - __func__, ha->fw_dump_size, ha->fw_dump_size); - - /* Update current timestamp before taking dump */ - now = get_jiffies_64(); - timestamp = (u32)(jiffies_to_msecs(now) / 1000); - tmplt_hdr->driver_timestamp = timestamp; - - entry_hdr = (struct qla82xx_minidump_entry_hdr *) - (((uint8_t *)ha->fw_dump_tmplt_hdr) + - tmplt_hdr->first_entry_offset); - - /* Walk through the entry headers - validate/perform required action */ - for (i = 0; i < num_entry_hdr; i++) { - if (data_collected >= ha->fw_dump_size) { - ql4_printk(KERN_INFO, ha, - "Data collected: [0x%x], Total Dump size: [0x%x]\n", - data_collected, ha->fw_dump_size); - return rval; - } - - if (!(entry_hdr->d_ctrl.entry_capture_mask & - ha->fw_dump_capture_mask)) { - entry_hdr->d_ctrl.driver_flags |= - QLA82XX_DBG_SKIPPED_FLAG; - goto skip_nxt_entry; - } - - DEBUG2(ql4_printk(KERN_INFO, ha, - "Data collected: [0x%x], Dump size left:[0x%x]\n", - data_collected, - (ha->fw_dump_size - data_collected))); - - /* Decode the entry type and take required action to capture - * debug data - */ - switch (entry_hdr->entry_type) { - case QLA82XX_RDEND: - ql4_8xxx_mark_entry_skipped(ha, entry_hdr, i); - break; - case QLA82XX_CNTRL: - rval = qla4_8xxx_minidump_process_control(ha, - entry_hdr); - if (rval != QLA_SUCCESS) { - ql4_8xxx_mark_entry_skipped(ha, entry_hdr, i); - goto md_failed; - } - break; - case QLA82XX_RDCRB: - qla4_8xxx_minidump_process_rdcrb(ha, entry_hdr, - &data_ptr); - break; - case QLA82XX_RDMEM: - rval = qla4_8xxx_minidump_process_rdmem(ha, entry_hdr, - &data_ptr); - if (rval != QLA_SUCCESS) { - ql4_8xxx_mark_entry_skipped(ha, entry_hdr, i); - goto md_failed; - } - break; - case QLA82XX_BOARD: - case QLA82XX_RDROM: - qla4_8xxx_minidump_process_rdrom(ha, entry_hdr, - &data_ptr); - break; - case QLA82XX_L2DTG: - case QLA82XX_L2ITG: - case QLA82XX_L2DAT: - case QLA82XX_L2INS: - rval = qla4_8xxx_minidump_process_l2tag(ha, entry_hdr, - &data_ptr); - if (rval != QLA_SUCCESS) { - ql4_8xxx_mark_entry_skipped(ha, entry_hdr, i); - goto md_failed; - } - break; - case QLA82XX_L1DAT: - case QLA82XX_L1INS: - qla4_8xxx_minidump_process_l1cache(ha, entry_hdr, - &data_ptr); - break; - case QLA82XX_RDOCM: - qla4_8xxx_minidump_process_rdocm(ha, entry_hdr, - &data_ptr); - break; - case QLA82XX_RDMUX: - qla4_8xxx_minidump_process_rdmux(ha, entry_hdr, - &data_ptr); - break; - case QLA82XX_QUEUE: - qla4_8xxx_minidump_process_queue(ha, entry_hdr, - &data_ptr); - break; - case QLA82XX_RDNOP: - default: - ql4_8xxx_mark_entry_skipped(ha, entry_hdr, i); - break; - } - - data_collected = (uint8_t *)data_ptr - - ((uint8_t *)((uint8_t *)ha->fw_dump + - ha->fw_dump_tmplt_size)); -skip_nxt_entry: - /* next entry in the template */ - entry_hdr = (struct qla82xx_minidump_entry_hdr *) - (((uint8_t *)entry_hdr) + - entry_hdr->entry_size); - } - - if ((data_collected + ha->fw_dump_tmplt_size) != ha->fw_dump_size) { - ql4_printk(KERN_INFO, ha, - "Dump data mismatch: Data collected: [0x%x], total_data_size:[0x%x]\n", - data_collected, ha->fw_dump_size); - goto md_failed; - } - - DEBUG2(ql4_printk(KERN_INFO, ha, "Leaving fn: %s Last entry: 0x%x\n", - __func__, i)); -md_failed: - return rval; -} - -/** - * qla4_8xxx_uevent_emit - Send uevent when the firmware dump is ready. - * @ha: pointer to adapter structure - **/ -static void qla4_8xxx_uevent_emit(struct scsi_qla_host *ha, u32 code) -{ - char event_string[40]; - char *envp[] = { event_string, NULL }; - - switch (code) { - case QL4_UEVENT_CODE_FW_DUMP: - snprintf(event_string, sizeof(event_string), "FW_DUMP=%ld", - ha->host_no); - break; - default: - /*do nothing*/ - break; - } - - kobject_uevent_env(&(&ha->pdev->dev)->kobj, KOBJ_CHANGE, envp); -} - /** * qla4_8xxx_device_bootstrap - Initialize device, set DEV_READY, start fw * @ha: pointer to adapter structure @@ -2324,15 +1659,6 @@ qla4_8xxx_device_bootstrap(struct scsi_qla_host *ha) qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, QLA82XX_IDC_VERSION); qla4_8xxx_idc_unlock(ha); - if (ql4xenablemd && test_bit(AF_FW_RECOVERY, &ha->flags) && - !test_and_set_bit(AF_82XX_FW_DUMPED, &ha->flags)) { - if (!qla4_8xxx_collect_md_data(ha)) { - qla4_8xxx_uevent_emit(ha, QL4_UEVENT_CODE_FW_DUMP); - } else { - ql4_printk(KERN_INFO, ha, "Unable to collect minidump\n"); - clear_bit(AF_82XX_FW_DUMPED, &ha->flags); - } - } rval = qla4_8xxx_try_start_fw(ha); qla4_8xxx_idc_lock(ha); @@ -2360,7 +1686,6 @@ static void qla4_8xxx_need_reset_handler(struct scsi_qla_host *ha) { uint32_t dev_state, drv_state, drv_active; - uint32_t active_mask = 0xFFFFFFFF; unsigned long reset_timeout; ql4_printk(KERN_INFO, ha, @@ -2372,14 +1697,7 @@ qla4_8xxx_need_reset_handler(struct scsi_qla_host *ha) qla4_8xxx_idc_lock(ha); } - if (!test_bit(AF_82XX_RST_OWNER, &ha->flags)) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "%s(%ld): reset acknowledged\n", - __func__, ha->host_no)); - qla4_8xxx_set_rst_ready(ha); - } else { - active_mask = (~(1 << (ha->func_num * 4))); - } + qla4_8xxx_set_rst_ready(ha); /* wait for 10 seconds for reset ack from all functions */ reset_timeout = jiffies + (ha->nx_reset_timeout * HZ); @@ -2391,24 +1709,12 @@ qla4_8xxx_need_reset_handler(struct scsi_qla_host *ha) "%s(%ld): drv_state = 0x%x, drv_active = 0x%x\n", __func__, ha->host_no, drv_state, drv_active); - while (drv_state != (drv_active & active_mask)) { + while (drv_state != drv_active) { if (time_after_eq(jiffies, reset_timeout)) { - ql4_printk(KERN_INFO, ha, - "%s: RESET TIMEOUT! drv_state: 0x%08x, drv_active: 0x%08x\n", - DRIVER_NAME, drv_state, drv_active); + printk("%s: RESET TIMEOUT!\n", DRIVER_NAME); break; } - /* - * When reset_owner times out, check which functions - * acked/did not ack - */ - if (test_bit(AF_82XX_RST_OWNER, &ha->flags)) { - ql4_printk(KERN_INFO, ha, - "%s(%ld): drv_state = 0x%x, drv_active = 0x%x\n", - __func__, ha->host_no, drv_state, - drv_active); - } qla4_8xxx_idc_unlock(ha); msleep(1000); qla4_8xxx_idc_lock(ha); @@ -2417,18 +1723,14 @@ qla4_8xxx_need_reset_handler(struct scsi_qla_host *ha) drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); } - /* Clear RESET OWNER as we are not going to use it any further */ - clear_bit(AF_82XX_RST_OWNER, &ha->flags); - dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - ql4_printk(KERN_INFO, ha, "Device state is 0x%x = %s\n", dev_state, - dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown"); + ql4_printk(KERN_INFO, ha, "3:Device state is 0x%x = %s\n", dev_state, + dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown"); /* Force to DEV_COLD unless someone else is starting a reset */ if (dev_state != QLA82XX_DEV_INITIALIZING) { ql4_printk(KERN_INFO, ha, "HW State: COLD/RE-INIT\n"); qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_COLD); - qla4_8xxx_set_rst_ready(ha); } } @@ -2463,9 +1765,8 @@ int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha) } dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - DEBUG2(ql4_printk(KERN_INFO, ha, "Device state is 0x%x = %s\n", - dev_state, dev_state < MAX_STATES ? - qdev_state[dev_state] : "Unknown")); + ql4_printk(KERN_INFO, ha, "1:Device state is 0x%x = %s\n", dev_state, + dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown"); /* wait for 30 seconds for device to go ready */ dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ); @@ -2474,19 +1775,15 @@ int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha) while (1) { if (time_after_eq(jiffies, dev_init_timeout)) { - ql4_printk(KERN_WARNING, ha, - "%s: Device Init Failed 0x%x = %s\n", - DRIVER_NAME, - dev_state, dev_state < MAX_STATES ? - qdev_state[dev_state] : "Unknown"); + ql4_printk(KERN_WARNING, ha, "Device init failed!\n"); qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_FAILED); } dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - ql4_printk(KERN_INFO, ha, "Device state is 0x%x = %s\n", - dev_state, dev_state < MAX_STATES ? - qdev_state[dev_state] : "Unknown"); + ql4_printk(KERN_INFO, ha, + "2:Device state is 0x%x = %s\n", dev_state, + dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown"); /* NOTE: Make sure idc unlocked upon exit of switch statement */ switch (dev_state) { @@ -2887,7 +2184,6 @@ qla4_8xxx_isp_reset(struct scsi_qla_host *ha) ql4_printk(KERN_INFO, ha, "HW State: NEED RESET\n"); qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_NEED_RESET); - set_bit(AF_82XX_RST_OWNER, &ha->flags); } else ql4_printk(KERN_INFO, ha, "HW State: DEVICE INITIALIZING\n"); @@ -2899,10 +2195,8 @@ qla4_8xxx_isp_reset(struct scsi_qla_host *ha) qla4_8xxx_clear_rst_ready(ha); qla4_8xxx_idc_unlock(ha); - if (rval == QLA_SUCCESS) { - ql4_printk(KERN_INFO, ha, "Clearing AF_RECOVERY in qla4_8xxx_isp_reset\n"); + if (rval == QLA_SUCCESS) clear_bit(AF_FW_RECOVERY, &ha->flags); - } return rval; } diff --git a/trunk/drivers/scsi/qla4xxx/ql4_nx.h b/trunk/drivers/scsi/qla4xxx/ql4_nx.h index 30258479f100..dc7500e47b8b 100644 --- a/trunk/drivers/scsi/qla4xxx/ql4_nx.h +++ b/trunk/drivers/scsi/qla4xxx/ql4_nx.h @@ -792,196 +792,4 @@ struct crb_addr_pair { #define MIU_TEST_AGT_WRDATA_UPPER_LO (0x0b0) #define MIU_TEST_AGT_WRDATA_UPPER_HI (0x0b4) -/* Minidump related */ - -/* Entry Type Defines */ -#define QLA82XX_RDNOP 0 -#define QLA82XX_RDCRB 1 -#define QLA82XX_RDMUX 2 -#define QLA82XX_QUEUE 3 -#define QLA82XX_BOARD 4 -#define QLA82XX_RDOCM 6 -#define QLA82XX_PREGS 7 -#define QLA82XX_L1DTG 8 -#define QLA82XX_L1ITG 9 -#define QLA82XX_L1DAT 11 -#define QLA82XX_L1INS 12 -#define QLA82XX_L2DTG 21 -#define QLA82XX_L2ITG 22 -#define QLA82XX_L2DAT 23 -#define QLA82XX_L2INS 24 -#define QLA82XX_RDROM 71 -#define QLA82XX_RDMEM 72 -#define QLA82XX_CNTRL 98 -#define QLA82XX_RDEND 255 - -/* Opcodes for Control Entries. - * These Flags are bit fields. - */ -#define QLA82XX_DBG_OPCODE_WR 0x01 -#define QLA82XX_DBG_OPCODE_RW 0x02 -#define QLA82XX_DBG_OPCODE_AND 0x04 -#define QLA82XX_DBG_OPCODE_OR 0x08 -#define QLA82XX_DBG_OPCODE_POLL 0x10 -#define QLA82XX_DBG_OPCODE_RDSTATE 0x20 -#define QLA82XX_DBG_OPCODE_WRSTATE 0x40 -#define QLA82XX_DBG_OPCODE_MDSTATE 0x80 - -/* Driver Flags */ -#define QLA82XX_DBG_SKIPPED_FLAG 0x80 /* driver skipped this entry */ -#define QLA82XX_DBG_SIZE_ERR_FLAG 0x40 /* Entry vs Capture size - * mismatch */ - -/* Driver_code is for driver to write some info about the entry - * currently not used. - */ -struct qla82xx_minidump_entry_hdr { - uint32_t entry_type; - uint32_t entry_size; - uint32_t entry_capture_size; - struct { - uint8_t entry_capture_mask; - uint8_t entry_code; - uint8_t driver_code; - uint8_t driver_flags; - } d_ctrl; -}; - -/* Read CRB entry header */ -struct qla82xx_minidump_entry_crb { - struct qla82xx_minidump_entry_hdr h; - uint32_t addr; - struct { - uint8_t addr_stride; - uint8_t state_index_a; - uint16_t poll_timeout; - } crb_strd; - uint32_t data_size; - uint32_t op_count; - - struct { - uint8_t opcode; - uint8_t state_index_v; - uint8_t shl; - uint8_t shr; - } crb_ctrl; - - uint32_t value_1; - uint32_t value_2; - uint32_t value_3; -}; - -struct qla82xx_minidump_entry_cache { - struct qla82xx_minidump_entry_hdr h; - uint32_t tag_reg_addr; - struct { - uint16_t tag_value_stride; - uint16_t init_tag_value; - } addr_ctrl; - uint32_t data_size; - uint32_t op_count; - uint32_t control_addr; - struct { - uint16_t write_value; - uint8_t poll_mask; - uint8_t poll_wait; - } cache_ctrl; - uint32_t read_addr; - struct { - uint8_t read_addr_stride; - uint8_t read_addr_cnt; - uint16_t rsvd_1; - } read_ctrl; -}; - -/* Read OCM */ -struct qla82xx_minidump_entry_rdocm { - struct qla82xx_minidump_entry_hdr h; - uint32_t rsvd_0; - uint32_t rsvd_1; - uint32_t data_size; - uint32_t op_count; - uint32_t rsvd_2; - uint32_t rsvd_3; - uint32_t read_addr; - uint32_t read_addr_stride; -}; - -/* Read Memory */ -struct qla82xx_minidump_entry_rdmem { - struct qla82xx_minidump_entry_hdr h; - uint32_t rsvd[6]; - uint32_t read_addr; - uint32_t read_data_size; -}; - -/* Read ROM */ -struct qla82xx_minidump_entry_rdrom { - struct qla82xx_minidump_entry_hdr h; - uint32_t rsvd[6]; - uint32_t read_addr; - uint32_t read_data_size; -}; - -/* Mux entry */ -struct qla82xx_minidump_entry_mux { - struct qla82xx_minidump_entry_hdr h; - uint32_t select_addr; - uint32_t rsvd_0; - uint32_t data_size; - uint32_t op_count; - uint32_t select_value; - uint32_t select_value_stride; - uint32_t read_addr; - uint32_t rsvd_1; -}; - -/* Queue entry */ -struct qla82xx_minidump_entry_queue { - struct qla82xx_minidump_entry_hdr h; - uint32_t select_addr; - struct { - uint16_t queue_id_stride; - uint16_t rsvd_0; - } q_strd; - uint32_t data_size; - uint32_t op_count; - uint32_t rsvd_1; - uint32_t rsvd_2; - uint32_t read_addr; - struct { - uint8_t read_addr_stride; - uint8_t read_addr_cnt; - uint16_t rsvd_3; - } rd_strd; -}; - -#define QLA82XX_MINIDUMP_OCM0_SIZE (256 * 1024) -#define QLA82XX_MINIDUMP_L1C_SIZE (256 * 1024) -#define QLA82XX_MINIDUMP_L2C_SIZE 1572864 -#define QLA82XX_MINIDUMP_COMMON_STR_SIZE 0 -#define QLA82XX_MINIDUMP_FCOE_STR_SIZE 0 -#define QLA82XX_MINIDUMP_MEM_SIZE 0 -#define QLA82XX_MAX_ENTRY_HDR 4 - -struct qla82xx_minidump { - uint32_t md_ocm0_data[QLA82XX_MINIDUMP_OCM0_SIZE]; - uint32_t md_l1c_data[QLA82XX_MINIDUMP_L1C_SIZE]; - uint32_t md_l2c_data[QLA82XX_MINIDUMP_L2C_SIZE]; - uint32_t md_cs_data[QLA82XX_MINIDUMP_COMMON_STR_SIZE]; - uint32_t md_fcoes_data[QLA82XX_MINIDUMP_FCOE_STR_SIZE]; - uint32_t md_mem_data[QLA82XX_MINIDUMP_MEM_SIZE]; -}; - -#define MBC_DIAGNOSTIC_MINIDUMP_TEMPLATE 0x129 -#define RQST_TMPLT_SIZE 0x0 -#define RQST_TMPLT 0x1 -#define MD_DIRECT_ROM_WINDOW 0x42110030 -#define MD_DIRECT_ROM_READ_BASE 0x42150000 -#define MD_MIU_TEST_AGT_CTRL 0x41000090 -#define MD_MIU_TEST_AGT_ADDR_LO 0x41000094 -#define MD_MIU_TEST_AGT_ADDR_HI 0x41000098 - -static const int MD_MIU_TEST_AGT_RDDATA[] = { 0x410000A8, - 0x410000AC, 0x410000B8, 0x410000BC }; #endif diff --git a/trunk/drivers/scsi/qla4xxx/ql4_os.c b/trunk/drivers/scsi/qla4xxx/ql4_os.c index cd15678f9ada..ee47820c30a6 100644 --- a/trunk/drivers/scsi/qla4xxx/ql4_os.c +++ b/trunk/drivers/scsi/qla4xxx/ql4_os.c @@ -68,34 +68,12 @@ MODULE_PARM_DESC(ql4xmaxqdepth, " Maximum queue depth to report for target devices.\n" "\t\t Default: 32."); -static int ql4xqfulltracking = 1; -module_param(ql4xqfulltracking, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(ql4xqfulltracking, - " Enable or disable dynamic tracking and adjustment of\n" - "\t\t scsi device queue depth.\n" - "\t\t 0 - Disable.\n" - "\t\t 1 - Enable. (Default)"); - static int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO; module_param(ql4xsess_recovery_tmo, int, S_IRUGO); MODULE_PARM_DESC(ql4xsess_recovery_tmo, " Target Session Recovery Timeout.\n" "\t\t Default: 120 sec."); -int ql4xmdcapmask = 0x1F; -module_param(ql4xmdcapmask, int, S_IRUGO); -MODULE_PARM_DESC(ql4xmdcapmask, - " Set the Minidump driver capture mask level.\n" - "\t\t Default is 0x1F.\n" - "\t\t Can be set to 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F"); - -int ql4xenablemd = 1; -module_param(ql4xenablemd, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(ql4xenablemd, - " Set to enable minidump.\n" - "\t\t 0 - disable minidump\n" - "\t\t 1 - enable minidump (Default)"); - static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha); /* * SCSI host template entry points @@ -162,8 +140,6 @@ static int qla4xxx_slave_configure(struct scsi_device *device); static void qla4xxx_slave_destroy(struct scsi_device *sdev); static umode_t ql4_attr_is_visible(int param_type, int param); static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type); -static int qla4xxx_change_queue_depth(struct scsi_device *sdev, int qdepth, - int reason); static struct qla4_8xxx_legacy_intr_set legacy_intr[] = QLA82XX_LEGACY_INTR_CONFIG; @@ -183,7 +159,6 @@ static struct scsi_host_template qla4xxx_driver_template = { .slave_configure = qla4xxx_slave_configure, .slave_alloc = qla4xxx_slave_alloc, .slave_destroy = qla4xxx_slave_destroy, - .change_queue_depth = qla4xxx_change_queue_depth, .this_id = -1, .cmd_per_lun = 3, @@ -1580,53 +1555,19 @@ static void qla4xxx_session_destroy(struct iscsi_cls_session *cls_sess) struct iscsi_session *sess; struct ddb_entry *ddb_entry; struct scsi_qla_host *ha; - unsigned long flags, wtime; - struct dev_db_entry *fw_ddb_entry = NULL; - dma_addr_t fw_ddb_entry_dma; - uint32_t ddb_state; - int ret; + unsigned long flags; DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); sess = cls_sess->dd_data; ddb_entry = sess->dd_data; ha = ddb_entry->ha; - fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), - &fw_ddb_entry_dma, GFP_KERNEL); - if (!fw_ddb_entry) { - ql4_printk(KERN_ERR, ha, - "%s: Unable to allocate dma buffer\n", __func__); - goto destroy_session; - } - - wtime = jiffies + (HZ * LOGOUT_TOV); - do { - ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, - fw_ddb_entry, fw_ddb_entry_dma, - NULL, NULL, &ddb_state, NULL, - NULL, NULL); - if (ret == QLA_ERROR) - goto destroy_session; - - if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) || - (ddb_state == DDB_DS_SESSION_FAILED)) - goto destroy_session; - - schedule_timeout_uninterruptible(HZ); - } while ((time_after(wtime, jiffies))); - -destroy_session: qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index); spin_lock_irqsave(&ha->hardware_lock, flags); qla4xxx_free_ddb(ha, ddb_entry); spin_unlock_irqrestore(&ha->hardware_lock, flags); - iscsi_session_teardown(cls_sess); - - if (fw_ddb_entry) - dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), - fw_ddb_entry, fw_ddb_entry_dma); } static struct iscsi_cls_conn * @@ -2279,9 +2220,6 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha) dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues, ha->queues_dma); - if (ha->fw_dump) - vfree(ha->fw_dump); - ha->queues_len = 0; ha->queues = NULL; ha->queues_dma = 0; @@ -2291,8 +2229,6 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha) ha->response_dma = 0; ha->shadow_regs = NULL; ha->shadow_regs_dma = 0; - ha->fw_dump = NULL; - ha->fw_dump_size = 0; /* Free srb pool. */ if (ha->srb_mempool) @@ -5087,8 +5023,6 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, set_bit(AF_INIT_DONE, &ha->flags); - qla4_8xxx_alloc_sysfs_attr(ha); - printk(KERN_INFO " QLogic iSCSI HBA Driver version: %s\n" " QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n", @@ -5215,7 +5149,6 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) iscsi_boot_destroy_kset(ha->boot_kset); qla4xxx_destroy_fw_ddb_session(ha); - qla4_8xxx_free_sysfs_attr(ha); scsi_remove_host(ha->host); @@ -5284,15 +5217,6 @@ static void qla4xxx_slave_destroy(struct scsi_device *sdev) scsi_deactivate_tcq(sdev, 1); } -static int qla4xxx_change_queue_depth(struct scsi_device *sdev, int qdepth, - int reason) -{ - if (!ql4xqfulltracking) - return -EOPNOTSUPP; - - return iscsi_change_queue_depth(sdev, qdepth, reason); -} - /** * qla4xxx_del_from_active_array - returns an active srb * @ha: Pointer to host adapter structure. diff --git a/trunk/drivers/scsi/qla4xxx/ql4_version.h b/trunk/drivers/scsi/qla4xxx/ql4_version.h index cc1cc3518b87..97b30c108e36 100644 --- a/trunk/drivers/scsi/qla4xxx/ql4_version.h +++ b/trunk/drivers/scsi/qla4xxx/ql4_version.h @@ -5,4 +5,4 @@ * See LICENSE.qla4xxx for copyright and licensing details. */ -#define QLA4XXX_DRIVER_VERSION "5.02.00-k17" +#define QLA4XXX_DRIVER_VERSION "5.02.00-k16" diff --git a/trunk/drivers/scsi/scsi_lib.c b/trunk/drivers/scsi/scsi_lib.c index 6dfb9785d345..62ddfd31d4ce 100644 --- a/trunk/drivers/scsi/scsi_lib.c +++ b/trunk/drivers/scsi/scsi_lib.c @@ -1378,19 +1378,16 @@ static int scsi_lld_busy(struct request_queue *q) { struct scsi_device *sdev = q->queuedata; struct Scsi_Host *shost; + struct scsi_target *starget; if (!sdev) return 0; shost = sdev->host; + starget = scsi_target(sdev); - /* - * Ignore host/starget busy state. - * Since block layer does not have a concept of fairness across - * multiple queues, congestion of host/starget needs to be handled - * in SCSI layer. - */ - if (scsi_host_in_recovery(shost) || scsi_device_is_busy(sdev)) + if (scsi_host_in_recovery(shost) || scsi_host_is_busy(shost) || + scsi_target_is_busy(starget) || scsi_device_is_busy(sdev)) return 1; return 0; diff --git a/trunk/drivers/scsi/scsi_pm.c b/trunk/drivers/scsi/scsi_pm.c index d4201ded3b22..f661a41fa4c6 100644 --- a/trunk/drivers/scsi/scsi_pm.c +++ b/trunk/drivers/scsi/scsi_pm.c @@ -24,11 +24,8 @@ static int scsi_dev_type_suspend(struct device *dev, pm_message_t msg) err = scsi_device_quiesce(to_scsi_device(dev)); if (err == 0) { drv = dev->driver; - if (drv && drv->suspend) { + if (drv && drv->suspend) err = drv->suspend(dev, msg); - if (err) - scsi_device_resume(to_scsi_device(dev)); - } } dev_dbg(dev, "scsi suspend: %d\n", err); return err; diff --git a/trunk/drivers/scsi/scsi_scan.c b/trunk/drivers/scsi/scsi_scan.c index 2e5fe584aad3..01b03744f1f9 100644 --- a/trunk/drivers/scsi/scsi_scan.c +++ b/trunk/drivers/scsi/scsi_scan.c @@ -147,7 +147,7 @@ int scsi_complete_async_scans(void) do { if (list_empty(&scanning_hosts)) - goto out; + return 0; /* If we can't get memory immediately, that's OK. Just * sleep a little. Even if we never get memory, the async * scans will finish eventually. @@ -179,11 +179,8 @@ int scsi_complete_async_scans(void) } done: spin_unlock(&async_scan_lock); - kfree(data); - - out: - async_synchronize_full_domain(&scsi_sd_probe_domain); + kfree(data); return 0; } diff --git a/trunk/drivers/scsi/scsi_wait_scan.c b/trunk/drivers/scsi/scsi_wait_scan.c index ae7814874618..74708fcaf82f 100644 --- a/trunk/drivers/scsi/scsi_wait_scan.c +++ b/trunk/drivers/scsi/scsi_wait_scan.c @@ -12,7 +12,7 @@ #include #include -#include "scsi_priv.h" +#include static int __init wait_scan_init(void) { diff --git a/trunk/drivers/scsi/ufs/ufshcd.c b/trunk/drivers/scsi/ufs/ufshcd.c index 6a4fd00117ca..4e010b727818 100644 --- a/trunk/drivers/scsi/ufs/ufshcd.c +++ b/trunk/drivers/scsi/ufs/ufshcd.c @@ -1836,7 +1836,7 @@ ufshcd_probe(struct pci_dev *pdev, const struct pci_device_id *id) err = pci_request_regions(pdev, UFSHCD); if (err < 0) { dev_err(&pdev->dev, "request regions failed\n"); - goto out_host_put; + goto out_disable; } hba->mmio_base = pci_ioremap_bar(pdev, 0); @@ -1925,9 +1925,8 @@ ufshcd_probe(struct pci_dev *pdev, const struct pci_device_id *id) iounmap(hba->mmio_base); out_release_regions: pci_release_regions(pdev); -out_host_put: - scsi_host_put(host); out_disable: + scsi_host_put(host); pci_clear_master(pdev); pci_disable_device(pdev); out_error: diff --git a/trunk/drivers/tty/serial/lantiq.c b/trunk/drivers/tty/serial/lantiq.c index 02da071fe1e7..96c1cacc7360 100644 --- a/trunk/drivers/tty/serial/lantiq.c +++ b/trunk/drivers/tty/serial/lantiq.c @@ -31,19 +31,16 @@ #include #include #include -#include -#include -#include +#include #include #include -#include #include #define PORT_LTQ_ASC 111 #define MAXPORTS 2 #define UART_DUMMY_UER_RX 1 -#define DRVNAME "lantiq,asc" +#define DRVNAME "ltq_asc" #ifdef __BIG_ENDIAN #define LTQ_ASC_TBUF (0x0020 + 3) #define LTQ_ASC_RBUF (0x0024 + 3) @@ -117,9 +114,6 @@ static DEFINE_SPINLOCK(ltq_asc_lock); struct ltq_uart_port { struct uart_port port; - /* clock used to derive divider */ - struct clk *fpiclk; - /* clock gating of the ASC core */ struct clk *clk; unsigned int tx_irq; unsigned int rx_irq; @@ -322,9 +316,7 @@ lqasc_startup(struct uart_port *port) struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); int retval; - if (ltq_port->clk) - clk_enable(ltq_port->clk); - port->uartclk = clk_get_rate(ltq_port->fpiclk); + port->uartclk = clk_get_rate(ltq_port->clk); ltq_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET), port->membase + LTQ_ASC_CLC); @@ -390,8 +382,6 @@ lqasc_shutdown(struct uart_port *port) port->membase + LTQ_ASC_RXFCON); ltq_w32_mask(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU, port->membase + LTQ_ASC_TXFCON); - if (ltq_port->clk) - clk_disable(ltq_port->clk); } static void @@ -640,7 +630,7 @@ lqasc_console_setup(struct console *co, char *options) port = <q_port->port; - port->uartclk = clk_get_rate(ltq_port->fpiclk); + port->uartclk = clk_get_rate(ltq_port->clk); if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -678,32 +668,37 @@ static struct uart_driver lqasc_reg = { static int __init lqasc_probe(struct platform_device *pdev) { - struct device_node *node = pdev->dev.of_node; struct ltq_uart_port *ltq_port; struct uart_port *port; - struct resource *mmres, irqres[3]; - int line = 0; + struct resource *mmres, *irqres; + int tx_irq, rx_irq, err_irq; + struct clk *clk; int ret; mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ret = of_irq_to_resource_table(node, irqres, 3); - if (!mmres || (ret != 3)) { - dev_err(&pdev->dev, - "failed to get memory/irq for serial port\n"); + irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!mmres || !irqres) return -ENODEV; - } - /* check if this is the console port */ - if (mmres->start != CPHYSADDR(LTQ_EARLY_ASC)) - line = 1; + if (pdev->id >= MAXPORTS) + return -EBUSY; - if (lqasc_port[line]) { - dev_err(&pdev->dev, "port %d already allocated\n", line); + if (lqasc_port[pdev->id] != NULL) return -EBUSY; + + clk = clk_get(&pdev->dev, "fpi"); + if (IS_ERR(clk)) { + pr_err("failed to get fpi clk\n"); + return -ENOENT; } - ltq_port = devm_kzalloc(&pdev->dev, sizeof(struct ltq_uart_port), - GFP_KERNEL); + tx_irq = platform_get_irq_byname(pdev, "tx"); + rx_irq = platform_get_irq_byname(pdev, "rx"); + err_irq = platform_get_irq_byname(pdev, "err"); + if ((tx_irq < 0) | (rx_irq < 0) | (err_irq < 0)) + return -ENODEV; + + ltq_port = kzalloc(sizeof(struct ltq_uart_port), GFP_KERNEL); if (!ltq_port) return -ENOMEM; @@ -714,26 +709,19 @@ lqasc_probe(struct platform_device *pdev) port->ops = &lqasc_pops; port->fifosize = 16; port->type = PORT_LTQ_ASC, - port->line = line; + port->line = pdev->id; port->dev = &pdev->dev; - /* unused, just to be backward-compatible */ - port->irq = irqres[0].start; - port->mapbase = mmres->start; - ltq_port->fpiclk = clk_get_fpi(); - if (IS_ERR(ltq_port->fpiclk)) { - pr_err("failed to get fpi clk\n"); - return -ENOENT; - } + port->irq = tx_irq; /* unused, just to be backward-compatibe */ + port->mapbase = mmres->start; - /* not all asc ports have clock gates, lets ignore the return code */ - ltq_port->clk = clk_get(&pdev->dev, NULL); + ltq_port->clk = clk; - ltq_port->tx_irq = irqres[0].start; - ltq_port->rx_irq = irqres[1].start; - ltq_port->err_irq = irqres[2].start; + ltq_port->tx_irq = tx_irq; + ltq_port->rx_irq = rx_irq; + ltq_port->err_irq = err_irq; - lqasc_port[line] = ltq_port; + lqasc_port[pdev->id] = ltq_port; platform_set_drvdata(pdev, ltq_port); ret = uart_add_one_port(&lqasc_reg, port); @@ -741,17 +729,10 @@ lqasc_probe(struct platform_device *pdev) return ret; } -static const struct of_device_id ltq_asc_match[] = { - { .compatible = DRVNAME }, - {}, -}; -MODULE_DEVICE_TABLE(of, ltq_asc_match); - static struct platform_driver lqasc_driver = { .driver = { .name = DRVNAME, .owner = THIS_MODULE, - .of_match_table = ltq_asc_match, }, }; diff --git a/trunk/drivers/tty/serial/sb1250-duart.c b/trunk/drivers/tty/serial/sb1250-duart.c index f76b1688c5c8..0be8a2f00d0b 100644 --- a/trunk/drivers/tty/serial/sb1250-duart.c +++ b/trunk/drivers/tty/serial/sb1250-duart.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/tty/serial/zs.c b/trunk/drivers/tty/serial/zs.c index 92c00b24d0df..4001eee6c08d 100644 --- a/trunk/drivers/tty/serial/zs.c +++ b/trunk/drivers/tty/serial/zs.c @@ -57,7 +57,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/tty/tty_mutex.c b/trunk/drivers/tty/tty_mutex.c index 67feac9e6ebb..69adc80c98cd 100644 --- a/trunk/drivers/tty/tty_mutex.c +++ b/trunk/drivers/tty/tty_mutex.c @@ -6,17 +6,11 @@ /* Legacy tty mutex glue */ -enum { - TTY_MUTEX_NORMAL, - TTY_MUTEX_NESTED, -}; - /* * Getting the big tty mutex. */ -static void __lockfunc tty_lock_nested(struct tty_struct *tty, - unsigned int subclass) +void __lockfunc tty_lock(struct tty_struct *tty) { if (tty->magic != TTY_MAGIC) { printk(KERN_ERR "L Bad %p\n", tty); @@ -24,12 +18,7 @@ static void __lockfunc tty_lock_nested(struct tty_struct *tty, return; } tty_kref_get(tty); - mutex_lock_nested(&tty->legacy_mutex, subclass); -} - -void __lockfunc tty_lock(struct tty_struct *tty) -{ - return tty_lock_nested(tty, TTY_MUTEX_NORMAL); + mutex_lock(&tty->legacy_mutex); } EXPORT_SYMBOL(tty_lock); @@ -54,11 +43,11 @@ void __lockfunc tty_lock_pair(struct tty_struct *tty, { if (tty < tty2) { tty_lock(tty); - tty_lock_nested(tty2, TTY_MUTEX_NESTED); + tty_lock(tty2); } else { if (tty2 && tty2 != tty) tty_lock(tty2); - tty_lock_nested(tty, TTY_MUTEX_NESTED); + tty_lock(tty); } } EXPORT_SYMBOL(tty_lock_pair); diff --git a/trunk/drivers/video/Kconfig b/trunk/drivers/video/Kconfig index 0217f7415ef5..a290be51a1f4 100644 --- a/trunk/drivers/video/Kconfig +++ b/trunk/drivers/video/Kconfig @@ -2210,7 +2210,7 @@ config FB_XILINX config FB_COBALT tristate "Cobalt server LCD frame buffer support" - depends on FB && (MIPS_COBALT || MIPS_SEAD3) + depends on FB && MIPS_COBALT config FB_SH7760 bool "SH7760/SH7763/SH7720/SH7721 LCDC support" @@ -2382,39 +2382,6 @@ config FB_BROADSHEET and could also have been called by other names when coupled with a bridge adapter. -config FB_AUO_K190X - tristate "AUO-K190X EPD controller support" - depends on FB - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO - help - Provides support for epaper controllers from the K190X series - of AUO. These controllers can be used to drive epaper displays - from Sipix. - - This option enables the common support, shared by the individual - controller drivers. You will also have to enable the driver - for the controller type used in your device. - -config FB_AUO_K1900 - tristate "AUO-K1900 EPD controller support" - depends on FB && FB_AUO_K190X - help - This driver implements support for the AUO K1900 epd-controller. - This controller can drive Sipix epaper displays but can only do - serial updates, reducing the number of possible frames per second. - -config FB_AUO_K1901 - tristate "AUO-K1901 EPD controller support" - depends on FB && FB_AUO_K190X - help - This driver implements support for the AUO K1901 epd-controller. - This controller can drive Sipix epaper displays and supports - concurrent updates, making higher frames per second possible. - config FB_JZ4740 tristate "JZ4740 LCD framebuffer support" depends on FB && MACH_JZ4740 diff --git a/trunk/drivers/video/Makefile b/trunk/drivers/video/Makefile index ee8dafb69e36..9356add945b3 100644 --- a/trunk/drivers/video/Makefile +++ b/trunk/drivers/video/Makefile @@ -118,9 +118,6 @@ obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o obj-$(CONFIG_FB_MAXINE) += maxinefb.o obj-$(CONFIG_FB_METRONOME) += metronomefb.o obj-$(CONFIG_FB_BROADSHEET) += broadsheetfb.o -obj-$(CONFIG_FB_AUO_K190X) += auo_k190x.o -obj-$(CONFIG_FB_AUO_K1900) += auo_k1900fb.o -obj-$(CONFIG_FB_AUO_K1901) += auo_k1901fb.o obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o obj-$(CONFIG_FB_SH7760) += sh7760fb.o obj-$(CONFIG_FB_IMX) += imxfb.o diff --git a/trunk/drivers/video/auo_k1900fb.c b/trunk/drivers/video/auo_k1900fb.c deleted file mode 100644 index c36cf961dcb2..000000000000 --- a/trunk/drivers/video/auo_k1900fb.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * auok190xfb.c -- FB driver for AUO-K1900 controllers - * - * Copyright (C) 2011, 2012 Heiko Stuebner - * - * based on broadsheetfb.c - * - * Copyright (C) 2008, Jaya Kumar - * - * 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. - * - * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. - * - * This driver is written to be used with the AUO-K1900 display controller. - * - * It is intended to be architecture independent. A board specific driver - * must be used to perform all the physical IO interactions. - * - * The controller supports different update modes: - * mode0+1 16 step gray (4bit) - * mode2 4 step gray (2bit) - FIXME: add strange refresh - * mode3 2 step gray (1bit) - FIXME: add strange refresh - * mode4 handwriting mode (strange behaviour) - * mode5 automatic selection of update mode - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include